mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
feat: add ai bubble button on mobile home page (#5992)
* chore: skip check list test if the task is not found
* feat: add ai bubble button in home page
* feat: only show the ai bubble button for the cloud user
* chore: add border color to ai bubble button
* Revert "chore: skip check list test if the task is not found"
This reverts commit 961f594a31
.
* fix: only display ai bubble button on home page
This commit is contained in:
parent
d0ce65f711
commit
e460120a1c
@ -134,7 +134,27 @@ class _MobileHomePageState extends State<MobileHomePage> {
|
||||
value: getIt<ReminderBloc>()..add(const ReminderEvent.started()),
|
||||
),
|
||||
],
|
||||
child: BlocConsumer<UserWorkspaceBloc, UserWorkspaceState>(
|
||||
child: _HomePage(userProfile: widget.userProfile),
|
||||
);
|
||||
}
|
||||
|
||||
void _onLatestViewChange() async {
|
||||
final id = getIt<MenuSharedState>().latestOpenView?.id;
|
||||
if (id == null) {
|
||||
return;
|
||||
}
|
||||
await FolderEventSetLatestView(ViewIdPB(value: id)).send();
|
||||
}
|
||||
}
|
||||
|
||||
class _HomePage extends StatelessWidget {
|
||||
const _HomePage({required this.userProfile});
|
||||
|
||||
final UserProfilePB userProfile;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return BlocConsumer<UserWorkspaceBloc, UserWorkspaceState>(
|
||||
buildWhen: (previous, current) =>
|
||||
previous.currentWorkspace?.workspaceId !=
|
||||
current.currentWorkspace?.workspaceId,
|
||||
@ -159,7 +179,7 @@ class _MobileHomePageState extends State<MobileHomePage> {
|
||||
top: Platform.isAndroid ? 8.0 : 0.0,
|
||||
),
|
||||
child: MobileHomePageHeader(
|
||||
userProfile: widget.userProfile,
|
||||
userProfile: userProfile,
|
||||
),
|
||||
),
|
||||
|
||||
@ -167,14 +187,14 @@ class _MobileHomePageState extends State<MobileHomePage> {
|
||||
child: MultiBlocProvider(
|
||||
providers: [
|
||||
BlocProvider(
|
||||
create: (_) => SpaceOrderBloc()
|
||||
..add(const SpaceOrderEvent.initial()),
|
||||
create: (_) =>
|
||||
SpaceOrderBloc()..add(const SpaceOrderEvent.initial()),
|
||||
),
|
||||
BlocProvider(
|
||||
create: (_) => SidebarSectionsBloc()
|
||||
..add(
|
||||
SidebarSectionsEvent.initial(
|
||||
widget.userProfile,
|
||||
userProfile,
|
||||
workspaceId,
|
||||
),
|
||||
),
|
||||
@ -187,7 +207,7 @@ class _MobileHomePageState extends State<MobileHomePage> {
|
||||
create: (_) => SpaceBloc()
|
||||
..add(
|
||||
SpaceEvent.initial(
|
||||
widget.userProfile,
|
||||
userProfile,
|
||||
workspaceId,
|
||||
openFirstPage: false,
|
||||
),
|
||||
@ -195,22 +215,13 @@ class _MobileHomePageState extends State<MobileHomePage> {
|
||||
),
|
||||
],
|
||||
child: MobileSpaceTab(
|
||||
userProfile: widget.userProfile,
|
||||
userProfile: userProfile,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _onLatestViewChange() async {
|
||||
final id = getIt<MenuSharedState>().latestOpenView?.id;
|
||||
if (id == null) {
|
||||
return;
|
||||
}
|
||||
await FolderEventSetLatestView(ViewIdPB(value: id)).send();
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,81 @@
|
||||
import 'package:appflowy/generated/flowy_svgs.g.dart';
|
||||
import 'package:appflowy/generated/locale_keys.g.dart';
|
||||
import 'package:appflowy/mobile/presentation/base/gesture.dart';
|
||||
import 'package:appflowy/mobile/presentation/home/tab/mobile_space_tab.dart';
|
||||
import 'package:appflowy/util/theme_extension.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class FloatingAIEntry extends StatelessWidget {
|
||||
const FloatingAIEntry({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return AnimatedGestureDetector(
|
||||
scaleFactor: 0.99,
|
||||
onTapUp: () => mobileCreateNewAIChatNotifier.value =
|
||||
mobileCreateNewAIChatNotifier.value + 1,
|
||||
child: DecoratedBox(
|
||||
decoration: _buildShadowDecoration(context),
|
||||
child: Container(
|
||||
decoration: _buildWrapperDecoration(context),
|
||||
height: 48,
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(left: 18),
|
||||
child: _buildHintText(context),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
BoxDecoration _buildShadowDecoration(BuildContext context) {
|
||||
return BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(30),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
blurRadius: 20,
|
||||
spreadRadius: 1,
|
||||
offset: const Offset(0, 4),
|
||||
color: Colors.black.withOpacity(0.05),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
BoxDecoration _buildWrapperDecoration(BuildContext context) {
|
||||
final outlineColor = Theme.of(context).colorScheme.outline;
|
||||
final borderColor = Theme.of(context).isLightMode
|
||||
? outlineColor.withOpacity(0.7)
|
||||
: outlineColor.withOpacity(0.3);
|
||||
return BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(30),
|
||||
color: Theme.of(context).colorScheme.surface,
|
||||
border: Border.fromBorderSide(
|
||||
BorderSide(
|
||||
color: borderColor,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildHintText(BuildContext context) {
|
||||
return Row(
|
||||
children: [
|
||||
FlowySvg(
|
||||
FlowySvgs.toolbar_item_ai_s,
|
||||
size: const Size.square(16.0),
|
||||
color: Theme.of(context).hintColor,
|
||||
opacity: 0.7,
|
||||
),
|
||||
const HSpace(8),
|
||||
FlowyText(
|
||||
LocaleKeys.chat_inputMessageHint.tr(),
|
||||
color: Theme.of(context).hintColor,
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
@ -20,6 +20,10 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
import 'ai_bubble_button.dart';
|
||||
|
||||
final ValueNotifier<int> mobileCreateNewAIChatNotifier = ValueNotifier(0);
|
||||
|
||||
class MobileSpaceTab extends StatefulWidget {
|
||||
const MobileSpaceTab({
|
||||
super.key,
|
||||
@ -40,7 +44,8 @@ class _MobileSpaceTabState extends State<MobileSpaceTab>
|
||||
void initState() {
|
||||
super.initState();
|
||||
|
||||
mobileCreateNewPageNotifier.addListener(_createNewPage);
|
||||
mobileCreateNewPageNotifier.addListener(_createNewDocument);
|
||||
mobileCreateNewAIChatNotifier.addListener(_createNewAIChat);
|
||||
mobileLeaveWorkspaceNotifier.addListener(_leaveWorkspace);
|
||||
}
|
||||
|
||||
@ -48,7 +53,9 @@ class _MobileSpaceTabState extends State<MobileSpaceTab>
|
||||
void dispose() {
|
||||
tabController?.removeListener(_onTabChange);
|
||||
tabController?.dispose();
|
||||
mobileCreateNewPageNotifier.removeListener(_createNewPage);
|
||||
|
||||
mobileCreateNewPageNotifier.removeListener(_createNewDocument);
|
||||
mobileCreateNewAIChatNotifier.removeListener(_createNewAIChat);
|
||||
mobileLeaveWorkspaceNotifier.removeListener(_leaveWorkspace);
|
||||
|
||||
super.dispose();
|
||||
@ -145,7 +152,20 @@ class _MobileSpaceTabState extends State<MobileSpaceTab>
|
||||
case MobileSpaceTabType.recent:
|
||||
return const MobileRecentSpace();
|
||||
case MobileSpaceTabType.spaces:
|
||||
return MobileHomeSpace(userProfile: widget.userProfile);
|
||||
return Stack(
|
||||
children: [
|
||||
MobileHomeSpace(userProfile: widget.userProfile),
|
||||
// only show ai chat button for cloud user
|
||||
if (widget.userProfile.authenticator ==
|
||||
AuthenticatorPB.AppFlowyCloud)
|
||||
Positioned(
|
||||
bottom: MediaQuery.of(context).padding.bottom + 16,
|
||||
left: 20,
|
||||
right: 20,
|
||||
child: const FloatingAIEntry(),
|
||||
),
|
||||
],
|
||||
);
|
||||
case MobileSpaceTabType.favorites:
|
||||
return MobileFavoriteSpace(userProfile: widget.userProfile);
|
||||
default:
|
||||
@ -155,15 +175,24 @@ class _MobileSpaceTabState extends State<MobileSpaceTab>
|
||||
}
|
||||
|
||||
// quick create new page when clicking the add button in navigation bar
|
||||
void _createNewPage() {
|
||||
void _createNewDocument() {
|
||||
_createNewPage(ViewLayoutPB.Document);
|
||||
}
|
||||
|
||||
void _createNewAIChat() {
|
||||
_createNewPage(ViewLayoutPB.Chat);
|
||||
}
|
||||
|
||||
void _createNewPage(ViewLayoutPB layout) {
|
||||
if (context.read<SpaceBloc>().state.spaces.isNotEmpty) {
|
||||
context.read<SpaceBloc>().add(
|
||||
SpaceEvent.createPage(
|
||||
name: LocaleKeys.menuAppHeader_defaultNewPageName.tr(),
|
||||
layout: ViewLayoutPB.Document,
|
||||
layout: layout,
|
||||
),
|
||||
);
|
||||
} else {
|
||||
} else if (layout == ViewLayoutPB.Document) {
|
||||
// only support create document in section
|
||||
context.read<SidebarSectionsBloc>().add(
|
||||
SidebarSectionsEvent.createRootViewInSection(
|
||||
name: LocaleKeys.menuAppHeader_defaultNewPageName.tr(),
|
||||
|
@ -73,6 +73,7 @@ class ChatWelcomePage extends StatelessWidget {
|
||||
const VSpace(8),
|
||||
Wrap(
|
||||
direction: Axis.vertical,
|
||||
spacing: isMobile ? 12.0 : 0.0,
|
||||
children: items
|
||||
.map(
|
||||
(i) => WelcomeQuestionWidget(
|
||||
|
Loading…
Reference in New Issue
Block a user