diff --git a/.github/workflows/android-release-appcenter.yaml b/.github/workflows/android-release-appcenter.yaml
index 2a1369e0a..3216bb418 100644
--- a/.github/workflows/android-release-appcenter.yaml
+++ b/.github/workflows/android-release-appcenter.yaml
@@ -35,6 +35,8 @@ jobs:
echo "FLUTTER_VERSION_CODE=${{ github.event.inputs.build-number }}" >> $GITHUB_ENV
echo "BRANCH_KEY=${{ secrets.BRANCH_KEY }}" >> $GITHUB_ENV
echo "BRANCH_KEY_TEST=${{ secrets.BRANCH_KEY_TEST }}" >> $GITHUB_ENV
+ echo "SIGNATURE_HASH=${{ secrets.SIGNATURE_HASH }}" >> $GITHUB_ENV
+ echo "SIGNATURE_HASH_INHOUSE=${{ secrets.SIGNATURE_HASH_INHOUSE }}" >> $GITHUB_ENV
${{ github.event.inputs.testnet == 'true' }} && echo APPCENTER_APP_ID=support-zzd0-28/Autonomy-Android-Test >> $GITHUB_ENV || echo APPCENTER_APP_ID=support-zzd0-28/Autonomy-Android-1 >> $GITHUB_ENV
${{ github.event.inputs.testnet == 'true' }} && echo NAME_SUFFIX=test-${{ github.event.inputs.build-number }} >> $GITHUB_ENV || echo NAME_SUFFIX=main-${{ github.event.inputs.build-number }} >> $GITHUB_ENV
diff --git a/.github/workflows/bmvn_build_appcenter_android.yaml b/.github/workflows/bmvn_build_appcenter_android.yaml
index f4653440c..70f5d572b 100644
--- a/.github/workflows/bmvn_build_appcenter_android.yaml
+++ b/.github/workflows/bmvn_build_appcenter_android.yaml
@@ -65,6 +65,8 @@ jobs:
# echo "FLUTTER_VERSION_CODE=${{ inputs.build-number }}" >> $GITHUB_ENV
echo "BRANCH_KEY=${{ secrets.BRANCH_KEY }}" >> $GITHUB_ENV
echo "BRANCH_KEY_TEST=${{ secrets.BRANCH_KEY_TEST }}" >> $GITHUB_ENV
+ echo "SIGNATURE_HASH=${{ secrets.SIGNATURE_HASH }}" >> $GITHUB_ENV
+ echo "SIGNATURE_HASH_INHOUSE=${{ secrets.SIGNATURE_HASH_INHOUSE }}" >> $GITHUB_ENV
${{ inputs.testnet == true }} && echo APPCENTER_APP_ID=support-zzd0-28/Autonomy-Android-Test >> $GITHUB_ENV || echo APPCENTER_APP_ID=support-zzd0-28/Autonomy-Android-1 >> $GITHUB_ENV
${{ inputs.testnet == true }} && echo NAME_SUFFIX=test-${{env.FLUTTER_VERSION_CODE}} >> $GITHUB_ENV || echo NAME_SUFFIX=main-${{env.FLUTTER_VERSION_CODE}} >> $GITHUB_ENV
diff --git a/README.md b/README.md
index 049b66aec..d70f4474d 100644
--- a/README.md
+++ b/README.md
@@ -1,18 +1,62 @@
-# Autonomy: Digital Art Wallet
-_Collect, View & Discovery_
+# Feral File: the way to collect art
+
## About
-Autonomy is the world’s first and only digital art wallet. It gives you one easy-to-use app to securely collect, view and discover digital art you love. Autonomy works with Ethereum and Tezos and is built to support all new chains as they emerge.
-
-- _Collect_: Buy digital art on Tezos or Ethereum and let Autonomy secure, organize and showcase your collection—all in one beautiful, simple experience. Autonomy takes care of the hard stuff so you can focus on growing the good stuff.
-
-- _View_: Enjoy your digital art anywhere—on any screen, TV or projector. Autonomy is the only app that does this. It’s like having an infinite personal gallery you can share and experience anywhere you go.
-
-- _Discover_: Autonomy automatically helps you discover new art by knowing the artists you collect, what they’ve minted and what they’ve bought for themselves. We don’t use likes, trends or algorithms. We go straight to the source to give you the stuff we know you’ll love.
+### [Feral File](https://feralfile.com/) is the place to experience digital art today.
+
+Visit curated exhibitions of world-class, software-based art, interact with dynamic digital works, and organize your personal digital art collection directly in the app. You can share and enjoy all artwork found in the app with friends and family by Streaming to any compatible screen.
+
+Co-create a [MoMA Postcard](https://www.moma.org/calendar/exhibitions/5618) and experiment with borderless collaboration and creativity.
+
+
+
+
+
+
+The **Feral File** app enhances the digital experience, increasing the ways people can share, organize, explore, and live with software-based artwork.
+
+
+#### Explore Feral File Exhibitions
+
+- Each exhibition on **Feral File** begins with the curator. World-class artists collaborate with visionary curators to create and exhibit artworks around a single, ambitious theme.
+
+- Exhibitions never close on **[feralfile.com](https://feralfile.com/)**. Soon, all exhibitions will be viewable and streamable on the **Feral File** app. For now, the current exhibition is on view.
+
+
+#### Live with digital art
+
+- Stream digital artwork to any compatible screen. Share and enjoy your favorite pieces with family, friends, and colleagues at home and in the office.
+
+- For interactive works, your mobile device becomes the remote control. Use the keyboard, experiment with the artist’s commands, and dive into the immersive world of software-based art.
+
+
+#### Organize
+
+- Consolidate collected digital art across blockchains (Ethereum and Tezos)
+
+- Create collections within your collection.
+
+- The app classifies artwork into 3 categories: Still, Video, Interactive.
+
+
+#### Share
+
+- Co-create a digital chain letter with [MoMA Postcard](https://www.moma.org/calendar/exhibitions/5618). This experiment in borderless collaboration and creativity explores ways individuals, groups, and institutions can make and own digital goods.
+
+- The “View existing address” feature allows you to see other collections and share yours with friends.
+
+
+
+
+
+
+Bitmark started with the idea of building tools to help individuals and institutions secure digital property rights. Feral File, an online gallery co-founded by Casey Reas, applies this vision to art made with software, helping artists and collectors secure the property rights to their artwork. Visit feralfile.com and experience world-class digital art in-situ. The **Feral File** app goes beyond ownership and provides dynamic ways to engage with digital art on your personal devices, in your home, and across the world.
+
+
+![all in one](https://github.com/bitmark-inc/feralfile-app/assets/61187455/a63402ea-3949-4188-b9dd-c26c7457952b)
-
## Getting Started
@@ -29,7 +73,7 @@ Autonomy is the world’s first and only digital art wallet. It gives you one ea
6. Run ./script/encrypt_secrets.sh <-entropy-> to generate the encrypted secrets file.
- <-entropy-> is a random string. You can type a random string like akhrdsgl4893tynk3iu4y8hf
- You only need to run this script again when you want to update .env.secret.
-7. Run `flutter run --flavor inhouse` to run Feral File app development on the connected device.
+7. Run `flutter run --flavor inhouse` to run **Feral File** app development on the connected device.
A few resources to get you started if this is your first Flutter project:
@@ -41,8 +85,8 @@ For help getting started with Flutter, view our
samples, guidance on mobile development, and a full API reference.
## Status - Released
-- [App Store](https://apps.apple.com/us/app/autonomy-app/id1544022728)
-- [Google Play](https://play.google.com/store/apps/details?id=com.bitmark.autonomy_client)
+- [App Store](https://apps.apple.com/us/app/feral-file/id1544022728)
+- [Google Play](https://play.google.com/store/apps/details?id=com.bitmark.autonomy_client&pli=)
[Release Notes](https://github.com/bitmark-inc/autonomy-apps/tree/main/release_notes/production)
diff --git a/android/app/build.gradle b/android/app/build.gradle
index 3116ff146..064977be9 100644
--- a/android/app/build.gradle
+++ b/android/app/build.gradle
@@ -161,7 +161,7 @@ dependencies {
implementation 'com.google.android.gms:play-services-auth-blockstore:16.1.0'
implementation 'io.reactivex.rxjava2:rxjava:2.2.10'
implementation 'io.reactivex.rxjava2:rxandroid:2.1.1'
- implementation('com.github.bitmark-inc:libauk-kotlin:aaf6d60725') {
+ implementation('com.github.bitmark-inc:libauk-kotlin:0.6.3') {
exclude group: 'com.google.protobuf'
exclude module: 'jetified-protobuf-java'
}
diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml
index 56dba0b82..989a3d6b5 100644
--- a/android/app/src/main/AndroidManifest.xml
+++ b/android/app/src/main/AndroidManifest.xml
@@ -26,12 +26,8 @@
android:icon="${appIcon}"
android:label="@string/app_name"
android:roundIcon="${appIconRound}"
- android:usesCleartextTraffic="true"
+ android:networkSecurityConfig="@xml/network_security_config"
tools:replace="android:label">
-
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/assets b/assets
index 8ab764287..6da3440ec 160000
--- a/assets
+++ b/assets
@@ -1 +1 @@
-Subproject commit 8ab764287b941406ee087d42bdf1dcb321bc3395
+Subproject commit 6da3440ecfd11f061c8f406bcacf4c10fb0daf68
diff --git a/ios/Runner-Inhouse-Info.plist b/ios/Runner-Inhouse-Info.plist
index c08dd2b85..9e5b62786 100644
--- a/ios/Runner-Inhouse-Info.plist
+++ b/ios/Runner-Inhouse-Info.plist
@@ -39,6 +39,7 @@
tezos
autonomy-wc
autonomy-app
+ feralfile
diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj
index 01bd8e446..02376c185 100644
--- a/ios/Runner.xcodeproj/project.pbxproj
+++ b/ios/Runner.xcodeproj/project.pbxproj
@@ -2050,7 +2050,7 @@
repositoryURL = "https://github.com/bitmark-inc/libauk-swift.git";
requirement = {
kind = revision;
- revision = f0da0d9fd232e2ef478b819ddeaf1d6270ef6b60;
+ revision = 686289ec506b54a491a0b2721540a6ec2433b90f;
};
};
63D4B0F628B7180C0014B2C0 /* XCRemoteSwiftPackageReference "Starscream" */ = {
diff --git a/ios/Runner/AppDelegate.swift b/ios/Runner/AppDelegate.swift
index 2ebbc8a3a..8a49c18c6 100644
--- a/ios/Runner/AppDelegate.swift
+++ b/ios/Runner/AppDelegate.swift
@@ -16,6 +16,8 @@ import flutter_downloader
//import Sentry
import Starscream
import IOSSecuritySuite
+import Sentry
+import Logging
@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
@@ -23,37 +25,40 @@ import IOSSecuritySuite
var cancelBag = Set()
var authenticationVC = BiometricAuthenticationViewController()
var splashScreenVC: SplashViewController? = SplashViewController()
-
+
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
-
- if !Constant.isInhouse {
- IOSSecuritySuite.denyDebugger()
- if checkDebugger() {
- exit(0)
+ DispatchQueue.main.asyncAfter(deadline: .now() + 5) {
+ if !Constant.isInhouse {
+ IOSSecuritySuite.denyDebugger()
+
+ if self.checkDebugger() {
+ self.captureMessage(message: "[Security check] Debugger detected")
+ exit(0)
+ }
}
- }
-
- let isSecure = checkMainBundleIdentifier()
- if !isSecure {
- exit(0)
- }
+ let isSecure = self.checkMainBundleIdentifier()
- if IOSSecuritySuite.amIReverseEngineered() {
- exit(0)
- }
+ if !isSecure {
+ self.captureMessage(message: "[Security check] Integrity check failed")
+ exit(0)
+ }
+
+ if IOSSecuritySuite.amIReverseEngineered() {
+ self.captureMessage(message: "[Security check] Reverse engineering tool detected")
+ exit(0)
+ }
- DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
if IOSSecuritySuite.amIJailbroken() {
- // If jailbreak is detected, notify the user and terminate the app
+ self.captureMessage(message: "[Security check] Jail broken device detected")
self.showAlertAndExit()
}
}
-
+
LibAuk.create(keyChainGroup: Constant.keychainGroup)
authenticationVC.authenticationCallback = self.authenticationCompleted
@@ -136,10 +141,10 @@ import IOSSecuritySuite
result(FlutterMethodNotImplemented)
}
})
-
+
let keychainChannel = FlutterMethodChannel(name: "keychain",
binaryMessenger: controller.binaryMessenger)
-
+
keychainChannel.setMethodCallHandler({(call: FlutterMethodCall, result: @escaping FlutterResult) -> Void in
switch call.method {
case "removeKeychainItems":
@@ -148,7 +153,7 @@ import IOSSecuritySuite
result(FlutterMethodNotImplemented)
}
})
-
+
let secureScreenChannel = FlutterMethodChannel(name: "secure_screen_channel",
binaryMessenger: controller.binaryMessenger)
secureScreenChannel.setMethodCallHandler({(call: FlutterMethodCall, result: @escaping FlutterResult) -> Void in
@@ -159,7 +164,7 @@ import IOSSecuritySuite
result(FlutterMethodNotImplemented)
}
})
-
+
let migrationChannel = FlutterMethodChannel(name: "migration_util",
binaryMessenger: controller.binaryMessenger)
migrationChannel.setMethodCallHandler({(call: FlutterMethodCall, result: @escaping FlutterResult) -> Void in
@@ -218,7 +223,6 @@ import IOSSecuritySuite
})
beaconEventChannel.setStreamHandler(BeaconChannelHandler.shared)
-
let cloudEventChannel = FlutterEventChannel(name: "cloud/event", binaryMessenger: controller.binaryMessenger)
cloudEventChannel.setStreamHandler(CloudChannelHandler.shared)
@@ -242,7 +246,122 @@ import IOSSecuritySuite
override func application(_ application: UIApplication, shouldAllowExtensionPointIdentifier extensionPointIdentifier: UIApplication.ExtensionPointIdentifier) -> Bool {
return extensionPointIdentifier != .keyboard
}
-
+
+ private func captureMessage(message: String) {
+ do {
+ SentrySDK.capture(message: message)
+ } catch {}
+ }
+
+
+ override func application(_ application: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
+ logger.info("handle deeplink")
+ if url.scheme == "feralfile" {
+
+ handleEmergencyLog(url)
+ }
+ return super.application(application, open: url, options: options)
+ }
+
+ private func handleEmergencyLog(_ url: URL) {
+ logger.info("handle feralfile deeplink")
+
+ if url.host == "emergency-logs" {
+ logger.info("emergency-logs")
+ let token = url.lastPathComponent
+ uploadLogFile(uploadURL: Logger.appLogURL,token: token)
+ }
+ }
+
+ func uploadLogFile(uploadURL: URL , token: String) {
+ // Create a URLSession configuration
+ logger.info("upload log file")
+ let config = URLSessionConfiguration.default
+ let session = URLSession(configuration: config)
+
+ let endpoint = Constant.isInhouse ? "https://support.test.autonomy.io/v1/issues/" : "https://support.autonomy.io/v1/issues/"
+ // Create the request body
+ guard let url = URL(string: endpoint) else {
+ return
+ }
+
+ var request = URLRequest(url: url)
+ request.httpMethod = "POST"
+
+ // Set the authorization header
+ request.setValue("Emergency \(token)", forHTTPHeaderField: "Authorization")
+ request.setValue("application/json", forHTTPHeaderField: "Content-Type")
+
+
+ let fileData = base64EncodedFile(fileURL: uploadURL)
+
+ if (fileData == nil) {
+ return
+ }
+ // Construct the request body
+ let requestBody: [String: Any] = [
+ "attachments": [
+ [
+ "data": fileData,
+ "title": "Emergency log",
+ "path": "",
+ "contentType": ""
+ ]
+ ],
+ "title": "Emergency log",
+ "message": "Emergency log",
+ "tags": ["emergency", "iOS"]
+ ]
+
+ // Convert the request body to JSON data
+ guard let jsonData = try? JSONSerialization.data(withJSONObject: requestBody) else {
+ print("Failed to encode request body")
+ return
+ }
+
+ // Set the request body
+ request.httpBody = jsonData
+
+
+ // Create a data task to perform the request
+ let task = session.dataTask(with: request) { data, response, error in
+ if let error = error {
+ print("Upload log Error: \(error)")
+ return
+ }
+
+ guard let httpResponse = response as? HTTPURLResponse else {
+ print("Upload log Invalid response")
+ return
+ }
+
+ print("Upload log Response status: \(httpResponse.statusCode)")
+ return
+ }
+
+ // Start the data task
+ task.resume()
+ }
+
+ func base64EncodedFile(fileURL: URL) -> String? {
+ do {
+ // Read file contents as bytes
+ let fileData = try Data(contentsOf: fileURL)
+
+ // Encode bytes to Base64
+ let base64Data = fileData.base64EncodedData()
+
+ // Convert Base64 data to a string representation
+ let base64String = String(data: base64Data, encoding: .utf8)
+
+ return base64String
+ } catch {
+ // Handle any errors that occur during file reading
+ print("Error reading file:", error.localizedDescription)
+ return nil
+ }
+ }
+
override func applicationWillEnterForeground(_ application: UIApplication) {
if UserDefaults.standard.bool(forKey: "flutter.device_passcode") == true {
authenticationVC.authentication()
@@ -260,7 +379,7 @@ import IOSSecuritySuite
showSplashScreen()
}
}
-
+
func showAlertAndExit() {
let alert = UIAlertController(title: "Jailbreak Detected",
message: "This app cannot run on jailbroken devices.",
@@ -269,16 +388,16 @@ import IOSSecuritySuite
// Dismiss the alert and exit the app
exit(0)
}))
-
+
// Get the root view controller to present the alert
if let rootViewController = UIApplication.shared.keyWindow?.rootViewController {
rootViewController.present(alert, animated: true, completion: nil)
-
+
}
-
+
}
-
-
+
+
private func showSplashScreen() {
if splashScreenVC == nil {
splashScreenVC = SplashViewController()
@@ -286,7 +405,7 @@ import IOSSecuritySuite
window?.rootViewController?.present(splashScreenVC!, animated: false, completion: nil)
}
}
-
+
private func removeSplashScreen() {
if let splashVC = splashScreenVC {
splashVC.dismiss(animated: false, completion: {
@@ -317,11 +436,11 @@ extension AppDelegate {
self?.authenticationVC.view.removeFromSuperview()
}
}
-
+
func checkDebugger() -> Bool {
return checkExceptionPorts() || checkSignalHandlers() || checkExecutionStates()
}
-
+
private static let EXC_MASK_ALL = (
EXC_MASK_BAD_ACCESS | EXC_MASK_BAD_INSTRUCTION | EXC_MASK_ARITHMETIC |
EXC_MASK_EMULATION | EXC_MASK_SOFTWARE | EXC_MASK_BREAKPOINT |
diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist
index 1051f1a27..60924ce26 100644
--- a/ios/Runner/Info.plist
+++ b/ios/Runner/Info.plist
@@ -44,6 +44,7 @@
tezos
autonomy-wc
autonomy-app
+ feralfile
diff --git a/ios/Runner/PrivacyInfo.xcprivacy b/ios/Runner/PrivacyInfo.xcprivacy
index 03d1a4440..21d9fd8c7 100644
--- a/ios/Runner/PrivacyInfo.xcprivacy
+++ b/ios/Runner/PrivacyInfo.xcprivacy
@@ -1,47 +1,41 @@
-
-
- NSPrivacyAccessedAPITypes
-
-
- NSPrivacyAccessedAPIType
- NSPrivacyAccessedAPICategoryUserDefaults
- NSPrivacyAccessedAPITypeReasons
-
- CA92.1
-
-
-
- NSPrivacyAccessedAPIType
- NSPrivacyAccessedAPICategorySystemBootTime
- NSPrivacyAccessedAPITypeReasons
-
- 35F9.1
-
-
-
- NSPrivacyAccessedAPIType
- NSPrivacyAccessedAPICategoryFileTimestamp
- NSPrivacyAccessedAPITypeReasons
-
- C617.1
-
-
-
- NSPrivacyAccessedAPIType
- NSPrivacyAccessedAPICategoryDiskSpace
- NSPrivacyAccessedAPITypeReasons
-
- 85F4.1
-
-
-
+
+ NSPrivacyAccessedAPITypes
+
+
+ NSPrivacyAccessedAPIType
+ NSPrivacyAccessedAPICategoryUserDefaults
+ NSPrivacyAccessedAPITypeReasons
+
+ CA92.1
+
+
+
+ NSPrivacyAccessedAPIType
+ NSPrivacyAccessedAPICategorySystemBootTime
+ NSPrivacyAccessedAPITypeReasons
+
+ 35F9.1
+
+
+
+ NSPrivacyAccessedAPIType
+ NSPrivacyAccessedAPICategoryFileTimestamp
+ NSPrivacyAccessedAPITypeReasons
+
+ C617.1
+
+
+
+ NSPrivacyAccessedAPIType
+ NSPrivacyAccessedAPICategoryDiskSpace
+ NSPrivacyAccessedAPITypeReasons
+
+ 85F4.1
+
+
+
+
diff --git a/ios/fastlane/provisioning_profiles/Autonomy_Inhouse_Adhoc.mobileprovision b/ios/fastlane/provisioning_profiles/Autonomy_Inhouse_Adhoc.mobileprovision
index 032ef0e7b..9b847156f 100644
Binary files a/ios/fastlane/provisioning_profiles/Autonomy_Inhouse_Adhoc.mobileprovision and b/ios/fastlane/provisioning_profiles/Autonomy_Inhouse_Adhoc.mobileprovision differ
diff --git a/ios/fastlane/provisioning_profiles/Autonomy_Inhouse_Adhoc_Notification.mobileprovision b/ios/fastlane/provisioning_profiles/Autonomy_Inhouse_Adhoc_Notification.mobileprovision
index d20ece66a..9940c4173 100644
Binary files a/ios/fastlane/provisioning_profiles/Autonomy_Inhouse_Adhoc_Notification.mobileprovision and b/ios/fastlane/provisioning_profiles/Autonomy_Inhouse_Adhoc_Notification.mobileprovision differ
diff --git a/lib/common/injector.dart b/lib/common/injector.dart
index c4289d3f0..54e20e8dc 100644
--- a/lib/common/injector.dart
+++ b/lib/common/injector.dart
@@ -130,20 +130,13 @@ Future setup() async {
final cloudDB = await $FloorCloudDatabase
.databaseBuilder('cloud_database.db')
- .addMigrations([
- migrateCloudV1ToV2,
- migrateCloudV2ToV3,
- migrateCloudV3ToV4,
- migrateCloudV4ToV5,
- migrateCloudV5ToV6,
- migrateCloudV6ToV7,
- migrateCloudV7ToV8,
- ]).build();
+ .addMigrations(cloudDatabaseMigrations)
+ .build();
final BaseOptions dioOptions = BaseOptions(
followRedirects: true,
- connectTimeout: const Duration(seconds: 10),
- receiveTimeout: const Duration(seconds: 10),
+ connectTimeout: const Duration(seconds: 3),
+ receiveTimeout: const Duration(seconds: 3),
);
final dio = baseDio(dioOptions);
diff --git a/lib/database/app_database.dart b/lib/database/app_database.dart
index 150649502..ed0509e5a 100644
--- a/lib/database/app_database.dart
+++ b/lib/database/app_database.dart
@@ -14,6 +14,7 @@ import 'package:autonomy_flutter/database/dao/identity_dao.dart';
import 'package:autonomy_flutter/database/entity/announcement_local.dart';
import 'package:autonomy_flutter/database/entity/draft_customer_support.dart';
import 'package:autonomy_flutter/database/entity/identity.dart';
+import 'package:autonomy_flutter/util/log.dart';
import 'package:feralfile_app_tv_proto/feralfile_app_tv_proto.dart';
import 'package:floor/floor.dart';
import 'package:nft_collection/models/token.dart';
@@ -54,34 +55,40 @@ abstract class AppDatabase extends FloorDatabase {
final migrateV1ToV2 = Migration(1, 2, (database) async {
await database.execute(
'ALTER TABLE AssetToken ADD COLUMN lastActivityTime int DEFAULT(0)');
+ log.info('Migrated App database from version 1 to 2');
});
final migrateV2ToV3 = Migration(2, 3, (database) async {
await database.execute(
'CREATE TABLE IF NOT EXISTS `Provenance` (`txID` TEXT NOT NULL, `type` TEXT NOT NULL, `blockchain` TEXT NOT NULL, `owner` TEXT NOT NULL, `timestamp` INTEGER NOT NULL, `tokenID` TEXT NOT NULL, FOREIGN KEY (`tokenID`) REFERENCES `AssetToken` (`id`) ON UPDATE NO ACTION ON DELETE NO ACTION, PRIMARY KEY (`txID`))');
+ log.info('Migrated App database from version 2 to 3');
});
// For unknown reason, execute DROP then CREATE in same migration execution doesn't work.
// So I have to separate 2 versions
final migrateV3ToV4 = Migration(3, 4, (database) async {
await database.execute('DROP TABLE IF EXISTS Provenance;');
+ log.info('Migrated App database from version 3 to 4');
});
final migrateV4ToV5 = Migration(4, 5, (database) async {
await database.execute('''
CREATE TABLE IF NOT EXISTS `Provenance` (`txID` TEXT NOT NULL, `type` TEXT NOT NULL, `blockchain` TEXT NOT NULL, `owner` TEXT NOT NULL, `timestamp` INTEGER NOT NULL, `txURL` TEXT NOT NULL, `tokenID` TEXT NOT NULL, FOREIGN KEY (`tokenID`) REFERENCES `AssetToken` (`id`) ON UPDATE NO ACTION ON DELETE NO ACTION, PRIMARY KEY (`txID`));
CREATE INDEX `index_Provenance_tokenID` ON `Provenance` (`tokenID`);''');
+ log.info('Migrated App database from version 4 to 5');
});
final migrateV5ToV6 = Migration(5, 6, (database) async {
await database
.execute('ALTER TABLE AssetToken ADD COLUMN hidden int DEFAULT(NULL)');
+ log.info('Migrated App database from version 5 to 6');
});
final migrateV6ToV7 = Migration(6, 7, (database) async {
await database.execute('''
DROP TABLE IF EXISTS Provenance;
''');
+ log.info('Migrated App database from version 6 to 7');
});
final migrateV7ToV8 = Migration(7, 8, (database) async {
@@ -89,46 +96,54 @@ final migrateV7ToV8 = Migration(7, 8, (database) async {
CREATE TABLE IF NOT EXISTS `Provenance` (`txID` TEXT NOT NULL, `type` TEXT NOT NULL, `blockchain` TEXT NOT NULL, `owner` TEXT NOT NULL, `timestamp` INTEGER NOT NULL, `txURL` TEXT NOT NULL, `tokenID` TEXT NOT NULL, FOREIGN KEY (`tokenID`) REFERENCES `AssetToken` (`id`) ON UPDATE NO ACTION ON DELETE CASCADE, PRIMARY KEY (`txID`));
CREATE INDEX `index_Provenance_tokenID` ON `Provenance` (`tokenID`);
''');
+ log.info('Migrated App database from version 7 to 8');
});
final migrateV8ToV9 = Migration(8, 9, (database) async {
await database.execute('''
ALTER TABLE AssetToken ADD COLUMN blockchainURL TEXT;
''');
+ log.info('Migrated App database from version 8 to 9');
});
final migrateV9ToV10 = Migration(9, 10, (database) async {
await database.execute('''
CREATE TABLE IF NOT EXISTS `DraftCustomerSupport` (`uuid` TEXT NOT NULL, `issueID` TEXT NOT NULL, `type` TEXT NOT NULL, `data` TEXT NOT NULL, `createdAt` INTEGER NOT NULL, `reportIssueType` TEXT NOT NULL, `mutedMessages` TEXT NOT NULL, PRIMARY KEY (`uuid`));
''');
+ log.info('Migrated App database from version 9 to 10');
});
final migrateV10ToV11 = Migration(10, 11, (database) async {
await database.execute('''
ALTER TABLE AssetToken ADD COLUMN mimeType TEXT;
''');
+ log.info('Migrated App database from version 10 to 11');
});
final migrateV11ToV12 = Migration(11, 12, (database) async {
await database.execute('''
ALTER TABLE AssetToken ADD COLUMN artistID TEXT;
''');
+ log.info('Migrated App database from version 11 to 12');
});
final migrateV12ToV13 = Migration(12, 13, (database) async {
await database.execute('''
ALTER TABLE AssetToken ADD COLUMN contractAddress TEXT, tokenId TEXT;
''');
+ log.info('Migrated App database from version 12 to 13');
});
final migrateV13ToV14 = Migration(13, 14, (database) async {
await database.execute('DROP TABLE IF EXISTS AssetToken;');
await database.execute('DROP TABLE IF EXISTS Provenance;');
+ log.info('Migrated App database from version 13 to 14');
});
final migrateV14ToV15 = Migration(14, 15, (database) async {
await database.execute(
'CREATE TABLE IF NOT EXISTS `AnnouncementLocal` (`announcementContextId` TEXT NOT NULL, `title` TEXT NOT NULL, `body` TEXT NOT NULL, `createdAt` INTEGER NOT NULL, `announceAt` INTEGER NOT NULL, `type` TEXT NOT NULL, `unread` INTEGER NOT NULL, PRIMARY KEY (`announcementContextId`))');
+ log.info('Migrated App database from version 14 to 15');
});
final migrateV15ToV16 = Migration(15, 16, (database) async {
@@ -136,13 +151,16 @@ final migrateV15ToV16 = Migration(15, 16, (database) async {
'CREATE TABLE IF NOT EXISTS `CanvasDevice` (`id` TEXT NOT NULL, `ip` TEXT NOT NULL, `port` INTEGER NOT NULL, `name` TEXT NOT NULL, `isConnecting` INTEGER NOT NULL, `lastScenePlayed` TEXT, `playingSceneId` TEXT, PRIMARY KEY (`id`))');
await database.execute(
'CREATE TABLE IF NOT EXISTS `Scene` (`id` TEXT NOT NULL, `deviceId` TEXT NOT NULL, `metadata` TEXT NOT NULL, PRIMARY KEY (`id`))');
+ log.info('Migrated App database from version 15 to 16');
});
final migrateV16ToV17 = Migration(16, 17, (database) async {
await database.execute(
'CREATE TABLE IF NOT EXISTS `Followee` (`address` TEXT NOT NULL, `type` INTEGER NOT NULL, `isFollowed` INTEGER NOT NULL, `createdAt` INTEGER NOT NULL, `name` TEXT NOT NULL, PRIMARY KEY (`address`))');
+ log.info('Migrated from version 16 to 17');
});
final migrateV17ToV18 = Migration(17, 18, (database) async {
await database.execute('DROP TABLE IF EXISTS Followee;');
+ log.info('Migrated App database from version 17 to 18');
});
diff --git a/lib/database/cloud_database.dart b/lib/database/cloud_database.dart
index f16322e88..0aeea09aa 100644
--- a/lib/database/cloud_database.dart
+++ b/lib/database/cloud_database.dart
@@ -14,17 +14,18 @@ import 'package:autonomy_flutter/database/dao/persona_dao.dart';
import 'package:autonomy_flutter/database/entity/audit.dart';
import 'package:autonomy_flutter/database/entity/connection.dart';
import 'package:autonomy_flutter/database/entity/persona.dart';
+import 'package:autonomy_flutter/database/entity/wallet_address.dart';
import 'package:autonomy_flutter/util/constants.dart';
+import 'package:autonomy_flutter/util/log.dart';
import 'package:autonomy_flutter/util/wallet_storage_ext.dart';
import 'package:floor/floor.dart';
import 'package:sqflite/sqflite.dart' as sqflite;
-import 'entity/wallet_address.dart';
-
part 'cloud_database.g.dart'; // the generated code will be there
+//ignore_for_file: lines_longer_than_80_chars
@TypeConverters([DateTimeConverter])
-@Database(version: 8, entities: [Persona, Connection, Audit, WalletAddress])
+@Database(version: 9, entities: [Persona, Connection, Audit, WalletAddress])
abstract class CloudDatabase extends FloorDatabase {
PersonaDao get personaDao;
@@ -60,51 +61,58 @@ abstract class CloudDatabase extends FloorDatabase {
final migrateCloudV1ToV2 = Migration(1, 2, (database) async {
await database.execute(
'CREATE TABLE IF NOT EXISTS `Audit` (`uuid` TEXT NOT NULL, `category` TEXT NOT NULL, `action` TEXT NOT NULL, `createdAt` INTEGER NOT NULL, `metadata` TEXT NOT NULL, PRIMARY KEY (`uuid`))');
+ log.info('Migrated Cloud database from version 1 to 2');
});
final migrateCloudV2ToV3 = Migration(2, 3, (database) async {
- await database.execute("""
+ await database.execute('''
ALTER TABLE Persona ADD COLUMN defaultAccount int DEFAULT(NULL);
UPDATE Persona SET defaultAccount=1 ORDER BY id LIMIT 1;
- """);
+ ''');
+ log.info('Migrated Cloud database from version 2 to 3');
});
final migrateCloudV3ToV4 = Migration(3, 4, (database) async {
final countTezosIndex = sqflite.Sqflite.firstIntValue(await database.rawQuery(
"SELECT COUNT(*) FROM pragma_table_info('Persona') WHERE name='tezosIndex';"));
+ log.info('Migrating Cloud database countTezosIndex: $countTezosIndex');
if (countTezosIndex == 0) {
- await database.execute("""
+ await database.execute('''
ALTER TABLE Persona ADD COLUMN tezosIndex INTEGER NOT NULL DEFAULT(1);
- """);
+ ''');
}
final countETHINdex = sqflite.Sqflite.firstIntValue(await database.rawQuery(
"SELECT COUNT(*) FROM pragma_table_info('Persona') WHERE name='ethereumIndex';"));
+ log.info('Migrating Cloud database countETHINdex: $countETHINdex');
if (countETHINdex == 0) {
- await database.execute("""
+ await database.execute('''
ALTER TABLE Persona ADD COLUMN ethereumIndex INTEGER NOT NULL DEFAULT(1);
- """);
+ ''');
}
+ log.info('Migrated Cloud database from version 3 to 4');
});
final migrateCloudV4ToV5 = Migration(4, 5, (database) async {
final countTezosIndexes = sqflite.Sqflite.firstIntValue(await database.rawQuery(
"SELECT COUNT(*) FROM pragma_table_info('Persona') WHERE name='tezosIndexes';"));
+ log.info('Migrating Cloud database countTezosIndexes: $countTezosIndexes');
if (countTezosIndexes == 0) {
- await database.execute("""
+ await database.execute('''
ALTER TABLE Persona ADD COLUMN tezosIndexes TEXT;
- """);
+ ''');
}
final countETHIndexes = sqflite.Sqflite.firstIntValue(await database.rawQuery(
"SELECT COUNT(*) FROM pragma_table_info('Persona') WHERE name='ethereumIndexes';"));
+ log.info('Migrating Cloud database countETHIndexes: $countETHIndexes');
if (countETHIndexes == 0) {
- await database.execute("""
+ await database.execute('''
ALTER TABLE Persona ADD COLUMN ethereumIndexes TEXT;
- """);
+ ''');
}
- await database.execute("""
+ await database.execute('''
UPDATE Persona SET tezosIndexes =
(WITH RECURSIVE
cnt(x, y, id) AS (
@@ -114,9 +122,11 @@ final migrateCloudV4ToV5 = Migration(4, 5, (database) async {
LIMIT 100
)
SELECT y FROM cnt WHERE x = (SELECT id FROM cnt WHERE x = 0));
- """);
+ ''');
+
+ log.info('Migrating Cloud database: executed tezosIndexes');
- await database.execute("""
+ await database.execute('''
UPDATE Persona SET ethereumIndexes =
(WITH RECURSIVE
cnt(x, y, id) AS (
@@ -126,66 +136,111 @@ final migrateCloudV4ToV5 = Migration(4, 5, (database) async {
LIMIT 100
)
SELECT y FROM cnt WHERE x = (SELECT id FROM cnt WHERE x = 0));
- """);
+ ''');
+ log.info('Migrated Cloud database from version 4 to 5');
});
final migrateCloudV5ToV6 = Migration(5, 6, (database) async {
await database.execute(
'CREATE TABLE IF NOT EXISTS `WalletAddress` (`address` TEXT NOT NULL, `uuid` TEXT NOT NULL, `index` INTEGER NOT NULL, `cryptoType` TEXT NOT NULL, `createdAt` INTEGER NOT NULL, `isHidden` INTEGER NOT NULL, PRIMARY KEY (`address`))');
- final personaTable = await database.query("Persona");
+ log.info('Migrating Cloud database: created WalletAddress table');
+ final personaTable = await database.query('Persona');
final personas = personaTable.map((e) => Persona.fromJson(e)).toList();
+ log.info('Migrating Cloud database: personas '
+ '${personas.map((e) => e.toJson()).toList()}');
for (var persona in personas) {
- List? tezIndexesStr = (persona.tezosIndexes ?? "").split(',');
- tezIndexesStr.removeWhere((element) => element.isEmpty);
+ List? tezIndexesStr = (persona.tezosIndexes ?? '').split(',')
+ ..removeWhere((element) => element.isEmpty);
+ log.info('Migrating Cloud database: tezIndexesStr $tezIndexesStr');
final tezIndexes = tezIndexesStr.map((e) => int.parse(e)).toList();
for (var index in tezIndexes) {
await database.insert(
- "WalletAddress",
+ 'WalletAddress',
{
- "address": await persona.wallet().getTezosAddress(index: index),
- "uuid": persona.uuid,
- "index": index,
- "cryptoType": CryptoType.XTZ.source,
- "createdAt": persona.createdAt.millisecondsSinceEpoch,
- "isHidden": 0,
+ 'address': await persona.wallet().getTezosAddress(index: index),
+ 'uuid': persona.uuid,
+ 'index': index,
+ 'cryptoType': CryptoType.XTZ.source,
+ 'createdAt': persona.createdAt.millisecondsSinceEpoch,
+ 'isHidden': 0,
},
conflictAlgorithm: sqflite.ConflictAlgorithm.ignore);
}
- List? ethIndexesStr = (persona.ethereumIndexes ?? "").split(',');
-
- ethIndexesStr.removeWhere((element) => element.isEmpty);
+ List? ethIndexesStr = (persona.ethereumIndexes ?? '').split(',')
+ ..removeWhere((element) => element.isEmpty);
+ log.info('Migrating Cloud database: ethIndexesStr $ethIndexesStr');
final ethIndexes = ethIndexesStr.map((e) => int.parse(e)).toList();
for (var index in ethIndexes) {
await database.insert(
- "WalletAddress",
+ 'WalletAddress',
{
- "address": await persona.wallet().getETHEip55Address(index: index),
- "uuid": persona.uuid,
- "index": index,
- "cryptoType": CryptoType.ETH.source,
- "createdAt": persona.createdAt.millisecondsSinceEpoch,
- "isHidden": 0,
+ 'address': await persona.wallet().getETHEip55Address(index: index),
+ 'uuid': persona.uuid,
+ 'index': index,
+ 'cryptoType': CryptoType.ETH.source,
+ 'createdAt': persona.createdAt.millisecondsSinceEpoch,
+ 'isHidden': 0,
},
conflictAlgorithm: sqflite.ConflictAlgorithm.ignore);
}
}
+ log.info('Migrated Cloud database from version 5 to 6');
});
final migrateCloudV6ToV7 = Migration(6, 7, (database) async {
final countNameCol = sqflite.Sqflite.firstIntValue(await database.rawQuery(
"SELECT COUNT(*) FROM pragma_table_info('WalletAddress') WHERE name='name';"));
+ log.info('Migrating Cloud database countNameCol: $countNameCol');
if (countNameCol == 0) {
- await database.execute("""
+ await database.execute('''
ALTER TABLE WalletAddress ADD COLUMN name TEXT;
- """);
+ ''');
}
+ log.info('Migrated Cloud database from version 6 to 7');
});
final migrateCloudV7ToV8 = Migration(7, 8, (database) async {
final countNameCol = sqflite.Sqflite.firstIntValue(await database.rawQuery(
"SELECT COUNT(*) FROM pragma_table_info('WalletAddress') WHERE name='name';"));
+ log.info('Migrating Cloud database countNameCol: $countNameCol');
if (countNameCol == 0) {
- await database.execute("""
+ await database.execute('''
ALTER TABLE WalletAddress ADD COLUMN name TEXT;
- """);
+ ''');
+ }
+ log.info('Migrated Cloud database from version 7 to 8');
+});
+
+final migrateCloudV8ToV9 = Migration(8, 9, (database) async {
+ // Check if 'accountOrder' column exists in 'Connection' table
+ final countOrderColInConnection = sqflite.Sqflite.firstIntValue(
+ await database.rawQuery(
+ "SELECT COUNT(*) FROM pragma_table_info('Connection') WHERE name='accountOrder';"));
+
+ if (countOrderColInConnection == 0) {
+ await database
+ .execute('ALTER TABLE Connection ADD COLUMN accountOrder INTEGER;');
+ }
+
+ // Check if 'accountOrder' column exists in 'WalletAddress' table
+ final countOrderColInWalletAddress = sqflite.Sqflite.firstIntValue(
+ await database.rawQuery(
+ "SELECT COUNT(*) FROM pragma_table_info('WalletAddress') WHERE name='accountOrder';"));
+
+ if (countOrderColInWalletAddress == 0) {
+ await database
+ .execute('ALTER TABLE WalletAddress ADD COLUMN accountOrder INTEGER;');
}
+
+ log.info('Migrated Cloud database from version 8 to 9');
});
+
+final cloudDatabaseMigrations = [
+ migrateCloudV1ToV2,
+ migrateCloudV2ToV3,
+ migrateCloudV3ToV4,
+ migrateCloudV4ToV5,
+ migrateCloudV5ToV6,
+ migrateCloudV6ToV7,
+ migrateCloudV7ToV8,
+ migrateCloudV8ToV9,
+];
diff --git a/lib/database/cloud_database.g.dart b/lib/database/cloud_database.g.dart
index 142f1b78c..af0a0c6f8 100644
--- a/lib/database/cloud_database.g.dart
+++ b/lib/database/cloud_database.g.dart
@@ -75,7 +75,7 @@ class _$CloudDatabase extends CloudDatabase {
Callback? callback,
]) async {
final databaseOptions = sqflite.OpenDatabaseOptions(
- version: 8,
+ version: 9,
onConfigure: (database) async {
await database.execute('PRAGMA foreign_keys = ON');
await callback?.onConfigure?.call(database);
@@ -93,11 +93,11 @@ class _$CloudDatabase extends CloudDatabase {
await database.execute(
'CREATE TABLE IF NOT EXISTS `Persona` (`uuid` TEXT NOT NULL, `name` TEXT NOT NULL, `createdAt` INTEGER NOT NULL, `defaultAccount` INTEGER, `ethereumIndex` INTEGER NOT NULL, `tezosIndex` INTEGER NOT NULL, `ethereumIndexes` TEXT, `tezosIndexes` TEXT, PRIMARY KEY (`uuid`))');
await database.execute(
- 'CREATE TABLE IF NOT EXISTS `Connection` (`key` TEXT NOT NULL, `name` TEXT NOT NULL, `data` TEXT NOT NULL, `connectionType` TEXT NOT NULL, `accountNumber` TEXT NOT NULL, `createdAt` INTEGER NOT NULL, PRIMARY KEY (`key`))');
+ 'CREATE TABLE IF NOT EXISTS `Connection` (`key` TEXT NOT NULL, `name` TEXT NOT NULL, `data` TEXT NOT NULL, `connectionType` TEXT NOT NULL, `accountNumber` TEXT NOT NULL, `createdAt` INTEGER NOT NULL, `accountOrder` INTEGER, PRIMARY KEY (`key`))');
await database.execute(
'CREATE TABLE IF NOT EXISTS `Audit` (`uuid` TEXT NOT NULL, `category` TEXT NOT NULL, `action` TEXT NOT NULL, `createdAt` INTEGER NOT NULL, `metadata` TEXT NOT NULL, PRIMARY KEY (`uuid`))');
await database.execute(
- 'CREATE TABLE IF NOT EXISTS `WalletAddress` (`address` TEXT NOT NULL, `uuid` TEXT NOT NULL, `index` INTEGER NOT NULL, `cryptoType` TEXT NOT NULL, `createdAt` INTEGER NOT NULL, `isHidden` INTEGER NOT NULL, `name` TEXT, PRIMARY KEY (`address`))');
+ 'CREATE TABLE IF NOT EXISTS `WalletAddress` (`address` TEXT NOT NULL, `uuid` TEXT NOT NULL, `index` INTEGER NOT NULL, `cryptoType` TEXT NOT NULL, `createdAt` INTEGER NOT NULL, `isHidden` INTEGER NOT NULL, `name` TEXT, `accountOrder` INTEGER, PRIMARY KEY (`address`))');
await callback?.onCreate?.call(database, version);
},
@@ -276,7 +276,8 @@ class _$ConnectionDao extends ConnectionDao {
'data': item.data,
'connectionType': item.connectionType,
'accountNumber': item.accountNumber,
- 'createdAt': _dateTimeConverter.encode(item.createdAt)
+ 'createdAt': _dateTimeConverter.encode(item.createdAt),
+ 'accountOrder': item.accountOrder
}),
_connectionUpdateAdapter = UpdateAdapter(
database,
@@ -288,7 +289,8 @@ class _$ConnectionDao extends ConnectionDao {
'data': item.data,
'connectionType': item.connectionType,
'accountNumber': item.accountNumber,
- 'createdAt': _dateTimeConverter.encode(item.createdAt)
+ 'createdAt': _dateTimeConverter.encode(item.createdAt),
+ 'accountOrder': item.accountOrder
}),
_connectionDeletionAdapter = DeletionAdapter(
database,
@@ -300,7 +302,8 @@ class _$ConnectionDao extends ConnectionDao {
'data': item.data,
'connectionType': item.connectionType,
'accountNumber': item.accountNumber,
- 'createdAt': _dateTimeConverter.encode(item.createdAt)
+ 'createdAt': _dateTimeConverter.encode(item.createdAt),
+ 'accountOrder': item.accountOrder
});
final sqflite.DatabaseExecutor database;
@@ -324,7 +327,8 @@ class _$ConnectionDao extends ConnectionDao {
data: row['data'] as String,
connectionType: row['connectionType'] as String,
accountNumber: row['accountNumber'] as String,
- createdAt: _dateTimeConverter.decode(row['createdAt'] as int)));
+ createdAt: _dateTimeConverter.decode(row['createdAt'] as int),
+ accountOrder: row['accountOrder'] as int?));
}
@override
@@ -337,7 +341,8 @@ class _$ConnectionDao extends ConnectionDao {
data: row['data'] as String,
connectionType: row['connectionType'] as String,
accountNumber: row['accountNumber'] as String,
- createdAt: _dateTimeConverter.decode(row['createdAt'] as int)));
+ createdAt: _dateTimeConverter.decode(row['createdAt'] as int),
+ accountOrder: row['accountOrder'] as int?));
}
@override
@@ -350,27 +355,29 @@ class _$ConnectionDao extends ConnectionDao {
data: row['data'] as String,
connectionType: row['connectionType'] as String,
accountNumber: row['accountNumber'] as String,
- createdAt: _dateTimeConverter.decode(row['createdAt'] as int)));
+ createdAt: _dateTimeConverter.decode(row['createdAt'] as int),
+ accountOrder: row['accountOrder'] as int?));
}
@override
Future> getWc2Connections() async {
return _queryAdapter.queryList(
- 'SELECT * FROM Connection WHERE connectionType IN (\"dappConnect2\",\ "walletConnect2\")',
+ 'SELECT * FROM Connection WHERE connectionType IN (\"dappConnect2\", \"walletConnect2\")',
mapper: (Map row) => Connection(
key: row['key'] as String,
name: row['name'] as String,
data: row['data'] as String,
connectionType: row['connectionType'] as String,
accountNumber: row['accountNumber'] as String,
- createdAt: _dateTimeConverter.decode(row['createdAt'] as int)));
+ createdAt: _dateTimeConverter.decode(row['createdAt'] as int),
+ accountOrder: row['accountOrder'] as int?));
}
@override
Future> getConnectionsByType(String type) async {
return _queryAdapter.queryList(
'SELECT * FROM Connection WHERE connectionType = ?1 ORDER BY createdAt DESC',
- mapper: (Map row) => Connection(key: row['key'] as String, name: row['name'] as String, data: row['data'] as String, connectionType: row['connectionType'] as String, accountNumber: row['accountNumber'] as String, createdAt: _dateTimeConverter.decode(row['createdAt'] as int)),
+ mapper: (Map row) => Connection(key: row['key'] as String, name: row['name'] as String, data: row['data'] as String, connectionType: row['connectionType'] as String, accountNumber: row['accountNumber'] as String, createdAt: _dateTimeConverter.decode(row['createdAt'] as int), accountOrder: row['accountOrder'] as int?),
arguments: [type]);
}
@@ -385,10 +392,21 @@ class _$ConnectionDao extends ConnectionDao {
data: row['data'] as String,
connectionType: row['connectionType'] as String,
accountNumber: row['accountNumber'] as String,
- createdAt: _dateTimeConverter.decode(row['createdAt'] as int)),
+ createdAt: _dateTimeConverter.decode(row['createdAt'] as int),
+ accountOrder: row['accountOrder'] as int?),
arguments: [accountNumber]);
}
+ @override
+ Future setConnectionOrder(
+ String accountNumber,
+ int accountOrder,
+ ) async {
+ await _queryAdapter.queryNoReturn(
+ 'UPDATE Connection SET accountOrder = ?2 WHERE accountNumber = ?1',
+ arguments: [accountNumber, accountOrder]);
+ }
+
@override
Future findById(String key) async {
return _queryAdapter.query('SELECT * FROM Connection WHERE key = ?1',
@@ -398,7 +416,8 @@ class _$ConnectionDao extends ConnectionDao {
data: row['data'] as String,
connectionType: row['connectionType'] as String,
accountNumber: row['accountNumber'] as String,
- createdAt: _dateTimeConverter.decode(row['createdAt'] as int)),
+ createdAt: _dateTimeConverter.decode(row['createdAt'] as int),
+ accountOrder: row['accountOrder'] as int?),
arguments: [key]);
}
@@ -531,7 +550,8 @@ class _$WalletAddressDao extends WalletAddressDao {
'cryptoType': item.cryptoType,
'createdAt': _dateTimeConverter.encode(item.createdAt),
'isHidden': item.isHidden ? 1 : 0,
- 'name': item.name
+ 'name': item.name,
+ 'accountOrder': item.accountOrder
}),
_walletAddressUpdateAdapter = UpdateAdapter(
database,
@@ -544,7 +564,8 @@ class _$WalletAddressDao extends WalletAddressDao {
'cryptoType': item.cryptoType,
'createdAt': _dateTimeConverter.encode(item.createdAt),
'isHidden': item.isHidden ? 1 : 0,
- 'name': item.name
+ 'name': item.name,
+ 'accountOrder': item.accountOrder
}),
_walletAddressDeletionAdapter = DeletionAdapter(
database,
@@ -557,7 +578,8 @@ class _$WalletAddressDao extends WalletAddressDao {
'cryptoType': item.cryptoType,
'createdAt': _dateTimeConverter.encode(item.createdAt),
'isHidden': item.isHidden ? 1 : 0,
- 'name': item.name
+ 'name': item.name,
+ 'accountOrder': item.accountOrder
});
final sqflite.DatabaseExecutor database;
@@ -582,7 +604,8 @@ class _$WalletAddressDao extends WalletAddressDao {
cryptoType: row['cryptoType'] as String,
createdAt: _dateTimeConverter.decode(row['createdAt'] as int),
isHidden: (row['isHidden'] as int) != 0,
- name: row['name'] as String?));
+ name: row['name'] as String?,
+ accountOrder: row['accountOrder'] as int?));
}
@override
@@ -595,7 +618,8 @@ class _$WalletAddressDao extends WalletAddressDao {
cryptoType: row['cryptoType'] as String,
createdAt: _dateTimeConverter.decode(row['createdAt'] as int),
isHidden: (row['isHidden'] as int) != 0,
- name: row['name'] as String?),
+ name: row['name'] as String?,
+ accountOrder: row['accountOrder'] as int?),
arguments: [address]);
}
@@ -610,7 +634,8 @@ class _$WalletAddressDao extends WalletAddressDao {
cryptoType: row['cryptoType'] as String,
createdAt: _dateTimeConverter.decode(row['createdAt'] as int),
isHidden: (row['isHidden'] as int) != 0,
- name: row['name'] as String?),
+ name: row['name'] as String?,
+ accountOrder: row['accountOrder'] as int?),
arguments: [uuid]);
}
@@ -626,7 +651,8 @@ class _$WalletAddressDao extends WalletAddressDao {
cryptoType: row['cryptoType'] as String,
createdAt: _dateTimeConverter.decode(row['createdAt'] as int),
isHidden: (row['isHidden'] as int) != 0,
- name: row['name'] as String?),
+ name: row['name'] as String?,
+ accountOrder: row['accountOrder'] as int?),
arguments: [isHidden ? 1 : 0]);
}
@@ -644,7 +670,8 @@ class _$WalletAddressDao extends WalletAddressDao {
cryptoType: row['cryptoType'] as String,
createdAt: _dateTimeConverter.decode(row['createdAt'] as int),
isHidden: (row['isHidden'] as int) != 0,
- name: row['name'] as String?),
+ name: row['name'] as String?,
+ accountOrder: row['accountOrder'] as int?),
arguments: [uuid, cryptoType]);
}
@@ -659,7 +686,8 @@ class _$WalletAddressDao extends WalletAddressDao {
cryptoType: row['cryptoType'] as String,
createdAt: _dateTimeConverter.decode(row['createdAt'] as int),
isHidden: (row['isHidden'] as int) != 0,
- name: row['name'] as String?),
+ name: row['name'] as String?,
+ accountOrder: row['accountOrder'] as int?),
arguments: [cryptoType]);
}
@@ -673,6 +701,16 @@ class _$WalletAddressDao extends WalletAddressDao {
arguments: [address, isHidden ? 1 : 0]);
}
+ @override
+ Future setAddressOrder(
+ String address,
+ int accountOrder,
+ ) async {
+ await _queryAdapter.queryNoReturn(
+ 'UPDATE WalletAddress SET accountOrder = ?2 WHERE address = ?1',
+ arguments: [address, accountOrder]);
+ }
+
@override
Future removeAll() async {
await _queryAdapter.queryNoReturn('DELETE FROM WalletAddress');
diff --git a/lib/database/dao/address_dao.dart b/lib/database/dao/address_dao.dart
index fbfb1e8df..f563b3df3 100644
--- a/lib/database/dao/address_dao.dart
+++ b/lib/database/dao/address_dao.dart
@@ -1,5 +1,6 @@
import 'package:autonomy_flutter/database/entity/wallet_address.dart';
import 'package:floor/floor.dart';
+//ignore_for_file: lines_longer_than_80_chars
@dao
abstract class WalletAddressDao {
@@ -32,6 +33,11 @@ abstract class WalletAddressDao {
'UPDATE WalletAddress SET isHidden = :isHidden WHERE address = :address')
Future setAddressIsHidden(String address, bool isHidden);
+ // update order query
+ @Query(
+ 'UPDATE WalletAddress SET accountOrder = :accountOrder WHERE address = :address')
+ Future setAddressOrder(String address, int accountOrder);
+
@update
Future updateAddress(WalletAddress address);
diff --git a/lib/database/dao/connection_dao.dart b/lib/database/dao/connection_dao.dart
index f49b933c0..425adb416 100644
--- a/lib/database/dao/connection_dao.dart
+++ b/lib/database/dao/connection_dao.dart
@@ -9,6 +9,7 @@ import 'dart:convert';
import 'package:autonomy_flutter/database/entity/connection.dart';
import 'package:floor/floor.dart';
+//ignore_for_file: lines_longer_than_80_chars
@dao
abstract class ConnectionDao {
@@ -52,6 +53,11 @@ abstract class ConnectionDao {
'COLLATE NOCASE')
Future> getConnectionsByAccountNumber(String accountNumber);
+ // update order query
+ @Query(
+ 'UPDATE Connection SET accountOrder = :accountOrder WHERE accountNumber = :accountNumber')
+ Future setConnectionOrder(String accountNumber, int accountOrder);
+
@Insert(onConflict: OnConflictStrategy.replace)
Future insertConnection(Connection connection);
diff --git a/lib/database/entity/connection.dart b/lib/database/entity/connection.dart
index 009661955..290005c62 100644
--- a/lib/database/entity/connection.dart
+++ b/lib/database/entity/connection.dart
@@ -7,11 +7,10 @@
import 'dart:convert';
+import 'package:autonomy_flutter/model/connection_supports.dart';
import 'package:autonomy_flutter/util/constants.dart';
import 'package:autonomy_flutter/util/wallet_storage_ext.dart';
import 'package:floor/floor.dart';
-
-import 'package:autonomy_flutter/model/connection_supports.dart';
import 'package:nft_collection/models/address_index.dart';
enum ConnectionType {
@@ -35,6 +34,7 @@ class Connection {
String connectionType;
String accountNumber;
DateTime createdAt;
+ int? accountOrder;
/* Data
enum ConnectionType {
@@ -55,6 +55,7 @@ class Connection {
required this.connectionType,
required this.accountNumber,
required this.createdAt,
+ this.accountOrder,
});
Connection copyWith({
@@ -64,19 +65,22 @@ class Connection {
String? connectionType,
String? accountNumber,
DateTime? createdAt,
- }) {
- return Connection(
- key: key ?? this.key,
- name: name ?? this.name,
- data: data ?? this.data,
- connectionType: connectionType ?? this.connectionType,
- accountNumber: accountNumber ?? this.accountNumber,
- createdAt: createdAt ?? this.createdAt,
- );
- }
+ int? accountOrder,
+ }) =>
+ Connection(
+ key: key ?? this.key,
+ name: name ?? this.name,
+ data: data ?? this.data,
+ connectionType: connectionType ?? this.connectionType,
+ accountNumber: accountNumber ?? this.accountNumber,
+ createdAt: createdAt ?? this.createdAt,
+ accountOrder: accountOrder ?? this.accountOrder,
+ );
BeaconConnectConnection? get beaconConnectConnection {
- if (connectionType != ConnectionType.beaconP2PPeer.rawValue) return null;
+ if (connectionType != ConnectionType.beaconP2PPeer.rawValue) {
+ return null;
+ }
final jsonData = json.decode(data);
return BeaconConnectConnection.fromJson(jsonData);
@@ -84,35 +88,35 @@ class Connection {
String? get wc2ConnectedSession {
if (connectionType != ConnectionType.walletConnect2.rawValue &&
- connectionType != ConnectionType.dappConnect2.rawValue) return null;
+ connectionType != ConnectionType.dappConnect2.rawValue) {
+ return null;
+ }
return data;
}
String get appName {
if (beaconConnectConnection != null) {
- return beaconConnectConnection?.peer.name ?? "";
+ return beaconConnectConnection?.peer.name ?? '';
}
if (wc2ConnectedSession != null) {
return name;
}
- return "";
+ return '';
}
- List get accountNumbers {
- return accountNumber.split("||");
- }
+ List get accountNumbers => accountNumber.split('||');
- List get addressIndexes {
- return accountNumbers
- .map((e) => AddressIndex(address: e, createdAt: createdAt))
- .toList();
- }
+ List get addressIndexes => accountNumbers
+ .map((e) => AddressIndex(address: e, createdAt: createdAt))
+ .toList();
@override
bool operator ==(covariant Connection other) {
- if (identical(this, other)) return true;
+ if (identical(this, other)) {
+ return true;
+ }
return other.key == key &&
other.name == name &&
@@ -123,29 +127,32 @@ class Connection {
}
static Connection? getManuallyAddress(String? address) {
- if (address == null) return null;
+ if (address == null) {
+ return null;
+ }
String checkAddress = address;
final cryptoType = CryptoType.fromAddress(address);
if (cryptoType == CryptoType.ETH) {
checkAddress = address.getETHEip55Address();
}
- if (cryptoType == CryptoType.UNKNOWN) return null;
+ if (cryptoType == CryptoType.UNKNOWN) {
+ return null;
+ }
return Connection(
key: checkAddress,
name: cryptoType.source,
- data: "",
+ data: '',
connectionType: ConnectionType.manuallyAddress.rawValue,
accountNumber: checkAddress,
createdAt: DateTime.now());
}
@override
- int get hashCode {
- return key.hashCode ^
- name.hashCode ^
- data.hashCode ^
- connectionType.hashCode ^
- accountNumber.hashCode ^
- createdAt.hashCode;
- }
+ int get hashCode =>
+ key.hashCode ^
+ name.hashCode ^
+ data.hashCode ^
+ connectionType.hashCode ^
+ accountNumber.hashCode ^
+ createdAt.hashCode;
}
diff --git a/lib/database/entity/persona.dart b/lib/database/entity/persona.dart
index 14d5b2873..9f87487d4 100644
--- a/lib/database/entity/persona.dart
+++ b/lib/database/entity/persona.dart
@@ -19,14 +19,11 @@ import 'package:nft_collection/services/address_service.dart';
class DateTimeConverter extends TypeConverter {
@override
- DateTime decode(int databaseValue) {
- return DateTime.fromMillisecondsSinceEpoch(databaseValue);
- }
+ DateTime decode(int databaseValue) =>
+ DateTime.fromMillisecondsSinceEpoch(databaseValue);
@override
- int encode(DateTime value) {
- return value.millisecondsSinceEpoch;
- }
+ int encode(DateTime value) => value.millisecondsSinceEpoch;
}
@entity
@@ -48,18 +45,18 @@ class Persona {
this.defaultAccount,
this.ethereumIndex = 1,
this.tezosIndex = 1,
- this.ethereumIndexes = "",
- this.tezosIndexes = ""});
+ this.ethereumIndexes = '',
+ this.tezosIndexes = ''});
Persona.newPersona(
{required this.uuid,
- this.name = "",
+ this.name = '',
this.defaultAccount,
DateTime? createdAt,
this.ethereumIndex = 1,
this.tezosIndex = 1,
- this.ethereumIndexes = "0",
- this.tezosIndexes = "0"})
+ this.ethereumIndexes = '0',
+ this.tezosIndexes = '0'})
: createdAt = createdAt ?? DateTime.now();
Persona copyWith({
@@ -67,49 +64,53 @@ class Persona {
DateTime? createdAt,
String? ethereumIndexes,
String? tezosIndexes,
- }) {
- return Persona(
- uuid: uuid,
- name: name ?? this.name,
- defaultAccount: defaultAccount,
- createdAt: createdAt ?? this.createdAt,
- ethereumIndexes: ethereumIndexes ?? this.ethereumIndexes,
- tezosIndexes: tezosIndexes ?? this.tezosIndexes);
- }
+ }) =>
+ Persona(
+ uuid: uuid,
+ name: name ?? this.name,
+ defaultAccount: defaultAccount,
+ createdAt: createdAt ?? this.createdAt,
+ ethereumIndexes: ethereumIndexes ?? this.ethereumIndexes,
+ tezosIndexes: tezosIndexes ?? this.tezosIndexes);
// fromJson method
- factory Persona.fromJson(Map json) {
- return Persona(
- uuid: json['uuid'],
- name: json['name'],
- createdAt: DateTimeConverter().decode(json['createdAt']),
- defaultAccount: json['defaultAccount'],
- ethereumIndex: json['ethereumIndex'],
- tezosIndex: json['tezosIndex'],
- ethereumIndexes: json['ethereumIndexes'],
- tezosIndexes: json['tezosIndexes'],
- );
- }
-
- WalletStorage wallet() {
- return LibAukDart.getWallet(uuid);
- }
-
- Future> getWalletAddresses() async {
- return injector().addressDao.findByWalletID(uuid);
- }
-
- Future> getEthWalletAddresses() async {
- return injector()
- .addressDao
- .getAddresses(uuid, CryptoType.ETH.source);
- }
-
- Future> getTezWalletAddresses() async {
- return injector()
- .addressDao
- .getAddresses(uuid, CryptoType.XTZ.source);
- }
+ factory Persona.fromJson(Map json) => Persona(
+ uuid: json['uuid'],
+ name: json['name'],
+ createdAt: DateTimeConverter().decode(json['createdAt']),
+ defaultAccount: json['defaultAccount'],
+ ethereumIndex: json['ethereumIndex'],
+ tezosIndex: json['tezosIndex'],
+ ethereumIndexes: json['ethereumIndexes'],
+ tezosIndexes: json['tezosIndexes'],
+ );
+
+ // toJson method
+ Map toJson() => {
+ 'uuid': uuid,
+ 'name': name,
+ 'createdAt': DateTimeConverter().encode(createdAt),
+ 'defaultAccount': defaultAccount,
+ 'ethereumIndex': ethereumIndex,
+ 'tezosIndex': tezosIndex,
+ 'ethereumIndexes': ethereumIndexes,
+ 'tezosIndexes': tezosIndexes,
+ };
+
+ WalletStorage wallet() => LibAukDart.getWallet(uuid);
+
+ Future> getWalletAddresses() async =>
+ injector().addressDao.findByWalletID(uuid);
+
+ Future> getEthWalletAddresses() async =>
+ injector()
+ .addressDao
+ .getAddresses(uuid, CryptoType.ETH.source);
+
+ Future> getTezWalletAddresses() async =>
+ injector()
+ .addressDao
+ .getAddresses(uuid, CryptoType.XTZ.source);
bool isDefault() => defaultAccount == 1;
@@ -187,7 +188,9 @@ class Persona {
@override
bool operator ==(covariant Persona other) {
- if (identical(this, other)) return true;
+ if (identical(this, other)) {
+ return true;
+ }
return other.uuid == uuid &&
other.name == name &&
@@ -198,12 +201,11 @@ class Persona {
}
@override
- int get hashCode {
- return uuid.hashCode ^
- name.hashCode ^
- createdAt.hashCode ^
- defaultAccount.hashCode ^
- ethereumIndexes.hashCode ^
- tezosIndexes.hashCode;
- }
+ int get hashCode =>
+ uuid.hashCode ^
+ name.hashCode ^
+ createdAt.hashCode ^
+ defaultAccount.hashCode ^
+ ethereumIndexes.hashCode ^
+ tezosIndexes.hashCode;
}
diff --git a/lib/database/entity/wallet_address.dart b/lib/database/entity/wallet_address.dart
index 4461f4a68..f9c6ebdc9 100644
--- a/lib/database/entity/wallet_address.dart
+++ b/lib/database/entity/wallet_address.dart
@@ -17,6 +17,7 @@ class WalletAddress {
final DateTime createdAt;
final bool isHidden;
final String? name;
+ final int? accountOrder;
WalletAddress(
{required this.address,
@@ -25,7 +26,8 @@ class WalletAddress {
required this.cryptoType,
required this.createdAt,
this.isHidden = false,
- this.name});
+ this.name,
+ this.accountOrder});
WalletAddress copyWith({
String? address,
@@ -35,17 +37,18 @@ class WalletAddress {
DateTime? createdAt,
bool? isHidden,
String? name,
- }) {
- return WalletAddress(
- address: address ?? this.address,
- uuid: uuid ?? this.uuid,
- index: index ?? this.index,
- cryptoType: cryptoType ?? this.cryptoType,
- createdAt: createdAt ?? this.createdAt,
- isHidden: isHidden ?? this.isHidden,
- name: name ?? this.name,
- );
- }
+ int? accountOrder,
+ }) =>
+ WalletAddress(
+ address: address ?? this.address,
+ uuid: uuid ?? this.uuid,
+ index: index ?? this.index,
+ cryptoType: cryptoType ?? this.cryptoType,
+ createdAt: createdAt ?? this.createdAt,
+ isHidden: isHidden ?? this.isHidden,
+ name: name ?? this.name,
+ accountOrder: accountOrder ?? this.accountOrder,
+ );
AddressIndex get addressIndex =>
AddressIndex(address: address, createdAt: createdAt);
diff --git a/lib/screen/bloc/accounts/accounts_bloc.dart b/lib/screen/bloc/accounts/accounts_bloc.dart
index ee2408b46..165a23399 100644
--- a/lib/screen/bloc/accounts/accounts_bloc.dart
+++ b/lib/screen/bloc/accounts/accounts_bloc.dart
@@ -53,6 +53,44 @@ class AccountsBloc extends AuBloc {
emit(AccountsState(accounts: accounts));
});
+ on((event, emit) {
+ int newOrder = event.newOrder;
+ final oldOrder = event.oldOrder;
+ if (oldOrder == newOrder ||
+ state.accounts == null ||
+ oldOrder >= state.accounts!.length ||
+ newOrder > state.accounts!.length) {
+ return;
+ }
+
+ if (oldOrder < newOrder) {
+ newOrder -= 1;
+ }
+ final List accounts = [...state.accounts!];
+ final Account account = accounts.removeAt(oldOrder);
+ accounts.insert(newOrder, account);
+ emit(state.copyWith(accounts: accounts));
+ add(SaveAccountOrderEvent(accounts: accounts));
+ });
+
+ on((event, emit) async {
+ final accounts = event.accounts;
+ await _cloudDB.database.database.transaction((tx) async {
+ final batch = tx.batch();
+ for (int i = 0; i < accounts.length; i++) {
+ final account = accounts[i];
+ if (account.persona != null) {
+ batch.update('WalletAddress', {'accountOrder': i},
+ where: 'address = ?', whereArgs: [account.key]);
+ } else {
+ batch.update('Connection', {'accountOrder': i},
+ where: 'accountNumber = ?', whereArgs: [account.accountNumber]);
+ }
+ }
+ await batch.commit();
+ });
+ });
+
on((event, emit) async {
final addresses = await _cloudDB.addressDao.getAllAddresses();
@@ -113,9 +151,9 @@ class AccountsBloc extends AuBloc {
}
if (event.getEth) {
final ethConnections = connections.where((connection) {
- final crytoType =
+ final cryptoType =
CryptoType.fromAddress(connection.accountNumber).source;
- return crytoType == CryptoType.ETH.source;
+ return cryptoType == CryptoType.ETH.source;
}).toList();
categorizedConnection.addAll(ethConnections);
}
@@ -127,14 +165,14 @@ class AccountsBloc extends AuBloc {
}
List accounts = await getAccountPersona(addresses);
- accounts.addAll(viewOnlyAccounts);
- accounts.sort(_compareAccount);
+ accounts
+ ..addAll(viewOnlyAccounts)
+ ..sort(_compareAccount);
emit(state.copyWith(accounts: accounts));
});
on((event, emit) {
- final connection = event.connection;
- connection.name = event.name;
+ final connection = event.connection..name = event.name;
_cloudDB.connectionDao.updateConnection(connection);
add(GetAccountsEvent());
@@ -175,7 +213,9 @@ class AccountsBloc extends AuBloc {
final existingConnections = await _cloudDB.connectionDao
.getConnectionsByAccountNumber(accountNumber);
- if (existingConnections.isEmpty) return null;
+ if (existingConnections.isEmpty) {
+ return null;
+ }
return existingConnections.first;
}
@@ -183,8 +223,7 @@ class AccountsBloc extends AuBloc {
Future> getAccountPersona(
List walletAddresses) async {
final personas = await _cloudDB.personaDao.getPersonas();
- final List addresses = [];
- addresses.addAll(walletAddresses);
+ final List addresses = [...walletAddresses];
List accounts = [];
for (var e in addresses) {
final name = e.name != null && e.name!.isNotEmpty ? e.name : e.cryptoType;
@@ -194,17 +233,33 @@ class AccountsBloc extends AuBloc {
accounts.add(Account(
key: e.address,
persona: persona,
- name: name ?? "",
+ name: name ?? '',
blockchain: e.cryptoType,
walletAddress: e,
accountNumber: e.address,
- createdAt: e.createdAt));
+ createdAt: e.createdAt,
+ accountOrder: e.accountOrder));
}
}
return accounts;
}
int _compareAccount(Account a, Account b) {
+ if (a.accountOrder == b.accountOrder) {
+ return _compareAccountWithoutOrder(a, b);
+ }
+
+ if (a.accountOrder == null) {
+ return 1;
+ }
+ if (b.accountOrder == null) {
+ return -1;
+ }
+
+ return a.accountOrder!.compareTo(b.accountOrder!);
+ }
+
+ int _compareAccountWithoutOrder(Account a, Account b) {
final aDefault = a.persona?.defaultAccount ?? 0;
final bDefault = b.persona?.defaultAccount ?? 0;
if (aDefault != bDefault) {
@@ -224,6 +279,7 @@ class AccountsBloc extends AuBloc {
blockchain: cryptoType,
name: name,
createdAt: connection.createdAt,
+ accountOrder: connection.accountOrder,
);
}
}
diff --git a/lib/screen/bloc/accounts/accounts_state.dart b/lib/screen/bloc/accounts/accounts_state.dart
index fab710c72..1db3ea9e7 100644
--- a/lib/screen/bloc/accounts/accounts_state.dart
+++ b/lib/screen/bloc/accounts/accounts_state.dart
@@ -13,6 +13,19 @@ class ResetEventEvent extends AccountsEvent {}
class GetAccountsEvent extends AccountsEvent {}
+class ChangeAccountOrderEvent extends AccountsEvent {
+ final int oldOrder;
+ final int newOrder;
+
+ ChangeAccountOrderEvent({required this.oldOrder, required this.newOrder});
+}
+
+class SaveAccountOrderEvent extends AccountsEvent {
+ final List accounts;
+
+ SaveAccountOrderEvent({required this.accounts});
+}
+
class GetCategorizedAccountsEvent extends AccountsEvent {
final bool includeLinkedAccount;
final bool getTezos;
@@ -63,32 +76,36 @@ class Account {
WalletAddress? walletAddress;
String accountNumber;
DateTime createdAt;
+ int? accountOrder;
- bool get isTez => blockchain == "Tezos";
+ bool get isTez => blockchain == 'Tezos';
- bool get isEth => blockchain == "Ethereum";
+ bool get isEth => blockchain == 'Ethereum';
- bool get isUsdc => blockchain == "USDC";
+ bool get isUsdc => blockchain == 'USDC';
String get className =>
- persona != null && walletAddress != null ? "Persona" : "Connection";
+ persona != null && walletAddress != null ? 'Persona' : 'Connection';
bool get isViewOnly => persona == null && walletAddress == null;
Account({
required this.key,
+ required this.createdAt,
this.persona,
this.connections,
this.blockchain,
this.walletAddress,
- this.accountNumber = "",
- this.name = "",
- required this.createdAt,
+ this.accountNumber = '',
+ this.name = '',
+ this.accountOrder,
});
@override
bool operator ==(covariant Account other) {
- if (identical(this, other)) return true;
+ if (identical(this, other)) {
+ return true;
+ }
return other.key == key &&
other.persona == persona &&
@@ -97,20 +114,21 @@ class Account {
other.blockchain == blockchain &&
other.walletAddress == walletAddress &&
other.accountNumber == accountNumber &&
- other.createdAt == createdAt;
+ other.createdAt == createdAt &&
+ other.accountOrder == accountOrder;
}
@override
- int get hashCode {
- return key.hashCode ^
- persona.hashCode ^
- connections.hashCode ^
- name.hashCode ^
- blockchain.hashCode ^
- walletAddress.hashCode ^
- accountNumber.hashCode ^
- createdAt.hashCode;
- }
+ int get hashCode =>
+ key.hashCode ^
+ persona.hashCode ^
+ connections.hashCode ^
+ name.hashCode ^
+ blockchain.hashCode ^
+ walletAddress.hashCode ^
+ accountNumber.hashCode ^
+ createdAt.hashCode ^
+ accountOrder.hashCode;
}
class AccountsState {
@@ -121,24 +139,21 @@ class AccountsState {
AccountsState({this.addresses = const [], this.accounts, this.event});
AccountsState copyWith(
- {List? addresses,
- List? accounts,
- Network? network,
- AccountBlocStateEvent? event}) {
- return AccountsState(
- addresses: addresses ?? this.addresses,
- accounts: accounts ?? this.accounts,
- event: event ?? this.event,
- );
- }
-
- AccountsState setEvent(AccountBlocStateEvent? event) {
- return AccountsState(
- addresses: addresses,
- accounts: accounts,
- event: event,
- );
- }
+ {List? addresses,
+ List? accounts,
+ Network? network,
+ AccountBlocStateEvent? event}) =>
+ AccountsState(
+ addresses: addresses ?? this.addresses,
+ accounts: accounts ?? this.accounts,
+ event: event ?? this.event,
+ );
+
+ AccountsState setEvent(AccountBlocStateEvent? event) => AccountsState(
+ addresses: addresses,
+ accounts: accounts,
+ event: event,
+ );
}
abstract class AccountBlocStateEvent {}
diff --git a/lib/screen/bloc/router/router_bloc.dart b/lib/screen/bloc/router/router_bloc.dart
index bc46da4e6..09312d486 100644
--- a/lib/screen/bloc/router/router_bloc.dart
+++ b/lib/screen/bloc/router/router_bloc.dart
@@ -100,14 +100,17 @@ class RouterBloc extends AuBloc {
if (_configurationService.isDoneOnboarding()) {
return;
}
+ log.info('[RestoreCloudDatabase] restoreCloudDatabase');
await _backupService.restoreCloudDatabase(
await _accountService.getDefaultAccount(), event.version);
await _settingsDataService.restoreSettingsData();
await _accountService.androidRestoreKeys();
+ log.info('[RestoreCloudDatabase] restoreCloudDatabase success');
final personas = await _cloudDB.personaDao.getPersonas();
+ log.info('[RestoreCloudDatabase] personas: ${personas.length}');
for (var persona in personas) {
if (persona.name != '') {
unawaited(persona.wallet().updateName(persona.name));
@@ -115,6 +118,7 @@ class RouterBloc extends AuBloc {
}
final connections =
await _cloudDB.connectionDao.getUpdatedLinkedAccounts();
+ log.info('[RestoreCloudDatabase] connections: ${connections.length}');
if (personas.isEmpty && connections.isEmpty) {
await _configurationService.setDoneOnboarding(false);
emit(RouterState(onboardingStep: OnboardingStep.startScreen));
diff --git a/lib/screen/irl_screen/webview_irl_screen.dart b/lib/screen/irl_screen/webview_irl_screen.dart
index 8f869bd95..7853be0e9 100644
--- a/lib/screen/irl_screen/webview_irl_screen.dart
+++ b/lib/screen/irl_screen/webview_irl_screen.dart
@@ -112,6 +112,8 @@ class _IRLWebScreenState extends State {
SelectAddressView(
addresses: addresses,
),
+ padding: const EdgeInsets.symmetric(vertical: 32),
+ paddingTitle: const EdgeInsets.symmetric(horizontal: 14),
);
}
if (address != null) {
diff --git a/lib/screen/migration/key_sync_bloc.dart b/lib/screen/migration/key_sync_bloc.dart
index cc3f8c42d..b5bc8ba95 100644
--- a/lib/screen/migration/key_sync_bloc.dart
+++ b/lib/screen/migration/key_sync_bloc.dart
@@ -44,15 +44,8 @@ class KeySyncBloc extends AuBloc {
final tmpCloudDb = await $FloorCloudDatabase
.databaseBuilder(tmpCloudDbName)
- .addMigrations([
- migrateCloudV1ToV2,
- migrateCloudV2ToV3,
- migrateCloudV3ToV4,
- migrateCloudV4ToV5,
- migrateCloudV5ToV6,
- migrateCloudV6ToV7,
- migrateCloudV7ToV8,
- ]).build();
+ .addMigrations(cloudDatabaseMigrations)
+ .build();
final connections = await tmpCloudDb.connectionDao.getConnections();
await _cloudDatabase.connectionDao.insertConnections(connections);
diff --git a/lib/screen/scan_qr/scan_qr_page.dart b/lib/screen/scan_qr/scan_qr_page.dart
index 75d7cf064..c9dd46ad3 100644
--- a/lib/screen/scan_qr/scan_qr_page.dart
+++ b/lib/screen/scan_qr/scan_qr_page.dart
@@ -566,8 +566,8 @@ class QRScanViewState extends State
'scan_qr_to'.tr(),
style: theme.textTheme.ppMori700White14,
),
- Divider(
- color: theme.colorScheme.secondary,
+ const Divider(
+ color: AppColor.auGreyBackground,
height: 30,
),
RichText(
@@ -589,7 +589,24 @@ class QRScanViewState extends State
const SizedBox(height: 15),
RichText(
text: TextSpan(
- text: 'autonomy_canvas'.tr(),
+ text: 'sign_transaction'.tr(),
+ children: [
+ TextSpan(
+ text: ' ',
+ style: theme.textTheme.ppMori400Grey14,
+ ),
+ TextSpan(
+ text: 'after_connecting'.tr(),
+ style: theme.textTheme.ppMori400Grey14,
+ ),
+ ],
+ style: theme.textTheme.ppMori400White14,
+ ),
+ ),
+ const SizedBox(height: 15),
+ RichText(
+ text: TextSpan(
+ text: 'display_with_ff'.tr(),
children: [
TextSpan(
text: ' ',
diff --git a/lib/screen/settings/connection/accounts_view.dart b/lib/screen/settings/connection/accounts_view.dart
index 98154d38c..9cac0f5f0 100644
--- a/lib/screen/settings/connection/accounts_view.dart
+++ b/lib/screen/settings/connection/accounts_view.dart
@@ -51,64 +51,63 @@ class _AccountsViewState extends State {
}
@override
- Widget build(BuildContext context) {
- final theme = Theme.of(context);
+ Widget build(BuildContext context) =>
+ BlocConsumer(listener: (context, state) {
+ final accounts = state.accounts;
+ if (accounts == null) {
+ return;
+ }
+ }, builder: (context, state) {
+ final accounts = state.accounts;
+ if (accounts == null) {
+ return const Center(child: CupertinoActivityIndicator());
+ }
+ if (accounts.isEmpty) {
+ return const SizedBox();
+ }
- return BlocConsumer(
- listener: (context, state) {
- final accounts = state.accounts;
- if (accounts == null) {
- return;
- }
- }, builder: (context, state) {
- final accounts = state.accounts;
- if (accounts == null) {
- return const Center(child: CupertinoActivityIndicator());
- }
- if (accounts.isEmpty) {
- return const SizedBox();
- }
+ if (!widget.isInSettingsPage) {
+ return _noEditAccountsListWidget(accounts);
+ }
+ return ReorderableListView(
+ header: widget.isInSettingsPage ? const SizedBox(height: 40) : null,
+ onReorder: (int oldIndex, int newIndex) {
+ context.read().add(ChangeAccountOrderEvent(
+ newOrder: newIndex, oldOrder: oldIndex));
+ },
+ children: accounts
+ .map((account) => _accountCard(context, account))
+ .toList(),
+ );
+ });
- if (!widget.isInSettingsPage) {
- return _noEditAccountsListWidget(accounts);
- }
- return SlidableAutoCloseBehavior(
- child: Column(
- children: [
- ...accounts.map(
- (account) => Column(
+ Widget _accountCard(BuildContext context, Account account) => Column(
+ key: ValueKey(account.key),
+ children: [
+ Padding(
+ padding: padding,
+ child: Slidable(
+ groupTag: 'accountsView',
+ endActionPane: ActionPane(
+ motion: const DrawerMotion(),
+ dragDismissible: false,
+ children: slidableActions(account),
+ ),
+ child: Column(
children: [
- Padding(
- padding: padding,
- child: Slidable(
- groupTag: 'accountsView',
- endActionPane: ActionPane(
- motion: const DrawerMotion(),
- dragDismissible: false,
- children: slidableActions(account),
- ),
- child: Column(
- children: [
- if (_editingAccountKey == null ||
- _editingAccountKey != account.key) ...[
- _viewAccountItem(account),
- ] else ...[
- _editAccountItem(account),
- ],
- ],
- ),
- ),
- ),
- const Divider(
- height: 1, thickness: 1, color: AppColor.auLightGrey)
+ if (_editingAccountKey == null ||
+ _editingAccountKey != account.key) ...[
+ _viewAccountItem(account),
+ ] else ...[
+ _editAccountItem(account),
+ ],
],
),
),
- ],
- ),
+ ),
+ const Divider(height: 1, thickness: 1, color: AppColor.auLightGrey)
+ ],
);
- });
- }
List slidableActions(Account account) {
final theme = Theme.of(context);
diff --git a/lib/screen/settings/preferences/preferences_bloc.dart b/lib/screen/settings/preferences/preferences_bloc.dart
index b5741aade..4987b7760 100644
--- a/lib/screen/settings/preferences/preferences_bloc.dart
+++ b/lib/screen/settings/preferences/preferences_bloc.dart
@@ -5,12 +5,14 @@
// that can be found in the LICENSE file.
//
+import 'dart:async';
import 'dart:io';
import 'package:autonomy_flutter/au_bloc.dart';
import 'package:autonomy_flutter/common/injector.dart';
import 'package:autonomy_flutter/screen/settings/preferences/preferences_state.dart';
import 'package:autonomy_flutter/service/configuration_service.dart';
+import 'package:autonomy_flutter/service/local_auth_service.dart';
import 'package:autonomy_flutter/service/mix_panel_client_service.dart';
import 'package:autonomy_flutter/service/settings_data_service.dart';
import 'package:autonomy_flutter/util/biometrics_util.dart';
@@ -26,7 +28,7 @@ class PreferencesBloc extends AuBloc {
List _availableBiometrics = List.empty();
PreferencesBloc(this._configurationService)
- : super(PreferenceState(false, false, false, "", false, false)) {
+ : super(PreferenceState(false, false, false, '', false, false)) {
on((event, emit) async {
_availableBiometrics = await _localAuth.getAvailableBiometrics();
final canCheckBiometrics = await authenticateIsAvailable();
@@ -57,8 +59,8 @@ class PreferencesBloc extends AuBloc {
if (canCheckBiometrics) {
bool didAuthenticate = false;
try {
- didAuthenticate = await _localAuth.authenticate(
- localizedReason: "authen_for_autonomy".tr());
+ didAuthenticate = await LocalAuthenticationService.authenticate(
+ localizedReason: 'authen_for_autonomy'.tr());
} catch (e) {
log.info(e);
}
@@ -72,25 +74,26 @@ class PreferencesBloc extends AuBloc {
}
} else {
event.newState.isDevicePasscodeEnabled = false;
- openAppSettings();
+ unawaited(openAppSettings());
}
}
if (event.newState.isNotificationEnabled != state.isNotificationEnabled) {
try {
- if (event.newState.isNotificationEnabled == true) {
- registerPushNotifications(askPermission: true)
- .then((value) => event.newState.isNotificationEnabled == value);
+ if (event.newState.isNotificationEnabled) {
+ unawaited(registerPushNotifications(askPermission: true).then(
+ (value) => event.newState.isNotificationEnabled == value));
} else if (Platform.isIOS) {
+ // ignore: lines_longer_than_80_chars
// TODO: for iOS only, do not un-registry push, but silent the notification
- deregisterPushNotification();
+ unawaited(deregisterPushNotification());
}
await _configurationService
.setNotificationEnabled(event.newState.isNotificationEnabled);
await _configurationService.setPendingSettings(false);
} catch (error) {
- log.warning("Error when setting notification: $error");
+ log.warning('Error when setting notification: $error');
}
}
@@ -98,7 +101,7 @@ class PreferencesBloc extends AuBloc {
await _configurationService
.setAnalyticEnabled(event.newState.isAnalyticEnabled);
await _configurationService.setPendingSettings(false);
- injector().backup();
+ unawaited(injector().backup());
if (event.newState.isAnalyticEnabled) {
injector().mixpanel.optInTracking();
diff --git a/lib/screen/wallet/wallet_page.dart b/lib/screen/wallet/wallet_page.dart
index 4896be577..54213eec6 100644
--- a/lib/screen/wallet/wallet_page.dart
+++ b/lib/screen/wallet/wallet_page.dart
@@ -139,17 +139,12 @@ class _WalletPageState extends State
),
action: _showAddWalletOption),
body: SafeArea(
- child: SingleChildScrollView(
+ child: Padding(
padding: EdgeInsets.only(
bottom: ResponsiveLayout.pageEdgeInsetsWithSubmitButton.bottom,
),
- child: const Column(
- children: [
- SizedBox(height: 40),
- AccountsView(
- isInSettingsPage: true,
- ),
- ],
+ child: const AccountsView(
+ isInSettingsPage: true,
),
),
),
diff --git a/lib/service/backup_service.dart b/lib/service/backup_service.dart
index aea6c780b..f56a38996 100644
--- a/lib/service/backup_service.dart
+++ b/lib/service/backup_service.dart
@@ -5,6 +5,7 @@
// that can be found in the LICENSE file.
//
+import 'dart:async';
import 'dart:convert';
import 'dart:io';
@@ -23,6 +24,7 @@ import 'package:http/http.dart' as http;
import 'package:libauk_dart/libauk_dart.dart';
import 'package:package_info_plus/package_info_plus.dart';
import 'package:path_provider/path_provider.dart';
+import 'package:sentry_flutter/sentry_flutter.dart';
import 'package:sqflite/sqflite.dart' as sqflite;
import 'package:sqflite/sqflite.dart';
@@ -133,8 +135,10 @@ class BackupService {
},
);
if (resp.statusCode == 200) {
+ log.info('[BackupService] got response');
try {
final version = await injector().database.getVersion();
+ log.info('[BackupService] Cloud database local version is $version');
final tempFilePath =
'${(await getTemporaryDirectory()).path}/$_dbEncryptedFileName';
final tempFile = File(tempFilePath);
@@ -151,6 +155,9 @@ class BackupService {
} catch (e) {
log.warning('[BackupService] Cloud database decrypted failed,'
' fallback to legacy method');
+ unawaited(Sentry.captureException(
+ '[BackupService] Cloud database decrypted failed, '
+ 'fallback to legacy method, $e'));
await account.decryptFile(
inputPath: tempFilePath,
outputPath: dbFilePath,
@@ -160,17 +167,11 @@ class BackupService {
final tempDbOld = await sqfliteDatabaseFactory.openDatabase(dbFilePath);
final backUpVersion = await tempDbOld.getVersion();
+ log.info(
+ '[BackupService] Cloud database backup version is $backUpVersion');
if (version > backUpVersion) {
await MigrationAdapter.runMigrations(
- tempDbOld, backUpVersion, version, [
- migrateCloudV1ToV2,
- migrateCloudV2ToV3,
- migrateCloudV3ToV4,
- migrateCloudV4ToV5,
- migrateCloudV5ToV6,
- migrateCloudV6ToV7,
- migrateCloudV7ToV8,
- ]);
+ tempDbOld, backUpVersion, version, cloudDatabaseMigrations);
}
final tempDb =
@@ -178,12 +179,12 @@ class BackupService {
await injector().copyDataFrom(tempDb);
await tempFile.delete();
await File(dbFilePath).delete();
- log.info(
- '[BackupService] Cloud database is restored $backUpVersion to '
- '$version');
+ log.info('[BackupService] Cloud database is restored $backUpVersion to '
+ '$version');
return;
} catch (e) {
- log.info('[BackupService] Failed to restore Cloud Database $e');
+ log.info("[BackupService] Failed to restore Cloud Database $e");
+ unawaited(Sentry.captureException(e, stackTrace: StackTrace.current));
return;
}
}
diff --git a/lib/service/local_auth_service.dart b/lib/service/local_auth_service.dart
index d943c6160..8ccadb1e3 100644
--- a/lib/service/local_auth_service.dart
+++ b/lib/service/local_auth_service.dart
@@ -1,11 +1,42 @@
+import 'dart:async';
+
import 'package:autonomy_flutter/common/injector.dart';
import 'package:autonomy_flutter/service/configuration_service.dart';
import 'package:autonomy_flutter/util/biometrics_util.dart';
import 'package:autonomy_flutter/util/log.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:local_auth/local_auth.dart';
+import 'package:sentry/sentry_io.dart';
class LocalAuthenticationService {
+ static final LocalAuthentication _localAuth = LocalAuthentication();
+ static int _count = 0;
+ static Timer? _resetTimer;
+ static const int _maxCount = 3;
+
+ static Future authenticate({required String localizedReason}) async {
+ final result = await _localAuth.authenticate(
+ localizedReason: localizedReason,
+ );
+ _resetTimer?.cancel();
+ if (result) {
+ _count = 0;
+ } else {
+ _count++;
+ if (_count >= _maxCount) {
+ // capture sentry event
+ log.info('Local auth failed $_count times');
+ unawaited(Sentry.captureMessage('Local auth failed $_count times'));
+ _count = 0;
+ } else {
+ _resetTimer = Timer(const Duration(minutes: 1), () {
+ _count = 0;
+ });
+ }
+ }
+ return result;
+ }
+
static Future checkLocalAuth() async {
final configurationService = injector();
final isAvailable = await authenticateIsAvailable();
@@ -13,10 +44,9 @@ class LocalAuthenticationService {
configurationService.isDevicePasscodeEnabled();
if (isDevicePasscodeEnabled && isAvailable) {
- final localAuth = LocalAuthentication();
bool didAuthenticate = false;
try {
- didAuthenticate = await localAuth.authenticate(
+ didAuthenticate = await _localAuth.authenticate(
localizedReason: 'authen_for_autonomy'.tr(),
);
} catch (e) {
diff --git a/lib/service/tezos_beacon_service.dart b/lib/service/tezos_beacon_service.dart
index b410d0523..0745cd2c7 100644
--- a/lib/service/tezos_beacon_service.dart
+++ b/lib/service/tezos_beacon_service.dart
@@ -155,7 +155,7 @@ class TezosBeaconService implements BeaconHandler {
final result = await _navigationService
.navigateTo(AppRouter.tbSignMessagePage, arguments: request);
log.info('TezosBeaconService: handle permission Request result: $result');
- if (result) {
+ if (result is String || result == true) {
_showYouAllSet();
}
_clearConnectFlag();
diff --git a/lib/util/http_certificate_check.dart b/lib/util/http_certificate_check.dart
index 6379a2777..17d4b2133 100644
--- a/lib/util/http_certificate_check.dart
+++ b/lib/util/http_certificate_check.dart
@@ -35,6 +35,12 @@ Future _fetchCertificate(Uri url) async {
}
Future checkCertificate(String url) async {
+ if (url.startsWith('http://localhost:') ||
+ url.startsWith('http://192.168.')) {
+ log.info('Localhost, skip certificate check');
+ return true;
+ }
+
final fingerprint = await _fetchCertificate(Uri.parse(url));
if (fingerprint == null) {
unawaited(Sentry.captureMessage(
diff --git a/lib/view/select_address.dart b/lib/view/select_address.dart
index 3364a24e5..642667ce3 100644
--- a/lib/view/select_address.dart
+++ b/lib/view/select_address.dart
@@ -45,28 +45,31 @@ class _SelectAddressViewState extends State {
.toList(),
)),
),
- Row(
- children: [
- Expanded(
- child: Column(
- children: [
- PrimaryButton(
- text: widget.selectButton ?? 'connect'.tr(),
- enabled: _selectedAddress != null,
- onTap: () {
- Navigator.pop(context, _selectedAddress);
- }),
- const SizedBox(
- height: 10,
- ),
- OutlineButton(
- text: 'cancel'.tr(),
- onTap: () {
- Navigator.pop(context, null);
- })
- ],
- )),
- ],
+ Padding(
+ padding: const EdgeInsets.symmetric(horizontal: 14),
+ child: Row(
+ children: [
+ Expanded(
+ child: Column(
+ children: [
+ PrimaryButton(
+ text: widget.selectButton ?? 'connect'.tr(),
+ enabled: _selectedAddress != null,
+ onTap: () {
+ Navigator.pop(context, _selectedAddress);
+ }),
+ const SizedBox(
+ height: 10,
+ ),
+ OutlineButton(
+ text: 'cancel'.tr(),
+ onTap: () {
+ Navigator.pop(context, null);
+ })
+ ],
+ )),
+ ],
+ ),
)
],
));
@@ -88,17 +91,18 @@ class AddressView extends StatelessWidget {
Widget build(BuildContext context) {
final theme = Theme.of(context);
final cryptoType = CryptoType.fromSource(address.cryptoType);
- final color = address.address == selectedAddress
- ? AppColor.white
- : AppColor.disabledColor;
+ final isSelected = address.address == selectedAddress;
+ final color = isSelected ? AppColor.white : AppColor.disabledColor;
final name = address.name ?? '';
return GestureDetector(
onTap: onTap,
child: Column(
children: [
Container(
- padding: const EdgeInsets.symmetric(vertical: 15),
- color: Colors.transparent,
+ padding: const EdgeInsets.symmetric(vertical: 15, horizontal: 14),
+ color: isSelected
+ ? const Color.fromRGBO(30, 30, 30, 1)
+ : Colors.transparent,
child: Row(
children: [
LogoCrypto(
diff --git a/pubspec.lock b/pubspec.lock
index 279a2617f..48f0bf105 100644
--- a/pubspec.lock
+++ b/pubspec.lock
@@ -314,7 +314,7 @@ packages:
source: hosted
version: "2.0.3"
chewie:
- dependency: "direct main"
+ dependency: transitive
description:
name: chewie
sha256: "3427e469d7cc99536ac4fbaa069b3352c21760263e65ffb4f0e1c054af43a73e"
@@ -1685,8 +1685,8 @@ packages:
dependency: "direct main"
description:
path: "."
- ref: "363360e5af9cb76744093c734e8fa290794e189b"
- resolved-ref: "363360e5af9cb76744093c734e8fa290794e189b"
+ ref: "598a4627345f746d7e8fd62e7d0da4766ed29fb6"
+ resolved-ref: "598a4627345f746d7e8fd62e7d0da4766ed29fb6"
url: "https://github.com/autonomy-system/libauk-dart.git"
source: git
version: "0.0.1"
@@ -1887,8 +1887,8 @@ packages:
dependency: "direct main"
description:
path: "."
- ref: b3f4bec450f971829695d9354188d33cd6c6ce75
- resolved-ref: b3f4bec450f971829695d9354188d33cd6c6ce75
+ ref: "0d4cce1bd966cf95edfdf36d5f54505b8534b995"
+ resolved-ref: "0d4cce1bd966cf95edfdf36d5f54505b8534b995"
url: "https://github.com/autonomy-system/nft-rendering.git"
source: git
version: "1.0.9"
@@ -2886,10 +2886,10 @@ packages:
dependency: "direct main"
description:
name: video_player
- sha256: afc65f4b8bcb2c188f64a591f84fb471f4f2e19fc607c65fd8d2f8fedb3dec23
+ sha256: db6a72d8f4fd155d0189845678f55ad2fd54b02c10dcafd11c068dbb631286c0
url: "https://pub.dev"
source: hosted
- version: "2.8.3"
+ version: "2.8.6"
video_player_android:
dependency: transitive
description:
@@ -3116,4 +3116,4 @@ packages:
version: "3.1.2"
sdks:
dart: ">=3.3.0-279.1.beta <4.0.0"
- flutter: ">=3.16.0"
+ flutter: ">=3.16.6"
diff --git a/pubspec.yaml b/pubspec.yaml
index 23b7b465f..4e19bfb14 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -69,7 +69,7 @@ dependencies:
libauk_dart:
git:
url: https://github.com/autonomy-system/libauk-dart.git
- ref: 363360e5af9cb76744093c734e8fa290794e189b
+ ref: 598a4627345f746d7e8fd62e7d0da4766ed29fb6
local_auth: ^2.1.0
logging: ^1.2.0
measured_size: ^1.0.0
@@ -78,7 +78,7 @@ dependencies:
nft_rendering:
git:
url: https://github.com/autonomy-system/nft-rendering.git
- ref: b3f4bec450f971829695d9354188d33cd6c6ce75
+ ref: 0d4cce1bd966cf95edfdf36d5f54505b8534b995
onesignal_flutter: ^3.3.0
open_settings: ^2.0.2
overlay_support: ^2.0.0
@@ -105,7 +105,6 @@ dependencies:
url_launcher: ^6.0.20
uuid: ^3.0.5
wakelock_plus: ^1.1.1
- chewie: ^1.7.0
web3dart: ^2.5.1
web_socket_channel: ^2.1.0
json_annotation: ^4.6.0
@@ -154,7 +153,7 @@ dependencies:
geocoding: ^2.1.0
flutter_inappwebview: ^6.0.0
html: ^0.15.1
- video_player: ^2.4.8
+ video_player: ^2.8.6
walletconnect_flutter_v2: ^2.1.11
awesome_notifications: ^0.8.3
shimmer: ^3.0.0