Skip to content

Commit e8e04f2

Browse files
authored
Merge pull request #473 from OpenPecha/feat/PlanShareDeepLink
feat: add deep link support for series sharing and enhance routing
2 parents bc2be77 + e8c681a commit e8e04f2

5 files changed

Lines changed: 55 additions & 0 deletions

File tree

lib/core/config/router/app_router.dart

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,16 @@ final appRouterProvider = Provider<GoRouter>((ref) {
122122
redirect: (_, __) => AppRoutes.home,
123123
),
124124

125+
// Compatibility fallback for series deep links delivered directly to
126+
// go_router instead of through AppLinksDeepLinkService.
127+
GoRoute(
128+
path: '/open/series/:seriesId',
129+
name: 'open-series',
130+
redirect: (_, state) {
131+
final seriesId = state.pathParameters['seriesId'] ?? '';
132+
return '/home/series/$seriesId';
133+
},
134+
),
125135
// Compatibility fallback in case a platform sends the first-party app
126136
// link directly to go_router instead of through AppLinksDeepLinkService.
127137
GoRoute(

lib/core/deep_linking/deep_link_router.dart

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,16 @@ class DeepLinkRouter {
8181

8282
static _DeepLinkDestination _resolveFirstPartyAppLink(Uri uri) {
8383
final segments = uri.pathSegments;
84+
if (segments.length >= 3 &&
85+
segments[0] == 'open' &&
86+
segments[1] == 'series') {
87+
final seriesId = segments[2];
88+
return _DeepLinkDestination(
89+
'/home/series/${Uri.encodeComponent(seriesId)}',
90+
opensOnTop: true,
91+
);
92+
}
93+
8494
if (segments.length >= 3 &&
8595
segments[0] == 'open' &&
8696
segments[1] == 'reader') {

lib/core/deep_linking/deep_link_url_builder.dart

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

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

6+
static Uri seriesLink({required String seriesId}) {
7+
return Uri(
8+
scheme: 'https',
9+
host: _host,
10+
pathSegments: ['open', 'series', seriesId],
11+
);
12+
}
13+
614
static Uri readerSegmentLink({
715
required String textId,
816
required String segmentId,

lib/features/home/presentation/screens/series_detail_screen.dart

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import 'package:flutter/material.dart';
22
import 'package:flutter_pecha/core/constants/app_assets.dart';
3+
import 'package:flutter_pecha/core/deep_linking/deep_link_url_builder.dart';
34
import 'package:flutter_pecha/core/l10n/generated/app_localizations.dart';
45
import 'package:flutter_pecha/core/widgets/error_state_widget.dart';
56
import 'package:flutter_pecha/core/widgets/skeletons/skeletons.dart';
@@ -17,6 +18,7 @@ import 'package:flutter_pecha/features/practice/presentation/providers/bookmark_
1718
import 'package:flutter_pecha/shared/utils/helper_functions.dart';
1819
import 'package:flutter_riverpod/flutter_riverpod.dart';
1920
import 'package:go_router/go_router.dart';
21+
import 'package:share_plus/share_plus.dart';
2022

2123
class SeriesDetailScreen extends ConsumerWidget {
2224
final String seriesId;
@@ -199,9 +201,17 @@ class SeriesDetailScreen extends ConsumerWidget {
199201
seriesId: series.id,
200202
seriesName: series.title,
201203
onAddToPractices: () => _onAddToPractices(context, ref, series),
204+
onShare: () => _onShare(series),
202205
);
203206
}
204207

208+
Future<void> _onShare(Series series) async {
209+
final url = DeepLinkUrlBuilder.seriesLink(seriesId: series.id).toString();
210+
final message =
211+
'Join me in practicing ${series.title} on WeBuddhist.\n\n$url';
212+
await SharePlus.instance.share(ShareParams(text: message));
213+
}
214+
205215
/// Adds the series to the user's practice routine.
206216
///
207217
/// Opens the routine editor with the already-loaded [series] injected. Adding

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

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,17 +13,20 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
1313
/// Contains:
1414
/// • "+ Add to my practices" action
1515
/// • Bookmark toggle action
16+
/// • Share action
1617
class SeriesMoreBottomSheet extends ConsumerStatefulWidget {
1718
const SeriesMoreBottomSheet({
1819
super.key,
1920
required this.seriesId,
2021
required this.seriesName,
2122
this.onAddToPractices,
23+
this.onShare,
2224
});
2325

2426
final String seriesId;
2527
final String seriesName;
2628
final VoidCallback? onAddToPractices;
29+
final VoidCallback? onShare;
2730

2831
@override
2932
ConsumerState<SeriesMoreBottomSheet> createState() =>
@@ -118,6 +121,18 @@ class _SeriesMoreBottomSheetState extends ConsumerState<SeriesMoreBottomSheet> {
118121
},
119122
),
120123

124+
// ── Share ──────────────────────────────────────────────────────
125+
_SectionDivider(theme: theme),
126+
ListTile(
127+
leading: Icon(AppAssets.share, color: theme.colorScheme.onSurface),
128+
title: Text('Share', style: theme.textTheme.bodyLarge),
129+
onTap: () {
130+
HapticFeedback.lightImpact();
131+
Navigator.of(context).pop();
132+
widget.onShare?.call();
133+
},
134+
),
135+
121136
const SizedBox(height: 8),
122137
],
123138
),
@@ -140,6 +155,7 @@ void showSeriesMoreBottomSheet(
140155
required String seriesId,
141156
required String seriesName,
142157
VoidCallback? onAddToPractices,
158+
VoidCallback? onShare,
143159
}) {
144160
showModalBottomSheet(
145161
context: context,
@@ -153,6 +169,7 @@ void showSeriesMoreBottomSheet(
153169
seriesId: seriesId,
154170
seriesName: seriesName,
155171
onAddToPractices: onAddToPractices,
172+
onShare: onShare,
156173
),
157174
);
158175
}

0 commit comments

Comments
 (0)