Skip to content

Commit 75beaaf

Browse files
authored
Merge pull request #475 from OpenPecha/feat/ChantsShare
Feat/chants share
2 parents 48d492c + 715ef66 commit 75beaaf

8 files changed

Lines changed: 85 additions & 51 deletions

File tree

lib/core/deep_linking/deep_link_url_builder.dart

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,16 @@ class DeepLinkUrlBuilder {
33

44
static const String _host = 'webuddhist.com';
55

6+
/// Returns a link that opens the reader at the very first segment —
7+
/// i.e. no segment/lang params so the app starts from the top.
8+
static Uri readerLink({required String textId}) {
9+
return Uri(
10+
scheme: 'https',
11+
host: _host,
12+
pathSegments: ['open', 'reader', textId],
13+
);
14+
}
15+
616
static Uri seriesLink({required String seriesId}) {
717
return Uri(
818
scheme: 'https',

lib/features/home/presentation/widgets/home_shortcuts_row.dart

Lines changed: 1 addition & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,6 @@ import 'package:flutter_pecha/features/home/domain/entities/series.dart';
66
import 'package:flutter_pecha/features/practice/presentation/providers/practice_explore_providers.dart';
77
import 'package:flutter_pecha/features/practice/presentation/screens/all_plans_screen.dart';
88
import 'package:flutter_pecha/features/practice/presentation/screens/all_recitations_screen.dart';
9-
import 'package:flutter_pecha/features/reader/data/models/navigation_context.dart';
10-
import 'package:flutter_pecha/features/recitation/data/models/recitation_model.dart';
119
import 'package:flutter_pecha/shared/utils/helper_functions.dart';
1210
import 'package:flutter_riverpod/flutter_riverpod.dart';
1311
import 'package:go_router/go_router.dart';
@@ -54,21 +52,9 @@ class HomeShortcutsRow extends ConsumerWidget {
5452
});
5553
}
5654

57-
void _navigateToRecitation(BuildContext context, RecitationModel recitation) {
58-
final navigationContext = NavigationContext(
59-
source: NavigationSource.normal,
60-
);
61-
context.push('/reader/${recitation.textId}', extra: navigationContext);
62-
}
63-
6455
void _onChantsTap(BuildContext context, WidgetRef ref) {
6556
Navigator.of(context).push(
66-
MaterialPageRoute(
67-
builder:
68-
(_) => AllRecitationsScreen(
69-
onTap: (r) => _navigateToRecitation(context, r),
70-
),
71-
),
57+
MaterialPageRoute(builder: (_) => const AllRecitationsScreen()),
7258
);
7359
}
7460

lib/features/practice/presentation/screens/all_recitations_screen.dart

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,13 @@ import 'package:flutter_pecha/core/extensions/context_ext.dart';
33
import 'package:flutter_pecha/core/widgets/error_state_widget.dart';
44
import 'package:flutter_pecha/features/practice/presentation/providers/practice_recitations_paginated_provider.dart';
55
import 'package:flutter_pecha/features/practice/presentation/screens/recitations_search_screen.dart';
6+
import 'package:flutter_pecha/features/practice/presentation/utils/recitation_reader_navigation.dart';
67
import 'package:flutter_pecha/features/practice/presentation/widgets/practice_chant_list_tile.dart';
7-
import 'package:flutter_pecha/features/recitation/data/models/recitation_model.dart';
88
import 'package:flutter_pecha/features/recitation/presentation/widgets/recitation_list_skeleton.dart';
99
import 'package:flutter_riverpod/flutter_riverpod.dart';
1010

1111
class AllRecitationsScreen extends ConsumerStatefulWidget {
12-
const AllRecitationsScreen({super.key, required this.onTap});
13-
14-
final ValueChanged<RecitationModel> onTap;
12+
const AllRecitationsScreen({super.key});
1513

1614
@override
1715
ConsumerState<AllRecitationsScreen> createState() =>
@@ -43,7 +41,7 @@ class _AllRecitationsScreenState extends ConsumerState<AllRecitationsScreen> {
4341

4442
void _openSearch(BuildContext context) {
4543
Navigator.of(context).push(
46-
MaterialPageRoute(builder: (_) => RecitationsSearchScreen(onTap: widget.onTap)),
44+
MaterialPageRoute(builder: (_) => const RecitationsSearchScreen()),
4745
);
4846
}
4947

@@ -111,7 +109,7 @@ class _AllRecitationsScreenState extends ConsumerState<AllRecitationsScreen> {
111109
final recitation = state.recitations[index];
112110
return PracticeChantListTile(
113111
recitation: recitation,
114-
onTap: () => widget.onTap(recitation),
112+
onTap: () => openRecitationReader(context, recitation),
115113
);
116114
},
117115
);

lib/features/practice/presentation/screens/recitations_search_screen.dart

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,15 @@
11
import 'package:flutter/material.dart';
22
import 'package:flutter_pecha/core/extensions/context_ext.dart';
33
import 'package:flutter_pecha/core/theme/app_colors.dart';
4+
import 'package:flutter_pecha/features/practice/presentation/utils/recitation_reader_navigation.dart';
45
import 'package:flutter_pecha/features/practice/presentation/widgets/practice_chant_list_tile.dart';
5-
import 'package:flutter_pecha/features/recitation/data/models/recitation_model.dart';
66
import 'package:flutter_pecha/features/recitation/presentation/providers/recitation_search_provider.dart';
77
import 'package:flutter_pecha/features/recitation/presentation/providers/recitations_providers.dart';
88
import 'package:flutter_pecha/features/recitation/presentation/widgets/recitation_list_skeleton.dart';
99
import 'package:flutter_riverpod/flutter_riverpod.dart';
1010

1111
class RecitationsSearchScreen extends ConsumerStatefulWidget {
12-
const RecitationsSearchScreen({super.key, required this.onTap});
13-
14-
final ValueChanged<RecitationModel> onTap;
12+
const RecitationsSearchScreen({super.key});
1513

1614
@override
1715
ConsumerState<RecitationsSearchScreen> createState() =>
@@ -205,7 +203,7 @@ class _RecitationsSearchScreenState
205203
final recitation = searchState.results[index];
206204
return PracticeChantListTile(
207205
recitation: recitation,
208-
onTap: () => widget.onTap(recitation),
206+
onTap: () => openRecitationReader(context, recitation),
209207
);
210208
},
211209
);
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import 'package:flutter/material.dart';
2+
import 'package:flutter_pecha/features/reader/data/models/navigation_context.dart';
3+
import 'package:flutter_pecha/features/recitation/data/models/recitation_model.dart';
4+
import 'package:go_router/go_router.dart';
5+
6+
/// Opens a chant/recitation in the shared reader with practice-context actions
7+
/// (e.g. "Add to my practices" in the more menu).
8+
void openRecitationReader(BuildContext context, RecitationModel recitation) {
9+
context.push(
10+
'/reader/${recitation.textId}',
11+
extra: const NavigationContext(source: NavigationSource.recitationList),
12+
);
13+
}

lib/features/practice/presentation/widgets/practice_chants_section.dart

Lines changed: 4 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,11 @@ import 'package:flutter/material.dart';
22
import 'package:flutter_pecha/core/extensions/context_ext.dart';
33
import 'package:flutter_pecha/features/practice/presentation/providers/practice_explore_providers.dart';
44
import 'package:flutter_pecha/features/practice/presentation/screens/all_recitations_screen.dart';
5+
import 'package:flutter_pecha/features/practice/presentation/utils/recitation_reader_navigation.dart';
56
import 'package:flutter_pecha/features/practice/presentation/widgets/practice_chant_list_tile.dart';
67
import 'package:flutter_pecha/features/practice/presentation/widgets/practice_section_container.dart';
78
import 'package:flutter_pecha/features/practice/presentation/widgets/practice_section_skeleton.dart';
8-
import 'package:flutter_pecha/features/reader/data/models/navigation_context.dart';
9-
import 'package:flutter_pecha/features/recitation/data/models/recitation_model.dart';
109
import 'package:flutter_riverpod/flutter_riverpod.dart';
11-
import 'package:go_router/go_router.dart';
1210

1311
class PracticeChantsSection extends ConsumerWidget {
1412
const PracticeChantsSection({super.key});
@@ -38,7 +36,8 @@ class PracticeChantsSection extends ConsumerWidget {
3836
.map(
3937
(r) => PracticeChantListTile(
4038
recitation: r,
41-
onTap: () => _navigateToRecitation(context, r),
39+
onTap:
40+
() => openRecitationReader(context, r),
4241
),
4342
)
4443
.toList(),
@@ -57,21 +56,9 @@ class PracticeChantsSection extends ConsumerWidget {
5756
);
5857
}
5958

60-
void _navigateToRecitation(BuildContext context, RecitationModel recitation) {
61-
final navigationContext = NavigationContext(
62-
source: NavigationSource.recitationList,
63-
);
64-
context.push('/reader/${recitation.textId}', extra: navigationContext);
65-
}
66-
6759
void _showAllRecitations(BuildContext context) {
6860
Navigator.of(context).push(
69-
MaterialPageRoute(
70-
builder:
71-
(_) => AllRecitationsScreen(
72-
onTap: (r) => _navigateToRecitation(context, r),
73-
),
74-
),
61+
MaterialPageRoute(builder: (_) => const AllRecitationsScreen()),
7562
);
7663
}
7764
}

lib/features/reader/presentation/widgets/reader_app_bar/reader_more_bottom_sheet.dart

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
11
import 'package:flutter/material.dart';
22
import 'package:flutter/services.dart';
33
import 'package:flutter_pecha/core/constants/app_assets.dart';
4+
import 'package:flutter_pecha/core/deep_linking/deep_link_url_builder.dart';
45
import 'package:flutter_pecha/core/extensions/context_ext.dart';
56
import 'package:flutter_pecha/features/practice/data/datasource/bookmark_remote_datasource.dart';
67
import 'package:flutter_pecha/features/practice/presentation/controllers/bookmark_controller.dart';
78
import 'package:flutter_pecha/features/practice/presentation/providers/bookmark_providers.dart';
89
import 'package:flutter_pecha/features/reader/presentation/widgets/reader_app_bar/reader_font_size_bottom_sheet.dart';
910
import 'package:flutter_pecha/features/texts/presentation/providers/font_size_notifier.dart';
11+
import 'package:flutter_pecha/shared/utils/helper_functions.dart';
1012
import 'package:flutter_riverpod/flutter_riverpod.dart';
13+
import 'package:share_plus/share_plus.dart';
1114

1215
/// Bottom sheet opened from the reader's three-dot (⋮) button.
1316
///
@@ -34,6 +37,7 @@ class ReaderMoreBottomSheet extends ConsumerStatefulWidget {
3437

3538
class _ReaderMoreBottomSheetState extends ConsumerState<ReaderMoreBottomSheet> {
3639
bool _isBookmarking = false;
40+
bool _isSharing = false;
3741

3842
BookmarkTarget get _bookmarkTarget => BookmarkTarget(
3943
type: BookmarkType.text,
@@ -55,6 +59,23 @@ class _ReaderMoreBottomSheetState extends ConsumerState<ReaderMoreBottomSheet> {
5559
}
5660
}
5761

62+
Future<void> _share() async {
63+
if (_isSharing) return;
64+
setState(() => _isSharing = true);
65+
try {
66+
final shareUrl =
67+
DeepLinkUrlBuilder.readerLink(textId: widget.textId).toString();
68+
if (!mounted) return;
69+
final sharePositionOrigin = getSharePositionOrigin(context: context);
70+
await SharePlus.instance.share(
71+
ShareParams(text: shareUrl, sharePositionOrigin: sharePositionOrigin),
72+
);
73+
if (mounted) Navigator.of(context).pop();
74+
} finally {
75+
if (mounted) setState(() => _isSharing = false);
76+
}
77+
}
78+
5879
// ── font size helpers ──────────────────────────────────────────────────────
5980

6081
int _stepIndex(double fontSize) {
@@ -196,6 +217,27 @@ class _ReaderMoreBottomSheetState extends ConsumerState<ReaderMoreBottomSheet> {
196217
},
197218
),
198219

220+
// ── Share ──────────────────────────────────────────────────────
221+
_SectionDivider(theme: theme),
222+
ListTile(
223+
leading:
224+
_isSharing
225+
? SizedBox(
226+
width: 22,
227+
height: 22,
228+
child: CircularProgressIndicator(
229+
strokeWidth: 2,
230+
color: theme.colorScheme.onSurface,
231+
),
232+
)
233+
: Icon(Icons.share, color: theme.colorScheme.onSurface),
234+
title: Text(l10n.share, style: theme.textTheme.bodyLarge),
235+
onTap: () {
236+
HapticFeedback.lightImpact();
237+
_share();
238+
},
239+
),
240+
199241
const SizedBox(height: 8),
200242
],
201243
),

pubspec.lock

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -221,10 +221,10 @@ packages:
221221
dependency: transitive
222222
description:
223223
name: characters
224-
sha256: faf38497bda5ead2a8c7615f4f7939df04333478bf32e4173fcb06d428b5716b
224+
sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803
225225
url: "https://pub.dev"
226226
source: hosted
227-
version: "1.4.1"
227+
version: "1.4.0"
228228
checked_yaml:
229229
dependency: transitive
230230
description:
@@ -1145,18 +1145,18 @@ packages:
11451145
dependency: transitive
11461146
description:
11471147
name: matcher
1148-
sha256: dc0b7dc7651697ea4ff3e69ef44b0407ea32c487a39fff6a4004fa585e901861
1148+
sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2
11491149
url: "https://pub.dev"
11501150
source: hosted
1151-
version: "0.12.19"
1151+
version: "0.12.17"
11521152
material_color_utilities:
11531153
dependency: transitive
11541154
description:
11551155
name: material_color_utilities
1156-
sha256: "9c337007e82b1889149c82ed242ed1cb24a66044e30979c44912381e9be4c48b"
1156+
sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec
11571157
url: "https://pub.dev"
11581158
source: hosted
1159-
version: "0.13.0"
1159+
version: "0.11.1"
11601160
meta:
11611161
dependency: transitive
11621162
description:
@@ -1687,10 +1687,10 @@ packages:
16871687
dependency: transitive
16881688
description:
16891689
name: test_api
1690-
sha256: "8161c84903fd860b26bfdefb7963b3f0b68fee7adea0f59ef805ecca346f0c7a"
1690+
sha256: ab2726c1a94d3176a45960b6234466ec367179b87dd74f1611adb1f3b5fb9d55
16911691
url: "https://pub.dev"
16921692
source: hosted
1693-
version: "0.7.10"
1693+
version: "0.7.7"
16941694
tibetan_calendar:
16951695
dependency: "direct main"
16961696
description:

0 commit comments

Comments
 (0)