Skip to content

Commit

Permalink
Merge pull request #46 from MXCzkEVM/app_links
Browse files Browse the repository at this point in the history
App links
  • Loading branch information
reasje authored Sep 26, 2024
2 parents 3cebffb + 8a30b8c commit cb89d22
Show file tree
Hide file tree
Showing 22 changed files with 241 additions and 16 deletions.
10 changes: 10 additions & 0 deletions android/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,16 @@
<data android:mimeType="image/*" />
<data android:mimeType="application/pdf" />
</intent-filter>

<meta-data android:name="flutter_deeplinking_enabled" android:value="false" />

<!-- App Link sample -->
<intent-filter android:autoVerify="true">
<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" android:host="mxc1usd.com" android:pathPrefix="/app" />
</intent-filter>
</activity>

<provider android:name="androidx.core.content.FileProvider" android:authorities="${applicationId}.provider" android:exported="false" android:grantUriPermissions="true">
Expand Down
2 changes: 2 additions & 0 deletions ios/Runner/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
<string>com.mxc.moonchain.minerAutoClaimTask</string>
<string>com.mxc.moonchain.blueberryAutoSyncTask</string>
</array>
<key>FlutterDeepLinkingEnabled</key>
<false/>
<key>CADisableMinimumFrameDurationOnPhone</key>
<true/>
<key>CFBundleDevelopmentRegion</key>
Expand Down
6 changes: 3 additions & 3 deletions lib/app/app_presenter.dart
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import 'package:moonchain_wallet/core/core.dart';

final appContainer =
PresenterContainer<SettingsPresenter, void>(() => SettingsPresenter());
PresenterContainer<AppPresenter, void>(() => AppPresenter());

class SettingsPresenter extends CompletePresenter {
SettingsPresenter() : super(null);
class AppPresenter extends CompletePresenter {
AppPresenter() : super(null);

@override
void initState() {
Expand Down
2 changes: 2 additions & 0 deletions lib/core/core.dart
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,5 @@ export 'src/cache/base_cache.dart';
export 'src/moonchain_wallet_notification.dart';
export 'src/firebase/moonchain_wallet_firebase.dart';
export 'src/background_process/background_process.dart';
export 'src/app_links/app_links.dart';

2 changes: 2 additions & 0 deletions lib/core/src/app_links/app_links.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export 'app_links_router.dart';
export 'moonchain_app_links.dart';
95 changes: 95 additions & 0 deletions lib/core/src/app_links/app_links_router.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import 'package:flutter/material.dart';
import 'package:moonchain_wallet/app/logger.dart';
import 'package:moonchain_wallet/core/core.dart';
import 'package:moonchain_wallet/features/dapps/dapps.dart';
import 'package:moonchain_wallet/features/portfolio/presentation/portfolio_page.dart';
import 'package:moonchain_wallet/features/wallet/wallet.dart';

class AppLinksRouter {
AppLinksRouter(this.navigator);

NavigatorState? navigator;

// TODO:
// CHeck login
// What if already in that page
// Check to push and replace or only push
// Link : https://www.mxc1usd.com/app/
// Routes : dapps - wallet - portfolio (wallet sub page) - openDapp - sendCrypto -
//
// https://www.mxc1usd.com/app/openDapp?url=https://github.com/reasje
Widget openLink(Uri uri) {
final page = getPage(uri);
final params = getParams(uri);

return getPageWithParams(page, params);
}

// Get page from uri
String getPage(Uri uri) => uri.pathSegments[1];

// Get params
// Note: https://mxc1usd.com/app/openDapp?url=https://testnet.blueberryring.com?invite=p8M6E7b02l has the
// https://testnet.blueberryring.com?invite=p8M6E7b02l as List of params in the first index
Map<String, List<String>>? getParams(Uri uri) =>
uri.hasQuery ? uri.queryParametersAll : null;

// Push to stack
Future pushTo(Widget page) => navigator!.push(route(page));
// Remove stacks until that page
Future pushAndReplaceUntil(Widget page) => navigator!.pushAndRemoveUntil(
route(page),
(route) => false,
);

// Combine page with It's params
Widget getPageWithParams(String page, Map<String, List<String>>? params) {
late Widget toPushPage;

switch ('/$page') {
case '/':
toPushPage = const DAppsPage();
break;
case '/dapps':
toPushPage = const DAppsPage();
break;
case '/openDapp':
final url = params!['url']![0];
toPushPage = OpenDAppPage(url: url,);
break;
case '/wallet':
toPushPage = const WalletPage();
break;
case '/portfolio':
toPushPage = const PortfolioPage();
break;
default:
toPushPage = const DAppsPage();
}

return toPushPage;
}

/// This function will do the navigation according to the page widget that
/// includes the params based on how page specific navigation instruction.
void navigateTo(Widget toPushPage){
late Function() navigationFunc;

if (toPushPage.runtimeType == OpenDAppPage) {
navigationFunc = () {
pushTo(toPushPage);
};
} else if (toPushPage.runtimeType == PortfolioPage) {
navigationFunc = () {
pushAndReplaceUntil(const WalletPage());
pushTo(toPushPage);
};
} else {
navigationFunc = () {
pushAndReplaceUntil(toPushPage);
};
}

navigationFunc();
}
}
25 changes: 25 additions & 0 deletions lib/core/src/app_links/moonchain_app_links.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import 'dart:async';

import 'package:app_links/app_links.dart';

class MoonchainAppLinks {
late AppLinks _appLinks;
StreamSubscription<Uri>? linkSubscription;


Future<Uri?> initAppLinks() async {
_appLinks = AppLinks();

// Check initial link if app was in cold state (terminated)
final appLink = await _appLinks.getInitialAppLink();

// Handle link when app is in warm state (front or background)
linkSubscription = _appLinks.uriLinkStream.listen((event) { });
return appLink;
}


void cancelAppLinks() {
linkSubscription?.cancel();
}
}
8 changes: 8 additions & 0 deletions lib/core/src/providers/providers_use_cases.dart
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,14 @@ final Provider<LauncherUseCase> launcherUseCaseProvider = Provider(
),
);

final Provider<MoonchainAppLinksUseCase> appLinksUseCaseProvider = Provider(
(ref) => MoonchainAppLinksUseCase(
ref.watch(authUseCaseProvider),
ref.watch(passcodeUseCaseProvider),
),
);


final Provider<MXCTransactionsUseCase> mxcTransactionsUseCaseProvider =
Provider(
(ref) => MXCTransactionsUseCase(
Expand Down
1 change: 1 addition & 0 deletions lib/features/common/app/app.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ export 'error_use_case.dart';
export 'launcher_use_case.dart';
export 'function_use_case.dart';
export 'contextless_translation_use_case.dart';
export 'app_links_use_case.dart';
66 changes: 66 additions & 0 deletions lib/features/common/app/app_links_use_case.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import 'dart:async';

import 'package:flutter/material.dart';
import 'package:moonchain_wallet/app/app.dart';
import 'package:moonchain_wallet/core/core.dart';
import 'package:moonchain_wallet/features/security/security.dart';
import 'package:mxc_logic/mxc_logic.dart';

class MoonchainAppLinksUseCase extends ReactiveUseCase {
MoonchainAppLinksUseCase(
this._authUseCase,
this._passcodeUseCase,
) {
initializeListeners();
}

final AuthUseCase _authUseCase;
final PasscodeUseCase _passcodeUseCase;

BuildContext get currentContext => appNavigatorKey.currentContext!;
NavigatorState? get navigator => appNavigatorKey.currentState;

AppLinksRouter get _appLinksRouter => AppLinksRouter(navigator);
late final MoonchainAppLinks _moonchainAppLinks = MoonchainAppLinks();

late final ValueStream<Stream<dynamic>?> websocketStreamSubscription =
reactive(null);
StreamSubscription<dynamic>? websocketCloseStreamSubscription;
late final ValueStream<Stream<dynamic>> addressStream =
reactive(const Stream.empty());
bool isPassCodeScreenShown = true;
// This is the widget we need to navigate

Widget? toNavigateWidget;
Account? account;

void initializeListeners() {
_passcodeUseCase.passcodeScreenIsShown.listen((event) {
isPassCodeScreenShown = event;
checkNavigationFunction();
});

_moonchainAppLinks.initAppLinks().then((value) {
if (value != null) {
toNavigateWidget = _appLinksRouter.openLink(value);
}
_moonchainAppLinks.linkSubscription!.onData((data) {
toNavigateWidget = _appLinksRouter.openLink(data);
checkNavigationFunction();
});
});
}

void checkNavigationFunction() {
if (!isPassCodeScreenShown && toNavigateWidget != null) {
_appLinksRouter.navigateTo(toNavigateWidget!);
toNavigateWidget = null;
}
}

@override
Future<void> dispose() async {
_moonchainAppLinks.cancelAppLinks();
super.dispose();
}
}
2 changes: 1 addition & 1 deletion lib/features/common/app/error_use_case.dart
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ class ErrorUseCase extends ReactiveUseCase {
final l3BridgeUri = Urls.networkL3Bridge(chainId);
Navigator.of(context).push(route.featureDialog(
maintainState: false,
OpenAppPage(
OpenDAppPage(
url: l3BridgeUri,
),
));
Expand Down
1 change: 0 additions & 1 deletion lib/features/common/app/launcher_use_case.dart
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import 'dart:async';
import 'dart:io';

import 'package:moonchain_wallet/common/common.dart';
import 'package:moonchain_wallet/core/core.dart';
import 'package:moonchain_wallet/features/common/common.dart';
import 'package:moonchain_wallet/features/settings/subfeatures/chain_configuration/domain/chain_configuration_use_case.dart';
Expand Down
2 changes: 1 addition & 1 deletion lib/features/dapps/dapps.dart
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ Future<void> openAppPage(
.push(
route.featureDialog(
maintainState: false,
OpenAppPage(url: url),
OpenDAppPage(url: url),
),
)
.then((value) => refreshApp());
Expand Down
4 changes: 2 additions & 2 deletions lib/features/dapps/subfeatures/open_dapp/open_dapp_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ import 'open_dapp_presenter.dart';
import 'widgets/bridge_params.dart';
import 'widgets/allow_multiple_gestures.dart';

class OpenAppPage extends HookConsumerWidget {
const OpenAppPage({Key? key, required this.url}) : super(key: key);
class OpenDAppPage extends HookConsumerWidget {
const OpenDAppPage({Key? key, required this.url}) : super(key: key);

final String url;

Expand Down
1 change: 0 additions & 1 deletion lib/features/portfolio/presentation/portfolio_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import 'dart:ui';
import 'package:moonchain_wallet/core/core.dart';
import 'package:moonchain_wallet/features/common/common.dart';
import 'package:moonchain_wallet/features/dapps/dapps.dart';
import 'package:moonchain_wallet/features/dapps/subfeatures/open_dapp/open_dapp.dart';
import 'package:moonchain_wallet/features/portfolio/subfeatures/nft/choose_nft/choose_nft_page.dart';
import 'package:moonchain_wallet/features/portfolio/subfeatures/nft/nft_list/nft_list.dart';
import 'package:moonchain_wallet/features/portfolio/subfeatures/tokens_balance_list/tokens_balance_list.dart';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ class PortfolioPresenter extends CompletePresenter<PortfolioState> {
final l3BridgeUri = Urls.networkL3Bridge(chainId);
Navigator.of(context!).push(route.featureDialog(
maintainState: false,
OpenAppPage(
OpenDAppPage(
url: l3BridgeUri,
),
));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ class NFTList extends HookConsumerWidget {
if (launchUrl != null) {
Navigator.of(context).push(route.featureDialog(
maintainState: false,
OpenAppPage(
OpenDAppPage(
url: launchUrl,
),
));
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import 'dart:async';

import 'package:moonchain_wallet/features/security/security.dart';
import 'package:flutter/widgets.dart';
import 'package:moonchain_wallet/core/core.dart';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import 'dart:async';
import 'dart:ui';

import 'package:flutter/scheduler.dart';
import 'package:flutter/widgets.dart';
import 'package:moonchain_wallet/core/core.dart';
Expand All @@ -21,6 +21,10 @@ class AppThemePresenter extends Presenter<AppThemeState>

@override
void initState() {

// Init app links NOTE that It will be alive for app life cycle
ref.read(appLinksUseCaseProvider);

super.initState();
state.darkMode = _darkThemeShouldBeShown();
listen<ThemeOption>(_themeUseCase.currentTheme, (_) => refreshTheme());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ class SplashMNSQueryPresenter extends CompletePresenter<SplashMNSQueryState> {
final l3BridgeUri = Urls.networkL3Bridge(chainId);
Navigator.of(context!).push(route.featureDialog(
maintainState: false,
OpenAppPage(
OpenDAppPage(
url: l3BridgeUri,
),
));
Expand All @@ -116,7 +116,7 @@ class SplashMNSQueryPresenter extends CompletePresenter<SplashMNSQueryState> {
? Urls.mainnetMns(name)
: Urls.testnetMns(name);
await navigator
?.push(route.featureDialog(OpenAppPage(url: launchUrl)))
?.push(route.featureDialog(OpenDAppPage(url: launchUrl)))
.then((_) {
navigator?.replaceAll(route(const DAppsPage()));
});
Expand Down
8 changes: 8 additions & 0 deletions pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "0.2.1"
app_links:
dependency: "direct main"
description:
name: app_links
sha256: eb83c2b15b78a66db04e95132678e910fcdb8dc3a9b0aed0c138f50b2bef0dae
url: "https://pub.dev"
source: hosted
version: "3.4.5"
app_settings:
dependency: "direct main"
description:
Expand Down
Loading

0 comments on commit cb89d22

Please sign in to comment.