Skip to content

Commit 11200a5

Browse files
authored
feat: enable shared section on mobile (AppFlowy-IO#8020)
* feat: enable shared section on mobile * feat: update mobile view item * feat: shared with me section on mobile
1 parent 5598689 commit 11200a5

File tree

11 files changed

+247
-15
lines changed

11 files changed

+247
-15
lines changed
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
import 'package:appflowy/features/shared_section/data/repositories/rust_shared_pages_repository_impl.dart';
2+
import 'package:appflowy/features/shared_section/logic/shared_section_bloc.dart';
3+
import 'package:appflowy/features/shared_section/presentation/widgets/m_shared_page_list.dart';
4+
import 'package:appflowy/features/shared_section/presentation/widgets/m_shared_section_header.dart';
5+
import 'package:appflowy/features/shared_section/presentation/widgets/refresh_button.dart';
6+
import 'package:appflowy/features/shared_section/presentation/widgets/shared_section_error.dart';
7+
import 'package:appflowy/features/shared_section/presentation/widgets/shared_section_loading.dart';
8+
import 'package:appflowy/mobile/application/mobile_router.dart';
9+
import 'package:appflowy/shared/icon_emoji_picker/tab.dart';
10+
import 'package:appflowy/workspace/presentation/home/home_sizes.dart';
11+
import 'package:flowy_infra_ui/widget/spacing.dart';
12+
import 'package:flutter/foundation.dart';
13+
import 'package:flutter/material.dart';
14+
import 'package:flutter_bloc/flutter_bloc.dart';
15+
16+
class MSharedSection extends StatelessWidget {
17+
const MSharedSection({
18+
super.key,
19+
required this.workspaceId,
20+
});
21+
22+
final String workspaceId;
23+
24+
@override
25+
Widget build(BuildContext context) {
26+
final repository = RustSharePagesRepositoryImpl();
27+
28+
return BlocProvider(
29+
create: (_) => SharedSectionBloc(
30+
workspaceId: workspaceId,
31+
repository: repository,
32+
enablePolling: true,
33+
)..add(const SharedSectionInitEvent()),
34+
child: BlocBuilder<SharedSectionBloc, SharedSectionState>(
35+
builder: (context, state) {
36+
if (state.isLoading) {
37+
return const SharedSectionLoading();
38+
}
39+
40+
if (state.errorMessage.isNotEmpty) {
41+
return SharedSectionError(errorMessage: state.errorMessage);
42+
}
43+
44+
// hide the shared section if there are no shared pages
45+
if (state.sharedPages.isEmpty) {
46+
return const SizedBox.shrink();
47+
}
48+
49+
return Column(
50+
crossAxisAlignment: CrossAxisAlignment.start,
51+
children: [
52+
const VSpace(HomeSpaceViewSizes.mVerticalPadding),
53+
54+
// Shared header
55+
MSharedSectionHeader(),
56+
57+
Padding(
58+
padding: const EdgeInsets.only(
59+
left: HomeSpaceViewSizes.mHorizontalPadding,
60+
),
61+
child: MSharedPageList(
62+
sharedPages: state.sharedPages,
63+
onSelected: (view) {
64+
context.pushView(
65+
view,
66+
tabs: [
67+
PickerTabType.emoji,
68+
PickerTabType.icon,
69+
PickerTabType.custom,
70+
].map((e) => e.name).toList(),
71+
);
72+
},
73+
),
74+
),
75+
76+
// Refresh button, for debugging only
77+
if (kDebugMode)
78+
RefreshSharedSectionButton(
79+
onTap: () {
80+
context.read<SharedSectionBloc>().add(
81+
const SharedSectionEvent.refresh(),
82+
);
83+
},
84+
),
85+
],
86+
);
87+
},
88+
),
89+
);
90+
}
91+
}

frontend/appflowy_flutter/lib/features/shared_section/presentation/shared_section.dart

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
import 'package:appflowy/features/shared_section/data/repositories/rust_shared_pages_repository_impl.dart';
1+
import 'package:appflowy/features/shared_section/data/repositories/local_shared_pages_repository_impl.dart';
22
import 'package:appflowy/features/shared_section/logic/shared_section_bloc.dart';
33
import 'package:appflowy/features/shared_section/presentation/widgets/refresh_button.dart';
4-
import 'package:appflowy/features/shared_section/presentation/widgets/shared_pages_list.dart';
4+
import 'package:appflowy/features/shared_section/presentation/widgets/shared_page_list.dart';
55
import 'package:appflowy/features/shared_section/presentation/widgets/shared_section_error.dart';
66
import 'package:appflowy/features/shared_section/presentation/widgets/shared_section_header.dart';
77
import 'package:appflowy/features/shared_section/presentation/widgets/shared_section_loading.dart';
@@ -30,7 +30,8 @@ class SharedSection extends StatelessWidget {
3030

3131
@override
3232
Widget build(BuildContext context) {
33-
final repository = RustSharePagesRepositoryImpl();
33+
// final repository = RustSharePagesRepositoryImpl();
34+
final repository = LocalSharedPagesRepositoryImpl();
3435

3536
return BlocProvider(
3637
create: (_) => SharedSectionBloc(
@@ -68,7 +69,7 @@ class SharedSection extends StatelessWidget {
6869

6970
// Shared pages list
7071
if (state.isExpanded)
71-
SharedPagesList(
72+
SharedPageList(
7273
sharedPages: state.sharedPages,
7374
onSetEditing: (context, value) {
7475
context.read<ViewBloc>().add(ViewEvent.setIsEditing(value));
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import 'package:appflowy/features/shared_section/models/shared_page.dart';
2+
import 'package:appflowy/mobile/presentation/page_item/mobile_view_item.dart';
3+
import 'package:appflowy/workspace/application/sidebar/folder/folder_bloc.dart';
4+
import 'package:appflowy/workspace/presentation/home/home_sizes.dart';
5+
import 'package:flutter/material.dart';
6+
7+
/// Shared pages on mobile
8+
class MSharedPageList extends StatelessWidget {
9+
const MSharedPageList({
10+
super.key,
11+
required this.sharedPages,
12+
required this.onSelected,
13+
});
14+
15+
final SharedPages sharedPages;
16+
final ViewItemOnSelected onSelected;
17+
18+
@override
19+
Widget build(BuildContext context) {
20+
return Column(
21+
mainAxisSize: MainAxisSize.min,
22+
children: sharedPages.map((sharedPage) {
23+
final view = sharedPage.view;
24+
return MobileViewItem(
25+
key: ValueKey(view.id),
26+
spaceType: FolderSpaceType.public,
27+
isFirstChild: view.id == sharedPages.first.view.id,
28+
view: view,
29+
level: 0,
30+
isDraggable: false, // disable draggable for shared pages
31+
leftPadding: HomeSpaceViewSizes.leftPadding,
32+
isFeedback: false,
33+
onSelected: onSelected,
34+
);
35+
}).toList(),
36+
);
37+
}
38+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import 'package:appflowy/generated/flowy_svgs.g.dart';
2+
import 'package:appflowy/generated/locale_keys.g.dart';
3+
import 'package:appflowy/workspace/presentation/home/home_sizes.dart';
4+
import 'package:appflowy_ui/appflowy_ui.dart';
5+
import 'package:easy_localization/easy_localization.dart';
6+
import 'package:flowy_infra_ui/style_widget/text.dart';
7+
import 'package:flowy_infra_ui/widget/spacing.dart';
8+
import 'package:flutter/material.dart';
9+
10+
class MSharedSectionHeader extends StatelessWidget {
11+
const MSharedSectionHeader({
12+
super.key,
13+
});
14+
15+
@override
16+
Widget build(BuildContext context) {
17+
final theme = AppFlowyTheme.of(context);
18+
return SizedBox(
19+
height: 48,
20+
child: Row(
21+
children: [
22+
const HSpace(HomeSpaceViewSizes.mHorizontalPadding),
23+
FlowySvg(
24+
FlowySvgs.shared_with_me_m,
25+
color: theme.badgeColorScheme.color13Thick2,
26+
),
27+
const HSpace(10.0),
28+
FlowyText.medium(
29+
LocaleKeys.shareSection_shared.tr(),
30+
lineHeight: 1.15,
31+
fontSize: 16.0,
32+
),
33+
const HSpace(HomeSpaceViewSizes.mHorizontalPadding),
34+
],
35+
),
36+
);
37+
}
38+
}
Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,9 @@ import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
99
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
1010
import 'package:flutter/material.dart';
1111

12-
class SharedPagesList extends StatelessWidget {
13-
const SharedPagesList({
12+
/// Shared pages on desktop
13+
class SharedPageList extends StatelessWidget {
14+
const SharedPageList({
1415
super.key,
1516
required this.sharedPages,
1617
required this.onAction,
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import 'package:appflowy/generated/flowy_svgs.g.dart';
2+
import 'package:appflowy_ui/appflowy_ui.dart';
3+
import 'package:flowy_infra_ui/widget/spacing.dart';
4+
import 'package:flutter/material.dart';
5+
6+
class SharedSectionEmpty extends StatelessWidget {
7+
const SharedSectionEmpty({super.key});
8+
9+
@override
10+
Widget build(BuildContext context) {
11+
final theme = AppFlowyTheme.of(context);
12+
return Center(
13+
child: Column(
14+
mainAxisAlignment: MainAxisAlignment.center,
15+
children: [
16+
FlowySvg(
17+
FlowySvgs.empty_shared_section_m,
18+
color: theme.iconColorScheme.tertiary,
19+
),
20+
const VSpace(12),
21+
Text(
22+
'Nothing shared with you',
23+
style: theme.textStyle.heading3.enhanced(
24+
color: theme.textColorScheme.secondary,
25+
),
26+
textAlign: TextAlign.center,
27+
),
28+
const VSpace(4),
29+
Text(
30+
'Pages shared with you will show here',
31+
style: theme.textStyle.heading4.standard(
32+
color: theme.textColorScheme.tertiary,
33+
),
34+
textAlign: TextAlign.center,
35+
),
36+
const VSpace(kBottomNavigationBarHeight + 60.0),
37+
],
38+
),
39+
);
40+
}
41+
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -239,7 +239,7 @@ class _HomePageState extends State<_HomePage> {
239239
),
240240
),
241241
],
242-
child: MobileSpaceTab(
242+
child: MobileHomePageTab(
243243
userProfile: widget.userProfile,
244244
),
245245
),

frontend/appflowy_flutter/lib/mobile/presentation/home/tab/mobile_space_tab.dart

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import 'package:appflowy/features/shared_section/presentation/m_shared_section.dart';
12
import 'package:appflowy/features/workspace/logic/workspace_bloc.dart';
23
import 'package:appflowy/mobile/application/mobile_router.dart';
34
import 'package:appflowy/mobile/presentation/home/favorite_folder/favorite_space.dart';
@@ -23,19 +24,19 @@ import 'ai_bubble_button.dart';
2324

2425
final ValueNotifier<int> mobileCreateNewAIChatNotifier = ValueNotifier(0);
2526

26-
class MobileSpaceTab extends StatefulWidget {
27-
const MobileSpaceTab({
27+
class MobileHomePageTab extends StatefulWidget {
28+
const MobileHomePageTab({
2829
super.key,
2930
required this.userProfile,
3031
});
3132

3233
final UserProfilePB userProfile;
3334

3435
@override
35-
State<MobileSpaceTab> createState() => _MobileSpaceTabState();
36+
State<MobileHomePageTab> createState() => _MobileHomePageTabState();
3637
}
3738

38-
class _MobileSpaceTabState extends State<MobileSpaceTab>
39+
class _MobileHomePageTabState extends State<MobileHomePageTab>
3940
with SingleTickerProviderStateMixin {
4041
TabController? tabController;
4142

@@ -178,6 +179,18 @@ class _MobileSpaceTabState extends State<MobileSpaceTab>
178179
);
179180
case MobileSpaceTabType.favorites:
180181
return MobileFavoriteSpace(userProfile: widget.userProfile);
182+
case MobileSpaceTabType.shared:
183+
final workspaceId = context
184+
.read<UserWorkspaceBloc>()
185+
.state
186+
.currentWorkspace
187+
?.workspaceId;
188+
if (workspaceId == null) {
189+
return const SizedBox.shrink();
190+
}
191+
return MSharedSection(
192+
workspaceId: workspaceId,
193+
);
181194
}
182195
}).toList();
183196
}

frontend/appflowy_flutter/lib/mobile/presentation/home/tab/space_order_bloc.dart

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@ enum MobileSpaceTabType {
1515
// DO NOT CHANGE THE ORDER
1616
spaces,
1717
recent,
18-
favorites;
18+
favorites,
19+
shared;
1920

2021
String get tr {
2122
switch (this) {
@@ -25,6 +26,8 @@ enum MobileSpaceTabType {
2526
return LocaleKeys.sideBar_Spaces.tr();
2627
case MobileSpaceTabType.favorites:
2728
return LocaleKeys.sideBar_favoriteSpace.tr();
29+
case MobileSpaceTabType.shared:
30+
return 'Shared';
2831
}
2932
}
3033
}
@@ -89,6 +92,9 @@ class SpaceOrderBloc extends Bloc<SpaceOrderEvent, SpaceOrderState> {
8992
if (order.isEmpty) {
9093
return MobileSpaceTabType.values;
9194
}
95+
if (!order.contains(MobileSpaceTabType.shared.index)) {
96+
order.add(MobileSpaceTabType.shared.index);
97+
}
9298
return order
9399
.map((e) => MobileSpaceTabType.values[e])
94100
.cast<MobileSpaceTabType>()

frontend/appflowy_flutter/test/widget_test/lib/features/share_section/shared_pages_list_test.dart

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import 'package:appflowy/core/config/kv.dart';
22
import 'package:appflowy/features/share_tab/data/models/share_access_level.dart';
33
import 'package:appflowy/features/shared_section/models/shared_page.dart';
4-
import 'package:appflowy/features/shared_section/presentation/widgets/shared_pages_list.dart';
4+
import 'package:appflowy/features/shared_section/presentation/widgets/shared_page_list.dart';
55
import 'package:appflowy/workspace/presentation/home/menu/menu_shared_state.dart';
66
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
77
import 'package:flutter/material.dart';
@@ -47,7 +47,7 @@ void main() {
4747
await tester.pumpWidget(
4848
WidgetTestWrapper(
4949
child: SingleChildScrollView(
50-
child: SharedPagesList(
50+
child: SharedPageList(
5151
sharedPages: sharedPages,
5252
onAction: (action, view, data) {},
5353
onSelected: (context, view) {},
@@ -59,7 +59,7 @@ void main() {
5959
);
6060
expect(find.text('Page 1'), findsOneWidget);
6161
expect(find.text('Page 2'), findsOneWidget);
62-
expect(find.byType(SharedPagesList), findsOneWidget);
62+
expect(find.byType(SharedPageList), findsOneWidget);
6363
});
6464
});
6565
}

0 commit comments

Comments
 (0)