mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2025-11-02 02:53:59 +00:00
feat: switch ai mode on mobile (#7391)
* fix: the default page name should be empty when creating * feat: switch ai model on mobile
This commit is contained in:
parent
15b4d496fd
commit
55fbb7522b
@ -3,16 +3,19 @@ import 'package:appflowy/env/env.dart';
|
||||
import 'package:appflowy/generated/locale_keys.g.dart';
|
||||
import 'package:appflowy/mobile/presentation/base/app_bar/app_bar.dart';
|
||||
import 'package:appflowy/mobile/presentation/presentation.dart';
|
||||
import 'package:appflowy/mobile/presentation/setting/ai/ai_settings_group.dart';
|
||||
import 'package:appflowy/mobile/presentation/setting/cloud/cloud_setting_group.dart';
|
||||
import 'package:appflowy/mobile/presentation/setting/user_session_setting_group.dart';
|
||||
import 'package:appflowy/mobile/presentation/setting/workspace/workspace_setting_group.dart';
|
||||
import 'package:appflowy/mobile/presentation/widgets/widgets.dart';
|
||||
import 'package:appflowy/startup/startup.dart';
|
||||
import 'package:appflowy/user/application/auth/auth_service.dart';
|
||||
import 'package:appflowy/workspace/application/user/user_workspace_bloc.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-user/protobuf.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
|
||||
class MobileHomeSettingPage extends StatefulWidget {
|
||||
const MobileHomeSettingPage({
|
||||
@ -70,29 +73,47 @@ class _MobileHomeSettingPageState extends State<MobileHomeSettingPage> {
|
||||
Widget _buildSettingsWidget(UserProfilePB userProfile) {
|
||||
// show the third-party sign in buttons if user logged in with local session and auth is enabled.
|
||||
|
||||
final showThirdPartyLogin =
|
||||
final isLocalAuthEnabled =
|
||||
userProfile.authenticator == AuthenticatorPB.Local && isAuthEnabled;
|
||||
return SingleChildScrollView(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: Column(
|
||||
children: [
|
||||
PersonalInfoSettingGroup(
|
||||
userProfile: userProfile,
|
||||
'';
|
||||
|
||||
return BlocProvider(
|
||||
create: (context) => UserWorkspaceBloc(userProfile: userProfile)
|
||||
..add(const UserWorkspaceEvent.initial()),
|
||||
child: BlocBuilder<UserWorkspaceBloc, UserWorkspaceState>(
|
||||
builder: (context, state) {
|
||||
final currentWorkspaceId = state.currentWorkspace?.workspaceId ?? '';
|
||||
return SingleChildScrollView(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: Column(
|
||||
children: [
|
||||
PersonalInfoSettingGroup(
|
||||
userProfile: userProfile,
|
||||
),
|
||||
const WorkspaceSettingGroup(),
|
||||
const AppearanceSettingGroup(),
|
||||
const LanguageSettingGroup(),
|
||||
if (Env.enableCustomCloud) const CloudSettingGroup(),
|
||||
if (isAuthEnabled)
|
||||
AiSettingsGroup(
|
||||
key: ValueKey(currentWorkspaceId),
|
||||
userProfile: userProfile,
|
||||
workspaceId: currentWorkspaceId,
|
||||
currentWorkspaceMemberRole: state.currentWorkspace?.role,
|
||||
),
|
||||
const SupportSettingGroup(),
|
||||
const AboutSettingGroup(),
|
||||
UserSessionSettingGroup(
|
||||
userProfile: userProfile,
|
||||
showThirdPartyLogin: isLocalAuthEnabled,
|
||||
),
|
||||
const VSpace(20),
|
||||
],
|
||||
),
|
||||
),
|
||||
const WorkspaceSettingGroup(),
|
||||
const AppearanceSettingGroup(),
|
||||
const LanguageSettingGroup(),
|
||||
if (Env.enableCustomCloud) const CloudSettingGroup(),
|
||||
const SupportSettingGroup(),
|
||||
const AboutSettingGroup(),
|
||||
UserSessionSettingGroup(
|
||||
userProfile: userProfile,
|
||||
showThirdPartyLogin: showThirdPartyLogin,
|
||||
),
|
||||
const VSpace(20),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@ -0,0 +1,106 @@
|
||||
import 'package:appflowy/generated/locale_keys.g.dart';
|
||||
import 'package:appflowy/mobile/presentation/bottom_sheet/show_mobile_bottom_sheet.dart';
|
||||
import 'package:appflowy/mobile/presentation/setting/widgets/mobile_setting_group_widget.dart';
|
||||
import 'package:appflowy/mobile/presentation/setting/widgets/mobile_setting_item_widget.dart';
|
||||
import 'package:appflowy/mobile/presentation/widgets/flowy_option_tile.dart';
|
||||
import 'package:appflowy/workspace/application/settings/ai/settings_ai_bloc.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-user/user_profile.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-user/workspace.pbenum.dart';
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flowy_infra_ui/style_widget/text.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
|
||||
class AiSettingsGroup extends StatelessWidget {
|
||||
const AiSettingsGroup({
|
||||
super.key,
|
||||
required this.userProfile,
|
||||
required this.workspaceId,
|
||||
this.currentWorkspaceMemberRole,
|
||||
});
|
||||
|
||||
final UserProfilePB userProfile;
|
||||
final String workspaceId;
|
||||
final AFRolePB? currentWorkspaceMemberRole;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final theme = Theme.of(context);
|
||||
return BlocProvider(
|
||||
create: (context) => SettingsAIBloc(
|
||||
userProfile,
|
||||
workspaceId,
|
||||
currentWorkspaceMemberRole,
|
||||
)..add(const SettingsAIEvent.started()),
|
||||
child: BlocBuilder<SettingsAIBloc, SettingsAIState>(
|
||||
builder: (context, state) {
|
||||
return MobileSettingGroup(
|
||||
groupTitle: LocaleKeys.settings_aiPage_title.tr(),
|
||||
settingItemList: [
|
||||
MobileSettingItem(
|
||||
name: LocaleKeys.settings_aiPage_keys_llmModelType.tr(),
|
||||
trailing: ConstrainedBox(
|
||||
constraints: const BoxConstraints(maxWidth: 200),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Flexible(
|
||||
child: FlowyText(
|
||||
state.selectedAIModel,
|
||||
color: theme.colorScheme.onSurface,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
const Icon(Icons.chevron_right),
|
||||
],
|
||||
),
|
||||
),
|
||||
onTap: () => _onLLMModelTypeTap(context, state),
|
||||
),
|
||||
// enable AI search if needed
|
||||
// MobileSettingItem(
|
||||
// name: LocaleKeys.settings_aiPage_keys_enableAISearchTitle.tr(),
|
||||
// trailing: const Icon(
|
||||
// Icons.chevron_right,
|
||||
// ),
|
||||
// onTap: () => context.push(AppFlowyCloudPage.routeName),
|
||||
// ),
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _onLLMModelTypeTap(BuildContext context, SettingsAIState state) {
|
||||
final availableModels = state.availableModels;
|
||||
showMobileBottomSheet(
|
||||
context,
|
||||
showHeader: true,
|
||||
showDragHandle: true,
|
||||
showDivider: false,
|
||||
title: LocaleKeys.settings_aiPage_keys_llmModelType.tr(),
|
||||
builder: (_) {
|
||||
return Column(
|
||||
children: availableModels
|
||||
.mapIndexed(
|
||||
(index, model) => FlowyOptionTile.checkbox(
|
||||
text: model,
|
||||
showTopBorder: index == 0,
|
||||
isSelected: state.selectedAIModel == model,
|
||||
onTap: () {
|
||||
context
|
||||
.read<SettingsAIBloc>()
|
||||
.add(SettingsAIEvent.selectModel(model));
|
||||
context.pop();
|
||||
},
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -91,7 +91,9 @@ class FavoriteBloc extends Bloc<FavoriteEvent, FavoriteState> {
|
||||
await _service.toggleFavorite(view.item.id);
|
||||
await _service.toggleFavorite(view.item.id);
|
||||
}
|
||||
add(const FavoriteEvent.fetchFavorites());
|
||||
if (!isClosed) {
|
||||
add(const FavoriteEvent.fetchFavorites());
|
||||
}
|
||||
isReordering = false;
|
||||
},
|
||||
);
|
||||
|
||||
@ -57,8 +57,8 @@ class SettingsAIBloc extends Bloc<SettingsAIEvent, SettingsAIState> {
|
||||
}
|
||||
|
||||
void _dispatch() {
|
||||
on<SettingsAIEvent>((event, emit) {
|
||||
event.when(
|
||||
on<SettingsAIEvent>((event, emit) async {
|
||||
await event.when(
|
||||
started: () {
|
||||
_userListener.start(
|
||||
onProfileUpdated: _onProfileUpdated,
|
||||
@ -83,13 +83,14 @@ class SettingsAIBloc extends Bloc<SettingsAIEvent, SettingsAIState> {
|
||||
!(state.aiSettings?.disableSearchIndexing ?? false),
|
||||
);
|
||||
},
|
||||
selectModel: (String model) {
|
||||
_updateUserWorkspaceSetting(model: model);
|
||||
selectModel: (String model) async {
|
||||
await _updateUserWorkspaceSetting(model: model);
|
||||
},
|
||||
didLoadAISetting: (UseAISettingPB settings) {
|
||||
emit(
|
||||
state.copyWith(
|
||||
aiSettings: settings,
|
||||
selectedAIModel: settings.aiModel,
|
||||
enableSearchIndexing: !settings.disableSearchIndexing,
|
||||
),
|
||||
);
|
||||
@ -129,10 +130,10 @@ class SettingsAIBloc extends Bloc<SettingsAIEvent, SettingsAIState> {
|
||||
});
|
||||
}
|
||||
|
||||
void _updateUserWorkspaceSetting({
|
||||
Future<FlowyResult<void, FlowyError>> _updateUserWorkspaceSetting({
|
||||
bool? disableSearchIndexing,
|
||||
String? model,
|
||||
}) {
|
||||
}) async {
|
||||
final payload = UpdateUserWorkspaceSettingPB(
|
||||
workspaceId: workspaceId,
|
||||
);
|
||||
@ -142,7 +143,12 @@ class SettingsAIBloc extends Bloc<SettingsAIEvent, SettingsAIState> {
|
||||
if (model != null) {
|
||||
payload.aiModel = model;
|
||||
}
|
||||
UserEventUpdateWorkspaceSetting(payload).send();
|
||||
final result = await UserEventUpdateWorkspaceSetting(payload).send();
|
||||
result.fold(
|
||||
(ok) => Log.info('Update workspace setting success'),
|
||||
(err) => Log.error('Update workspace setting failed: $err'),
|
||||
);
|
||||
return result;
|
||||
}
|
||||
|
||||
void _onProfileUpdated(
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user