mirror of
https://github.com/meditohq/medito-app.git
synced 2024-10-05 16:08:17 +03:00
Android deep links
This commit is contained in:
parent
085a930a4a
commit
5d7ca21dc8
@ -53,6 +53,26 @@
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
|
||||
<data android:scheme="https" />
|
||||
<data android:host="medito.app" />
|
||||
<data android:pathPrefix="/tracks/" />
|
||||
</intent-filter>
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
|
||||
<data android:scheme="https" />
|
||||
<data android:host="medito.app" />
|
||||
<data android:pathPrefix="/packs/" />
|
||||
</intent-filter>
|
||||
|
||||
</activity>
|
||||
|
||||
@ -62,6 +82,9 @@
|
||||
<meta-data
|
||||
android:name="com.google.firebase.messaging.default_notification_channel_id"
|
||||
android:value="high_importance_channel" />
|
||||
<meta-data
|
||||
android:name="flutter_deeplinking_enabled"
|
||||
android:value="true" />
|
||||
|
||||
<service
|
||||
android:name=".AudioPlayerService"
|
||||
|
@ -2,17 +2,17 @@ class RouteConstants {
|
||||
static const String root = '/';
|
||||
static const String bottomNavbarPath = '/bottomNavbar';
|
||||
static const String homePath = '/home';
|
||||
static const String trackPath = '/track/:sid';
|
||||
static const String trackPath = '/tracks/:sid';
|
||||
static const String downloadsPath = '/downloads';
|
||||
static const String maintenancePath = '/maintenance';
|
||||
static const String playerPath = '/player';
|
||||
static const String packPath = '/pack/:pid';
|
||||
static const String player1 = '/pack/:pid/meditation/:sid';
|
||||
static const String pack2Path = '/pack/:pid/pack2/:p2id';
|
||||
static const String player2 = '/pack/:pid/pack2/:p2id/meditation/:sid';
|
||||
static const String pack3Path = '/pack/:pid/pack2/:p2id/pack3/:p3id';
|
||||
static const String packPath = '/packs/:pid';
|
||||
static const String player1 = '/packs/:pid/meditations/:sid';
|
||||
static const String pack2Path = '/packs/:pid/pack2/:p2id';
|
||||
static const String player2 = '/packs/:pid/pack2/:p2id/meditations/:sid';
|
||||
static const String pack3Path = '/packs/:pid/pack2/:p2id/pack3/:p3id';
|
||||
static const String player3 =
|
||||
'/pack/:pid/pack2/:p2id/pack3/:p3id/meditation/:sid';
|
||||
'/packs/:pid/pack2/:p2id/pack3/:p3id/meditations/:sid';
|
||||
static const String urlPath = '/url';
|
||||
static const String connectivityErrorPath = '/connectivityError';
|
||||
static const String backgroundSoundsPath = '/backgroundsounds';
|
||||
|
@ -262,37 +262,41 @@ MaterialPage<void> _getFolderMaterialPage(GoRouterState state) {
|
||||
|
||||
Future<void> handleNavigation(
|
||||
String? place,
|
||||
List<String?> ids, {
|
||||
BuildContext? context,
|
||||
List<String?> ids,
|
||||
BuildContext context, {
|
||||
WidgetRef? ref,
|
||||
GoRouter? goRouterContext,
|
||||
}) async {
|
||||
ids.removeWhere((element) => element == null);
|
||||
var path;
|
||||
var params;
|
||||
if (place == TypeConstants.track) {
|
||||
unawaited(
|
||||
showModalBottomSheet<void>(
|
||||
context: context!,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.vertical(
|
||||
top: Radius.circular(24.0),
|
||||
),
|
||||
),
|
||||
useRootNavigator: true,
|
||||
isScrollControlled: true,
|
||||
backgroundColor: ColorConstants.ebony,
|
||||
builder: (BuildContext context) {
|
||||
return SafeArea(
|
||||
child: TrackView(
|
||||
id: ids.first!,
|
||||
if (place == 'tracks') {
|
||||
try {
|
||||
unawaited(
|
||||
showModalBottomSheet<void>(
|
||||
context: context,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.vertical(
|
||||
top: Radius.circular(24.0),
|
||||
),
|
||||
);
|
||||
},
|
||||
).then(
|
||||
(value) => ref?.refresh(fetchStatsProvider),
|
||||
),
|
||||
);
|
||||
),
|
||||
useRootNavigator: true,
|
||||
isScrollControlled: true,
|
||||
backgroundColor: ColorConstants.ebony,
|
||||
builder: (BuildContext context) {
|
||||
return SafeArea(
|
||||
child: TrackView(
|
||||
id: ids.first!,
|
||||
),
|
||||
);
|
||||
},
|
||||
).then(
|
||||
(value) => ref?.refresh(fetchStatsProvider),
|
||||
),
|
||||
);
|
||||
} catch (e, s) {
|
||||
print(s);
|
||||
}
|
||||
|
||||
return;
|
||||
} else if (place != null && place.contains('pack3')) {
|
||||
@ -335,3 +339,18 @@ Future<void> handleNavigation(
|
||||
unawaited(goRouterContext.push(path, extra: params));
|
||||
}
|
||||
}
|
||||
|
||||
void handleDeepLink(Uri? uri, BuildContext context) {
|
||||
var path = uri?.path;
|
||||
if (path != null) {
|
||||
if (path.contains('tracks')) {
|
||||
handleNavigation(
|
||||
'tracks',
|
||||
[uri?.pathSegments.last ?? ''],
|
||||
context,
|
||||
);
|
||||
} else {
|
||||
unawaited(context.push(path));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -9,6 +9,7 @@ import 'package:firebase_messaging/firebase_messaging.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:permission_handler/permission_handler.dart';
|
||||
|
||||
late final FirebaseMessaging? _messaging;
|
||||
@ -127,10 +128,10 @@ void _navigate(
|
||||
var goRouterContext = ref.read(goRouterProvider);
|
||||
if (data.type.isNotNullAndNotEmpty()) {
|
||||
handleNavigation(
|
||||
goRouterContext: goRouterContext,
|
||||
context: context,
|
||||
data.type,
|
||||
[data.id.toString().getIdFromPath(), data.path],
|
||||
context,
|
||||
goRouterContext: goRouterContext,
|
||||
);
|
||||
} else {
|
||||
goRouterContext.go(RouteConstants.bottomNavbarPath);
|
||||
|
@ -72,7 +72,11 @@ class DonationWidget extends ConsumerWidget {
|
||||
height: 48,
|
||||
width: MediaQuery.of(context).size.width,
|
||||
child: LoadingButtonWidget(
|
||||
onPressed: () => handleNavigation(donationPageModel.ctaType, [donationPageModel.ctaPath]),
|
||||
onPressed: () => handleNavigation(
|
||||
donationPageModel.ctaType,
|
||||
[donationPageModel.ctaPath],
|
||||
context,
|
||||
),
|
||||
btnText: donationPageModel.ctaTitle ?? StringConstants.donateNow,
|
||||
bgColor: ColorConstants.walterWhite,
|
||||
textColor: parseColor(donationPageModel.colorBackground),
|
||||
|
@ -54,9 +54,9 @@ class ExploreInitialPageWidget extends ConsumerWidget {
|
||||
subTitle: element.subtitle,
|
||||
coverUrlPath: element.coverUrl,
|
||||
onTap: () => handleNavigation(
|
||||
context: context,
|
||||
element.type,
|
||||
[element.id.toString(), element.path],
|
||||
context,
|
||||
ref: ref,
|
||||
),
|
||||
),
|
||||
|
@ -79,9 +79,9 @@ class ExploreResultWidget extends ConsumerWidget {
|
||||
checkConnectivity().then((value) {
|
||||
if (value) {
|
||||
handleNavigation(
|
||||
context: context,
|
||||
type,
|
||||
[id.toString(), path],
|
||||
context,
|
||||
);
|
||||
} else {
|
||||
createSnackBar(StringConstants.checkConnection, context);
|
||||
|
@ -8,8 +8,11 @@ import 'package:Medito/views/home/widgets/header_and_announcement_widget.dart';
|
||||
import 'package:Medito/widgets/widgets.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:uni_links/uni_links.dart';
|
||||
|
||||
import '../../models/home/home_model.dart';
|
||||
import '../../routes/routes.dart';
|
||||
import 'widgets/quote/quote_widget.dart';
|
||||
import 'widgets/shortcuts/shortcuts_widget.dart';
|
||||
|
||||
@ -22,6 +25,18 @@ class HomeView extends ConsumerStatefulWidget {
|
||||
|
||||
class _HomeViewState extends ConsumerState<HomeView>
|
||||
with TickerProviderStateMixin, AutomaticKeepAliveClientMixin {
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
navigateToDeepLink();
|
||||
}
|
||||
|
||||
void navigateToDeepLink() {
|
||||
Future.delayed(Duration(seconds: 1), () async {
|
||||
handleDeepLink(await getInitialUri(), context);
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
super.build(context);
|
||||
|
@ -134,9 +134,9 @@ class _AnnouncementWidgetState extends ConsumerState<AnnouncementWidget> {
|
||||
var path = widget.announcement.ctaPath;
|
||||
_handleTrackEvent();
|
||||
await handleNavigation(
|
||||
context: context,
|
||||
widget.announcement.ctaType,
|
||||
[path.toString().getIdFromPath(), path],
|
||||
context,
|
||||
ref: ref,
|
||||
);
|
||||
}
|
||||
|
@ -91,9 +91,9 @@ class MenuBottomSheetWidget extends ConsumerWidget {
|
||||
) async {
|
||||
Navigator.pop(context);
|
||||
await handleNavigation(
|
||||
context: context,
|
||||
element.type,
|
||||
[element.path.toString().getIdFromPath(), element.path],
|
||||
context,
|
||||
ref: ref,
|
||||
);
|
||||
}
|
||||
|
@ -47,9 +47,9 @@ class CarouselWidget extends ConsumerWidget {
|
||||
padding: const EdgeInsets.symmetric(horizontal: padding20),
|
||||
child: InkWell(
|
||||
onTap: () => handleNavigation(
|
||||
context: context,
|
||||
first.type,
|
||||
[first.path.toString().getIdFromPath(), first.path],
|
||||
context,
|
||||
),
|
||||
child: Stack(
|
||||
children: [
|
||||
|
@ -35,9 +35,9 @@ class _ShortcutsItemsWidgetState extends ConsumerState<ShortcutsItemsWidget> {
|
||||
ShortcutsModel element,
|
||||
) async {
|
||||
await handleNavigation(
|
||||
context: context,
|
||||
element.type,
|
||||
[element.path.toString().getIdFromPath(), element.path],
|
||||
context,
|
||||
ref: ref,
|
||||
);
|
||||
}
|
||||
|
@ -155,22 +155,22 @@ class _PackViewState extends ConsumerState<PackView>
|
||||
if (type == TypeConstants.pack) {
|
||||
if (location.contains('pack2')) {
|
||||
unawaited(handleNavigation(
|
||||
context: context,
|
||||
RouteConstants.pack3Path,
|
||||
[location.split('/')[2], widget.id, id.toString()],
|
||||
context,
|
||||
));
|
||||
} else {
|
||||
unawaited(handleNavigation(
|
||||
context: context,
|
||||
RouteConstants.pack2Path,
|
||||
[widget.id, id.toString()],
|
||||
context,
|
||||
));
|
||||
}
|
||||
} else {
|
||||
unawaited(handleNavigation(
|
||||
context: context,
|
||||
type,
|
||||
[id.toString(), path],
|
||||
context,
|
||||
ref: ref,
|
||||
));
|
||||
}
|
||||
|
@ -117,7 +117,9 @@ class _PlayerViewState extends ConsumerState<PlayerView> {
|
||||
void onPlayPausePressed() {
|
||||
var isPlaying = ref.read(audioStateProvider).isPlaying;
|
||||
ref.read(playerProvider.notifier).playPause();
|
||||
ref.read(backgroundSoundsNotifierProvider.notifier).togglePlayPause(isPlaying);
|
||||
ref
|
||||
.read(backgroundSoundsNotifierProvider.notifier)
|
||||
.togglePlayPause(isPlaying);
|
||||
}
|
||||
|
||||
bool _isBackgroundSoundSelected() {
|
||||
|
@ -81,9 +81,9 @@ class ArtistTitleWidget extends ConsumerWidget {
|
||||
void _handleArtistNameTap(BuildContext context) async {
|
||||
if (isPlayerScreen && artistUrlPath != null) {
|
||||
await handleNavigation(
|
||||
context: context,
|
||||
TypeConstants.url,
|
||||
[artistUrlPath],
|
||||
context,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:flutter_svg/svg.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:uni_links/uni_links.dart';
|
||||
|
||||
class SplashView extends ConsumerStatefulWidget {
|
||||
const SplashView({super.key});
|
||||
|
@ -86,9 +86,9 @@ class _TrackViewState extends ConsumerState<TrackView>
|
||||
bgSoundNotifier.getVolumeFromPref();
|
||||
bgSoundNotifier.playBackgroundSoundFromPref();
|
||||
await ref.read(playerProvider.notifier).loadSelectedTrack(
|
||||
trackModel: trackModel,
|
||||
file: file,
|
||||
);
|
||||
trackModel: trackModel,
|
||||
file: file,
|
||||
);
|
||||
unawaited(context.push(RouteConstants.playerPath));
|
||||
} catch (e) {
|
||||
print(e);
|
||||
@ -331,9 +331,9 @@ class _TrackViewState extends ConsumerState<TrackView>
|
||||
),
|
||||
onTapLink: (text, href, title) {
|
||||
handleNavigation(
|
||||
context: context,
|
||||
TypeConstants.url,
|
||||
[href],
|
||||
context,
|
||||
);
|
||||
},
|
||||
),
|
||||
|
@ -58,9 +58,9 @@ class MarkdownWidget extends StatelessWidget {
|
||||
|
||||
void _linkTap(BuildContext context, String? href) {
|
||||
handleNavigation(
|
||||
context: context,
|
||||
TypeConstants.url,
|
||||
[href],
|
||||
context,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
24
pubspec.lock
24
pubspec.lock
@ -1469,6 +1469,30 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.3.2"
|
||||
uni_links:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: uni_links
|
||||
sha256: "051098acfc9e26a9fde03b487bef5d3d228ca8f67693480c6f33fd4fbb8e2b6e"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.5.1"
|
||||
uni_links_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: uni_links_platform_interface
|
||||
sha256: "929cf1a71b59e3b7c2d8a2605a9cf7e0b125b13bc858e55083d88c62722d4507"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.0"
|
||||
uni_links_web:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: uni_links_web
|
||||
sha256: "7539db908e25f67de2438e33cc1020b30ab94e66720b5677ba6763b25f6394df"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.1.0"
|
||||
url_launcher:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
@ -61,6 +61,7 @@ dependencies:
|
||||
shared_preferences: ^2.2.2
|
||||
url_launcher: ^6.1.14
|
||||
workmanager: ^0.5.2
|
||||
uni_links: ^0.5.1
|
||||
|
||||
dependency_overrides:
|
||||
firebase_core_platform_interface: 4.5.1
|
||||
|
Loading…
Reference in New Issue
Block a user