Skip to content

Commit d466bdc

Browse files
committed
feat: switch ai model on mobile
1 parent f299737 commit d466bdc

File tree

3 files changed

+161
-25
lines changed

3 files changed

+161
-25
lines changed

frontend/appflowy_flutter/lib/mobile/presentation/home/mobile_home_setting_page.dart

Lines changed: 40 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,19 @@ import 'package:appflowy/env/env.dart';
33
import 'package:appflowy/generated/locale_keys.g.dart';
44
import 'package:appflowy/mobile/presentation/base/app_bar/app_bar.dart';
55
import 'package:appflowy/mobile/presentation/presentation.dart';
6+
import 'package:appflowy/mobile/presentation/setting/ai/ai_settings_group.dart';
67
import 'package:appflowy/mobile/presentation/setting/cloud/cloud_setting_group.dart';
78
import 'package:appflowy/mobile/presentation/setting/user_session_setting_group.dart';
89
import 'package:appflowy/mobile/presentation/setting/workspace/workspace_setting_group.dart';
910
import 'package:appflowy/mobile/presentation/widgets/widgets.dart';
1011
import 'package:appflowy/startup/startup.dart';
1112
import 'package:appflowy/user/application/auth/auth_service.dart';
13+
import 'package:appflowy/workspace/application/user/user_workspace_bloc.dart';
1214
import 'package:appflowy_backend/protobuf/flowy-user/protobuf.dart';
1315
import 'package:easy_localization/easy_localization.dart';
1416
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
1517
import 'package:flutter/material.dart';
18+
import 'package:flutter_bloc/flutter_bloc.dart';
1619

1720
class MobileHomeSettingPage extends StatefulWidget {
1821
const MobileHomeSettingPage({
@@ -70,29 +73,45 @@ class _MobileHomeSettingPageState extends State<MobileHomeSettingPage> {
7073
Widget _buildSettingsWidget(UserProfilePB userProfile) {
7174
// show the third-party sign in buttons if user logged in with local session and auth is enabled.
7275

73-
final showThirdPartyLogin =
76+
final isLocalAuthEnabled =
7477
userProfile.authenticator == AuthenticatorPB.Local && isAuthEnabled;
75-
return SingleChildScrollView(
76-
child: Padding(
77-
padding: const EdgeInsets.all(16),
78-
child: Column(
79-
children: [
80-
PersonalInfoSettingGroup(
81-
userProfile: userProfile,
82-
),
83-
const WorkspaceSettingGroup(),
84-
const AppearanceSettingGroup(),
85-
const LanguageSettingGroup(),
86-
if (Env.enableCustomCloud) const CloudSettingGroup(),
87-
const SupportSettingGroup(),
88-
const AboutSettingGroup(),
89-
UserSessionSettingGroup(
90-
userProfile: userProfile,
91-
showThirdPartyLogin: showThirdPartyLogin,
78+
'';
79+
80+
return BlocProvider(
81+
create: (context) => UserWorkspaceBloc(userProfile: userProfile)
82+
..add(const UserWorkspaceEvent.initial()),
83+
child: BlocBuilder<UserWorkspaceBloc, UserWorkspaceState>(
84+
builder: (context, state) {
85+
return SingleChildScrollView(
86+
child: Padding(
87+
padding: const EdgeInsets.all(16),
88+
child: Column(
89+
children: [
90+
PersonalInfoSettingGroup(
91+
userProfile: userProfile,
92+
),
93+
const WorkspaceSettingGroup(),
94+
const AppearanceSettingGroup(),
95+
const LanguageSettingGroup(),
96+
if (Env.enableCustomCloud) const CloudSettingGroup(),
97+
if (isAuthEnabled)
98+
AiSettingsGroup(
99+
userProfile: userProfile,
100+
workspaceId: state.currentWorkspace?.workspaceId ?? '',
101+
currentWorkspaceMemberRole: state.currentWorkspace?.role,
102+
),
103+
const SupportSettingGroup(),
104+
const AboutSettingGroup(),
105+
UserSessionSettingGroup(
106+
userProfile: userProfile,
107+
showThirdPartyLogin: isLocalAuthEnabled,
108+
),
109+
const VSpace(20),
110+
],
111+
),
92112
),
93-
const VSpace(20),
94-
],
95-
),
113+
);
114+
},
96115
),
97116
);
98117
}
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
import 'package:appflowy/generated/locale_keys.g.dart';
2+
import 'package:appflowy/mobile/presentation/bottom_sheet/show_mobile_bottom_sheet.dart';
3+
import 'package:appflowy/mobile/presentation/setting/widgets/mobile_setting_group_widget.dart';
4+
import 'package:appflowy/mobile/presentation/setting/widgets/mobile_setting_item_widget.dart';
5+
import 'package:appflowy/mobile/presentation/widgets/flowy_option_tile.dart';
6+
import 'package:appflowy/workspace/application/settings/ai/settings_ai_bloc.dart';
7+
import 'package:appflowy_backend/protobuf/flowy-user/user_profile.pb.dart';
8+
import 'package:appflowy_backend/protobuf/flowy-user/workspace.pbenum.dart';
9+
import 'package:collection/collection.dart';
10+
import 'package:easy_localization/easy_localization.dart';
11+
import 'package:flowy_infra_ui/style_widget/text.dart';
12+
import 'package:flutter/material.dart';
13+
import 'package:flutter_bloc/flutter_bloc.dart';
14+
import 'package:go_router/go_router.dart';
15+
16+
class AiSettingsGroup extends StatelessWidget {
17+
const AiSettingsGroup({
18+
super.key,
19+
required this.userProfile,
20+
required this.workspaceId,
21+
this.currentWorkspaceMemberRole,
22+
});
23+
24+
final UserProfilePB userProfile;
25+
final String workspaceId;
26+
final AFRolePB? currentWorkspaceMemberRole;
27+
28+
@override
29+
Widget build(BuildContext context) {
30+
final theme = Theme.of(context);
31+
return BlocProvider(
32+
create: (context) => SettingsAIBloc(
33+
userProfile,
34+
workspaceId,
35+
currentWorkspaceMemberRole,
36+
)..add(const SettingsAIEvent.started()),
37+
child: BlocBuilder<SettingsAIBloc, SettingsAIState>(
38+
builder: (context, state) {
39+
return MobileSettingGroup(
40+
groupTitle: LocaleKeys.settings_aiPage_title.tr(),
41+
settingItemList: [
42+
MobileSettingItem(
43+
name: LocaleKeys.settings_aiPage_keys_llmModelType.tr(),
44+
trailing: Row(
45+
mainAxisSize: MainAxisSize.min,
46+
children: [
47+
FlowyText(
48+
state.selectedAIModel,
49+
color: theme.colorScheme.onSurface,
50+
),
51+
const Icon(Icons.chevron_right),
52+
],
53+
),
54+
onTap: () => _onLLMModelTypeTap(context, state),
55+
),
56+
// enable AI search if needed
57+
// MobileSettingItem(
58+
// name: LocaleKeys.settings_aiPage_keys_enableAISearchTitle.tr(),
59+
// trailing: const Icon(
60+
// Icons.chevron_right,
61+
// ),
62+
// onTap: () => context.push(AppFlowyCloudPage.routeName),
63+
// ),
64+
],
65+
);
66+
},
67+
),
68+
);
69+
}
70+
71+
void _onEnableAISearchTap(BuildContext context) {}
72+
73+
void _onLLMModelTypeTap(BuildContext context, SettingsAIState state) {
74+
final availableModels = state.availableModels;
75+
showMobileBottomSheet(
76+
context,
77+
showHeader: true,
78+
showDragHandle: true,
79+
showDivider: false,
80+
title: LocaleKeys.settings_aiPage_keys_llmModelType.tr(),
81+
builder: (_) {
82+
return Column(
83+
children: availableModels
84+
.mapIndexed(
85+
(index, model) => FlowyOptionTile.checkbox(
86+
text: model,
87+
showTopBorder: index == 0,
88+
isSelected: state.selectedAIModel == model,
89+
onTap: () {
90+
context
91+
.read<SettingsAIBloc>()
92+
.add(SettingsAIEvent.selectModel(model));
93+
context.pop();
94+
},
95+
),
96+
)
97+
.toList(),
98+
);
99+
},
100+
);
101+
}
102+
}

frontend/appflowy_flutter/lib/workspace/application/settings/ai/settings_ai_bloc.dart

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,17 @@ class SettingsAIBloc extends Bloc<SettingsAIEvent, SettingsAIState> {
8484
);
8585
},
8686
selectModel: (String model) {
87-
_updateUserWorkspaceSetting(model: model);
87+
final result = _updateUserWorkspaceSetting(model: model);
88+
result.fold(
89+
(success) {
90+
emit(
91+
state.copyWith(
92+
selectedAIModel: model,
93+
),
94+
);
95+
},
96+
(_) {},
97+
);
8898
},
8999
didLoadAISetting: (UseAISettingPB settings) {
90100
emit(
@@ -129,10 +139,10 @@ class SettingsAIBloc extends Bloc<SettingsAIEvent, SettingsAIState> {
129139
});
130140
}
131141

132-
void _updateUserWorkspaceSetting({
142+
Future<FlowyResult<void, FlowyError>> _updateUserWorkspaceSetting({
133143
bool? disableSearchIndexing,
134144
String? model,
135-
}) {
145+
}) async {
136146
final payload = UpdateUserWorkspaceSettingPB(
137147
workspaceId: workspaceId,
138148
);
@@ -142,7 +152,12 @@ class SettingsAIBloc extends Bloc<SettingsAIEvent, SettingsAIState> {
142152
if (model != null) {
143153
payload.aiModel = model;
144154
}
145-
UserEventUpdateWorkspaceSetting(payload).send();
155+
final result = await UserEventUpdateWorkspaceSetting(payload).send();
156+
result.fold(
157+
(ok) => Log.info('Update workspace setting success'),
158+
(err) => Log.error('Update workspace setting failed: $err'),
159+
);
160+
return result;
146161
}
147162

148163
void _onProfileUpdated(

0 commit comments

Comments
 (0)