diff --git a/android/app/appcenter-post-clone.sh b/android/app/appcenter-post-clone.sh
index 01b61a37..f44f5938 100644
--- a/android/app/appcenter-post-clone.sh
+++ b/android/app/appcenter-post-clone.sh
@@ -37,4 +37,24 @@ echo "APPCENTER_DISTRIBUTION_GROUP_ID_ANDROID=${APPCENTER_DISTRIBUTION_GROUP_ID_
flutter build apk --flavor product --release
# copy the APK where AppCenter will find it
-mkdir -p android/app/build/outputs/apk/; mv build/app/outputs/apk/product/release/axs-wallet.apk $_
\ No newline at end of file
+
+mkdir -p android/app/build/outputs/apk/; mv build/app/outputs/apk/product/release/app-product-release.apk $_
+
+# copy the AAB where AppCenter will find it
+mkdir -p android/app/build/outputs/bundle/; mv build/app/outputs/bundle/googleplayRelease/app-googleplay-release.aab $_
+
+# To configure appCenter builds with Waldo UI Automation tool
+export WALDO_CLI_BIN=/usr/local/bin
+bash -c "$(curl -fLs https://github.com/waldoapp/waldo-go-cli/raw/master/install-waldo.sh)"
+
+export PATH="$WALDO_CLI_BIN:$PATH"
+
+# To configure appCenter builds with Waldo UI Automation tool
+export WALDO_UPLOAD_TOKEN=$ANDROID_WALDO_UPLOAD_TOKEN
+
+_build_path=android/app/build/outputs/apk/app-product-release.apk
+
+waldo upload "$_build_path"
+
+# /usr/local/bin/waldo upload "$BUILD_PATH"
+
diff --git a/android/app/build.gradle b/android/app/build.gradle
index 7669bae7..05c747d7 100644
--- a/android/app/build.gradle
+++ b/android/app/build.gradle
@@ -29,7 +29,7 @@ apply plugin: 'kotlin-android'
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
android {
- compileSdkVersion 33
+ compileSdkVersion 34
buildToolsVersion "33.0.1"
ndkVersion flutter.ndkVersion
diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml
index 0795324a..323f9cd0 100644
--- a/android/app/src/main/AndroidManifest.xml
+++ b/android/app/src/main/AndroidManifest.xml
@@ -30,7 +30,7 @@
-
+
diff --git a/assets/flutter_i18n/en.json b/assets/flutter_i18n/en.json
index 1a3cb359..9346e225 100644
--- a/assets/flutter_i18n/en.json
+++ b/assets/flutter_i18n/en.json
@@ -4,6 +4,8 @@
"telegram_secured_storage": "Telegram secured storage",
"wechat_secured_storage": "WeChat secured storage",
"email_secured_storage": "Email secured storage",
+ "local_secured_storage": "Local secured storage",
+ "save_locally": "Save locally",
"set_passcode": "Create passcode",
"set_passcode_hint": "Enter a 6-digit passcode to unlock your wallet with ease. This passcode can’t be used to recover your wallet.",
"passcode_didnt_match": "Passcodes did not match. Try again.",
@@ -68,6 +70,7 @@
"share": "Share",
"wechat": "WeChat",
"email_to_myself_description": "Make sure to email your keys only to yourself.",
+ "save_locally_description": "Make sure to save your keys locally and then you are good to go.",
"email_to_myself": "Email to myself",
"security_notice": "Important Security Notice",
"ensure_saved_platform": "Please ensure that you have securely saved your key on a trusted platform such as email, Telegram, or WeChat.",
@@ -399,6 +402,7 @@
"axs_location_permission_use_case": "AXS Wallet needs access to your location for features such as Wi-Fi hooks while the app is in use or running in the background. Your location data is not saved or shared with any third parties.",
"axs_camera_permission_use_case": "AXS Wallet needs access to your camera when the app is in use for services such as RWA minting. Image data is not saved or shared with any third parties.",
"axs_photos_permission_use_case": "AXS Wallet needs access to your photos to save images such as RWA. Your photos are not saved or shared with any third parties.",
+ "axs_storage_permission_use_case": "AXS Wallet needs access to your storage for features such as RWA. Your storage data is not saved or shared with any third parties.",
"permission_use_cases": "Permission use cases",
"ok_allow": "OK, Allow",
"not_now": "Not now",
@@ -407,5 +411,6 @@
"remove_dapp": "Remove dApp",
"dapp_removal_dialog_text": "Deleting this dApp will remove it from your Home Screen.",
"information": "Information",
- "ok": "Ok"
+ "ok": "Ok",
+ "local_backup": "Local backup"
}
\ No newline at end of file
diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist
index 21fa240c..30e132e8 100644
--- a/ios/Runner/Info.plist
+++ b/ios/Runner/Info.plist
@@ -1,154 +1,156 @@
-
- BGTaskSchedulerPermittedIdentifiers
-
- com.transistorsoft.fetch
- com.mxc.axswallet.periodicalTasks
- com.mxc.axswallet.dappHooksTasks
- com.mxc.axswallet.minerAutoClaimTask
-
- CADisableMinimumFrameDurationOnPhone
-
- CFBundleDevelopmentRegion
- $(DEVELOPMENT_LANGUAGE)
- CFBundleDisplayName
- AXS
- CFBundleDocumentTypes
-
-
- CFBundleTypeName
- FlSharedLink
- LSHandlerRank
- Default
- LSItemContentTypes
-
- public.file-url
- public.image
- public.text
- public.url
- public.data
-
-
-
- CFBundleExecutable
- $(EXECUTABLE_NAME)
- CFBundleIdentifier
- $(PRODUCT_BUNDLE_IDENTIFIER)
- CFBundleInfoDictionaryVersion
- 6.0
- CFBundleLocalizations
-
- en
- zh_TW
- zh_CN
- zh_HK
- ko
- ja
- vi
- ru
- tr
- de
- es
- pt
- tl
- id
- it
- fr
-
- CFBundleName
- axs
- CFBundlePackageType
- APPL
- CFBundleShortVersionString
- $(FLUTTER_BUILD_NAME)
- CFBundleSignature
- ????
- CFBundleVersion
- $(FLUTTER_BUILD_NUMBER)
- LSApplicationQueriesSchemes
-
- tg
- weixin
- wechat
- googlegmail
- x-dispatch
- readdle-spark
- airmail
- ms-outlook
- ymail
- fastmail
- superhuman
- protonmail
-
- LSRequiresIPhoneOS
-
- LSSupportsOpeningDocumentsInPlace
- No
- NSAppTransportSecurity
- NSAllowsArbitraryLoads
+ BGTaskSchedulerPermittedIdentifiers
+
+ com.transistorsoft.fetch
+ com.mxc.axswallet.periodicalTasks
+ com.mxc.axswallet.dappHooksTasks
+ com.mxc.axswallet.minerAutoClaimTask
+
+ CADisableMinimumFrameDurationOnPhone
-
- NSAppleMusicUsageDescription
- Would you allow AXS Wallet to use the Media Library?
- NSBluetoothPeripheralUsageDescription
- Would you allow AXS Wallet to use the Bluetooth?
- NSCalendarsUsageDescription
- Would you allow AXS Wallet to use the Calendar?
- NSCameraUsageDescription
- AXS Wallet needs access to your camera when the app is in use for services such as RWA minting. Image data is not saved or shared with any third parties.
- NSFaceIDUsageDescription
- AXS Wallet needs access to your Biometric data when the app is in use for authentication only. Your Biometric data is not saved or shared with any third parties.
- NSLocationAlwaysAndWhenInUseUsageDescription
- AXS Wallet needs access to your location for features such as Wi-Fi hooks while the app is in use or running in the background. Your location data is not saved or shared with any third parties.
+ CFBundleDevelopmentRegion
+ $(DEVELOPMENT_LANGUAGE)
+ CFBundleDisplayName
+ AXS
+ CFBundleDocumentTypes
+
+
+ CFBundleTypeName
+ FlSharedLink
+ LSHandlerRank
+ Default
+ LSItemContentTypes
+
+ public.file-url
+ public.image
+ public.text
+ public.url
+ public.data
+
+
+
+ CFBundleExecutable
+ $(EXECUTABLE_NAME)
+ CFBundleIdentifier
+ $(PRODUCT_BUNDLE_IDENTIFIER)
+ CFBundleInfoDictionaryVersion
+ 6.0
+ CFBundleLocalizations
+
+ en
+ zh_TW
+ zh_CN
+ zh_HK
+ ko
+ ja
+ vi
+ ru
+ tr
+ de
+ es
+ pt
+ tl
+ id
+ it
+ fr
+
+ CFBundleName
+ axs
+ CFBundlePackageType
+ APPL
+ CFBundleShortVersionString
+ $(FLUTTER_BUILD_NAME)
+ CFBundleSignature
+ ????
+ CFBundleVersion
+ $(FLUTTER_BUILD_NUMBER)
+ LSApplicationQueriesSchemes
+
+ tg
+ weixin
+ wechat
+ googlegmail
+ x-dispatch
+ readdle-spark
+ airmail
+ ms-outlook
+ ymail
+ fastmail
+ superhuman
+ protonmail
+
+ LSRequiresIPhoneOS
+
+ LSSupportsOpeningDocumentsInPlace
+ No
+ NSAppTransportSecurity
+
+ NSAllowsArbitraryLoads
+
+
+ NSAppleMusicUsageDescription
+ Would you allow AXS Wallet to use the Media Library?
+ NSBluetoothPeripheralUsageDescription
+ Would you allow AXS Wallet to use the Bluetooth?
+ NSCalendarsUsageDescription
+ Would you allow AXS Wallet to use the Calendar?
+ NSCameraUsageDescription
+ AXS Wallet needs access to your camera when the app is in use for services such as RWA minting. Image data is not saved or shared with any third parties.
+ NSFaceIDUsageDescription
+ AXS Wallet needs access to your Biometric data when the app is in use for authentication only. Your Biometric data is not saved or shared with any third parties.
+ NSLocationAlwaysAndWhenInUseUsageDescription
+ AXS Wallet needs access to your location for features such as Wi-Fi hooks while the app is in use or running in the background. Your location data is not saved or shared with any third parties.
- NSLocationAlwaysUsageDescription
- AXS Wallet requires access to your location at all times for services such as Wi-Fi hooks. Your location data is not saved or shared with any third parties.
+ NSLocationAlwaysUsageDescription
+ AXS Wallet requires access to your location at all times for services such as Wi-Fi hooks. Your location data is not saved or shared with any third parties.
- NSLocationUsageDescription
- AXS Wallet needs access to your location to provide services such as Wi-Fi hooks. Your location data is not saved or shared with any third parties.
+ NSLocationUsageDescription
+ AXS Wallet needs access to your location to provide services such as Wi-Fi hooks. Your location data is not saved or shared with any third parties.
- NSLocationWhenInUseUsageDescription
- AXS Wallet needs access to your location when the app is in use for services such as Wi-Fi hooks. Your location data is not saved or shared with any third parties.
- NSMotionUsageDescription
- Would you allow AXS Wallet to use the Motion?
- NSPhotoLibraryAddUsageDescription
- AXS Wallet needs access to your photos to save images such as RWA. Your photos are not saved or shared with any third parties.
- NSPhotoLibraryUsageDescription
- AXS Wallet needs access to your photos when the app is in use for services such as RWA minting. Your photos are not saved or shared with any third parties.
- NSSpeechRecognitionUsageDescription
- Would you allow AXS Wallet to use the Speech Recognition?
- PermissionGroupNotification
- Would you allow AXS Wallet to use the Notification?
- UIApplicationSupportsIndirectInputEvents
-
- UIBackgroundModes
-
- fetch
- location
- processing
- remote-notification
-
- UILaunchStoryboardName
- LaunchScreen
- UIMainStoryboardFile
- Main
- UISupportedInterfaceOrientations
-
- UIInterfaceOrientationPortrait
- UIInterfaceOrientationLandscapeLeft
- UIInterfaceOrientationLandscapeRight
-
- UISupportedInterfaceOrientations~ipad
-
- UIInterfaceOrientationPortrait
- UIInterfaceOrientationPortraitUpsideDown
- UIInterfaceOrientationLandscapeLeft
- UIInterfaceOrientationLandscapeRight
-
- UIViewControllerBasedStatusBarAppearance
-
-
+ NSLocationWhenInUseUsageDescription
+ AXS Wallet needs access to your location when the app is in use for services such as Wi-Fi hooks. Your location data is not saved or shared with any third parties.
+ NSMotionUsageDescription
+ Would you allow AXS Wallet to use the Motion?
+ NSPhotoLibraryAddUsageDescription
+ AXS Wallet needs access to your photos to save images such as RWA. Your photos are not saved or shared with any third parties.
+ NSPhotoLibraryUsageDescription
+ AXS Wallet needs access to your photos when the app is in use for services such as RWA minting. Your photos are not saved or shared with any third parties.
+ NSSpeechRecognitionUsageDescription
+ Would you allow AXS Wallet to use the Speech Recognition?
+ PermissionGroupNotification
+ Would you allow AXS Wallet to use the Notification?
+ UIApplicationSupportsIndirectInputEvents
+
+ UIBackgroundModes
+
+ fetch
+ location
+ processing
+ remote-notification
+
+ UILaunchStoryboardName
+ LaunchScreen
+ UIMainStoryboardFile
+ Main
+ UISupportedInterfaceOrientations
+
+ UIInterfaceOrientationPortrait
+ UIInterfaceOrientationLandscapeLeft
+ UIInterfaceOrientationLandscapeRight
+
+ UISupportedInterfaceOrientations~ipad
+
+ UIInterfaceOrientationPortrait
+ UIInterfaceOrientationPortraitUpsideDown
+ UIInterfaceOrientationLandscapeLeft
+ UIInterfaceOrientationLandscapeRight
+
+ UIViewControllerBasedStatusBarAppearance
+
+ UISupportsDocumentBrowser
+
+
diff --git a/ios/appcenter-post-clone.sh b/ios/appcenter-post-clone.sh
index 7bbc81d8..dc28dc06 100644
--- a/ios/appcenter-post-clone.sh
+++ b/ios/appcenter-post-clone.sh
@@ -27,9 +27,10 @@ flutter build ios --release --no-codesign
## To configure appCenter builds with Waldo UI Automation tool
export WALDO_CLI_BIN=/usr/local/bin
-
bash -c "$(curl -fLs https://github.com/waldoapp/waldo-go-cli/raw/master/install-waldo.sh)"
+export PATH="$WALDO_CLI_BIN:$PATH"
+
# Remove START-SIM-SEC secion from Podfile
sed -i '' "/#-START-SIM-SEC/,/#-END-SIM-SEC/d" 'ios/Podfile'
flutter build ios --simulator
@@ -38,6 +39,8 @@ flutter build ios --simulator
_build_path="build/ios/iphonesimulator/Runner.app"
# adjust this as necessary
-export WALDO_UPLOAD_TOKEN=7359ffbc47e3005dd303a0161d48b890
+export WALDO_UPLOAD_TOKEN=$IOS_WALDO_UPLOAD_TOKEN
+
+# waldo auth $IOS_WALDO_UPLOAD_TOKEN
-/usr/local/bin/waldo upload "$_build_path"
+waldo upload "$_build_path"
diff --git a/lib/common/layout/mxc_page.dart b/lib/common/layout/mxc_page.dart
index b834045f..f10270a4 100644
--- a/lib/common/layout/mxc_page.dart
+++ b/lib/common/layout/mxc_page.dart
@@ -31,6 +31,7 @@ abstract class MxcPage extends HookConsumerWidget {
this.fixedFooter = false,
this.floatingActionButton,
this.backgroundColor,
+ this.backgroundGradient,
this.useFooterPadding = true,
this.resizeToAvoidBottomInset = true,
this.useSplashBackground = false,
@@ -55,6 +56,7 @@ abstract class MxcPage extends HookConsumerWidget {
bool fixedFooter,
Widget? floatingActionButton,
Color? backgroundColor,
+ Gradient? backgroundGradient,
bool useFooterPadding,
bool resizeToAvoidBottomInset,
bool useSplashBackground,
@@ -103,6 +105,7 @@ abstract class MxcPage extends HookConsumerWidget {
final bool fixedFooter;
final Widget? floatingActionButton;
final Color? backgroundColor;
+ final Gradient? backgroundGradient;
final bool resizeToAvoidBottomInset;
final bool useSplashBackground;
@@ -169,6 +172,9 @@ abstract class MxcPage extends HookConsumerWidget {
bool get maintainBottomSafeArea => true;
Color resolveBackgroundColor(BuildContext context) {
+ if (backgroundGradient != null) {
+ return Colors.transparent;
+ }
if (backgroundColor != null) {
return backgroundColor!;
}
@@ -221,40 +227,45 @@ abstract class MxcPage extends HookConsumerWidget {
? Brightness.dark
: Brightness.light,
),
- child: Scaffold(
- backgroundColor: resolveBackgroundColor(context),
- extendBodyBehindAppBar: false,
- drawer: drawer,
- key: scaffoldKey,
- resizeToAvoidBottomInset: false,
- floatingActionButton: floatingActionButton,
- bottomNavigationBar: buildBottomNavigation(context, ref),
- floatingActionButtonLocation:
- FloatingActionButtonLocation.miniCenterFloat,
- body: PresenterHooks(
- presenter: presenter,
- child: splashLinearBackground(
- visiable: useSplashBackground,
- child: SafeArea(
- bottom: maintainBottomSafeArea,
- top: topSafeArea,
- child: Column(
- children: [
- buildAppBar(context, ref),
- Expanded(
- child: Padding(
- padding: childrenPadding ?? EdgeInsets.zero,
- child: content(context, ref),
- )),
- if (placeBottomInsetFiller)
- AnimatedSize(
- curve: Curves.easeOutQuad,
- duration: const Duration(milliseconds: 275),
- child: SizedBox(
- height: MediaQuery.of(context).viewInsets.bottom,
+ child: Container(
+ decoration: BoxDecoration(
+ gradient: backgroundGradient,
+ ),
+ child: Scaffold(
+ backgroundColor: resolveBackgroundColor(context),
+ extendBodyBehindAppBar: false,
+ drawer: drawer,
+ key: scaffoldKey,
+ resizeToAvoidBottomInset: false,
+ floatingActionButton: floatingActionButton,
+ bottomNavigationBar: buildBottomNavigation(context, ref),
+ floatingActionButtonLocation:
+ FloatingActionButtonLocation.miniCenterFloat,
+ body: PresenterHooks(
+ presenter: presenter,
+ child: splashLinearBackground(
+ visiable: useSplashBackground,
+ child: SafeArea(
+ bottom: maintainBottomSafeArea,
+ top: topSafeArea,
+ child: Column(
+ children: [
+ buildAppBar(context, ref),
+ Expanded(
+ child: Padding(
+ padding: childrenPadding ?? EdgeInsets.zero,
+ child: content(context, ref),
+ )),
+ if (placeBottomInsetFiller)
+ AnimatedSize(
+ curve: Curves.easeOutQuad,
+ duration: const Duration(milliseconds: 275),
+ child: SizedBox(
+ height: MediaQuery.of(context).viewInsets.bottom,
+ ),
),
- ),
- ],
+ ],
+ ),
),
),
),
diff --git a/lib/common/layout/mxc_page_layer.dart b/lib/common/layout/mxc_page_layer.dart
index 60eba807..d9a02288 100644
--- a/lib/common/layout/mxc_page_layer.dart
+++ b/lib/common/layout/mxc_page_layer.dart
@@ -30,6 +30,7 @@ class MxcPageLayer extends MxcPage {
bool fixedFooter = false,
Widget? floatingActionButton,
Color? backgroundColor,
+ Gradient? backgroundGradient,
bool useFooterPadding = true,
bool resizeToAvoidBottomInset = true,
bool useSplashBackground = false,
@@ -53,6 +54,7 @@ class MxcPageLayer extends MxcPage {
fixedFooter: fixedFooter,
floatingActionButton: floatingActionButton,
backgroundColor: backgroundColor,
+ backgroundGradient: backgroundGradient,
useFooterPadding: useFooterPadding,
resizeToAvoidBottomInset: resizeToAvoidBottomInset,
useSplashBackground: useSplashBackground,
diff --git a/lib/common/layout/mxc_page_regular.dart b/lib/common/layout/mxc_page_regular.dart
index 21dc2cfc..89b361b1 100644
--- a/lib/common/layout/mxc_page_regular.dart
+++ b/lib/common/layout/mxc_page_regular.dart
@@ -26,6 +26,7 @@ class MxcPageRegular extends MxcPage {
bool fixedFooter = false,
Widget? floatingActionButton,
Color? backgroundColor,
+ Gradient? backgroundGradient,
bool useFooterPadding = true,
bool resizeToAvoidBottomInset = true,
bool useSplashBackground = false,
@@ -48,6 +49,7 @@ class MxcPageRegular extends MxcPage {
fixedFooter: fixedFooter,
floatingActionButton: floatingActionButton,
backgroundColor: backgroundColor,
+ backgroundGradient: backgroundGradient,
useFooterPadding: useFooterPadding,
resizeToAvoidBottomInset: resizeToAvoidBottomInset,
useSplashBackground: useSplashBackground,
diff --git a/lib/common/utils/permission.dart b/lib/common/utils/permission.dart
index bd3a2512..bac758a8 100644
--- a/lib/common/utils/permission.dart
+++ b/lib/common/utils/permission.dart
@@ -1,3 +1,5 @@
+import 'dart:io';
+
import 'package:datadashwallet/common/utils/permissions_bottom_sheet.dart';
import 'package:f_logs/f_logs.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
@@ -31,6 +33,9 @@ class PermissionUtils {
static Future showUseCaseBottomSheet(
Permission permission, BuildContext context) async {
+ if (Platform.isIOS) {
+ return true;
+ }
return showPermissionUseCasesBottomSheet(context, permission: permission);
}
@@ -89,6 +94,31 @@ class PermissionUtils {
return status == PermissionStatus.granted;
}
+ static void storagePermissionWrapper(Future Function() func,
+ Function addError, BuildContext context) async {
+ final askForPermission = await PermissionUtils.showUseCaseBottomSheet(
+ Permission.storage, context);
+ if (askForPermission ?? false) {
+ final result = await PermissionUtils.askForStoragePermission();
+ if (result) {
+ try {
+ await func();
+ } catch (e, s) {
+ addError(e, s);
+ }
+ }
+ }
+ }
+
+ static Future askForStoragePermission() async {
+ final status = await Permission.manageExternalStorage.request();
+ final storageStatus = await Permission.storage.request();
+ if (Platform.isIOS) {
+ return storageStatus == PermissionStatus.granted;
+ }
+ return status == PermissionStatus.granted;
+ }
+
static Future checkNotificationPermission() async {
AuthorizationStatus authorizationStatus = await getNotificationPermission();
diff --git a/lib/common/utils/permissions_bottom_sheet.dart b/lib/common/utils/permissions_bottom_sheet.dart
index bda4d982..9ade56a5 100644
--- a/lib/common/utils/permissions_bottom_sheet.dart
+++ b/lib/common/utils/permissions_bottom_sheet.dart
@@ -79,7 +79,7 @@ String getPermissionUseCaseText(Permission permission) {
} else if (Permission.camera == permission) {
return 'axs_camera_permission_use_case';
} else if (Permission.storage == permission) {
- return 'axs_photos_permission_use_case';
+ return 'axs_storage_permission_use_case';
} else if (Permission.photos == permission) {
return 'axs_photos_permission_use_case';
} else {
diff --git a/lib/core/src/providers/providers_use_cases.dart b/lib/core/src/providers/providers_use_cases.dart
index 00a83728..2071c11f 100644
--- a/lib/core/src/providers/providers_use_cases.dart
+++ b/lib/core/src/providers/providers_use_cases.dart
@@ -42,7 +42,8 @@ final Provider gesturesInstructionUseCaseProvider =
);
final Provider dappsOrderUseCaseProvider = Provider(
- (ref) => DappsOrderUseCase(ref.watch(datadashCacheProvider).dappsOrderRepository),
+ (ref) =>
+ DappsOrderUseCase(ref.watch(datadashCacheProvider).dappsOrderRepository),
);
final Provider tokenContractUseCaseProvider = Provider(
@@ -104,6 +105,10 @@ final Provider authUseCaseProvider = Provider(
),
);
+final Provider directoryUseCaseProvider = Provider(
+ (ref) => DirectoryUseCase(),
+);
+
final Provider accountUseCaseProvider = Provider(
(ref) => AccountUseCase(
ref.watch(web3RepositoryProvider),
diff --git a/lib/features/common/app_nav_bar/app_nav_bar.dart b/lib/features/common/app_nav_bar/app_nav_bar.dart
index 47b141e7..76b6f66b 100644
--- a/lib/features/common/app_nav_bar/app_nav_bar.dart
+++ b/lib/features/common/app_nav_bar/app_nav_bar.dart
@@ -44,7 +44,7 @@ class AppNavBar extends HookConsumerWidget {
padding: const EdgeInsets.all(Sizes.space2XSmall),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(50),
- color: ColorsTheme.of(context).backgroundDisabled,
+ color: ColorsTheme.of(context).iconPrimary,
),
child: GestureDetector(
onTap: () => presenter.copy(),
@@ -59,7 +59,9 @@ class AppNavBar extends HookConsumerWidget {
state.account?.mns ??
MXCFormatter.formatWalletAddress(
state.account?.address ?? ''),
- style: FontTheme.of(context).subtitle1(),
+ style: FontTheme.of(context).subtitle1().copyWith(
+ color: ColorsTheme.of(context).screenBackground,
+ ),
)
],
),
diff --git a/lib/features/dapps/domain/dapp_store_use_case.dart b/lib/features/dapps/domain/dapp_store_use_case.dart
index 2fd26dbd..d1846250 100644
--- a/lib/features/dapps/domain/dapp_store_use_case.dart
+++ b/lib/features/dapps/domain/dapp_store_use_case.dart
@@ -14,12 +14,21 @@ class DappStoreUseCase extends ReactiveUseCase {
late final ValueStream> dapps = reactive([]);
- loadLocalDApps() async {
+ Future loadDapps() async {
+ Future.delayed(
+ const Duration(seconds: 1),
+ () => loadLocalDApps(),
+ );
+
+ await loadRemoteDApps();
+ }
+
+ Future loadLocalDApps() async {
final result = await _repository.dappStoreRepository.getAllDappsFromLocal();
update(dapps, result);
}
- Future getAllDapps() async {
+ Future loadRemoteDApps() async {
final result = await _repository.dappStoreRepository.getAllDapps();
update(dapps, result);
diff --git a/lib/features/dapps/helpers/permissions_helpers.dart b/lib/features/dapps/helpers/permissions_helpers.dart
index 10d2c64a..fe1a98d5 100644
--- a/lib/features/dapps/helpers/permissions_helpers.dart
+++ b/lib/features/dapps/helpers/permissions_helpers.dart
@@ -53,7 +53,6 @@ class PermissionsHelper {
Future checkPermissionStatusAndRequest(
Permission permission,
) async {
- final l = await permission.status;
if (!(await PermissionUtils.isPermissionGranted(permission)) &&
!(await PermissionUtils.isPermissionPermanentlyDenied(permission))) {
final askForPermission =
diff --git a/lib/features/dapps/helpers/reorder_helper.dart b/lib/features/dapps/helpers/reorder_helper.dart
index ee16a837..255c20e5 100644
--- a/lib/features/dapps/helpers/reorder_helper.dart
+++ b/lib/features/dapps/helpers/reorder_helper.dart
@@ -1,7 +1,4 @@
-import 'dart:async';
-
import 'package:datadashwallet/features/dapps/presentation/responsive_layout/dapp_utils.dart';
-import 'package:flutter/material.dart';
import 'package:mxc_logic/mxc_logic.dart';
import '../domain/domain.dart';
diff --git a/lib/features/dapps/presentation/dapps_page.dart b/lib/features/dapps/presentation/dapps_page.dart
index 057f1c88..5abdd1d5 100644
--- a/lib/features/dapps/presentation/dapps_page.dart
+++ b/lib/features/dapps/presentation/dapps_page.dart
@@ -1,9 +1,6 @@
import 'package:datadashwallet/common/common.dart';
-import 'package:datadashwallet/core/core.dart';
-import 'package:datadashwallet/features/common/common.dart';
-import 'package:datadashwallet/features/dapps/dapps.dart';
-import 'package:datadashwallet/features/settings/settings.dart';
-import 'package:datadashwallet/features/wallet/wallet.dart';
+import 'package:datadashwallet/features/dapps/presentation/widgets/default_app_bar.dart';
+import 'package:datadashwallet/features/dapps/presentation/widgets/edit_mode_app_bar.dart';
import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:mxc_ui/mxc_ui.dart';
@@ -11,7 +8,6 @@ import 'package:mxc_ui/mxc_ui.dart';
import 'dapps_presenter.dart';
import 'dapps_state.dart';
import 'responsive_layout/responsive_layout.dart';
-import 'widgets/edit_mode_status_bar.dart';
class DAppsPage extends HookConsumerWidget {
const DAppsPage({Key? key}) : super(key: key);
@@ -29,41 +25,22 @@ class DAppsPage extends HookConsumerWidget {
return MxcPage(
layout: LayoutType.column,
useContentPadding: false,
- childrenPadding: const EdgeInsets.symmetric(horizontal: 12, vertical: 16),
- backgroundColor: ColorsTheme.of(context).screenBackground,
+ childrenPadding: const EdgeInsets.symmetric(
+ horizontal: Sizes.spaceSmall, vertical: Sizes.spaceNormal),
+ backgroundGradient: const LinearGradient(
+ colors: [
+ Color(0xFF0E1629),
+ Color(0xFF333333),
+ ],
+ begin: Alignment.topLeft,
+ end: Alignment.bottomRight,
+ ),
presenter: ref.watch(presenter),
appBar: Column(
children: [
- if (ref.watch(state).isEditMode) ...[
- EditAppsModeStatusBar(
- onAdd: dappsPresenter.addBookmark,
- onDone: dappsPresenter.changeEditMode,
- ),
- ],
- AppNavBar(
- leading: IconButton(
- key: const ValueKey('settingsButton'),
- icon: const Icon(MxcIcons.settings),
- iconSize: 32,
- onPressed: () {
- Navigator.of(context).push(
- route(
- const SettingsPage(),
- ),
- );
- },
- color: ColorsTheme.of(context).iconPrimary,
- ),
- action: IconButton(
- key: const ValueKey('walletButton'),
- icon: const Icon(MxcIcons.wallet),
- iconSize: 32,
- onPressed: () => Navigator.of(context).replaceAll(
- route(const WalletPage()),
- ),
- color: ColorsTheme.of(context).iconPrimary,
- ),
- ),
+ ref.watch(state).isEditMode
+ ? const EditModeAppBar()
+ : const DefaultAppBar(),
],
),
children: const [
diff --git a/lib/features/dapps/presentation/dapps_presenter.dart b/lib/features/dapps/presentation/dapps_presenter.dart
index b76c3b69..f64aa16a 100644
--- a/lib/features/dapps/presentation/dapps_presenter.dart
+++ b/lib/features/dapps/presentation/dapps_presenter.dart
@@ -96,6 +96,8 @@ class DAppsPagePresenter extends CompletePresenter {
listen(_chainConfigurationUseCase.selectedNetwork, (value) {
if (value != null) {
if (state.network != null && state.network!.chainId != value.chainId) {
+ DappUtils.loadingOnce = true;
+ notify(() => state.loading = true);
reorderHelper.resetDappsMerge();
}
notify(() => state.network = value);
@@ -157,7 +159,7 @@ class DAppsPagePresenter extends CompletePresenter {
void initializeDapps() async {
try {
- await _dappStoreUseCase.getAllDapps();
+ await _dappStoreUseCase.loadDapps();
} catch (e, s) {
addError(e, s);
}
@@ -171,7 +173,8 @@ class DAppsPagePresenter extends CompletePresenter {
void addBookmark() async => bookmarksHelper.addBookmark();
- void updateBookmarkFavIcon(Bookmark item) async => bookmarksHelper.updateBookmarkFavIcon(item);
+ void updateBookmarkFavIcon(Bookmark item) async =>
+ bookmarksHelper.updateBookmarkFavIcon(item);
void onPageChage(int index) => notify(() => state.pageIndex = index);
diff --git a/lib/features/dapps/presentation/responsive_layout/card_item.dart b/lib/features/dapps/presentation/responsive_layout/card_item.dart
deleted file mode 100644
index c90e48dd..00000000
--- a/lib/features/dapps/presentation/responsive_layout/card_item.dart
+++ /dev/null
@@ -1,39 +0,0 @@
-import 'package:flutter/material.dart';
-import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart';
-
-class CardCrossAxisCount {
- static const int mobile = 4;
- static const int tablet = 5;
-}
-
-class CardMainAxisCount {
- static const int mobile = 3;
- static const int tablet = 4;
-}
-
-
-class CardSizes {
- static Widget large({required Widget child}) {
- return StaggeredGridTile.count(
- crossAxisCellCount: 4,
- mainAxisCellCount: 2,
- child: child,
- );
- }
-
- static Widget medium({required Widget child}) {
- return StaggeredGridTile.count(
- crossAxisCellCount: 2,
- mainAxisCellCount: 2,
- child: child,
- );
- }
-
- static Widget small({required Widget child}) {
- return StaggeredGridTile.count(
- crossAxisCellCount: 1,
- mainAxisCellCount: 1,
- child: child,
- );
- }
-}
diff --git a/lib/features/dapps/presentation/responsive_layout/dapp_card.dart b/lib/features/dapps/presentation/responsive_layout/dapp_card.dart
deleted file mode 100644
index bc5c324c..00000000
--- a/lib/features/dapps/presentation/responsive_layout/dapp_card.dart
+++ /dev/null
@@ -1,91 +0,0 @@
-import 'package:cached_network_image/cached_network_image.dart';
-import 'package:flutter/material.dart';
-import 'package:mxc_logic/mxc_logic.dart';
-import 'package:mxc_ui/mxc_ui.dart';
-
-class DappCard extends StatelessWidget {
- const DappCard({
- super.key,
- required this.dapp,
- this.isEditMode = false,
- this.onTap,
- this.onLongPress,
- this.onRemoveTap,
- });
-
- final Dapp dapp;
- final bool isEditMode;
- final VoidCallback? onTap;
- final VoidCallback? onLongPress;
- final Function(Bookmark?)? onRemoveTap;
-
- Widget cardBox(BuildContext context) {
- final bookmark = dapp is Bookmark ? dapp as Bookmark : null;
- if (bookmark != null) {
- return Container(
- padding: const EdgeInsets.all(2),
- width: double.infinity,
- height: double.infinity,
- alignment: Alignment.center,
- decoration: BoxDecoration(
- borderRadius: const BorderRadius.all(
- Radius.circular(8),
- ),
- color: ColorsTheme.of(context).cardBackground,
- ),
- child: Text(
- bookmark.title,
- style: FontTheme.of(context).subtitle2().copyWith(
- color: ColorsTheme.of(context).textSecondary,
- ),
- overflow: TextOverflow.ellipsis,
- ),
- );
- } else {
- final icons = dapp.reviewApi!.icons!;
- final image = icons.islarge != null && icons.islarge!
- ? icons.iconLarge
- : icons.iconSmall;
-
- return ClipRRect(
- borderRadius: BorderRadius.circular(22),
- child: image!.contains('https')
- ? CachedNetworkImage(
- imageUrl: image,
- fit: BoxFit.cover,
- )
- : Image.asset(image));
- }
- }
-
- @override
- Widget build(BuildContext context) {
- return GestureDetector(
- onTap: onTap,
- onLongPress: onLongPress,
- child: Stack(
- children: [
- Padding(
- padding: const EdgeInsets.all(4),
- child: Center(
- child: cardBox(context),
- ),
- ),
- if (isEditMode)
- Positioned(
- top: -2,
- left: -2,
- child: InkWell(
- onTap: onRemoveTap != null
- ? () => onRemoveTap!(dapp as Bookmark)
- : null,
- child: const Icon(
- Icons.remove_circle_rounded,
- ),
- ),
- ),
- ],
- ),
- );
- }
-}
diff --git a/lib/features/dapps/presentation/responsive_layout/dapp_card_layout.dart b/lib/features/dapps/presentation/responsive_layout/dapp_card_layout.dart
index c2b20a32..123cc7dc 100644
--- a/lib/features/dapps/presentation/responsive_layout/dapp_card_layout.dart
+++ b/lib/features/dapps/presentation/responsive_layout/dapp_card_layout.dart
@@ -7,10 +7,10 @@ import 'package:reorderable_grid_view/reorderable_grid_view.dart';
import '../dapps_state.dart';
import '../widgets/dapp_indicator.dart';
-import 'card_item.dart';
+import 'dapps_layout/card_item.dart';
import 'dapp_loading.dart';
import 'dapp_utils.dart';
-import 'new_dapp_card.dart';
+import 'dapps_layout/dapp_card.dart';
class DappCardLayout extends HookConsumerWidget {
const DappCardLayout({
@@ -82,6 +82,9 @@ class DappCardLayout extends HookConsumerWidget {
},
),
),
+ const SizedBox(
+ height: Sizes.spaceXLarge,
+ ),
DAppIndicator(
total: pages,
selectedIndex: state.pageIndex,
@@ -99,7 +102,7 @@ List getList(List dapps, DAppsPagePresenter actions,
final item = dapps[i];
final isBookMark = item is Bookmark;
final dappCard = isBookMark
- ? NewDAppCard(
+ ? DAppCard(
index: i,
width: itemWidth,
dapp: item,
@@ -107,7 +110,7 @@ List getList(List dapps, DAppsPagePresenter actions,
onTap: state.isEditMode ? null : () => actions.openDapp(item.url),
mainAxisCount: mainAxisCount,
)
- : NewDAppCard(
+ : DAppCard(
index: i,
width: itemWidth,
dapp: item,
diff --git a/lib/features/dapps/presentation/responsive_layout/dapp_loading.dart b/lib/features/dapps/presentation/responsive_layout/dapp_loading.dart
index 724cda7e..e3844fd2 100644
--- a/lib/features/dapps/presentation/responsive_layout/dapp_loading.dart
+++ b/lib/features/dapps/presentation/responsive_layout/dapp_loading.dart
@@ -1,9 +1,8 @@
import 'package:flutter/material.dart';
-import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart';
import 'package:mxc_ui/mxc_ui.dart';
import 'package:shimmer/shimmer.dart';
-import 'card_item.dart';
+import 'dapps_layout/card_item.dart';
class DAppLoading extends StatelessWidget {
const DAppLoading({
diff --git a/lib/features/dapps/presentation/responsive_layout/dapp_utils.dart b/lib/features/dapps/presentation/responsive_layout/dapp_utils.dart
index 56e9b393..2d1016bf 100644
--- a/lib/features/dapps/presentation/responsive_layout/dapp_utils.dart
+++ b/lib/features/dapps/presentation/responsive_layout/dapp_utils.dart
@@ -2,7 +2,7 @@ import 'dart:io';
import 'package:flutter/material.dart';
import 'package:mxc_logic/mxc_logic.dart';
-import 'card_item.dart';
+import 'dapps_layout/card_item.dart';
class DappUtils {
static bool loadingOnce = true;
@@ -25,7 +25,9 @@ class DappUtils {
if (e is Bookmark) {
return true;
} else {
- return (e.store!.chainid == chainId) &&
+ return (!MXCChains.isMXCChains(chainId)
+ ? MXCChains.isMXCMainnet(e.store!.chainid!)
+ : e.store!.chainid == chainId) &&
isSupported(e.app!.supportedPlatforms!);
}
}).toList();
@@ -44,8 +46,8 @@ class DappUtils {
// Sort the DApps list based on the order specified in dappsOrder
dapps.sort((a, b) {
- final aUrl = a is Bookmark ? a.url : a.app!.url!;
- final bUrl = b is Bookmark ? b.url : b.app!.url!;
+ final aUrl = a is Bookmark ? a.url : a.app!.url!;
+ final bUrl = b is Bookmark ? b.url : b.app!.url!;
int indexA = urlIndices[aUrl] ?? dapps.length;
int indexB = urlIndices[bUrl] ?? dapps.length;
return dappsOrder.indexOf(aUrl) - dappsOrder.indexOf(bUrl);
diff --git a/lib/features/dapps/presentation/responsive_layout/dapps_layout/build_card.dart b/lib/features/dapps/presentation/responsive_layout/dapps_layout/build_card.dart
new file mode 100644
index 00000000..c72e5fe9
--- /dev/null
+++ b/lib/features/dapps/presentation/responsive_layout/dapps_layout/build_card.dart
@@ -0,0 +1,133 @@
+import 'package:cached_network_image/cached_network_image.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter_svg/flutter_svg.dart';
+import 'package:mxc_logic/mxc_logic.dart';
+import 'package:mxc_ui/mxc_ui.dart';
+
+import '../../dapps_presenter.dart';
+import 'card_item.dart';
+
+Widget buildCard(
+ BuildContext context,
+ Dapp dapp,
+ int mainAxisCount,
+ VoidCallback? onTap,
+ bool isEditMode,
+ double width, {
+ double? ratioFactor,
+ DAppsPagePresenter? actions,
+ void Function()? shatter,
+ bool animated = false,
+}) {
+
+ final isMobile = mainAxisCount == CardMainAxisCount.mobile;
+ final imageRatioFactor = (isMobile ? 0.2 : 0.1);
+ String? image;
+ if (dapp is Bookmark) {
+ if ((dapp as Bookmark).image != null) {
+ image = (dapp as Bookmark).image!;
+ } else {
+ actions!.updateBookmarkFavIcon(dapp as Bookmark);
+ }
+ } else {
+ image = dapp.reviewApi!.icon!;
+ }
+ final name = dapp is Bookmark ? (dapp as Bookmark).title : dapp.app!.name!;
+ final imageSize = width * (ratioFactor ?? imageRatioFactor);
+ return GestureDetector(
+ onTap: () {
+ if (animated) {
+ Navigator.pop(context);
+ Future.delayed(
+ const Duration(milliseconds: 500),
+ () => onTap!(),
+ );
+ } else if (onTap != null) {
+ onTap();
+ }
+ },
+ child: Column(
+ mainAxisSize: MainAxisSize.max,
+ mainAxisAlignment: MainAxisAlignment.center,
+ children: [
+ Stack(
+ clipBehavior: Clip.none,
+ children: [
+ Container(
+ padding: const EdgeInsets.all(Sizes.spaceLarge),
+ decoration: BoxDecoration(
+ borderRadius: const BorderRadius.all(Radius.circular(15)),
+ gradient: LinearGradient(
+ colors: [
+ ColorsTheme.of(context).textBlack100,
+ ColorsTheme.of(context).iconBlack200,
+ ],
+ begin: AlignmentDirectional.bottomEnd,
+ end: AlignmentDirectional.topStart,
+ ),
+ ),
+ child: SizedBox(
+ width: imageSize,
+ height: imageSize,
+ child: image == null
+ ? Icon(
+ Icons.image_not_supported_rounded,
+ color: ColorsTheme.of(context).textPrimary,
+ )
+ : image.contains('https') && dapp is Bookmark
+ ? CachedNetworkImage(
+ imageUrl: image,
+ fit: BoxFit.cover,
+ errorWidget: (context, url, error) {
+ return Column(
+ children: [
+ Icon(
+ Icons.image_not_supported_outlined,
+ color: ColorsTheme.of(context).textError,
+ ),
+ const SizedBox(
+ height: Sizes.spaceXSmall,
+ ),
+ ],
+ );
+ },
+ )
+ : image.contains('https')
+ ? SvgPicture.network(
+ image,
+ )
+ : SvgPicture.asset(
+ image,
+ ),
+ ),
+ ),
+ if (isEditMode && dapp is Bookmark)
+ Positioned(
+ top: -6,
+ left: -6,
+ child: GestureDetector(
+ onTap: () =>
+ actions!.removeBookmarkDialog(dapp as Bookmark, shatter!),
+ child: const Icon(
+ Icons.remove_circle_rounded,
+ ),
+ ),
+ ),
+ ],
+ ),
+ const SizedBox(
+ height: Sizes.space2XSmall,
+ ),
+ Text(
+ name,
+ style: FontTheme.of(context)
+ .caption1
+ .primary()
+ .copyWith(fontWeight: FontWeight.w700),
+ softWrap: false,
+ overflow: TextOverflow.ellipsis,
+ ),
+ ],
+ ),
+ );
+}
diff --git a/lib/features/dapps/presentation/responsive_layout/dapps_layout/card_item.dart b/lib/features/dapps/presentation/responsive_layout/dapps_layout/card_item.dart
new file mode 100644
index 00000000..b259876b
--- /dev/null
+++ b/lib/features/dapps/presentation/responsive_layout/dapps_layout/card_item.dart
@@ -0,0 +1,9 @@
+class CardCrossAxisCount {
+ static const int mobile = 6;
+ static const int tablet = 7;
+}
+
+class CardMainAxisCount {
+ static const int mobile = 4;
+ static const int tablet = 5;
+}
diff --git a/lib/features/dapps/presentation/responsive_layout/dapps_layout/context_menu_actions.dart b/lib/features/dapps/presentation/responsive_layout/dapps_layout/context_menu_actions.dart
new file mode 100644
index 00000000..a088f053
--- /dev/null
+++ b/lib/features/dapps/presentation/responsive_layout/dapps_layout/context_menu_actions.dart
@@ -0,0 +1,120 @@
+import 'package:flutter/cupertino.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter_i18n/flutter_i18n.dart';
+import 'package:mxc_logic/mxc_logic.dart';
+import 'package:mxc_ui/mxc_ui.dart';
+
+import '../../dapps_presenter.dart';
+
+getContextMenuActions(
+ DAppsPagePresenter actions,
+ BuildContext context,
+ Dapp dapp,
+ void Function()? shatter,
+) =>
+ dapp is Bookmark?
+ ? getBookMarkContextMenuAction(
+ actions,
+ context,
+ dapp,
+ shatter!,
+ )
+ : getDAppMarkContextMenuAction(
+ actions,
+ context,
+ dapp,
+ );
+
+List getDAppMarkContextMenuAction(
+ DAppsPagePresenter actions,
+ BuildContext context,
+ Dapp dapp,
+) =>
+ [
+ CupertinoContextMenuAction(
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Text(
+ FlutterI18n.translate(context, 'about'),
+ style: FontTheme.of(context)
+ .caption1
+ .primary()
+ .copyWith(fontWeight: FontWeight.w700),
+ ),
+ Text(
+ dapp.app!.description!,
+ style: FontTheme.of(context).caption1.primary(),
+ ),
+ ],
+ )),
+ CupertinoContextMenuAction(
+ trailingIcon: Icons.phone_iphone_rounded,
+ child: Text(FlutterI18n.translate(context, 'edit_home_screen'),
+ style: FontTheme.of(context).subtitle1()),
+ onPressed: () => popWrapper(actions.changeEditMode, context)),
+ CupertinoContextMenuAction(
+ trailingIcon: Icons.add_circle_outline_rounded,
+ child: Text(FlutterI18n.translate(context, 'add_new_dapp'),
+ style: FontTheme.of(context).subtitle1()),
+ onPressed: () => popWrapper(actions.addBookmark, context)),
+ ];
+
+getBookMarkContextMenuAction(
+ DAppsPagePresenter actions,
+ BuildContext context,
+ Dapp dapp,
+ void Function() shatter,
+) =>
+ [
+ CupertinoContextMenuAction(
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Text(
+ FlutterI18n.translate(context, 'about'),
+ style: FontTheme.of(context)
+ .caption1
+ .primary()
+ .copyWith(fontWeight: FontWeight.w700),
+ ),
+ Text(
+ getDappAbout(dapp),
+ style: FontTheme.of(context).caption1.primary(),
+ ),
+ ],
+ )),
+ CupertinoContextMenuAction(
+ trailingIcon: Icons.phone_iphone_rounded,
+ child: Text(FlutterI18n.translate(context, 'edit_home_screen'),
+ style: FontTheme.of(context).body1()),
+ onPressed: () => popWrapper(actions.changeEditMode, context)),
+ CupertinoContextMenuAction(
+ trailingIcon: Icons.add_circle_outline_rounded,
+ child: Text(FlutterI18n.translate(context, 'add_new_dapp'),
+ style: FontTheme.of(context).body1()),
+ onPressed: () => popWrapper(actions.addBookmark, context)),
+ CupertinoContextMenuAction(
+ isDestructiveAction: true,
+ trailingIcon: Icons.remove_circle_outline_rounded,
+ onPressed: () => popWrapper(() async {
+ actions.removeBookmarkDialog(dapp as Bookmark, shatter);
+ }, context),
+ child: Text(FlutterI18n.translate(context, 'remove_dapp'),
+ style: FontTheme.of(context).body1Cl()))
+ ];
+
+void popWrapper(void Function()? func, BuildContext context) {
+ Navigator.pop(context);
+ Future.delayed(
+ const Duration(milliseconds: 500),
+ () => {if (func != null) func()},
+ );
+}
+
+String getDappAbout(
+ Dapp dapp,
+) {
+ final dappAbout = dapp is Bookmark ? (dapp).title : dapp.app!.description!;
+ return dappAbout;
+}
diff --git a/lib/features/dapps/presentation/responsive_layout/dapps_layout/dapp_card.dart b/lib/features/dapps/presentation/responsive_layout/dapps_layout/dapp_card.dart
new file mode 100644
index 00000000..4b957c18
--- /dev/null
+++ b/lib/features/dapps/presentation/responsive_layout/dapps_layout/dapp_card.dart
@@ -0,0 +1,126 @@
+import 'dart:math';
+
+import 'package:datadashwallet/common/components/context_menu_extended.dart';
+import 'package:flutter/cupertino.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter_hooks/flutter_hooks.dart';
+import 'package:hooks_riverpod/hooks_riverpod.dart';
+import 'package:mxc_logic/mxc_logic.dart';
+import 'package:reorderable_grid_view/reorderable_grid_view.dart';
+import '../../dapps_presenter.dart';
+import 'build_card.dart';
+import 'context_menu_actions.dart';
+import 'shatter_widget.dart';
+import 'card_item.dart';
+
+class DAppCard extends HookConsumerWidget {
+ final Dapp dapp;
+ final int index;
+ final double width;
+ final bool isEditMode;
+ final VoidCallback? onTap;
+ final int mainAxisCount;
+ const DAppCard({
+ super.key,
+ required this.index,
+ required this.width,
+ required this.dapp,
+ required this.isEditMode,
+ required this.onTap,
+ required this.mainAxisCount,
+ });
+
+ @override
+ Widget build(
+ BuildContext context,
+ WidgetRef ref,
+ ) {
+ final actions = ref.read(appsPagePageContainer.actions);
+ final dappUrl = dapp is Bookmark ? (dapp as Bookmark).url : dapp.app!.url!;
+ final isBookMark = dapp is Bookmark;
+
+ final isMobile = mainAxisCount == CardMainAxisCount.mobile;
+ final imageRatioFactor = (isMobile ? 0.2 : 0.1);
+ final animatedSize = (isMobile ? 0.25 : 0.15);
+ final sizeLimit = (imageRatioFactor / animatedSize);
+
+ final animationController = useAnimationController(
+ duration: const Duration(milliseconds: 75),
+ lowerBound: -pi / 50,
+ upperBound: pi / 50,
+ );
+
+ if (isEditMode) {
+ animationController.forward();
+ } else {
+ animationController.stop();
+ }
+
+ animationController.addStatusListener((status) {
+ if (status == AnimationStatus.completed) {
+ animationController.reverse();
+ } else if (status == AnimationStatus.dismissed) {
+ animationController.forward();
+ }
+ });
+
+ Widget getCardItem({void Function()? shatter}) {
+ if (isEditMode) {
+ return ReorderableItemView(
+ key: Key(dappUrl),
+ index: index,
+ child: AnimatedBuilder(
+ animation: animationController,
+ builder: (context, child) {
+ return Transform.rotate(
+ angle: animationController.value *
+ (pi / 8), // Adjust the range of rotation
+ child: child,
+ );
+ },
+ child: SizedBox.expand(
+ child: buildCard(
+ context, dapp, mainAxisCount, onTap, isEditMode, width,
+ shatter: shatter, actions: actions)),
+ ),
+ );
+ }
+ return CupertinoContextMenuExtended.builder(
+ builder: (context, animation) {
+ return SizedBox(
+ width: MediaQuery.of(context).size.width / (mainAxisCount),
+ height: MediaQuery.of(context).size.width / (mainAxisCount),
+ child: buildCard(
+ context,
+ dapp,
+ mainAxisCount,
+ onTap,
+ isEditMode,
+ width,
+ ratioFactor: animation.value < sizeLimit
+ ? null
+ : (animatedSize * animation.value),
+ shatter: shatter,
+ actions: actions,
+ animated: animation.value != 0.0,
+ ),
+ );
+ },
+ actions: getContextMenuActions(
+ actions,
+ context,
+ dapp,
+ shatter,
+ ),
+ );
+ }
+
+ return isBookMark
+ ? ShatteringWidget(
+ builder: (shatter) {
+ return getCardItem(shatter: shatter);
+ },
+ onShatterCompleted: () => actions.removeBookmark(dapp as Bookmark))
+ : getCardItem();
+ }
+}
diff --git a/lib/features/dapps/presentation/responsive_layout/shatter_widget.dart b/lib/features/dapps/presentation/responsive_layout/dapps_layout/shatter_widget.dart
similarity index 100%
rename from lib/features/dapps/presentation/responsive_layout/shatter_widget.dart
rename to lib/features/dapps/presentation/responsive_layout/dapps_layout/shatter_widget.dart
diff --git a/lib/features/dapps/presentation/responsive_layout/new_dapp_card.dart b/lib/features/dapps/presentation/responsive_layout/new_dapp_card.dart
deleted file mode 100644
index 2bbadcc3..00000000
--- a/lib/features/dapps/presentation/responsive_layout/new_dapp_card.dart
+++ /dev/null
@@ -1,318 +0,0 @@
-import 'dart:async';
-import 'dart:math';
-
-import 'package:cached_network_image/cached_network_image.dart';
-import 'package:datadashwallet/features/dapps/presentation/responsive_layout/card_item.dart';
-import 'package:datadashwallet/common/components/context_menu_extended.dart';
-import 'package:flutter/cupertino.dart';
-import 'package:flutter/material.dart';
-import 'package:flutter_hooks/flutter_hooks.dart';
-import 'package:flutter_i18n/flutter_i18n.dart';
-import 'package:flutter_svg/flutter_svg.dart';
-import 'package:hooks_riverpod/hooks_riverpod.dart';
-import 'package:mxc_logic/mxc_logic.dart';
-import 'package:mxc_ui/mxc_ui.dart';
-import 'package:reorderable_grid_view/reorderable_grid_view.dart';
-import '../dapps_presenter.dart';
-import 'shatter_widget.dart';
-
-class NewDAppCard extends HookConsumerWidget {
- final Dapp dapp;
- final int index;
- final double width;
- final bool isEditMode;
- final VoidCallback? onTap;
- final int mainAxisCount;
- const NewDAppCard({
- super.key,
- required this.index,
- required this.width,
- required this.dapp,
- required this.isEditMode,
- required this.onTap,
- required this.mainAxisCount,
- });
-
- Widget cardBox(
- BuildContext context, {
- double? ratioFactor,
- DAppsPagePresenter? actions,
- void Function()? shatter,
- bool animated = false,
- }) {
- String? image;
- if (dapp is Bookmark) {
- if ((dapp as Bookmark).image != null) {
- image = (dapp as Bookmark).image!;
- } else {
- actions!.updateBookmarkFavIcon(dapp as Bookmark);
- }
- } else {
- image = dapp.reviewApi!.icon!;
- }
- final name = dapp is Bookmark ? (dapp as Bookmark).title : dapp.app!.name!;
- final imageSize = width *
- (ratioFactor ??
- (mainAxisCount == CardMainAxisCount.mobile ? 0.3 : 0.2));
- return GestureDetector(
- onTap: () {
- if (animated) {
- Navigator.pop(context);
- Future.delayed(
- const Duration(milliseconds: 500),
- () => onTap!(),
- );
- } else if (onTap != null) {
- onTap!();
- }
- },
- child: Column(
- mainAxisSize: MainAxisSize.max,
- mainAxisAlignment: MainAxisAlignment.center,
- children: [
- Stack(
- clipBehavior: Clip.none,
- children: [
- Container(
- padding: const EdgeInsets.all(Sizes.spaceXLarge),
- decoration: BoxDecoration(
- borderRadius: const BorderRadius.all(Radius.circular(15)),
- gradient: LinearGradient(
- colors: [
- ColorsTheme.of(context).textBlack100,
- ColorsTheme.of(context).iconBlack200,
- ],
- begin: AlignmentDirectional.bottomEnd,
- end: AlignmentDirectional.topStart,
- ),
- ),
- child: SizedBox(
- width: imageSize,
- height: imageSize,
- child: image == null
- ? Icon(
- Icons.image_not_supported_rounded,
- color: ColorsTheme.of(context).textPrimary,
- )
- : image.contains('https') && dapp is Bookmark
- ? CachedNetworkImage(
- imageUrl: image,
- fit: BoxFit.cover,
- errorWidget: (context, url, error) {
- return Column(
- children: [
- Icon(
- Icons.image_not_supported_outlined,
- color: ColorsTheme.of(context).textError,
- ),
- const SizedBox(
- height: Sizes.spaceXSmall,
- ),
- ],
- );
- },
- )
- : image.contains('https')
- ? SvgPicture.network(
- image,
- )
- : SvgPicture.asset(
- image,
- ),
- ),
- ),
- if (isEditMode && dapp is Bookmark)
- Positioned(
- top: -6,
- left: -6,
- child: GestureDetector(
- onTap: () => actions!
- .removeBookmarkDialog(dapp as Bookmark, shatter!),
- child: const Icon(
- Icons.remove_circle_rounded,
- ),
- ),
- ),
- ],
- ),
- const SizedBox(
- height: Sizes.spaceXSmall,
- ),
- Text(
- name,
- style: FontTheme.of(context)
- .caption1
- .primary()
- .copyWith(fontWeight: FontWeight.w700),
- softWrap: false,
- overflow: TextOverflow.ellipsis,
- ),
- ],
- ),
- );
- }
-
- @override
- Widget build(
- BuildContext context,
- WidgetRef ref,
- ) {
- final state = ref.watch(appsPagePageContainer.state);
- final actions = ref.read(appsPagePageContainer.actions);
- final dapps = state.orderedDapps;
- final dappAbout =
- dapp is Bookmark ? (dapp as Bookmark).title : dapp.app!.description!;
- final dappUrl = dapp is Bookmark ? (dapp as Bookmark).url : dapp.app!.url!;
- final isBookMark = dapp is Bookmark;
-
- final animationController = useAnimationController(
- duration: const Duration(milliseconds: 75),
- lowerBound: -pi / 50,
- upperBound: pi / 50,
- );
-
- if (isEditMode) {
- animationController.forward();
- } else {
- animationController.stop();
- }
-
- animationController.addStatusListener((status) {
- if (status == AnimationStatus.completed) {
- animationController.reverse();
- } else if (status == AnimationStatus.dismissed) {
- animationController.forward();
- }
- });
-
- List getDAppMarkContextMenuAction() => [
- CupertinoContextMenuAction(
- child: Column(
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- Text(
- FlutterI18n.translate(context, 'about'),
- style: FontTheme.of(context)
- .caption1
- .primary()
- .copyWith(fontWeight: FontWeight.w700),
- ),
- Text(
- dapp.app!.description!,
- style: FontTheme.of(context).caption1.primary(),
- ),
- ],
- )),
- CupertinoContextMenuAction(
- trailingIcon: Icons.phone_iphone_rounded,
- child: Text(FlutterI18n.translate(context, 'edit_home_screen'),
- style: FontTheme.of(context).subtitle1()),
- onPressed: () => popWrapper(actions.changeEditMode, context)),
- CupertinoContextMenuAction(
- trailingIcon: Icons.add_circle_outline_rounded,
- child: Text(FlutterI18n.translate(context, 'add_new_dapp'),
- style: FontTheme.of(context).subtitle1()),
- onPressed: () => popWrapper(actions.addBookmark, context)),
- ];
-
- getBookMarkContextMenuAction(void Function() shatter) => [
- CupertinoContextMenuAction(
- child: Column(
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- Text(
- FlutterI18n.translate(context, 'about'),
- style: FontTheme.of(context)
- .caption1
- .primary()
- .copyWith(fontWeight: FontWeight.w700),
- ),
- Text(
- dappAbout,
- style: FontTheme.of(context).caption1.primary(),
- ),
- ],
- )),
- CupertinoContextMenuAction(
- trailingIcon: Icons.phone_iphone_rounded,
- child: Text(FlutterI18n.translate(context, 'edit_home_screen'),
- style: FontTheme.of(context).body1()),
- onPressed: () => popWrapper(actions.changeEditMode, context)),
- CupertinoContextMenuAction(
- trailingIcon: Icons.add_circle_outline_rounded,
- child: Text(FlutterI18n.translate(context, 'add_new_dapp'),
- style: FontTheme.of(context).body1()),
- onPressed: () => popWrapper(actions.addBookmark, context)),
- CupertinoContextMenuAction(
- isDestructiveAction: true,
- trailingIcon: Icons.remove_circle_outline_rounded,
- onPressed: () => popWrapper(() async {
- actions.removeBookmarkDialog(dapp as Bookmark, shatter);
- }, context),
- child: Text(FlutterI18n.translate(context, 'remove_dapp'),
- style: FontTheme.of(context).body1Cl()))
- ];
-
- final size = (mainAxisCount == CardMainAxisCount.mobile ? 0.5 : 0.3);
- final sizeLimit =
- (mainAxisCount == CardMainAxisCount.mobile ? 0.6000 : 0.6666);
-
- Widget getCardItem({void Function()? shatter}) {
- final contextMenuActions = dapp is Bookmark?
- ? getBookMarkContextMenuAction(shatter!)
- : getDAppMarkContextMenuAction();
- if (isEditMode) {
- return ReorderableItemView(
- key: Key(dappUrl),
- index: index,
- child: AnimatedBuilder(
- animation: animationController,
- builder: (context, child) {
- return Transform.rotate(
- angle: animationController.value *
- (pi / 8), // Adjust the range of rotation
- child: child,
- );
- },
- child: SizedBox.expand(
- child: cardBox(context, shatter: shatter, actions: actions)),
- ),
- );
- }
- return CupertinoContextMenuExtended.builder(
- builder: (context, animation) {
- return SizedBox(
- width: MediaQuery.of(context).size.width /
- (mainAxisCount - animation.value),
- height: MediaQuery.of(context).size.width /
- (mainAxisCount - animation.value),
- child: cardBox(context,
- ratioFactor: animation.value < sizeLimit
- ? null
- : (size * animation.value),
- shatter: shatter,
- actions: actions,
- animated: animation.value != 0.0),
- );
- },
- actions: contextMenuActions,
- );
- }
-
- return isBookMark
- ? ShatteringWidget(
- builder: (shatter) {
- return getCardItem(shatter: shatter);
- },
- onShatterCompleted: () => actions.removeBookmark(dapp as Bookmark))
- : getCardItem();
- }
-}
-
-void popWrapper(void Function()? func, BuildContext context) {
- Navigator.pop(context);
- Future.delayed(
- const Duration(milliseconds: 500),
- () => {if (func != null) func()},
- );
-}
diff --git a/lib/features/dapps/presentation/responsive_layout/responsive_layout.dart b/lib/features/dapps/presentation/responsive_layout/responsive_layout.dart
index c6071607..05a806f6 100644
--- a/lib/features/dapps/presentation/responsive_layout/responsive_layout.dart
+++ b/lib/features/dapps/presentation/responsive_layout/responsive_layout.dart
@@ -1,7 +1,7 @@
import 'package:flutter/material.dart';
import 'package:responsive_builder/responsive_builder.dart';
-import 'card_item.dart';
+import 'dapps_layout/card_item.dart';
import 'dapp_card_layout.dart';
class ResponsiveLayout extends StatelessWidget {
diff --git a/lib/features/dapps/presentation/widgets/default_app_bar.dart b/lib/features/dapps/presentation/widgets/default_app_bar.dart
new file mode 100644
index 00000000..76d398e4
--- /dev/null
+++ b/lib/features/dapps/presentation/widgets/default_app_bar.dart
@@ -0,0 +1,39 @@
+import 'package:datadashwallet/core/core.dart';
+import 'package:datadashwallet/features/common/common.dart';
+import 'package:datadashwallet/features/settings/presentation/settings_page.dart';
+import 'package:datadashwallet/features/wallet/presentation/wallet_page.dart';
+import 'package:flutter/material.dart';
+import 'package:mxc_ui/mxc_ui.dart';
+
+
+class DefaultAppBar extends StatelessWidget {
+ const DefaultAppBar({super.key});
+
+ @override
+ Widget build(BuildContext context) {
+ return AppNavBar(
+ leading: IconButton(
+ key: const ValueKey('settingsButton'),
+ icon: const Icon(MxcIcons.settings),
+ iconSize: Sizes.space2XLarge,
+ onPressed: () {
+ Navigator.of(context).push(
+ route(
+ const SettingsPage(),
+ ),
+ );
+ },
+ color: ColorsTheme.of(context).iconPrimary,
+ ),
+ action: IconButton(
+ key: const ValueKey('walletButton'),
+ icon: const Icon(MxcIcons.wallet),
+ iconSize: Sizes.space2XLarge,
+ onPressed: () => Navigator.of(context).replaceAll(
+ route(const WalletPage()),
+ ),
+ color: ColorsTheme.of(context).iconPrimary,
+ ),
+ );
+ }
+}
diff --git a/lib/features/dapps/presentation/widgets/edit_mode_app_bar.dart b/lib/features/dapps/presentation/widgets/edit_mode_app_bar.dart
new file mode 100644
index 00000000..37d6a2ec
--- /dev/null
+++ b/lib/features/dapps/presentation/widgets/edit_mode_app_bar.dart
@@ -0,0 +1,65 @@
+import 'package:datadashwallet/features/common/common.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter_i18n/flutter_i18n.dart';
+import 'package:hooks_riverpod/hooks_riverpod.dart';
+import 'package:mxc_ui/mxc_ui.dart';
+
+import '../dapps_presenter.dart';
+
+class EditModeAppBar extends HookConsumerWidget {
+ const EditModeAppBar({super.key});
+
+ @override
+ Widget build(BuildContext context, WidgetRef ref) {
+ final dappsPresenter = ref.watch(appsPagePageContainer.actions);
+ return AppNavBar(
+ leading: EditModeButton(
+ onTap: dappsPresenter.addBookmark,
+ child: Icon(
+ Icons.add,
+ size: 20,
+ color: ColorsTheme.of(context).screenBackground,
+ ),
+ ),
+ action: EditModeButton(
+ onTap: dappsPresenter.changeEditMode,
+ child: Text(
+ FlutterI18n.translate(context, 'done'),
+ style: FontTheme.of(context).subtitle1().copyWith(
+ color: ColorsTheme.of(context).screenBackground,
+ fontWeight: FontWeight.w700),
+ ),
+ ),
+ );
+ }
+}
+
+class EditModeButton extends StatelessWidget {
+ const EditModeButton({
+ super.key,
+ required this.child,
+ this.onTap,
+ });
+
+ final Widget child;
+ final VoidCallback? onTap;
+
+ @override
+ Widget build(BuildContext context) {
+ return GestureDetector(
+ onTap: onTap,
+ child: Container(
+ width: 56,
+ height: 22,
+ alignment: Alignment.center,
+ decoration: BoxDecoration(
+ borderRadius: const BorderRadius.all(
+ Radius.circular(30),
+ ),
+ color: ColorsTheme.of(context).iconPrimary,
+ ),
+ child: child,
+ ),
+ );
+ }
+}
diff --git a/lib/features/dapps/presentation/widgets/edit_mode_status_bar.dart b/lib/features/dapps/presentation/widgets/edit_mode_status_bar.dart
deleted file mode 100644
index 25e74b18..00000000
--- a/lib/features/dapps/presentation/widgets/edit_mode_status_bar.dart
+++ /dev/null
@@ -1,73 +0,0 @@
-import 'package:flutter/material.dart';
-import 'package:flutter_i18n/flutter_i18n.dart';
-import 'package:mxc_ui/mxc_ui.dart';
-
-class EditAppsModeStatusBar extends StatelessWidget {
- const EditAppsModeStatusBar({
- super.key,
- this.onAdd,
- this.onDone,
- });
-
- final VoidCallback? onAdd;
- final VoidCallback? onDone;
-
- @override
- Widget build(BuildContext context) {
- return Padding(
- padding: const EdgeInsets.symmetric(horizontal: 30, vertical: 5),
- child: Row(
- children: [
- EditModeButton(
- onTap: onAdd,
- child: Icon(
- Icons.add,
- size: 20,
- color: ColorsTheme.of(context).iconPrimary,
- ),
- ),
- const Spacer(),
- EditModeButton(
- onTap: onDone,
- child: Text(
- FlutterI18n.translate(context, 'done'),
- style: FontTheme.of(context).subtitle1().copyWith(
- color: ColorsTheme.of(context).textPrimary,
- fontWeight: FontWeight.w700),
- ),
- )
- ],
- ),
- );
- }
-}
-
-class EditModeButton extends StatelessWidget {
- const EditModeButton({
- super.key,
- required this.child,
- this.onTap,
- });
-
- final Widget child;
- final VoidCallback? onTap;
-
- @override
- Widget build(BuildContext context) {
- return GestureDetector(
- onTap: onTap,
- child: Container(
- width: 56,
- height: 22,
- alignment: Alignment.center,
- decoration: BoxDecoration(
- borderRadius: const BorderRadius.all(
- Radius.circular(30),
- ),
- color: ColorsTheme.of(context).grey3,
- ),
- child: child,
- ),
- );
- }
-}
diff --git a/lib/features/portfolio/subfeatures/token/send_token/send_crypto/send_crypto_page.dart b/lib/features/portfolio/subfeatures/token/send_token/send_crypto/send_crypto_page.dart
index 0f255228..7f13fb4b 100644
--- a/lib/features/portfolio/subfeatures/token/send_token/send_crypto/send_crypto_page.dart
+++ b/lib/features/portfolio/subfeatures/token/send_token/send_crypto/send_crypto_page.dart
@@ -2,7 +2,6 @@ import 'package:datadashwallet/common/common.dart';
import 'package:datadashwallet/core/core.dart';
import 'package:datadashwallet/features/settings/subfeatures/address_book/address_book.dart';
import 'package:flutter/material.dart';
-import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:flutter_i18n/flutter_i18n.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:mxc_logic/mxc_logic.dart';
diff --git a/lib/features/portfolio/subfeatures/token/send_token/send_crypto/send_crypto_presenter.dart b/lib/features/portfolio/subfeatures/token/send_token/send_crypto/send_crypto_presenter.dart
index 2053b8fe..797636a8 100644
--- a/lib/features/portfolio/subfeatures/token/send_token/send_crypto/send_crypto_presenter.dart
+++ b/lib/features/portfolio/subfeatures/token/send_token/send_crypto/send_crypto_presenter.dart
@@ -5,9 +5,6 @@ import 'package:datadashwallet/common/utils/utils.dart';
import 'package:datadashwallet/core/core.dart';
import 'package:datadashwallet/features/common/common.dart';
import 'package:datadashwallet/features/common/app_nav_bar/app_nav_bar_presenter.dart';
-import 'package:datadashwallet/features/dapps/dapps.dart';
-import 'package:ens_dart/ens_dart.dart';
-import 'package:web3dart/web3dart.dart';
import 'package:equatable/equatable.dart';
import 'package:flutter/material.dart';
import 'package:mxc_logic/mxc_logic.dart';
@@ -149,6 +146,7 @@ class SendCryptoPresenter extends CompletePresenter {
}
void transactionProcess() async {
+ loading = true;
final amount = amountController.text;
final recipient = recipientController.text;
String recipientAddress = await getAddress(recipient);
diff --git a/lib/features/settings/subfeatures/accounts/portrait.dart b/lib/features/settings/subfeatures/accounts/portrait.dart
index 7314e461..c40bd5c3 100644
--- a/lib/features/settings/subfeatures/accounts/portrait.dart
+++ b/lib/features/settings/subfeatures/accounts/portrait.dart
@@ -13,7 +13,7 @@ class Portrait extends StatelessWidget {
@override
Widget build(BuildContext context) {
return CircleAvatar(
- radius: 16,
+ radius: 14,
child: SvgPicture.string(
Jdenticon.toSvg(name),
fit: BoxFit.contain,
diff --git a/lib/features/splash/create_storage/presentation/create_storage_page.dart b/lib/features/splash/create_storage/presentation/create_storage_page.dart
index 7901a171..d8846ee0 100644
--- a/lib/features/splash/create_storage/presentation/create_storage_page.dart
+++ b/lib/features/splash/create_storage/presentation/create_storage_page.dart
@@ -29,6 +29,13 @@ class SplashStoragePage extends SplashBasePage {
@override
List setButtons(BuildContext context, WidgetRef ref) {
+ final isEmailAvailable = ref.watch(state).isEmailAppAvailable == true;
+ final isTelegramAvailable = ref.watch(state).applist['telegram'] == true ||
+ ref.watch(state).applist['telegram_web'] == true;
+ final isWeChatAvailable = ref.watch(state).applist['weixin'] == true ||
+ ref.watch(state).applist['wechat'] == true;
+ final isNoneAvailable =
+ !(isEmailAvailable || isTelegramAvailable || isWeChatAvailable);
return [
MxcButton.secondaryWhite(
key: const ValueKey('telegramButton'),
@@ -36,8 +43,7 @@ class SplashStoragePage extends SplashBasePage {
iconSize: 32,
titleSize: 18,
title: FlutterI18n.translate(context, 'telegram_secured_storage'),
- onTap: ref.watch(state).applist['telegram'] == true ||
- ref.watch(state).applist['telegram_web'] == true
+ onTap: isTelegramAvailable
? () => Navigator.of(context).push(
route.featureDialog(
TelegramRecoveryPhrasePage(
@@ -53,8 +59,7 @@ class SplashStoragePage extends SplashBasePage {
iconSize: 32,
titleSize: 18,
title: FlutterI18n.translate(context, 'wechat_secured_storage'),
- onTap: ref.watch(state).applist['weixin'] == true ||
- ref.watch(state).applist['wechat'] == true
+ onTap: isWeChatAvailable
? () => Navigator.of(context).push(
route.featureDialog(
WechatRecoveryPhrasePage(
@@ -70,7 +75,7 @@ class SplashStoragePage extends SplashBasePage {
iconSize: 32,
titleSize: 18,
title: FlutterI18n.translate(context, 'email_secured_storage'),
- onTap: ref.watch(state).isEmailAppAvailable == true
+ onTap: isEmailAvailable
? () => Navigator.of(context).push(
route.featureDialog(
EmailRecoveryPhrasePage(
@@ -80,6 +85,22 @@ class SplashStoragePage extends SplashBasePage {
)
: null,
),
+ !isNoneAvailable
+ ? MxcButton.secondaryWhite(
+ key: const ValueKey('localButton'),
+ icon: Icons.file_download_rounded,
+ iconSize: 32,
+ titleSize: 18,
+ title: FlutterI18n.translate(context, 'local_secured_storage'),
+ onTap: () => Navigator.of(context).push(
+ route.featureDialog(
+ LocalRecoveryPhrasePage(
+ settingsFlow: settingsFlow,
+ ),
+ ),
+ ),
+ )
+ : Container(),
];
}
}
diff --git a/lib/features/splash/import_storage/import_storage_page.dart b/lib/features/splash/import_storage/import_storage_page.dart
index 392a6d63..06efb43a 100644
--- a/lib/features/splash/import_storage/import_storage_page.dart
+++ b/lib/features/splash/import_storage/import_storage_page.dart
@@ -25,6 +25,11 @@ class SplashImportStoragePage extends SplashBasePage {
@override
List setButtons(BuildContext context, WidgetRef ref) {
+ final isTelegramAvailable = ref.watch(state).applist['telegram'] == true ||
+ ref.watch(state).applist['telegram_web'] == true;
+ final isWeChatAvailable = ref.watch(state).applist['weixin'] == true ||
+ ref.watch(state).applist['wechat'] == true;
+ final isNoneAvailable = !(isTelegramAvailable || isWeChatAvailable);
return [
MxcButton.secondaryWhite(
key: const ValueKey('telegramButton'),
@@ -32,8 +37,7 @@ class SplashImportStoragePage extends SplashBasePage {
iconSize: 32,
titleSize: 18,
title: FlutterI18n.translate(context, 'telegram_secured_storage'),
- onTap: ref.watch(state).applist['telegram'] == true ||
- ref.watch(state).applist['telegram_web'] == true
+ onTap: isTelegramAvailable
? () => ref.read(presenter).openTelegram()
: null,
),
@@ -43,18 +47,9 @@ class SplashImportStoragePage extends SplashBasePage {
iconSize: 32,
titleSize: 18,
title: FlutterI18n.translate(context, 'wechat_secured_storage'),
- onTap: ref.watch(state).applist['weixin'] == true ||
- ref.watch(state).applist['wechat'] == true
- ? () => ref.read(presenter).openWechat()
- : null,
+ onTap:
+ isWeChatAvailable ? () => ref.read(presenter).openWechat() : null,
),
- // MxcButton.secondaryWhite(
- // key: const ValueKey('emailButton'),
- // icon: MxcIcons.email,
- // iconSize: 20,
- // title: FlutterI18n.translate(context, 'email_secured_storage'),
- // onTap: () => ref.read(presenter).openEmail(),
- // ),
MxcButton.secondaryWhite(
key: const ValueKey('mnemonicButton'),
icon: MxcIcons.cloud,
@@ -67,6 +62,16 @@ class SplashImportStoragePage extends SplashBasePage {
),
),
),
+ !isNoneAvailable
+ ? MxcButton.secondaryWhite(
+ key: const ValueKey('localButton'),
+ icon: Icons.file_download_rounded,
+ iconSize: 32,
+ titleSize: 18,
+ title: FlutterI18n.translate(context, 'local_secured_storage'),
+ onTap: () => ref.read(presenter).openLocalSeedPhrase(),
+ )
+ : Container()
];
}
}
diff --git a/lib/features/splash/import_storage/import_storage_presenter.dart b/lib/features/splash/import_storage/import_storage_presenter.dart
index dccbb8ba..0428c5a4 100644
--- a/lib/features/splash/import_storage/import_storage_presenter.dart
+++ b/lib/features/splash/import_storage/import_storage_presenter.dart
@@ -1,8 +1,8 @@
import 'package:datadashwallet/core/core.dart';
import 'package:datadashwallet/features/splash/splash.dart';
-import 'package:flutter/material.dart';
+import 'package:mxc_logic/mxc_logic.dart';
+import 'package:open_file_manager/open_file_manager.dart';
import 'package:open_mail_app/open_mail_app.dart';
-import 'package:url_launcher/url_launcher.dart';
final splashImportStorageContainer =
PresenterContainer(
@@ -13,6 +13,7 @@ class SplashImportStoragePresenter
SplashImportStoragePresenter() : super(SplashBaseState());
late final _launcherUseCase = ref.read(launcherUseCaseProvider);
+ late final _directoryUseCase = ref.read(directoryUseCaseProvider);
@override
void initState() {
@@ -48,4 +49,19 @@ class SplashImportStoragePresenter
loading = false;
}
}
+
+ Future openLocalSeedPhrase() async {
+ const selectedFolderType = FolderType.download;
+
+ await _directoryUseCase.checkDownloadsDirectoryDirectory();
+
+ await openFileManager(
+ androidConfig: AndroidConfig(
+ folderType: selectedFolderType,
+ ),
+ iosConfig: IosConfig(
+ subFolderPath: 'Downloads',
+ ),
+ );
+ }
}
diff --git a/lib/features/splash/secure_recovery_phrase/presentation/email_recovery_phrase_alert/email_recovery_phrase_page.dart b/lib/features/splash/secure_recovery_phrase/presentation/email_recovery_phrase_alert/email_recovery_phrase_page.dart
index ab751f58..e23a5bac 100644
--- a/lib/features/splash/secure_recovery_phrase/presentation/email_recovery_phrase_alert/email_recovery_phrase_page.dart
+++ b/lib/features/splash/secure_recovery_phrase/presentation/email_recovery_phrase_alert/email_recovery_phrase_page.dart
@@ -31,7 +31,7 @@ class EmailRecoveryPhrasePage extends RecoveryPhraseBasePage {
);
@override
- Color themeColor() => const Color(0xFFE64340);
+ Color themeColor({BuildContext? context}) => const Color(0xFFE64340);
@override
Widget buildAlert(BuildContext context) {
diff --git a/lib/features/splash/secure_recovery_phrase/presentation/local_seed_phrase_alert/local_recovery_phrase_page.dart b/lib/features/splash/secure_recovery_phrase/presentation/local_seed_phrase_alert/local_recovery_phrase_page.dart
new file mode 100644
index 00000000..58ca6c00
--- /dev/null
+++ b/lib/features/splash/secure_recovery_phrase/presentation/local_seed_phrase_alert/local_recovery_phrase_page.dart
@@ -0,0 +1,86 @@
+import 'package:datadashwallet/features/splash/secure_recovery_phrase/secure_recovery_phrase.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter_i18n/flutter_i18n.dart';
+import 'package:hooks_riverpod/hooks_riverpod.dart';
+import 'package:mxc_ui/mxc_ui.dart';
+
+import 'local_recovery_phrase_presenter.dart';
+import 'local_recovery_phrase_state.dart';
+
+class LocalRecoveryPhrasePage extends RecoveryPhraseBasePage {
+ const LocalRecoveryPhrasePage({
+ Key? key,
+ this.settingsFlow = false,
+ }) : super(key: key);
+
+ final bool settingsFlow;
+
+ @override
+ ProviderBase get presenter =>
+ emailRecoveryPhraseContainer.actions;
+
+ @override
+ ProviderBase get state =>
+ emailRecoveryPhraseContainer.state;
+
+ @override
+ Widget icon(BuildContext context) => Icon(
+ Icons.file_download_rounded,
+ size: 40,
+ color: themeColor(context: context),
+ );
+
+ @override
+ Color themeColor({BuildContext? context}) => ColorsTheme.of(context!).primary;
+
+ @override
+ Widget buildAlert(BuildContext context) {
+ return Container(
+ width: double.infinity,
+ alignment: Alignment.center,
+ padding: const EdgeInsets.all(24),
+ decoration: BoxDecoration(
+ color: ColorsTheme.of(context).cardBackground,
+ borderRadius: const BorderRadius.all(Radius.circular(10)),
+ ),
+ child: Column(
+ children: [
+ Container(
+ width: 72,
+ height: 72,
+ padding: const EdgeInsets.all(18),
+ decoration: BoxDecoration(
+ shape: BoxShape.circle,
+ color: themeColor(context: context),
+ ),
+ child: const Icon(
+ Icons.file_download_rounded,
+ color: Colors.white,
+ ),
+ ),
+ const SizedBox(height: 12),
+ Text(
+ FlutterI18n.translate(context, 'save_locally_description'),
+ style: FontTheme.of(context).body1().copyWith(
+ fontWeight: FontWeight.w500,
+ color: ColorsTheme.of(context).textPrimary,
+ ),
+ textAlign: TextAlign.center,
+ ),
+ ],
+ ),
+ );
+ }
+
+ @override
+ Widget? buildFooter(BuildContext context, WidgetRef ref) => MxcButton.primary(
+ key: const ValueKey('saveLocallyButton'),
+ title: FlutterI18n.translate(context, 'save_locally'),
+ titleColor: ColorsTheme.of(context).textBlack200,
+ color: themeColor(context: context),
+ borderColor: themeColor(context: context),
+ onTap: () => ref.read(presenter).saveLocally(
+ settingsFlow,
+ ),
+ );
+}
diff --git a/lib/features/splash/secure_recovery_phrase/presentation/local_seed_phrase_alert/local_recovery_phrase_presenter.dart b/lib/features/splash/secure_recovery_phrase/presentation/local_seed_phrase_alert/local_recovery_phrase_presenter.dart
new file mode 100644
index 00000000..10f53451
--- /dev/null
+++ b/lib/features/splash/secure_recovery_phrase/presentation/local_seed_phrase_alert/local_recovery_phrase_presenter.dart
@@ -0,0 +1,13 @@
+import 'package:datadashwallet/core/core.dart';
+import 'package:datadashwallet/features/splash/secure_recovery_phrase/secure_recovery_phrase.dart';
+
+import 'local_recovery_phrase_state.dart';
+
+final emailRecoveryPhraseContainer =
+ PresenterContainer(
+ () => LocalRecoveryPhrasePresenter());
+
+class LocalRecoveryPhrasePresenter
+ extends RecoveryPhraseBasePresenter {
+ LocalRecoveryPhrasePresenter() : super(LocalRecoveryPhraseState());
+}
diff --git a/lib/features/splash/secure_recovery_phrase/presentation/local_seed_phrase_alert/local_recovery_phrase_state.dart b/lib/features/splash/secure_recovery_phrase/presentation/local_seed_phrase_alert/local_recovery_phrase_state.dart
new file mode 100644
index 00000000..8ffe503d
--- /dev/null
+++ b/lib/features/splash/secure_recovery_phrase/presentation/local_seed_phrase_alert/local_recovery_phrase_state.dart
@@ -0,0 +1,10 @@
+import 'package:equatable/equatable.dart';
+import 'package:datadashwallet/features/splash/secure_recovery_phrase/secure_recovery_phrase.dart';
+
+class LocalRecoveryPhraseState extends RecoveryPhraseBaseState
+ with EquatableMixin {
+ @override
+ List