mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-11-09 13:09:21 +03:00
feat: customize self host url on launch page (#4465)
This commit is contained in:
parent
2554ba81b5
commit
e239ba46aa
@ -0,0 +1,37 @@
|
||||
import 'package:appflowy/env/env.dart';
|
||||
import 'package:appflowy/generated/locale_keys.g.dart';
|
||||
import 'package:appflowy/mobile/presentation/presentation.dart';
|
||||
import 'package:appflowy/mobile/presentation/setting/self_host_setting_group.dart';
|
||||
import 'package:appflowy/workspace/application/settings/appearance/appearance_cubit.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
|
||||
class MobileLaunchSettingsPage extends StatelessWidget {
|
||||
const MobileLaunchSettingsPage({
|
||||
super.key,
|
||||
});
|
||||
|
||||
static const routeName = '/launch_settings';
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
context.watch<AppearanceSettingsCubit>();
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text(LocaleKeys.settings_title.tr()),
|
||||
),
|
||||
body: SingleChildScrollView(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: Column(
|
||||
children: [
|
||||
const LanguageSettingGroup(),
|
||||
if (Env.enableCustomCloud) const SelfHostSettingGroup(),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@ -1,38 +0,0 @@
|
||||
import 'package:appflowy/generated/locale_keys.g.dart';
|
||||
import 'package:appflowy/startup/startup.dart';
|
||||
import 'package:appflowy/user/application/auth/auth_service.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class LogoutSettingGroup extends StatelessWidget {
|
||||
const LogoutSettingGroup({
|
||||
super.key,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Column(
|
||||
children: [
|
||||
const Divider(),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(bottom: 4),
|
||||
child: FlowyButton(
|
||||
margin: const EdgeInsets.symmetric(
|
||||
vertical: 16.0,
|
||||
),
|
||||
text: FlowyText.medium(
|
||||
LocaleKeys.settings_menu_logout.tr(),
|
||||
textAlign: TextAlign.center,
|
||||
fontSize: 14.0,
|
||||
),
|
||||
onTap: () async {
|
||||
await getIt<AuthService>().signOut();
|
||||
runAppFlowy();
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,110 @@
|
||||
import 'package:appflowy/env/cloud_env.dart';
|
||||
import 'package:appflowy/generated/locale_keys.g.dart';
|
||||
import 'package:appflowy/startup/startup.dart';
|
||||
import 'package:appflowy/workspace/application/settings/appflowy_cloud_urls_bloc.dart';
|
||||
import 'package:appflowy_backend/log.dart';
|
||||
import 'package:dartz/dartz.dart' show Some;
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
|
||||
class SelfHostUrlBottomSheet extends StatefulWidget {
|
||||
const SelfHostUrlBottomSheet({
|
||||
super.key,
|
||||
required this.url,
|
||||
});
|
||||
|
||||
final String url;
|
||||
|
||||
@override
|
||||
State<SelfHostUrlBottomSheet> createState() => _SelfHostUrlBottomSheetState();
|
||||
}
|
||||
|
||||
class _SelfHostUrlBottomSheetState extends State<SelfHostUrlBottomSheet> {
|
||||
final TextEditingController _textFieldController = TextEditingController();
|
||||
|
||||
final _formKey = GlobalKey<FormState>();
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
|
||||
_textFieldController.text = widget.url;
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_textFieldController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final theme = Theme.of(context);
|
||||
|
||||
return Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: <Widget>[
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
LocaleKeys.editor_urlHint.tr(),
|
||||
style: theme.textTheme.labelSmall,
|
||||
),
|
||||
IconButton(
|
||||
icon: Icon(
|
||||
Icons.close,
|
||||
color: theme.hintColor,
|
||||
),
|
||||
onPressed: () {
|
||||
context.pop();
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(
|
||||
height: 16,
|
||||
),
|
||||
Form(
|
||||
key: _formKey,
|
||||
child: TextFormField(
|
||||
controller: _textFieldController,
|
||||
keyboardType: TextInputType.text,
|
||||
validator: (value) {
|
||||
if (value == null || value.isEmpty) {
|
||||
return LocaleKeys.settings_mobile_usernameEmptyError.tr();
|
||||
}
|
||||
return null;
|
||||
},
|
||||
onEditingComplete: _saveSelfHostUrl,
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 16,
|
||||
),
|
||||
SizedBox(
|
||||
width: double.infinity,
|
||||
child: ElevatedButton(
|
||||
onPressed: _saveSelfHostUrl,
|
||||
child: Text(LocaleKeys.settings_menu_restartApp.tr()),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
void _saveSelfHostUrl() {
|
||||
if (_formKey.currentState!.validate()) {
|
||||
final value = _textFieldController.text;
|
||||
if (value.isNotEmpty) {
|
||||
validateUrl(value).fold(
|
||||
(url) async {
|
||||
await setAppFlowyCloudUrl(Some(url));
|
||||
runAppFlowy();
|
||||
},
|
||||
(err) => Log.error(err),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,52 @@
|
||||
import 'package:appflowy/env/cloud_env.dart';
|
||||
import 'package:appflowy/generated/locale_keys.g.dart';
|
||||
import 'package:appflowy/mobile/presentation/bottom_sheet/bottom_sheet.dart';
|
||||
import 'package:appflowy/mobile/presentation/setting/self_host/self_host_bottom_sheet.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'setting.dart';
|
||||
|
||||
class SelfHostSettingGroup extends StatefulWidget {
|
||||
const SelfHostSettingGroup({
|
||||
super.key,
|
||||
});
|
||||
|
||||
@override
|
||||
State<SelfHostSettingGroup> createState() => _SelfHostSettingGroupState();
|
||||
}
|
||||
|
||||
class _SelfHostSettingGroupState extends State<SelfHostSettingGroup> {
|
||||
final future = getAppFlowyCloudUrl();
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return FutureBuilder(
|
||||
future: future,
|
||||
builder: (context, snapshot) {
|
||||
if (!snapshot.hasData) {
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
final url = snapshot.data ?? '';
|
||||
return MobileSettingGroup(
|
||||
groupTitle: LocaleKeys.settings_menu_cloudAppFlowySelfHost.tr(),
|
||||
settingItemList: [
|
||||
MobileSettingItem(
|
||||
name: url,
|
||||
onTap: () {
|
||||
showMobileBottomSheet(
|
||||
context,
|
||||
builder: (_) {
|
||||
return SelfHostUrlBottomSheet(
|
||||
url: url,
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
@ -82,7 +82,6 @@ class InitAppWidgetTask extends LaunchTask {
|
||||
path: 'assets/translations',
|
||||
fallbackLocale: const Locale('en'),
|
||||
useFallbackTranslations: true,
|
||||
saveLocale: false,
|
||||
child: app,
|
||||
),
|
||||
);
|
||||
|
@ -12,6 +12,7 @@ import 'package:appflowy/mobile/presentation/presentation.dart';
|
||||
import 'package:appflowy/mobile/presentation/setting/cloud/appflowy_cloud_page.dart';
|
||||
import 'package:appflowy/mobile/presentation/setting/font/font_picker_screen.dart';
|
||||
import 'package:appflowy/mobile/presentation/setting/language/language_picker_screen.dart';
|
||||
import 'package:appflowy/mobile/presentation/setting/launch_settings_page.dart';
|
||||
import 'package:appflowy/plugins/base/color/color_picker_screen.dart';
|
||||
import 'package:appflowy/plugins/base/emoji/emoji_picker_screen.dart';
|
||||
import 'package:appflowy/plugins/document/presentation/editor_plugins/code_block/code_language_screen.dart';
|
||||
@ -49,6 +50,7 @@ GoRouter generateRouter(Widget child) {
|
||||
_mobileHomeSettingPageRoute(),
|
||||
_mobileSettingUserAgreementPageRoute(),
|
||||
_mobileCloudSettingAppFlowyCloudPageRoute(),
|
||||
_mobileLaunchSettingsPageRoute(),
|
||||
|
||||
// view page
|
||||
_mobileEditorScreenRoute(),
|
||||
@ -215,6 +217,16 @@ GoRoute _mobileSettingUserAgreementPageRoute() {
|
||||
);
|
||||
}
|
||||
|
||||
GoRoute _mobileLaunchSettingsPageRoute() {
|
||||
return GoRoute(
|
||||
parentNavigatorKey: AppGlobals.rootNavKey,
|
||||
path: MobileLaunchSettingsPage.routeName,
|
||||
pageBuilder: (context, state) {
|
||||
return const MaterialPage(child: MobileLaunchSettingsPage());
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
GoRoute _mobileHomeTrashPageRoute() {
|
||||
return GoRoute(
|
||||
parentNavigatorKey: AppGlobals.rootNavKey,
|
||||
|
@ -1,10 +1,12 @@
|
||||
import 'package:appflowy/env/cloud_env.dart';
|
||||
import 'package:appflowy/generated/flowy_svgs.g.dart';
|
||||
import 'package:appflowy/generated/locale_keys.g.dart';
|
||||
import 'package:appflowy/mobile/presentation/setting/launch_settings_page.dart';
|
||||
import 'package:appflowy/user/presentation/screens/sign_in_screen/widgets/widgets.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
|
||||
class MobileSignInScreen extends StatelessWidget {
|
||||
const MobileSignInScreen({
|
||||
@ -20,65 +22,89 @@ class MobileSignInScreen extends StatelessWidget {
|
||||
padding: const EdgeInsets.symmetric(vertical: 50, horizontal: 40),
|
||||
child: Column(
|
||||
children: [
|
||||
const Spacer(
|
||||
flex: 4,
|
||||
),
|
||||
const FlowySvg(
|
||||
FlowySvgs.flowy_logo_xl,
|
||||
size: Size.square(64),
|
||||
blendMode: null,
|
||||
),
|
||||
const Spacer(flex: 4),
|
||||
_buildLogo(),
|
||||
const VSpace(spacing * 2),
|
||||
// Welcome to
|
||||
FlowyText(
|
||||
LocaleKeys.welcomeTo.tr(),
|
||||
textAlign: TextAlign.center,
|
||||
fontSize: 32,
|
||||
fontWeight: FontWeight.w700,
|
||||
),
|
||||
// AppFlowy
|
||||
FlowyText(
|
||||
LocaleKeys.appName.tr(),
|
||||
textAlign: TextAlign.center,
|
||||
fontSize: 32,
|
||||
color: const Color(0xFF00BCF0),
|
||||
fontWeight: FontWeight.w700,
|
||||
),
|
||||
_buildWelcomeText(),
|
||||
_buildAppNameText(colorScheme),
|
||||
const VSpace(spacing),
|
||||
const Spacer(
|
||||
flex: 2,
|
||||
),
|
||||
|
||||
const Spacer(flex: 2),
|
||||
const SignInAnonymousButton(),
|
||||
const VSpace(spacing),
|
||||
|
||||
// if the cloud env is enabled, show the third-party sign in buttons.
|
||||
if (isAuthEnabled) ...[
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
const Expanded(child: Divider()),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8),
|
||||
child: FlowyText(
|
||||
LocaleKeys.signIn_or.tr(),
|
||||
color: colorScheme.onSecondary,
|
||||
),
|
||||
),
|
||||
const Expanded(child: Divider()),
|
||||
],
|
||||
),
|
||||
_buildThirdPartySignInButtons(colorScheme),
|
||||
const VSpace(spacing),
|
||||
const ThirdPartySignInButtons(),
|
||||
_buildSettingsButton(context),
|
||||
],
|
||||
if (!isAuthEnabled)
|
||||
const Spacer(
|
||||
flex: 2,
|
||||
),
|
||||
const VSpace(spacing),
|
||||
if (!isAuthEnabled) const Spacer(flex: 2),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildWelcomeText() {
|
||||
return FlowyText(
|
||||
LocaleKeys.welcomeTo.tr(),
|
||||
textAlign: TextAlign.center,
|
||||
fontSize: 32,
|
||||
fontWeight: FontWeight.w700,
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildLogo() {
|
||||
return const FlowySvg(
|
||||
FlowySvgs.flowy_logo_xl,
|
||||
size: Size.square(64),
|
||||
blendMode: null,
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildAppNameText(ColorScheme colorScheme) {
|
||||
return FlowyText(
|
||||
LocaleKeys.appName.tr(),
|
||||
textAlign: TextAlign.center,
|
||||
fontSize: 32,
|
||||
color: const Color(0xFF00BCF0),
|
||||
fontWeight: FontWeight.w700,
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildThirdPartySignInButtons(ColorScheme colorScheme) {
|
||||
return Column(
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
const Expanded(child: Divider()),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8),
|
||||
child: FlowyText(
|
||||
LocaleKeys.signIn_or.tr(),
|
||||
color: colorScheme.onSecondary,
|
||||
),
|
||||
),
|
||||
const Expanded(child: Divider()),
|
||||
],
|
||||
),
|
||||
const VSpace(16),
|
||||
const ThirdPartySignInButtons(),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildSettingsButton(BuildContext context) {
|
||||
return FlowyButton(
|
||||
text: const FlowyText(
|
||||
'settings',
|
||||
textAlign: TextAlign.center,
|
||||
fontSize: 12.0,
|
||||
fontWeight: FontWeight.w500,
|
||||
decoration: TextDecoration.underline,
|
||||
),
|
||||
onTap: () async {
|
||||
context.push(MobileLaunchSettingsPage.routeName);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -59,6 +59,7 @@ class SignInAnonymousButton extends StatelessWidget {
|
||||
LocaleKeys.signIn_loginStartWithAnonymous.tr(),
|
||||
fontSize: 14,
|
||||
color: Theme.of(context).colorScheme.onPrimary,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
@ -51,9 +51,10 @@ class MobileSignInOrLogoutButton extends StatelessWidget {
|
||||
),
|
||||
const HSpace(8),
|
||||
],
|
||||
Text(
|
||||
FlowyText(
|
||||
labelText,
|
||||
style: Theme.of(context).textTheme.titleSmall,
|
||||
fontSize: 14.0,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
],
|
||||
),
|
||||
|
@ -23,7 +23,7 @@ class ThirdPartySignInButtons extends StatelessWidget {
|
||||
// When user changes themeMode, it changes the state in AppearanceSettingsCubit, but the themeMode for the MaterialApp won't change, it only got updated(get value from AppearanceSettingsCubit) when user open the app again. Thus, we should get themeMode from AppearanceSettingsCubit rather than MediaQuery.
|
||||
|
||||
final themeModeFromCubit =
|
||||
context.read<AppearanceSettingsCubit>().state.themeMode;
|
||||
context.watch<AppearanceSettingsCubit>().state.themeMode;
|
||||
|
||||
final isDarkMode = themeModeFromCubit == ThemeMode.system
|
||||
? MediaQuery.of(context).platformBrightness == Brightness.dark
|
||||
|
@ -440,8 +440,8 @@
|
||||
},
|
||||
"mobile": {
|
||||
"personalInfo": "Personal Information",
|
||||
"username": "Username",
|
||||
"usernameEmptyError": "Username cannot be empty",
|
||||
"username": "User Name",
|
||||
"usernameEmptyError": "User name cannot be empty",
|
||||
"about": "About",
|
||||
"pushNotifications": "Push Notifications",
|
||||
"support": "Support",
|
||||
|
Loading…
Reference in New Issue
Block a user