mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
test: add document sync test on appflowy cloud (#4163)
* test: add document sync test on appflowy cloud * chore: add runner * test: Stream has already been listened to. * fix: using singleton subscription * fix: using singleton subscription
This commit is contained in:
@ -49,7 +49,6 @@ class DependencyResolver {
|
||||
_resolveUserDeps(getIt, mode);
|
||||
_resolveHomeDeps(getIt);
|
||||
_resolveFolderDeps(getIt);
|
||||
_resolveDocDeps(getIt);
|
||||
_resolveCommonService(getIt, mode);
|
||||
}
|
||||
}
|
||||
@ -219,10 +218,3 @@ void _resolveFolderDeps(GetIt getIt) {
|
||||
);
|
||||
getIt.registerFactory<FavoriteBloc>(() => FavoriteBloc());
|
||||
}
|
||||
|
||||
void _resolveDocDeps(GetIt getIt) {
|
||||
// Doc
|
||||
getIt.registerFactoryParam<DocumentBloc, ViewPB, void>(
|
||||
(view, _) => DocumentBloc(view: view),
|
||||
);
|
||||
}
|
||||
|
@ -13,6 +13,7 @@ import 'package:appflowy/user/application/user_auth_listener.dart';
|
||||
import 'package:appflowy/workspace/presentation/home/toast.dart';
|
||||
import 'package:appflowy_backend/dispatch/dispatch.dart';
|
||||
import 'package:appflowy_backend/log.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-error/code.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-user/protobuf.dart';
|
||||
import 'package:dartz/dartz.dart';
|
||||
@ -21,30 +22,38 @@ import 'package:url_protocol/url_protocol.dart';
|
||||
|
||||
class AppFlowyCloudDeepLink {
|
||||
final _appLinks = AppLinks();
|
||||
StreamSubscription<Uri?>? _deeplinkSubscription;
|
||||
final ValueNotifier<DeepLinkResult?> stateNotifier = ValueNotifier(null);
|
||||
// The AppLinks is a singleton, so we need to cancel the previous subscription
|
||||
// before creating a new one.
|
||||
static StreamSubscription<Uri?>? _deeplinkSubscription;
|
||||
ValueNotifier<DeepLinkResult?>? _stateNotifier = ValueNotifier(null);
|
||||
Completer<Either<FlowyError, UserProfilePB>>? _completer;
|
||||
|
||||
AppFlowyCloudDeepLink() {
|
||||
if (Platform.isWindows) {
|
||||
// register deep link for Windows
|
||||
registerProtocolHandler(appflowyDeepLinkSchema);
|
||||
if (_deeplinkSubscription == null) {
|
||||
_deeplinkSubscription = _appLinks.uriLinkStream.listen(
|
||||
(Uri? uri) async {
|
||||
Log.info('onDeepLink: ${uri.toString()}');
|
||||
await _handleUri(uri);
|
||||
},
|
||||
onError: (Object err, StackTrace stackTrace) {
|
||||
Log.error('on deeplink stream error: ${err.toString()}', stackTrace);
|
||||
_deeplinkSubscription?.cancel();
|
||||
_deeplinkSubscription = null;
|
||||
},
|
||||
);
|
||||
if (Platform.isWindows) {
|
||||
// register deep link for Windows
|
||||
registerProtocolHandler(appflowyDeepLinkSchema);
|
||||
}
|
||||
} else {
|
||||
_deeplinkSubscription?.resume();
|
||||
}
|
||||
|
||||
_deeplinkSubscription = _appLinks.uriLinkStream.listen(
|
||||
(Uri? uri) async {
|
||||
Log.info('onDeepLink: ${uri.toString()}');
|
||||
await _handleUri(uri);
|
||||
},
|
||||
onError: (Object err, StackTrace stackTrace) {
|
||||
Log.error('on deeplink stream error: ${err.toString()}', stackTrace);
|
||||
_deeplinkSubscription?.cancel();
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> dispose() async {
|
||||
await _deeplinkSubscription?.cancel();
|
||||
_deeplinkSubscription?.pause();
|
||||
_stateNotifier?.dispose();
|
||||
_stateNotifier = null;
|
||||
}
|
||||
|
||||
void resigerCompleter(
|
||||
@ -57,71 +66,80 @@ class AppFlowyCloudDeepLink {
|
||||
ValueChanged<DeepLinkResult> listener,
|
||||
) {
|
||||
void listenerFn() {
|
||||
if (stateNotifier.value != null) {
|
||||
listener(stateNotifier.value!);
|
||||
if (_stateNotifier?.value != null) {
|
||||
listener(_stateNotifier!.value!);
|
||||
}
|
||||
}
|
||||
|
||||
stateNotifier.addListener(listenerFn);
|
||||
_stateNotifier?.addListener(listenerFn);
|
||||
return listenerFn;
|
||||
}
|
||||
|
||||
void unsubscribeDeepLinkLoadingState(
|
||||
VoidCallback listener,
|
||||
) {
|
||||
stateNotifier.removeListener(listener);
|
||||
}
|
||||
void unsubscribeDeepLinkLoadingState(VoidCallback listener) =>
|
||||
_stateNotifier?.removeListener(listener);
|
||||
|
||||
Future<void> _handleUri(
|
||||
Uri? uri,
|
||||
) async {
|
||||
stateNotifier.value = DeepLinkResult(state: DeepLinkState.none);
|
||||
_stateNotifier?.value = DeepLinkResult(state: DeepLinkState.none);
|
||||
if (uri != null) {
|
||||
if (_isAuthCallbackDeeplink(uri)) {
|
||||
final deviceId = await getDeviceId();
|
||||
final payload = OauthSignInPB(
|
||||
authType: AuthTypePB.AFCloud,
|
||||
map: {
|
||||
AuthServiceMapKeys.signInURL: uri.toString(),
|
||||
AuthServiceMapKeys.deviceId: deviceId,
|
||||
},
|
||||
);
|
||||
stateNotifier.value = DeepLinkResult(state: DeepLinkState.loading);
|
||||
final result = await UserEventOauthSignIn(payload)
|
||||
.send()
|
||||
.then((value) => value.swap());
|
||||
|
||||
stateNotifier.value = DeepLinkResult(
|
||||
state: DeepLinkState.finish,
|
||||
result: result,
|
||||
);
|
||||
// If there is no completer, runAppFlowy() will be called.
|
||||
if (_completer == null) {
|
||||
result.fold(
|
||||
(err) {
|
||||
Log.error(err);
|
||||
final context = AppGlobals.rootNavKey.currentState?.context;
|
||||
if (context != null) {
|
||||
showSnackBarMessage(
|
||||
context,
|
||||
err.msg,
|
||||
);
|
||||
}
|
||||
},
|
||||
(err) async {
|
||||
Log.error(err);
|
||||
await runAppFlowy();
|
||||
_isAuthCallbackDeeplink(uri).fold(
|
||||
(_) async {
|
||||
final deviceId = await getDeviceId();
|
||||
final payload = OauthSignInPB(
|
||||
authType: AuthTypePB.AFCloud,
|
||||
map: {
|
||||
AuthServiceMapKeys.signInURL: uri.toString(),
|
||||
AuthServiceMapKeys.deviceId: deviceId,
|
||||
},
|
||||
);
|
||||
} else {
|
||||
_completer?.complete(result);
|
||||
_completer = null;
|
||||
}
|
||||
} else {
|
||||
Log.error('onDeepLinkError: Unexpect deep link: ${uri.toString()}');
|
||||
_completer?.complete(left(AuthError.signInWithOauthError));
|
||||
_completer = null;
|
||||
}
|
||||
_stateNotifier?.value = DeepLinkResult(state: DeepLinkState.loading);
|
||||
final result = await UserEventOauthSignIn(payload)
|
||||
.send()
|
||||
.then((value) => value.swap());
|
||||
|
||||
_stateNotifier?.value = DeepLinkResult(
|
||||
state: DeepLinkState.finish,
|
||||
result: result,
|
||||
);
|
||||
// If there is no completer, runAppFlowy() will be called.
|
||||
if (_completer == null) {
|
||||
result.fold(
|
||||
(err) {
|
||||
Log.error(err);
|
||||
final context = AppGlobals.rootNavKey.currentState?.context;
|
||||
if (context != null) {
|
||||
showSnackBarMessage(
|
||||
context,
|
||||
err.msg,
|
||||
);
|
||||
}
|
||||
},
|
||||
(_) async {
|
||||
await runAppFlowy();
|
||||
},
|
||||
);
|
||||
} else {
|
||||
_completer?.complete(result);
|
||||
_completer = null;
|
||||
}
|
||||
},
|
||||
(err) {
|
||||
Log.error('onDeepLinkError: Unexpect deep link: $err');
|
||||
if (_completer == null) {
|
||||
final context = AppGlobals.rootNavKey.currentState?.context;
|
||||
if (context != null) {
|
||||
showSnackBarMessage(
|
||||
context,
|
||||
err.msg,
|
||||
);
|
||||
}
|
||||
} else {
|
||||
_completer?.complete(left(err));
|
||||
_completer = null;
|
||||
}
|
||||
},
|
||||
);
|
||||
} else {
|
||||
Log.error('onDeepLinkError: Unexpect empty deep link callback');
|
||||
_completer?.complete(left(AuthError.emptyDeeplink));
|
||||
@ -129,8 +147,16 @@ class AppFlowyCloudDeepLink {
|
||||
}
|
||||
}
|
||||
|
||||
bool _isAuthCallbackDeeplink(Uri uri) {
|
||||
return (uri.fragment.contains('access_token'));
|
||||
Either<(), FlowyError> _isAuthCallbackDeeplink(Uri uri) {
|
||||
if (uri.fragment.contains('access_token')) {
|
||||
return left(());
|
||||
}
|
||||
|
||||
return right(
|
||||
FlowyError.create()
|
||||
..code = ErrorCode.MissingAuthField
|
||||
..msg = uri.path,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user