mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2025-09-20 05:57:24 +00:00
feat: support appflowy cloud in sign-in settings page (#6386)
* feat: support appflowy cloud in sign-in settings page * test: add cloud server test * test: wait until the tooltip disappear
This commit is contained in:
parent
0d2841227a
commit
c51b495544
@ -3,6 +3,7 @@ import 'package:integration_test/integration_test.dart';
|
||||
import 'notifications_settings_test.dart' as notifications_settings_test;
|
||||
import 'settings_billing_test.dart' as settings_billing_test;
|
||||
import 'shortcuts_settings_test.dart' as shortcuts_settings_test;
|
||||
import 'sign_in_page_settings_test.dart' as sign_in_page_settings_test;
|
||||
|
||||
void main() {
|
||||
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
|
||||
@ -10,4 +11,5 @@ void main() {
|
||||
notifications_settings_test.main();
|
||||
settings_billing_test.main();
|
||||
shortcuts_settings_test.main();
|
||||
sign_in_page_settings_test.main();
|
||||
}
|
||||
|
@ -0,0 +1,103 @@
|
||||
import 'package:appflowy/env/cloud_env.dart';
|
||||
import 'package:appflowy/generated/locale_keys.g.dart';
|
||||
import 'package:appflowy/user/presentation/screens/sign_in_screen/desktop_sign_in_screen.dart';
|
||||
import 'package:appflowy/workspace/presentation/settings/settings_dialog.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:integration_test/integration_test.dart';
|
||||
import 'package:toastification/toastification.dart';
|
||||
|
||||
import '../../shared/util.dart';
|
||||
|
||||
void main() {
|
||||
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
|
||||
|
||||
Finder findServerType(AuthenticatorType type) {
|
||||
return find
|
||||
.descendant(
|
||||
of: find.byType(SettingsServerDropdownMenu),
|
||||
matching: find.findTextInFlowyText(
|
||||
type.label,
|
||||
),
|
||||
)
|
||||
.last;
|
||||
}
|
||||
|
||||
group('sign-in page settings: ', () {
|
||||
testWidgets('change server type', (tester) async {
|
||||
await tester.initializeAppFlowy();
|
||||
|
||||
// reset the app to the default state
|
||||
await useAppFlowyBetaCloudWithURL(
|
||||
kAppflowyCloudUrl,
|
||||
AuthenticatorType.appflowyCloud,
|
||||
);
|
||||
|
||||
// open the settings page
|
||||
final settingsButton = find.byType(DesktopSignInSettingsButton);
|
||||
await tester.tapButton(settingsButton);
|
||||
|
||||
expect(find.byType(SimpleSettingsDialog), findsOneWidget);
|
||||
|
||||
// the default type should be appflowy cloud
|
||||
final appflowyCloudType = findServerType(AuthenticatorType.appflowyCloud);
|
||||
expect(appflowyCloudType, findsOneWidget);
|
||||
|
||||
// change the server type to self-host
|
||||
await tester.tapButton(appflowyCloudType);
|
||||
final selfhostedButton = findServerType(
|
||||
AuthenticatorType.appflowyCloudSelfHost,
|
||||
);
|
||||
await tester.tapButton(selfhostedButton);
|
||||
|
||||
// update server url
|
||||
const serverUrl = 'https://test.appflowy.cloud';
|
||||
await tester.enterText(
|
||||
find.byKey(kSelfHostedTextInputFieldKey),
|
||||
serverUrl,
|
||||
);
|
||||
await tester.pumpAndSettle();
|
||||
await tester.tapButton(
|
||||
find.findTextInFlowyText(LocaleKeys.button_save.tr()),
|
||||
);
|
||||
|
||||
// wait the app to restart, and the tooltip to disappear
|
||||
await tester.pumpUntilNotFound(find.byType(BuiltInToastBuilder));
|
||||
await tester.pumpAndSettle(const Duration(milliseconds: 250));
|
||||
|
||||
// open settings page to check the result
|
||||
await tester.tapButton(settingsButton);
|
||||
|
||||
// check the server type
|
||||
expect(
|
||||
findServerType(AuthenticatorType.appflowyCloudSelfHost),
|
||||
findsOneWidget,
|
||||
);
|
||||
// check the server url
|
||||
expect(
|
||||
find.text(serverUrl),
|
||||
findsOneWidget,
|
||||
);
|
||||
|
||||
// reset to appflowy cloud
|
||||
await tester.tapButton(
|
||||
findServerType(AuthenticatorType.appflowyCloudSelfHost),
|
||||
);
|
||||
// change the server type to appflowy cloud
|
||||
await tester.tapButton(
|
||||
findServerType(AuthenticatorType.appflowyCloud),
|
||||
);
|
||||
|
||||
// wait the app to restart, and the tooltip to disappear
|
||||
await tester.pumpUntilNotFound(find.byType(BuiltInToastBuilder));
|
||||
await tester.pumpAndSettle(const Duration(milliseconds: 250));
|
||||
|
||||
// check the server type
|
||||
await tester.tapButton(settingsButton);
|
||||
expect(
|
||||
findServerType(AuthenticatorType.appflowyCloud),
|
||||
findsOneWidget,
|
||||
);
|
||||
});
|
||||
});
|
||||
}
|
@ -391,17 +391,23 @@ class _AFDropdownMenuState<T> extends State<AFDropdownMenu<T>> {
|
||||
);
|
||||
}
|
||||
|
||||
// Remove the code here, it will throw a FlutterError
|
||||
// Unless we upgrade to Flutter 3.24 https://github.com/flutter/flutter/issues/146764
|
||||
void scrollToHighlight() {
|
||||
WidgetsBinding.instance.addPostFrameCallback(
|
||||
(_) {
|
||||
final BuildContext? highlightContext =
|
||||
buttonItemKeys[currentHighlight!].currentContext;
|
||||
if (highlightContext != null) {
|
||||
Scrollable.ensureVisible(highlightContext);
|
||||
}
|
||||
},
|
||||
debugLabel: 'DropdownMenu.scrollToHighlight',
|
||||
);
|
||||
// WidgetsBinding.instance.addPostFrameCallback(
|
||||
// (_) {
|
||||
// // try {
|
||||
// final BuildContext? highlightContext =
|
||||
// buttonItemKeys[currentHighlight!].currentContext;
|
||||
// if (highlightContext != null) {
|
||||
// Scrollable.ensureVisible(highlightContext);
|
||||
// }
|
||||
// } catch (_) {
|
||||
// return;
|
||||
// }
|
||||
// },
|
||||
// debugLabel: 'DropdownMenu.scrollToHighlight',
|
||||
// );
|
||||
}
|
||||
|
||||
double? getWidth(GlobalKey key) {
|
||||
|
@ -68,7 +68,7 @@ class DesktopSignInScreen extends StatelessWidget {
|
||||
const Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
_SettingsButton(),
|
||||
DesktopSignInSettingsButton(),
|
||||
HSpace(42),
|
||||
SignInAnonymousButtonV2(),
|
||||
],
|
||||
@ -92,8 +92,10 @@ class DesktopSignInScreen extends StatelessWidget {
|
||||
}
|
||||
}
|
||||
|
||||
class _SettingsButton extends StatelessWidget {
|
||||
const _SettingsButton();
|
||||
class DesktopSignInSettingsButton extends StatelessWidget {
|
||||
const DesktopSignInSettingsButton({
|
||||
super.key,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
@ -14,7 +14,9 @@ import 'package:appflowy/workspace/presentation/settings/pages/settings_manage_d
|
||||
import 'package:appflowy/workspace/presentation/settings/pages/settings_plan_view.dart';
|
||||
import 'package:appflowy/workspace/presentation/settings/pages/settings_shortcuts_view.dart';
|
||||
import 'package:appflowy/workspace/presentation/settings/pages/settings_workspace_view.dart';
|
||||
import 'package:appflowy/workspace/presentation/settings/shared/af_dropdown_menu_entry.dart';
|
||||
import 'package:appflowy/workspace/presentation/settings/shared/settings_category.dart';
|
||||
import 'package:appflowy/workspace/presentation/settings/shared/settings_dropdown.dart';
|
||||
import 'package:appflowy/workspace/presentation/settings/widgets/feature_flags/feature_flag_page.dart';
|
||||
import 'package:appflowy/workspace/presentation/settings/widgets/members/workspace_member_page.dart';
|
||||
import 'package:appflowy/workspace/presentation/settings/widgets/settings_menu.dart';
|
||||
@ -30,6 +32,10 @@ import 'package:toastification/toastification.dart';
|
||||
|
||||
import 'widgets/setting_cloud.dart';
|
||||
|
||||
@visibleForTesting
|
||||
const kSelfHostedTextInputFieldKey =
|
||||
ValueKey('self_hosted_url_input_text_field');
|
||||
|
||||
class SettingsDialog extends StatelessWidget {
|
||||
SettingsDialog(
|
||||
this.user, {
|
||||
@ -173,6 +179,7 @@ class _SimpleSettingsDialogState extends State<SimpleSettingsDialog> {
|
||||
return FlowyDialog(
|
||||
width: MediaQuery.of(context).size.width * 0.7,
|
||||
constraints: const BoxConstraints(maxWidth: 784, minWidth: 564),
|
||||
child: SingleChildScrollView(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(24.0),
|
||||
child: Column(
|
||||
@ -200,6 +207,7 @@ class _SimpleSettingsDialogState extends State<SimpleSettingsDialog> {
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -229,6 +237,7 @@ class _SelfHostSettings extends StatefulWidget {
|
||||
|
||||
class _SelfHostSettingsState extends State<_SelfHostSettings> {
|
||||
final textController = TextEditingController();
|
||||
AuthenticatorType type = AuthenticatorType.appflowyCloud;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
@ -236,6 +245,11 @@ class _SelfHostSettingsState extends State<_SelfHostSettings> {
|
||||
|
||||
getAppFlowyCloudUrl().then((url) {
|
||||
textController.text = url;
|
||||
if (kAppflowyCloudUrl != url) {
|
||||
setState(() {
|
||||
type = AuthenticatorType.appflowyCloudSelfHost;
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@ -248,22 +262,38 @@ class _SelfHostSettingsState extends State<_SelfHostSettings> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return SettingsCategory(
|
||||
title: LocaleKeys.settings_menu_cloudAppFlowySelfHost.tr(),
|
||||
title: LocaleKeys.settings_menu_cloudAppFlowy.tr(),
|
||||
children: [
|
||||
Row(
|
||||
Flexible(
|
||||
child: SettingsServerDropdownMenu(
|
||||
selectedServer: type,
|
||||
onSelected: _onSelected,
|
||||
),
|
||||
),
|
||||
if (type == AuthenticatorType.appflowyCloudSelfHost) _buildInputField(),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildInputField() {
|
||||
return Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: SizedBox(
|
||||
height: 36,
|
||||
child: FlowyTextField(
|
||||
key: kSelfHostedTextInputFieldKey,
|
||||
controller: textController,
|
||||
autoFocus: false,
|
||||
textStyle: const TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w400,
|
||||
),
|
||||
hintText: 'https://beta.appflowy.cloud',
|
||||
onEditingComplete: _saveSelfHostUrl,
|
||||
hintText: kAppflowyCloudUrl,
|
||||
onEditingComplete: () => _saveUrl(
|
||||
url: textController.text,
|
||||
type: AuthenticatorType.appflowyCloudSelfHost,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -273,17 +303,40 @@ class _SelfHostSettingsState extends State<_SelfHostSettings> {
|
||||
constraints: const BoxConstraints(minWidth: 78),
|
||||
child: OutlinedRoundedButton(
|
||||
text: LocaleKeys.button_save.tr(),
|
||||
onTap: _saveSelfHostUrl,
|
||||
onTap: () => _saveUrl(
|
||||
url: textController.text,
|
||||
type: AuthenticatorType.appflowyCloudSelfHost,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
void _saveSelfHostUrl() {
|
||||
final url = textController.text;
|
||||
void _onSelected(AuthenticatorType type) {
|
||||
if (type == this.type) {
|
||||
return;
|
||||
}
|
||||
|
||||
Log.info('Switching server type to $type');
|
||||
|
||||
setState(() {
|
||||
this.type = type;
|
||||
});
|
||||
|
||||
if (type == AuthenticatorType.appflowyCloud) {
|
||||
textController.text = kAppflowyCloudUrl;
|
||||
_saveUrl(
|
||||
url: textController.text,
|
||||
type: type,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void _saveUrl({
|
||||
required String url,
|
||||
required AuthenticatorType type,
|
||||
}) {
|
||||
if (url.isEmpty) {
|
||||
showToastNotification(
|
||||
context,
|
||||
@ -301,7 +354,7 @@ class _SelfHostSettingsState extends State<_SelfHostSettings> {
|
||||
);
|
||||
|
||||
Navigator.of(context).pop();
|
||||
await useSelfHostedAppFlowyCloudWithURL(url);
|
||||
await useAppFlowyBetaCloudWithURL(url, type);
|
||||
await runAppFlowy();
|
||||
},
|
||||
(err) {
|
||||
@ -316,6 +369,57 @@ class _SelfHostSettingsState extends State<_SelfHostSettings> {
|
||||
}
|
||||
}
|
||||
|
||||
@visibleForTesting
|
||||
extension SettingsServerDropdownMenuExtension on AuthenticatorType {
|
||||
String get label {
|
||||
switch (this) {
|
||||
case AuthenticatorType.appflowyCloud:
|
||||
return LocaleKeys.settings_menu_cloudAppFlowy.tr();
|
||||
case AuthenticatorType.appflowyCloudSelfHost:
|
||||
return LocaleKeys.settings_menu_cloudAppFlowySelfHost.tr();
|
||||
default:
|
||||
throw Exception('Unsupported server type: $this');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@visibleForTesting
|
||||
class SettingsServerDropdownMenu extends StatelessWidget {
|
||||
const SettingsServerDropdownMenu({
|
||||
super.key,
|
||||
required this.selectedServer,
|
||||
required this.onSelected,
|
||||
});
|
||||
|
||||
final AuthenticatorType selectedServer;
|
||||
final void Function(AuthenticatorType type) onSelected;
|
||||
|
||||
// in the settings page from sign in page, we only support appflowy cloud and self-hosted
|
||||
static final supportedServers = [
|
||||
AuthenticatorType.appflowyCloud,
|
||||
AuthenticatorType.appflowyCloudSelfHost,
|
||||
];
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return SettingsDropdown<AuthenticatorType>(
|
||||
expandWidth: false,
|
||||
onChanged: onSelected,
|
||||
selectedOption: selectedServer,
|
||||
options: supportedServers
|
||||
.map(
|
||||
(serverType) => buildDropdownMenuEntry<AuthenticatorType>(
|
||||
context,
|
||||
selectedValue: selectedServer,
|
||||
value: serverType,
|
||||
label: serverType.label,
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _SupportSettings extends StatelessWidget {
|
||||
const _SupportSettings({
|
||||
super.key,
|
||||
|
@ -1,5 +1,3 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:appflowy/flutter/af_dropdown_menu.dart';
|
||||
import 'package:appflowy/shared/google_fonts_extension.dart';
|
||||
import 'package:appflowy/workspace/application/settings/appearance/appearance_cubit.dart';
|
||||
@ -7,6 +5,7 @@ import 'package:appflowy/workspace/application/settings/appearance/base_appearan
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:flowy_infra/size.dart';
|
||||
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
|
||||
class SettingsDropdown<T> extends StatefulWidget {
|
||||
|
Loading…
x
Reference in New Issue
Block a user