diff --git a/mnemo_cards/.gitignore b/mnemo_cards/.gitignore deleted file mode 100644 index 79c113f..0000000 --- a/mnemo_cards/.gitignore +++ /dev/null @@ -1,45 +0,0 @@ -# Miscellaneous -*.class -*.log -*.pyc -*.swp -.DS_Store -.atom/ -.build/ -.buildlog/ -.history -.svn/ -.swiftpm/ -migrate_working_dir/ - -# IntelliJ related -*.iml -*.ipr -*.iws -.idea/ - -# The .vscode folder contains launch configuration and tasks you configure in -# VS Code which you may wish to be included in version control, so this line -# is commented out by default. -#.vscode/ - -# Flutter/Dart/Pub related -**/doc/api/ -**/ios/Flutter/.last_build_id -.dart_tool/ -.flutter-plugins -.flutter-plugins-dependencies -.pub-cache/ -.pub/ -/build/ - -# Symbolication related -app.*.symbols - -# Obfuscation related -app.*.map.json - -# Android Studio will place build artifacts here -/android/app/debug -/android/app/profile -/android/app/release diff --git a/mnemo_cards/.metadata b/mnemo_cards/.metadata deleted file mode 100644 index 7622536..0000000 --- a/mnemo_cards/.metadata +++ /dev/null @@ -1,30 +0,0 @@ -# This file tracks properties of this Flutter project. -# Used by Flutter tool to assess capabilities and perform upgrades etc. -# -# This file should be version controlled and should not be manually edited. - -version: - revision: "17025dd88227cd9532c33fa78f5250d548d87e9a" - channel: "stable" - -project_type: app - -# Tracks metadata for the flutter migrate command -migration: - platforms: - - platform: root - create_revision: 17025dd88227cd9532c33fa78f5250d548d87e9a - base_revision: 17025dd88227cd9532c33fa78f5250d548d87e9a - - platform: macos - create_revision: 17025dd88227cd9532c33fa78f5250d548d87e9a - base_revision: 17025dd88227cd9532c33fa78f5250d548d87e9a - - # User provided section - - # List of Local paths (relative to this file) that should be - # ignored by the migrate tool. - # - # Files that are not part of the templates will be ignored by default. - unmanaged_files: - - 'lib/main.dart' - - 'ios/Runner.xcodeproj/project.pbxproj' diff --git a/mnemo_cards/.vscode/launch.json b/mnemo_cards/.vscode/launch.json deleted file mode 100644 index b31a259..0000000 --- a/mnemo_cards/.vscode/launch.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - // Use IntelliSense to learn about possible attributes. - // Hover to view descriptions of existing attributes. - // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 - "version": "0.2.0", - "configurations": [ - { - "name": "mnemo_cards", - "request": "launch", - "type": "dart" - }, - { - "name": "mnemo_cards (profile mode)", - "request": "launch", - "type": "dart", - "flutterMode": "profile" - }, - { - "name": "mnemo_cards (release mode)", - "request": "launch", - "type": "dart", - "flutterMode": "release" - } - ] -} \ No newline at end of file diff --git a/mnemo_cards/README.md b/mnemo_cards/README.md deleted file mode 100644 index 02b65df..0000000 --- a/mnemo_cards/README.md +++ /dev/null @@ -1,16 +0,0 @@ -# mnemo_cards - -Mnemo - -## Getting Started - -This project is a starting point for a Flutter application. - -A few resources to get you started if this is your first Flutter project: - -- [Lab: Write your first Flutter app](https://docs.flutter.dev/get-started/codelab) -- [Cookbook: Useful Flutter samples](https://docs.flutter.dev/cookbook) - -For help getting started with Flutter development, view the -[online documentation](https://docs.flutter.dev/), which offers tutorials, -samples, guidance on mobile development, and a full API reference. diff --git a/mnemo_cards/analysis_options.yaml b/mnemo_cards/analysis_options.yaml deleted file mode 100644 index 0cdae21..0000000 --- a/mnemo_cards/analysis_options.yaml +++ /dev/null @@ -1,9 +0,0 @@ -analyzer: - errors: - todo: info # чтобы отображать тудушки -# unused_import: error # Лишние импорты в проекте не нужны -# unused_local_variable: error # Неиспользуемые переменные в проекте не нужны -# missing_required_param: error # Не пропускаем обязательные параметры -# prefer_relative_imports: error # Относительные импорты в проекте -# directives_ordering: error # Следим за порядком импортов в проекте - unawaited_futures: error # Всегда резолвим Future \ No newline at end of file diff --git a/mnemo_cards/android/.gitignore b/mnemo_cards/android/.gitignore deleted file mode 100644 index 6f56801..0000000 --- a/mnemo_cards/android/.gitignore +++ /dev/null @@ -1,13 +0,0 @@ -gradle-wrapper.jar -/.gradle -/captures/ -/gradlew -/gradlew.bat -/local.properties -GeneratedPluginRegistrant.java - -# Remember to never publicly share your keystore. -# See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app -key.properties -**/*.keystore -**/*.jks diff --git a/mnemo_cards/android/app/build.gradle b/mnemo_cards/android/app/build.gradle deleted file mode 100644 index c881477..0000000 --- a/mnemo_cards/android/app/build.gradle +++ /dev/null @@ -1,92 +0,0 @@ -plugins { - id "com.android.application" - // START: FlutterFire Configuration - id 'com.google.gms.google-services' - id 'com.google.firebase.crashlytics' - // END: FlutterFire Configuration - id "kotlin-android" - // The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins. - id "dev.flutter.flutter-gradle-plugin" -} - -def localProperties = new Properties() -def localPropertiesFile = rootProject.file("local.properties") -if (localPropertiesFile.exists()) { - localPropertiesFile.withReader("UTF-8") { reader -> - localProperties.load(reader) - } -} - -def flutterVersionCode = localProperties.getProperty("flutter.versionCode") -if (flutterVersionCode == null) { - flutterVersionCode = "1" -} - -def flutterVersionName = localProperties.getProperty("flutter.versionName") -if (flutterVersionName == null) { - flutterVersionName = "1.0" -} - -def keystoreProperties = new Properties() -def keystorePropertiesFile = rootProject.file('key.properties') -if (keystorePropertiesFile.exists()) { - keystoreProperties.load(new FileInputStream(keystorePropertiesFile)) -} - -android { - namespace = "com.cinnabarflower.mnemo_cards" - compileSdk = flutter.compileSdkVersion - ndkVersion = flutter.ndkVersion - - compileOptions { - coreLibraryDesugaringEnabled true - sourceCompatibility = JavaVersion.VERSION_17 - targetCompatibility = JavaVersion.VERSION_17 - } - - kotlinOptions { - jvmTarget = "17" - } - - defaultConfig { - applicationId = "com.cinnabarflower.mnemo_cards" - // You can update the following values to match your application needs. - // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration. - minSdk = 25 - targetSdk = flutter.targetSdkVersion - versionCode = flutterVersionCode.toInteger() - versionName = flutterVersionName - } - - signingConfigs { - release { - keyAlias keystoreProperties['keyAlias'] - keyPassword keystoreProperties['keyPassword'] - storeFile keystoreProperties['storeFile'] ? file(keystoreProperties['storeFile']) : null - storePassword keystoreProperties['storePassword'] - } - debug { - keyAlias keystoreProperties['keyAlias'] - keyPassword keystoreProperties['keyPassword'] - storeFile keystoreProperties['storeFile'] ? file(keystoreProperties['storeFile']) : null - storePassword keystoreProperties['storePassword'] - } - } - - buildTypes { - release { - signingConfig signingConfigs.release - } - debug { - signingConfig signingConfigs.release - } - } -} - -dependencies { - coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.1.4' -} - -flutter { - source = "../.." -} diff --git a/mnemo_cards/android/app/google-services.json b/mnemo_cards/android/app/google-services.json deleted file mode 100644 index 1b69ccc..0000000 --- a/mnemo_cards/android/app/google-services.json +++ /dev/null @@ -1,70 +0,0 @@ -{ - "project_info": { - "project_number": "701767851968", - "project_id": "mnemo-cards", - "storage_bucket": "mnemo-cards.appspot.com" - }, - "client": [ - { - "client_info": { - "mobilesdk_app_id": "1:701767851968:android:6190df55346394732f7225", - "android_client_info": { - "package_name": "com.cinnabarflower.mnemo_cards" - } - }, - "oauth_client": [ - { - "client_id": "701767851968-3jgootslus3ie76t682j4v7glletloud.apps.googleusercontent.com", - "client_type": 1, - "android_info": { - "package_name": "com.cinnabarflower.mnemo_cards", - "certificate_hash": "6df4f259b9c53ac01472c17df69e8c91494f3947" - } - }, - { - "client_id": "701767851968-5e6v0b5humhj0iu22t21nb9dtgt4tjus.apps.googleusercontent.com", - "client_type": 1, - "android_info": { - "package_name": "com.cinnabarflower.mnemo_cards", - "certificate_hash": "49bb5b6863c9e6d8db43e7eb4d54796a300d87fe" - } - }, - { - "client_id": "701767851968-vqvjgf1u79jg924inm25bfuv4dg41t2u.apps.googleusercontent.com", - "client_type": 1, - "android_info": { - "package_name": "com.cinnabarflower.mnemo_cards", - "certificate_hash": "19f45c4abc59f7ce5f22e84376273ee1ee19bdc2" - } - }, - { - "client_id": "701767851968-bud97rud1d9qtqju96addn31nhm0oofu.apps.googleusercontent.com", - "client_type": 3 - } - ], - "api_key": [ - { - "current_key": "AIzaSyBGn7PVVDX-o7WipivtuBjdoH5nYEPsHms" - } - ], - "services": { - "appinvite_service": { - "other_platform_oauth_client": [ - { - "client_id": "701767851968-bud97rud1d9qtqju96addn31nhm0oofu.apps.googleusercontent.com", - "client_type": 3 - }, - { - "client_id": "701767851968-8dqcmk706p08gujqbl2m9s4sq1aljibs.apps.googleusercontent.com", - "client_type": 2, - "ios_info": { - "bundle_id": "com.cinnabarflower.mnemoCards" - } - } - ] - } - } - } - ], - "configuration_version": "1" -} \ No newline at end of file diff --git a/mnemo_cards/android/app/src/debug/AndroidManifest.xml b/mnemo_cards/android/app/src/debug/AndroidManifest.xml deleted file mode 100644 index 399f698..0000000 --- a/mnemo_cards/android/app/src/debug/AndroidManifest.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - diff --git a/mnemo_cards/android/app/src/main/AndroidManifest.xml b/mnemo_cards/android/app/src/main/AndroidManifest.xml deleted file mode 100644 index 12b6b3b..0000000 --- a/mnemo_cards/android/app/src/main/AndroidManifest.xml +++ /dev/null @@ -1,65 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/mnemo_cards/android/app/src/main/kotlin/com/cinnabarflower/mnemo_cards/MainActivity.kt b/mnemo_cards/android/app/src/main/kotlin/com/cinnabarflower/mnemo_cards/MainActivity.kt deleted file mode 100644 index 840a9e0..0000000 --- a/mnemo_cards/android/app/src/main/kotlin/com/cinnabarflower/mnemo_cards/MainActivity.kt +++ /dev/null @@ -1,5 +0,0 @@ -package com.cinnabarflower.mnemo_cards - -import io.flutter.embedding.android.FlutterActivity - -class MainActivity: FlutterActivity() diff --git a/mnemo_cards/android/app/src/main/res/drawable-hdpi/android12splash.png b/mnemo_cards/android/app/src/main/res/drawable-hdpi/android12splash.png deleted file mode 100644 index a950af6..0000000 Binary files a/mnemo_cards/android/app/src/main/res/drawable-hdpi/android12splash.png and /dev/null differ diff --git a/mnemo_cards/android/app/src/main/res/drawable-hdpi/splash.png b/mnemo_cards/android/app/src/main/res/drawable-hdpi/splash.png deleted file mode 100644 index a950af6..0000000 Binary files a/mnemo_cards/android/app/src/main/res/drawable-hdpi/splash.png and /dev/null differ diff --git a/mnemo_cards/android/app/src/main/res/drawable-mdpi/android12splash.png b/mnemo_cards/android/app/src/main/res/drawable-mdpi/android12splash.png deleted file mode 100644 index b8e69a5..0000000 Binary files a/mnemo_cards/android/app/src/main/res/drawable-mdpi/android12splash.png and /dev/null differ diff --git a/mnemo_cards/android/app/src/main/res/drawable-mdpi/splash.png b/mnemo_cards/android/app/src/main/res/drawable-mdpi/splash.png deleted file mode 100644 index b8e69a5..0000000 Binary files a/mnemo_cards/android/app/src/main/res/drawable-mdpi/splash.png and /dev/null differ diff --git a/mnemo_cards/android/app/src/main/res/drawable-night-hdpi/android12splash.png b/mnemo_cards/android/app/src/main/res/drawable-night-hdpi/android12splash.png deleted file mode 100644 index 01f4f03..0000000 Binary files a/mnemo_cards/android/app/src/main/res/drawable-night-hdpi/android12splash.png and /dev/null differ diff --git a/mnemo_cards/android/app/src/main/res/drawable-night-hdpi/splash.png b/mnemo_cards/android/app/src/main/res/drawable-night-hdpi/splash.png deleted file mode 100644 index 01f4f03..0000000 Binary files a/mnemo_cards/android/app/src/main/res/drawable-night-hdpi/splash.png and /dev/null differ diff --git a/mnemo_cards/android/app/src/main/res/drawable-night-mdpi/android12splash.png b/mnemo_cards/android/app/src/main/res/drawable-night-mdpi/android12splash.png deleted file mode 100644 index 53d7fdb..0000000 Binary files a/mnemo_cards/android/app/src/main/res/drawable-night-mdpi/android12splash.png and /dev/null differ diff --git a/mnemo_cards/android/app/src/main/res/drawable-night-mdpi/splash.png b/mnemo_cards/android/app/src/main/res/drawable-night-mdpi/splash.png deleted file mode 100644 index 53d7fdb..0000000 Binary files a/mnemo_cards/android/app/src/main/res/drawable-night-mdpi/splash.png and /dev/null differ diff --git a/mnemo_cards/android/app/src/main/res/drawable-night-v21/background.png b/mnemo_cards/android/app/src/main/res/drawable-night-v21/background.png deleted file mode 100644 index bb72a79..0000000 Binary files a/mnemo_cards/android/app/src/main/res/drawable-night-v21/background.png and /dev/null differ diff --git a/mnemo_cards/android/app/src/main/res/drawable-night-v21/launch_background.xml b/mnemo_cards/android/app/src/main/res/drawable-night-v21/launch_background.xml deleted file mode 100644 index 3cc4948..0000000 --- a/mnemo_cards/android/app/src/main/res/drawable-night-v21/launch_background.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/mnemo_cards/android/app/src/main/res/drawable-night-xhdpi/android12splash.png b/mnemo_cards/android/app/src/main/res/drawable-night-xhdpi/android12splash.png deleted file mode 100644 index 2b2d195..0000000 Binary files a/mnemo_cards/android/app/src/main/res/drawable-night-xhdpi/android12splash.png and /dev/null differ diff --git a/mnemo_cards/android/app/src/main/res/drawable-night-xhdpi/splash.png b/mnemo_cards/android/app/src/main/res/drawable-night-xhdpi/splash.png deleted file mode 100644 index 2b2d195..0000000 Binary files a/mnemo_cards/android/app/src/main/res/drawable-night-xhdpi/splash.png and /dev/null differ diff --git a/mnemo_cards/android/app/src/main/res/drawable-night-xxhdpi/android12splash.png b/mnemo_cards/android/app/src/main/res/drawable-night-xxhdpi/android12splash.png deleted file mode 100644 index 27c3f48..0000000 Binary files a/mnemo_cards/android/app/src/main/res/drawable-night-xxhdpi/android12splash.png and /dev/null differ diff --git a/mnemo_cards/android/app/src/main/res/drawable-night-xxhdpi/splash.png b/mnemo_cards/android/app/src/main/res/drawable-night-xxhdpi/splash.png deleted file mode 100644 index 27c3f48..0000000 Binary files a/mnemo_cards/android/app/src/main/res/drawable-night-xxhdpi/splash.png and /dev/null differ diff --git a/mnemo_cards/android/app/src/main/res/drawable-night-xxxhdpi/android12splash.png b/mnemo_cards/android/app/src/main/res/drawable-night-xxxhdpi/android12splash.png deleted file mode 100644 index 5d7087a..0000000 Binary files a/mnemo_cards/android/app/src/main/res/drawable-night-xxxhdpi/android12splash.png and /dev/null differ diff --git a/mnemo_cards/android/app/src/main/res/drawable-night-xxxhdpi/splash.png b/mnemo_cards/android/app/src/main/res/drawable-night-xxxhdpi/splash.png deleted file mode 100644 index 5d7087a..0000000 Binary files a/mnemo_cards/android/app/src/main/res/drawable-night-xxxhdpi/splash.png and /dev/null differ diff --git a/mnemo_cards/android/app/src/main/res/drawable-night/background.png b/mnemo_cards/android/app/src/main/res/drawable-night/background.png deleted file mode 100644 index bb72a79..0000000 Binary files a/mnemo_cards/android/app/src/main/res/drawable-night/background.png and /dev/null differ diff --git a/mnemo_cards/android/app/src/main/res/drawable-night/launch_background.xml b/mnemo_cards/android/app/src/main/res/drawable-night/launch_background.xml deleted file mode 100644 index 3cc4948..0000000 --- a/mnemo_cards/android/app/src/main/res/drawable-night/launch_background.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/mnemo_cards/android/app/src/main/res/drawable-v21/background.png b/mnemo_cards/android/app/src/main/res/drawable-v21/background.png deleted file mode 100644 index 3107d37..0000000 Binary files a/mnemo_cards/android/app/src/main/res/drawable-v21/background.png and /dev/null differ diff --git a/mnemo_cards/android/app/src/main/res/drawable-v21/launch_background.xml b/mnemo_cards/android/app/src/main/res/drawable-v21/launch_background.xml deleted file mode 100644 index 3cc4948..0000000 --- a/mnemo_cards/android/app/src/main/res/drawable-v21/launch_background.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/mnemo_cards/android/app/src/main/res/drawable-xhdpi/android12splash.png b/mnemo_cards/android/app/src/main/res/drawable-xhdpi/android12splash.png deleted file mode 100644 index aa97e95..0000000 Binary files a/mnemo_cards/android/app/src/main/res/drawable-xhdpi/android12splash.png and /dev/null differ diff --git a/mnemo_cards/android/app/src/main/res/drawable-xhdpi/splash.png b/mnemo_cards/android/app/src/main/res/drawable-xhdpi/splash.png deleted file mode 100644 index aa97e95..0000000 Binary files a/mnemo_cards/android/app/src/main/res/drawable-xhdpi/splash.png and /dev/null differ diff --git a/mnemo_cards/android/app/src/main/res/drawable-xxhdpi/android12splash.png b/mnemo_cards/android/app/src/main/res/drawable-xxhdpi/android12splash.png deleted file mode 100644 index 1d18d62..0000000 Binary files a/mnemo_cards/android/app/src/main/res/drawable-xxhdpi/android12splash.png and /dev/null differ diff --git a/mnemo_cards/android/app/src/main/res/drawable-xxhdpi/splash.png b/mnemo_cards/android/app/src/main/res/drawable-xxhdpi/splash.png deleted file mode 100644 index 1d18d62..0000000 Binary files a/mnemo_cards/android/app/src/main/res/drawable-xxhdpi/splash.png and /dev/null differ diff --git a/mnemo_cards/android/app/src/main/res/drawable-xxxhdpi/android12splash.png b/mnemo_cards/android/app/src/main/res/drawable-xxxhdpi/android12splash.png deleted file mode 100644 index 6a284fd..0000000 Binary files a/mnemo_cards/android/app/src/main/res/drawable-xxxhdpi/android12splash.png and /dev/null differ diff --git a/mnemo_cards/android/app/src/main/res/drawable-xxxhdpi/splash.png b/mnemo_cards/android/app/src/main/res/drawable-xxxhdpi/splash.png deleted file mode 100644 index 6a284fd..0000000 Binary files a/mnemo_cards/android/app/src/main/res/drawable-xxxhdpi/splash.png and /dev/null differ diff --git a/mnemo_cards/android/app/src/main/res/drawable/background.png b/mnemo_cards/android/app/src/main/res/drawable/background.png deleted file mode 100644 index 3107d37..0000000 Binary files a/mnemo_cards/android/app/src/main/res/drawable/background.png and /dev/null differ diff --git a/mnemo_cards/android/app/src/main/res/drawable/launch_background.xml b/mnemo_cards/android/app/src/main/res/drawable/launch_background.xml deleted file mode 100644 index 3cc4948..0000000 --- a/mnemo_cards/android/app/src/main/res/drawable/launch_background.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/mnemo_cards/android/app/src/main/res/mipmap-hdpi/launcher_icon.png b/mnemo_cards/android/app/src/main/res/mipmap-hdpi/launcher_icon.png deleted file mode 100644 index 6f591a2..0000000 Binary files a/mnemo_cards/android/app/src/main/res/mipmap-hdpi/launcher_icon.png and /dev/null differ diff --git a/mnemo_cards/android/app/src/main/res/mipmap-mdpi/launcher_icon.png b/mnemo_cards/android/app/src/main/res/mipmap-mdpi/launcher_icon.png deleted file mode 100644 index b725052..0000000 Binary files a/mnemo_cards/android/app/src/main/res/mipmap-mdpi/launcher_icon.png and /dev/null differ diff --git a/mnemo_cards/android/app/src/main/res/mipmap-xhdpi/launcher_icon.png b/mnemo_cards/android/app/src/main/res/mipmap-xhdpi/launcher_icon.png deleted file mode 100644 index 07bdd0c..0000000 Binary files a/mnemo_cards/android/app/src/main/res/mipmap-xhdpi/launcher_icon.png and /dev/null differ diff --git a/mnemo_cards/android/app/src/main/res/mipmap-xxhdpi/launcher_icon.png b/mnemo_cards/android/app/src/main/res/mipmap-xxhdpi/launcher_icon.png deleted file mode 100644 index e15861a..0000000 Binary files a/mnemo_cards/android/app/src/main/res/mipmap-xxhdpi/launcher_icon.png and /dev/null differ diff --git a/mnemo_cards/android/app/src/main/res/mipmap-xxxhdpi/launcher_icon.png b/mnemo_cards/android/app/src/main/res/mipmap-xxxhdpi/launcher_icon.png deleted file mode 100644 index 848e129..0000000 Binary files a/mnemo_cards/android/app/src/main/res/mipmap-xxxhdpi/launcher_icon.png and /dev/null differ diff --git a/mnemo_cards/android/app/src/main/res/values-night-v31/styles.xml b/mnemo_cards/android/app/src/main/res/values-night-v31/styles.xml deleted file mode 100644 index 09f904c..0000000 --- a/mnemo_cards/android/app/src/main/res/values-night-v31/styles.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - diff --git a/mnemo_cards/android/app/src/main/res/values-night/styles.xml b/mnemo_cards/android/app/src/main/res/values-night/styles.xml deleted file mode 100644 index dbc9ea9..0000000 --- a/mnemo_cards/android/app/src/main/res/values-night/styles.xml +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - diff --git a/mnemo_cards/android/app/src/main/res/values-v31/styles.xml b/mnemo_cards/android/app/src/main/res/values-v31/styles.xml deleted file mode 100644 index e437c38..0000000 --- a/mnemo_cards/android/app/src/main/res/values-v31/styles.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - diff --git a/mnemo_cards/android/app/src/main/res/values/styles.xml b/mnemo_cards/android/app/src/main/res/values/styles.xml deleted file mode 100644 index 0d1fa8f..0000000 --- a/mnemo_cards/android/app/src/main/res/values/styles.xml +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - diff --git a/mnemo_cards/android/app/src/main/res/xml/network_security_config.xml b/mnemo_cards/android/app/src/main/res/xml/network_security_config.xml deleted file mode 100644 index 8ec5168..0000000 --- a/mnemo_cards/android/app/src/main/res/xml/network_security_config.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/mnemo_cards/android/app/src/profile/AndroidManifest.xml b/mnemo_cards/android/app/src/profile/AndroidManifest.xml deleted file mode 100644 index 399f698..0000000 --- a/mnemo_cards/android/app/src/profile/AndroidManifest.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - diff --git a/mnemo_cards/android/build.gradle b/mnemo_cards/android/build.gradle deleted file mode 100644 index d2ffbff..0000000 --- a/mnemo_cards/android/build.gradle +++ /dev/null @@ -1,18 +0,0 @@ -allprojects { - repositories { - google() - mavenCentral() - } -} - -rootProject.buildDir = "../build" -subprojects { - project.buildDir = "${rootProject.buildDir}/${project.name}" -} -subprojects { - project.evaluationDependsOn(":app") -} - -tasks.register("clean", Delete) { - delete rootProject.buildDir -} diff --git a/mnemo_cards/android/gradle.properties b/mnemo_cards/android/gradle.properties deleted file mode 100644 index 3b5b324..0000000 --- a/mnemo_cards/android/gradle.properties +++ /dev/null @@ -1,3 +0,0 @@ -org.gradle.jvmargs=-Xmx4G -XX:+HeapDumpOnOutOfMemoryError -android.useAndroidX=true -android.enableJetifier=true diff --git a/mnemo_cards/android/gradle/wrapper/gradle-wrapper.properties b/mnemo_cards/android/gradle/wrapper/gradle-wrapper.properties deleted file mode 100644 index 5e6b542..0000000 --- a/mnemo_cards/android/gradle/wrapper/gradle-wrapper.properties +++ /dev/null @@ -1,5 +0,0 @@ -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-all.zip diff --git a/mnemo_cards/android/pepk.jar b/mnemo_cards/android/pepk.jar deleted file mode 100644 index 5ffdd4c..0000000 Binary files a/mnemo_cards/android/pepk.jar and /dev/null differ diff --git a/mnemo_cards/android/pepk_out.zip b/mnemo_cards/android/pepk_out.zip deleted file mode 100644 index 03ad643..0000000 Binary files a/mnemo_cards/android/pepk_out.zip and /dev/null differ diff --git a/mnemo_cards/android/settings.gradle b/mnemo_cards/android/settings.gradle deleted file mode 100644 index 8816418..0000000 --- a/mnemo_cards/android/settings.gradle +++ /dev/null @@ -1,43 +0,0 @@ -pluginManagement { - def flutterSdkPath = { - def properties = new Properties() - file("local.properties").withInputStream { properties.load(it) } - def flutterSdkPath = properties.getProperty("flutter.sdk") - assert flutterSdkPath != null, "flutter.sdk not set in local.properties" - return flutterSdkPath - }() - - includeBuild("$flutterSdkPath/packages/flutter_tools/gradle") - - repositories { - google() - mavenCentral() - gradlePluginPortal() - } - - // For yoo kassa - buildscript { - repositories { - mavenCentral() - maven { - url = uri("https://storage.googleapis.com/r8-releases/raw") - } - } - dependencies { - classpath("com.android.tools:r8:8.3.37") - } - } -} - -plugins { - id "dev.flutter.flutter-plugin-loader" version "1.0.0" - id "com.android.application" version "8.3.0" apply false - // START: FlutterFire Configuration - id "com.google.gms.google-services" version "4.4.2" apply false - id "com.google.firebase.crashlytics" version "2.9.9" apply false - - // END: FlutterFire Configuration - id "org.jetbrains.kotlin.android" version "2.1.0" apply false -} - -include ":app" diff --git a/mnemo_cards/android/upload_cert.pem b/mnemo_cards/android/upload_cert.pem deleted file mode 100644 index 9ab94a6..0000000 --- a/mnemo_cards/android/upload_cert.pem +++ /dev/null @@ -1,21 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIDfTCCAmWgAwIBAgIIKIPRK4QzqmcwDQYJKoZIhvcNAQEMBQAwbDEQMA4GA1UE -BhMHVW5rbm93bjEQMA4GA1UECBMHVW5rbm93bjEQMA4GA1UEBxMHVW5rbm93bjEQ -MA4GA1UEChMHVW5rbm93bjEQMA4GA1UECxMHVW5rbm93bjEQMA4GA1UEAxMHRG1p -dHJpaTAgFw0yMzExMTAxNTQwNDVaGA8yMDUxMDMyODE1NDA0NVowbDEQMA4GA1UE -BhMHVW5rbm93bjEQMA4GA1UECBMHVW5rbm93bjEQMA4GA1UEBxMHVW5rbm93bjEQ -MA4GA1UEChMHVW5rbm93bjEQMA4GA1UECxMHVW5rbm93bjEQMA4GA1UEAxMHRG1p -dHJpaTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALj52/fuR0JkoMzE -F0OerHwh65MBxLqsJfVL+lTeQVdwPMtzxp2lG7/TTFxzYEw57BgXBvzRbRg7P3RW -ti4Pm+v7G39h6/9GLVRMVBvt3rxNetfSNM8mBgUhnPaw5AFVD2wkzq8cW5QtTwQM -snLlNvsgT6tlNJ+VJR/dD69cHcXV9KLN6+GwJfseVQrxId9fYKMgTimqCZvM623x -Fp8rQMCFH00vX9M2eKwC+jSVNveEMuNrE/wC9dXL7qAJIdloZhW+T9fU+CamygXB -owKc9hRAXBm6TdYbfaNQx50kxlBRGQYasK9/wjGnr26IqUXTdES+xBa+gzayQaPt -5MES6ZECAwEAAaMhMB8wHQYDVR0OBBYEFJn16VE3tNxPHglEHGtlEMZCbGPsMA0G -CSqGSIb3DQEBDAUAA4IBAQCdBlikNsfbCvXChCTPa+mXP4BjmxDZNOdEnIV8a0gq -5ytOz0/FhOQa03MLZqYnT+lPkMrZJkWYBjehd2wQofsCCgscVvcl0g1Lf/lCe9/D -F9Uv16iJdT8o6thLHuskpzqU5p0inStMRd1Z664BMRA76PQxZeD1pN98oMUFPrYI -m2twIrR64mMt0zHUFLvGN3zzZAqXrBdwXsZnAoPnITcNlKLZyBOHzEoUkULyXn94 -vhaPek2h9xleXbo40ipvD7Ar6vaWrz9foIpKi8Ru+nOy3Noh2Hn1P7CA2rp4Tz4E -FsMi746InVwN38NelbILCK1HDm0ifjysn3xcAk0PMiW4 ------END CERTIFICATE----- diff --git a/mnemo_cards/build_app.sh b/mnemo_cards/build_app.sh deleted file mode 100644 index 2487f69..0000000 --- a/mnemo_cards/build_app.sh +++ /dev/null @@ -1,3 +0,0 @@ -set -e -v -cp ~/mnemo_cards/build/app/outputs/flutter-apk/app-arm64-v8a-release.apk ~/mnemo_cards_telegram_bot/apks/admin_app.apk - diff --git a/mnemo_cards/cerdo_1024x512.png b/mnemo_cards/cerdo_1024x512.png deleted file mode 100644 index d7f024a..0000000 Binary files a/mnemo_cards/cerdo_1024x512.png and /dev/null differ diff --git a/mnemo_cards/cerdo_512.png b/mnemo_cards/cerdo_512.png deleted file mode 100644 index 12a16b8..0000000 Binary files a/mnemo_cards/cerdo_512.png and /dev/null differ diff --git a/mnemo_cards/codegen.sh b/mnemo_cards/codegen.sh deleted file mode 100644 index 039619b..0000000 --- a/mnemo_cards/codegen.sh +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/bash -dart run build_runner build --delete-conflicting-outputs \ No newline at end of file diff --git a/mnemo_cards/coverage/lcov.info b/mnemo_cards/coverage/lcov.info deleted file mode 100644 index ad8de32..0000000 --- a/mnemo_cards/coverage/lcov.info +++ /dev/null @@ -1,7678 +0,0 @@ -SF:lib/main.dart -DA:39,0 -DA:40,3 -DA:43,0 -DA:44,0 -DA:46,4 -DA:50,0 -DA:57,0 -DA:68,0 -DA:70,0 -DA:71,0 -DA:75,0 -DA:76,0 -DA:79,0 -DA:80,0 -DA:81,0 -DA:82,0 -DA:83,0 -DA:84,0 -DA:86,0 -DA:87,0 -DA:88,0 -DA:89,0 -DA:92,0 -DA:93,0 -DA:95,0 -DA:100,0 -DA:101,0 -DA:105,0 -DA:108,0 -DA:110,0 -DA:111,0 -DA:112,0 -DA:114,0 -DA:115,0 -DA:117,0 -DA:118,0 -DA:119,0 -DA:121,0 -DA:122,0 -DA:123,0 -DA:125,0 -DA:126,0 -DA:127,0 -DA:129,0 -DA:130,0 -DA:131,0 -DA:133,0 -DA:134,0 -DA:135,0 -DA:137,0 -DA:138,0 -DA:140,0 -DA:141,0 -DA:143,0 -DA:144,0 -DA:145,0 -DA:148,0 -DA:149,0 -DA:150,0 -DA:152,0 -DA:153,0 -DA:156,0 -DA:157,0 -DA:159,0 -DA:160,0 -DA:161,0 -DA:162,0 -DA:163,0 -DA:165,0 -DA:166,0 -DA:167,0 -DA:168,0 -DA:172,0 -DA:173,0 -DA:174,0 -DA:176,0 -DA:177,0 -DA:179,0 -DA:180,0 -DA:182,0 -DA:186,0 -DA:187,0 -DA:188,0 -DA:189,0 -DA:191,0 -DA:193,0 -DA:195,0 -DA:197,0 -DA:199,0 -DA:201,0 -DA:203,0 -DA:205,0 -DA:207,0 -DA:210,0 -DA:211,0 -DA:212,0 -DA:216,0 -DA:218,0 -DA:219,0 -DA:221,0 -DA:222,0 -DA:223,0 -DA:224,0 -DA:225,0 -DA:226,0 -DA:227,0 -DA:234,0 -DA:235,0 -DA:236,0 -DA:238,0 -DA:239,0 -DA:240,0 -DA:242,0 -DA:245,0 -DA:248,0 -DA:251,0 -DA:253,0 -DA:259,0 -DA:261,0 -DA:265,0 -DA:267,0 -DA:268,0 -DA:269,0 -DA:271,0 -DA:272,0 -DA:274,0 -DA:275,0 -DA:283,1 -DA:285,1 -DA:287,2 -DA:288,1 -DA:292,1 -DA:293,1 -DA:294,1 -DA:295,1 -DA:296,1 -DA:298,2 -DA:299,1 -DA:303,1 -DA:307,1 -DA:312,0 -DA:315,0 -DA:316,0 -DA:318,0 -DA:319,0 -DA:321,0 -DA:322,0 -DA:324,0 -DA:326,0 -DA:334,1 -DA:336,0 -DA:337,0 -DA:351,0 -DA:353,0 -DA:354,0 -DA:357,0 -DA:359,0 -DA:360,0 -DA:361,0 -DA:362,0 -DA:363,0 -DA:366,0 -DA:369,0 -DA:370,0 -DA:371,0 -DA:372,0 -DA:373,0 -DA:378,0 -DA:379,0 -DA:380,0 -DA:385,0 -DA:387,0 -DA:390,0 -DA:391,0 -DA:392,0 -DA:396,0 -DA:397,0 -DA:400,0 -DA:402,0 -DA:403,0 -DA:406,0 -DA:407,0 -DA:408,0 -DA:409,0 -DA:410,0 -DA:415,0 -DA:421,0 -DA:429,0 -DA:432,0 -DA:439,0 -DA:443,0 -DA:445,0 -DA:447,0 -DA:456,0 -DA:457,0 -DA:458,0 -DA:459,0 -DA:461,0 -DA:463,0 -DA:464,0 -DA:466,0 -DA:471,0 -DA:472,0 -DA:473,0 -DA:474,0 -DA:476,0 -DA:482,0 -DA:483,0 -DA:484,0 -DA:486,0 -DA:488,0 -DA:489,0 -DA:490,0 -DA:491,0 -DA:492,0 -DA:493,0 -DA:494,0 -DA:496,0 -DA:497,0 -DA:501,0 -DA:502,0 -DA:504,0 -DA:505,0 -DA:508,0 -DA:509,0 -DA:510,0 -DA:511,0 -DA:513,0 -DA:514,0 -DA:516,0 -DA:517,0 -DA:518,0 -DA:519,0 -DA:520,0 -DA:521,0 -DA:523,0 -DA:525,0 -DA:527,0 -DA:529,0 -DA:530,0 -LF:240 -LH:16 -end_of_record -SF:lib/admin/add_card.dart -DA:20,0 -DA:35,0 -DA:36,0 -DA:37,0 -DA:38,0 -DA:39,0 -DA:41,0 -DA:43,0 -DA:44,0 -DA:46,0 -DA:51,0 -DA:53,0 -DA:55,0 -DA:57,0 -DA:58,0 -DA:59,0 -DA:61,0 -DA:62,0 -DA:63,0 -DA:64,0 -DA:68,0 -DA:69,0 -DA:71,0 -DA:72,0 -DA:73,0 -DA:75,0 -DA:76,0 -DA:77,0 -DA:78,0 -DA:82,0 -DA:83,0 -DA:85,0 -DA:86,0 -DA:88,0 -DA:89,0 -DA:91,0 -DA:92,0 -DA:95,0 -DA:96,0 -DA:97,0 -DA:99,0 -DA:100,0 -DA:103,0 -DA:105,0 -DA:106,0 -DA:107,0 -DA:108,0 -DA:109,0 -DA:110,0 -DA:111,0 -DA:112,0 -DA:114,0 -DA:115,0 -DA:116,0 -DA:117,0 -DA:118,0 -DA:120,0 -DA:121,0 -DA:122,0 -DA:123,0 -DA:128,0 -DA:129,0 -DA:130,0 -DA:132,0 -DA:133,0 -DA:134,0 -DA:135,0 -DA:138,0 -DA:139,0 -DA:140,0 -DA:141,0 -DA:143,0 -DA:144,0 -DA:148,0 -DA:152,0 -DA:154,0 -DA:157,0 -DA:159,0 -DA:160,0 -DA:164,0 -DA:168,0 -DA:169,0 -DA:170,0 -DA:172,0 -DA:175,0 -DA:176,0 -DA:177,0 -DA:178,0 -DA:180,0 -DA:181,0 -DA:182,0 -DA:184,0 -DA:188,0 -DA:189,0 -DA:191,0 -DA:192,0 -DA:194,0 -DA:195,0 -DA:199,0 -DA:200,0 -DA:201,0 -DA:204,0 -DA:205,0 -DA:206,0 -DA:210,0 -DA:214,0 -DA:215,0 -DA:217,0 -DA:218,0 -DA:220,0 -DA:221,0 -DA:229,0 -DA:230,0 -DA:232,0 -DA:233,0 -DA:234,0 -DA:236,0 -DA:238,0 -DA:239,0 -DA:240,0 -DA:241,0 -DA:242,0 -DA:243,0 -DA:246,0 -DA:250,0 -DA:252,0 -DA:253,0 -DA:256,0 -DA:261,0 -DA:262,0 -DA:263,0 -DA:264,0 -DA:265,0 -DA:266,0 -DA:267,0 -DA:273,0 -DA:276,0 -DA:277,0 -DA:278,0 -DA:279,0 -DA:280,0 -DA:282,0 -DA:289,0 -DA:291,0 -DA:292,0 -DA:296,0 -DA:300,0 -DA:301,0 -DA:304,0 -DA:306,0 -DA:307,0 -DA:309,0 -DA:313,0 -DA:314,0 -LF:154 -LH:0 -end_of_record -SF:lib/domain/router/dialogs.dart -DA:10,0 -DA:16,0 -DA:17,0 -DA:18,0 -DA:21,0 -DA:22,0 -DA:23,0 -DA:25,0 -DA:26,0 -DA:27,0 -DA:28,0 -DA:29,0 -DA:30,0 -DA:31,0 -DA:32,0 -DA:33,0 -DA:36,0 -DA:38,0 -DA:40,0 -DA:41,0 -DA:42,0 -DA:43,0 -DA:46,0 -DA:47,0 -DA:48,0 -DA:51,0 -DA:53,0 -DA:54,0 -DA:57,0 -DA:58,0 -DA:59,0 -DA:60,0 -DA:64,0 -DA:65,0 -DA:69,0 -DA:74,0 -DA:75,0 -DA:76,0 -DA:77,0 -DA:78,0 -DA:80,0 -DA:81,0 -DA:84,0 -DA:87,0 -DA:98,0 -DA:100,0 -DA:103,0 -DA:105,0 -DA:106,0 -LF:49 -LH:0 -end_of_record -SF:lib/managers/repository/api.dart -DA:7,0 -DA:9,0 -DA:12,0 -LF:3 -LH:0 -end_of_record -SF:lib/admin/admin_api.dart -DA:15,0 -DA:17,0 -DA:21,0 -DA:22,0 -DA:23,0 -DA:24,0 -DA:25,0 -DA:26,0 -DA:27,0 -DA:29,0 -DA:30,0 -DA:31,0 -DA:34,0 -DA:37,0 -DA:38,0 -DA:39,0 -DA:40,0 -DA:42,0 -DA:45,0 -DA:46,0 -DA:47,0 -DA:50,0 -DA:51,0 -DA:52,0 -DA:53,0 -DA:55,0 -DA:58,0 -DA:59,0 -DA:60,0 -DA:61,0 -DA:63,0 -DA:64,0 -DA:65,0 -DA:66,0 -DA:69,0 -DA:70,0 -DA:71,0 -DA:74,0 -DA:75,0 -DA:76,0 -DA:77,0 -DA:79,0 -DA:80,0 -DA:81,0 -DA:82,0 -DA:85,0 -DA:86,0 -DA:87,0 -DA:88,0 -DA:90,0 -DA:93,0 -DA:94,0 -DA:95,0 -DA:96,0 -DA:98,0 -DA:101,0 -DA:102,0 -DA:103,0 -DA:106,0 -DA:107,0 -DA:108,0 -DA:109,0 -DA:111,0 -DA:114,0 -DA:115,0 -DA:116,0 -DA:117,0 -DA:119,0 -DA:122,0 -DA:123,0 -DA:125,0 -DA:126,0 -DA:127,0 -DA:128,0 -DA:129,0 -DA:130,0 -DA:133,0 -DA:134,0 -DA:135,0 -DA:136,0 -DA:138,0 -DA:141,0 -DA:142,0 -DA:143,0 -DA:146,0 -DA:147,0 -DA:148,0 -DA:151,0 -DA:152,0 -DA:153,0 -DA:154,0 -DA:156,0 -DA:159,0 -DA:160,0 -DA:161,0 -DA:162,0 -DA:163,0 -DA:164,0 -DA:167,0 -DA:168,0 -DA:169,0 -DA:172,0 -DA:173,0 -DA:174,0 -DA:175,0 -DA:177,0 -DA:180,0 -DA:181,0 -DA:182,0 -DA:183,0 -DA:184,0 -DA:185,0 -DA:188,0 -DA:190,0 -DA:191,0 -DA:193,0 -LF:116 -LH:0 -end_of_record -SF:lib/admin/add_discount_campaign.dart -DA:22,0 -DA:23,0 -DA:24,0 -DA:27,0 -DA:28,0 -DA:29,0 -DA:30,0 -DA:32,0 -DA:35,0 -DA:36,0 -DA:40,0 -DA:42,0 -DA:44,0 -DA:45,0 -DA:51,0 -DA:52,0 -DA:53,0 -DA:54,0 -DA:57,0 -DA:59,0 -DA:60,0 -DA:63,0 -DA:64,0 -DA:66,0 -DA:70,0 -DA:71,0 -DA:73,0 -DA:75,0 -DA:76,0 -DA:79,0 -DA:80,0 -DA:82,0 -DA:86,0 -DA:87,0 -DA:89,0 -DA:90,0 -DA:91,0 -DA:92,0 -DA:93,0 -DA:94,0 -DA:95,0 -DA:96,0 -DA:100,0 -DA:101,0 -DA:102,0 -DA:103,0 -DA:104,0 -DA:105,0 -DA:106,0 -DA:107,0 -DA:109,0 -DA:110,0 -DA:111,0 -DA:112,0 -DA:113,0 -DA:115,0 -DA:116,0 -DA:117,0 -DA:118,0 -DA:119,0 -DA:120,0 -DA:122,0 -DA:124,0 -DA:125,0 -DA:126,0 -DA:127,0 -DA:132,0 -DA:134,0 -DA:135,0 -DA:136,0 -DA:137,0 -DA:138,0 -DA:142,0 -DA:143,0 -DA:144,0 -DA:145,0 -DA:146,0 -DA:147,0 -DA:150,0 -DA:152,0 -DA:154,0 -DA:155,0 -DA:156,0 -DA:157,0 -DA:158,0 -DA:159,0 -DA:161,0 -DA:162,0 -DA:163,0 -DA:168,0 -DA:170,0 -DA:171,0 -DA:172,0 -DA:173,0 -DA:174,0 -DA:178,0 -DA:180,0 -DA:181,0 -DA:182,0 -DA:183,0 -DA:184,0 -DA:188,0 -DA:191,0 -DA:192,0 -DA:193,0 -DA:194,0 -DA:197,0 -DA:201,0 -DA:203,0 -DA:204,0 -DA:207,0 -DA:208,0 -DA:209,0 -DA:210,0 -DA:211,0 -DA:212,0 -DA:213,0 -DA:214,0 -DA:216,0 -DA:219,0 -DA:220,0 -DA:221,0 -DA:222,0 -DA:223,0 -DA:224,0 -DA:226,0 -DA:227,0 -DA:229,0 -DA:230,0 -DA:238,0 -DA:239,0 -DA:240,0 -DA:241,0 -DA:242,0 -DA:243,0 -DA:248,0 -DA:249,0 -DA:253,0 -DA:254,0 -DA:255,0 -DA:256,0 -DA:257,0 -DA:258,0 -DA:279,0 -DA:283,0 -DA:284,0 -DA:286,0 -DA:287,0 -DA:289,0 -DA:290,0 -DA:291,0 -DA:292,0 -DA:293,0 -DA:294,0 -DA:295,0 -DA:296,0 -DA:297,0 -DA:298,0 -DA:300,0 -DA:303,0 -DA:304,0 -DA:305,0 -DA:307,0 -DA:308,0 -DA:309,0 -DA:311,0 -DA:312,0 -DA:313,0 -DA:317,0 -DA:318,0 -DA:319,0 -DA:320,0 -DA:322,0 -DA:323,0 -DA:325,0 -DA:326,0 -DA:327,0 -DA:328,0 -DA:332,0 -DA:334,0 -DA:335,0 -DA:339,0 -DA:342,0 -DA:343,0 -DA:344,0 -DA:345,0 -DA:346,0 -DA:347,0 -DA:354,0 -DA:355,0 -DA:356,0 -DA:358,0 -DA:371,0 -DA:372,0 -DA:373,0 -DA:374,0 -DA:375,0 -DA:377,0 -DA:379,0 -DA:381,0 -LF:200 -LH:0 -end_of_record -SF:lib/di/injector.dart -DA:37,0 -DA:39,0 -DA:40,0 -DA:41,0 -DA:42,0 -DA:44,0 -DA:45,0 -DA:47,0 -DA:49,0 -DA:50,0 -DA:52,0 -DA:54,0 -DA:55,0 -DA:58,0 -DA:59,0 -DA:62,0 -DA:63,0 -DA:66,0 -DA:68,0 -DA:69,0 -DA:72,0 -DA:73,0 -DA:74,0 -DA:75,0 -DA:78,0 -DA:80,0 -DA:81,0 -DA:83,0 -DA:85,0 -DA:86,0 -DA:88,0 -DA:90,0 -DA:91,0 -DA:93,0 -DA:95,0 -DA:96,0 -DA:98,0 -DA:100,0 -DA:101,0 -DA:102,0 -DA:103,0 -DA:106,0 -DA:108,0 -DA:109,0 -DA:110,0 -DA:111,0 -DA:112,0 -DA:115,0 -DA:117,0 -DA:118,0 -DA:119,0 -DA:120,0 -DA:121,0 -DA:124,0 -DA:126,0 -DA:127,0 -DA:128,0 -DA:129,0 -DA:130,0 -DA:131,0 -DA:132,0 -DA:135,0 -DA:137,0 -DA:138,0 -DA:139,0 -DA:142,0 -DA:144,0 -DA:145,0 -DA:147,0 -DA:149,0 -DA:150,0 -DA:153,0 -DA:154,0 -DA:155,0 -DA:156,0 -DA:157,0 -DA:160,0 -DA:162,0 -DA:163,0 -DA:165,0 -DA:167,0 -DA:168,0 -DA:171,0 -DA:172,0 -DA:175,0 -DA:176,0 -DA:177,0 -DA:178,0 -DA:182,0 -DA:183,0 -DA:184,0 -DA:185,0 -DA:186,0 -DA:187,0 -DA:188,0 -DA:194,0 -DA:195,0 -DA:197,0 -LF:98 -LH:0 -end_of_record -SF:lib/admin/date_param.dart -DA:10,0 -DA:12,0 -DA:14,0 -DA:16,0 -DA:17,0 -DA:18,0 -DA:19,0 -DA:22,0 -DA:23,0 -DA:24,0 -DA:25,0 -DA:26,0 -DA:27,0 -DA:29,0 -DA:31,0 -DA:32,0 -DA:35,0 -DA:36,0 -DA:37,0 -DA:38,0 -DA:41,0 -DA:43,0 -DA:44,0 -DA:47,0 -DA:48,0 -DA:49,0 -DA:50,0 -DA:51,0 -DA:52,0 -DA:61,0 -DA:63,0 -DA:64,0 -DA:65,0 -DA:66,0 -LF:34 -LH:0 -end_of_record -SF:lib/admin/enum_param.dart -DA:12,0 -DA:21,0 -DA:23,0 -DA:25,0 -DA:26,0 -DA:28,0 -DA:29,0 -DA:30,0 -DA:33,0 -DA:34,0 -DA:35,0 -DA:36,0 -DA:37,0 -DA:38,0 -DA:42,0 -DA:45,0 -DA:46,0 -DA:47,0 -DA:49,0 -DA:50,0 -DA:51,0 -DA:52,0 -DA:56,0 -DA:57,0 -DA:59,0 -LF:25 -LH:0 -end_of_record -SF:lib/admin/int_param.dart -DA:9,0 -DA:11,0 -DA:13,0 -DA:15,0 -DA:16,0 -DA:17,0 -DA:18,0 -DA:21,0 -DA:22,0 -DA:24,0 -DA:25,0 -LF:11 -LH:0 -end_of_record -SF:lib/admin/text_param.dart -DA:10,0 -DA:12,0 -DA:14,0 -DA:16,0 -DA:17,0 -DA:18,0 -DA:21,0 -DA:22,0 -DA:23,0 -DA:24,0 -DA:25,0 -DA:26,0 -DA:30,0 -DA:33,0 -DA:34,0 -DA:35,0 -DA:36,0 -LF:17 -LH:0 -end_of_record -SF:lib/admin/add_package.dart -DA:21,0 -DA:22,0 -DA:24,0 -DA:25,0 -DA:26,0 -DA:27,0 -DA:28,0 -DA:31,0 -DA:32,0 -DA:34,0 -DA:35,0 -DA:36,0 -DA:39,0 -DA:40,0 -DA:46,0 -DA:48,0 -DA:49,0 -DA:52,0 -DA:53,0 -DA:55,0 -DA:59,0 -DA:60,0 -DA:62,0 -DA:63,0 -DA:66,0 -DA:67,0 -DA:69,0 -DA:73,0 -DA:74,0 -DA:76,0 -DA:77,0 -DA:78,0 -DA:79,0 -DA:81,0 -DA:82,0 -DA:83,0 -DA:84,0 -DA:86,0 -DA:87,0 -DA:88,0 -DA:89,0 -DA:90,0 -DA:92,0 -DA:93,0 -DA:94,0 -DA:95,0 -DA:100,0 -DA:102,0 -DA:103,0 -DA:104,0 -DA:107,0 -DA:109,0 -DA:110,0 -DA:111,0 -DA:114,0 -DA:116,0 -DA:117,0 -DA:119,0 -DA:121,0 -DA:122,0 -DA:123,0 -DA:124,0 -DA:128,0 -DA:130,0 -DA:131,0 -DA:132,0 -DA:135,0 -DA:137,0 -DA:138,0 -DA:139,0 -DA:142,0 -DA:144,0 -DA:145,0 -DA:146,0 -DA:149,0 -DA:151,0 -DA:152,0 -DA:153,0 -DA:156,0 -DA:157,0 -DA:158,0 -DA:159,0 -DA:160,0 -DA:161,0 -DA:162,0 -DA:163,0 -DA:164,0 -DA:170,0 -DA:171,0 -DA:172,0 -DA:173,0 -DA:174,0 -DA:175,0 -DA:176,0 -DA:177,0 -DA:178,0 -DA:179,0 -DA:184,0 -DA:185,0 -DA:188,0 -DA:190,0 -DA:192,0 -DA:193,0 -DA:195,0 -DA:196,0 -DA:202,0 -DA:203,0 -DA:204,0 -DA:205,0 -DA:206,0 -DA:207,0 -DA:209,0 -DA:210,0 -DA:211,0 -DA:212,0 -DA:213,0 -DA:214,0 -DA:217,0 -DA:221,0 -DA:223,0 -DA:224,0 -DA:227,0 -DA:232,0 -DA:233,0 -DA:234,0 -DA:235,0 -DA:236,0 -DA:237,0 -DA:241,0 -DA:244,0 -DA:245,0 -DA:246,0 -DA:249,0 -DA:251,0 -DA:258,0 -DA:260,0 -DA:261,0 -DA:263,0 -DA:264,0 -DA:265,0 -DA:266,0 -DA:269,0 -DA:271,0 -DA:272,0 -DA:273,0 -DA:274,0 -DA:278,0 -DA:280,0 -DA:281,0 -DA:283,0 -DA:284,0 -DA:285,0 -DA:286,0 -DA:287,0 -LF:154 -LH:0 -end_of_record -SF:lib/utils/string_helper.dart -DA:13,0 -DA:14,0 -DA:16,0 -DA:17,0 -DA:18,0 -DA:20,0 -DA:21,0 -DA:22,0 -DA:24,0 -DA:27,0 -DA:28,0 -DA:31,0 -DA:36,0 -DA:37,0 -DA:38,0 -DA:39,0 -DA:40,0 -DA:42,0 -DA:43,0 -DA:44,0 -DA:45,0 -DA:46,0 -DA:48,0 -DA:49,0 -DA:50,0 -DA:52,0 -DA:53,0 -DA:54,0 -DA:56,0 -DA:57,0 -DA:58,0 -DA:59,0 -DA:60,0 -DA:63,0 -DA:64,0 -DA:65,0 -DA:67,0 -DA:70,0 -DA:71,0 -DA:72,0 -DA:77,0 -LF:41 -LH:0 -end_of_record -SF:lib/admin/add_plan.dart -DA:22,0 -DA:23,0 -DA:24,0 -DA:27,0 -DA:28,0 -DA:43,0 -DA:46,0 -DA:47,0 -DA:48,0 -DA:52,0 -DA:53,0 -DA:54,0 -DA:55,0 -DA:59,0 -DA:60,0 -DA:63,0 -DA:64,0 -DA:66,0 -DA:70,0 -DA:71,0 -DA:72,0 -DA:74,0 -DA:75,0 -DA:78,0 -DA:79,0 -DA:81,0 -DA:85,0 -DA:86,0 -DA:88,0 -DA:89,0 -DA:90,0 -DA:91,0 -DA:92,0 -DA:93,0 -DA:94,0 -DA:95,0 -DA:99,0 -DA:100,0 -DA:101,0 -DA:102,0 -DA:103,0 -DA:104,0 -DA:105,0 -DA:106,0 -DA:108,0 -DA:109,0 -DA:110,0 -DA:111,0 -DA:112,0 -DA:113,0 -DA:115,0 -DA:117,0 -DA:118,0 -DA:119,0 -DA:121,0 -DA:122,0 -DA:123,0 -DA:124,0 -DA:125,0 -DA:127,0 -DA:129,0 -DA:130,0 -DA:131,0 -DA:132,0 -DA:137,0 -DA:139,0 -DA:140,0 -DA:141,0 -DA:142,0 -DA:143,0 -DA:147,0 -DA:148,0 -DA:149,0 -DA:150,0 -DA:151,0 -DA:152,0 -DA:155,0 -DA:157,0 -DA:159,0 -DA:160,0 -DA:162,0 -DA:163,0 -DA:164,0 -DA:165,0 -DA:169,0 -DA:170,0 -DA:171,0 -DA:172,0 -DA:174,0 -DA:175,0 -DA:176,0 -DA:180,0 -DA:182,0 -DA:183,0 -DA:184,0 -DA:185,0 -DA:188,0 -DA:190,0 -DA:191,0 -DA:192,0 -DA:193,0 -DA:198,0 -DA:199,0 -DA:202,0 -DA:203,0 -DA:205,0 -DA:206,0 -DA:207,0 -DA:208,0 -DA:209,0 -DA:210,0 -DA:211,0 -DA:212,0 -DA:213,0 -DA:215,0 -DA:216,0 -DA:220,0 -DA:221,0 -DA:223,0 -DA:227,0 -DA:228,0 -DA:230,0 -DA:231,0 -DA:232,0 -DA:235,0 -DA:236,0 -DA:239,0 -DA:241,0 -DA:242,0 -DA:243,0 -DA:246,0 -DA:247,0 -DA:250,0 -DA:252,0 -DA:253,0 -DA:254,0 -DA:257,0 -DA:258,0 -DA:261,0 -DA:263,0 -DA:264,0 -DA:265,0 -DA:268,0 -DA:269,0 -DA:272,0 -DA:274,0 -DA:275,0 -DA:276,0 -DA:279,0 -DA:280,0 -DA:283,0 -DA:285,0 -DA:286,0 -DA:287,0 -DA:290,0 -DA:291,0 -DA:294,0 -DA:296,0 -DA:297,0 -DA:298,0 -DA:301,0 -DA:302,0 -DA:305,0 -DA:307,0 -DA:308,0 -DA:309,0 -DA:312,0 -DA:313,0 -DA:316,0 -DA:319,0 -DA:320,0 -DA:321,0 -DA:322,0 -DA:323,0 -DA:324,0 -DA:326,0 -DA:328,0 -DA:329,0 -DA:332,0 -DA:333,0 -DA:334,0 -DA:335,0 -DA:336,0 -DA:340,0 -DA:341,0 -DA:342,0 -DA:343,0 -DA:344,0 -DA:357,0 -DA:359,0 -DA:360,0 -DA:361,0 -DA:384,0 -DA:385,0 -DA:386,0 -LF:195 -LH:0 -end_of_record -SF:lib/admin/add_promocode_campaign.dart -DA:31,0 -DA:32,0 -DA:33,0 -DA:36,0 -DA:37,0 -DA:38,0 -DA:39,0 -DA:40,0 -DA:45,0 -DA:49,0 -DA:53,0 -DA:55,0 -DA:57,0 -DA:58,0 -DA:64,0 -DA:66,0 -DA:68,0 -DA:69,0 -DA:70,0 -DA:73,0 -DA:74,0 -DA:80,0 -DA:81,0 -DA:83,0 -DA:84,0 -DA:87,0 -DA:88,0 -DA:90,0 -DA:94,0 -DA:95,0 -DA:97,0 -DA:99,0 -DA:100,0 -DA:103,0 -DA:104,0 -DA:106,0 -DA:110,0 -DA:111,0 -DA:113,0 -DA:114,0 -DA:115,0 -DA:116,0 -DA:117,0 -DA:118,0 -DA:119,0 -DA:120,0 -DA:124,0 -DA:125,0 -DA:126,0 -DA:127,0 -DA:128,0 -DA:130,0 -DA:131,0 -DA:132,0 -DA:133,0 -DA:135,0 -DA:136,0 -DA:137,0 -DA:138,0 -DA:139,0 -DA:140,0 -DA:141,0 -DA:143,0 -DA:145,0 -DA:147,0 -DA:148,0 -DA:149,0 -DA:151,0 -DA:152,0 -DA:153,0 -DA:154,0 -DA:155,0 -DA:156,0 -DA:158,0 -DA:160,0 -DA:161,0 -DA:162,0 -DA:163,0 -DA:168,0 -DA:170,0 -DA:171,0 -DA:172,0 -DA:173,0 -DA:174,0 -DA:178,0 -DA:179,0 -DA:180,0 -DA:181,0 -DA:182,0 -DA:183,0 -DA:186,0 -DA:188,0 -DA:190,0 -DA:191,0 -DA:192,0 -DA:193,0 -DA:194,0 -DA:195,0 -DA:197,0 -DA:198,0 -DA:199,0 -DA:204,0 -DA:206,0 -DA:207,0 -DA:208,0 -DA:215,0 -DA:217,0 -DA:218,0 -DA:219,0 -DA:223,0 -DA:225,0 -DA:226,0 -DA:227,0 -DA:232,0 -DA:234,0 -DA:235,0 -DA:236,0 -DA:241,0 -DA:243,0 -DA:244,0 -DA:245,0 -DA:246,0 -DA:247,0 -DA:251,0 -DA:253,0 -DA:254,0 -DA:255,0 -DA:256,0 -DA:257,0 -DA:261,0 -DA:264,0 -DA:265,0 -DA:266,0 -DA:267,0 -DA:270,0 -DA:274,0 -DA:276,0 -DA:277,0 -DA:280,0 -DA:281,0 -DA:282,0 -DA:283,0 -DA:284,0 -DA:285,0 -DA:286,0 -DA:288,0 -DA:291,0 -DA:292,0 -DA:299,0 -DA:300,0 -DA:301,0 -DA:302,0 -DA:303,0 -DA:304,0 -DA:309,0 -DA:310,0 -DA:314,0 -DA:315,0 -DA:316,0 -DA:317,0 -DA:318,0 -DA:319,0 -DA:326,0 -DA:329,0 -DA:330,0 -DA:332,0 -DA:333,0 -DA:334,0 -DA:354,0 -DA:358,0 -DA:359,0 -DA:361,0 -DA:362,0 -DA:364,0 -DA:365,0 -DA:367,0 -DA:368,0 -DA:369,0 -DA:371,0 -DA:374,0 -DA:375,0 -DA:376,0 -DA:379,0 -DA:380,0 -DA:381,0 -DA:383,0 -DA:394,0 -DA:395,0 -DA:396,0 -LF:189 -LH:0 -end_of_record -SF:lib/admin/add_user.dart -DA:17,0 -DA:19,0 -DA:20,0 -DA:21,0 -DA:23,0 -DA:24,0 -DA:27,0 -DA:28,0 -DA:30,0 -DA:34,0 -DA:35,0 -DA:37,0 -DA:38,0 -DA:41,0 -DA:42,0 -DA:44,0 -DA:48,0 -DA:49,0 -DA:52,0 -DA:55,0 -DA:57,0 -DA:59,0 -DA:60,0 -DA:61,0 -DA:62,0 -DA:63,0 -DA:64,0 -DA:65,0 -DA:66,0 -DA:68,0 -DA:69,0 -DA:70,0 -DA:71,0 -DA:72,0 -DA:74,0 -DA:75,0 -DA:76,0 -DA:77,0 -DA:82,0 -DA:83,0 -DA:84,0 -DA:85,0 -DA:86,0 -DA:87,0 -DA:88,0 -DA:89,0 -DA:90,0 -DA:91,0 -DA:94,0 -DA:96,0 -DA:97,0 -DA:99,0 -DA:100,0 -DA:102,0 -DA:104,0 -DA:105,0 -DA:108,0 -DA:109,0 -DA:110,0 -DA:111,0 -DA:112,0 -DA:113,0 -DA:114,0 -DA:115,0 -DA:116,0 -DA:117,0 -DA:123,0 -DA:125,0 -DA:127,0 -DA:128,0 -DA:129,0 -DA:130,0 -DA:131,0 -DA:132,0 -DA:133,0 -DA:134,0 -DA:135,0 -DA:136,0 -DA:139,0 -DA:141,0 -DA:142,0 -DA:149,0 -DA:150,0 -DA:151,0 -DA:153,0 -DA:154,0 -DA:156,0 -DA:157,0 -DA:172,0 -DA:174,0 -DA:176,0 -DA:177,0 -DA:179,0 -DA:180,0 -DA:182,0 -DA:184,0 -DA:186,0 -DA:187,0 -DA:190,0 -DA:191,0 -DA:193,0 -DA:194,0 -DA:196,0 -DA:198,0 -DA:199,0 -DA:201,0 -DA:202,0 -DA:203,0 -DA:204,0 -DA:205,0 -DA:206,0 -DA:209,0 -DA:210,0 -DA:211,0 -DA:212,0 -DA:213,0 -DA:218,0 -DA:226,0 -DA:227,0 -LF:119 -LH:0 -end_of_record -SF:lib/features/packs/packs_api.dart -DA:13,0 -DA:16,0 -DA:19,0 -DA:20,0 -DA:24,0 -DA:29,0 -DA:32,0 -DA:33,0 -DA:37,0 -DA:42,0 -DA:43,0 -DA:44,0 -DA:46,0 -DA:50,0 -DA:51,0 -DA:52,0 -DA:54,0 -DA:59,0 -DA:63,0 -DA:64,0 -DA:65,0 -DA:70,0 -DA:72,0 -LF:23 -LH:0 -end_of_record -SF:lib/features/worker/worker_ext.dart -DA:7,0 -DA:8,0 -DA:9,0 -DA:11,0 -DA:14,0 -DA:16,0 -DA:17,0 -DA:19,0 -DA:24,0 -DA:25,0 -DA:27,0 -LF:11 -LH:0 -end_of_record -SF:lib/admin/all_cards.dart -DA:19,0 -DA:20,0 -DA:22,1 -DA:26,0 -DA:27,0 -DA:29,0 -DA:32,0 -DA:33,0 -DA:35,0 -DA:37,0 -DA:39,0 -DA:41,0 -DA:42,0 -DA:43,0 -DA:44,0 -DA:45,0 -DA:47,0 -DA:48,0 -DA:49,0 -DA:50,0 -DA:52,0 -DA:53,0 -DA:54,0 -DA:56,0 -DA:57,0 -DA:59,0 -DA:64,0 -DA:65,0 -DA:66,0 -DA:69,0 -DA:70,0 -DA:71,0 -DA:74,0 -DA:76,0 -DA:77,0 -DA:81,0 -DA:84,0 -DA:87,0 -DA:88,0 -DA:90,0 -DA:91,0 -DA:94,0 -DA:95,0 -DA:97,0 -DA:98,0 -DA:102,0 -DA:104,0 -DA:105,0 -DA:107,0 -DA:109,0 -DA:112,0 -DA:115,0 -DA:117,0 -DA:118,0 -DA:119,0 -DA:120,0 -DA:121,0 -DA:122,0 -DA:123,0 -DA:124,0 -DA:125,0 -DA:126,0 -DA:127,0 -DA:128,0 -DA:131,0 -DA:132,0 -DA:133,0 -DA:135,0 -DA:137,0 -DA:138,0 -DA:139,0 -DA:140,0 -DA:141,0 -DA:142,0 -DA:144,0 -DA:146,0 -DA:147,0 -DA:149,0 -DA:150,0 -DA:151,0 -DA:152,0 -DA:153,0 -DA:154,0 -DA:159,0 -DA:160,0 -DA:161,0 -DA:162,0 -DA:163,0 -DA:165,0 -DA:171,0 -DA:172,0 -DA:173,0 -DA:174,0 -DA:175,0 -DA:176,0 -DA:177,0 -DA:178,0 -DA:179,0 -DA:180,0 -DA:186,0 -DA:187,0 -DA:189,0 -DA:191,0 -DA:193,0 -DA:194,0 -DA:195,0 -DA:196,0 -DA:197,0 -DA:198,0 -DA:200,0 -DA:202,0 -DA:203,0 -DA:204,0 -DA:205,0 -DA:206,0 -DA:212,0 -DA:213,0 -DA:214,0 -DA:215,0 -DA:216,0 -DA:217,0 -DA:218,0 -DA:220,0 -DA:221,0 -DA:223,0 -DA:225,0 -DA:226,0 -DA:228,0 -DA:231,0 -DA:232,0 -DA:233,0 -DA:235,0 -DA:236,0 -DA:238,0 -DA:240,0 -DA:241,0 -DA:243,0 -DA:249,0 -DA:250,0 -DA:251,0 -DA:252,0 -DA:254,0 -DA:256,0 -DA:257,0 -DA:259,0 -DA:272,0 -DA:273,0 -DA:274,0 -DA:275,0 -DA:276,0 -DA:278,0 -DA:280,0 -DA:283,0 -DA:284,0 -DA:285,0 -DA:286,0 -DA:288,0 -DA:292,0 -DA:296,0 -DA:298,0 -DA:301,0 -DA:305,0 -DA:306,0 -DA:307,0 -DA:308,0 -DA:309,0 -DA:310,0 -DA:311,0 -DA:312,0 -DA:315,0 -DA:316,0 -DA:318,0 -DA:320,0 -DA:322,0 -DA:325,0 -DA:326,0 -DA:327,0 -DA:339,0 -DA:341,0 -DA:343,0 -DA:344,0 -DA:345,0 -DA:346,0 -DA:347,0 -DA:348,0 -DA:349,0 -DA:350,0 -DA:352,0 -DA:353,0 -DA:354,0 -DA:356,0 -DA:357,0 -DA:358,0 -LF:193 -LH:1 -end_of_record -SF:lib/managers/repository/dio_provider.dart -DA:23,0 -DA:25,0 -DA:27,0 -DA:28,0 -DA:30,0 -DA:31,0 -DA:33,0 -DA:36,0 -DA:40,0 -DA:41,0 -DA:43,0 -DA:46,0 -DA:47,0 -DA:49,0 -DA:50,0 -DA:51,0 -DA:52,0 -DA:53,0 -DA:55,0 -DA:56,0 -DA:69,0 -DA:71,0 -DA:74,0 -DA:75,0 -DA:77,0 -DA:78,0 -DA:81,0 -DA:86,0 -DA:87,0 -DA:90,0 -DA:91,0 -DA:92,0 -DA:93,0 -DA:95,0 -DA:98,0 -DA:99,0 -DA:100,0 -DA:101,0 -DA:103,0 -DA:108,0 -DA:113,0 -DA:114,0 -DA:115,0 -DA:116,0 -DA:117,0 -DA:118,0 -DA:119,0 -DA:120,0 -DA:121,0 -DA:122,0 -DA:124,0 -DA:125,0 -DA:126,0 -DA:134,0 -DA:139,0 -DA:140,0 -DA:141,0 -DA:144,0 -DA:146,0 -DA:147,0 -DA:148,0 -LF:61 -LH:0 -end_of_record -SF:lib/theme/themes.dart -DA:4,3 -DA:21,3 -DA:34,3 -DA:47,3 -DA:52,1 -DA:54,2 -DA:55,2 -DA:56,2 -DA:59,1 -DA:60,1 -DA:61,2 -DA:64,1 -DA:65,1 -DA:66,1 -DA:67,1 -DA:68,1 -DA:69,1 -DA:70,1 -DA:71,1 -DA:72,1 -DA:73,1 -DA:74,1 -DA:75,1 -DA:76,1 -DA:77,1 -DA:78,1 -DA:79,1 -DA:81,2 -DA:82,1 -DA:84,3 -DA:89,1 -DA:90,2 -DA:94,1 -DA:95,2 -DA:97,1 -DA:98,1 -DA:99,2 -DA:101,2 -DA:102,1 -LF:39 -LH:39 -end_of_record -SF:lib/admin/all_users.dart -DA:15,0 -DA:16,0 -DA:18,1 -DA:22,0 -DA:23,0 -DA:28,0 -DA:30,0 -DA:32,0 -DA:34,0 -DA:35,0 -DA:36,0 -DA:37,0 -DA:39,0 -DA:40,0 -DA:41,0 -DA:42,0 -DA:43,0 -DA:45,0 -DA:50,0 -DA:51,0 -DA:52,0 -DA:55,0 -DA:57,0 -DA:58,0 -DA:62,0 -DA:65,0 -DA:68,0 -DA:69,0 -DA:71,0 -DA:72,0 -DA:75,0 -DA:76,0 -DA:81,0 -DA:82,0 -DA:83,0 -DA:84,0 -DA:85,0 -DA:86,0 -DA:89,0 -DA:92,0 -DA:94,0 -DA:95,0 -DA:96,0 -DA:97,0 -DA:98,0 -DA:99,0 -DA:100,0 -DA:101,0 -DA:103,0 -DA:104,0 -DA:105,0 -DA:108,0 -DA:109,0 -DA:111,0 -DA:113,0 -DA:114,0 -DA:115,0 -DA:116,0 -DA:117,0 -DA:119,0 -DA:121,0 -DA:122,0 -DA:124,0 -DA:125,0 -DA:126,0 -DA:127,0 -DA:128,0 -DA:129,0 -DA:147,0 -DA:148,0 -DA:152,0 -DA:153,0 -DA:155,0 -DA:157,0 -DA:159,0 -DA:160,0 -DA:161,0 -DA:162,0 -DA:163,0 -DA:165,0 -DA:167,0 -DA:168,0 -DA:169,0 -DA:183,0 -DA:184,0 -DA:185,0 -DA:186,0 -DA:189,0 -DA:190,0 -DA:191,0 -DA:192,0 -DA:194,0 -DA:198,0 -DA:202,0 -DA:203,0 -DA:204,0 -DA:205,0 -DA:207,0 -DA:219,0 -DA:221,0 -DA:223,0 -DA:224,0 -DA:225,0 -DA:226,0 -DA:227,0 -LF:105 -LH:1 -end_of_record -SF:lib/di/locator.dart -DA:26,0 -DA:28,1 -DA:30,0 -DA:32,0 -DA:34,0 -DA:36,0 -DA:38,0 -DA:40,0 -DA:41,0 -DA:43,0 -DA:45,0 -DA:47,0 -DA:49,0 -DA:51,0 -DA:53,0 -DA:55,0 -DA:56,0 -DA:58,0 -DA:60,0 -DA:62,0 -DA:64,0 -DA:65,0 -DA:67,0 -LF:23 -LH:1 -end_of_record -SF:lib/common_device_info.dart -DA:4,0 -LF:1 -LH:0 -end_of_record -SF:lib/features/games/games_repository.dart -DA:21,0 -DA:23,0 -DA:24,0 -DA:25,0 -DA:28,0 -DA:29,0 -DA:33,0 -DA:34,0 -DA:37,0 -DA:39,0 -DA:40,0 -DA:42,0 -DA:46,0 -DA:47,0 -DA:49,0 -DA:52,0 -DA:53,0 -DA:54,0 -DA:55,0 -DA:57,0 -DA:59,0 -DA:61,0 -DA:63,0 -DA:66,0 -DA:67,0 -DA:70,0 -DA:71,0 -DA:72,0 -DA:73,0 -DA:75,0 -DA:78,0 -LF:31 -LH:0 -end_of_record -SF:lib/features/packs/pack_cache_manager.dart -DA:21,0 -DA:23,0 -DA:24,0 -DA:25,0 -DA:28,0 -DA:30,0 -DA:37,0 -DA:39,0 -DA:40,0 -DA:41,0 -DA:42,0 -DA:43,0 -DA:44,0 -DA:47,0 -DA:48,0 -DA:56,0 -DA:61,0 -DA:63,0 -DA:64,0 -DA:65,0 -DA:66,0 -DA:67,0 -DA:69,0 -DA:71,0 -DA:72,0 -DA:73,0 -DA:74,0 -DA:75,0 -DA:76,0 -DA:77,0 -DA:79,0 -DA:84,0 -DA:85,0 -DA:93,0 -DA:94,0 -DA:99,0 -DA:101,0 -DA:103,0 -DA:104,0 -DA:105,0 -DA:106,0 -DA:107,0 -DA:108,0 -DA:112,0 -DA:116,0 -DA:117,0 -DA:118,0 -DA:120,0 -DA:124,0 -DA:125,0 -DA:128,0 -DA:133,0 -DA:134,0 -DA:135,0 -DA:136,0 -DA:138,0 -DA:143,0 -DA:145,0 -DA:151,0 -DA:153,0 -DA:154,0 -DA:156,0 -DA:158,0 -DA:161,0 -DA:162,0 -DA:166,0 -DA:167,0 -DA:170,0 -DA:171,0 -DA:174,0 -DA:175,0 -DA:176,0 -DA:177,0 -DA:179,0 -DA:182,0 -DA:186,0 -DA:187,0 -DA:188,0 -DA:189,0 -DA:190,0 -DA:191,0 -DA:192,0 -DA:195,0 -DA:196,0 -DA:197,0 -DA:198,0 -DA:200,0 -DA:201,0 -DA:202,0 -DA:203,0 -DA:204,0 -DA:205,0 -DA:207,0 -DA:208,0 -DA:214,0 -DA:217,0 -DA:218,0 -LF:97 -LH:0 -end_of_record -SF:lib/features/purchase/google_purchase_handler.dart -DA:20,0 -DA:22,0 -DA:28,0 -DA:29,0 -DA:32,0 -DA:33,0 -DA:36,0 -DA:37,0 -DA:38,0 -DA:39,0 -DA:40,0 -DA:42,0 -DA:51,0 -DA:52,0 -DA:53,0 -DA:55,0 -DA:57,0 -DA:58,0 -DA:60,0 -DA:62,0 -DA:69,0 -DA:71,0 -DA:73,0 -DA:75,0 -DA:76,0 -DA:78,0 -DA:87,0 -DA:89,0 -DA:90,0 -DA:93,0 -DA:94,0 -DA:95,0 -DA:97,0 -DA:99,0 -DA:100,0 -DA:101,0 -DA:104,0 -DA:107,0 -DA:110,0 -DA:111,0 -DA:113,0 -DA:114,0 -DA:119,0 -DA:126,0 -DA:127,0 -DA:130,0 -DA:132,0 -DA:133,0 -DA:134,0 -DA:137,0 -DA:140,0 -DA:142,0 -DA:143,0 -DA:145,0 -DA:147,0 -DA:150,0 -DA:154,0 -DA:158,0 -DA:160,0 -DA:163,0 -DA:168,0 -DA:171,0 -DA:176,0 -DA:177,0 -DA:178,0 -DA:179,0 -DA:180,0 -DA:182,0 -DA:183,0 -DA:184,0 -DA:185,0 -DA:187,0 -DA:189,0 -DA:190,0 -DA:191,0 -DA:192,0 -DA:195,0 -DA:204,0 -DA:205,0 -DA:206,0 -LF:80 -LH:0 -end_of_record -SF:lib/features/purchase/yookassa_purchase_handler.dart -DA:20,0 -DA:22,0 -DA:27,0 -DA:30,0 -DA:34,0 -DA:41,0 -DA:44,0 -DA:49,0 -DA:55,0 -DA:63,0 -DA:64,0 -DA:65,0 -DA:67,0 -DA:68,0 -DA:70,0 -DA:73,0 -DA:74,0 -DA:75,0 -DA:76,0 -DA:77,0 -DA:78,0 -DA:79,0 -DA:80,0 -DA:82,0 -DA:83,0 -DA:84,0 -DA:85,0 -DA:89,0 -DA:95,0 -DA:102,0 -DA:103,0 -DA:104,0 -DA:105,0 -DA:106,0 -DA:110,0 -DA:116,0 -DA:135,0 -DA:137,0 -DA:138,0 -DA:143,0 -LF:40 -LH:0 -end_of_record -SF:lib/features/subscription/subscription_api.dart -DA:11,0 -DA:13,0 -DA:14,0 -DA:15,0 -DA:16,0 -DA:17,0 -DA:18,0 -DA:21,0 -DA:26,0 -DA:27,0 -DA:28,0 -DA:29,0 -DA:33,0 -DA:35,0 -LF:14 -LH:0 -end_of_record -SF:lib/managers/favorite_cards.dart -DA:13,0 -DA:15,0 -DA:16,0 -DA:17,0 -DA:19,0 -DA:21,0 -DA:24,0 -DA:25,0 -DA:26,0 -DA:29,0 -DA:30,0 -DA:33,0 -DA:34,0 -DA:35,0 -DA:36,0 -DA:37,0 -DA:39,0 -DA:41,0 -DA:44,0 -DA:46,0 -DA:47,0 -DA:49,0 -LF:22 -LH:0 -end_of_record -SF:lib/managers/repository/http_repository.dart -DA:15,0 -DA:17,0 -DA:18,0 -DA:20,0 -DA:22,0 -DA:24,0 -DA:27,0 -DA:30,0 -DA:31,0 -DA:32,0 -DA:34,0 -DA:35,0 -DA:36,0 -DA:41,0 -DA:47,0 -DA:48,0 -DA:49,0 -DA:51,0 -DA:52,0 -DA:53,0 -DA:58,0 -DA:66,0 -DA:68,0 -DA:73,0 -DA:74,0 -DA:75,0 -DA:76,0 -DA:81,0 -DA:83,0 -DA:84,0 -DA:85,0 -DA:86,0 -DA:91,0 -DA:93,0 -DA:94,0 -DA:95,0 -DA:96,0 -DA:99,0 -DA:100,0 -DA:105,0 -DA:107,0 -DA:110,0 -DA:112,0 -DA:115,0 -DA:117,0 -DA:118,0 -DA:119,0 -DA:123,0 -DA:125,0 -DA:126,0 -DA:128,0 -DA:131,0 -DA:133,0 -DA:134,0 -DA:137,0 -DA:139,0 -DA:144,0 -DA:150,0 -DA:151,0 -DA:152,0 -DA:153,0 -DA:154,0 -DA:156,0 -DA:159,0 -DA:162,0 -DA:164,0 -DA:165,0 -DA:169,0 -DA:174,0 -DA:175,0 -DA:176,0 -DA:178,0 -DA:179,0 -DA:182,0 -DA:185,0 -DA:186,0 -DA:187,0 -DA:188,0 -DA:190,0 -LF:79 -LH:0 -end_of_record -SF:lib/features/deeplinks/deeplinks_manager_impl.dart -DA:15,0 -DA:20,0 -DA:21,0 -DA:24,0 -DA:25,0 -DA:26,0 -DA:29,0 -DA:31,0 -DA:32,0 -DA:39,0 -DA:40,0 -DA:42,0 -DA:43,0 -DA:44,0 -DA:45,0 -DA:48,0 -DA:49,0 -LF:17 -LH:0 -end_of_record -SF:lib/features/games/games_api.dart -DA:11,0 -DA:13,0 -DA:14,0 -DA:15,0 -DA:16,0 -DA:20,0 -DA:23,0 -DA:24,0 -DA:25,0 -DA:27,0 -LF:10 -LH:0 -end_of_record -SF:lib/features/games/games_manager.dart -DA:15,0 -DA:17,0 -DA:18,0 -DA:19,0 -DA:20,0 -DA:23,0 -DA:27,0 -DA:28,0 -DA:31,0 -DA:32,0 -DA:35,0 -DA:37,0 -LF:12 -LH:0 -end_of_record -SF:lib/features/packs/active_pack_cubit.dart -DA:15,0 -DA:27,0 -DA:31,0 -DA:34,0 -DA:35,0 -DA:36,0 -DA:40,0 -DA:41,0 -DA:43,0 -DA:46,0 -DA:47,0 -DA:49,0 -DA:52,0 -DA:57,0 -DA:58,0 -DA:59,0 -DA:60,0 -DA:63,0 -DA:65,0 -DA:66,0 -DA:70,0 -DA:72,0 -DA:73,0 -DA:74,0 -DA:76,0 -DA:81,0 -DA:83,0 -DA:85,0 -DA:86,0 -DA:88,0 -DA:91,0 -DA:96,0 -DA:98,0 -DA:99,0 -DA:100,0 -DA:103,0 -DA:104,0 -DA:105,0 -DA:108,0 -DA:113,0 -DA:114,0 -DA:116,0 -DA:117,0 -DA:118,0 -DA:121,0 -DA:126,0 -DA:131,0 -DA:132,0 -DA:134,0 -DA:141,0 -DA:142,0 -DA:143,0 -DA:147,0 -DA:148,0 -DA:149,0 -DA:150,0 -DA:151,0 -DA:153,0 -DA:155,0 -DA:156,0 -DA:157,0 -DA:158,0 -DA:163,0 -DA:164,0 -DA:165,0 -DA:170,0 -DA:171,0 -DA:172,0 -DA:177,0 -DA:178,0 -DA:179,0 -DA:184,0 -DA:185,0 -LF:73 -LH:0 -end_of_record -SF:lib/features/packs/images_holder.dart -DA:11,0 -DA:13,0 -DA:18,0 -DA:20,0 -DA:21,0 -DA:24,0 -DA:25,0 -DA:28,0 -DA:29,0 -DA:30,0 -DA:31,0 -DA:34,0 -DA:35,0 -DA:40,0 -DA:41,0 -DA:45,0 -DA:47,0 -DA:51,0 -DA:55,0 -LF:19 -LH:0 -end_of_record -SF:lib/features/packs/pack_updater.dart -DA:29,0 -DA:37,0 -DA:38,0 -DA:39,0 -DA:42,0 -DA:43,0 -DA:44,0 -DA:45,0 -DA:46,0 -DA:50,0 -DA:51,0 -DA:52,0 -DA:55,0 -DA:56,0 -DA:58,0 -DA:59,0 -DA:62,0 -DA:63,0 -DA:64,0 -DA:67,0 -DA:70,0 -DA:71,0 -DA:72,0 -DA:73,0 -DA:74,0 -DA:75,0 -DA:76,0 -DA:80,0 -DA:82,0 -DA:83,0 -DA:97,0 -DA:98,0 -DA:99,0 -DA:100,0 -DA:101,0 -DA:103,0 -DA:104,0 -DA:105,0 -DA:106,0 -DA:109,0 -DA:112,0 -DA:113,0 -DA:115,0 -DA:126,0 -DA:127,0 -DA:131,0 -DA:132,0 -DA:134,0 -DA:139,0 -DA:147,0 -DA:148,0 -DA:149,0 -DA:150,0 -DA:151,0 -DA:153,0 -DA:156,0 -DA:157,0 -DA:161,0 -DA:165,0 -DA:166,0 -DA:172,0 -DA:176,0 -DA:177,0 -DA:179,0 -DA:180,0 -DA:183,0 -DA:184,0 -DA:185,0 -DA:186,0 -DA:188,0 -DA:189,0 -DA:190,0 -DA:191,0 -DA:193,0 -DA:195,0 -DA:197,0 -DA:199,0 -DA:200,0 -DA:202,0 -DA:206,0 -DA:207,0 -DA:208,0 -DA:211,0 -DA:212,0 -DA:217,0 -DA:218,0 -DA:220,0 -DA:221,0 -DA:222,0 -DA:223,0 -DA:225,0 -DA:226,0 -DA:231,0 -LF:93 -LH:0 -end_of_record -SF:lib/features/packs/packs_holder.dart -DA:9,0 -DA:11,0 -DA:14,0 -DA:16,0 -DA:19,0 -DA:21,0 -DA:22,0 -DA:23,0 -DA:24,0 -DA:31,0 -DA:34,0 -DA:37,0 -DA:38,0 -DA:39,0 -DA:40,0 -DA:43,0 -DA:44,0 -DA:47,0 -DA:50,0 -DA:52,0 -DA:55,0 -DA:56,0 -DA:60,0 -DA:63,0 -DA:65,0 -DA:66,0 -DA:67,0 -DA:68,0 -DA:72,0 -DA:73,0 -DA:76,0 -DA:77,0 -LF:32 -LH:0 -end_of_record -SF:lib/features/packs/preview_packs_poller.dart -DA:12,0 -DA:14,0 -DA:15,0 -DA:16,0 -DA:20,0 -DA:21,0 -DA:23,0 -DA:24,0 -DA:25,0 -DA:27,0 -DA:28,0 -DA:29,0 -DA:30,0 -DA:31,0 -DA:35,0 -LF:15 -LH:0 -end_of_record -SF:lib/features/packs/web_pack_cache_manager.dart -DA:21,0 -DA:23,0 -DA:24,0 -DA:27,0 -DA:29,0 -DA:36,0 -DA:38,0 -DA:39,0 -DA:41,0 -DA:42,0 -DA:43,0 -DA:46,0 -DA:47,0 -DA:55,0 -DA:60,0 -DA:62,0 -DA:63,0 -DA:65,0 -DA:66,0 -DA:68,0 -DA:70,0 -DA:71,0 -DA:72,0 -DA:91,0 -DA:92,0 -DA:96,0 -DA:97,0 -DA:102,0 -DA:104,0 -DA:106,0 -DA:107,0 -DA:108,0 -DA:109,0 -DA:110,0 -DA:111,0 -DA:115,0 -DA:119,0 -DA:120,0 -DA:121,0 -DA:122,0 -DA:124,0 -DA:128,0 -DA:130,0 -DA:136,0 -DA:138,0 -DA:139,0 -DA:142,0 -DA:144,0 -DA:147,0 -DA:154,0 -DA:155,0 -DA:156,0 -DA:157,0 -DA:159,0 -DA:162,0 -DA:166,0 -DA:167,0 -DA:168,0 -DA:169,0 -DA:170,0 -DA:184,0 -DA:187,0 -DA:189,0 -DA:192,0 -DA:195,0 -DA:198,0 -DA:201,0 -DA:204,0 -LF:68 -LH:0 -end_of_record -SF:lib/features/purchase/in_app_purchase.dart -DA:29,0 -DA:61,0 -DA:67,0 -DA:68,0 -DA:72,0 -DA:73,0 -DA:75,0 -DA:76,0 -DA:77,0 -DA:78,0 -DA:85,0 -DA:86,0 -DA:88,0 -DA:90,0 -DA:93,0 -DA:96,0 -DA:97,0 -DA:98,0 -DA:99,0 -DA:100,0 -DA:102,0 -DA:105,0 -DA:109,0 -DA:111,0 -DA:112,0 -DA:113,0 -DA:115,0 -DA:116,0 -DA:117,0 -DA:118,0 -DA:121,0 -DA:124,0 -DA:175,0 -DA:176,0 -DA:177,0 -DA:180,0 -DA:181,0 -DA:182,0 -DA:183,0 -DA:186,0 -DA:187,0 -DA:194,0 -DA:196,0 -DA:198,0 -DA:200,0 -DA:201,0 -DA:202,0 -DA:203,0 -DA:206,0 -DA:207,0 -DA:208,0 -DA:211,0 -DA:212,0 -DA:215,0 -DA:217,0 -DA:218,0 -DA:220,0 -DA:222,0 -DA:225,0 -DA:227,0 -DA:230,0 -DA:236,0 -DA:238,0 -DA:239,0 -DA:240,0 -DA:241,0 -DA:243,0 -DA:244,0 -DA:245,0 -DA:246,0 -DA:254,0 -DA:255,0 -LF:72 -LH:0 -end_of_record -SF:lib/features/purchase/purchase_deeplink_handler.dart -DA:13,0 -DA:15,0 -DA:16,0 -DA:18,0 -DA:20,0 -DA:22,0 -DA:23,0 -DA:24,0 -DA:25,0 -DA:27,0 -DA:30,0 -DA:31,0 -DA:32,0 -DA:33,0 -DA:34,0 -DA:35,0 -DA:36,0 -DA:37,0 -DA:41,0 -DA:42,0 -DA:43,0 -DA:44,0 -DA:45,0 -DA:46,0 -DA:48,0 -DA:49,0 -DA:52,0 -DA:53,0 -DA:54,0 -DA:58,0 -DA:59,0 -DA:60,0 -LF:32 -LH:0 -end_of_record -SF:lib/features/purchase/purchase_manager.dart -DA:11,0 -DA:16,0 -DA:24,0 -DA:25,0 -DA:27,0 -DA:28,0 -DA:30,0 -DA:31,0 -DA:33,0 -DA:34,0 -DA:36,0 -DA:37,0 -DA:39,0 -DA:40,0 -DA:42,0 -DA:46,0 -DA:54,0 -DA:55,0 -DA:62,0 -DA:70,0 -DA:71,0 -DA:77,0 -DA:79,0 -DA:81,0 -DA:82,0 -DA:87,0 -DA:89,0 -DA:91,0 -DA:96,0 -DA:102,0 -DA:103,0 -DA:107,0 -DA:109,0 -DA:111,0 -DA:112,0 -DA:116,0 -DA:118,0 -DA:120,0 -LF:38 -LH:0 -end_of_record -SF:lib/features/subscription/subscription_deeplink_handler.dart -DA:7,0 -DA:8,0 -DA:10,0 -DA:11,0 -LF:4 -LH:0 -end_of_record -SF:lib/features/subscription/subscription_manager.dart -DA:14,0 -DA:19,0 -DA:20,0 -DA:22,0 -DA:26,0 -DA:28,0 -DA:29,0 -DA:30,0 -LF:8 -LH:0 -end_of_record -SF:lib/features/tests/test_manager.dart -DA:30,0 -DA:32,0 -DA:34,0 -DA:35,0 -DA:36,0 -DA:38,0 -DA:40,0 -DA:41,0 -DA:42,0 -DA:43,0 -DA:44,0 -DA:48,0 -DA:50,0 -DA:52,0 -DA:54,0 -DA:55,0 -DA:57,0 -DA:60,0 -DA:62,0 -DA:64,0 -DA:65,0 -DA:69,0 -DA:70,0 -DA:71,0 -DA:75,0 -DA:76,0 -DA:77,0 -DA:80,0 -DA:84,0 -DA:86,0 -DA:88,0 -DA:90,0 -DA:91,0 -DA:92,0 -DA:93,0 -DA:98,0 -DA:99,0 -DA:100,0 -DA:101,0 -DA:106,0 -DA:107,0 -DA:108,0 -DA:109,0 -DA:110,0 -DA:111,0 -DA:112,0 -DA:113,0 -DA:114,0 -DA:116,0 -DA:117,0 -DA:118,0 -DA:125,0 -DA:126,0 -DA:127,0 -DA:128,0 -DA:129,0 -DA:131,0 -DA:132,0 -DA:133,0 -DA:140,0 -DA:141,0 -DA:142,0 -DA:147,0 -DA:148,0 -DA:149,0 -DA:152,0 -DA:153,0 -DA:154,0 -DA:155,0 -DA:156,0 -DA:157,0 -DA:159,0 -DA:160,0 -DA:161,0 -DA:165,0 -DA:166,0 -DA:168,0 -DA:169,0 -DA:170,0 -DA:171,0 -DA:173,0 -DA:180,0 -DA:182,0 -LF:83 -LH:0 -end_of_record -SF:lib/features/packs/pack_manager.dart -DA:17,0 -DA:23,0 -DA:24,0 -DA:25,0 -DA:28,0 -DA:29,0 -DA:30,0 -DA:31,0 -DA:34,0 -DA:35,0 -DA:36,0 -DA:37,0 -DA:38,0 -LF:13 -LH:0 -end_of_record -SF:lib/features/packs/preview_pack_holder.dart -DA:13,0 -DA:15,0 -DA:16,0 -DA:17,0 -DA:21,0 -DA:22,0 -DA:23,0 -DA:24,0 -DA:27,0 -DA:28,0 -DA:30,0 -DA:31,0 -DA:33,0 -DA:36,0 -DA:39,0 -DA:40,0 -DA:41,0 -DA:42,0 -DA:44,0 -DA:45,0 -DA:47,0 -DA:50,0 -DA:51,0 -DA:54,0 -DA:55,0 -DA:57,0 -DA:59,0 -DA:62,0 -DA:64,0 -DA:70,0 -LF:30 -LH:0 -end_of_record -SF:lib/features/tests/tests_cache.dart -DA:7,0 -DA:8,0 -DA:9,0 -DA:12,0 -DA:13,0 -DA:14,0 -DA:16,0 -LF:7 -LH:0 -end_of_record -SF:lib/features/yandex_ads/ads_deeplink_handler.dart -DA:15,0 -DA:17,0 -DA:18,0 -DA:20,0 -DA:22,0 -DA:24,0 -DA:25,0 -DA:27,0 -DA:30,0 -DA:31,0 -DA:32,0 -DA:34,0 -DA:36,0 -DA:47,0 -DA:50,0 -LF:15 -LH:0 -end_of_record -SF:lib/features/yandex_ads/yandex_rewarded_ads.dart -DA:16,0 -DA:27,0 -DA:28,0 -DA:29,0 -DA:30,0 -DA:32,0 -DA:33,0 -DA:34,0 -DA:35,0 -DA:37,0 -DA:38,0 -DA:40,0 -DA:41,0 -DA:42,0 -DA:43,0 -DA:47,0 -DA:48,0 -DA:50,0 -DA:51,0 -DA:52,0 -DA:53,0 -DA:55,0 -DA:58,0 -DA:59,0 -DA:60,0 -DA:61,0 -DA:63,0 -DA:64,0 -DA:65,0 -DA:67,0 -DA:76,0 -DA:78,0 -DA:79,0 -DA:81,0 -DA:82,0 -DA:83,0 -DA:88,0 -DA:92,0 -DA:93,0 -DA:94,0 -DA:95,0 -DA:97,0 -LF:42 -LH:0 -end_of_record -SF:lib/managers/user_manager.dart -DA:28,0 -DA:30,0 -DA:32,0 -DA:34,0 -DA:36,0 -DA:38,0 -DA:42,0 -DA:45,0 -DA:46,0 -DA:49,0 -DA:54,0 -DA:55,0 -DA:57,0 -DA:58,0 -DA:60,0 -DA:65,0 -DA:68,0 -DA:72,0 -DA:73,0 -DA:75,0 -DA:79,0 -DA:80,0 -DA:81,0 -DA:82,0 -DA:83,0 -DA:86,0 -DA:92,0 -DA:98,0 -DA:99,0 -DA:102,0 -DA:103,0 -DA:104,0 -DA:107,0 -DA:108,0 -DA:111,0 -DA:112,0 -DA:115,0 -DA:116,0 -DA:120,0 -DA:124,0 -DA:128,0 -DA:129,0 -DA:131,0 -DA:133,0 -DA:134,0 -DA:137,0 -DA:138,0 -DA:151,0 -DA:152,0 -DA:153,0 -DA:154,0 -DA:156,0 -DA:157,0 -DA:164,0 -DA:165,0 -DA:168,0 -DA:171,0 -DA:173,0 -DA:176,0 -DA:177,0 -DA:178,0 -DA:179,0 -DA:180,0 -DA:181,0 -DA:182,0 -DA:185,0 -DA:186,0 -DA:189,0 -DA:190,0 -DA:191,0 -DA:192,0 -DA:194,0 -DA:195,0 -DA:197,0 -DA:204,0 -DA:208,0 -DA:209,0 -DA:210,0 -DA:214,0 -DA:215,0 -DA:216,0 -DA:218,0 -DA:219,0 -DA:223,0 -DA:226,0 -DA:227,0 -DA:228,0 -DA:229,0 -DA:230,0 -DA:232,0 -DA:236,0 -DA:237,0 -DA:238,0 -DA:239,0 -DA:240,0 -DA:248,0 -DA:249,0 -DA:250,0 -LF:98 -LH:0 -end_of_record -SF:lib/domain/router/app_router.dart -DA:13,1 -DA:15,1 -DA:16,1 -DA:17,1 -DA:19,1 -DA:21,1 -DA:22,1 -DA:23,1 -DA:27,1 -DA:28,1 -DA:32,1 -DA:33,1 -DA:37,1 -DA:38,1 -DA:42,1 -DA:43,1 -DA:49,1 -DA:50,1 -DA:51,1 -DA:52,1 -DA:55,1 -DA:56,1 -DA:59,1 -DA:60,1 -DA:63,1 -DA:64,1 -DA:72,0 -DA:73,0 -DA:74,0 -DA:75,0 -DA:79,0 -DA:80,0 -DA:81,0 -DA:82,0 -DA:86,0 -DA:87,0 -DA:88,0 -DA:90,0 -DA:94,0 -DA:95,0 -DA:96,0 -DA:97,0 -DA:98,0 -DA:100,0 -LF:44 -LH:26 -end_of_record -SF:lib/features/chat/chat_page.dart -DA:14,0 -DA:16,0 -DA:17,0 -DA:18,0 -DA:19,0 -DA:20,0 -DA:22,0 -DA:23,0 -LF:8 -LH:0 -end_of_record -SF:lib/features/games/games_page.dart -DA:17,0 -DA:19,0 -DA:20,0 -DA:21,0 -DA:22,0 -DA:23,0 -DA:24,0 -DA:26,0 -DA:27,0 -DA:28,0 -DA:29,0 -DA:31,0 -DA:32,0 -DA:33,0 -DA:34,0 -DA:35,0 -DA:36,0 -DA:37,0 -DA:38,0 -DA:46,0 -DA:51,0 -DA:52,0 -DA:53,0 -DA:54,0 -DA:55,0 -DA:56,0 -LF:26 -LH:0 -end_of_record -SF:lib/features/games/payloads/integration_example.dart -DA:11,0 -DA:12,0 -DA:15,0 -DA:17,0 -DA:20,0 -DA:25,0 -DA:30,0 -DA:32,0 -DA:33,0 -DA:34,0 -DA:35,0 -DA:36,0 -DA:37,0 -DA:42,0 -DA:47,0 -DA:53,0 -DA:54,0 -DA:62,0 -DA:76,0 -DA:80,0 -DA:89,0 -DA:95,0 -DA:96,0 -DA:103,0 -DA:105,0 -DA:106,0 -DA:109,0 -DA:112,0 -DA:115,0 -DA:116,0 -DA:117,0 -DA:121,0 -DA:122,0 -DA:123,0 -DA:124,0 -DA:128,0 -DA:130,0 -DA:131,0 -DA:132,0 -DA:133,0 -DA:134,0 -DA:135,0 -DA:136,0 -DA:138,0 -DA:145,0 -DA:146,0 -DA:147,0 -DA:148,0 -DA:153,0 -DA:155,0 -DA:156,0 -DA:157,0 -DA:167,0 -DA:173,0 -DA:175,0 -DA:176,0 -DA:177,0 -LF:57 -LH:0 -end_of_record -SF:lib/features/games/payloads_demo_page.dart -DA:8,1 -DA:10,0 -DA:11,0 -DA:18,0 -DA:20,0 -DA:21,0 -DA:24,0 -DA:27,0 -DA:28,0 -DA:29,0 -DA:34,0 -DA:35,0 -DA:36,0 -DA:37,0 -DA:38,0 -DA:43,0 -DA:45,0 -DA:46,0 -DA:48,0 -DA:50,0 -DA:51,0 -DA:53,0 -DA:55,0 -DA:56,0 -DA:63,0 -DA:65,0 -DA:67,0 -DA:73,0 -DA:74,0 -DA:75,0 -DA:76,0 -DA:77,0 -DA:82,0 -DA:83,0 -DA:84,0 -DA:91,0 -DA:92,0 -DA:93,0 -DA:94,0 -DA:95,0 -DA:100,0 -DA:101,0 -DA:102,0 -DA:113,0 -DA:116,0 -DA:117,0 -DA:118,0 -DA:120,0 -DA:122,0 -DA:128,0 -DA:129,0 -DA:130,0 -DA:131,0 -DA:132,0 -DA:134,0 -DA:135,0 -DA:150,0 -DA:152,0 -DA:153,0 -DA:154,0 -DA:156,0 -DA:160,0 -DA:162,0 -DA:163,0 -DA:171,0 -DA:181,0 -DA:182,0 -DA:184,0 -DA:188,0 -DA:190,0 -DA:195,0 -DA:198,0 -DA:199,0 -DA:201,0 -DA:205,0 -DA:207,0 -DA:208,0 -DA:210,0 -DA:211,0 -DA:213,0 -DA:217,0 -DA:219,0 -DA:220,0 -LF:83 -LH:1 -end_of_record -SF:lib/features/tests/test_page.dart -DA:21,0 -DA:22,0 -DA:24,0 -DA:28,0 -DA:33,0 -DA:35,0 -DA:36,0 -DA:37,0 -DA:38,0 -DA:41,0 -DA:43,0 -DA:44,0 -DA:47,0 -DA:48,0 -DA:51,0 -DA:52,0 -DA:54,0 -DA:55,0 -DA:56,0 -DA:57,0 -DA:58,0 -DA:60,0 -DA:63,0 -DA:64,0 -DA:65,0 -DA:66,0 -DA:69,0 -DA:76,0 -DA:79,0 -DA:80,0 -DA:81,0 -DA:82,0 -DA:83,0 -DA:84,0 -DA:85,0 -DA:86,0 -DA:91,0 -DA:93,0 -DA:94,0 -DA:95,0 -DA:96,0 -DA:97,0 -DA:98,0 -DA:99,0 -DA:100,0 -DA:101,0 -DA:106,0 -DA:107,0 -DA:110,0 -DA:111,0 -DA:112,0 -DA:113,0 -DA:117,0 -DA:118,0 -DA:119,0 -DA:120,0 -DA:121,0 -DA:122,0 -DA:123,0 -DA:124,0 -DA:125,0 -DA:126,0 -DA:129,0 -DA:130,0 -DA:133,0 -DA:134,0 -DA:135,0 -DA:136,0 -DA:138,0 -DA:139,0 -DA:140,0 -DA:141,0 -DA:144,0 -DA:145,0 -DA:146,0 -DA:147,0 -DA:148,0 -DA:153,0 -DA:154,0 -DA:155,0 -DA:157,0 -DA:159,0 -DA:160,0 -DA:162,0 -DA:164,0 -DA:165,0 -DA:167,0 -DA:168,0 -DA:182,0 -DA:183,0 -DA:184,0 -DA:185,0 -DA:190,0 -DA:192,0 -DA:195,0 -DA:196,0 -DA:197,0 -DA:200,0 -DA:202,0 -LF:99 -LH:0 -end_of_record -SF:lib/pages/auth_page.dart -DA:16,0 -DA:18,0 -DA:19,0 -DA:20,0 -DA:21,0 -DA:22,0 -DA:23,0 -DA:25,0 -DA:27,0 -DA:28,0 -DA:34,0 -DA:35,0 -DA:37,0 -DA:38,0 -DA:39,0 -DA:45,0 -DA:46,0 -DA:47,0 -DA:49,0 -DA:53,0 -DA:55,0 -DA:56,0 -DA:57,0 -DA:58,0 -DA:59,0 -DA:61,0 -DA:62,0 -DA:63,0 -DA:65,0 -DA:66,0 -DA:68,0 -DA:75,0 -DA:77,0 -DA:78,0 -DA:79,0 -DA:80,0 -DA:81,0 -DA:83,0 -DA:84,0 -DA:85,0 -DA:87,0 -DA:88,0 -DA:90,0 -DA:95,0 -DA:97,0 -DA:98,0 -DA:99,0 -DA:100,0 -DA:101,0 -DA:112,0 -DA:114,0 -DA:115,0 -DA:118,0 -DA:119,0 -DA:121,0 -DA:122,0 -LF:56 -LH:0 -end_of_record -SF:lib/pages/home_page.dart -DA:9,0 -DA:11,0 -DA:12,0 -DA:13,0 -DA:14,0 -DA:19,0 -LF:6 -LH:0 -end_of_record -SF:lib/pages/profile_page.dart -DA:22,0 -DA:24,0 -DA:25,0 -DA:26,0 -DA:27,0 -DA:28,0 -DA:29,0 -DA:30,0 -DA:31,0 -DA:32,0 -DA:34,0 -DA:35,0 -DA:36,0 -DA:37,0 -DA:38,0 -DA:39,0 -DA:45,0 -DA:50,0 -DA:52,0 -DA:53,0 -DA:54,0 -DA:56,0 -DA:59,0 -DA:61,0 -DA:64,0 -DA:66,0 -DA:68,0 -DA:69,0 -DA:70,0 -DA:71,0 -DA:78,0 -DA:80,0 -DA:83,0 -DA:85,0 -DA:86,0 -DA:89,0 -DA:91,0 -DA:93,0 -DA:94,0 -DA:95,0 -DA:97,0 -DA:98,0 -DA:99,0 -DA:101,0 -DA:102,0 -DA:104,0 -DA:105,0 -DA:108,0 -DA:110,0 -DA:111,0 -DA:114,0 -DA:116,0 -DA:118,0 -DA:119,0 -DA:132,0 -DA:133,0 -DA:134,0 -DA:135,0 -DA:138,0 -LF:59 -LH:0 -end_of_record -SF:lib/pages/settgins_page.dart -DA:27,0 -DA:28,0 -DA:29,0 -DA:30,0 -DA:31,0 -DA:35,0 -DA:37,0 -DA:38,0 -DA:39,0 -DA:40,0 -DA:41,0 -DA:42,0 -DA:47,0 -DA:48,0 -DA:50,0 -DA:52,0 -DA:54,0 -DA:55,0 -DA:56,0 -DA:57,0 -DA:59,0 -DA:60,0 -DA:61,0 -DA:62,0 -DA:63,0 -DA:64,0 -DA:66,0 -DA:73,0 -DA:75,0 -DA:76,0 -DA:81,0 -DA:83,0 -DA:88,0 -DA:90,0 -DA:91,0 -DA:96,0 -DA:98,0 -DA:100,0 -DA:101,0 -DA:106,0 -DA:108,0 -DA:110,0 -DA:111,0 -DA:116,0 -DA:118,0 -DA:120,0 -DA:122,0 -DA:123,0 -DA:126,0 -DA:129,0 -DA:130,0 -DA:132,0 -DA:133,0 -DA:138,0 -DA:141,0 -DA:146,0 -DA:147,0 -DA:149,0 -DA:151,0 -DA:154,0 -DA:155,0 -DA:156,0 -DA:157,0 -DA:159,0 -DA:160,0 -DA:161,0 -DA:179,0 -DA:180,0 -DA:182,0 -DA:183,0 -DA:184,0 -DA:187,0 -DA:189,0 -DA:190,0 -DA:191,0 -DA:194,0 -DA:196,0 -DA:197,0 -DA:198,0 -DA:201,0 -DA:203,0 -DA:204,0 -DA:205,0 -DA:208,0 -DA:210,0 -DA:211,0 -DA:212,0 -DA:215,0 -DA:217,0 -DA:218,0 -DA:219,0 -DA:222,0 -DA:223,0 -DA:224,0 -DA:230,0 -DA:234,0 -DA:235,0 -DA:236,0 -DA:237,0 -DA:240,0 -LF:100 -LH:0 -end_of_record -SF:lib/pages/vocabulary_page.dart -DA:7,1 -DA:9,0 -DA:11,0 -LF:3 -LH:1 -end_of_record -SF:lib/widgets/card_game/card_game_page.dart -DA:25,0 -DA:34,0 -DA:35,0 -DA:46,0 -DA:47,0 -DA:49,0 -DA:50,0 -DA:55,0 -DA:59,0 -DA:60,0 -DA:61,0 -DA:62,0 -DA:65,0 -DA:66,0 -DA:68,0 -DA:73,0 -DA:80,0 -DA:81,0 -DA:82,0 -DA:83,0 -DA:87,0 -DA:88,0 -DA:89,0 -DA:90,0 -DA:91,0 -DA:92,0 -DA:93,0 -DA:94,0 -DA:95,0 -DA:97,0 -DA:98,0 -DA:99,0 -DA:100,0 -DA:101,0 -DA:102,0 -DA:103,0 -DA:104,0 -DA:107,0 -DA:108,0 -DA:109,0 -DA:110,0 -DA:111,0 -DA:112,0 -DA:113,0 -DA:116,0 -DA:117,0 -DA:118,0 -DA:119,0 -DA:121,0 -DA:122,0 -DA:125,0 -DA:126,0 -DA:127,0 -DA:128,0 -DA:133,0 -DA:134,0 -DA:135,0 -DA:136,0 -DA:137,0 -DA:140,0 -DA:141,0 -DA:142,0 -DA:143,0 -DA:144,0 -DA:145,0 -DA:146,0 -DA:147,0 -DA:148,0 -DA:149,0 -DA:151,0 -DA:152,0 -DA:154,0 -DA:156,0 -DA:157,0 -DA:159,0 -DA:171,0 -DA:172,0 -DA:174,0 -DA:175,0 -DA:177,0 -DA:178,0 -DA:179,0 -DA:180,0 -DA:181,0 -DA:182,0 -DA:183,0 -DA:184,0 -DA:185,0 -DA:186,0 -DA:187,0 -DA:189,0 -DA:190,0 -DA:191,0 -DA:193,0 -DA:194,0 -DA:195,0 -DA:196,0 -DA:197,0 -DA:199,0 -DA:201,0 -DA:203,0 -DA:204,0 -DA:205,0 -DA:207,0 -DA:208,0 -DA:209,0 -DA:210,0 -DA:211,0 -DA:214,0 -DA:216,0 -DA:217,0 -DA:218,0 -DA:219,0 -DA:220,0 -DA:224,0 -DA:225,0 -DA:227,0 -DA:228,0 -DA:229,0 -DA:238,0 -DA:239,0 -DA:241,0 -DA:243,0 -DA:244,0 -DA:248,0 -DA:249,0 -DA:253,0 -DA:255,0 -DA:256,0 -DA:257,0 -DA:258,0 -DA:259,0 -DA:261,0 -DA:263,0 -DA:264,0 -DA:266,0 -DA:267,0 -DA:289,0 -DA:291,0 -DA:292,0 -DA:293,0 -DA:294,0 -DA:296,0 -DA:297,0 -DA:298,0 -DA:301,0 -DA:302,0 -DA:303,0 -DA:304,0 -DA:307,0 -DA:310,0 -DA:312,0 -DA:313,0 -DA:314,0 -DA:316,0 -DA:323,0 -DA:325,0 -DA:326,0 -DA:328,0 -LF:159 -LH:0 -end_of_record -SF:lib/widgets/card_pack/card_pack_page.dart -DA:23,0 -DA:25,0 -DA:26,0 -DA:30,0 -DA:32,0 -DA:33,0 -DA:34,0 -DA:35,0 -DA:36,0 -DA:37,0 -DA:39,0 -DA:46,0 -DA:48,0 -DA:50,0 -DA:51,0 -DA:53,0 -DA:55,0 -DA:56,0 -DA:58,0 -DA:59,0 -DA:60,0 -DA:62,0 -DA:63,0 -DA:64,0 -DA:65,0 -DA:68,0 -DA:69,0 -DA:70,0 -DA:74,0 -DA:75,0 -DA:76,0 -DA:77,0 -DA:78,0 -DA:79,0 -DA:88,0 -DA:90,0 -DA:91,0 -LF:37 -LH:0 -end_of_record -SF:lib/features/analytics/analytics.dart -DA:6,0 -DA:7,0 -DA:9,0 -DA:10,0 -DA:13,0 -DA:14,0 -DA:17,0 -DA:18,0 -DA:20,0 -DA:21,0 -DA:22,0 -DA:24,0 -DA:27,0 -DA:28,0 -DA:31,0 -DA:32,0 -DA:33,0 -DA:36,0 -DA:37,0 -DA:40,0 -DA:41,0 -DA:42,0 -DA:45,0 -DA:46,0 -DA:49,0 -DA:50,0 -DA:51,0 -DA:54,0 -DA:55,0 -DA:58,0 -DA:59,0 -DA:60,0 -DA:63,0 -DA:64,0 -DA:67,0 -DA:68,0 -DA:69,0 -DA:70,0 -DA:71,0 -DA:74,0 -DA:75,0 -DA:78,0 -DA:79,0 -DA:80,0 -DA:81,0 -DA:82,0 -DA:83,0 -DA:86,0 -DA:87,0 -DA:89,0 -DA:90,0 -DA:91,0 -DA:92,0 -DA:93,0 -DA:94,0 -DA:95,0 -DA:98,0 -DA:103,0 -DA:105,0 -DA:106,0 -DA:107,0 -DA:108,0 -DA:109,0 -DA:112,0 -DA:120,0 -DA:122,0 -DA:123,0 -DA:124,0 -DA:125,0 -DA:126,0 -DA:127,0 -DA:128,0 -DA:129,0 -DA:130,0 -DA:133,0 -DA:139,0 -DA:141,0 -DA:142,0 -DA:143,0 -DA:144,0 -DA:145,0 -DA:146,0 -DA:147,0 -DA:148,0 -DA:152,0 -DA:158,0 -DA:160,0 -DA:161,0 -DA:162,0 -DA:163,0 -DA:164,0 -DA:165,0 -DA:166,0 -DA:167,0 -DA:170,0 -DA:177,0 -DA:179,0 -DA:180,0 -DA:181,0 -DA:182,0 -DA:183,0 -DA:184,0 -DA:185,0 -DA:186,0 -DA:190,0 -DA:191,0 -DA:194,0 -DA:195,0 -DA:196,0 -DA:197,0 -DA:199,0 -DA:202,0 -DA:203,0 -DA:206,0 -DA:207,0 -DA:208,0 -DA:209,0 -DA:210,0 -DA:211,0 -DA:214,0 -DA:220,0 -DA:224,0 -DA:227,0 -DA:232,0 -DA:234,0 -DA:235,0 -DA:236,0 -DA:237,0 -DA:238,0 -DA:244,0 -DA:245,0 -DA:246,0 -LF:132 -LH:0 -end_of_record -SF:lib/features/card_flipper/flip_card.dart -DA:41,0 -DA:53,0 -DA:55,0 -DA:56,0 -DA:65,0 -DA:67,0 -DA:68,0 -DA:69,0 -DA:70,0 -DA:71,0 -DA:72,0 -DA:73,0 -DA:75,0 -DA:76,0 -DA:77,0 -DA:78,0 -DA:79,0 -DA:80,0 -DA:81,0 -DA:86,0 -DA:88,0 -DA:89,0 -DA:90,0 -DA:91,0 -DA:94,0 -DA:95,0 -DA:96,0 -DA:97,0 -DA:99,0 -DA:100,0 -DA:103,0 -DA:105,0 -DA:106,0 -DA:109,0 -DA:110,0 -DA:111,0 -DA:112,0 -DA:113,0 -DA:114,0 -DA:116,0 -DA:117,0 -DA:118,0 -DA:119,0 -DA:122,0 -DA:124,0 -DA:128,0 -DA:129,0 -DA:132,0 -DA:137,0 -DA:140,0 -LF:50 -LH:0 -end_of_record -SF:lib/features/card_flipper/flip_card_controllers.dart -DA:11,0 -DA:14,0 -DA:15,0 -DA:16,0 -DA:19,0 -DA:21,0 -DA:22,0 -LF:7 -LH:0 -end_of_record -SF:lib/features/games/game_button.dart -DA:19,0 -DA:24,0 -DA:26,0 -DA:28,0 -DA:29,0 -DA:30,0 -DA:31,0 -DA:32,0 -DA:33,0 -DA:34,0 -DA:35,0 -DA:37,0 -DA:38,0 -DA:39,0 -DA:40,0 -DA:41,0 -DA:42,0 -DA:45,0 -DA:48,0 -DA:50,0 -DA:51,0 -DA:52,0 -DA:53,0 -DA:55,0 -DA:56,0 -DA:57,0 -DA:58,0 -DA:60,0 -DA:62,0 -DA:63,0 -DA:65,0 -DA:66,0 -DA:68,0 -DA:69,0 -DA:71,0 -DA:73,0 -DA:74,0 -DA:76,0 -DA:77,0 -DA:78,0 -DA:80,0 -DA:85,0 -DA:86,0 -DA:88,0 -DA:89,0 -DA:90,0 -DA:92,0 -DA:96,0 -DA:97,0 -DA:98,0 -DA:100,0 -DA:116,0 -DA:118,0 -DA:121,0 -DA:123,0 -DA:124,0 -DA:125,0 -DA:127,0 -DA:128,0 -DA:129,0 -DA:130,0 -DA:131,0 -DA:132,0 -DA:133,0 -DA:137,0 -DA:141,0 -DA:144,0 -DA:150,0 -DA:152,0 -DA:153,0 -DA:154,0 -DA:155,0 -DA:156,0 -DA:157,0 -DA:160,0 -DA:163,0 -DA:164,0 -LF:77 -LH:0 -end_of_record -SF:lib/features/games/game_assets_loader.dart -DA:13,0 -DA:15,0 -DA:17,0 -DA:20,0 -DA:22,0 -LF:5 -LH:0 -end_of_record -SF:lib/managers/audio_player.dart -DA:6,0 -DA:7,0 -DA:9,0 -DA:10,0 -DA:11,0 -DA:13,0 -DA:14,0 -DA:15,0 -DA:17,0 -DA:21,0 -DA:23,0 -DA:26,0 -DA:28,0 -DA:29,0 -LF:14 -LH:0 -end_of_record -SF:lib/features/games/games_bloc.dart -DA:9,0 -DA:11,0 -DA:12,0 -DA:14,0 -DA:15,0 -DA:16,0 -DA:18,0 -DA:22,0 -DA:23,0 -DA:24,0 -DA:25,0 -DA:37,0 -DA:44,0 -LF:13 -LH:0 -end_of_record -SF:lib/widgets/choose_cards.dart -DA:18,0 -DA:20,0 -DA:21,0 -DA:27,0 -DA:29,0 -DA:30,0 -DA:31,0 -DA:32,0 -DA:34,0 -DA:37,0 -DA:39,0 -DA:40,0 -DA:42,0 -DA:45,0 -DA:48,0 -DA:50,0 -DA:51,0 -DA:52,0 -DA:57,0 -DA:58,0 -DA:60,0 -DA:61,0 -DA:62,0 -DA:63,0 -DA:64,0 -DA:65,0 -DA:66,0 -DA:67,0 -DA:71,0 -DA:72,0 -DA:73,0 -DA:75,0 -DA:77,0 -DA:78,0 -DA:82,0 -DA:83,0 -DA:85,0 -DA:88,0 -DA:93,0 -DA:111,0 -DA:113,0 -DA:115,0 -DA:117,0 -DA:118,0 -DA:121,0 -DA:122,0 -DA:123,0 -DA:125,0 -DA:130,0 -DA:131,0 -DA:134,0 -DA:135,0 -DA:136,0 -DA:138,0 -LF:54 -LH:0 -end_of_record -SF:lib/utils/archive_decoder.dart -DA:6,0 -DA:8,0 -DA:13,0 -DA:14,0 -DA:15,0 -DA:23,0 -DA:24,0 -DA:25,0 -DA:26,0 -DA:27,0 -DA:29,0 -DA:30,0 -DA:31,0 -DA:34,0 -DA:35,0 -DA:36,0 -DA:37,0 -DA:39,0 -DA:49,0 -LF:19 -LH:0 -end_of_record -SF:lib/features/games/payloads/bridge_webview.dart -DA:12,0 -DA:20,0 -DA:21,0 -DA:25,0 -DA:27,0 -DA:29,0 -DA:32,0 -DA:34,0 -DA:35,0 -DA:36,0 -DA:37,0 -DA:38,0 -DA:41,0 -DA:42,0 -DA:43,0 -DA:44,0 -DA:47,0 -DA:48,0 -DA:49,0 -DA:50,0 -DA:51,0 -DA:52,0 -DA:53,0 -DA:55,0 -DA:56,0 -DA:58,0 -DA:60,0 -DA:61,0 -DA:65,0 -DA:67,0 -LF:30 -LH:0 -end_of_record -SF:lib/features/games/payloads/bridge_webview_controller.dart -DA:14,0 -DA:15,0 -DA:18,0 -DA:19,0 -DA:20,0 -DA:21,0 -DA:24,0 -DA:26,0 -DA:29,0 -DA:30,0 -DA:33,0 -DA:36,0 -DA:37,0 -DA:38,0 -DA:40,0 -DA:45,0 -DA:46,0 -DA:47,0 -DA:51,0 -DA:54,0 -DA:56,0 -DA:58,0 -DA:61,0 -DA:65,0 -DA:66,0 -DA:67,0 -DA:72,0 -DA:73,0 -DA:74,0 -DA:76,0 -DA:79,0 -DA:80,0 -DA:81,0 -DA:82,0 -DA:89,0 -DA:90,0 -DA:91,0 -DA:96,0 -DA:97,0 -DA:98,0 -DA:102,0 -DA:103,0 -DA:107,0 -DA:111,0 -DA:113,0 -DA:114,0 -DA:115,0 -DA:116,0 -DA:117,0 -LF:49 -LH:0 -end_of_record -SF:lib/features/games/payloads/handlers/payload_handlers_manager.dart -DA:9,0 -DA:11,0 -DA:12,0 -DA:15,0 -DA:19,0 -DA:22,0 -DA:23,0 -DA:25,0 -DA:30,0 -DA:37,0 -DA:39,0 -DA:41,0 -DA:47,0 -DA:49,0 -DA:50,0 -DA:51,0 -DA:59,0 -DA:61,0 -DA:64,0 -DA:68,0 -DA:69,0 -DA:76,0 -DA:77,0 -DA:78,0 -DA:79,0 -DA:80,0 -DA:81,0 -DA:82,0 -DA:83,0 -DA:84,0 -DA:88,0 -DA:89,0 -DA:90,0 -DA:91,0 -DA:95,0 -DA:100,0 -DA:101,0 -DA:103,0 -LF:38 -LH:0 -end_of_record -SF:lib/features/games/payloads/registration.dart -DA:5,0 -DA:7,0 -LF:2 -LH:0 -end_of_record -SF:lib/features/games/payloads/handlers/user_cards_handler.dart -DA:7,0 -DA:9,0 -DA:12,0 -DA:14,0 -DA:19,0 -DA:20,0 -DA:27,0 -DA:32,0 -DA:33,0 -DA:41,0 -LF:10 -LH:0 -end_of_record -SF:lib/features/packs/active_pack_state.g.dart -DA:36,0 -DA:40,0 -DA:43,0 -DA:45,0 -DA:46,0 -DA:48,0 -DA:49,0 -DA:51,0 -DA:53,0 -DA:55,0 -DA:69,0 -DA:70,0 -DA:71,0 -DA:74,0 -DA:75,0 -DA:78,0 -DA:79,0 -DA:83,0 -DA:84,0 -DA:94,0 -DA:95,0 -LF:21 -LH:0 -end_of_record -SF:lib/features/packs/active_pack_state.dart -DA:14,1 -DA:22,0 -DA:27,0 -DA:28,0 -DA:36,0 -DA:37,0 -DA:45,0 -DA:46,0 -LF:8 -LH:1 -end_of_record -SF:lib/flags.dart -DA:12,1 -DA:14,0 -DA:15,0 -DA:18,0 -DA:20,0 -DA:21,0 -DA:22,0 -DA:23,0 -DA:25,0 -LF:9 -LH:1 -end_of_record -SF:lib/managers/user_state_holder.dart -DA:14,0 -DA:16,0 -DA:18,0 -DA:20,0 -DA:21,0 -DA:22,0 -DA:24,0 -DA:25,0 -DA:28,0 -DA:29,0 -DA:30,0 -DA:31,0 -DA:34,0 -DA:36,0 -DA:37,0 -DA:39,0 -LF:16 -LH:0 -end_of_record -SF:lib/features/subscription/subscription_page.dart -DA:13,0 -DA:15,0 -DA:17,0 -DA:18,0 -DA:19,0 -DA:20,0 -DA:21,0 -DA:22,0 -DA:25,0 -DA:26,0 -DA:27,0 -DA:31,0 -DA:41,0 -DA:43,0 -DA:45,0 -DA:46,0 -DA:47,0 -DA:48,0 -DA:49,0 -DA:50,0 -DA:52,0 -DA:53,0 -DA:54,0 -DA:55,0 -DA:56,0 -DA:57,0 -DA:58,0 -DA:59,0 -DA:60,0 -DA:62,0 -DA:63,0 -DA:64,0 -DA:65,0 -DA:66,0 -DA:68,0 -DA:70,0 -DA:71,0 -DA:72,0 -DA:73,0 -DA:74,0 -DA:80,0 -DA:81,0 -DA:82,0 -DA:83,0 -DA:85,0 -DA:86,0 -DA:87,0 -DA:88,0 -DA:90,0 -DA:91,0 -DA:92,0 -DA:93,0 -DA:102,0 -DA:103,0 -DA:106,0 -DA:107,0 -DA:108,0 -DA:109,0 -DA:110,0 -DA:111,0 -DA:112,0 -DA:113,0 -DA:115,0 -DA:116,0 -DA:117,0 -DA:118,0 -DA:123,0 -DA:127,0 -DA:128,0 -DA:129,0 -DA:130,0 -DA:131,0 -DA:132,0 -DA:133,0 -DA:140,0 -DA:141,0 -DA:142,0 -DA:143,0 -DA:144,0 -DA:145,0 -DA:146,0 -DA:157,0 -DA:158,0 -DA:159,0 -DA:162,0 -DA:163,0 -DA:164,0 -DA:165,0 -DA:166,0 -DA:167,0 -DA:169,0 -DA:170,0 -DA:171,0 -DA:175,0 -DA:177,0 -DA:179,0 -DA:185,0 -LF:97 -LH:0 -end_of_record -SF:lib/features/tests/progress_widget.dart -DA:17,0 -DA:18,0 -DA:20,0 -DA:21,0 -DA:22,0 -DA:24,0 -DA:30,0 -DA:51,0 -DA:53,0 -DA:55,0 -DA:57,0 -DA:58,0 -DA:59,0 -DA:60,0 -DA:62,0 -DA:63,0 -DA:64,0 -DA:65,0 -DA:66,0 -DA:68,0 -DA:70,0 -DA:72,0 -DA:73,0 -DA:75,0 -DA:76,0 -DA:77,0 -DA:87,0 -DA:88,0 -DA:89,0 -DA:90,0 -DA:91,0 -DA:92,0 -DA:93,0 -DA:94,0 -DA:95,0 -DA:96,0 -DA:97,0 -DA:99,0 -DA:100,0 -DA:101,0 -DA:102,0 -DA:103,0 -DA:105,0 -DA:107,0 -DA:108,0 -DA:109,0 -DA:110,0 -DA:111,0 -DA:112,0 -DA:113,0 -DA:114,0 -DA:126,0 -DA:127,0 -DA:128,0 -DA:129,0 -DA:131,0 -DA:132,0 -DA:133,0 -DA:136,0 -DA:137,0 -DA:138,0 -DA:139,0 -DA:141,0 -DA:142,0 -DA:143,0 -DA:146,0 -DA:147,0 -DA:148,0 -DA:149,0 -DA:155,0 -DA:156,0 -DA:157,0 -DA:158,0 -DA:159,0 -DA:160,0 -DA:166,0 -DA:172,0 -DA:174,0 -DA:176,0 -DA:177,0 -DA:178,0 -DA:179,0 -DA:180,0 -DA:182,0 -DA:183,0 -DA:184,0 -DA:186,0 -DA:188,0 -DA:191,0 -DA:192,0 -DA:194,0 -DA:195,0 -DA:196,0 -DA:198,0 -DA:199,0 -DA:201,0 -DA:203,0 -LF:97 -LH:0 -end_of_record -SF:lib/features/tests/question_states/input_buttons_test_state.dart -DA:19,0 -LF:1 -LH:0 -end_of_record -SF:lib/features/tests/question_states/input_buttons_test_state.g.dart -DA:47,0 -DA:51,0 -DA:52,0 -DA:54,0 -DA:55,0 -DA:57,0 -DA:58,0 -DA:60,0 -DA:62,0 -DA:64,0 -DA:65,0 -DA:67,0 -DA:69,0 -DA:71,0 -DA:72,0 -DA:74,0 -DA:76,0 -DA:78,0 -DA:96,0 -DA:97,0 -DA:98,0 -DA:101,0 -DA:102,0 -DA:105,0 -DA:106,0 -DA:109,0 -DA:110,0 -DA:113,0 -DA:114,0 -DA:118,0 -DA:119,0 -DA:122,0 -DA:123,0 -DA:126,0 -DA:127,0 -DA:137,0 -DA:138,0 -DA:145,0 -DA:147,0 -DA:148,0 -DA:149,0 -DA:150,0 -DA:151,0 -DA:152,0 -DA:154,0 -DA:155,0 -DA:156,0 -DA:158,0 -DA:159,0 -DA:160,0 -DA:162,0 -DA:166,0 -DA:168,0 -DA:169,0 -DA:170,0 -DA:171,0 -DA:172,0 -DA:173,0 -DA:174,0 -DA:175,0 -DA:176,0 -LF:61 -LH:0 -end_of_record -SF:lib/features/tests/question_states/test_question_state.g.dart -DA:34,0 -DA:38,0 -DA:40,0 -DA:42,0 -DA:43,0 -DA:45,0 -DA:46,0 -DA:48,0 -DA:49,0 -DA:51,0 -DA:65,0 -DA:66,0 -DA:67,0 -DA:70,0 -DA:71,0 -DA:75,0 -DA:76,0 -DA:79,0 -DA:80,0 -DA:90,0 -DA:91,0 -LF:21 -LH:0 -end_of_record -SF:lib/features/tests/question_states/test_question_state.dart -DA:10,0 -DA:17,0 -LF:2 -LH:0 -end_of_record -SF:lib/features/tests/question_states/simple_test_state.dart -DA:18,0 -LF:1 -LH:0 -end_of_record -SF:lib/features/tests/question_states/simple_test_state.g.dart -DA:43,0 -DA:47,0 -DA:48,0 -DA:50,0 -DA:51,0 -DA:53,0 -DA:54,0 -DA:56,0 -DA:57,0 -DA:59,0 -DA:60,0 -DA:62,0 -DA:63,0 -DA:65,0 -DA:67,0 -DA:69,0 -DA:86,0 -DA:87,0 -DA:88,0 -DA:91,0 -DA:92,0 -DA:95,0 -DA:96,0 -DA:99,0 -DA:100,0 -DA:104,0 -DA:105,0 -DA:108,0 -DA:109,0 -DA:112,0 -DA:113,0 -DA:123,0 -DA:130,0 -DA:131,0 -DA:132,0 -DA:133,0 -DA:134,0 -DA:135,0 -DA:136,0 -DA:137,0 -DA:139,0 -DA:143,0 -DA:144,0 -DA:145,0 -DA:146,0 -DA:147,0 -DA:148,0 -DA:149,0 -DA:150,0 -DA:151,0 -LF:50 -LH:0 -end_of_record -SF:lib/features/tests/scroll_physics.dart -DA:23,0 -DA:28,0 -DA:30,0 -DA:32,0 -DA:33,0 -DA:34,0 -DA:35,0 -DA:39,0 -DA:40,0 -DA:42,0 -DA:43,0 -DA:45,0 -DA:47,0 -DA:48,0 -DA:49,0 -DA:50,0 -DA:52,0 -DA:61,0 -DA:63,0 -DA:64,0 -DA:65,0 -DA:68,0 -DA:69,0 -DA:71,0 -DA:74,0 -DA:75,0 -DA:77,0 -DA:80,0 -DA:81,0 -DA:83,0 -DA:87,0 -DA:88,0 -DA:89,0 -DA:93,0 -DA:94,0 -DA:97,0 -DA:98,0 -DA:106,0 -DA:107,0 -DA:114,0 -DA:118,0 -DA:133,0 -DA:135,0 -DA:137,0 -DA:139,0 -DA:140,0 -DA:156,0 -DA:159,0 -DA:161,0 -DA:163,0 -DA:164,0 -LF:51 -LH:0 -end_of_record -SF:lib/features/tests/test_complete_widget.dart -DA:17,0 -DA:19,0 -DA:24,0 -DA:26,0 -DA:27,0 -DA:28,0 -DA:29,0 -DA:31,0 -DA:32,0 -DA:33,0 -DA:34,0 -DA:35,0 -DA:36,0 -DA:38,0 -DA:39,0 -DA:40,0 -DA:41,0 -DA:42,0 -DA:44,0 -DA:45,0 -DA:47,0 -DA:51,0 -DA:52,0 -DA:53,0 -DA:55,0 -DA:57,0 -DA:59,0 -DA:60,0 -DA:61,0 -DA:62,0 -DA:64,0 -DA:65,0 -DA:66,0 -DA:68,0 -DA:69,0 -DA:70,0 -DA:71,0 -DA:72,0 -DA:73,0 -DA:74,0 -DA:75,0 -DA:80,0 -DA:81,0 -DA:82,0 -DA:83,0 -DA:85,0 -DA:86,0 -DA:88,0 -DA:89,0 -DA:92,0 -DA:93,0 -DA:95,0 -DA:96,0 -DA:98,0 -DA:99,0 -DA:102,0 -DA:103,0 -DA:105,0 -DA:106,0 -DA:108,0 -DA:109,0 -DA:117,0 -DA:118,0 -DA:119,0 -DA:136,0 -DA:138,0 -DA:140,0 -DA:142,0 -DA:143,0 -DA:144,0 -DA:145,0 -DA:150,0 -DA:152,0 -DA:153,0 -DA:154,0 -DA:155,0 -DA:160,0 -DA:161,0 -DA:162,0 -DA:163,0 -DA:164,0 -DA:165,0 -DA:166,0 -DA:189,0 -DA:191,0 -DA:193,0 -DA:195,0 -DA:196,0 -DA:197,0 -DA:198,0 -DA:201,0 -DA:202,0 -DA:203,0 -DA:204,0 -LF:94 -LH:0 -end_of_record -SF:lib/utils/color_helper.dart -DA:4,0 -DA:5,0 -DA:7,0 -DA:8,0 -DA:10,0 -DA:13,0 -DA:14,0 -DA:16,0 -DA:18,0 -DA:20,0 -LF:10 -LH:0 -end_of_record -SF:lib/features/tests/test_state_holder.dart -DA:13,0 -DA:15,0 -DA:16,0 -DA:17,0 -DA:18,0 -DA:19,0 -DA:21,0 -DA:22,0 -DA:24,0 -DA:26,0 -DA:27,0 -DA:29,0 -DA:32,0 -DA:35,0 -DA:37,0 -DA:43,0 -DA:44,0 -DA:45,0 -DA:46,0 -DA:47,0 -DA:52,0 -DA:53,0 -DA:56,0 -DA:60,0 -DA:61,0 -DA:62,0 -DA:63,0 -DA:64,0 -DA:65,0 -DA:67,0 -DA:69,0 -DA:70,0 -DA:72,0 -DA:74,0 -DA:75,0 -DA:76,0 -DA:80,0 -DA:83,0 -DA:85,0 -DA:87,0 -DA:88,0 -DA:95,0 -DA:97,0 -DA:99,0 -LF:44 -LH:0 -end_of_record -SF:lib/features/tests/test_widgets/test_image.dart -DA:14,0 -DA:16,0 -DA:17,0 -DA:21,0 -DA:25,0 -DA:27,0 -DA:28,0 -DA:31,0 -DA:38,0 -DA:40,0 -DA:43,0 -DA:45,0 -DA:47,0 -DA:50,0 -DA:53,0 -DA:54,0 -DA:56,0 -DA:57,0 -DA:59,0 -DA:60,0 -DA:61,0 -DA:65,0 -DA:67,0 -DA:68,0 -DA:69,0 -DA:71,0 -DA:73,0 -DA:83,0 -DA:88,0 -DA:90,0 -DA:93,0 -DA:94,0 -DA:97,0 -DA:98,0 -DA:100,0 -DA:103,0 -DA:104,0 -DA:105,0 -DA:106,0 -DA:108,0 -DA:112,0 -DA:114,0 -LF:42 -LH:0 -end_of_record -SF:lib/features/tests/test_progress_widget.dart -DA:11,0 -DA:12,0 -DA:14,1 -DA:25,0 -DA:26,0 -DA:27,0 -DA:28,0 -DA:32,0 -DA:33,0 -DA:36,0 -DA:37,0 -DA:38,0 -DA:39,0 -DA:40,0 -DA:41,0 -DA:44,0 -DA:46,0 -DA:47,0 -DA:49,0 -DA:52,0 -DA:53,0 -DA:54,0 -DA:56,0 -DA:59,0 -DA:61,0 -DA:62,0 -DA:63,0 -DA:68,0 -DA:71,0 -DA:73,0 -DA:74,0 -DA:75,0 -DA:76,0 -DA:77,0 -LF:34 -LH:1 -end_of_record -SF:lib/features/tests/test_widgets/input_buttons_test.dart -DA:16,0 -DA:18,0 -DA:19,0 -DA:21,0 -DA:23,0 -DA:25,0 -DA:27,0 -DA:28,0 -DA:29,0 -DA:30,0 -DA:31,0 -DA:33,0 -DA:34,0 -DA:35,0 -DA:37,0 -DA:38,0 -DA:40,0 -DA:41,0 -DA:42,0 -DA:43,0 -DA:46,0 -DA:48,0 -DA:50,0 -DA:51,0 -DA:69,0 -DA:70,0 -DA:72,0 -DA:73,0 -DA:75,0 -DA:77,0 -DA:79,0 -DA:80,0 -DA:82,0 -DA:83,0 -DA:86,0 -DA:87,0 -DA:88,0 -DA:89,0 -DA:90,0 -DA:92,0 -DA:97,0 -DA:99,0 -DA:100,0 -DA:101,0 -DA:106,0 -DA:108,0 -DA:109,0 -DA:110,0 -DA:111,0 -DA:112,0 -DA:113,0 -DA:114,0 -DA:117,0 -DA:118,0 -DA:119,0 -DA:120,0 -DA:121,0 -DA:122,0 -DA:124,0 -DA:125,0 -DA:126,0 -DA:127,0 -DA:129,0 -DA:132,0 -DA:137,0 -DA:138,0 -DA:139,0 -DA:141,0 -DA:143,0 -DA:146,0 -DA:148,0 -DA:152,0 -DA:153,0 -DA:154,0 -DA:155,0 -DA:156,0 -DA:157,0 -DA:158,0 -DA:159,0 -DA:160,0 -DA:161,0 -DA:164,0 -DA:165,0 -DA:166,0 -DA:175,0 -DA:183,0 -DA:186,0 -DA:187,0 -DA:188,0 -DA:190,0 -DA:191,0 -DA:192,0 -DA:193,0 -DA:195,0 -DA:197,0 -DA:198,0 -DA:200,0 -DA:202,0 -DA:203,0 -DA:204,0 -DA:205,0 -DA:206,0 -DA:207,0 -DA:208,0 -DA:209,0 -DA:213,0 -DA:222,0 -DA:224,0 -DA:225,0 -DA:226,0 -DA:227,0 -DA:229,0 -DA:231,0 -DA:232,0 -DA:234,0 -DA:237,0 -DA:238,0 -DA:244,0 -DA:260,0 -DA:270,0 -DA:274,0 -DA:276,0 -DA:283,0 -DA:285,0 -DA:286,0 -DA:289,0 -DA:290,0 -DA:291,0 -DA:293,0 -DA:294,0 -DA:295,0 -DA:296,0 -DA:298,0 -DA:299,0 -DA:300,0 -DA:301,0 -DA:302,0 -LF:137 -LH:0 -end_of_record -SF:lib/features/tests/test_widgets/simple_test.dart -DA:17,0 -DA:19,0 -DA:21,0 -DA:23,0 -DA:25,0 -DA:27,0 -DA:29,0 -DA:31,0 -DA:32,0 -DA:34,0 -DA:35,0 -DA:37,0 -DA:39,0 -DA:40,0 -DA:41,0 -DA:42,0 -DA:43,0 -DA:44,0 -DA:47,0 -DA:50,0 -DA:51,0 -DA:52,0 -DA:53,0 -DA:54,0 -DA:55,0 -DA:60,0 -DA:61,0 -DA:62,0 -DA:64,0 -DA:68,0 -DA:69,0 -DA:70,0 -DA:71,0 -DA:76,0 -DA:77,0 -DA:80,0 -DA:81,0 -DA:84,0 -DA:85,0 -DA:86,0 -DA:90,0 -DA:91,0 -DA:92,0 -DA:93,0 -DA:94,0 -DA:95,0 -DA:96,0 -DA:97,0 -DA:98,0 -DA:101,0 -DA:102,0 -DA:103,0 -DA:104,0 -DA:105,0 -DA:108,0 -DA:111,0 -DA:112,0 -DA:113,0 -DA:114,0 -DA:117,0 -DA:118,0 -DA:119,0 -DA:120,0 -DA:121,0 -DA:125,0 -LF:65 -LH:0 -end_of_record -SF:lib/features/tests/test_widgets/common_test_question_widget.dart -DA:14,0 -DA:21,0 -DA:23,0 -DA:25,0 -DA:27,0 -DA:28,0 -DA:29,0 -DA:30,0 -DA:33,0 -DA:35,0 -DA:37,0 -DA:38,0 -DA:39,0 -DA:41,0 -DA:42,0 -DA:43,0 -DA:45,0 -DA:46,0 -DA:47,0 -DA:49,0 -DA:50,0 -DA:53,0 -DA:55,0 -DA:63,0 -DA:64,0 -DA:65,0 -DA:66,0 -DA:67,0 -DA:71,0 -DA:73,0 -DA:77,0 -DA:78,0 -DA:81,0 -DA:84,0 -DA:85,0 -DA:86,0 -DA:87,0 -DA:89,0 -DA:90,0 -DA:91,0 -DA:92,0 -DA:93,0 -DA:96,0 -DA:97,0 -DA:99,0 -DA:105,0 -DA:106,0 -DA:109,0 -DA:110,0 -DA:111,0 -LF:50 -LH:0 -end_of_record -SF:lib/widgets/game_card_widget.dart -DA:28,0 -DA:38,0 -DA:39,0 -DA:47,0 -DA:49,0 -DA:50,0 -DA:51,0 -DA:52,0 -DA:53,0 -DA:54,0 -DA:55,0 -DA:56,0 -DA:58,0 -DA:60,0 -DA:62,0 -DA:63,0 -DA:64,0 -DA:66,0 -DA:67,0 -DA:70,0 -DA:71,0 -DA:73,0 -DA:74,0 -DA:75,0 -DA:77,0 -DA:81,0 -DA:82,0 -DA:83,0 -DA:85,0 -DA:91,0 -DA:93,0 -DA:95,0 -DA:96,0 -DA:98,0 -DA:99,0 -DA:103,0 -DA:104,0 -DA:106,0 -DA:107,0 -DA:108,0 -DA:110,0 -DA:111,0 -DA:113,0 -DA:114,0 -DA:115,0 -DA:116,0 -DA:117,0 -DA:120,0 -DA:122,0 -DA:126,0 -DA:127,0 -DA:129,0 -DA:130,0 -DA:132,0 -DA:133,0 -DA:137,0 -DA:141,0 -DA:154,0 -DA:156,0 -DA:158,0 -DA:159,0 -DA:160,0 -DA:162,0 -DA:165,0 -DA:167,0 -DA:168,0 -DA:169,0 -DA:170,0 -DA:184,0 -DA:186,0 -DA:188,0 -DA:189,0 -DA:190,0 -DA:191,0 -DA:192,0 -DA:193,0 -DA:194,0 -DA:197,0 -DA:198,0 -DA:199,0 -DA:201,0 -DA:203,0 -DA:204,0 -DA:207,0 -DA:209,0 -DA:210,0 -DA:211,0 -DA:212,0 -DA:214,0 -DA:216,0 -DA:219,0 -DA:220,0 -DA:221,0 -DA:222,0 -DA:223,0 -DA:224,0 -DA:225,0 -DA:226,0 -DA:231,0 -DA:232,0 -DA:233,0 -DA:234,0 -DA:240,0 -DA:241,0 -DA:242,0 -DA:243,0 -DA:244,0 -DA:245,0 -DA:251,0 -DA:252,0 -DA:253,0 -DA:254,0 -DA:256,0 -DA:257,0 -DA:262,0 -DA:263,0 -DA:264,0 -DA:265,0 -DA:266,0 -DA:267,0 -DA:268,0 -DA:269,0 -DA:270,0 -DA:271,0 -DA:272,0 -DA:273,0 -DA:278,0 -DA:279,0 -DA:280,0 -DA:281,0 -DA:292,0 -DA:293,0 -DA:294,0 -DA:296,0 -DA:297,0 -DA:298,0 -DA:299,0 -DA:300,0 -DA:304,0 -DA:305,0 -DA:306,0 -DA:313,0 -DA:314,0 -DA:315,0 -DA:318,0 -DA:319,0 -DA:323,0 -DA:324,0 -DA:325,0 -DA:327,0 -DA:328,0 -DA:336,0 -DA:337,0 -DA:338,0 -DA:341,0 -DA:343,0 -DA:344,0 -DA:345,0 -DA:352,0 -DA:353,0 -DA:354,0 -DA:355,0 -DA:358,0 -DA:359,0 -DA:360,0 -DA:362,0 -DA:363,0 -DA:367,0 -DA:368,0 -DA:369,0 -DA:370,0 -DA:371,0 -DA:373,0 -DA:374,0 -DA:376,0 -DA:377,0 -DA:379,0 -DA:380,0 -DA:381,0 -LF:179 -LH:0 -end_of_record -SF:lib/features/tests/test_widgets/test_button.dart -DA:13,0 -DA:22,0 -DA:24,0 -DA:25,0 -DA:26,0 -DA:27,0 -DA:28,0 -DA:29,0 -DA:31,0 -DA:32,0 -DA:34,0 -DA:42,0 -DA:44,0 -DA:46,0 -DA:48,0 -DA:49,0 -DA:50,0 -DA:51,0 -DA:52,0 -DA:54,0 -DA:55,0 -DA:58,0 -DA:59,0 -DA:60,0 -DA:62,0 -LF:25 -LH:0 -end_of_record -SF:lib/features/vocabulary/cubit/vocabulary_cubit.dart -DA:10,0 -DA:13,0 -DA:14,0 -DA:18,0 -DA:19,0 -DA:22,0 -DA:24,0 -DA:27,0 -DA:29,0 -DA:30,0 -DA:38,0 -DA:43,0 -DA:46,0 -DA:47,0 -DA:49,0 -DA:54,0 -DA:65,0 -DA:66,0 -DA:70,0 -DA:71,0 -DA:75,0 -DA:76,0 -DA:77,0 -DA:78,0 -DA:81,0 -DA:83,0 -DA:87,0 -DA:89,0 -DA:93,0 -DA:94,0 -DA:98,0 -DA:102,0 -DA:104,0 -DA:105,0 -DA:106,0 -DA:107,0 -DA:115,0 -DA:116,0 -DA:117,0 -DA:119,0 -DA:122,0 -DA:125,0 -DA:129,0 -DA:130,0 -DA:131,0 -DA:135,0 -DA:136,0 -DA:137,0 -DA:138,0 -DA:139,0 -DA:140,0 -DA:141,0 -DA:142,0 -DA:150,0 -DA:153,0 -DA:154,0 -DA:155,0 -DA:156,0 -DA:163,0 -DA:164,0 -DA:165,0 -DA:167,0 -DA:169,0 -DA:171,0 -DA:173,0 -LF:65 -LH:0 -end_of_record -SF:lib/features/vocabulary/models/vocabulary_page_state.dart -DA:14,1 -DA:24,0 -DA:33,0 -DA:34,0 -DA:35,0 -DA:36,0 -DA:37,0 -DA:38,0 -DA:39,0 -DA:40,0 -DA:45,0 -DA:46,0 -DA:47,0 -DA:51,0 -DA:55,0 -DA:56,0 -DA:57,0 -DA:58,0 -DA:62,0 -DA:63,0 -DA:65,0 -DA:66,0 -DA:67,0 -DA:68,0 -DA:69,0 -DA:73,0 -DA:74,0 -DA:78,0 -DA:79,0 -DA:83,0 -DA:84,0 -DA:85,0 -DA:88,0 -DA:91,0 -DA:92,0 -DA:93,0 -DA:94,0 -DA:95,0 -DA:96,0 -DA:97,0 -DA:98,0 -DA:101,0 -DA:103,0 -DA:104,0 -DA:105,0 -DA:106,0 -DA:107,0 -DA:108,0 -DA:109,0 -LF:49 -LH:1 -end_of_record -SF:lib/features/vocabulary/models/vocabulary_word.dart -DA:13,0 -DA:21,0 -DA:24,0 -DA:27,0 -DA:30,0 -DA:33,0 -DA:36,0 -DA:37,0 -DA:38,0 -DA:39,0 -DA:43,0 -DA:44,0 -DA:47,0 -DA:48,0 -DA:52,0 -DA:53,0 -DA:54,0 -DA:58,0 -DA:61,0 -DA:63,0 -DA:69,0 -DA:70,0 -DA:71,0 -DA:72,0 -DA:73,0 -DA:78,0 -DA:79,0 -DA:82,0 -DA:85,0 -DA:86,0 -DA:87,0 -DA:88,0 -DA:91,0 -DA:93,0 -LF:34 -LH:0 -end_of_record -SF:lib/features/vocabulary/models/vocabulary_category.dart -DA:13,0 -DA:22,0 -DA:30,0 -DA:31,0 -DA:32,0 -DA:33,0 -DA:34,0 -DA:35,0 -DA:36,0 -DA:41,0 -DA:42,0 -DA:45,0 -DA:46,0 -DA:47,0 -DA:51,0 -DA:52,0 -DA:53,0 -DA:54,0 -DA:57,0 -DA:59,0 -DA:62,0 -DA:65,0 -DA:66,0 -DA:67,0 -DA:68,0 -DA:69,0 -DA:72,0 -DA:74,0 -DA:75,0 -DA:76,0 -DA:77,0 -LF:31 -LH:0 -end_of_record -SF:lib/features/vocabulary/models/word_difficulty.dart -DA:10,0 -DA:12,0 -DA:14,0 -DA:16,0 -DA:21,0 -DA:23,0 -DA:25,0 -DA:27,0 -DA:34,0 -DA:35,0 -DA:37,0 -LF:11 -LH:0 -end_of_record -SF:lib/features/vocabulary/pages/vocabulary_page.dart -DA:16,0 -DA:18,0 -DA:19,0 -DA:27,0 -DA:29,0 -DA:30,0 -DA:31,0 -DA:32,0 -DA:33,0 -DA:34,0 -DA:37,0 -DA:40,0 -DA:42,0 -DA:43,0 -DA:44,0 -DA:47,0 -DA:48,0 -DA:49,0 -DA:50,0 -DA:51,0 -DA:55,0 -DA:57,0 -DA:58,0 -DA:59,0 -DA:60,0 -DA:62,0 -DA:63,0 -DA:64,0 -DA:65,0 -DA:66,0 -DA:67,0 -DA:69,0 -DA:70,0 -DA:76,0 -DA:77,0 -DA:78,0 -DA:82,0 -DA:83,0 -DA:84,0 -DA:86,0 -DA:87,0 -DA:88,0 -DA:89,0 -DA:91,0 -DA:92,0 -DA:96,0 -DA:97,0 -DA:98,0 -DA:100,0 -DA:101,0 -DA:102,0 -DA:105,0 -DA:106,0 -DA:107,0 -DA:115,0 -DA:116,0 -DA:117,0 -DA:118,0 -DA:119,0 -DA:121,0 -DA:122,0 -DA:123,0 -DA:124,0 -DA:126,0 -DA:127,0 -DA:128,0 -DA:129,0 -DA:131,0 -DA:132,0 -DA:133,0 -DA:134,0 -DA:135,0 -DA:137,0 -DA:138,0 -DA:139,0 -DA:140,0 -DA:141,0 -DA:143,0 -DA:144,0 -LF:79 -LH:0 -end_of_record -SF:lib/features/vocabulary/widgets/vocabulary_header.dart -DA:8,0 -DA:15,0 -DA:16,0 -DA:18,0 -DA:19,0 -DA:20,0 -DA:21,0 -DA:22,0 -DA:24,0 -DA:28,0 -DA:30,0 -DA:32,0 -DA:33,0 -DA:34,0 -DA:36,0 -DA:37,0 -DA:38,0 -DA:39,0 -LF:18 -LH:0 -end_of_record -SF:lib/features/vocabulary/widgets/vocabulary_search_bar.dart -DA:7,0 -DA:12,0 -DA:13,0 -DA:20,0 -DA:22,0 -DA:23,0 -DA:26,0 -DA:28,0 -DA:29,0 -DA:32,0 -DA:33,0 -DA:34,0 -DA:35,0 -DA:39,0 -DA:40,0 -DA:41,0 -DA:44,0 -DA:46,0 -DA:47,0 -DA:48,0 -DA:49,0 -DA:50,0 -DA:51,0 -DA:53,0 -DA:54,0 -DA:55,0 -DA:56,0 -DA:58,0 -DA:59,0 -DA:60,0 -DA:62,0 -DA:64,0 -DA:65,0 -DA:67,0 -DA:68,0 -DA:69,0 -DA:71,0 -DA:72,0 -DA:74,0 -DA:78,0 -DA:79,0 -DA:80,0 -DA:83,0 -DA:84,0 -LF:44 -LH:0 -end_of_record -SF:lib/features/vocabulary/widgets/vocabulary_categories.dart -DA:10,0 -DA:17,0 -DA:19,0 -DA:23,0 -DA:25,0 -DA:26,0 -DA:28,0 -DA:29,0 -DA:33,0 -DA:34,0 -DA:35,0 -DA:36,0 -DA:38,0 -DA:39,0 -DA:40,0 -DA:41,0 -DA:44,0 -DA:45,0 -DA:53,0 -DA:54,0 -DA:56,0 -DA:57,0 -DA:58,0 -DA:59,0 -DA:60,0 -DA:62,0 -DA:63,0 -DA:64,0 -DA:65,0 -DA:66,0 -DA:67,0 -DA:71,0 -DA:73,0 -DA:74,0 -DA:76,0 -DA:77,0 -DA:79,0 -DA:80,0 -DA:82,0 -DA:83,0 -DA:85,0 -DA:95,0 -DA:96,0 -DA:98,0 -DA:99,0 -DA:100,0 -DA:101,0 -DA:102,0 -DA:104,0 -DA:105,0 -DA:106,0 -DA:107,0 -DA:108,0 -DA:109,0 -DA:113,0 -DA:115,0 -DA:116,0 -DA:117,0 -DA:118,0 -DA:119,0 -DA:121,0 -DA:122,0 -DA:123,0 -DA:124,0 -DA:125,0 -DA:127,0 -DA:130,0 -DA:131,0 -DA:132,0 -DA:133,0 -DA:135,0 -DA:136,0 -DA:137,0 -DA:139,0 -DA:140,0 -DA:141,0 -DA:142,0 -DA:144,0 -LF:78 -LH:0 -end_of_record -SF:lib/features/vocabulary/widgets/vocabulary_progress.dart -DA:10,0 -DA:17,0 -DA:19,0 -DA:20,0 -DA:21,0 -DA:23,0 -DA:24,0 -DA:25,0 -DA:26,0 -DA:32,0 -DA:34,0 -DA:35,0 -DA:36,0 -DA:37,0 -DA:38,0 -DA:42,0 -DA:43,0 -DA:44,0 -DA:45,0 -DA:46,0 -DA:49,0 -LF:21 -LH:0 -end_of_record -SF:lib/features/vocabulary/widgets/vocabulary_words_list.dart -DA:9,0 -DA:14,0 -DA:16,0 -DA:17,0 -DA:18,0 -DA:20,0 -DA:21,0 -DA:23,0 -DA:24,0 -DA:26,0 -DA:27,0 -DA:30,0 -DA:31,0 -DA:32,0 -DA:35,0 -DA:36,0 -DA:39,0 -DA:40,0 -DA:41,0 -DA:49,0 -DA:51,0 -DA:52,0 -DA:53,0 -DA:54,0 -DA:55,0 -DA:59,0 -DA:60,0 -DA:63,0 -DA:64,0 -DA:65,0 -DA:66,0 -DA:67,0 -DA:69,0 -DA:70,0 -LF:34 -LH:0 -end_of_record -SF:lib/features/vocabulary/widgets/vocabulary_word_card.dart -DA:15,0 -DA:22,0 -DA:24,0 -DA:26,0 -DA:27,0 -DA:28,0 -DA:29,0 -DA:30,0 -DA:31,0 -DA:35,0 -DA:36,0 -DA:38,0 -DA:39,0 -DA:42,0 -DA:45,0 -DA:46,0 -DA:47,0 -DA:48,0 -DA:55,0 -DA:56,0 -DA:57,0 -DA:58,0 -DA:59,0 -DA:60,0 -DA:61,0 -DA:64,0 -DA:65,0 -DA:69,0 -DA:70,0 -DA:72,0 -DA:74,0 -DA:75,0 -DA:76,0 -DA:77,0 -DA:78,0 -DA:79,0 -DA:81,0 -DA:82,0 -DA:89,0 -DA:93,0 -DA:94,0 -DA:95,0 -DA:98,0 -DA:101,0 -DA:102,0 -DA:103,0 -LF:46 -LH:0 -end_of_record -SF:lib/features/vocabulary/widgets/difficulty_chart.dart -DA:11,0 -DA:18,0 -DA:20,0 -DA:21,0 -DA:22,0 -DA:23,0 -DA:24,0 -DA:33,0 -DA:35,0 -DA:37,0 -DA:38,0 -DA:39,0 -DA:40,0 -DA:41,0 -DA:43,0 -DA:46,0 -DA:47,0 -DA:48,0 -DA:50,0 -DA:51,0 -DA:53,0 -DA:54,0 -DA:58,0 -DA:61,0 -DA:63,0 -DA:64,0 -DA:66,0 -DA:68,0 -DA:69,0 -DA:70,0 -DA:71,0 -DA:73,0 -DA:78,0 -DA:80,0 -DA:81,0 -DA:83,0 -DA:85,0 -DA:86,0 -DA:87,0 -DA:88,0 -DA:90,0 -DA:95,0 -DA:97,0 -DA:98,0 -DA:100,0 -DA:102,0 -DA:103,0 -DA:104,0 -DA:105,0 -DA:107,0 -DA:112,0 -DA:114,0 -DA:115,0 -LF:53 -LH:0 -end_of_record -SF:lib/features/yandex_ads/yandex_ads.dart -DA:13,0 -DA:19,0 -DA:22,0 -DA:23,0 -DA:24,0 -DA:27,0 -DA:28,0 -DA:29,0 -DA:31,0 -DA:35,0 -DA:38,0 -DA:41,0 -DA:44,0 -LF:13 -LH:0 -end_of_record -SF:lib/firebase_options.dart -DA:18,0 -DA:22,0 -DA:23,0 -DA:25,0 -DA:27,0 -DA:29,0 -DA:30,0 -DA:34,0 -DA:35,0 -DA:40,0 -LF:10 -LH:0 -end_of_record -SF:lib/managers/repository/firebase_config_repository.dart -DA:5,0 -DA:9,0 -DA:14,0 -DA:15,0 -DA:16,0 -DA:17,0 -DA:18,0 -DA:19,0 -DA:20,0 -DA:27,0 -LF:10 -LH:0 -end_of_record -SF:lib/managers/remote_config_manager.dart -DA:6,0 -DA:8,0 -DA:10,0 -DA:18,0 -DA:20,0 -DA:21,0 -DA:23,0 -DA:26,0 -DA:27,0 -DA:34,0 -DA:35,0 -DA:40,0 -DA:41,0 -DA:42,0 -DA:45,0 -DA:46,0 -DA:50,0 -DA:53,0 -DA:57,0 -DA:58,0 -DA:59,0 -DA:64,0 -DA:65,0 -DA:68,0 -DA:69,0 -DA:73,0 -DA:78,0 -DA:80,0 -DA:81,0 -DA:82,0 -DA:85,0 -DA:87,0 -LF:32 -LH:0 -end_of_record -SF:lib/managers/repository/dio_throttler.dart -DA:25,0 -DA:27,0 -DA:29,0 -DA:30,0 -DA:34,0 -DA:35,0 -DA:36,0 -DA:38,0 -DA:40,0 -DA:44,0 -DA:47,0 -DA:49,0 -DA:50,0 -DA:51,0 -DA:52,0 -DA:55,0 -LF:16 -LH:0 -end_of_record -SF:lib/widgets/shared_pref_button.dart -DA:16,0 -DA:24,0 -DA:32,0 -DA:33,0 -DA:34,0 -DA:35,0 -DA:36,0 -DA:37,0 -DA:38,0 -DA:39,0 -LF:10 -LH:0 -end_of_record -SF:lib/widgets/packs_menu_widget.dart -DA:22,0 -DA:29,0 -DA:30,0 -DA:34,0 -DA:36,0 -DA:38,0 -DA:39,0 -DA:40,0 -DA:41,0 -DA:42,0 -DA:46,0 -DA:48,0 -DA:53,0 -DA:54,0 -DA:55,0 -DA:56,0 -DA:57,0 -DA:58,0 -DA:59,0 -DA:60,0 -DA:61,0 -DA:63,0 -DA:64,0 -DA:65,0 -DA:67,0 -DA:68,0 -DA:70,0 -DA:71,0 -DA:78,0 -DA:82,0 -DA:83,0 -DA:85,0 -DA:88,0 -DA:89,0 -DA:90,0 -DA:95,0 -DA:106,0 -DA:107,0 -DA:108,0 -DA:110,0 -DA:112,0 -DA:113,0 -DA:114,0 -DA:115,0 -DA:117,0 -DA:118,0 -DA:120,0 -DA:121,0 -DA:122,0 -DA:125,0 -DA:131,0 -DA:135,0 -DA:136,0 -LF:53 -LH:0 -end_of_record -SF:lib/widgets/buy_subscription_widget.dart -DA:10,0 -DA:12,0 -DA:13,0 -DA:14,0 -DA:18,1 -LF:5 -LH:1 -end_of_record -SF:lib/widgets/enter_promo_code_widget.dart -DA:8,0 -DA:10,0 -DA:13,0 -DA:14,0 -DA:15,0 -DA:18,1 -LF:6 -LH:1 -end_of_record -SF:lib/widgets/card_game/card_game_main.dart -DA:20,0 -DA:29,0 -DA:31,0 -DA:34,0 -DA:35,0 -DA:37,0 -DA:39,0 -DA:41,0 -DA:44,0 -DA:46,0 -DA:47,0 -DA:50,0 -DA:51,0 -DA:52,0 -DA:53,0 -DA:55,0 -DA:56,0 -DA:57,0 -DA:58,0 -DA:59,0 -DA:60,0 -DA:61,0 -DA:62,0 -DA:63,0 -DA:64,0 -DA:65,0 -DA:67,0 -DA:68,0 -DA:69,0 -DA:73,0 -DA:75,0 -DA:76,0 -DA:77,0 -DA:78,0 -DA:79,0 -DA:80,0 -DA:84,0 -DA:92,0 -DA:105,0 -DA:107,0 -DA:109,0 -LF:41 -LH:0 -end_of_record -SF:lib/widgets/card_pack/available_pack.dart -DA:25,0 -DA:26,0 -DA:33,0 -DA:35,0 -DA:37,0 -DA:38,0 -DA:39,0 -DA:40,0 -DA:41,0 -DA:42,0 -DA:43,0 -DA:45,0 -DA:46,0 -DA:47,0 -DA:48,0 -DA:49,0 -DA:50,0 -DA:51,0 -DA:55,0 -DA:56,0 -DA:57,0 -DA:60,0 -DA:62,0 -DA:63,0 -DA:65,0 -DA:66,0 -DA:68,0 -DA:69,0 -DA:70,0 -DA:72,0 -DA:74,0 -DA:75,0 -DA:76,0 -DA:77,0 -DA:78,0 -DA:79,0 -DA:80,0 -DA:81,0 -DA:82,0 -DA:83,0 -DA:84,0 -DA:88,0 -DA:90,0 -DA:91,0 -DA:92,0 -DA:93,0 -DA:95,0 -DA:102,0 -DA:105,0 -DA:106,0 -DA:107,0 -DA:108,0 -DA:109,0 -DA:110,0 -DA:111,0 -DA:112,0 -DA:113,0 -DA:114,0 -DA:115,0 -DA:116,0 -DA:118,0 -DA:120,0 -DA:121,0 -DA:130,0 -DA:131,0 -DA:132,0 -DA:133,0 -DA:134,0 -DA:137,0 -DA:138,0 -DA:139,0 -DA:140,0 -DA:152,0 -DA:153,0 -DA:155,0 -DA:156,0 -DA:160,0 -DA:162,0 -DA:164,0 -DA:175,0 -DA:177,0 -DA:179,0 -DA:180,0 -DA:181,0 -DA:182,0 -DA:183,0 -DA:185,0 -DA:187,0 -DA:188,0 -DA:189,0 -DA:190,0 -DA:194,0 -DA:195,0 -DA:196,0 -DA:197,0 -DA:198,0 -DA:199,0 -DA:202,0 -DA:203,0 -DA:204,0 -DA:206,0 -DA:207,0 -DA:208,0 -DA:209,0 -DA:210,0 -DA:211,0 -DA:212,0 -DA:213,0 -DA:214,0 -DA:215,0 -DA:218,0 -DA:219,0 -DA:220,0 -DA:221,0 -DA:223,0 -DA:225,0 -DA:226,0 -DA:228,0 -DA:229,0 -DA:230,0 -DA:231,0 -DA:232,0 -DA:236,0 -DA:237,0 -DA:238,0 -DA:240,0 -DA:241,0 -DA:242,0 -DA:244,0 -DA:245,0 -DA:246,0 -DA:247,0 -DA:248,0 -DA:249,0 -DA:250,0 -DA:252,0 -DA:253,0 -DA:255,0 -DA:256,0 -DA:257,0 -DA:258,0 -DA:259,0 -DA:260,0 -DA:261,0 -DA:262,0 -DA:277,0 -DA:281,0 -DA:283,0 -DA:284,0 -DA:285,0 -DA:286,0 -DA:287,0 -DA:288,0 -DA:291,0 -DA:292,0 -DA:293,0 -DA:294,0 -DA:295,0 -DA:297,0 -DA:298,0 -DA:299,0 -DA:302,0 -DA:304,0 -DA:305,0 -DA:317,0 -DA:319,0 -DA:321,0 -DA:322,0 -DA:323,0 -DA:324,0 -DA:325,0 -DA:326,0 -DA:327,0 -DA:328,0 -DA:329,0 -DA:332,0 -DA:333,0 -DA:334,0 -DA:335,0 -DA:348,0 -DA:350,0 -DA:352,0 -DA:353,0 -DA:354,0 -DA:355,0 -DA:356,0 -DA:357,0 -DA:358,0 -DA:359,0 -DA:360,0 -DA:363,0 -DA:364,0 -DA:365,0 -DA:366,0 -DA:368,0 -DA:369,0 -DA:388,0 -DA:398,0 -DA:400,0 -DA:401,0 -DA:402,0 -DA:403,0 -DA:405,0 -DA:406,0 -DA:407,0 -DA:408,0 -DA:410,0 -DA:411,0 -DA:412,0 -DA:413,0 -DA:414,0 -DA:416,0 -DA:417,0 -DA:418,0 -DA:419,0 -DA:422,0 -DA:423,0 -DA:424,0 -DA:425,0 -DA:426,0 -DA:431,0 -DA:432,0 -DA:434,0 -DA:435,0 -DA:436,0 -DA:437,0 -DA:443,0 -DA:444,0 -DA:445,0 -DA:447,0 -DA:448,0 -DA:449,0 -DA:450,0 -DA:451,0 -DA:452,0 -DA:453,0 -DA:454,0 -DA:463,0 -DA:464,0 -DA:465,0 -DA:467,0 -DA:468,0 -DA:469,0 -DA:470,0 -DA:471,0 -DA:472,0 -DA:476,0 -DA:477,0 -DA:478,0 -DA:479,0 -DA:480,0 -LF:251 -LH:0 -end_of_record -SF:lib/widgets/card_pack/card_pack_header.dart -DA:12,0 -DA:14,0 -DA:15,0 -DA:16,0 -DA:17,0 -DA:19,0 -DA:21,0 -DA:22,0 -DA:23,0 -DA:24,0 -DA:25,0 -DA:30,0 -DA:32,0 -DA:34,0 -DA:35,0 -LF:15 -LH:0 -end_of_record -SF:lib/widgets/card_pack/cards_view.dart -DA:24,0 -DA:32,0 -DA:33,0 -DA:38,0 -DA:40,0 -DA:54,0 -DA:55,0 -DA:58,0 -DA:59,0 -DA:60,0 -DA:61,0 -DA:62,0 -DA:64,0 -DA:65,0 -DA:66,0 -DA:68,0 -DA:72,0 -DA:74,0 -DA:81,0 -DA:83,0 -DA:84,0 -DA:85,0 -DA:86,0 -DA:89,0 -DA:91,0 -DA:92,0 -DA:93,0 -DA:94,0 -DA:96,0 -DA:98,0 -DA:99,0 -DA:100,0 -DA:103,0 -DA:105,0 -DA:106,0 -DA:107,0 -DA:110,0 -DA:111,0 -DA:112,0 -DA:114,0 -DA:115,0 -DA:117,0 -DA:119,0 -DA:120,0 -DA:137,0 -DA:139,0 -DA:140,0 -DA:143,0 -DA:144,0 -DA:145,0 -DA:146,0 -DA:147,0 -DA:149,0 -DA:151,0 -DA:152,0 -DA:153,0 -DA:154,0 -DA:158,0 -DA:159,0 -DA:160,0 -DA:162,0 -DA:163,0 -DA:164,0 -DA:166,0 -DA:167,0 -DA:168,0 -DA:170,0 -DA:172,0 -DA:173,0 -DA:174,0 -DA:175,0 -DA:176,0 -DA:181,0 -DA:182,0 -DA:183,0 -DA:184,0 -DA:185,0 -DA:198,0 -DA:203,0 -DA:205,0 -DA:206,0 -DA:208,0 -DA:209,0 -DA:210,0 -DA:211,0 -LF:85 -LH:0 -end_of_record -SF:lib/widgets/card_pack/cards_view_controller.dart -DA:19,0 -DA:26,0 -DA:31,0 -DA:32,0 -DA:34,0 -DA:36,0 -DA:38,0 -DA:39,0 -DA:40,0 -DA:41,0 -DA:43,0 -DA:44,0 -DA:45,0 -DA:46,0 -DA:49,0 -DA:50,0 -DA:51,0 -DA:52,0 -DA:53,0 -DA:55,0 -DA:57,0 -DA:58,0 -DA:59,0 -DA:60,0 -DA:64,0 -DA:65,0 -DA:66,0 -DA:67,0 -DA:68,0 -DA:71,0 -DA:72,0 -DA:73,0 -DA:78,0 -DA:79,0 -DA:80,0 -DA:81,0 -DA:83,0 -DA:84,0 -DA:85,0 -DA:86,0 -DA:87,0 -DA:89,0 -DA:90,0 -DA:91,0 -DA:92,0 -DA:94,0 -DA:95,0 -DA:99,0 -DA:100,0 -DA:101,0 -DA:103,0 -DA:105,0 -DA:106,0 -DA:109,0 -DA:110,0 -DA:111,0 -DA:113,0 -DA:115,0 -DA:116,0 -DA:119,0 -DA:120,0 -DA:121,0 -DA:122,0 -DA:125,0 -DA:126,0 -DA:129,0 -DA:131,0 -DA:133,0 -DA:135,0 -DA:136,0 -DA:137,0 -DA:138,0 -DA:139,0 -DA:142,0 -DA:143,0 -DA:144,0 -DA:145,0 -DA:146,0 -DA:147,0 -DA:148,0 -DA:149,0 -DA:150,0 -DA:151,0 -DA:153,0 -DA:155,0 -DA:158,0 -DA:160,0 -DA:161,0 -DA:162,0 -DA:163,0 -DA:164,0 -DA:169,0 -DA:170,0 -DA:171,0 -DA:181,0 -DA:187,0 -DA:188,0 -DA:190,0 -DA:192,0 -DA:193,0 -DA:194,0 -DA:195,0 -DA:196,0 -LF:103 -LH:0 -end_of_record -SF:lib/widgets/card_pack/buy_pack_page.dart -DA:20,0 -DA:22,0 -DA:25,0 -DA:26,0 -DA:28,0 -DA:30,0 -DA:32,0 -DA:34,0 -DA:35,0 -DA:36,0 -DA:37,0 -DA:40,0 -DA:41,0 -DA:42,0 -DA:43,0 -DA:44,0 -DA:45,0 -DA:46,0 -DA:47,0 -DA:48,0 -DA:49,0 -DA:51,0 -DA:53,0 -DA:54,0 -DA:55,0 -DA:56,0 -DA:59,0 -DA:60,0 -DA:63,0 -DA:64,0 -DA:65,0 -DA:66,0 -DA:70,0 -DA:73,0 -DA:79,0 -DA:80,0 -DA:82,0 -DA:92,0 -DA:93,0 -DA:105,0 -DA:107,0 -DA:109,0 -DA:110,0 -DA:111,0 -DA:112,0 -DA:113,0 -DA:114,0 -DA:115,0 -DA:117,0 -DA:119,0 -DA:121,0 -DA:126,0 -DA:140,0 -DA:142,0 -DA:144,0 -DA:145,0 -DA:146,0 -DA:148,0 -DA:151,0 -DA:152,0 -DA:153,0 -DA:155,0 -DA:157,0 -DA:158,0 -DA:159,0 -DA:160,0 -DA:161,0 -DA:168,0 -DA:171,0 -DA:173,0 -DA:180,0 -DA:181,0 -DA:182,0 -DA:183,0 -DA:184,0 -DA:185,0 -DA:186,0 -DA:189,0 -DA:192,0 -DA:194,0 -DA:195,0 -DA:197,0 -DA:198,0 -DA:203,0 -DA:205,0 -DA:206,0 -DA:211,0 -DA:212,0 -DA:214,0 -DA:215,0 -DA:216,0 -DA:217,0 -DA:218,0 -DA:225,0 -LF:94 -LH:0 -end_of_record -SF:lib/widgets/card_pack/error_loading_pack.dart -DA:16,0 -DA:18,0 -DA:20,0 -DA:22,0 -DA:23,0 -DA:24,0 -DA:25,0 -DA:26,0 -DA:27,0 -DA:29,0 -DA:30,0 -DA:31,0 -DA:33,0 -DA:35,0 -DA:36,0 -DA:37,0 -DA:40,0 -DA:45,0 -DA:46,0 -DA:48,0 -DA:50,0 -DA:55,0 -LF:22 -LH:0 -end_of_record -SF:lib/widgets/card_pack/loading_pack.dart -DA:15,0 -DA:17,0 -DA:19,0 -DA:21,0 -DA:23,0 -DA:24,0 -DA:25,0 -DA:26,0 -DA:27,0 -DA:28,0 -DA:29,0 -DA:30,0 -DA:32,0 -DA:33,0 -DA:34,0 -DA:36,0 -DA:38,0 -DA:39,0 -DA:40,0 -DA:43,0 -DA:48,0 -DA:49,0 -DA:51,0 -DA:53,0 -DA:54,0 -DA:56,0 -DA:57,0 -DA:58,0 -DA:59,0 -DA:61,0 -DA:62,0 -DA:73,0 -DA:74,0 -DA:75,0 -DA:76,0 -DA:77,0 -DA:78,0 -DA:79,0 -DA:81,0 -DA:82,0 -DA:84,0 -DA:86,0 -DA:87,0 -DA:89,0 -DA:90,0 -DA:91,0 -LF:46 -LH:0 -end_of_record -SF:lib/widgets/card_pack/cards_list.dart -DA:24,0 -DA:36,0 -DA:38,0 -DA:40,0 -DA:41,0 -DA:43,0 -DA:44,0 -DA:45,0 -DA:47,0 -DA:48,0 -DA:49,0 -DA:50,0 -DA:51,0 -DA:60,0 -DA:62,0 -DA:63,0 -DA:65,0 -DA:67,0 -DA:68,0 -DA:69,0 -DA:70,0 -DA:72,0 -DA:86,0 -DA:97,0 -DA:99,0 -DA:100,0 -DA:101,0 -DA:103,0 -DA:104,0 -DA:105,0 -DA:106,0 -DA:107,0 -DA:108,0 -DA:109,0 -DA:122,0 -DA:129,0 -DA:131,0 -DA:132,0 -DA:133,0 -DA:134,0 -DA:135,0 -DA:136,0 -DA:137,0 -DA:139,0 -DA:140,0 -DA:141,0 -DA:142,0 -DA:146,0 -DA:147,0 -DA:148,0 -DA:150,0 -DA:152,0 -DA:153,0 -DA:154,0 -DA:155,0 -DA:157,0 -DA:158,0 -LF:57 -LH:0 -end_of_record -SF:lib/widgets/pack_button.dart -DA:21,0 -DA:26,0 -DA:28,0 -DA:30,0 -DA:31,0 -DA:32,0 -DA:33,0 -DA:34,0 -DA:36,0 -DA:37,0 -DA:38,0 -DA:39,0 -DA:40,0 -DA:41,0 -DA:44,0 -DA:47,0 -DA:49,0 -DA:50,0 -DA:51,0 -DA:52,0 -DA:54,0 -DA:55,0 -DA:56,0 -DA:58,0 -DA:60,0 -DA:61,0 -DA:63,0 -DA:64,0 -DA:65,0 -DA:67,0 -DA:69,0 -DA:70,0 -DA:72,0 -DA:73,0 -DA:74,0 -DA:76,0 -DA:81,0 -DA:82,0 -DA:84,0 -DA:85,0 -DA:86,0 -DA:88,0 -DA:92,0 -DA:93,0 -DA:95,0 -DA:96,0 -DA:97,0 -DA:98,0 -DA:99,0 -DA:100,0 -DA:101,0 -DA:103,0 -DA:106,0 -DA:108,0 -DA:109,0 -DA:110,0 -DA:115,0 -DA:116,0 -DA:117,0 -DA:119,0 -DA:126,0 -DA:127,0 -DA:128,0 -DA:129,0 -DA:130,0 -DA:131,0 -DA:132,0 -DA:134,0 -DA:135,0 -DA:136,0 -DA:137,0 -DA:146,0 -DA:147,0 -DA:149,0 -DA:150,0 -DA:159,0 -DA:161,0 -DA:163,0 -DA:164,0 -DA:166,0 -DA:167,0 -DA:168,0 -DA:170,0 -DA:174,0 -DA:176,0 -DA:180,0 -DA:181,0 -DA:182,0 -DA:183,0 -DA:184,0 -DA:185,0 -DA:187,0 -DA:190,0 -DA:191,0 -DA:194,0 -DA:195,0 -DA:196,0 -DA:197,0 -DA:201,0 -DA:203,0 -DA:204,0 -DA:205,0 -DA:221,0 -DA:248,0 -DA:250,0 -DA:251,0 -DA:252,0 -DA:254,0 -DA:256,0 -DA:257,0 -DA:258,0 -DA:260,0 -DA:262,0 -LF:113 -LH:0 -end_of_record diff --git a/mnemo_cards/devtools_options.yaml b/mnemo_cards/devtools_options.yaml deleted file mode 100644 index fa0b357..0000000 --- a/mnemo_cards/devtools_options.yaml +++ /dev/null @@ -1,3 +0,0 @@ -description: This file stores settings for Dart & Flutter DevTools. -documentation: https://docs.flutter.dev/tools/devtools/extensions#configure-extension-enablement-states -extensions: diff --git a/mnemo_cards/firebase.json b/mnemo_cards/firebase.json deleted file mode 100644 index 4d12b0d..0000000 --- a/mnemo_cards/firebase.json +++ /dev/null @@ -1 +0,0 @@ -{"flutter":{"platforms":{"android":{"default":{"projectId":"mnemo-cards","appId":"1:701767851968:android:6190df55346394732f7225","fileOutput":"android/app/google-services.json"}},"ios":{"default":{"projectId":"mnemo-cards","appId":"1:701767851968:ios:5c9040634eac8c152f7225","uploadDebugSymbols":false,"fileOutput":"ios/Runner/GoogleService-Info.plist"}},"dart":{"lib/firebase_options.dart":{"projectId":"mnemo-cards","configurations":{"android":"1:701767851968:android:6190df55346394732f7225","ios":"1:701767851968:ios:5c9040634eac8c152f7225"}}}}}} \ No newline at end of file diff --git a/mnemo_cards/firepit-log.txt b/mnemo_cards/firepit-log.txt deleted file mode 100644 index c4eff32..0000000 --- a/mnemo_cards/firepit-log.txt +++ /dev/null @@ -1,13 +0,0 @@ -Welcome to firepit v1.1.0! -Doing JSON parses for version checks at /snapshot/firepit/vendor/node_modules/firebase-tools/package.json -firebase-tools -Installed ft@11.29.1 and packaged ft@11.29.1 -Checking for npm/bin/npm-cli install at /Users/dmitry/.cache/firebase/tools/lib/node_modules/npm/bin/npm-cli -Checking for npm/bin/npm-cli install at /Users/dmitry/.cache/firebase/tools/node_modules/npm/bin/npm-cli -Checking for npm/bin/npm-cli install at /snapshot/firepit/node_modules/npm/bin/npm-cli -Found npm/bin/npm-cli install. -Checking for npm/bin/npm-cli install at /Users/dmitry/.cache/firebase/tools/lib/node_modules/npm/bin/npm-cli -Checking for npm/bin/npm-cli install at /Users/dmitry/.cache/firebase/tools/node_modules/npm/bin/npm-cli -Checking for npm/bin/npm-cli install at /snapshot/firepit/node_modules/npm/bin/npm-cli -Found npm/bin/npm-cli install. -ShellJSInternalError: ENOENT: no such file or directory, chmod '/Users/dmitry/.cache/firebase/runtime/shell' \ No newline at end of file diff --git a/mnemo_cards/fonts/Nunito-VariableFont_wght.ttf b/mnemo_cards/fonts/Nunito-VariableFont_wght.ttf deleted file mode 100644 index 0a00f63..0000000 Binary files a/mnemo_cards/fonts/Nunito-VariableFont_wght.ttf and /dev/null differ diff --git a/mnemo_cards/gen_images/cerdo.jpg b/mnemo_cards/gen_images/cerdo.jpg deleted file mode 100644 index 31c8c5f..0000000 Binary files a/mnemo_cards/gen_images/cerdo.jpg and /dev/null differ diff --git a/mnemo_cards/gen_images/cerdo_big.jpg b/mnemo_cards/gen_images/cerdo_big.jpg deleted file mode 100644 index b4b80b1..0000000 Binary files a/mnemo_cards/gen_images/cerdo_big.jpg and /dev/null differ diff --git a/mnemo_cards/gen_images/icon.png b/mnemo_cards/gen_images/icon.png deleted file mode 100644 index 09fba16..0000000 Binary files a/mnemo_cards/gen_images/icon.png and /dev/null differ diff --git a/mnemo_cards/gen_images/icon_512.png b/mnemo_cards/gen_images/icon_512.png deleted file mode 100644 index 2dfe098..0000000 Binary files a/mnemo_cards/gen_images/icon_512.png and /dev/null differ diff --git a/mnemo_cards/gen_images/luna.png b/mnemo_cards/gen_images/luna.png deleted file mode 100644 index 0825a73..0000000 Binary files a/mnemo_cards/gen_images/luna.png and /dev/null differ diff --git a/mnemo_cards/gen_images/luna_big_dark.jpg b/mnemo_cards/gen_images/luna_big_dark.jpg deleted file mode 100644 index 775ffd0..0000000 Binary files a/mnemo_cards/gen_images/luna_big_dark.jpg and /dev/null differ diff --git a/mnemo_cards/gen_images/luna_dark.jpg b/mnemo_cards/gen_images/luna_dark.jpg deleted file mode 100644 index 82c0196..0000000 Binary files a/mnemo_cards/gen_images/luna_dark.jpg and /dev/null differ diff --git a/mnemo_cards/github_key b/mnemo_cards/github_key deleted file mode 100644 index 934c22c..0000000 --- a/mnemo_cards/github_key +++ /dev/null @@ -1,7 +0,0 @@ ------BEGIN OPENSSH PRIVATE KEY----- -b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW -QyNTUxOQAAACAJe7uHER6ZkHwo1y2mUvx43+saFRPXRK3iLhwJapfYUgAAAKDdcSod3XEq -HQAAAAtzc2gtZWQyNTUxOQAAACAJe7uHER6ZkHwo1y2mUvx43+saFRPXRK3iLhwJapfYUg -AAAEAGbB1nOEIZ6asQU4hkNAe4TNjIfrVFIMNMBSgiI2fDwQl7u4cRHpmQfCjXLaZS/Hjf -6xoVE9dEreIuHAlql9hSAAAAGGNpbm5hYmFyZmxvd2VyQGdtYWlsLmNvbQECAwQF ------END OPENSSH PRIVATE KEY----- diff --git a/mnemo_cards/github_key.pub b/mnemo_cards/github_key.pub deleted file mode 100644 index cf6577d..0000000 --- a/mnemo_cards/github_key.pub +++ /dev/null @@ -1 +0,0 @@ -ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAl7u4cRHpmQfCjXLaZS/Hjf6xoVE9dEreIuHAlql9hS cinnabarflower@gmail.com diff --git a/mnemo_cards/icons/ad.webp b/mnemo_cards/icons/ad.webp deleted file mode 100644 index e88f337..0000000 Binary files a/mnemo_cards/icons/ad.webp and /dev/null differ diff --git a/mnemo_cards/icons/back.webp b/mnemo_cards/icons/back.webp deleted file mode 100644 index 7e0aba6..0000000 Binary files a/mnemo_cards/icons/back.webp and /dev/null differ diff --git a/mnemo_cards/icons/cards.webp b/mnemo_cards/icons/cards.webp deleted file mode 100644 index 5002c95..0000000 Binary files a/mnemo_cards/icons/cards.webp and /dev/null differ diff --git a/mnemo_cards/icons/chat.webp b/mnemo_cards/icons/chat.webp deleted file mode 100644 index 1345684..0000000 Binary files a/mnemo_cards/icons/chat.webp and /dev/null differ diff --git a/mnemo_cards/icons/clock.webp b/mnemo_cards/icons/clock.webp deleted file mode 100644 index a04b34a..0000000 Binary files a/mnemo_cards/icons/clock.webp and /dev/null differ diff --git a/mnemo_cards/icons/crown.webp b/mnemo_cards/icons/crown.webp deleted file mode 100644 index 63bffc8..0000000 Binary files a/mnemo_cards/icons/crown.webp and /dev/null differ diff --git a/mnemo_cards/icons/down.webp b/mnemo_cards/icons/down.webp deleted file mode 100644 index 6ce685b..0000000 Binary files a/mnemo_cards/icons/down.webp and /dev/null differ diff --git a/mnemo_cards/icons/download.webp b/mnemo_cards/icons/download.webp deleted file mode 100644 index 6008778..0000000 Binary files a/mnemo_cards/icons/download.webp and /dev/null differ diff --git a/mnemo_cards/icons/exit.webp b/mnemo_cards/icons/exit.webp deleted file mode 100644 index 3aaa5d7..0000000 Binary files a/mnemo_cards/icons/exit.webp and /dev/null differ diff --git a/mnemo_cards/icons/exit2.webp b/mnemo_cards/icons/exit2.webp deleted file mode 100644 index 272562d..0000000 Binary files a/mnemo_cards/icons/exit2.webp and /dev/null differ diff --git a/mnemo_cards/icons/exit3.webp b/mnemo_cards/icons/exit3.webp deleted file mode 100644 index d677859..0000000 Binary files a/mnemo_cards/icons/exit3.webp and /dev/null differ diff --git a/mnemo_cards/icons/gift.webp b/mnemo_cards/icons/gift.webp deleted file mode 100644 index b2757ff..0000000 Binary files a/mnemo_cards/icons/gift.webp and /dev/null differ diff --git a/mnemo_cards/icons/google.webp b/mnemo_cards/icons/google.webp deleted file mode 100644 index 088aa58..0000000 Binary files a/mnemo_cards/icons/google.webp and /dev/null differ diff --git a/mnemo_cards/icons/heart.webp b/mnemo_cards/icons/heart.webp deleted file mode 100644 index d4415fa..0000000 Binary files a/mnemo_cards/icons/heart.webp and /dev/null differ diff --git a/mnemo_cards/icons/heart_fill.webp b/mnemo_cards/icons/heart_fill.webp deleted file mode 100644 index bf53614..0000000 Binary files a/mnemo_cards/icons/heart_fill.webp and /dev/null differ diff --git a/mnemo_cards/icons/lock.webp b/mnemo_cards/icons/lock.webp deleted file mode 100644 index c3e60ad..0000000 Binary files a/mnemo_cards/icons/lock.webp and /dev/null differ diff --git a/mnemo_cards/icons/mic_off.webp b/mnemo_cards/icons/mic_off.webp deleted file mode 100644 index 4cec1a9..0000000 Binary files a/mnemo_cards/icons/mic_off.webp and /dev/null differ diff --git a/mnemo_cards/icons/mic_on.webp b/mnemo_cards/icons/mic_on.webp deleted file mode 100644 index edd52f0..0000000 Binary files a/mnemo_cards/icons/mic_on.webp and /dev/null differ diff --git a/mnemo_cards/icons/next.webp b/mnemo_cards/icons/next.webp deleted file mode 100644 index 8a1c91f..0000000 Binary files a/mnemo_cards/icons/next.webp and /dev/null differ diff --git a/mnemo_cards/icons/profile.webp b/mnemo_cards/icons/profile.webp deleted file mode 100644 index 4e4d3f3..0000000 Binary files a/mnemo_cards/icons/profile.webp and /dev/null differ diff --git a/mnemo_cards/icons/settings.webp b/mnemo_cards/icons/settings.webp deleted file mode 100644 index e8045ba..0000000 Binary files a/mnemo_cards/icons/settings.webp and /dev/null differ diff --git a/mnemo_cards/icons/shuffle.webp b/mnemo_cards/icons/shuffle.webp deleted file mode 100644 index 6a88c1a..0000000 Binary files a/mnemo_cards/icons/shuffle.webp and /dev/null differ diff --git a/mnemo_cards/icons/skull.webp b/mnemo_cards/icons/skull.webp deleted file mode 100644 index b7b9681..0000000 Binary files a/mnemo_cards/icons/skull.webp and /dev/null differ diff --git a/mnemo_cards/icons/small_circle.webp b/mnemo_cards/icons/small_circle.webp deleted file mode 100644 index 2fd26c0..0000000 Binary files a/mnemo_cards/icons/small_circle.webp and /dev/null differ diff --git a/mnemo_cards/icons/sound_off.webp b/mnemo_cards/icons/sound_off.webp deleted file mode 100644 index 4438c46..0000000 Binary files a/mnemo_cards/icons/sound_off.webp and /dev/null differ diff --git a/mnemo_cards/icons/sound_on.webp b/mnemo_cards/icons/sound_on.webp deleted file mode 100644 index 6bbbeb4..0000000 Binary files a/mnemo_cards/icons/sound_on.webp and /dev/null differ diff --git a/mnemo_cards/icons/telegram.webp b/mnemo_cards/icons/telegram.webp deleted file mode 100644 index 76f3871..0000000 Binary files a/mnemo_cards/icons/telegram.webp and /dev/null differ diff --git a/mnemo_cards/icons/tg.webp b/mnemo_cards/icons/tg.webp deleted file mode 100644 index a44171d..0000000 Binary files a/mnemo_cards/icons/tg.webp and /dev/null differ diff --git a/mnemo_cards/icons/view.webp b/mnemo_cards/icons/view.webp deleted file mode 100644 index 2a79315..0000000 Binary files a/mnemo_cards/icons/view.webp and /dev/null differ diff --git a/mnemo_cards/images/cerdo.webp b/mnemo_cards/images/cerdo.webp deleted file mode 100644 index 2ef102a..0000000 Binary files a/mnemo_cards/images/cerdo.webp and /dev/null differ diff --git a/mnemo_cards/images/luna.webp b/mnemo_cards/images/luna.webp deleted file mode 100644 index 5caceed..0000000 Binary files a/mnemo_cards/images/luna.webp and /dev/null differ diff --git a/mnemo_cards/images_gen.sh b/mnemo_cards/images_gen.sh deleted file mode 100644 index 03500e2..0000000 --- a/mnemo_cards/images_gen.sh +++ /dev/null @@ -1,2 +0,0 @@ -dart run flutter_native_splash:create -dart run flutter_launcher_icons \ No newline at end of file diff --git a/mnemo_cards/integration_test/e2e/app_flow_e2e_test.dart b/mnemo_cards/integration_test/e2e/app_flow_e2e_test.dart deleted file mode 100644 index 2cd9f3e..0000000 --- a/mnemo_cards/integration_test/e2e/app_flow_e2e_test.dart +++ /dev/null @@ -1,138 +0,0 @@ -import 'package:flutter_test/flutter_test.dart'; -import 'package:patrol/patrol.dart'; - -void main() { - patrolTest( - 'Complete app flow e2e test', - ($) async { - // Запуск приложения - await $.pumpWidgetAndSettle(); - - // Проверка загрузки главной страницы - await $.native.tap(Selector(text: 'Начать')); - await $.pumpAndSettle(); - - // Проверка навигации - expect($.native.$(Selector(text: 'Главная')), findsOneWidget); - - // Тест авторизации (если требуется) - if ($.native.$(Selector(text: 'Войти')).exists) { - await $.native.tap(Selector(text: 'Войти')); - await $.pumpAndSettle(); - - // Заполнение формы авторизации - await $.native.enterText( - Selector(text: 'Email'), - 'test@example.com', - ); - await $.native.enterText( - Selector(text: 'Пароль'), - 'testpassword', - ); - - await $.native.tap(Selector(text: 'Войти')); - await $.pumpAndSettle(); - } - - // Тест навигации по разделам - await $.native.tap(Selector(text: 'Словарь')); - await $.pumpAndSettle(); - expect($.native.$(Selector(text: 'Словарь')), findsOneWidget); - - await $.native.tap(Selector(text: 'Игры')); - await $.pumpAndSettle(); - expect($.native.$(Selector(text: 'Игры')), findsOneWidget); - - await $.native.tap(Selector(text: 'Профиль')); - await $.pumpAndSettle(); - expect($.native.$(Selector(text: 'Профиль')), findsOneWidget); - - // Тест производительности - await $.native.takeScreenshot('app_flow_complete'); - }, - ); - - patrolTest( - 'Vocabulary learning flow test', - ($) async { - await $.pumpWidgetAndSettle(); - - // Переход к словарю - await $.native.tap(Selector(text: 'Словарь')); - await $.pumpAndSettle(); - - // Выбор пакета карточек - if ($.native.$(Selector(text: 'Выбрать пакет')).exists) { - await $.native.tap(Selector(text: 'Выбрать пакет')); - await $.pumpAndSettle(); - - // Выбор первого доступного пакета - await $.native.tap(Selector(text: 'Начать изучение')); - await $.pumpAndSettle(); - } - - // Тест изучения карточек - for (int i = 0; i < 3; i++) { - // Просмотр карточки - await $.native.tap(Selector(text: 'Показать перевод')); - await $.pumpAndSettle(); - - // Оценка знания - await $.native.tap(Selector(text: 'Знаю')); - await $.pumpAndSettle(); - } - - await $.native.takeScreenshot('vocabulary_learning_complete'); - }, - ); - - patrolTest( - 'Game integration test', - ($) async { - await $.pumpWidgetAndSettle(); - - // Переход к играм - await $.native.tap(Selector(text: 'Игры')); - await $.pumpAndSettle(); - - // Запуск игры (если доступна) - if ($.native.$(Selector(text: 'Играть')).exists) { - await $.native.tap(Selector(text: 'Играть')); - await $.pumpAndSettle(); - - // Базовые действия в игре - await $.native.tap(Selector(text: 'Начать')); - await $.pumpAndSettle(); - - // Завершение игры - await $.native.tap(Selector(text: 'Завершить')); - await $.pumpAndSettle(); - } - - await $.native.takeScreenshot('game_integration_complete'); - }, - ); - - patrolTest( - 'Network connectivity test', - ($) async { - await $.pumpWidgetAndSettle(); - - // Проверка сетевых запросов - await $.native.tap(Selector(text: 'Профиль')); - await $.pumpAndSettle(); - - // Обновление данных - if ($.native.$(Selector(text: 'Обновить')).exists) { - await $.native.tap(Selector(text: 'Обновить')); - await $.pumpAndSettle(); - } - - // Проверка синхронизации - await $.native.tap(Selector(text: 'Синхронизировать')); - await $.pumpAndSettle(); - - await $.native.takeScreenshot('network_test_complete'); - }, - ); -} diff --git a/mnemo_cards/ios/.gitignore b/mnemo_cards/ios/.gitignore deleted file mode 100644 index 7a7f987..0000000 --- a/mnemo_cards/ios/.gitignore +++ /dev/null @@ -1,34 +0,0 @@ -**/dgph -*.mode1v3 -*.mode2v3 -*.moved-aside -*.pbxuser -*.perspectivev3 -**/*sync/ -.sconsign.dblite -.tags* -**/.vagrant/ -**/DerivedData/ -Icon? -**/Pods/ -**/.symlinks/ -profile -xcuserdata -**/.generated/ -Flutter/App.framework -Flutter/Flutter.framework -Flutter/Flutter.podspec -Flutter/Generated.xcconfig -Flutter/ephemeral/ -Flutter/app.flx -Flutter/app.zip -Flutter/flutter_assets/ -Flutter/flutter_export_environment.sh -ServiceDefinitions.json -Runner/GeneratedPluginRegistrant.* - -# Exceptions to above rules. -!default.mode1v3 -!default.mode2v3 -!default.pbxuser -!default.perspectivev3 diff --git a/mnemo_cards/ios/Flutter/AppFrameworkInfo.plist b/mnemo_cards/ios/Flutter/AppFrameworkInfo.plist deleted file mode 100644 index 163000d..0000000 --- a/mnemo_cards/ios/Flutter/AppFrameworkInfo.plist +++ /dev/null @@ -1,26 +0,0 @@ - - - - - CFBundleDevelopmentRegion - en - CFBundleExecutable - App - CFBundleIdentifier - io.flutter.flutter.app - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - App - CFBundlePackageType - FMWK - CFBundleShortVersionString - 1.0 - CFBundleSignature - ???? - CFBundleVersion - 1.0 - MinimumOSVersion - 14.0 - - diff --git a/mnemo_cards/ios/Flutter/Debug.xcconfig b/mnemo_cards/ios/Flutter/Debug.xcconfig deleted file mode 100644 index ec97fc6..0000000 --- a/mnemo_cards/ios/Flutter/Debug.xcconfig +++ /dev/null @@ -1,2 +0,0 @@ -#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" -#include "Generated.xcconfig" diff --git a/mnemo_cards/ios/Flutter/Release.xcconfig b/mnemo_cards/ios/Flutter/Release.xcconfig deleted file mode 100644 index c4855bf..0000000 --- a/mnemo_cards/ios/Flutter/Release.xcconfig +++ /dev/null @@ -1,2 +0,0 @@ -#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" -#include "Generated.xcconfig" diff --git a/mnemo_cards/ios/Podfile b/mnemo_cards/ios/Podfile deleted file mode 100644 index 003e055..0000000 --- a/mnemo_cards/ios/Podfile +++ /dev/null @@ -1,49 +0,0 @@ -# source 'https://github.com/CocoaPods/Specs.git' -# source 'https://git.yoomoney.ru/scm/sdk/cocoa-pod-specs.git' - - -# Uncomment this line to define a global platform for your project -platform :ios, '14.0' - -# CocoaPods analytics sends network stats synchronously affecting flutter build latency. -ENV['COCOAPODS_DISABLE_STATS'] = 'true' - -project 'Runner', { - 'Debug' => :debug, - 'Profile' => :release, - 'Release' => :release, -} - -def flutter_root - generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) - unless File.exist?(generated_xcode_build_settings_path) - raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" - end - - File.foreach(generated_xcode_build_settings_path) do |line| - matches = line.match(/FLUTTER_ROOT\=(.*)/) - return matches[1].strip if matches - end - raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" -end - -require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) - -flutter_ios_podfile_setup - -target 'Runner' do - use_frameworks! :linkage => :static -# use_frameworks! - use_modular_headers! - - flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) - target 'RunnerTests' do - inherit! :search_paths - end -end - -post_install do |installer| - installer.pods_project.targets.each do |target| - flutter_additional_ios_build_settings(target) - end -end diff --git a/mnemo_cards/ios/Podfile.lock b/mnemo_cards/ios/Podfile.lock deleted file mode 100644 index 8c7da31..0000000 --- a/mnemo_cards/ios/Podfile.lock +++ /dev/null @@ -1,1976 +0,0 @@ -PODS: - - abseil/algorithm (1.20240722.0): - - abseil/algorithm/algorithm (= 1.20240722.0) - - abseil/algorithm/container (= 1.20240722.0) - - abseil/algorithm/algorithm (1.20240722.0): - - abseil/base/config - - abseil/xcprivacy - - abseil/algorithm/container (1.20240722.0): - - abseil/algorithm/algorithm - - abseil/base/config - - abseil/base/core_headers - - abseil/base/nullability - - abseil/meta/type_traits - - abseil/xcprivacy - - abseil/base (1.20240722.0): - - abseil/base/atomic_hook (= 1.20240722.0) - - abseil/base/base (= 1.20240722.0) - - abseil/base/base_internal (= 1.20240722.0) - - abseil/base/config (= 1.20240722.0) - - abseil/base/core_headers (= 1.20240722.0) - - abseil/base/cycleclock_internal (= 1.20240722.0) - - abseil/base/dynamic_annotations (= 1.20240722.0) - - abseil/base/endian (= 1.20240722.0) - - abseil/base/errno_saver (= 1.20240722.0) - - abseil/base/fast_type_id (= 1.20240722.0) - - abseil/base/log_severity (= 1.20240722.0) - - abseil/base/malloc_internal (= 1.20240722.0) - - abseil/base/no_destructor (= 1.20240722.0) - - abseil/base/nullability (= 1.20240722.0) - - abseil/base/poison (= 1.20240722.0) - - abseil/base/prefetch (= 1.20240722.0) - - abseil/base/pretty_function (= 1.20240722.0) - - abseil/base/raw_logging_internal (= 1.20240722.0) - - abseil/base/spinlock_wait (= 1.20240722.0) - - abseil/base/strerror (= 1.20240722.0) - - abseil/base/throw_delegate (= 1.20240722.0) - - abseil/base/atomic_hook (1.20240722.0): - - abseil/base/config - - abseil/base/core_headers - - abseil/xcprivacy - - abseil/base/base (1.20240722.0): - - abseil/base/atomic_hook - - abseil/base/base_internal - - abseil/base/config - - abseil/base/core_headers - - abseil/base/cycleclock_internal - - abseil/base/dynamic_annotations - - abseil/base/log_severity - - abseil/base/nullability - - abseil/base/raw_logging_internal - - abseil/base/spinlock_wait - - abseil/meta/type_traits - - abseil/xcprivacy - - abseil/base/base_internal (1.20240722.0): - - abseil/base/config - - abseil/meta/type_traits - - abseil/xcprivacy - - abseil/base/config (1.20240722.0): - - abseil/xcprivacy - - abseil/base/core_headers (1.20240722.0): - - abseil/base/config - - abseil/xcprivacy - - abseil/base/cycleclock_internal (1.20240722.0): - - abseil/base/base_internal - - abseil/base/config - - abseil/xcprivacy - - abseil/base/dynamic_annotations (1.20240722.0): - - abseil/base/config - - abseil/base/core_headers - - abseil/xcprivacy - - abseil/base/endian (1.20240722.0): - - abseil/base/base - - abseil/base/config - - abseil/base/core_headers - - abseil/base/nullability - - abseil/xcprivacy - - abseil/base/errno_saver (1.20240722.0): - - abseil/base/config - - abseil/xcprivacy - - abseil/base/fast_type_id (1.20240722.0): - - abseil/base/config - - abseil/xcprivacy - - abseil/base/log_severity (1.20240722.0): - - abseil/base/config - - abseil/base/core_headers - - abseil/xcprivacy - - abseil/base/malloc_internal (1.20240722.0): - - abseil/base/base - - abseil/base/base_internal - - abseil/base/config - - abseil/base/core_headers - - abseil/base/dynamic_annotations - - abseil/base/raw_logging_internal - - abseil/xcprivacy - - abseil/base/no_destructor (1.20240722.0): - - abseil/base/config - - abseil/base/nullability - - abseil/xcprivacy - - abseil/base/nullability (1.20240722.0): - - abseil/base/config - - abseil/base/core_headers - - abseil/meta/type_traits - - abseil/xcprivacy - - abseil/base/poison (1.20240722.0): - - abseil/base/config - - abseil/base/core_headers - - abseil/base/malloc_internal - - abseil/xcprivacy - - abseil/base/prefetch (1.20240722.0): - - abseil/base/config - - abseil/base/core_headers - - abseil/xcprivacy - - abseil/base/pretty_function (1.20240722.0): - - abseil/xcprivacy - - abseil/base/raw_logging_internal (1.20240722.0): - - abseil/base/atomic_hook - - abseil/base/config - - abseil/base/core_headers - - abseil/base/errno_saver - - abseil/base/log_severity - - abseil/xcprivacy - - abseil/base/spinlock_wait (1.20240722.0): - - abseil/base/base_internal - - abseil/base/core_headers - - abseil/base/errno_saver - - abseil/xcprivacy - - abseil/base/strerror (1.20240722.0): - - abseil/base/config - - abseil/base/core_headers - - abseil/base/errno_saver - - abseil/xcprivacy - - abseil/base/throw_delegate (1.20240722.0): - - abseil/base/config - - abseil/base/raw_logging_internal - - abseil/xcprivacy - - abseil/cleanup/cleanup (1.20240722.0): - - abseil/base/config - - abseil/base/core_headers - - abseil/cleanup/cleanup_internal - - abseil/xcprivacy - - abseil/cleanup/cleanup_internal (1.20240722.0): - - abseil/base/base_internal - - abseil/base/core_headers - - abseil/utility/utility - - abseil/xcprivacy - - abseil/container/common (1.20240722.0): - - abseil/meta/type_traits - - abseil/types/optional - - abseil/xcprivacy - - abseil/container/common_policy_traits (1.20240722.0): - - abseil/meta/type_traits - - abseil/xcprivacy - - abseil/container/compressed_tuple (1.20240722.0): - - abseil/utility/utility - - abseil/xcprivacy - - abseil/container/container_memory (1.20240722.0): - - abseil/base/config - - abseil/memory/memory - - abseil/meta/type_traits - - abseil/utility/utility - - abseil/xcprivacy - - abseil/container/fixed_array (1.20240722.0): - - abseil/algorithm/algorithm - - abseil/base/config - - abseil/base/core_headers - - abseil/base/dynamic_annotations - - abseil/base/throw_delegate - - abseil/container/compressed_tuple - - abseil/memory/memory - - abseil/xcprivacy - - abseil/container/flat_hash_map (1.20240722.0): - - abseil/algorithm/container - - abseil/base/core_headers - - abseil/container/container_memory - - abseil/container/hash_container_defaults - - abseil/container/raw_hash_map - - abseil/meta/type_traits - - abseil/xcprivacy - - abseil/container/flat_hash_set (1.20240722.0): - - abseil/algorithm/container - - abseil/base/core_headers - - abseil/container/container_memory - - abseil/container/hash_container_defaults - - abseil/container/raw_hash_set - - abseil/memory/memory - - abseil/meta/type_traits - - abseil/xcprivacy - - abseil/container/hash_container_defaults (1.20240722.0): - - abseil/base/config - - abseil/container/hash_function_defaults - - abseil/xcprivacy - - abseil/container/hash_function_defaults (1.20240722.0): - - abseil/base/config - - abseil/container/common - - abseil/hash/hash - - abseil/meta/type_traits - - abseil/strings/cord - - abseil/strings/strings - - abseil/xcprivacy - - abseil/container/hash_policy_traits (1.20240722.0): - - abseil/container/common_policy_traits - - abseil/meta/type_traits - - abseil/xcprivacy - - abseil/container/hashtable_debug_hooks (1.20240722.0): - - abseil/base/config - - abseil/xcprivacy - - abseil/container/hashtablez_sampler (1.20240722.0): - - abseil/base/base - - abseil/base/config - - abseil/base/core_headers - - abseil/base/no_destructor - - abseil/base/raw_logging_internal - - abseil/debugging/stacktrace - - abseil/memory/memory - - abseil/profiling/exponential_biased - - abseil/profiling/sample_recorder - - abseil/synchronization/synchronization - - abseil/time/time - - abseil/utility/utility - - abseil/xcprivacy - - abseil/container/inlined_vector (1.20240722.0): - - abseil/algorithm/algorithm - - abseil/base/core_headers - - abseil/base/throw_delegate - - abseil/container/inlined_vector_internal - - abseil/memory/memory - - abseil/meta/type_traits - - abseil/xcprivacy - - abseil/container/inlined_vector_internal (1.20240722.0): - - abseil/base/base_internal - - abseil/base/config - - abseil/base/core_headers - - abseil/container/compressed_tuple - - abseil/memory/memory - - abseil/meta/type_traits - - abseil/types/span - - abseil/xcprivacy - - abseil/container/layout (1.20240722.0): - - abseil/base/config - - abseil/base/core_headers - - abseil/debugging/demangle_internal - - abseil/meta/type_traits - - abseil/strings/strings - - abseil/types/span - - abseil/utility/utility - - abseil/xcprivacy - - abseil/container/raw_hash_map (1.20240722.0): - - abseil/base/config - - abseil/base/core_headers - - abseil/base/throw_delegate - - abseil/container/container_memory - - abseil/container/raw_hash_set - - abseil/xcprivacy - - abseil/container/raw_hash_set (1.20240722.0): - - abseil/base/config - - abseil/base/core_headers - - abseil/base/dynamic_annotations - - abseil/base/endian - - abseil/base/prefetch - - abseil/base/raw_logging_internal - - abseil/container/common - - abseil/container/compressed_tuple - - abseil/container/container_memory - - abseil/container/hash_policy_traits - - abseil/container/hashtable_debug_hooks - - abseil/container/hashtablez_sampler - - abseil/hash/hash - - abseil/memory/memory - - abseil/meta/type_traits - - abseil/numeric/bits - - abseil/utility/utility - - abseil/xcprivacy - - abseil/crc/cpu_detect (1.20240722.0): - - abseil/base/base - - abseil/base/config - - abseil/xcprivacy - - abseil/crc/crc32c (1.20240722.0): - - abseil/base/config - - abseil/base/core_headers - - abseil/base/endian - - abseil/base/prefetch - - abseil/crc/cpu_detect - - abseil/crc/crc_internal - - abseil/crc/non_temporal_memcpy - - abseil/strings/str_format - - abseil/strings/strings - - abseil/xcprivacy - - abseil/crc/crc_cord_state (1.20240722.0): - - abseil/base/config - - abseil/base/no_destructor - - abseil/crc/crc32c - - abseil/numeric/bits - - abseil/xcprivacy - - abseil/crc/crc_internal (1.20240722.0): - - abseil/base/config - - abseil/base/core_headers - - abseil/base/endian - - abseil/base/prefetch - - abseil/base/raw_logging_internal - - abseil/crc/cpu_detect - - abseil/memory/memory - - abseil/numeric/bits - - abseil/xcprivacy - - abseil/crc/non_temporal_arm_intrinsics (1.20240722.0): - - abseil/base/config - - abseil/xcprivacy - - abseil/crc/non_temporal_memcpy (1.20240722.0): - - abseil/base/config - - abseil/base/core_headers - - abseil/crc/non_temporal_arm_intrinsics - - abseil/xcprivacy - - abseil/debugging/bounded_utf8_length_sequence (1.20240722.0): - - abseil/base/config - - abseil/numeric/bits - - abseil/xcprivacy - - abseil/debugging/debugging_internal (1.20240722.0): - - abseil/base/config - - abseil/base/core_headers - - abseil/base/dynamic_annotations - - abseil/base/errno_saver - - abseil/base/raw_logging_internal - - abseil/xcprivacy - - abseil/debugging/decode_rust_punycode (1.20240722.0): - - abseil/base/config - - abseil/base/nullability - - abseil/debugging/bounded_utf8_length_sequence - - abseil/debugging/utf8_for_code_point - - abseil/xcprivacy - - abseil/debugging/demangle_internal (1.20240722.0): - - abseil/base/base - - abseil/base/config - - abseil/base/core_headers - - abseil/base/nullability - - abseil/debugging/demangle_rust - - abseil/numeric/bits - - abseil/xcprivacy - - abseil/debugging/demangle_rust (1.20240722.0): - - abseil/base/config - - abseil/base/core_headers - - abseil/debugging/decode_rust_punycode - - abseil/xcprivacy - - abseil/debugging/examine_stack (1.20240722.0): - - abseil/base/config - - abseil/base/core_headers - - abseil/base/raw_logging_internal - - abseil/debugging/stacktrace - - abseil/debugging/symbolize - - abseil/xcprivacy - - abseil/debugging/stacktrace (1.20240722.0): - - abseil/base/config - - abseil/base/core_headers - - abseil/base/dynamic_annotations - - abseil/base/raw_logging_internal - - abseil/debugging/debugging_internal - - abseil/xcprivacy - - abseil/debugging/symbolize (1.20240722.0): - - abseil/base/base - - abseil/base/config - - abseil/base/core_headers - - abseil/base/dynamic_annotations - - abseil/base/malloc_internal - - abseil/base/raw_logging_internal - - abseil/debugging/debugging_internal - - abseil/debugging/demangle_internal - - abseil/strings/strings - - abseil/xcprivacy - - abseil/debugging/utf8_for_code_point (1.20240722.0): - - abseil/base/config - - abseil/xcprivacy - - abseil/flags/commandlineflag (1.20240722.0): - - abseil/base/config - - abseil/base/fast_type_id - - abseil/flags/commandlineflag_internal - - abseil/strings/strings - - abseil/types/optional - - abseil/xcprivacy - - abseil/flags/commandlineflag_internal (1.20240722.0): - - abseil/base/config - - abseil/base/fast_type_id - - abseil/xcprivacy - - abseil/flags/config (1.20240722.0): - - abseil/base/config - - abseil/base/core_headers - - abseil/flags/path_util - - abseil/flags/program_name - - abseil/strings/strings - - abseil/synchronization/synchronization - - abseil/xcprivacy - - abseil/flags/flag (1.20240722.0): - - abseil/base/config - - abseil/base/core_headers - - abseil/flags/commandlineflag - - abseil/flags/config - - abseil/flags/flag_internal - - abseil/flags/reflection - - abseil/strings/strings - - abseil/xcprivacy - - abseil/flags/flag_internal (1.20240722.0): - - abseil/base/base - - abseil/base/config - - abseil/base/core_headers - - abseil/base/dynamic_annotations - - abseil/flags/commandlineflag - - abseil/flags/commandlineflag_internal - - abseil/flags/config - - abseil/flags/marshalling - - abseil/flags/reflection - - abseil/memory/memory - - abseil/meta/type_traits - - abseil/strings/strings - - abseil/synchronization/synchronization - - abseil/utility/utility - - abseil/xcprivacy - - abseil/flags/marshalling (1.20240722.0): - - abseil/base/config - - abseil/base/core_headers - - abseil/base/log_severity - - abseil/numeric/int128 - - abseil/strings/str_format - - abseil/strings/strings - - abseil/types/optional - - abseil/xcprivacy - - abseil/flags/path_util (1.20240722.0): - - abseil/base/config - - abseil/strings/strings - - abseil/xcprivacy - - abseil/flags/private_handle_accessor (1.20240722.0): - - abseil/base/config - - abseil/flags/commandlineflag - - abseil/flags/commandlineflag_internal - - abseil/strings/strings - - abseil/xcprivacy - - abseil/flags/program_name (1.20240722.0): - - abseil/base/config - - abseil/base/core_headers - - abseil/flags/path_util - - abseil/strings/strings - - abseil/synchronization/synchronization - - abseil/xcprivacy - - abseil/flags/reflection (1.20240722.0): - - abseil/base/config - - abseil/base/core_headers - - abseil/base/no_destructor - - abseil/container/flat_hash_map - - abseil/flags/commandlineflag - - abseil/flags/commandlineflag_internal - - abseil/flags/config - - abseil/flags/private_handle_accessor - - abseil/strings/strings - - abseil/synchronization/synchronization - - abseil/xcprivacy - - abseil/functional/any_invocable (1.20240722.0): - - abseil/base/base_internal - - abseil/base/config - - abseil/base/core_headers - - abseil/meta/type_traits - - abseil/utility/utility - - abseil/xcprivacy - - abseil/functional/bind_front (1.20240722.0): - - abseil/base/base_internal - - abseil/container/compressed_tuple - - abseil/meta/type_traits - - abseil/utility/utility - - abseil/xcprivacy - - abseil/functional/function_ref (1.20240722.0): - - abseil/base/base_internal - - abseil/base/core_headers - - abseil/functional/any_invocable - - abseil/meta/type_traits - - abseil/xcprivacy - - abseil/hash/city (1.20240722.0): - - abseil/base/config - - abseil/base/core_headers - - abseil/base/endian - - abseil/xcprivacy - - abseil/hash/hash (1.20240722.0): - - abseil/base/config - - abseil/base/core_headers - - abseil/base/endian - - abseil/container/fixed_array - - abseil/functional/function_ref - - abseil/hash/city - - abseil/hash/low_level_hash - - abseil/meta/type_traits - - abseil/numeric/bits - - abseil/numeric/int128 - - abseil/strings/strings - - abseil/types/optional - - abseil/types/variant - - abseil/utility/utility - - abseil/xcprivacy - - abseil/hash/low_level_hash (1.20240722.0): - - abseil/base/config - - abseil/base/endian - - abseil/base/prefetch - - abseil/numeric/int128 - - abseil/xcprivacy - - abseil/log/absl_check (1.20240722.0): - - abseil/log/internal/check_impl - - abseil/xcprivacy - - abseil/log/absl_log (1.20240722.0): - - abseil/log/internal/log_impl - - abseil/xcprivacy - - abseil/log/absl_vlog_is_on (1.20240722.0): - - abseil/base/config - - abseil/base/core_headers - - abseil/log/internal/vlog_config - - abseil/strings/strings - - abseil/xcprivacy - - abseil/log/check (1.20240722.0): - - abseil/log/internal/check_impl - - abseil/log/internal/check_op - - abseil/log/internal/conditions - - abseil/log/internal/log_message - - abseil/log/internal/strip - - abseil/xcprivacy - - abseil/log/globals (1.20240722.0): - - abseil/base/atomic_hook - - abseil/base/config - - abseil/base/core_headers - - abseil/base/log_severity - - abseil/base/raw_logging_internal - - abseil/hash/hash - - abseil/log/internal/vlog_config - - abseil/strings/strings - - abseil/xcprivacy - - abseil/log/internal/append_truncated (1.20240722.0): - - abseil/base/config - - abseil/strings/strings - - abseil/types/span - - abseil/xcprivacy - - abseil/log/internal/check_impl (1.20240722.0): - - abseil/base/core_headers - - abseil/log/internal/check_op - - abseil/log/internal/conditions - - abseil/log/internal/log_message - - abseil/log/internal/strip - - abseil/xcprivacy - - abseil/log/internal/check_op (1.20240722.0): - - abseil/base/config - - abseil/base/core_headers - - abseil/log/internal/nullguard - - abseil/log/internal/nullstream - - abseil/log/internal/strip - - abseil/strings/strings - - abseil/xcprivacy - - abseil/log/internal/conditions (1.20240722.0): - - abseil/base/base - - abseil/base/config - - abseil/base/core_headers - - abseil/log/internal/voidify - - abseil/xcprivacy - - abseil/log/internal/config (1.20240722.0): - - abseil/base/config - - abseil/base/core_headers - - abseil/xcprivacy - - abseil/log/internal/fnmatch (1.20240722.0): - - abseil/base/config - - abseil/strings/strings - - abseil/xcprivacy - - abseil/log/internal/format (1.20240722.0): - - abseil/base/config - - abseil/base/core_headers - - abseil/base/log_severity - - abseil/log/internal/append_truncated - - abseil/log/internal/config - - abseil/log/internal/globals - - abseil/strings/str_format - - abseil/strings/strings - - abseil/time/time - - abseil/types/span - - abseil/xcprivacy - - abseil/log/internal/globals (1.20240722.0): - - abseil/base/config - - abseil/base/core_headers - - abseil/base/log_severity - - abseil/base/raw_logging_internal - - abseil/strings/strings - - abseil/time/time - - abseil/xcprivacy - - abseil/log/internal/log_impl (1.20240722.0): - - abseil/log/absl_vlog_is_on - - abseil/log/internal/conditions - - abseil/log/internal/log_message - - abseil/log/internal/strip - - abseil/xcprivacy - - abseil/log/internal/log_message (1.20240722.0): - - abseil/base/base - - abseil/base/config - - abseil/base/core_headers - - abseil/base/errno_saver - - abseil/base/log_severity - - abseil/base/raw_logging_internal - - abseil/base/strerror - - abseil/container/inlined_vector - - abseil/debugging/examine_stack - - abseil/log/globals - - abseil/log/internal/append_truncated - - abseil/log/internal/format - - abseil/log/internal/globals - - abseil/log/internal/log_sink_set - - abseil/log/internal/nullguard - - abseil/log/internal/proto - - abseil/log/log_entry - - abseil/log/log_sink - - abseil/log/log_sink_registry - - abseil/memory/memory - - abseil/strings/strings - - abseil/time/time - - abseil/types/span - - abseil/xcprivacy - - abseil/log/internal/log_sink_set (1.20240722.0): - - abseil/base/base - - abseil/base/config - - abseil/base/core_headers - - abseil/base/log_severity - - abseil/base/no_destructor - - abseil/base/raw_logging_internal - - abseil/cleanup/cleanup - - abseil/log/globals - - abseil/log/internal/config - - abseil/log/internal/globals - - abseil/log/log_entry - - abseil/log/log_sink - - abseil/strings/strings - - abseil/synchronization/synchronization - - abseil/types/span - - abseil/xcprivacy - - abseil/log/internal/nullguard (1.20240722.0): - - abseil/base/config - - abseil/base/core_headers - - abseil/xcprivacy - - abseil/log/internal/nullstream (1.20240722.0): - - abseil/base/config - - abseil/base/core_headers - - abseil/base/log_severity - - abseil/strings/strings - - abseil/xcprivacy - - abseil/log/internal/proto (1.20240722.0): - - abseil/base/base - - abseil/base/config - - abseil/base/core_headers - - abseil/strings/strings - - abseil/types/span - - abseil/xcprivacy - - abseil/log/internal/strip (1.20240722.0): - - abseil/base/core_headers - - abseil/base/log_severity - - abseil/log/internal/log_message - - abseil/log/internal/nullstream - - abseil/xcprivacy - - abseil/log/internal/vlog_config (1.20240722.0): - - abseil/base/base - - abseil/base/config - - abseil/base/core_headers - - abseil/base/no_destructor - - abseil/log/internal/fnmatch - - abseil/memory/memory - - abseil/strings/strings - - abseil/synchronization/synchronization - - abseil/types/optional - - abseil/xcprivacy - - abseil/log/internal/voidify (1.20240722.0): - - abseil/base/config - - abseil/xcprivacy - - abseil/log/log (1.20240722.0): - - abseil/log/internal/log_impl - - abseil/log/vlog_is_on - - abseil/xcprivacy - - abseil/log/log_entry (1.20240722.0): - - abseil/base/config - - abseil/base/core_headers - - abseil/base/log_severity - - abseil/log/internal/config - - abseil/strings/strings - - abseil/time/time - - abseil/types/span - - abseil/xcprivacy - - abseil/log/log_sink (1.20240722.0): - - abseil/base/config - - abseil/log/log_entry - - abseil/xcprivacy - - abseil/log/log_sink_registry (1.20240722.0): - - abseil/base/config - - abseil/log/internal/log_sink_set - - abseil/log/log_sink - - abseil/xcprivacy - - abseil/log/vlog_is_on (1.20240722.0): - - abseil/log/absl_vlog_is_on - - abseil/xcprivacy - - abseil/memory (1.20240722.0): - - abseil/memory/memory (= 1.20240722.0) - - abseil/memory/memory (1.20240722.0): - - abseil/base/core_headers - - abseil/meta/type_traits - - abseil/xcprivacy - - abseil/meta (1.20240722.0): - - abseil/meta/type_traits (= 1.20240722.0) - - abseil/meta/type_traits (1.20240722.0): - - abseil/base/config - - abseil/base/core_headers - - abseil/xcprivacy - - abseil/numeric/bits (1.20240722.0): - - abseil/base/config - - abseil/base/core_headers - - abseil/xcprivacy - - abseil/numeric/int128 (1.20240722.0): - - abseil/base/config - - abseil/base/core_headers - - abseil/numeric/bits - - abseil/types/compare - - abseil/xcprivacy - - abseil/numeric/representation (1.20240722.0): - - abseil/base/config - - abseil/xcprivacy - - abseil/profiling/exponential_biased (1.20240722.0): - - abseil/base/config - - abseil/base/core_headers - - abseil/xcprivacy - - abseil/profiling/sample_recorder (1.20240722.0): - - abseil/base/config - - abseil/base/core_headers - - abseil/synchronization/synchronization - - abseil/time/time - - abseil/xcprivacy - - abseil/random/bit_gen_ref (1.20240722.0): - - abseil/base/core_headers - - abseil/base/fast_type_id - - abseil/meta/type_traits - - abseil/random/internal/distribution_caller - - abseil/random/internal/fast_uniform_bits - - abseil/random/random - - abseil/xcprivacy - - abseil/random/distributions (1.20240722.0): - - abseil/base/base_internal - - abseil/base/config - - abseil/base/core_headers - - abseil/meta/type_traits - - abseil/numeric/bits - - abseil/random/internal/distribution_caller - - abseil/random/internal/fast_uniform_bits - - abseil/random/internal/fastmath - - abseil/random/internal/generate_real - - abseil/random/internal/iostream_state_saver - - abseil/random/internal/traits - - abseil/random/internal/uniform_helper - - abseil/random/internal/wide_multiply - - abseil/strings/strings - - abseil/xcprivacy - - abseil/random/internal/distribution_caller (1.20240722.0): - - abseil/base/config - - abseil/base/fast_type_id - - abseil/utility/utility - - abseil/xcprivacy - - abseil/random/internal/fast_uniform_bits (1.20240722.0): - - abseil/base/config - - abseil/meta/type_traits - - abseil/random/internal/traits - - abseil/xcprivacy - - abseil/random/internal/fastmath (1.20240722.0): - - abseil/numeric/bits - - abseil/xcprivacy - - abseil/random/internal/generate_real (1.20240722.0): - - abseil/meta/type_traits - - abseil/numeric/bits - - abseil/random/internal/fastmath - - abseil/random/internal/traits - - abseil/xcprivacy - - abseil/random/internal/iostream_state_saver (1.20240722.0): - - abseil/meta/type_traits - - abseil/numeric/int128 - - abseil/xcprivacy - - abseil/random/internal/nonsecure_base (1.20240722.0): - - abseil/base/core_headers - - abseil/container/inlined_vector - - abseil/meta/type_traits - - abseil/random/internal/pool_urbg - - abseil/random/internal/salted_seed_seq - - abseil/random/internal/seed_material - - abseil/types/span - - abseil/xcprivacy - - abseil/random/internal/pcg_engine (1.20240722.0): - - abseil/base/config - - abseil/meta/type_traits - - abseil/numeric/bits - - abseil/numeric/int128 - - abseil/random/internal/fastmath - - abseil/random/internal/iostream_state_saver - - abseil/xcprivacy - - abseil/random/internal/platform (1.20240722.0): - - abseil/base/config - - abseil/xcprivacy - - abseil/random/internal/pool_urbg (1.20240722.0): - - abseil/base/base - - abseil/base/config - - abseil/base/core_headers - - abseil/base/endian - - abseil/base/raw_logging_internal - - abseil/random/internal/randen - - abseil/random/internal/seed_material - - abseil/random/internal/traits - - abseil/random/seed_gen_exception - - abseil/types/span - - abseil/xcprivacy - - abseil/random/internal/randen (1.20240722.0): - - abseil/base/raw_logging_internal - - abseil/random/internal/platform - - abseil/random/internal/randen_hwaes - - abseil/random/internal/randen_slow - - abseil/xcprivacy - - abseil/random/internal/randen_engine (1.20240722.0): - - abseil/base/endian - - abseil/meta/type_traits - - abseil/random/internal/iostream_state_saver - - abseil/random/internal/randen - - abseil/xcprivacy - - abseil/random/internal/randen_hwaes (1.20240722.0): - - abseil/base/config - - abseil/random/internal/platform - - abseil/random/internal/randen_hwaes_impl - - abseil/xcprivacy - - abseil/random/internal/randen_hwaes_impl (1.20240722.0): - - abseil/base/config - - abseil/base/core_headers - - abseil/numeric/int128 - - abseil/random/internal/platform - - abseil/xcprivacy - - abseil/random/internal/randen_slow (1.20240722.0): - - abseil/base/config - - abseil/base/core_headers - - abseil/base/endian - - abseil/numeric/int128 - - abseil/random/internal/platform - - abseil/xcprivacy - - abseil/random/internal/salted_seed_seq (1.20240722.0): - - abseil/container/inlined_vector - - abseil/meta/type_traits - - abseil/random/internal/seed_material - - abseil/types/optional - - abseil/types/span - - abseil/xcprivacy - - abseil/random/internal/seed_material (1.20240722.0): - - abseil/base/core_headers - - abseil/base/dynamic_annotations - - abseil/base/raw_logging_internal - - abseil/random/internal/fast_uniform_bits - - abseil/strings/strings - - abseil/types/optional - - abseil/types/span - - abseil/xcprivacy - - abseil/random/internal/traits (1.20240722.0): - - abseil/base/config - - abseil/numeric/bits - - abseil/numeric/int128 - - abseil/xcprivacy - - abseil/random/internal/uniform_helper (1.20240722.0): - - abseil/base/config - - abseil/meta/type_traits - - abseil/random/internal/traits - - abseil/xcprivacy - - abseil/random/internal/wide_multiply (1.20240722.0): - - abseil/base/config - - abseil/numeric/bits - - abseil/numeric/int128 - - abseil/random/internal/traits - - abseil/xcprivacy - - abseil/random/random (1.20240722.0): - - abseil/random/distributions - - abseil/random/internal/nonsecure_base - - abseil/random/internal/pcg_engine - - abseil/random/internal/pool_urbg - - abseil/random/internal/randen_engine - - abseil/random/seed_sequences - - abseil/xcprivacy - - abseil/random/seed_gen_exception (1.20240722.0): - - abseil/base/config - - abseil/xcprivacy - - abseil/random/seed_sequences (1.20240722.0): - - abseil/base/config - - abseil/base/nullability - - abseil/random/internal/pool_urbg - - abseil/random/internal/salted_seed_seq - - abseil/random/internal/seed_material - - abseil/random/seed_gen_exception - - abseil/strings/string_view - - abseil/types/span - - abseil/xcprivacy - - abseil/status/status (1.20240722.0): - - abseil/base/atomic_hook - - abseil/base/config - - abseil/base/core_headers - - abseil/base/no_destructor - - abseil/base/nullability - - abseil/base/raw_logging_internal - - abseil/base/strerror - - abseil/container/inlined_vector - - abseil/debugging/stacktrace - - abseil/debugging/symbolize - - abseil/functional/function_ref - - abseil/memory/memory - - abseil/strings/cord - - abseil/strings/str_format - - abseil/strings/strings - - abseil/types/optional - - abseil/types/span - - abseil/xcprivacy - - abseil/status/statusor (1.20240722.0): - - abseil/base/base - - abseil/base/config - - abseil/base/core_headers - - abseil/base/nullability - - abseil/base/raw_logging_internal - - abseil/meta/type_traits - - abseil/status/status - - abseil/strings/has_ostream_operator - - abseil/strings/str_format - - abseil/strings/strings - - abseil/types/variant - - abseil/utility/utility - - abseil/xcprivacy - - abseil/strings/charset (1.20240722.0): - - abseil/base/core_headers - - abseil/strings/string_view - - abseil/xcprivacy - - abseil/strings/cord (1.20240722.0): - - abseil/base/base - - abseil/base/config - - abseil/base/core_headers - - abseil/base/endian - - abseil/base/nullability - - abseil/base/raw_logging_internal - - abseil/container/inlined_vector - - abseil/crc/crc32c - - abseil/crc/crc_cord_state - - abseil/functional/function_ref - - abseil/meta/type_traits - - abseil/numeric/bits - - abseil/strings/cord_internal - - abseil/strings/cordz_functions - - abseil/strings/cordz_info - - abseil/strings/cordz_statistics - - abseil/strings/cordz_update_scope - - abseil/strings/cordz_update_tracker - - abseil/strings/internal - - abseil/strings/strings - - abseil/types/compare - - abseil/types/optional - - abseil/types/span - - abseil/xcprivacy - - abseil/strings/cord_internal (1.20240722.0): - - abseil/base/base_internal - - abseil/base/config - - abseil/base/core_headers - - abseil/base/endian - - abseil/base/raw_logging_internal - - abseil/base/throw_delegate - - abseil/container/compressed_tuple - - abseil/container/container_memory - - abseil/container/inlined_vector - - abseil/container/layout - - abseil/crc/crc_cord_state - - abseil/functional/function_ref - - abseil/meta/type_traits - - abseil/strings/strings - - abseil/types/span - - abseil/xcprivacy - - abseil/strings/cordz_functions (1.20240722.0): - - abseil/base/config - - abseil/base/core_headers - - abseil/base/raw_logging_internal - - abseil/profiling/exponential_biased - - abseil/xcprivacy - - abseil/strings/cordz_handle (1.20240722.0): - - abseil/base/config - - abseil/base/no_destructor - - abseil/base/raw_logging_internal - - abseil/synchronization/synchronization - - abseil/xcprivacy - - abseil/strings/cordz_info (1.20240722.0): - - abseil/base/base - - abseil/base/config - - abseil/base/core_headers - - abseil/base/raw_logging_internal - - abseil/container/inlined_vector - - abseil/debugging/stacktrace - - abseil/strings/cord_internal - - abseil/strings/cordz_functions - - abseil/strings/cordz_handle - - abseil/strings/cordz_statistics - - abseil/strings/cordz_update_tracker - - abseil/synchronization/synchronization - - abseil/time/time - - abseil/types/span - - abseil/xcprivacy - - abseil/strings/cordz_statistics (1.20240722.0): - - abseil/base/config - - abseil/strings/cordz_update_tracker - - abseil/xcprivacy - - abseil/strings/cordz_update_scope (1.20240722.0): - - abseil/base/config - - abseil/base/core_headers - - abseil/strings/cord_internal - - abseil/strings/cordz_info - - abseil/strings/cordz_update_tracker - - abseil/xcprivacy - - abseil/strings/cordz_update_tracker (1.20240722.0): - - abseil/base/config - - abseil/xcprivacy - - abseil/strings/has_ostream_operator (1.20240722.0): - - abseil/base/config - - abseil/xcprivacy - - abseil/strings/internal (1.20240722.0): - - abseil/base/config - - abseil/base/core_headers - - abseil/base/endian - - abseil/base/raw_logging_internal - - abseil/meta/type_traits - - abseil/xcprivacy - - abseil/strings/str_format (1.20240722.0): - - abseil/base/config - - abseil/base/core_headers - - abseil/base/nullability - - abseil/strings/str_format_internal - - abseil/strings/string_view - - abseil/types/span - - abseil/xcprivacy - - abseil/strings/str_format_internal (1.20240722.0): - - abseil/base/config - - abseil/base/core_headers - - abseil/container/fixed_array - - abseil/container/inlined_vector - - abseil/functional/function_ref - - abseil/meta/type_traits - - abseil/numeric/bits - - abseil/numeric/int128 - - abseil/numeric/representation - - abseil/strings/strings - - abseil/types/optional - - abseil/types/span - - abseil/utility/utility - - abseil/xcprivacy - - abseil/strings/string_view (1.20240722.0): - - abseil/base/base - - abseil/base/config - - abseil/base/core_headers - - abseil/base/nullability - - abseil/base/throw_delegate - - abseil/xcprivacy - - abseil/strings/strings (1.20240722.0): - - abseil/base/base - - abseil/base/config - - abseil/base/core_headers - - abseil/base/endian - - abseil/base/nullability - - abseil/base/raw_logging_internal - - abseil/base/throw_delegate - - abseil/memory/memory - - abseil/meta/type_traits - - abseil/numeric/bits - - abseil/numeric/int128 - - abseil/strings/charset - - abseil/strings/internal - - abseil/strings/string_view - - abseil/xcprivacy - - abseil/synchronization/graphcycles_internal (1.20240722.0): - - abseil/base/base - - abseil/base/base_internal - - abseil/base/config - - abseil/base/core_headers - - abseil/base/malloc_internal - - abseil/base/raw_logging_internal - - abseil/xcprivacy - - abseil/synchronization/kernel_timeout_internal (1.20240722.0): - - abseil/base/base - - abseil/base/config - - abseil/base/core_headers - - abseil/base/raw_logging_internal - - abseil/time/time - - abseil/xcprivacy - - abseil/synchronization/synchronization (1.20240722.0): - - abseil/base/atomic_hook - - abseil/base/base - - abseil/base/base_internal - - abseil/base/config - - abseil/base/core_headers - - abseil/base/dynamic_annotations - - abseil/base/malloc_internal - - abseil/base/raw_logging_internal - - abseil/debugging/stacktrace - - abseil/debugging/symbolize - - abseil/synchronization/graphcycles_internal - - abseil/synchronization/kernel_timeout_internal - - abseil/time/time - - abseil/xcprivacy - - abseil/time (1.20240722.0): - - abseil/time/internal (= 1.20240722.0) - - abseil/time/time (= 1.20240722.0) - - abseil/time/internal (1.20240722.0): - - abseil/time/internal/cctz (= 1.20240722.0) - - abseil/time/internal/cctz (1.20240722.0): - - abseil/time/internal/cctz/civil_time (= 1.20240722.0) - - abseil/time/internal/cctz/time_zone (= 1.20240722.0) - - abseil/time/internal/cctz/civil_time (1.20240722.0): - - abseil/base/config - - abseil/xcprivacy - - abseil/time/internal/cctz/time_zone (1.20240722.0): - - abseil/base/config - - abseil/time/internal/cctz/civil_time - - abseil/xcprivacy - - abseil/time/time (1.20240722.0): - - abseil/base/base - - abseil/base/config - - abseil/base/core_headers - - abseil/base/raw_logging_internal - - abseil/numeric/int128 - - abseil/strings/strings - - abseil/time/internal/cctz/civil_time - - abseil/time/internal/cctz/time_zone - - abseil/types/optional - - abseil/xcprivacy - - abseil/types (1.20240722.0): - - abseil/types/any (= 1.20240722.0) - - abseil/types/bad_any_cast (= 1.20240722.0) - - abseil/types/bad_any_cast_impl (= 1.20240722.0) - - abseil/types/bad_optional_access (= 1.20240722.0) - - abseil/types/bad_variant_access (= 1.20240722.0) - - abseil/types/compare (= 1.20240722.0) - - abseil/types/optional (= 1.20240722.0) - - abseil/types/span (= 1.20240722.0) - - abseil/types/variant (= 1.20240722.0) - - abseil/types/any (1.20240722.0): - - abseil/base/config - - abseil/base/core_headers - - abseil/base/fast_type_id - - abseil/meta/type_traits - - abseil/types/bad_any_cast - - abseil/utility/utility - - abseil/xcprivacy - - abseil/types/bad_any_cast (1.20240722.0): - - abseil/base/config - - abseil/types/bad_any_cast_impl - - abseil/xcprivacy - - abseil/types/bad_any_cast_impl (1.20240722.0): - - abseil/base/config - - abseil/base/raw_logging_internal - - abseil/xcprivacy - - abseil/types/bad_optional_access (1.20240722.0): - - abseil/base/config - - abseil/base/raw_logging_internal - - abseil/xcprivacy - - abseil/types/bad_variant_access (1.20240722.0): - - abseil/base/config - - abseil/base/raw_logging_internal - - abseil/xcprivacy - - abseil/types/compare (1.20240722.0): - - abseil/base/config - - abseil/base/core_headers - - abseil/meta/type_traits - - abseil/xcprivacy - - abseil/types/optional (1.20240722.0): - - abseil/base/base_internal - - abseil/base/config - - abseil/base/core_headers - - abseil/base/nullability - - abseil/memory/memory - - abseil/meta/type_traits - - abseil/types/bad_optional_access - - abseil/utility/utility - - abseil/xcprivacy - - abseil/types/span (1.20240722.0): - - abseil/algorithm/algorithm - - abseil/base/core_headers - - abseil/base/nullability - - abseil/base/throw_delegate - - abseil/meta/type_traits - - abseil/xcprivacy - - abseil/types/variant (1.20240722.0): - - abseil/base/base_internal - - abseil/base/config - - abseil/base/core_headers - - abseil/meta/type_traits - - abseil/types/bad_variant_access - - abseil/utility/utility - - abseil/xcprivacy - - abseil/utility/utility (1.20240722.0): - - abseil/base/base_internal - - abseil/base/config - - abseil/meta/type_traits - - abseil/xcprivacy - - abseil/xcprivacy (1.20240722.0) - - Alamofire (5.9.1) - - app_links (0.0.2): - - Flutter - - AppAuth (1.7.6): - - AppAuth/Core (= 1.7.6) - - AppAuth/ExternalUserAgent (= 1.7.6) - - AppAuth/Core (1.7.6) - - AppAuth/ExternalUserAgent (1.7.6): - - AppAuth/Core - - AppCheckCore (11.2.0): - - GoogleUtilities/Environment (~> 8.0) - - GoogleUtilities/UserDefaults (~> 8.0) - - PromisesObjC (~> 2.4) - - AppMetricaAdSupport (5.12.1): - - AppMetricaCore (= 5.12.1) - - AppMetricaCoreExtension (= 5.12.1) - - AppMetricaCore (5.12.1): - - AppMetricaCoreUtils (= 5.12.1) - - AppMetricaEncodingUtils (= 5.12.1) - - AppMetricaFMDB (= 5.12.1) - - AppMetricaHostState (= 5.12.1) - - AppMetricaIdentifiers (= 5.12.1) - - AppMetricaKeychain (= 5.12.1) - - AppMetricaLog (= 5.12.1) - - AppMetricaNetwork (= 5.12.1) - - AppMetricaPlatform (= 5.12.1) - - AppMetricaProtobuf (= 5.12.1) - - AppMetricaProtobufUtils (= 5.12.1) - - AppMetricaStorageUtils (= 5.12.1) - - AppMetricaCoreExtension (5.12.1): - - AppMetricaCore (= 5.12.1) - - AppMetricaStorageUtils (= 5.12.1) - - AppMetricaCoreUtils (5.12.1): - - AppMetricaLog (= 5.12.1) - - AppMetricaCrashes (5.12.1): - - AppMetricaCore (= 5.12.1) - - AppMetricaCoreExtension (= 5.12.1) - - AppMetricaCoreUtils (= 5.12.1) - - AppMetricaEncodingUtils (= 5.12.1) - - AppMetricaHostState (= 5.12.1) - - AppMetricaLog (= 5.12.1) - - AppMetricaPlatform (= 5.12.1) - - AppMetricaProtobufUtils (= 5.12.1) - - AppMetricaStorageUtils (= 5.12.1) - - KSCrash/Recording (< 2.2.0, >= 2.1.0) - - AppMetricaEncodingUtils (5.12.1): - - AppMetricaCoreUtils (= 5.12.1) - - AppMetricaLog (= 5.12.1) - - AppMetricaPlatform (= 5.12.1) - - AppMetricaFMDB (5.12.1) - - AppMetricaHostState (5.12.1): - - AppMetricaCoreUtils (= 5.12.1) - - AppMetricaLog (= 5.12.1) - - AppMetricaIdentifiers (5.12.1): - - AppMetricaKeychain (= 5.12.1) - - AppMetricaLogSwift (= 5.12.1) - - AppMetricaPlatform (= 5.12.1) - - AppMetricaStorageUtils (= 5.12.1) - - AppMetricaSynchronization (= 5.12.1) - - AppMetricaKeychain (5.12.1): - - AppMetricaCoreUtils (= 5.12.1) - - AppMetricaLog (= 5.12.1) - - AppMetricaStorageUtils (= 5.12.1) - - AppMetricaLibraryAdapter (5.12.1): - - AppMetricaCore (= 5.12.1) - - AppMetricaCoreExtension (= 5.12.1) - - AppMetricaLog (5.12.1) - - AppMetricaLogSwift (5.12.1): - - AppMetricaLog (= 5.12.1) - - AppMetricaNetwork (5.12.1): - - AppMetricaCoreUtils (= 5.12.1) - - AppMetricaLog (= 5.12.1) - - AppMetricaPlatform (= 5.12.1) - - AppMetricaPlatform (5.12.1): - - AppMetricaCoreUtils (= 5.12.1) - - AppMetricaLog (= 5.12.1) - - AppMetricaProtobuf (5.12.1) - - AppMetricaProtobufUtils (5.12.1): - - AppMetricaProtobuf (= 5.12.1) - - AppMetricaStorageUtils (5.12.1): - - AppMetricaCoreUtils (= 5.12.1) - - AppMetricaLog (= 5.12.1) - - AppMetricaSynchronization (5.12.1): - - AppMetricaLogSwift (= 5.12.1) - - BoringSSL-GRPC (0.0.37): - - BoringSSL-GRPC/Implementation (= 0.0.37) - - BoringSSL-GRPC/Interface (= 0.0.37) - - BoringSSL-GRPC/Implementation (0.0.37): - - BoringSSL-GRPC/Interface (= 0.0.37) - - BoringSSL-GRPC/Interface (0.0.37) - - cloud_firestore (5.6.11): - - Firebase/Firestore (= 11.15.0) - - firebase_core - - Flutter - - CocoaAsyncSocket (7.6.5) - - CryptoSwift (1.8.4) - - device_info_plus (0.0.1): - - Flutter - - DivKit (31.14.0): - - DivKit_LayoutKit (= 31.14.0) - - DivKit_Serialization (= 31.14.0) - - VGSL (~> 7.1) - - DivKit_LayoutKit (31.14.0): - - DivKit_LayoutKitInterface (= 31.14.0) - - VGSL (~> 7.1) - - DivKit_LayoutKitInterface (31.14.0): - - VGSL (~> 7.1) - - DivKit_Serialization (31.14.0): - - VGSL (~> 7.1) - - DivKitBinaryCompatibilityFacade (4.6.1): - - DivKit (~> 31.4) - - DKImagePickerController/Core (4.3.9): - - DKImagePickerController/ImageDataManager - - DKImagePickerController/Resource - - DKImagePickerController/ImageDataManager (4.3.9) - - DKImagePickerController/PhotoGallery (4.3.9): - - DKImagePickerController/Core - - DKPhotoGallery - - DKImagePickerController/Resource (4.3.9) - - DKPhotoGallery (0.0.19): - - DKPhotoGallery/Core (= 0.0.19) - - DKPhotoGallery/Model (= 0.0.19) - - DKPhotoGallery/Preview (= 0.0.19) - - DKPhotoGallery/Resource (= 0.0.19) - - SDWebImage - - SwiftyGif - - DKPhotoGallery/Core (0.0.19): - - DKPhotoGallery/Model - - DKPhotoGallery/Preview - - SDWebImage - - SwiftyGif - - DKPhotoGallery/Model (0.0.19): - - SDWebImage - - SwiftyGif - - DKPhotoGallery/Preview (0.0.19): - - DKPhotoGallery/Model - - DKPhotoGallery/Resource - - SDWebImage - - SwiftyGif - - DKPhotoGallery/Resource (0.0.19): - - SDWebImage - - SwiftyGif - - file_picker (0.0.1): - - DKImagePickerController/PhotoGallery - - Flutter - - Firebase/Analytics (11.15.0): - - Firebase/Core - - Firebase/Core (11.15.0): - - Firebase/CoreOnly - - FirebaseAnalytics (~> 11.15.0) - - Firebase/CoreOnly (11.15.0): - - FirebaseCore (~> 11.15.0) - - Firebase/Crashlytics (11.15.0): - - Firebase/CoreOnly - - FirebaseCrashlytics (~> 11.15.0) - - Firebase/Firestore (11.15.0): - - Firebase/CoreOnly - - FirebaseFirestore (~> 11.15.0) - - Firebase/Messaging (11.15.0): - - Firebase/CoreOnly - - FirebaseMessaging (~> 11.15.0) - - Firebase/RemoteConfig (11.15.0): - - Firebase/CoreOnly - - FirebaseRemoteConfig (~> 11.15.0) - - firebase_analytics (11.5.2): - - Firebase/Analytics (= 11.15.0) - - firebase_core - - Flutter - - firebase_core (3.15.1): - - Firebase/CoreOnly (= 11.15.0) - - Flutter - - firebase_crashlytics (4.3.9): - - Firebase/Crashlytics (= 11.15.0) - - firebase_core - - Flutter - - firebase_messaging (15.2.9): - - Firebase/Messaging (= 11.15.0) - - firebase_core - - Flutter - - firebase_remote_config (5.4.7): - - Firebase/RemoteConfig (= 11.15.0) - - firebase_core - - Flutter - - FirebaseABTesting (11.15.0): - - FirebaseCore (~> 11.15.0) - - FirebaseAnalytics (11.15.0): - - FirebaseAnalytics/Default (= 11.15.0) - - FirebaseCore (~> 11.15.0) - - FirebaseInstallations (~> 11.0) - - GoogleUtilities/AppDelegateSwizzler (~> 8.1) - - GoogleUtilities/MethodSwizzler (~> 8.1) - - GoogleUtilities/Network (~> 8.1) - - "GoogleUtilities/NSData+zlib (~> 8.1)" - - nanopb (~> 3.30910.0) - - FirebaseAnalytics/Default (11.15.0): - - FirebaseCore (~> 11.15.0) - - FirebaseInstallations (~> 11.0) - - GoogleAppMeasurement/Default (= 11.15.0) - - GoogleUtilities/AppDelegateSwizzler (~> 8.1) - - GoogleUtilities/MethodSwizzler (~> 8.1) - - GoogleUtilities/Network (~> 8.1) - - "GoogleUtilities/NSData+zlib (~> 8.1)" - - nanopb (~> 3.30910.0) - - FirebaseAppCheckInterop (11.15.0) - - FirebaseCore (11.15.0): - - FirebaseCoreInternal (~> 11.15.0) - - GoogleUtilities/Environment (~> 8.1) - - GoogleUtilities/Logger (~> 8.1) - - FirebaseCoreExtension (11.15.0): - - FirebaseCore (~> 11.15.0) - - FirebaseCoreInternal (11.15.0): - - "GoogleUtilities/NSData+zlib (~> 8.1)" - - FirebaseCrashlytics (11.15.0): - - FirebaseCore (~> 11.15.0) - - FirebaseInstallations (~> 11.0) - - FirebaseRemoteConfigInterop (~> 11.0) - - FirebaseSessions (~> 11.0) - - GoogleDataTransport (~> 10.0) - - GoogleUtilities/Environment (~> 8.1) - - nanopb (~> 3.30910.0) - - PromisesObjC (~> 2.4) - - FirebaseFirestore (11.15.0): - - FirebaseCore (~> 11.15.0) - - FirebaseCoreExtension (~> 11.15.0) - - FirebaseFirestoreInternal (= 11.15.0) - - FirebaseSharedSwift (~> 11.0) - - FirebaseFirestoreInternal (11.15.0): - - abseil/algorithm (~> 1.20240722.0) - - abseil/base (~> 1.20240722.0) - - abseil/container/flat_hash_map (~> 1.20240722.0) - - abseil/memory (~> 1.20240722.0) - - abseil/meta (~> 1.20240722.0) - - abseil/strings/strings (~> 1.20240722.0) - - abseil/time (~> 1.20240722.0) - - abseil/types (~> 1.20240722.0) - - FirebaseAppCheckInterop (~> 11.0) - - FirebaseCore (~> 11.15.0) - - "gRPC-C++ (~> 1.69.0)" - - gRPC-Core (~> 1.69.0) - - leveldb-library (~> 1.22) - - nanopb (~> 3.30910.0) - - FirebaseInstallations (11.15.0): - - FirebaseCore (~> 11.15.0) - - GoogleUtilities/Environment (~> 8.1) - - GoogleUtilities/UserDefaults (~> 8.1) - - PromisesObjC (~> 2.4) - - FirebaseMessaging (11.15.0): - - FirebaseCore (~> 11.15.0) - - FirebaseInstallations (~> 11.0) - - GoogleDataTransport (~> 10.0) - - GoogleUtilities/AppDelegateSwizzler (~> 8.1) - - GoogleUtilities/Environment (~> 8.1) - - GoogleUtilities/Reachability (~> 8.1) - - GoogleUtilities/UserDefaults (~> 8.1) - - nanopb (~> 3.30910.0) - - FirebaseRemoteConfig (11.15.0): - - FirebaseABTesting (~> 11.0) - - FirebaseCore (~> 11.15.0) - - FirebaseInstallations (~> 11.0) - - FirebaseRemoteConfigInterop (~> 11.0) - - FirebaseSharedSwift (~> 11.0) - - GoogleUtilities/Environment (~> 8.1) - - "GoogleUtilities/NSData+zlib (~> 8.1)" - - FirebaseRemoteConfigInterop (11.15.0) - - FirebaseSessions (11.15.0): - - FirebaseCore (~> 11.15.0) - - FirebaseCoreExtension (~> 11.15.0) - - FirebaseInstallations (~> 11.0) - - GoogleDataTransport (~> 10.0) - - GoogleUtilities/Environment (~> 8.1) - - GoogleUtilities/UserDefaults (~> 8.1) - - nanopb (~> 3.30910.0) - - PromisesSwift (~> 2.1) - - FirebaseSharedSwift (11.15.0) - - Flutter (1.0.0) - - flutter_local_notifications (0.0.1): - - Flutter - - flutter_native_splash (2.4.3): - - Flutter - - flutter_secure_storage (6.0.0): - - Flutter - - flutter_tts (0.0.1): - - Flutter - - google_sign_in_ios (0.0.1): - - AppAuth (>= 1.7.4) - - Flutter - - FlutterMacOS - - GoogleSignIn (~> 8.0) - - GTMSessionFetcher (>= 3.4.0) - - GoogleAdsOnDeviceConversion (2.1.0): - - GoogleUtilities/Logger (~> 8.1) - - GoogleUtilities/Network (~> 8.1) - - nanopb (~> 3.30910.0) - - GoogleAppMeasurement/Core (11.15.0): - - GoogleUtilities/AppDelegateSwizzler (~> 8.1) - - GoogleUtilities/MethodSwizzler (~> 8.1) - - GoogleUtilities/Network (~> 8.1) - - "GoogleUtilities/NSData+zlib (~> 8.1)" - - nanopb (~> 3.30910.0) - - GoogleAppMeasurement/Default (11.15.0): - - GoogleAdsOnDeviceConversion (= 2.1.0) - - GoogleAppMeasurement/Core (= 11.15.0) - - GoogleAppMeasurement/IdentitySupport (= 11.15.0) - - GoogleUtilities/AppDelegateSwizzler (~> 8.1) - - GoogleUtilities/MethodSwizzler (~> 8.1) - - GoogleUtilities/Network (~> 8.1) - - "GoogleUtilities/NSData+zlib (~> 8.1)" - - nanopb (~> 3.30910.0) - - GoogleAppMeasurement/IdentitySupport (11.15.0): - - GoogleAppMeasurement/Core (= 11.15.0) - - GoogleUtilities/AppDelegateSwizzler (~> 8.1) - - GoogleUtilities/MethodSwizzler (~> 8.1) - - GoogleUtilities/Network (~> 8.1) - - "GoogleUtilities/NSData+zlib (~> 8.1)" - - nanopb (~> 3.30910.0) - - GoogleDataTransport (10.1.0): - - nanopb (~> 3.30910.0) - - PromisesObjC (~> 2.4) - - GoogleSignIn (8.0.0): - - AppAuth (< 2.0, >= 1.7.3) - - AppCheckCore (~> 11.0) - - GTMAppAuth (< 5.0, >= 4.1.1) - - GTMSessionFetcher/Core (~> 3.3) - - GoogleUtilities/AppDelegateSwizzler (8.1.0): - - GoogleUtilities/Environment - - GoogleUtilities/Logger - - GoogleUtilities/Network - - GoogleUtilities/Privacy - - GoogleUtilities/Environment (8.1.0): - - GoogleUtilities/Privacy - - GoogleUtilities/Logger (8.1.0): - - GoogleUtilities/Environment - - GoogleUtilities/Privacy - - GoogleUtilities/MethodSwizzler (8.1.0): - - GoogleUtilities/Logger - - GoogleUtilities/Privacy - - GoogleUtilities/Network (8.1.0): - - GoogleUtilities/Logger - - "GoogleUtilities/NSData+zlib" - - GoogleUtilities/Privacy - - GoogleUtilities/Reachability - - "GoogleUtilities/NSData+zlib (8.1.0)": - - GoogleUtilities/Privacy - - GoogleUtilities/Privacy (8.1.0) - - GoogleUtilities/Reachability (8.1.0): - - GoogleUtilities/Logger - - GoogleUtilities/Privacy - - GoogleUtilities/UserDefaults (8.1.0): - - GoogleUtilities/Logger - - GoogleUtilities/Privacy - - "gRPC-C++ (1.69.0)": - - "gRPC-C++/Implementation (= 1.69.0)" - - "gRPC-C++/Interface (= 1.69.0)" - - "gRPC-C++/Implementation (1.69.0)": - - abseil/algorithm/container (~> 1.20240722.0) - - abseil/base/base (~> 1.20240722.0) - - abseil/base/config (~> 1.20240722.0) - - abseil/base/core_headers (~> 1.20240722.0) - - abseil/base/log_severity (~> 1.20240722.0) - - abseil/base/no_destructor (~> 1.20240722.0) - - abseil/cleanup/cleanup (~> 1.20240722.0) - - abseil/container/flat_hash_map (~> 1.20240722.0) - - abseil/container/flat_hash_set (~> 1.20240722.0) - - abseil/container/inlined_vector (~> 1.20240722.0) - - abseil/flags/flag (~> 1.20240722.0) - - abseil/flags/marshalling (~> 1.20240722.0) - - abseil/functional/any_invocable (~> 1.20240722.0) - - abseil/functional/bind_front (~> 1.20240722.0) - - abseil/functional/function_ref (~> 1.20240722.0) - - abseil/hash/hash (~> 1.20240722.0) - - abseil/log/absl_check (~> 1.20240722.0) - - abseil/log/absl_log (~> 1.20240722.0) - - abseil/log/check (~> 1.20240722.0) - - abseil/log/globals (~> 1.20240722.0) - - abseil/log/log (~> 1.20240722.0) - - abseil/memory/memory (~> 1.20240722.0) - - abseil/meta/type_traits (~> 1.20240722.0) - - abseil/numeric/bits (~> 1.20240722.0) - - abseil/random/bit_gen_ref (~> 1.20240722.0) - - abseil/random/distributions (~> 1.20240722.0) - - abseil/random/random (~> 1.20240722.0) - - abseil/status/status (~> 1.20240722.0) - - abseil/status/statusor (~> 1.20240722.0) - - abseil/strings/cord (~> 1.20240722.0) - - abseil/strings/str_format (~> 1.20240722.0) - - abseil/strings/strings (~> 1.20240722.0) - - abseil/synchronization/synchronization (~> 1.20240722.0) - - abseil/time/time (~> 1.20240722.0) - - abseil/types/optional (~> 1.20240722.0) - - abseil/types/span (~> 1.20240722.0) - - abseil/types/variant (~> 1.20240722.0) - - abseil/utility/utility (~> 1.20240722.0) - - "gRPC-C++/Interface (= 1.69.0)" - - "gRPC-C++/Privacy (= 1.69.0)" - - gRPC-Core (= 1.69.0) - - "gRPC-C++/Interface (1.69.0)" - - "gRPC-C++/Privacy (1.69.0)" - - gRPC-Core (1.69.0): - - gRPC-Core/Implementation (= 1.69.0) - - gRPC-Core/Interface (= 1.69.0) - - gRPC-Core/Implementation (1.69.0): - - abseil/algorithm/container (~> 1.20240722.0) - - abseil/base/base (~> 1.20240722.0) - - abseil/base/config (~> 1.20240722.0) - - abseil/base/core_headers (~> 1.20240722.0) - - abseil/base/log_severity (~> 1.20240722.0) - - abseil/base/no_destructor (~> 1.20240722.0) - - abseil/cleanup/cleanup (~> 1.20240722.0) - - abseil/container/flat_hash_map (~> 1.20240722.0) - - abseil/container/flat_hash_set (~> 1.20240722.0) - - abseil/container/inlined_vector (~> 1.20240722.0) - - abseil/flags/flag (~> 1.20240722.0) - - abseil/flags/marshalling (~> 1.20240722.0) - - abseil/functional/any_invocable (~> 1.20240722.0) - - abseil/functional/bind_front (~> 1.20240722.0) - - abseil/functional/function_ref (~> 1.20240722.0) - - abseil/hash/hash (~> 1.20240722.0) - - abseil/log/check (~> 1.20240722.0) - - abseil/log/globals (~> 1.20240722.0) - - abseil/log/log (~> 1.20240722.0) - - abseil/memory/memory (~> 1.20240722.0) - - abseil/meta/type_traits (~> 1.20240722.0) - - abseil/numeric/bits (~> 1.20240722.0) - - abseil/random/bit_gen_ref (~> 1.20240722.0) - - abseil/random/distributions (~> 1.20240722.0) - - abseil/random/random (~> 1.20240722.0) - - abseil/status/status (~> 1.20240722.0) - - abseil/status/statusor (~> 1.20240722.0) - - abseil/strings/cord (~> 1.20240722.0) - - abseil/strings/str_format (~> 1.20240722.0) - - abseil/strings/strings (~> 1.20240722.0) - - abseil/synchronization/synchronization (~> 1.20240722.0) - - abseil/time/time (~> 1.20240722.0) - - abseil/types/optional (~> 1.20240722.0) - - abseil/types/span (~> 1.20240722.0) - - abseil/types/variant (~> 1.20240722.0) - - abseil/utility/utility (~> 1.20240722.0) - - BoringSSL-GRPC (= 0.0.37) - - gRPC-Core/Interface (= 1.69.0) - - gRPC-Core/Privacy (= 1.69.0) - - gRPC-Core/Interface (1.69.0) - - gRPC-Core/Privacy (1.69.0) - - GTMAppAuth (4.1.1): - - AppAuth/Core (~> 1.7) - - GTMSessionFetcher/Core (< 4.0, >= 3.3) - - GTMSessionFetcher (3.5.0): - - GTMSessionFetcher/Full (= 3.5.0) - - GTMSessionFetcher/Core (3.5.0) - - GTMSessionFetcher/Full (3.5.0): - - GTMSessionFetcher/Core - - http_certificate_pinning (3.0.0): - - Alamofire (~> 5.9.0) - - CryptoSwift - - Flutter - - in_app_purchase_storekit (0.0.1): - - Flutter - - FlutterMacOS - - integration_test (0.0.1): - - Flutter - - IOSSecuritySuite (1.9.11) - - jailbreak_root_detection (1.0.1): - - Flutter - - IOSSecuritySuite (~> 1.9.10) - - KSCrash/Core (2.1.2) - - KSCrash/Recording (2.1.2): - - KSCrash/RecordingCore - - KSCrash/RecordingCore (2.1.2): - - KSCrash/Core - - leveldb-library (1.22.6) - - nanopb (3.30910.0): - - nanopb/decode (= 3.30910.0) - - nanopb/encode (= 3.30910.0) - - nanopb/decode (3.30910.0) - - nanopb/encode (3.30910.0) - - "no_screenshot (0.0.1+4)": - - Flutter - - ScreenProtectorKit (~> 1.3.1) - - package_info_plus (0.4.5): - - Flutter - - path_provider_foundation (0.0.1): - - Flutter - - FlutterMacOS - - patrol (0.0.1): - - CocoaAsyncSocket (~> 7.6) - - Flutter - - FlutterMacOS - - PromisesObjC (2.4.0) - - PromisesSwift (2.4.0): - - PromisesObjC (= 2.4.0) - - ScreenProtectorKit (1.3.1) - - SDWebImage (5.21.2): - - SDWebImage/Core (= 5.21.2) - - SDWebImage/Core (5.21.2) - - shared_preferences_foundation (0.0.1): - - Flutter - - FlutterMacOS - - SwiftyGif (5.4.5) - - url_launcher_ios (0.0.1): - - Flutter - - VGSL (7.9.2): - - VGSLFundamentals (= 7.9.2) - - VGSLNetworking (= 7.9.2) - - VGSLUI (= 7.9.2) - - VGSLFundamentals (7.9.2) - - VGSLNetworking (7.9.2): - - VGSLFundamentals (= 7.9.2) - - VGSLUI (= 7.9.2) - - VGSLUI (7.9.2): - - VGSLFundamentals (= 7.9.2) - - webview_flutter_wkwebview (0.0.1): - - Flutter - - FlutterMacOS - - yandex_mobileads (7.13.0): - - Flutter - - YandexMobileAds (~> 7.13.0) - - YandexMobileAds (7.13.0): - - AppMetricaAdSupport (< 6.0.0, >= 5.10.0) - - AppMetricaCore (< 6.0.0, >= 5.10.0) - - AppMetricaCrashes (< 6.0.0, >= 5.10.0) - - AppMetricaLibraryAdapter (< 6.0.0, >= 5.10.0) - - DivKitBinaryCompatibilityFacade (= 4.6.1) - -DEPENDENCIES: - - app_links (from `.symlinks/plugins/app_links/ios`) - - cloud_firestore (from `.symlinks/plugins/cloud_firestore/ios`) - - device_info_plus (from `.symlinks/plugins/device_info_plus/ios`) - - file_picker (from `.symlinks/plugins/file_picker/ios`) - - firebase_analytics (from `.symlinks/plugins/firebase_analytics/ios`) - - firebase_core (from `.symlinks/plugins/firebase_core/ios`) - - firebase_crashlytics (from `.symlinks/plugins/firebase_crashlytics/ios`) - - firebase_messaging (from `.symlinks/plugins/firebase_messaging/ios`) - - firebase_remote_config (from `.symlinks/plugins/firebase_remote_config/ios`) - - Flutter (from `Flutter`) - - flutter_local_notifications (from `.symlinks/plugins/flutter_local_notifications/ios`) - - flutter_native_splash (from `.symlinks/plugins/flutter_native_splash/ios`) - - flutter_secure_storage (from `.symlinks/plugins/flutter_secure_storage/ios`) - - flutter_tts (from `.symlinks/plugins/flutter_tts/ios`) - - google_sign_in_ios (from `.symlinks/plugins/google_sign_in_ios/darwin`) - - http_certificate_pinning (from `.symlinks/plugins/http_certificate_pinning/ios`) - - in_app_purchase_storekit (from `.symlinks/plugins/in_app_purchase_storekit/darwin`) - - integration_test (from `.symlinks/plugins/integration_test/ios`) - - jailbreak_root_detection (from `.symlinks/plugins/jailbreak_root_detection/ios`) - - no_screenshot (from `.symlinks/plugins/no_screenshot/ios`) - - package_info_plus (from `.symlinks/plugins/package_info_plus/ios`) - - path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`) - - patrol (from `.symlinks/plugins/patrol/darwin`) - - shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`) - - url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`) - - webview_flutter_wkwebview (from `.symlinks/plugins/webview_flutter_wkwebview/darwin`) - - yandex_mobileads (from `.symlinks/plugins/yandex_mobileads/ios`) - -SPEC REPOS: - trunk: - - abseil - - Alamofire - - AppAuth - - AppCheckCore - - AppMetricaAdSupport - - AppMetricaCore - - AppMetricaCoreExtension - - AppMetricaCoreUtils - - AppMetricaCrashes - - AppMetricaEncodingUtils - - AppMetricaFMDB - - AppMetricaHostState - - AppMetricaIdentifiers - - AppMetricaKeychain - - AppMetricaLibraryAdapter - - AppMetricaLog - - AppMetricaLogSwift - - AppMetricaNetwork - - AppMetricaPlatform - - AppMetricaProtobuf - - AppMetricaProtobufUtils - - AppMetricaStorageUtils - - AppMetricaSynchronization - - BoringSSL-GRPC - - CocoaAsyncSocket - - CryptoSwift - - DivKit - - DivKit_LayoutKit - - DivKit_LayoutKitInterface - - DivKit_Serialization - - DivKitBinaryCompatibilityFacade - - DKImagePickerController - - DKPhotoGallery - - Firebase - - FirebaseABTesting - - FirebaseAnalytics - - FirebaseAppCheckInterop - - FirebaseCore - - FirebaseCoreExtension - - FirebaseCoreInternal - - FirebaseCrashlytics - - FirebaseFirestore - - FirebaseFirestoreInternal - - FirebaseInstallations - - FirebaseMessaging - - FirebaseRemoteConfig - - FirebaseRemoteConfigInterop - - FirebaseSessions - - FirebaseSharedSwift - - GoogleAdsOnDeviceConversion - - GoogleAppMeasurement - - GoogleDataTransport - - GoogleSignIn - - GoogleUtilities - - "gRPC-C++" - - gRPC-Core - - GTMAppAuth - - GTMSessionFetcher - - IOSSecuritySuite - - KSCrash - - leveldb-library - - nanopb - - PromisesObjC - - PromisesSwift - - ScreenProtectorKit - - SDWebImage - - SwiftyGif - - VGSL - - VGSLFundamentals - - VGSLNetworking - - VGSLUI - - YandexMobileAds - -EXTERNAL SOURCES: - app_links: - :path: ".symlinks/plugins/app_links/ios" - cloud_firestore: - :path: ".symlinks/plugins/cloud_firestore/ios" - device_info_plus: - :path: ".symlinks/plugins/device_info_plus/ios" - file_picker: - :path: ".symlinks/plugins/file_picker/ios" - firebase_analytics: - :path: ".symlinks/plugins/firebase_analytics/ios" - firebase_core: - :path: ".symlinks/plugins/firebase_core/ios" - firebase_crashlytics: - :path: ".symlinks/plugins/firebase_crashlytics/ios" - firebase_messaging: - :path: ".symlinks/plugins/firebase_messaging/ios" - firebase_remote_config: - :path: ".symlinks/plugins/firebase_remote_config/ios" - Flutter: - :path: Flutter - flutter_local_notifications: - :path: ".symlinks/plugins/flutter_local_notifications/ios" - flutter_native_splash: - :path: ".symlinks/plugins/flutter_native_splash/ios" - flutter_secure_storage: - :path: ".symlinks/plugins/flutter_secure_storage/ios" - flutter_tts: - :path: ".symlinks/plugins/flutter_tts/ios" - google_sign_in_ios: - :path: ".symlinks/plugins/google_sign_in_ios/darwin" - http_certificate_pinning: - :path: ".symlinks/plugins/http_certificate_pinning/ios" - in_app_purchase_storekit: - :path: ".symlinks/plugins/in_app_purchase_storekit/darwin" - integration_test: - :path: ".symlinks/plugins/integration_test/ios" - jailbreak_root_detection: - :path: ".symlinks/plugins/jailbreak_root_detection/ios" - no_screenshot: - :path: ".symlinks/plugins/no_screenshot/ios" - package_info_plus: - :path: ".symlinks/plugins/package_info_plus/ios" - path_provider_foundation: - :path: ".symlinks/plugins/path_provider_foundation/darwin" - patrol: - :path: ".symlinks/plugins/patrol/darwin" - shared_preferences_foundation: - :path: ".symlinks/plugins/shared_preferences_foundation/darwin" - url_launcher_ios: - :path: ".symlinks/plugins/url_launcher_ios/ios" - webview_flutter_wkwebview: - :path: ".symlinks/plugins/webview_flutter_wkwebview/darwin" - yandex_mobileads: - :path: ".symlinks/plugins/yandex_mobileads/ios" - -SPEC CHECKSUMS: - abseil: a05cc83bf02079535e17169a73c5be5ba47f714b - Alamofire: f36a35757af4587d8e4f4bfa223ad10be2422b8c - app_links: 76b66b60cc809390ca1ad69bfd66b998d2387ac7 - AppAuth: d4f13a8fe0baf391b2108511793e4b479691fb73 - AppCheckCore: cc8fd0a3a230ddd401f326489c99990b013f0c4f - AppMetricaAdSupport: 26884bc5ec935a990b6bbfa938c854c0fdf1b248 - AppMetricaCore: 145ddc416db0a7eead339de9a5e1521863426a1b - AppMetricaCoreExtension: 1fc4222eef017e25e8f89c5b02b8563179a40d13 - AppMetricaCoreUtils: 9e23195da2dc2d76404ac49592e05f1dd276d1e8 - AppMetricaCrashes: 41d7e00fc2da7ca9c8de670546d65635c81ff821 - AppMetricaEncodingUtils: 02f48c8d45b7883c4e2a85d49ec3a66a39fd4f6d - AppMetricaFMDB: 482767dda08c9cec7c8d115d423aacb6b21e9e89 - AppMetricaHostState: 447bc4c02107b3531ae77fc91ea200ddc32bb029 - AppMetricaIdentifiers: 1c34f28d8650c4c5c931643ac8779f431e809c9f - AppMetricaKeychain: 76f4afe269b233c1a2493350712d24c4d18858b8 - AppMetricaLibraryAdapter: f9a428c799b5d979bf8f1fc524e58a7a3d81026c - AppMetricaLog: 84a50f144c83a7de66778dfa990db0ac1d60e10c - AppMetricaLogSwift: 3ca89a024f3c8c7b09f4b2ce89a6e7ce65b3b7d6 - AppMetricaNetwork: e8ba646d4408e2b62e272f8b49c66ffda103bfbd - AppMetricaPlatform: 543e24bd127eb94c14a708770980f9203e9403b4 - AppMetricaProtobuf: 437a155c3ea82c7fc9a5f8ff5037c513a2287225 - AppMetricaProtobufUtils: f8bf3222d88f466363a657dd14b575af16327d81 - AppMetricaStorageUtils: e10b5fbf8c8d9125ad200a360c9e95e53c7a0f3c - AppMetricaSynchronization: 3c019f1c791e11f80de51cacda4b2ed4b20935a8 - BoringSSL-GRPC: dded2a44897e45f28f08ae87a55ee4bcd19bc508 - cloud_firestore: 8b8ad857da9a98527dab9c7ae520d0eba975bef9 - CocoaAsyncSocket: 065fd1e645c7abab64f7a6a2007a48038fdc6a99 - CryptoSwift: e64e11850ede528a02a0f3e768cec8e9d92ecb90 - device_info_plus: 71ffc6ab7634ade6267c7a93088ed7e4f74e5896 - DivKit: 6199401ae3cd647f34a151d7a13e904cf0b652dd - DivKit_LayoutKit: 1f3c4f4f7623bdb72201e9f11423b6c827614261 - DivKit_LayoutKitInterface: 1d0a2b7093a881c91577c25241c3ee14b1e56447 - DivKit_Serialization: 8383d924c65cc2f3cddc6f7b21f593f35bf5b2aa - DivKitBinaryCompatibilityFacade: 99f7ce6693fe3705c8ccb8c6d8c27aae0637b5ec - DKImagePickerController: 946cec48c7873164274ecc4624d19e3da4c1ef3c - DKPhotoGallery: b3834fecb755ee09a593d7c9e389d8b5d6deed60 - file_picker: a0560bc09d61de87f12d246fc47d2119e6ef37be - Firebase: d99ac19b909cd2c548339c2241ecd0d1599ab02e - firebase_analytics: 740475b8bf6f9a79b04c2d55fe226a60679fe593 - firebase_core: ece862f94b2bc72ee0edbeec7ab5c7cb09fe1ab5 - firebase_crashlytics: f89f5137e667ba1733ca5d7ab1b7af3390572520 - firebase_messaging: e1a5fae495603115be1d0183bc849da748734e2b - firebase_remote_config: 88ede24650cdf0916188dc2fe4138e3a03e62712 - FirebaseABTesting: 5e9d432834aebf27ab72100d37af44dfbe8d82f7 - FirebaseAnalytics: 6433dfd311ba78084fc93bdfc145e8cb75740eae - FirebaseAppCheckInterop: 06fe5a3799278ae4667e6c432edd86b1030fa3df - FirebaseCore: efb3893e5b94f32b86e331e3bd6dadf18b66568e - FirebaseCoreExtension: edbd30474b5ccf04e5f001470bdf6ea616af2435 - FirebaseCoreInternal: 9afa45b1159304c963da48addb78275ef701c6b4 - FirebaseCrashlytics: e09d0bc19aa54a51e45b8039c836ef73f32c039a - FirebaseFirestore: 1e5fafdac2b2ef1ffc24034460b7b4821a15be96 - FirebaseFirestoreInternal: df9ab608a59a4e8eefd0796ed7652f3c1a88473a - FirebaseInstallations: 317270fec08a5d418fdbc8429282238cab3ac843 - FirebaseMessaging: 3b26e2cee503815e01c3701236b020aa9b576f09 - FirebaseRemoteConfig: b496646b82855e174a7f1e354c65e0e913085168 - FirebaseRemoteConfigInterop: 1c6135e8a094cc6368949f5faeeca7ee8948b8aa - FirebaseSessions: b9a92c1c51bbb81e78fc3142cda6d925d700f8e7 - FirebaseSharedSwift: e17c654ef1f1a616b0b33054e663ad1035c8fd40 - Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7 - flutter_local_notifications: a5a732f069baa862e728d839dd2ebb904737effb - flutter_native_splash: 6cad9122ea0fad137d23137dd14b937f3e90b145 - flutter_secure_storage: 1ed9476fba7e7a782b22888f956cce43e2c62f13 - flutter_tts: b88dbc8655d3dc961bc4a796e4e16a4cc1795833 - google_sign_in_ios: b48bb9af78576358a168361173155596c845f0b9 - GoogleAdsOnDeviceConversion: 2be6297a4f048459e0ae17fad9bfd2844e10cf64 - GoogleAppMeasurement: 700dce7541804bec33db590a5c496b663fbe2539 - GoogleDataTransport: aae35b7ea0c09004c3797d53c8c41f66f219d6a7 - GoogleSignIn: ce8c89bb9b37fb624b92e7514cc67335d1e277e4 - GoogleUtilities: 00c88b9a86066ef77f0da2fab05f65d7768ed8e1 - "gRPC-C++": cc207623316fb041a7a3e774c252cf68a058b9e8 - gRPC-Core: 860978b7db482de8b4f5e10677216309b5ff6330 - GTMAppAuth: f69bd07d68cd3b766125f7e072c45d7340dea0de - GTMSessionFetcher: 5aea5ba6bd522a239e236100971f10cb71b96ab6 - http_certificate_pinning: 133f28ad5c2d1ecda2581dd2d2cd9dc74da59012 - in_app_purchase_storekit: d1a48cb0f8b29dbf5f85f782f5dd79b21b90a5e6 - integration_test: 4a889634ef21a45d28d50d622cf412dc6d9f586e - IOSSecuritySuite: b51056d5411aee567153ca86ce7f6edfdc5d2654 - jailbreak_root_detection: 9201e1dfd51dc23069cbfb8d4f4a2d18305170bf - KSCrash: bd950ede6c40a50bfc9f246c38a7f3408705fa3c - leveldb-library: cc8b8f8e013647a295ad3f8cd2ddf49a6f19be19 - nanopb: fad817b59e0457d11a5dfbde799381cd727c1275 - no_screenshot: 6d183496405a3ab709a67a54e5cd0f639e94729e - package_info_plus: af8e2ca6888548050f16fa2f1938db7b5a5df499 - path_provider_foundation: 080d55be775b7414fd5a5ef3ac137b97b097e564 - patrol: 5df5d241d7f95f0df12a6906bbf45acb43a1e537 - PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47 - PromisesSwift: 9d77319bbe72ebf6d872900551f7eeba9bce2851 - ScreenProtectorKit: 83a6281b02c7a5902ee6eac4f5045f674e902ae4 - SDWebImage: 9f177d83116802728e122410fb25ad88f5c7608a - shared_preferences_foundation: 9e1978ff2562383bd5676f64ec4e9aa8fa06a6f7 - SwiftyGif: 706c60cf65fa2bc5ee0313beece843c8eb8194d4 - url_launcher_ios: 694010445543906933d732453a59da0a173ae33d - VGSL: cb706f55602d4b7849b62f4bef5cb4446a704e68 - VGSLFundamentals: 6d841efd7f661e6f2c28ee00b746ccbb79cd9edc - VGSLNetworking: 73414dd21c1d8f665bf01e725e42a59b53a8fd90 - VGSLUI: fa73227854aab89f844416d7ef49356921d955e2 - webview_flutter_wkwebview: 1821ceac936eba6f7984d89a9f3bcb4dea99ebb2 - yandex_mobileads: 47af34998142ae0909a6e2028d65db883c0890f8 - YandexMobileAds: 00a62ca359bc6510bf5d3b54f3d4c58ab1039608 - -PODFILE CHECKSUM: c8531e6f885a8636272dd138b4a3665a6db5268c - -COCOAPODS: 1.16.2 diff --git a/mnemo_cards/ios/Runner.xcodeproj/project.pbxproj b/mnemo_cards/ios/Runner.xcodeproj/project.pbxproj deleted file mode 100644 index bfbc0fe..0000000 --- a/mnemo_cards/ios/Runner.xcodeproj/project.pbxproj +++ /dev/null @@ -1,753 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 54; - objects = { - -/* Begin PBXBuildFile section */ - 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; - 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; }; - 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; - 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; - 88925E0304DA934B99CF07B5 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 039AEB256EC09C6DAD0D33F6 /* GoogleService-Info.plist */; }; - 92F786B29EF12520764C9B34 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 88D363FEAADB3317B3E14A0A /* Pods_Runner.framework */; }; - 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; - 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; - 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; - CF53E9FF8298D562D675E324 /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F30B1603BBE3F803AFE2385E /* Pods_RunnerTests.framework */; }; -/* End PBXBuildFile section */ - -/* Begin PBXContainerItemProxy section */ - 331C8085294A63A400263BE5 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 97C146E61CF9000F007C117D /* Project object */; - proxyType = 1; - remoteGlobalIDString = 97C146ED1CF9000F007C117D; - remoteInfo = Runner; - }; -/* End PBXContainerItemProxy section */ - -/* Begin PBXCopyFilesBuildPhase section */ - 9705A1C41CF9048500538489 /* Embed Frameworks */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = ""; - dstSubfolderSpec = 10; - files = ( - ); - name = "Embed Frameworks"; - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXCopyFilesBuildPhase section */ - -/* Begin PBXFileReference section */ - 039AEB256EC09C6DAD0D33F6 /* GoogleService-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; name = "GoogleService-Info.plist"; path = "Runner/GoogleService-Info.plist"; sourceTree = ""; }; - 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; - 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; - 331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; - 331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; - 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; - 4CC79C7D41E157D878D889F0 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; - 5B971DEAC48A015D192A8EAB /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; - 5DA2E070BDB961F389CD961D /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; - 5EFDFD0076C43FC4B256A2F9 /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = ""; }; - 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; - 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; - 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; - 88D363FEAADB3317B3E14A0A /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; - 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; - 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; - 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; - 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; - 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; - 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - D56245B45AA4EC506A74FF4E /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = ""; }; - F30B1603BBE3F803AFE2385E /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - F34F38B9F662A96F77B6E782 /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = ""; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - 7F8493084A5D32479BB9EA15 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - CF53E9FF8298D562D675E324 /* Pods_RunnerTests.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 97C146EB1CF9000F007C117D /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 92F786B29EF12520764C9B34 /* Pods_Runner.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 331C8082294A63A400263BE5 /* RunnerTests */ = { - isa = PBXGroup; - children = ( - 331C807B294A618700263BE5 /* RunnerTests.swift */, - ); - path = RunnerTests; - sourceTree = ""; - }; - 70EAEEDC0F0D76C181949289 /* Frameworks */ = { - isa = PBXGroup; - children = ( - 88D363FEAADB3317B3E14A0A /* Pods_Runner.framework */, - F30B1603BBE3F803AFE2385E /* Pods_RunnerTests.framework */, - ); - name = Frameworks; - sourceTree = ""; - }; - 9740EEB11CF90186004384FC /* Flutter */ = { - isa = PBXGroup; - children = ( - 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, - 9740EEB21CF90195004384FC /* Debug.xcconfig */, - 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, - 9740EEB31CF90195004384FC /* Generated.xcconfig */, - ); - name = Flutter; - sourceTree = ""; - }; - 97C146E51CF9000F007C117D = { - isa = PBXGroup; - children = ( - 9740EEB11CF90186004384FC /* Flutter */, - 97C146F01CF9000F007C117D /* Runner */, - 97C146EF1CF9000F007C117D /* Products */, - 331C8082294A63A400263BE5 /* RunnerTests */, - 9BC5FF8B20D1CEE670C66ACD /* Pods */, - 70EAEEDC0F0D76C181949289 /* Frameworks */, - 039AEB256EC09C6DAD0D33F6 /* GoogleService-Info.plist */, - ); - sourceTree = ""; - }; - 97C146EF1CF9000F007C117D /* Products */ = { - isa = PBXGroup; - children = ( - 97C146EE1CF9000F007C117D /* Runner.app */, - 331C8081294A63A400263BE5 /* RunnerTests.xctest */, - ); - name = Products; - sourceTree = ""; - }; - 97C146F01CF9000F007C117D /* Runner */ = { - isa = PBXGroup; - children = ( - 97C146FA1CF9000F007C117D /* Main.storyboard */, - 97C146FD1CF9000F007C117D /* Assets.xcassets */, - 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, - 97C147021CF9000F007C117D /* Info.plist */, - 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, - 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, - 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, - 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, - ); - path = Runner; - sourceTree = ""; - }; - 9BC5FF8B20D1CEE670C66ACD /* Pods */ = { - isa = PBXGroup; - children = ( - 4CC79C7D41E157D878D889F0 /* Pods-Runner.debug.xcconfig */, - 5B971DEAC48A015D192A8EAB /* Pods-Runner.release.xcconfig */, - 5DA2E070BDB961F389CD961D /* Pods-Runner.profile.xcconfig */, - 5EFDFD0076C43FC4B256A2F9 /* Pods-RunnerTests.debug.xcconfig */, - F34F38B9F662A96F77B6E782 /* Pods-RunnerTests.release.xcconfig */, - D56245B45AA4EC506A74FF4E /* Pods-RunnerTests.profile.xcconfig */, - ); - path = Pods; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXNativeTarget section */ - 331C8080294A63A400263BE5 /* RunnerTests */ = { - isa = PBXNativeTarget; - buildConfigurationList = 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; - buildPhases = ( - FD56395D2DB589B058B3AF52 /* [CP] Check Pods Manifest.lock */, - 331C807D294A63A400263BE5 /* Sources */, - 331C807F294A63A400263BE5 /* Resources */, - 7F8493084A5D32479BB9EA15 /* Frameworks */, - ); - buildRules = ( - ); - dependencies = ( - 331C8086294A63A400263BE5 /* PBXTargetDependency */, - ); - name = RunnerTests; - productName = RunnerTests; - productReference = 331C8081294A63A400263BE5 /* RunnerTests.xctest */; - productType = "com.apple.product-type.bundle.unit-test"; - }; - 97C146ED1CF9000F007C117D /* Runner */ = { - isa = PBXNativeTarget; - buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; - buildPhases = ( - 11939B8737D0761B1D52BA09 /* [CP] Check Pods Manifest.lock */, - 9740EEB61CF901F6004384FC /* Run Script */, - 97C146EA1CF9000F007C117D /* Sources */, - 97C146EB1CF9000F007C117D /* Frameworks */, - 97C146EC1CF9000F007C117D /* Resources */, - 9705A1C41CF9048500538489 /* Embed Frameworks */, - 3B06AD1E1E4923F5004D2608 /* Thin Binary */, - 10510DEBDDA8DED725BA2250 /* [CP] Copy Pods Resources */, - 0B6FA649E0972BCE89E292E3 /* FlutterFire: "flutterfire upload-crashlytics-symbols" */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = Runner; - productName = Runner; - productReference = 97C146EE1CF9000F007C117D /* Runner.app */; - productType = "com.apple.product-type.application"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - 97C146E61CF9000F007C117D /* Project object */ = { - isa = PBXProject; - attributes = { - BuildIndependentTargetsInParallel = YES; - LastUpgradeCheck = 1510; - ORGANIZATIONNAME = ""; - TargetAttributes = { - 331C8080294A63A400263BE5 = { - CreatedOnToolsVersion = 14.0; - TestTargetID = 97C146ED1CF9000F007C117D; - }; - 97C146ED1CF9000F007C117D = { - CreatedOnToolsVersion = 7.3.1; - LastSwiftMigration = 1100; - }; - }; - }; - buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; - compatibilityVersion = "Xcode 9.3"; - developmentRegion = en; - hasScannedForEncodings = 0; - knownRegions = ( - en, - Base, - ); - mainGroup = 97C146E51CF9000F007C117D; - productRefGroup = 97C146EF1CF9000F007C117D /* Products */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - 97C146ED1CF9000F007C117D /* Runner */, - 331C8080294A63A400263BE5 /* RunnerTests */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXResourcesBuildPhase section */ - 331C807F294A63A400263BE5 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 97C146EC1CF9000F007C117D /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, - 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, - 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, - 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, - 88925E0304DA934B99CF07B5 /* GoogleService-Info.plist in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXResourcesBuildPhase section */ - -/* Begin PBXShellScriptBuildPhase section */ - 0B6FA649E0972BCE89E292E3 /* FlutterFire: "flutterfire upload-crashlytics-symbols" */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - ); - inputPaths = ( - ); - name = "FlutterFire: \"flutterfire upload-crashlytics-symbols\""; - outputFileListPaths = ( - ); - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\n#!/bin/bash\nPATH=${PATH}:$FLUTTER_ROOT/bin:$HOME/.pub-cache/bin\nflutterfire upload-crashlytics-symbols --upload-symbols-script-path=$PODS_ROOT/FirebaseCrashlytics/upload-symbols --platform=ios --apple-project-path=${SRCROOT} --env-platform-name=${PLATFORM_NAME} --env-configuration=${CONFIGURATION} --env-project-dir=${PROJECT_DIR} --env-built-products-dir=${BUILT_PRODUCTS_DIR} --env-dwarf-dsym-folder-path=${DWARF_DSYM_FOLDER_PATH} --env-dwarf-dsym-file-name=${DWARF_DSYM_FILE_NAME} --env-infoplist-path=${INFOPLIST_PATH} --default-config=default\n"; - }; - 10510DEBDDA8DED725BA2250 /* [CP] Copy Pods Resources */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-input-files.xcfilelist", - ); - name = "[CP] Copy Pods Resources"; - outputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-output-files.xcfilelist", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n"; - showEnvVarsInLog = 0; - }; - 11939B8737D0761B1D52BA09 /* [CP] Check Pods Manifest.lock */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - ); - inputPaths = ( - "${PODS_PODFILE_DIR_PATH}/Podfile.lock", - "${PODS_ROOT}/Manifest.lock", - ); - name = "[CP] Check Pods Manifest.lock"; - outputFileListPaths = ( - ); - outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; - showEnvVarsInLog = 0; - }; - 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { - isa = PBXShellScriptBuildPhase; - alwaysOutOfDate = 1; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - "${TARGET_BUILD_DIR}/${INFOPLIST_PATH}", - ); - name = "Thin Binary"; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; - }; - 9740EEB61CF901F6004384FC /* Run Script */ = { - isa = PBXShellScriptBuildPhase; - alwaysOutOfDate = 1; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - ); - name = "Run Script"; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; - }; - FD56395D2DB589B058B3AF52 /* [CP] Check Pods Manifest.lock */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - ); - inputPaths = ( - "${PODS_PODFILE_DIR_PATH}/Podfile.lock", - "${PODS_ROOT}/Manifest.lock", - ); - name = "[CP] Check Pods Manifest.lock"; - outputFileListPaths = ( - ); - outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-RunnerTests-checkManifestLockResult.txt", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; - showEnvVarsInLog = 0; - }; -/* End PBXShellScriptBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - 331C807D294A63A400263BE5 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 97C146EA1CF9000F007C117D /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, - 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin PBXTargetDependency section */ - 331C8086294A63A400263BE5 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 97C146ED1CF9000F007C117D /* Runner */; - targetProxy = 331C8085294A63A400263BE5 /* PBXContainerItemProxy */; - }; -/* End PBXTargetDependency section */ - -/* Begin PBXVariantGroup section */ - 97C146FA1CF9000F007C117D /* Main.storyboard */ = { - isa = PBXVariantGroup; - children = ( - 97C146FB1CF9000F007C117D /* Base */, - ); - name = Main.storyboard; - sourceTree = ""; - }; - 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { - isa = PBXVariantGroup; - children = ( - 97C147001CF9000F007C117D /* Base */, - ); - name = LaunchScreen.storyboard; - sourceTree = ""; - }; -/* End PBXVariantGroup section */ - -/* Begin XCBuildConfiguration section */ - 249021D3217E4FDB00AE95B9 /* Profile */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_USER_SCRIPT_SANDBOXING = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 14.0; - MTL_ENABLE_DEBUG_INFO = NO; - SDKROOT = iphoneos; - SUPPORTED_PLATFORMS = iphoneos; - TARGETED_DEVICE_FAMILY = "1,2"; - VALIDATE_PRODUCT = YES; - }; - name = Profile; - }; - 249021D4217E4FDB00AE95B9 /* Profile */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ENABLE_MODULES = YES; - CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; - DEVELOPMENT_TEAM = 6ZNY923QXG; - ENABLE_BITCODE = NO; - INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - ); - PRODUCT_BUNDLE_IDENTIFIER = com.cinnabarflower.mnemoCards; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; - SWIFT_VERSION = 5.0; - VERSIONING_SYSTEM = "apple-generic"; - }; - name = Profile; - }; - 331C8088294A63A400263BE5 /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 5EFDFD0076C43FC4B256A2F9 /* Pods-RunnerTests.debug.xcconfig */; - buildSettings = { - BUNDLE_LOADER = "$(TEST_HOST)"; - CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; - GENERATE_INFOPLIST_FILE = YES; - MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = com.cinnabarflower.mnemoCards.RunnerTests; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 5.0; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; - }; - name = Debug; - }; - 331C8089294A63A400263BE5 /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = F34F38B9F662A96F77B6E782 /* Pods-RunnerTests.release.xcconfig */; - buildSettings = { - BUNDLE_LOADER = "$(TEST_HOST)"; - CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; - GENERATE_INFOPLIST_FILE = YES; - MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = com.cinnabarflower.mnemoCards.RunnerTests; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 5.0; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; - }; - name = Release; - }; - 331C808A294A63A400263BE5 /* Profile */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = D56245B45AA4EC506A74FF4E /* Pods-RunnerTests.profile.xcconfig */; - buildSettings = { - BUNDLE_LOADER = "$(TEST_HOST)"; - CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; - GENERATE_INFOPLIST_FILE = YES; - MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = com.cinnabarflower.mnemoCards.RunnerTests; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 5.0; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; - }; - name = Profile; - }; - 97C147031CF9000F007C117D /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = dwarf; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_TESTABILITY = YES; - ENABLE_USER_SCRIPT_SANDBOXING = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_DYNAMIC_NO_PIC = NO; - GCC_NO_COMMON_BLOCKS = YES; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 14.0; - MTL_ENABLE_DEBUG_INFO = YES; - ONLY_ACTIVE_ARCH = YES; - SDKROOT = iphoneos; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Debug; - }; - 97C147041CF9000F007C117D /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_USER_SCRIPT_SANDBOXING = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 14.0; - MTL_ENABLE_DEBUG_INFO = NO; - SDKROOT = iphoneos; - SUPPORTED_PLATFORMS = iphoneos; - SWIFT_COMPILATION_MODE = wholemodule; - SWIFT_OPTIMIZATION_LEVEL = "-O"; - TARGETED_DEVICE_FAMILY = "1,2"; - VALIDATE_PRODUCT = YES; - }; - name = Release; - }; - 97C147061CF9000F007C117D /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ENABLE_MODULES = YES; - CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; - DEVELOPMENT_TEAM = 6ZNY923QXG; - ENABLE_BITCODE = NO; - INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - ); - PRODUCT_BUNDLE_IDENTIFIER = com.cinnabarflower.mnemoCards; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 5.0; - VERSIONING_SYSTEM = "apple-generic"; - }; - name = Debug; - }; - 97C147071CF9000F007C117D /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ENABLE_MODULES = YES; - CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; - DEVELOPMENT_TEAM = 6ZNY923QXG; - ENABLE_BITCODE = NO; - INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - ); - PRODUCT_BUNDLE_IDENTIFIER = com.cinnabarflower.mnemoCards; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; - SWIFT_VERSION = 5.0; - VERSIONING_SYSTEM = "apple-generic"; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 331C8088294A63A400263BE5 /* Debug */, - 331C8089294A63A400263BE5 /* Release */, - 331C808A294A63A400263BE5 /* Profile */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 97C147031CF9000F007C117D /* Debug */, - 97C147041CF9000F007C117D /* Release */, - 249021D3217E4FDB00AE95B9 /* Profile */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 97C147061CF9000F007C117D /* Debug */, - 97C147071CF9000F007C117D /* Release */, - 249021D4217E4FDB00AE95B9 /* Profile */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - }; - rootObject = 97C146E61CF9000F007C117D /* Project object */; -} diff --git a/mnemo_cards/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/mnemo_cards/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index 919434a..0000000 --- a/mnemo_cards/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,7 +0,0 @@ - - - - - diff --git a/mnemo_cards/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/mnemo_cards/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist deleted file mode 100644 index 18d9810..0000000 --- a/mnemo_cards/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +++ /dev/null @@ -1,8 +0,0 @@ - - - - - IDEDidComputeMac32BitWarning - - - diff --git a/mnemo_cards/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/mnemo_cards/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings deleted file mode 100644 index f9b0d7c..0000000 --- a/mnemo_cards/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings +++ /dev/null @@ -1,8 +0,0 @@ - - - - - PreviewsEnabled - - - diff --git a/mnemo_cards/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/mnemo_cards/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme deleted file mode 100644 index e3773d4..0000000 --- a/mnemo_cards/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ /dev/null @@ -1,101 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/mnemo_cards/ios/Runner.xcworkspace/contents.xcworkspacedata b/mnemo_cards/ios/Runner.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index 21a3cc1..0000000 --- a/mnemo_cards/ios/Runner.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - diff --git a/mnemo_cards/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/mnemo_cards/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist deleted file mode 100644 index 18d9810..0000000 --- a/mnemo_cards/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +++ /dev/null @@ -1,8 +0,0 @@ - - - - - IDEDidComputeMac32BitWarning - - - diff --git a/mnemo_cards/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/mnemo_cards/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings deleted file mode 100644 index f9b0d7c..0000000 --- a/mnemo_cards/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings +++ /dev/null @@ -1,8 +0,0 @@ - - - - - PreviewsEnabled - - - diff --git a/mnemo_cards/ios/Runner/AppDelegate.swift b/mnemo_cards/ios/Runner/AppDelegate.swift deleted file mode 100644 index b636303..0000000 --- a/mnemo_cards/ios/Runner/AppDelegate.swift +++ /dev/null @@ -1,13 +0,0 @@ -import UIKit -import Flutter - -@main -@objc class AppDelegate: FlutterAppDelegate { - override func application( - _ application: UIApplication, - didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? - ) -> Bool { - GeneratedPluginRegistrant.register(with: self) - return super.application(application, didFinishLaunchingWithOptions: launchOptions) - } -} diff --git a/mnemo_cards/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/mnemo_cards/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json deleted file mode 100644 index d36b1fa..0000000 --- a/mnemo_cards/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json +++ /dev/null @@ -1,122 +0,0 @@ -{ - "images" : [ - { - "size" : "20x20", - "idiom" : "iphone", - "filename" : "Icon-App-20x20@2x.png", - "scale" : "2x" - }, - { - "size" : "20x20", - "idiom" : "iphone", - "filename" : "Icon-App-20x20@3x.png", - "scale" : "3x" - }, - { - "size" : "29x29", - "idiom" : "iphone", - "filename" : "Icon-App-29x29@1x.png", - "scale" : "1x" - }, - { - "size" : "29x29", - "idiom" : "iphone", - "filename" : "Icon-App-29x29@2x.png", - "scale" : "2x" - }, - { - "size" : "29x29", - "idiom" : "iphone", - "filename" : "Icon-App-29x29@3x.png", - "scale" : "3x" - }, - { - "size" : "40x40", - "idiom" : "iphone", - "filename" : "Icon-App-40x40@2x.png", - "scale" : "2x" - }, - { - "size" : "40x40", - "idiom" : "iphone", - "filename" : "Icon-App-40x40@3x.png", - "scale" : "3x" - }, - { - "size" : "60x60", - "idiom" : "iphone", - "filename" : "Icon-App-60x60@2x.png", - "scale" : "2x" - }, - { - "size" : "60x60", - "idiom" : "iphone", - "filename" : "Icon-App-60x60@3x.png", - "scale" : "3x" - }, - { - "size" : "20x20", - "idiom" : "ipad", - "filename" : "Icon-App-20x20@1x.png", - "scale" : "1x" - }, - { - "size" : "20x20", - "idiom" : "ipad", - "filename" : "Icon-App-20x20@2x.png", - "scale" : "2x" - }, - { - "size" : "29x29", - "idiom" : "ipad", - "filename" : "Icon-App-29x29@1x.png", - "scale" : "1x" - }, - { - "size" : "29x29", - "idiom" : "ipad", - "filename" : "Icon-App-29x29@2x.png", - "scale" : "2x" - }, - { - "size" : "40x40", - "idiom" : "ipad", - "filename" : "Icon-App-40x40@1x.png", - "scale" : "1x" - }, - { - "size" : "40x40", - "idiom" : "ipad", - "filename" : "Icon-App-40x40@2x.png", - "scale" : "2x" - }, - { - "size" : "76x76", - "idiom" : "ipad", - "filename" : "Icon-App-76x76@1x.png", - "scale" : "1x" - }, - { - "size" : "76x76", - "idiom" : "ipad", - "filename" : "Icon-App-76x76@2x.png", - "scale" : "2x" - }, - { - "size" : "83.5x83.5", - "idiom" : "ipad", - "filename" : "Icon-App-83.5x83.5@2x.png", - "scale" : "2x" - }, - { - "size" : "1024x1024", - "idiom" : "ios-marketing", - "filename" : "Icon-App-1024x1024@1x.png", - "scale" : "1x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} diff --git a/mnemo_cards/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/mnemo_cards/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png deleted file mode 100644 index 8efca3a..0000000 Binary files a/mnemo_cards/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png and /dev/null differ diff --git a/mnemo_cards/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/mnemo_cards/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png deleted file mode 100644 index 226e320..0000000 Binary files a/mnemo_cards/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png and /dev/null differ diff --git a/mnemo_cards/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/mnemo_cards/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png deleted file mode 100644 index 9b3f66b..0000000 Binary files a/mnemo_cards/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png and /dev/null differ diff --git a/mnemo_cards/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/mnemo_cards/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png deleted file mode 100644 index 03475e4..0000000 Binary files a/mnemo_cards/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png and /dev/null differ diff --git a/mnemo_cards/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/mnemo_cards/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png deleted file mode 100644 index e576db3..0000000 Binary files a/mnemo_cards/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png and /dev/null differ diff --git a/mnemo_cards/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/mnemo_cards/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png deleted file mode 100644 index 5c19bdc..0000000 Binary files a/mnemo_cards/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png and /dev/null differ diff --git a/mnemo_cards/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png b/mnemo_cards/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png deleted file mode 100644 index 9d26dc7..0000000 Binary files a/mnemo_cards/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png and /dev/null differ diff --git a/mnemo_cards/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png b/mnemo_cards/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png deleted file mode 100644 index 9b3f66b..0000000 Binary files a/mnemo_cards/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png and /dev/null differ diff --git a/mnemo_cards/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/mnemo_cards/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png deleted file mode 100644 index 5fd1173..0000000 Binary files a/mnemo_cards/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png and /dev/null differ diff --git a/mnemo_cards/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/mnemo_cards/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png deleted file mode 100644 index 88a0f0a..0000000 Binary files a/mnemo_cards/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png and /dev/null differ diff --git a/mnemo_cards/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@1x.png b/mnemo_cards/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@1x.png deleted file mode 100644 index 1d65fd8..0000000 Binary files a/mnemo_cards/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@1x.png and /dev/null differ diff --git a/mnemo_cards/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@2x.png b/mnemo_cards/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@2x.png deleted file mode 100644 index 39f354c..0000000 Binary files a/mnemo_cards/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@2x.png and /dev/null differ diff --git a/mnemo_cards/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@1x.png b/mnemo_cards/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@1x.png deleted file mode 100644 index df61d9a..0000000 Binary files a/mnemo_cards/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@1x.png and /dev/null differ diff --git a/mnemo_cards/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@2x.png b/mnemo_cards/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@2x.png deleted file mode 100644 index a2b6962..0000000 Binary files a/mnemo_cards/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@2x.png and /dev/null differ diff --git a/mnemo_cards/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/mnemo_cards/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png deleted file mode 100644 index 88a0f0a..0000000 Binary files a/mnemo_cards/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png and /dev/null differ diff --git a/mnemo_cards/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/mnemo_cards/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png deleted file mode 100644 index 585e88e..0000000 Binary files a/mnemo_cards/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png and /dev/null differ diff --git a/mnemo_cards/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@1x.png b/mnemo_cards/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@1x.png deleted file mode 100644 index 6f591a2..0000000 Binary files a/mnemo_cards/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@1x.png and /dev/null differ diff --git a/mnemo_cards/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@2x.png b/mnemo_cards/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@2x.png deleted file mode 100644 index e15861a..0000000 Binary files a/mnemo_cards/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@2x.png and /dev/null differ diff --git a/mnemo_cards/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/mnemo_cards/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png deleted file mode 100644 index 8ed25e7..0000000 Binary files a/mnemo_cards/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png and /dev/null differ diff --git a/mnemo_cards/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png b/mnemo_cards/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png deleted file mode 100644 index 2aa1201..0000000 Binary files a/mnemo_cards/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png and /dev/null differ diff --git a/mnemo_cards/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/mnemo_cards/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png deleted file mode 100644 index e8ceae7..0000000 Binary files a/mnemo_cards/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png and /dev/null differ diff --git a/mnemo_cards/ios/Runner/Assets.xcassets/LaunchBackground.imageset/Contents.json b/mnemo_cards/ios/Runner/Assets.xcassets/LaunchBackground.imageset/Contents.json deleted file mode 100644 index 8bb185b..0000000 --- a/mnemo_cards/ios/Runner/Assets.xcassets/LaunchBackground.imageset/Contents.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "images" : [ - { - "filename" : "background.png", - "idiom" : "universal" - }, - { - "appearances" : [ - { - "appearance" : "luminosity", - "value" : "dark" - } - ], - "filename" : "darkbackground.png", - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/mnemo_cards/ios/Runner/Assets.xcassets/LaunchBackground.imageset/background.png b/mnemo_cards/ios/Runner/Assets.xcassets/LaunchBackground.imageset/background.png deleted file mode 100644 index 3107d37..0000000 Binary files a/mnemo_cards/ios/Runner/Assets.xcassets/LaunchBackground.imageset/background.png and /dev/null differ diff --git a/mnemo_cards/ios/Runner/Assets.xcassets/LaunchBackground.imageset/darkbackground.png b/mnemo_cards/ios/Runner/Assets.xcassets/LaunchBackground.imageset/darkbackground.png deleted file mode 100644 index bb72a79..0000000 Binary files a/mnemo_cards/ios/Runner/Assets.xcassets/LaunchBackground.imageset/darkbackground.png and /dev/null differ diff --git a/mnemo_cards/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json b/mnemo_cards/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json deleted file mode 100644 index f3387d4..0000000 --- a/mnemo_cards/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json +++ /dev/null @@ -1,56 +0,0 @@ -{ - "images" : [ - { - "filename" : "LaunchImage.png", - "idiom" : "universal", - "scale" : "1x" - }, - { - "appearances" : [ - { - "appearance" : "luminosity", - "value" : "dark" - } - ], - "filename" : "LaunchImageDark.png", - "idiom" : "universal", - "scale" : "1x" - }, - { - "filename" : "LaunchImage@2x.png", - "idiom" : "universal", - "scale" : "2x" - }, - { - "appearances" : [ - { - "appearance" : "luminosity", - "value" : "dark" - } - ], - "filename" : "LaunchImageDark@2x.png", - "idiom" : "universal", - "scale" : "2x" - }, - { - "filename" : "LaunchImage@3x.png", - "idiom" : "universal", - "scale" : "3x" - }, - { - "appearances" : [ - { - "appearance" : "luminosity", - "value" : "dark" - } - ], - "filename" : "LaunchImageDark@3x.png", - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/mnemo_cards/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png b/mnemo_cards/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png deleted file mode 100644 index b8e69a5..0000000 Binary files a/mnemo_cards/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png and /dev/null differ diff --git a/mnemo_cards/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png b/mnemo_cards/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png deleted file mode 100644 index aa97e95..0000000 Binary files a/mnemo_cards/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png and /dev/null differ diff --git a/mnemo_cards/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png b/mnemo_cards/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png deleted file mode 100644 index 1d18d62..0000000 Binary files a/mnemo_cards/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png and /dev/null differ diff --git a/mnemo_cards/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImageDark.png b/mnemo_cards/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImageDark.png deleted file mode 100644 index 53d7fdb..0000000 Binary files a/mnemo_cards/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImageDark.png and /dev/null differ diff --git a/mnemo_cards/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImageDark@2x.png b/mnemo_cards/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImageDark@2x.png deleted file mode 100644 index 2b2d195..0000000 Binary files a/mnemo_cards/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImageDark@2x.png and /dev/null differ diff --git a/mnemo_cards/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImageDark@3x.png b/mnemo_cards/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImageDark@3x.png deleted file mode 100644 index 27c3f48..0000000 Binary files a/mnemo_cards/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImageDark@3x.png and /dev/null differ diff --git a/mnemo_cards/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md b/mnemo_cards/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md deleted file mode 100644 index 89c2725..0000000 --- a/mnemo_cards/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# Launch Screen Assets - -You can customize the launch screen with your own desired assets by replacing the image files in this directory. - -You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. \ No newline at end of file diff --git a/mnemo_cards/ios/Runner/Base.lproj/LaunchScreen.storyboard b/mnemo_cards/ios/Runner/Base.lproj/LaunchScreen.storyboard deleted file mode 100644 index 8d2b7d5..0000000 --- a/mnemo_cards/ios/Runner/Base.lproj/LaunchScreen.storyboard +++ /dev/null @@ -1,44 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/mnemo_cards/ios/Runner/Base.lproj/Main.storyboard b/mnemo_cards/ios/Runner/Base.lproj/Main.storyboard deleted file mode 100644 index f3c2851..0000000 --- a/mnemo_cards/ios/Runner/Base.lproj/Main.storyboard +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/mnemo_cards/ios/Runner/GoogleService-Info.plist b/mnemo_cards/ios/Runner/GoogleService-Info.plist deleted file mode 100644 index 813a0db..0000000 --- a/mnemo_cards/ios/Runner/GoogleService-Info.plist +++ /dev/null @@ -1,36 +0,0 @@ - - - - - CLIENT_ID - 701767851968-8dqcmk706p08gujqbl2m9s4sq1aljibs.apps.googleusercontent.com - REVERSED_CLIENT_ID - com.googleusercontent.apps.701767851968-8dqcmk706p08gujqbl2m9s4sq1aljibs - ANDROID_CLIENT_ID - 701767851968-3jgootslus3ie76t682j4v7glletloud.apps.googleusercontent.com - API_KEY - AIzaSyAodY8s0ntALNeeGiUiTx6eg4g2Ar6C1to - GCM_SENDER_ID - 701767851968 - PLIST_VERSION - 1 - BUNDLE_ID - com.cinnabarflower.mnemoCards - PROJECT_ID - mnemo-cards - STORAGE_BUCKET - mnemo-cards.appspot.com - IS_ADS_ENABLED - - IS_ANALYTICS_ENABLED - - IS_APPINVITE_ENABLED - - IS_GCM_ENABLED - - IS_SIGNIN_ENABLED - - GOOGLE_APP_ID - 1:701767851968:ios:5c9040634eac8c152f7225 - - \ No newline at end of file diff --git a/mnemo_cards/ios/Runner/Info.plist b/mnemo_cards/ios/Runner/Info.plist deleted file mode 100644 index 776517d..0000000 --- a/mnemo_cards/ios/Runner/Info.plist +++ /dev/null @@ -1,984 +0,0 @@ - - - - - CFBundleURLTypes - - - CFBundleTypeRole - Editor - CFBundleURLSchemes - - yookassapaymentsflutter - - - - CFBundleTypeRole - Editor - CFBundleURLSchemes - - com.googleusercontent.apps.701767851968-8dqcmk706p08gujqbl2m9s4sq1aljibs - - - - LSApplicationQueriesSchemes - - yoomoneyauth - sberpay - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleDisplayName - Mnemo Cards - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - mnemo_cards - CFBundlePackageType - APPL - CFBundleShortVersionString - $(FLUTTER_BUILD_NAME) - CFBundleSignature - ???? - CFBundleVersion - $(FLUTTER_BUILD_NUMBER) - LSRequiresIPhoneOS - - UILaunchStoryboardName - LaunchScreen - UIMainStoryboardFile - Main - UISupportedInterfaceOrientations - - UIInterfaceOrientationPortrait - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - UISupportedInterfaceOrientations~ipad - - UIInterfaceOrientationPortrait - UIInterfaceOrientationPortraitUpsideDown - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - CADisableMinimumFrameDurationOnPhone - - UIApplicationSupportsIndirectInputEvents - - SKAdNetworkItems - - - - SKAdNetworkIdentifier - zq492l623r.skadnetwork - - - - SKAdNetworkIdentifier - cstr6suwn9.skadnetwork - - - - SKAdNetworkIdentifier - n9x2a789qt.skadnetwork - - - - SKAdNetworkIdentifier - r26jy69rpl.skadnetwork - - - - SKAdNetworkIdentifier - 5l3tpt7t6e.skadnetwork - - - - SKAdNetworkIdentifier - 4dzt52r2t5.skadnetwork - - - - SKAdNetworkIdentifier - su67r6k2v3.skadnetwork - - - - SKAdNetworkIdentifier - ludvb6z3bs.skadnetwork - - - - SKAdNetworkIdentifier - kbd757ywx3.skadnetwork - - - SKAdNetworkIdentifier - 633vhxswh4.skadnetwork - - - SKAdNetworkIdentifier - tmhh9296z4.skadnetwork - - - SKAdNetworkIdentifier - vcra2ehyfk.skadnetwork - - - SKAdNetworkIdentifier - zh3b7bxvad.skadnetwork - - - SKAdNetworkIdentifier - xmn954pzmp.skadnetwork - - - SKAdNetworkIdentifier - 79w64w269u.skadnetwork - - - SKAdNetworkIdentifier - 488r3q3dtq.skadnetwork - - - SKAdNetworkIdentifier - d7g9azk84q.skadnetwork - - - SKAdNetworkIdentifier - nzq8sh4pbs.skadnetwork - - - SKAdNetworkIdentifier - 866k9ut3g3.skadnetwork - - - SKAdNetworkIdentifier - 2q884k2j68.skadnetwork - - - SKAdNetworkIdentifier - x8jxxk4ff5.skadnetwork - - - SKAdNetworkIdentifier - gfat3222tu.skadnetwork - - - SKAdNetworkIdentifier - pd25vrrwzn.skadnetwork - - - SKAdNetworkIdentifier - lr83yxwka7.skadnetwork - - - SKAdNetworkIdentifier - cp8zw746q7.skadnetwork - - - SKAdNetworkIdentifier - pwdxu55a5a.skadnetwork - - - SKAdNetworkIdentifier - c6k4g5qg8m.skadnetwork - - - SKAdNetworkIdentifier - s39g8k73mm.skadnetwork - - - SKAdNetworkIdentifier - wg4vff78zm.skadnetwork - - - SKAdNetworkIdentifier - g28c52eehv.skadnetwork - - - SKAdNetworkIdentifier - 523jb4fst2.skadnetwork - - - SKAdNetworkIdentifier - 294l99pt4k.skadnetwork - - - SKAdNetworkIdentifier - 3qy4746246.skadnetwork - - - SKAdNetworkIdentifier - a8cz6cu7e5.skadnetwork - - - SKAdNetworkIdentifier - ggvn48r87g.skadnetwork - - - SKAdNetworkIdentifier - y755zyxw56.skadnetwork - - - SKAdNetworkIdentifier - qlbq5gtkt8.skadnetwork - - - SKAdNetworkIdentifier - mls7yz5dvl.skadnetwork - - - SKAdNetworkIdentifier - 67369282zy.skadnetwork - - - SKAdNetworkIdentifier - 899vrgt9g8.skadnetwork - - - SKAdNetworkIdentifier - mj797d8u6f.skadnetwork - - - SKAdNetworkIdentifier - 3sh42y64q3.skadnetwork - - - SKAdNetworkIdentifier - f38h382jlk.skadnetwork - - - SKAdNetworkIdentifier - 24t9a8vw3c.skadnetwork - - - SKAdNetworkIdentifier - mp6xlyr22a.skadnetwork - - - SKAdNetworkIdentifier - x44k69ngh6.skadnetwork - - - SKAdNetworkIdentifier - 88k8774x49.skadnetwork - - - SKAdNetworkIdentifier - hs6bdukanm.skadnetwork - - - SKAdNetworkIdentifier - t3b3f7n3x8.skadnetwork - - - SKAdNetworkIdentifier - prcb7njmu6.skadnetwork - - - SKAdNetworkIdentifier - c7g47wypnu.skadnetwork - - - SKAdNetworkIdentifier - 52fl2v3hgk.skadnetwork - - - SKAdNetworkIdentifier - 9vvzujtq5s.skadnetwork - - - SKAdNetworkIdentifier - m8dbw4sv7c.skadnetwork - - - SKAdNetworkIdentifier - 9g2aggbj52.skadnetwork - - - SKAdNetworkIdentifier - m5mvw97r93.skadnetwork - - - SKAdNetworkIdentifier - z5b3gh5ugf.skadnetwork - - - SKAdNetworkIdentifier - dd3a75yxkv.skadnetwork - - - SKAdNetworkIdentifier - 9nlqeag3gk.skadnetwork - - - SKAdNetworkIdentifier - cj5566h2ga.skadnetwork - - - SKAdNetworkIdentifier - h5jmj969g5.skadnetwork - - - SKAdNetworkIdentifier - dr774724x4.skadnetwork - - - SKAdNetworkIdentifier - t7ky8fmwkd.skadnetwork - - - SKAdNetworkIdentifier - fz2k2k5tej.skadnetwork - - - SKAdNetworkIdentifier - u679fj5vs4.skadnetwork - - - SKAdNetworkIdentifier - cs644xg564.skadnetwork - - - SKAdNetworkIdentifier - 9b89h5y424.skadnetwork - - - SKAdNetworkIdentifier - w28pnjg2k4.skadnetwork - - - SKAdNetworkIdentifier - 2rq3zucswp.skadnetwork - - - SKAdNetworkIdentifier - a7xqa6mtl2.skadnetwork - - - SKAdNetworkIdentifier - g2y4y55b64.skadnetwork - - - SKAdNetworkIdentifier - vc83br9sjg.skadnetwork - - - SKAdNetworkIdentifier - eqhxz8m8av.skadnetwork - - - SKAdNetworkIdentifier - 7k3cvf297u.skadnetwork - - - SKAdNetworkIdentifier - w9q455wk68.skadnetwork - - - SKAdNetworkIdentifier - nu4557a4je.skadnetwork - - - SKAdNetworkIdentifier - v4nxqhlyqp.skadnetwork - - - SKAdNetworkIdentifier - wzmmz9fp6w.skadnetwork - - - SKAdNetworkIdentifier - 7fmhfwg9en.skadnetwork - - - SKAdNetworkIdentifier - yclnxrl5pm.skadnetwork - - - SKAdNetworkIdentifier - 7tnzynbdc7.skadnetwork - - - SKAdNetworkIdentifier - l6nv3x923s.skadnetwork - - - SKAdNetworkIdentifier - h8vml93bkz.skadnetwork - - - SKAdNetworkIdentifier - uzqba5354d.skadnetwork - - - SKAdNetworkIdentifier - 8qiegk9qfv.skadnetwork - - - SKAdNetworkIdentifier - v79kvwwj4g.skadnetwork - - - SKAdNetworkIdentifier - xx9sdjej2w.skadnetwork - - - SKAdNetworkIdentifier - au67k4efj4.skadnetwork - - - SKAdNetworkIdentifier - t38b2kh725.skadnetwork - - - SKAdNetworkIdentifier - 7ug5zh24hu.skadnetwork - - - SKAdNetworkIdentifier - rx5hdcabgc.skadnetwork - - - SKAdNetworkIdentifier - 5lm9lj6jb7.skadnetwork - - - SKAdNetworkIdentifier - qqp299437r.skadnetwork - - - SKAdNetworkIdentifier - zmvfpc5aq8.skadnetwork - - - SKAdNetworkIdentifier - 9rd848q2bz.skadnetwork - - - SKAdNetworkIdentifier - 79pbpufp6p.skadnetwork - - - SKAdNetworkIdentifier - dmv22haz9p.skadnetwork - - - SKAdNetworkIdentifier - y5ghdn5j9k.skadnetwork - - - SKAdNetworkIdentifier - n6fk4nfna4.skadnetwork - - - SKAdNetworkIdentifier - 7rz58n8ntl.skadnetwork - - - SKAdNetworkIdentifier - v9wttpbfk9.skadnetwork - - - SKAdNetworkIdentifier - n38lu8286q.skadnetwork - - - SKAdNetworkIdentifier - feyaarzu9v.skadnetwork - - - SKAdNetworkIdentifier - 7fbxrn65az.skadnetwork - - - SKAdNetworkIdentifier - 47vhws6wlr.skadnetwork - - - SKAdNetworkIdentifier - ejvt5qm6ak.skadnetwork - - - SKAdNetworkIdentifier - b55w3d8y8z.skadnetwork - - - SKAdNetworkIdentifier - v7896pgt74.skadnetwork - - - SKAdNetworkIdentifier - 5ghnmfs3dh.skadnetwork - - - SKAdNetworkIdentifier - 275upjj5gd.skadnetwork - - - SKAdNetworkIdentifier - 627r9wr2y5.skadnetwork - - - SKAdNetworkIdentifier - sczv5946wb.skadnetwork - - - SKAdNetworkIdentifier - 8w3np9l82g.skadnetwork - - - SKAdNetworkIdentifier - hb56zgv37p.skadnetwork - - - SKAdNetworkIdentifier - 9t245vhmpl.skadnetwork - - - SKAdNetworkIdentifier - nrt9jy4kw9.skadnetwork - - - SKAdNetworkIdentifier - 7953jerfzd.skadnetwork - - - SKAdNetworkIdentifier - dn942472g5.skadnetwork - - - SKAdNetworkIdentifier - 6v7lgmsu45.skadnetwork - - - SKAdNetworkIdentifier - cad8qz2s3j.skadnetwork - - - SKAdNetworkIdentifier - eh6m2bh4zr.skadnetwork - - - SKAdNetworkIdentifier - jb7bn6koa5.skadnetwork - - - SKAdNetworkIdentifier - fkak3gfpt6.skadnetwork - - - SKAdNetworkIdentifier - a2p9lx4jpn.skadnetwork - - - SKAdNetworkIdentifier - 97r2b46745.skadnetwork - - - SKAdNetworkIdentifier - 22mmun2rn5.skadnetwork - - - SKAdNetworkIdentifier - 238da6jt44.skadnetwork - - - SKAdNetworkIdentifier - 44jx6755aq.skadnetwork - - - SKAdNetworkIdentifier - b9bk5wbcq9.skadnetwork - - - SKAdNetworkIdentifier - k674qkevps.skadnetwork - - - SKAdNetworkIdentifier - tl55sbb4fm.skadnetwork - - - SKAdNetworkIdentifier - 24zw6aqk47.skadnetwork - - - SKAdNetworkIdentifier - 4468km3ulz.skadnetwork - - - SKAdNetworkIdentifier - 2tdux39lx8.skadnetwork - - - SKAdNetworkIdentifier - 2u9pt9hc89.skadnetwork - - - SKAdNetworkIdentifier - 8s468mfl3y.skadnetwork - - - SKAdNetworkIdentifier - 3cgn6rq224.skadnetwork - - - SKAdNetworkIdentifier - glqzh8vgby.skadnetwork - - - SKAdNetworkIdentifier - av6w8kgt66.skadnetwork - - - SKAdNetworkIdentifier - klf5c3l5u5.skadnetwork - - - SKAdNetworkIdentifier - nfqy3847ph.skadnetwork - - - SKAdNetworkIdentifier - dticjx1a9i.skadnetwork - - - SKAdNetworkIdentifier - ppxm28t8ap.skadnetwork - - - SKAdNetworkIdentifier - 9wsyqb3ku7.skadnetwork - - - SKAdNetworkIdentifier - 74b6s63p6l.skadnetwork - - - SKAdNetworkIdentifier - xy9t38ct57.skadnetwork - - - SKAdNetworkIdentifier - 424m5254lk.skadnetwork - - - SKAdNetworkIdentifier - qu637u8glc.skadnetwork - - - SKAdNetworkIdentifier - f73kdq92p3.skadnetwork - - - SKAdNetworkIdentifier - 44n7hlldy6.skadnetwork - - - SKAdNetworkIdentifier - kbmxgpxpgc.skadnetwork - - - SKAdNetworkIdentifier - ecpz2srf59.skadnetwork - - - SKAdNetworkIdentifier - x5854y7y24.skadnetwork - - - SKAdNetworkIdentifier - f7s53z58qe.skadnetwork - - - SKAdNetworkIdentifier - x8uqf25wch.skadnetwork - - - SKAdNetworkIdentifier - uw77j35x4d.skadnetwork - - - SKAdNetworkIdentifier - 6964rsfnh4.skadnetwork - - - SKAdNetworkIdentifier - gvmwg8q7h5.skadnetwork - - - SKAdNetworkIdentifier - 6yxyv74ff7.skadnetwork - - - SKAdNetworkIdentifier - 84993kbrcf.skadnetwork - - - SKAdNetworkIdentifier - 54nzkqm89y.skadnetwork - - - SKAdNetworkIdentifier - pwa73g5rt2.skadnetwork - - - SKAdNetworkIdentifier - mlmmfzh3r3.skadnetwork - - - SKAdNetworkIdentifier - 9yg77x724h.skadnetwork - - - SKAdNetworkIdentifier - n66cz3y3bx.skadnetwork - - - SKAdNetworkIdentifier - 578prtvx9j.skadnetwork - - - SKAdNetworkIdentifier - bvpn9ufa9b.skadnetwork - - - SKAdNetworkIdentifier - 6qx585k4p6.skadnetwork - - - SKAdNetworkIdentifier - mtkv5xtk9e.skadnetwork - - - SKAdNetworkIdentifier - l93v5h6a4m.skadnetwork - - - SKAdNetworkIdentifier - rvh3l7un93.skadnetwork - - - SKAdNetworkIdentifier - gta9lk7p23.skadnetwork - - - SKAdNetworkIdentifier - 5tjdwbrq8w.skadnetwork - - - SKAdNetworkIdentifier - r45fhb6rf7.skadnetwork - - - SKAdNetworkIdentifier - 32z4fx6l9h.skadnetwork - - - SKAdNetworkIdentifier - e5fvkxwrpn.skadnetwork - - - SKAdNetworkIdentifier - 8c4e2ghe7u.skadnetwork - - - SKAdNetworkIdentifier - axh5283zss.skadnetwork - - - SKAdNetworkIdentifier - 3rd42ekr43.skadnetwork - - - SKAdNetworkIdentifier - 5mv394q32t.skadnetwork - - - SKAdNetworkIdentifier - 3qcr597p9d.skadnetwork - - - SKAdNetworkIdentifier - v72qych5uu.skadnetwork - - - SKAdNetworkIdentifier - ydx93a7ass.skadnetwork - - - SKAdNetworkIdentifier - 4pfyvq9l8r.skadnetwork - - - SKAdNetworkIdentifier - 5a6flpkh64.skadnetwork - - - SKAdNetworkIdentifier - 4fzdc2evr5.skadnetwork - - - SKAdNetworkIdentifier - 4w7y6s5ca2.skadnetwork - - - SKAdNetworkIdentifier - 252b5q8x7y.skadnetwork - - - SKAdNetworkIdentifier - 2fnua5tdw4.skadnetwork - - - SKAdNetworkIdentifier - 3l6bd9hu43.skadnetwork - - - SKAdNetworkIdentifier - 4mn522wn87.skadnetwork - - - SKAdNetworkIdentifier - 6g9af3uyq4.skadnetwork - - - SKAdNetworkIdentifier - 6p4ks3rnbw.skadnetwork - - - SKAdNetworkIdentifier - 6xzpu9s2p8.skadnetwork - - - SKAdNetworkIdentifier - 737z793b9f.skadnetwork - - - SKAdNetworkIdentifier - 89z7zv988g.skadnetwork - - - SKAdNetworkIdentifier - 8m87ys6875.skadnetwork - - - SKAdNetworkIdentifier - 8r8llnkz5a.skadnetwork - - - SKAdNetworkIdentifier - bxvub5ada5.skadnetwork - - - SKAdNetworkIdentifier - c3frkrj4fj.skadnetwork - - - SKAdNetworkIdentifier - cg4yq2srnc.skadnetwork - - - SKAdNetworkIdentifier - dbu4b84rxf.skadnetwork - - - SKAdNetworkIdentifier - dkc879ngq3.skadnetwork - - - SKAdNetworkIdentifier - dzg6xy7pwj.skadnetwork - - - SKAdNetworkIdentifier - gta8lk7p23.skadnetwork - - - SKAdNetworkIdentifier - hdw39hrw9y.skadnetwork - - - SKAdNetworkIdentifier - hjevpa356n.skadnetwork - - - SKAdNetworkIdentifier - krvm3zuq6h.skadnetwork - - - SKAdNetworkIdentifier - ln5gz23vtd.skadnetwork - - - SKAdNetworkIdentifier - m297p6643m.skadnetwork - - - SKAdNetworkIdentifier - p78axxw29g.skadnetwork - - - SKAdNetworkIdentifier - pu4na253f3.skadnetwork - - - SKAdNetworkIdentifier - s69wq72ugq.skadnetwork - - - SKAdNetworkIdentifier - t6d3zquu66.skadnetwork - - - SKAdNetworkIdentifier - vutu7akeur.skadnetwork - - - SKAdNetworkIdentifier - x2jnk7ly8j.skadnetwork - - - SKAdNetworkIdentifier - x5l83yy675.skadnetwork - - - SKAdNetworkIdentifier - y45688jllp.skadnetwork - - - SKAdNetworkIdentifier - yrqqpx2mcb.skadnetwork - - - SKAdNetworkIdentifier - z4gj7hsk7h.skadnetwork - - - SKAdNetworkIdentifier - 33r6p7g8nc.skadnetwork - - - SKAdNetworkIdentifier - g69uk9uh2b.skadnetwork - - - UIStatusBarHidden - - NSAppTransportSecurity - - NSAllowsArbitraryLoads - - NSAllowsArbitraryLoadsInWebContent - - NSAllowsLocalNetworking - - - - diff --git a/mnemo_cards/ios/Runner/Runner-Bridging-Header.h b/mnemo_cards/ios/Runner/Runner-Bridging-Header.h deleted file mode 100644 index 308a2a5..0000000 --- a/mnemo_cards/ios/Runner/Runner-Bridging-Header.h +++ /dev/null @@ -1 +0,0 @@ -#import "GeneratedPluginRegistrant.h" diff --git a/mnemo_cards/ios/RunnerTests/RunnerTests.swift b/mnemo_cards/ios/RunnerTests/RunnerTests.swift deleted file mode 100644 index 86a7c3b..0000000 --- a/mnemo_cards/ios/RunnerTests/RunnerTests.swift +++ /dev/null @@ -1,12 +0,0 @@ -import Flutter -import UIKit -import XCTest - -class RunnerTests: XCTestCase { - - func testExample() { - // If you add code to the Runner application, consider adding tests here. - // See https://developer.apple.com/documentation/xctest for more information about using XCTest. - } - -} diff --git a/mnemo_cards/ios/firebase_app_id_file.json b/mnemo_cards/ios/firebase_app_id_file.json deleted file mode 100644 index a81cdf7..0000000 --- a/mnemo_cards/ios/firebase_app_id_file.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "file_generated_by": "FlutterFire CLI", - "purpose": "FirebaseAppID & ProjectID for this Firebase app in this directory", - "GOOGLE_APP_ID": "1:701767851968:ios:4148f84add5cc6732f7225", - "FIREBASE_PROJECT_ID": "mnemo-cards", - "GCM_SENDER_ID": "701767851968" -} \ No newline at end of file diff --git a/mnemo_cards/lib/admin/add_card.dart b/mnemo_cards/lib/admin/add_card.dart deleted file mode 100644 index 6d318f5..0000000 --- a/mnemo_cards/lib/admin/add_card.dart +++ /dev/null @@ -1,332 +0,0 @@ -import 'dart:async'; -import 'dart:convert'; -import 'package:mnemo_cards/domain/router/dialogs.dart'; -import 'package:universal_io/io.dart'; - -import 'package:flutter/material.dart'; - -import 'package:file_picker/file_picker.dart'; -import 'package:mnemo_cards/admin/admin_api.dart'; -import 'package:mnemo_cards_common/mnemo_cards_common.dart'; -import 'package:mnemo_cards_frontend_common/mnemo_cards_frontend_common.dart'; - -import '../main.dart'; - -class EditCard { - GameCardDto gameCardDto; - AdminApi adminApi; - bool imageChanged = false; - - EditCard(GameCardDto? cardDto, this.adminApi) - : gameCardDto = - cardDto ?? - const GameCardDto( - id: -1, - image: null, - mnemo: null, - original: null, - translation: null, - transcription: null, - transcriptionMnemo: null, - imageBack: null, - back: null, - ); - - void _saveCard() async { - final dto = imageChanged ? gameCardDto : gameCardDto.copyWith.image(null); - final _progress = ValueNotifier<(int, int)>((0, 1)); - final _dialogCompleter = Completer(); - showInfoDialog( - '', - child: ValueListenableBuilder( - valueListenable: _progress, - builder: (c, v, _) => Text( - (v.$1 == v.$2 || v.$2 < 0) - ? 'Waiting for response...' - : 'Uploading ${v.$1}/${v.$2}...', - ), - ), - completer: _dialogCompleter, - ); - final result = await adminApi.addCard( - dto, - progressCallback: (a, b) => _progress.value = (a, b), - ); - _dialogCompleter.complete(); - if (!result) { - ScaffoldMessenger.of( - scaffoldKey.currentContext!, - ).showSnackBar(SnackBar(content: Text('ERROR'))); - } else { - ScaffoldMessenger.of( - scaffoldKey.currentContext!, - ).showSnackBar(SnackBar(content: Text('Success!!!'))); - appRouter.maybePop(); - } - } - - void _deleteCard() async { - final result = await adminApi.deleteCard(gameCardDto); - if (!result) { - ScaffoldMessenger.of( - scaffoldKey.currentContext!, - ).showSnackBar(SnackBar(content: Text('ERROR'))); - } else { - ScaffoldMessenger.of( - scaffoldKey.currentContext!, - ).showSnackBar(SnackBar(content: Text('Success!!!'))); - appRouter.maybePop(); - } - } - - void addCard(BuildContext context) { - final theme = Theme.of(context).textTheme; - - final TextEditingController originalController = TextEditingController( - text: gameCardDto.original, - ); - final TextEditingController translationController = TextEditingController( - text: gameCardDto.translation, - ); - final TextEditingController transcriptionController = TextEditingController( - text: gameCardDto.transcription, - ); - final TextEditingController transcriptionMnemoController = - TextEditingController(text: gameCardDto.transcriptionMnemo); - final TextEditingController mnemoController = TextEditingController( - text: gameCardDto.mnemo, - ); - final TextEditingController backController = TextEditingController( - text: gameCardDto.back, - ); - - showDialog( - context: context, - builder: (c) { - return Center( - child: Scaffold( - body: Material( - child: ListView( - children: [ - Header( - '${gameCardDto.id}', - hasPopButton: true, - trail: Row( - children: [ - IconButton( - onPressed: _saveCard, - icon: Icon(Icons.save), - ), - if (gameCardDto.id >= 0) - GestureDetector( - onLongPress: _deleteCard, - child: Icon(Icons.delete), - ), - ], - ), - ), - StatefulBuilder( - builder: (context, setState) { - return Stack( - alignment: Alignment.center, - children: [ - Padding( - padding: EdgeInsets.all(8.0), - child: Column( - mainAxisSize: MainAxisSize.max, - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - Column( - children: [ - TextField( - controller: originalController, - onChanged: (v) { - gameCardDto = gameCardDto.copyWith( - original: v, - ); - }, - decoration: InputDecoration( - hintText: 'Original (cerdo)', - ), - maxLines: 1, - style: theme.displayMedium?.copyWith( - fontSize: - theme.displayMedium!.fontSize!, - ), - ), - TextField( - controller: translationController, - onChanged: (v) { - gameCardDto = gameCardDto.copyWith( - translation: v, - ); - }, - decoration: InputDecoration( - hintText: 'Translation (свинья)', - ), - maxLines: 1, - style: theme.headlineSmall?.copyWith( - color: theme.headlineSmall!.color! - .withOpacity(0.5), - fontSize: - theme.headlineSmall!.fontSize!, - ), - ), - Row( - children: [ - Flexible( - child: TextField( - controller: transcriptionController, - onChanged: (v) { - gameCardDto = gameCardDto - .copyWith(transcription: v); - }, - decoration: InputDecoration( - hintText: 'Transcription', - ), - maxLines: 1, - style: theme.headlineSmall - ?.copyWith( - color: theme - .headlineSmall! - .color!, - fontSize: theme - .headlineSmall! - .fontSize!, - ), - ), - ), - SizedBox(width: 4.0), - Flexible( - child: TextField( - controller: - transcriptionMnemoController, - onChanged: (v) { - gameCardDto = gameCardDto - .copyWith( - transcriptionMnemo: v, - ); - }, - decoration: InputDecoration( - hintText: 'Transcription mnemo', - ), - maxLines: 1, - style: theme.headlineSmall - ?.copyWith( - color: theme - .headlineSmall! - .color!, - fontSize: theme - .headlineSmall! - .fontSize!, - ), - ), - ), - ], - ), - ], - ), - SizedBox( - width: MediaQuery.of(context).size.width - 20, - height: - MediaQuery.of(context).size.width - 20, - child: GestureDetector( - onTap: () async { - FilePickerResult? result = - await FilePicker.platform.pickFiles(); - if (result != null && - result.files.isNotEmpty) { - imageChanged = true; - final file = result.files.first; - final encoded = base64.normalize( - base64.encode( - File(file.path!).readAsBytesSync(), - ), - ); - gameCardDto = gameCardDto.copyWith( - image: encoded, - ); - } - setState(() {}); - }, - child: gameCardDto.image == null - ? Container( - alignment: Alignment.center, - color: Colors.white, - child: Icon( - Icons.image, - color: Colors.grey, - ), - ) - : Stack( - children: [ - Image( - key: ValueKey(base64), - image: MemoryImage( - base64.decode( - gameCardDto.image!, - ), - ), - gaplessPlayback: true, - fit: BoxFit.contain, - ), - Positioned( - top: 8.0, - right: 8.0, - child: IconButton( - onPressed: () { - gameCardDto = gameCardDto - .copyWith(image: null); - setState(() {}); - }, - icon: Icon(Icons.delete), - ), - ), - ], - ), - ), - ), - TextField( - controller: mnemoController, - onChanged: (v) { - gameCardDto = gameCardDto.copyWith( - mnemo: v, - ); - }, - decoration: InputDecoration( - hintText: 'Mnemo ([свинья] с сердечком)', - ), - maxLines: 1, - style: theme.headlineSmall?.copyWith( - fontSize: theme.headlineSmall!.fontSize!, - ), - ), - TextField( - controller: backController, - onChanged: (v) { - gameCardDto = gameCardDto.copyWith(back: v); - }, - decoration: InputDecoration( - hintText: 'Задняя сторона', - ), - maxLines: 1, - style: theme.headlineSmall?.copyWith( - fontSize: theme.headlineSmall!.fontSize!, - ), - ), - ], - ), - ), - ], - ); - }, - ), - ], - ), - ), - ), - ); - }, - ); - } -} diff --git a/mnemo_cards/lib/admin/add_discount_campaign.dart b/mnemo_cards/lib/admin/add_discount_campaign.dart deleted file mode 100644 index 6e3d461..0000000 --- a/mnemo_cards/lib/admin/add_discount_campaign.dart +++ /dev/null @@ -1,383 +0,0 @@ -import 'dart:async'; -import 'dart:developer'; - -import 'package:flutter/material.dart'; - -import 'package:mnemo_cards/admin/admin_api.dart'; -import 'package:mnemo_cards_common/mnemo_cards_common.dart'; -import 'package:mnemo_cards_frontend_common/mnemo_cards_frontend_common.dart'; - -import '../di/injector.dart'; -import '../main.dart'; -import 'date_param.dart'; -import 'enum_param.dart'; -import 'int_param.dart'; -import 'text_param.dart'; - -class AddDiscountCampaign { - late DiscountCampaignDto campaignDto; - late AdminApi adminApi; - List _campaigns = []; - - AddDiscountCampaign() { - this.adminApi = getIt.get(); - _init(null); - } - - void _init(DiscountCampaignDto? dto) { - final now = DateTime.now(); - campaignDto = dto ?? - DiscountCampaignDto( - start: now, - finish: now.add(Duration(days: 30)), - status: DiscountCampaignStatus.disabled, - name: null, - tags: [], - discounts: [], - ); - } - - Future _loadCampaigns() async { - try { - _campaigns = await adminApi.getDiscountCampaigns(); - } catch (e, s) { - log('Error', error: e, stackTrace: s); - print('Error $e'); - return false; - } - return true; - } - - void _savePromoCodeCampaign() async { - for (final d in campaignDto.discounts) { - final products = d.products.map((p) => p.toProduct()); - d.products.replaceRange(0, products.length, products); - } - - final result = await adminApi.addDiscountCampaign(campaignDto); - if (!result) { - ScaffoldMessenger.of(scaffoldKey.currentContext!).showSnackBar(SnackBar( - content: Text('ERROR'), - )); - } else { - ScaffoldMessenger.of(scaffoldKey.currentContext!).showSnackBar(SnackBar( - content: Text('Success!!!'), - )); - appRouter.maybePop(); - } - } - - void _deleteDiscountCampaign() async { - if (campaignDto.id == null) return; - final result = - await adminApi.deleteDiscountCampaign(campaignDto.id.toString()); - if (result != null) { - ScaffoldMessenger.of(scaffoldKey.currentContext!).showSnackBar(SnackBar( - content: Text('ERROR'), - )); - } else { - ScaffoldMessenger.of(scaffoldKey.currentContext!).showSnackBar(SnackBar( - content: Text('Success!!!'), - )); - appRouter.maybePop(); - } - } - - void addCampaign(BuildContext context) { - showDialog( - context: context, - builder: (c) { - return FutureBuilder( - future: _loadCampaigns(), - builder: (context, snapshot) { - if (snapshot.data != true) { - return Center( - child: Material( - child: Center(child: CircularProgressIndicator()), - ), - ); - } - return Center( - child: Scaffold( - body: Material( - child: StatefulBuilder(builder: (context, setCampaign) { - return ListView( - children: [ - Header( - '${campaignDto.id}', - hasPopButton: true, - trail: Row( - children: [ - IconButton( - onPressed: _savePromoCodeCampaign, - icon: Icon(Icons.save), - ), - if (campaignDto.id != null) - IconButton( - onPressed: () async { - campaignDto = - campaignDto.copyWith(id: null); - _savePromoCodeCampaign(); - }, - icon: Icon(Icons.copy), - ), - if (campaignDto.id != null) - GestureDetector( - onLongPress: _deleteDiscountCampaign, - child: Icon(Icons.delete), - ) - ], - ), - ), - DropdownMenu( - initialSelection: null, - onSelected: (int? value) { - setCampaign(() { - _init( - _campaigns - .firstWhereOrNull((v) => v.id == value), - ); - }); - }, - dropdownMenuEntries: [ - ..._campaigns, - null, - ].map((campaign) { - return DropdownMenuEntry( - value: campaign?.id, - label: campaign == null - ? 'New' - : '${campaign.name ?? campaign.id} ${campaign.status.name}', - ); - }).toList(), - ), - StatefulBuilder(builder: (context, setState) { - return Padding( - padding: EdgeInsets.all(8.0), - child: Column( - children: [ - TextParam( - 'Name', - campaignDto.name, - (v) { - campaignDto = campaignDto.copyWith( - name: v, - ); - }, - ), - DateParam( - 'Start', - campaignDto.start, - (v) { - setState(() { - campaignDto = - campaignDto.copyWith(start: v); - }); - }, - ), - DateParam( - 'Finish', - campaignDto.finish, - (v) { - setState(() { - campaignDto = - campaignDto.copyWith(finish: v); - }); - }, - ), - EnumParam( - 'Status', - DiscountCampaignStatus.values, - campaignDto.status, (v) { - setState(() { - campaignDto = - campaignDto.copyWith(status: v); - }); - }), - Text( - 'Created to create or change\n' - 'Disabled to disable\n' - 'Dont use other statuses!', - style: TextStyle(fontSize: 12), - ), - Text('Discounts:'), - ListView.builder( - shrinkWrap: true, - itemCount: - campaignDto.discounts.length + 1, - itemBuilder: (context, index) { - if (index == - campaignDto.discounts.length) { - return Container( - child: SimpleTile( - title: Text('Add'), - onTap: () async { - final discount = - await _showDiscountDialog( - context, null); - if (discount != null) { - setState(() { - final ex = campaignDto - .discounts - .firstWhereOrNull((d) => - d.id == - discount.id); - if (ex != null) { - campaignDto.discounts - .remove(ex); - } - campaignDto.discounts - .add(discount); - }); - } - }, - ), - ); - } - final item = - campaignDto.discounts[index]; - return ListTile( - title: Text( - '${item.type.name} ${item.id ?? ''}'), - onTap: () async { - final p = await _showDiscountDialog( - context, - item, - ); - if (p != null) { - setState(() { - campaignDto.discounts.add(p); - }); - } - }, - trailing: IconButton( - icon: Icon(Icons.delete), - onPressed: () { - setState(() { - campaignDto.discounts - .remove(item); - }); - }, - ), - ); - }, - ), - ], - ), - ); - }), - ], - ); - }), - ), - ), - ); - }); - }); - } - - Future _showDiscountDialog( - BuildContext context, - DiscountDto? initialDiscount, - ) async { - var prod = initialDiscount ?? DiscountDto(discountPercent: 0, products: []); - final result = await showDialog( - context: context, - builder: (c) => Center( - child: Padding( - padding: const EdgeInsets.all(8.0), - child: Material( - child: FutureBuilder( - future: () async { - final allPacks = await adminApi.packs(); - final allPlans = await adminApi.getSubscriptionPlans(); - return [...allPacks, ...allPlans]; - }.call(), - builder: (context, snapshot) { - if (!snapshot.hasData) { - return Padding( - padding: const EdgeInsets.all(8.0), - child: Text('Loading products...'), - ); - } - final products = snapshot.requireData; - return SingleChildScrollView( - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - Text('Adding discount'), - TextParam( - 'Id', - prod.id, - (v) { - prod = prod.copyWith(id: v); - }, - description: 'Leave empty for new', - ), - IntParam('Discount 0-100', prod.discountPercent.toInt(), - (v) { - prod = prod.copyWith( - discountPercent: v?.toDouble() ?? 0.0); - }), - StatefulBuilder(builder: (context, ss) { - return ListView.builder( - shrinkWrap: true, - itemCount: prod.products.length + 1, - itemBuilder: (BuildContext context, int index) { - if (index == prod.products.length) { - return EnumParam( - 'Add product', - products, - null, - (p) { - if (p != null) { - ss(() { - prod.products.add(p); - }); - } - }, - getName: (p) => _productName(p, products), - ); - } - final p = prod.products[index]; - return ListTile( - title: Text(_productName(p, products)), - onTap: () async { - ss(() { - prod.products.remove(p); - }); - }, - ); - }, - ); - }), - MaterialButton( - onPressed: () { - Navigator.of(context).pop(prod); - }, - child: Text('Save'), - ), - ], - ), - ); - }), - ), - ), - ), - ); - return result; - } - - String _productName(MnemoCardsProductDto? p, List products) { - if (p is CardPackPreviewDto) { - return '${p.id} ${p.title} ${p.price} pack'; - } else if (p is SubscriptionPlanAdminDto) { - return '${p.id} ${p.ui.titleLead ?? ''} ${p.ui.title ?? ''} ${p.paymentSystem.name} ${p.price} plan'; - } - final matchedProduct = products.firstWhereOrNull((m) => m.productEquals(p)); - if (matchedProduct != null) { - return _productName(matchedProduct, []); - } - return '${p?.type.name} ${p?.id}'; - } -} diff --git a/mnemo_cards/lib/admin/add_package.dart b/mnemo_cards/lib/admin/add_package.dart deleted file mode 100644 index f6bd2ce..0000000 --- a/mnemo_cards/lib/admin/add_package.dart +++ /dev/null @@ -1,298 +0,0 @@ -import 'dart:convert'; -import 'package:universal_io/io.dart'; - -import 'package:flutter/material.dart'; -import 'package:flutter_colorpicker/flutter_colorpicker.dart'; -import 'package:mnemo_cards/admin/admin_api.dart'; -import 'package:mnemo_cards/managers/repository/api.dart'; -import 'package:mnemo_cards_common/mnemo_cards_common.dart'; -import 'package:file_picker/file_picker.dart'; -import 'package:mnemo_cards_frontend_common/mnemo_cards_frontend_common.dart'; -import '../utils/string_helper.dart'; - -import '../main.dart'; -import 'text_param.dart'; - -class AddPackage with Api { - EditCardPackDto cardPackDto; - AdminApi adminApi; - bool palleteVisible = false; - - AddPackage(EditCardPackDto? cardPackDto, this.adminApi) - : cardPackDto = cardPackDto ?? EditCardPackDto.fromJson({}); - - void _deletePack() async { - final delete = await showDialog( - context: scaffoldKey.currentContext!, - builder: (c) => Center( - child: Container( - color: Colors.white, - width: 200, - child: IconButton( - icon: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text('Удалить '), - Icon(Icons.delete), - ], - ), - onPressed: () { - Navigator.of(c).pop(true); - }, - ), - ), - )); - if (!delete) return; - final result = await adminApi.deletePack(cardPackDto); - if (!result) { - ScaffoldMessenger.of(scaffoldKey.currentContext!).showSnackBar(SnackBar( - content: Text('ERROR'), - )); - } else { - ScaffoldMessenger.of(scaffoldKey.currentContext!).showSnackBar(SnackBar( - content: Text('Success!!!'), - )); - appRouter.maybePop(); - } - } - - void _savePack() async { - final result = await adminApi.editPack(cardPackDto); - if (!result) { - ScaffoldMessenger.of(scaffoldKey.currentContext!).showSnackBar(SnackBar( - content: Text('ERROR'), - )); - } else { - ScaffoldMessenger.of(scaffoldKey.currentContext!).showSnackBar(SnackBar( - content: Text('Success!!!'), - )); - appRouter.maybePop(); - } - } - - void addPack(BuildContext context) { - showDialog( - context: context, - builder: (c) { - return Center( - child: Card( - child: Padding( - padding: const EdgeInsets.all(8.0), - child: ListView( - children: [ - Header( - '${cardPackDto.id}', - hasPopButton: true, - trail: Row( - children: [ - IconButton( - onPressed: _savePack, - icon: Icon(Icons.save), - ), - if (cardPackDto.id != null) - GestureDetector( - onLongPress: _deletePack, - child: Icon(Icons.delete), - ) - ], - ), - ), - TextParam( - 'Title', - cardPackDto.title, - (v) { - cardPackDto = cardPackDto.copyWith.title(v); - }, - ), - TextParam( - 'Subtitle', - cardPackDto.subtitle, - (v) { - cardPackDto = cardPackDto.copyWith.subtitle(v); - }, - ), - TextParam( - 'Description', - cardPackDto.description, - (v) => cardPackDto = cardPackDto.copyWith.description(v), - ), - TextParam( - 'Size', - cardPackDto.size?.toString(), - (v) { - cardPackDto = cardPackDto.copyWith.size( - int.tryParse(v), - ); - }, - ), - TextParam( - 'Google play id', - cardPackDto.googlePlayId, - (v) { - cardPackDto = cardPackDto.copyWith.googlePlayId(v); - }, - ), - TextParam( - 'Rustore id', - cardPackDto.rustoreId, - (v) { - cardPackDto = cardPackDto.copyWith.rustoreId(v); - }, - ), - TextParam( - 'Appstore id', - cardPackDto.appStoreId, - (v) { - cardPackDto = cardPackDto.copyWith.appStoreId(v); - }, - ), - TextParam( - 'Price', - cardPackDto.price, - (v) { - cardPackDto = cardPackDto.copyWith.price(v); - }, - ), - Row( - children: [ - Expanded(child: Text('Enabled ')), - StatefulBuilder(builder: (context, setState) { - return Switch( - value: cardPackDto.enabled ?? false, - onChanged: (v) { - setState(() { - cardPackDto = cardPackDto.copyWith.enabled(v); - }); - }); - }), - ], - ), - StatefulBuilder(builder: (context, setState) { - return Column( - children: [ - Row( - children: [ - Expanded(child: Text('Поменять цвет ')), - Switch( - value: palleteVisible, - onChanged: (v) => setState(() { - palleteVisible = !palleteVisible; - }), - ), - ], - ), - if (palleteVisible) - ColorPicker( - pickerAreaHeightPercent: 0.5, - paletteType: PaletteType.hsvWithHue, - pickerColor: cardPackDto.color?.asColor ?? - Colors.transparent, - onColorChanged: (color) { - String? colorString; - if (color.alpha != 0) { - colorString = '#${color.toHexString()}'; - } - cardPackDto = - cardPackDto.copyWith.color(colorString); - }, - ), - ], - ); - }), - StatefulBuilder(builder: (context, setState) { - return SizedBox( - width: MediaQuery.of(context).size.width - 20, - height: MediaQuery.of(context).size.width - 20, - child: GestureDetector( - onTap: () async { - FilePickerResult? result = - await FilePicker.platform.pickFiles(); - if (result != null && result.files.isNotEmpty) { - final file = result.files.first; - final encoded = base64.normalize( - base64.encode( - File(file.path!).readAsBytesSync(), - ), - ); - cardPackDto = cardPackDto.copyWith.cover( - encoded, - ); - } - setState(() {}); - }, - child: cardPackDto.cover == null - ? Container( - alignment: Alignment.center, - color: Colors.white, - child: Icon( - Icons.image, - color: Colors.grey, - ), - ) - : Stack( - children: [ - ImageFade( - key: ValueKey(cardPackDto.id), - image: MemoryImage( - base64.decode(cardPackDto.cover!)), - fit: BoxFit.contain, - syncDuration: Duration.zero, - ), - Positioned( - top: 8.0, - right: 8.0, - child: IconButton( - onPressed: () { - cardPackDto = cardPackDto.copyWith( - cover: null, - ); - setState(() {}); - }, - icon: Icon(Icons.delete)), - ), - ], - ), - ), - ); - }), - TextParam( - 'Preview cards', - cardPackDto.previewCards?.toString(), - (v) { - final cards = v - .decodeList() - .map((e) => e.toString()) - .toList(); - cardPackDto = cardPackDto.copyWith.previewCards(cards); - }, - ), - TextParam( - 'Order (lower is higher)', - cardPackDto.order?.toString(), - (v) { - cardPackDto = cardPackDto.copyWith.order( - int.tryParse(v), - ); - }, - ), - TextParam( - 'Cards order (ids)', - cardPackDto.cardsOrder?.join(','), - (v) { - final ids = v - .split(',') - .map((s) => int.tryParse(s.trim())) - .whereNotNull() - .toList(); - cardPackDto = cardPackDto.copyWith(cardsOrder: ids); - }, - ), - ], - ), - ), - ), - ); - }); - } -} - diff --git a/mnemo_cards/lib/admin/add_plan.dart b/mnemo_cards/lib/admin/add_plan.dart deleted file mode 100644 index 3ab4166..0000000 --- a/mnemo_cards/lib/admin/add_plan.dart +++ /dev/null @@ -1,389 +0,0 @@ -import 'package:flutter/material.dart'; - -import 'package:mnemo_cards/admin/admin_api.dart'; -import 'package:mnemo_cards_common/mnemo_cards_common.dart'; -import 'package:mnemo_cards_frontend_common/mnemo_cards_frontend_common.dart'; - -import '../di/injector.dart'; -import '../main.dart'; -import 'text_param.dart'; - -class AddPlan { - List allPlans = []; - List selectedFeatures = []; - late SubscriptionPlanAdminDto planDto; - late AdminApi adminApi; - - final availableFeatures = [ - SubscriptionFeatureEnum.ads, - SubscriptionFeatureEnum.packs, - ]; - - AddPlan() { - this.adminApi = getIt.get(); - _init(null); - } - - void _init(SubscriptionPlanAdminDto? dto) { - planDto = dto ?? - const SubscriptionPlanAdminDto( - ui: SubscriptionPlanUIDto( - currency: 'руб', - ), - price: '123', - currency: 'руб', - durationDays: 0, - features: [ - SubscriptionFeatureEnum.ads, - SubscriptionFeatureEnum.packs, - ], - paymentId: null, - paymentSystem: PaymentSystem.unknown, - ); - selectedFeatures = planDto.features.toList(); - } - - Future _loadPlans() async { - final result = await adminApi.getSubscriptionPlans(); - allPlans = result; - return true; - } - - void _saveSubscriptionPlan() async { - final result = await adminApi.addSubscriptionPlan( - planDto.copyWith( - features: selectedFeatures, - ), - ); - if (!result) { - ScaffoldMessenger.of(scaffoldKey.currentContext!).showSnackBar(SnackBar( - content: Text('ERROR'), - )); - } else { - ScaffoldMessenger.of(scaffoldKey.currentContext!).showSnackBar(SnackBar( - content: Text('Success!!!'), - )); - appRouter.maybePop(); - } - } - - void _deletePLan() async { - if (planDto.id == null) return; - final result = await adminApi.deleteSubscriptionPlan(planDto.id.toString()); - if (!result) { - ScaffoldMessenger.of(scaffoldKey.currentContext!).showSnackBar(SnackBar( - content: Text('ERROR'), - )); - } else { - ScaffoldMessenger.of(scaffoldKey.currentContext!).showSnackBar(SnackBar( - content: Text('Success!!!'), - )); - appRouter.maybePop(); - } - } - - void addPlan(BuildContext context) { - showDialog( - context: context, - builder: (c) { - return FutureBuilder( - future: _loadPlans(), - builder: (context, snapshot) { - if (snapshot.data != true) { - return Center( - child: Material( - child: Center(child: CircularProgressIndicator()), - ), - ); - } - return Center( - child: Scaffold( - body: Material( - child: StatefulBuilder(builder: (context, setPlan) { - return ListView( - children: [ - Header( - '${planDto.id}', - hasPopButton: true, - trail: Row( - children: [ - IconButton( - onPressed: () async { - await _loadPlans(); - setPlan(() {}); - }, - icon: Icon(Icons.sync), - ), - IconButton( - onPressed: _saveSubscriptionPlan, - icon: Icon(Icons.save), - ), - if (planDto.id != null) - IconButton( - onPressed: () async { - planDto = planDto.copyWith(id: null); - _saveSubscriptionPlan(); - }, - icon: Icon(Icons.copy), - ), - if (planDto.id != null) - GestureDetector( - onLongPress: _deletePLan, - child: Icon(Icons.delete), - ) - ], - ), - ), - DropdownMenu( - initialSelection: null, - onSelected: (String? value) { - setPlan(() { - _init( - allPlans - .firstWhereOrNull((v) => v.id == value), - ); - }); - }, - dropdownMenuEntries: [ - ...allPlans, - null, - ].map((plan) { - return DropdownMenuEntry( - value: plan?.id, - label: plan == null - ? 'New' - : '${plan.ui.titleLead ?? ''} ${plan.ui.title ?? ''} ${plan.paymentSystem.name}', - ); - }).toList(), - ), - StatefulBuilder(builder: (context, setState) { - return Stack( - alignment: Alignment.center, - children: [ - Padding( - padding: EdgeInsets.all(8.0), - child: Column( - mainAxisSize: MainAxisSize.max, - mainAxisAlignment: - MainAxisAlignment.spaceEvenly, - children: [ - Column( - children: [ - TextParam( - 'Currency', - planDto.currency, - (v) { - planDto = planDto.copyWith( - currency: v); - }, - ), - TextParam( - 'Price', - planDto.price, - (v) { - planDto = - planDto.copyWith(price: v); - }, - ), - TextParam( - 'Days', - planDto.durationDays.toString(), - (v) { - final days = int.parse(v); - planDto = planDto.copyWith( - durationDays: days, - ); - }, - ), - Text('Features:'), - ListView.builder( - shrinkWrap: true, - itemCount: - availableFeatures.length, - itemBuilder: (context, index) { - final item = - availableFeatures[index]; - return ListTile( - title: Text(item.name), - onTap: () { - setState(() { - if (selectedFeatures - .contains(item)) { - selectedFeatures - .remove(item); - } else { - selectedFeatures - .add(item); - } - }); - }, - selected: selectedFeatures - .contains(item), - selectedTileColor: Colors.blue - .withOpacity(0.5), - ); - }, - ), - Text('UI:'), - TextParam( - 'UI Currency', - planDto.ui.currency, - (v) { - final ui = planDto.ui.copyWith( - currency: v, - ); - planDto = - planDto.copyWith.ui(ui); - }, - ), - TextParam( - 'UI Title lead', - planDto.ui.titleLead, - (v) { - final ui = planDto.ui.copyWith( - titleLead: v, - ); - planDto = - planDto.copyWith.ui(ui); - }, - ), - TextParam( - 'UI Title', - planDto.ui.title, - (v) { - final ui = planDto.ui.copyWith( - title: v, - ); - planDto = - planDto.copyWith.ui(ui); - }, - ), - TextParam( - 'UI Price per month', - planDto.ui.pricePerMonth, - (v) { - final ui = planDto.ui.copyWith( - pricePerMonth: v, - ); - planDto = - planDto.copyWith.ui(ui); - }, - ), - TextParam( - 'UI Subtitle crossed', - planDto.ui.subtitleCrossed, - (v) { - final ui = planDto.ui.copyWith( - subtitleCrossed: v, - ); - planDto = - planDto.copyWith.ui(ui); - }, - ), - TextParam( - 'UI Subtitle', - planDto.ui.subtitle, - (v) { - final ui = planDto.ui.copyWith( - subtitle: v, - ); - planDto = - planDto.copyWith.ui(ui); - }, - ), - TextParam( - 'UI Tip', - planDto.ui.tip, - (v) { - final ui = planDto.ui.copyWith( - tip: v, - ); - planDto = - planDto.copyWith.ui(ui); - }, - ), - TextParam( - 'UI Tip color', - planDto.ui.tipColor, - (v) { - final ui = planDto.ui.copyWith( - tipColor: v, - ); - planDto = - planDto.copyWith.ui(ui); - }, - ), - Padding( - padding: - const EdgeInsets.all(8.0), - child: Row( - children: [ - Text('Payment type '), - Expanded( - child: StatefulBuilder( - builder: (context, - setState) { - return DropdownButton< - PaymentSystem>( - value: planDto - .paymentSystem, - items: - PaymentSystem.values - .map( - (v) => - DropdownMenuItem( - child: Text( - v.name), - value: v, - ), - ) - .toList(), - onChanged: (v) { - setState(() { - planDto = planDto - .copyWith( - paymentSystem: v ?? - PaymentSystem - .unknown, - ); - }); - }, - ); - }), - ), - ], - ), - ), - TextParam( - 'Payment id', - planDto.paymentId, - (v) { - planDto = planDto.copyWith( - paymentId: v, - ); - }, - ), - ], - ), - ], - ), - ), - ], - ); - }), - ], - ); - }), - ), - ), - ); - }); - }); - } - - Widget uiEditor() { - return Column( - children: [], - ); - } -} diff --git a/mnemo_cards/lib/admin/add_promocode_campaign.dart b/mnemo_cards/lib/admin/add_promocode_campaign.dart deleted file mode 100644 index efab938..0000000 --- a/mnemo_cards/lib/admin/add_promocode_campaign.dart +++ /dev/null @@ -1,399 +0,0 @@ -import 'dart:async'; -import 'dart:developer'; - -import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; - -import 'package:mnemo_cards/admin/admin_api.dart'; -import 'package:mnemo_cards_common/mnemo_cards_common.dart'; -import 'package:mnemo_cards_frontend_common/mnemo_cards_frontend_common.dart'; - -import '../di/injector.dart'; -import '../main.dart'; -import 'date_param.dart'; -import 'enum_param.dart'; -import 'int_param.dart'; -import 'text_param.dart'; - -class AddPromocodeCampaign { - late PromoCodesCampaignDto campaignDto; - late AdminApi adminApi; - List _campaigns = []; - - final availableStatuses = [ - PromoCodeCampaignStatus.created, - PromoCodeCampaignStatus.preparing, - PromoCodeCampaignStatus.ready, - PromoCodeCampaignStatus.active, - PromoCodeCampaignStatus.disabled, - ]; - - AddPromocodeCampaign() { - this.adminApi = getIt.get(); - _init(null); - } - - void _init(PromoCodesCampaignDto? dto) { - final now = DateTime.now(); - campaignDto = dto ?? - PromoCodesCampaignDto( - products: [], - activationsPerCode: 1, - activationsPerUser: 1, - generationSize: 100, - start: now, - finish: now.add(Duration(days: 60)), - status: PromoCodeCampaignStatus.disabled, - name: null, - template: r'$s$s$s$s$s$s$s$s', - tags: [], - ); - } - - Future _loadCampaigns() async { - try { - _campaigns = await adminApi.getPromoCodeCampaigns(); - } catch (e, s) { - log('Error', error: e, stackTrace: s); - print('Error $e'); - return false; - } - return true; - } - - Future _loadCampaign(String id) async { - try { - final campaign = await adminApi.getPromoCodeCampaign(id); - if (campaign != null) { - _campaigns.removeWhere((v) => v.id.toString() == id); - _campaigns.add(campaign); - campaignDto = campaign; - } - } catch (e, s) { - log('Error', error: e, stackTrace: s); - print('Error $e'); - return false; - } - return true; - } - - void _savePromoCodeCampaign() async { - final result = await adminApi.addPromoCodeCampaign(campaignDto); - if (!result) { - ScaffoldMessenger.of(scaffoldKey.currentContext!).showSnackBar(SnackBar( - content: Text('ERROR'), - )); - } else { - ScaffoldMessenger.of(scaffoldKey.currentContext!).showSnackBar(SnackBar( - content: Text('Success!!!'), - )); - appRouter.maybePop(); - } - } - - void _deletePromoCodeCampaign() async { - if (campaignDto.id == null) return; - final result = - await adminApi.deletePromoCodeCampaign(campaignDto.id.toString()); - if (!result) { - ScaffoldMessenger.of(scaffoldKey.currentContext!).showSnackBar(SnackBar( - content: Text('ERROR'), - )); - } else { - ScaffoldMessenger.of(scaffoldKey.currentContext!).showSnackBar(SnackBar( - content: Text('Success!!!'), - )); - appRouter.maybePop(); - } - } - - void addCampaign(BuildContext context) { - showDialog( - context: context, - builder: (c) { - return FutureBuilder( - future: _loadCampaigns(), - builder: (context, snapshot) { - if (snapshot.data != true) { - return Center( - child: Material( - child: Center(child: CircularProgressIndicator()), - ), - ); - } - return Center( - child: Scaffold( - body: Material( - child: StatefulBuilder(builder: (context, setCampaign) { - final codes = campaignDto.promoCodes; - - return ListView( - children: [ - Header( - '${campaignDto.id}', - hasPopButton: true, - trail: Row( - children: [ - if (campaignDto.id != null) - IconButton( - onPressed: () async { - await _loadCampaign( - campaignDto.id.toString(), - ); - setCampaign(() {}); - }, - icon: Icon(Icons.note), - ), - IconButton( - onPressed: _savePromoCodeCampaign, - icon: Icon(Icons.save), - ), - if (campaignDto.id != null) - IconButton( - onPressed: () async { - campaignDto = - campaignDto.copyWith(id: null); - _savePromoCodeCampaign(); - }, - icon: Icon(Icons.copy), - ), - if (campaignDto.id != null) - GestureDetector( - onLongPress: _deletePromoCodeCampaign, - child: Icon(Icons.delete), - ) - ], - ), - ), - DropdownMenu( - initialSelection: null, - onSelected: (int? value) { - setCampaign(() { - _init( - _campaigns - .firstWhereOrNull((v) => v.id == value), - ); - }); - }, - dropdownMenuEntries: [ - ..._campaigns, - null, - ].map((campaign) { - return DropdownMenuEntry( - value: campaign?.id, - label: campaign == null - ? 'New' - : '${campaign.name ?? campaign.id} ${campaign.status.name}', - ); - }).toList(), - ), - StatefulBuilder(builder: (context, setState) { - return Padding( - padding: EdgeInsets.all(8.0), - child: Column( - children: [ - TextParam( - 'Name', - campaignDto.name, - (v) { - campaignDto = campaignDto.copyWith( - name: v, - ); - }, - ), - TextParam( - 'Template', - campaignDto.template, - (v) { - campaignDto = campaignDto.copyWith( - template: v, - ); - }, - description: - r'$d - digit $l - letter $s - any', - ), - IntParam( - 'Generation size', - campaignDto.generationSize, - (v) { - campaignDto = campaignDto.copyWith( - generationSize: v); - }, - ), - IntParam( - 'Activations per code', - campaignDto.activationsPerCode, - (v) { - campaignDto = campaignDto.copyWith( - activationsPerCode: v, - ); - }, - ), - IntParam( - 'Activations per user', - campaignDto.activationsPerUser, - (v) { - campaignDto = campaignDto.copyWith( - activationsPerUser: v, - ); - }, - ), - DateParam( - 'Start', - campaignDto.start, - (v) { - setState(() { - campaignDto = - campaignDto.copyWith(start: v); - }); - }, - ), - DateParam( - 'Finish', - campaignDto.finish, - (v) { - setState(() { - campaignDto = - campaignDto.copyWith(finish: v); - }); - }, - ), - EnumParam( - 'Status', - PromoCodeCampaignStatus.values, - campaignDto.status, (v) { - setState(() { - campaignDto = - campaignDto.copyWith(status: v); - }); - }), - Text( - 'Created to generate promocodes\n' - 'Disabled to disable\n' - 'Dont use other statuses!', - style: TextStyle(fontSize: 12), - ), - Text('Products:'), - ListView.builder( - shrinkWrap: true, - itemCount: - campaignDto.products.length + 1, - itemBuilder: (context, index) { - if (index == - campaignDto.products.length) { - return ListTile( - title: Text('Add'), - onTap: () async { - final p = - await _showProductDialog( - context, null); - if (p != null) { - setState(() { - campaignDto.products.add(p); - }); - } - }, - ); - } - final item = - campaignDto.products[index]; - return ListTile( - title: Text( - '${item.type.name} ${item.id ?? ''}'), - onTap: () async { - final p = await _showProductDialog( - context, - item, - ); - if (p != null) { - setState(() { - campaignDto.products.add(p); - }); - } - }, - trailing: IconButton( - icon: Icon(Icons.delete), - onPressed: () { - setState(() { - campaignDto.products - .remove(item); - }); - }, - ), - ); - }, - ), - SimpleTile.text( - text: codes == null - ? 'Codes not loaded' - : 'Codes: ${codes.length == 1 ? codes.first : codes.length}', - onTap: () async { - if (codes != null) { - await Clipboard.setData( - ClipboardData( - text: codes.join('\n'), - ), - ); - } - }, - ), - ], - ), - ); - }), - ], - ); - }), - ), - ), - ); - }); - }); - } - - Future _showProductDialog( - BuildContext context, - MnemoCardsProductDto? initialProduct, - ) async { - var prod = initialProduct ?? MnemoCardsProductDto(); - final result = await showDialog( - context: context, - builder: (c) => Center( - child: Padding( - padding: const EdgeInsets.all(8.0), - child: Material( - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - TextParam('Id', prod.id, (v) { - prod = prod.copyWith(id: v); - }), - EnumParam( - 'Type', - MnemoCardsProductType.values, - prod.type, - (v) { - prod = prod.copyWith(type: v); - }, - ), - MaterialButton( - onPressed: () { - Navigator.of(context).pop(prod); - }, - child: Text('Save'), - ), - ], - ), - ), - ), - ), - ); - return result; - } - - Widget uiEditor() { - return Column( - children: [], - ); - } -} diff --git a/mnemo_cards/lib/admin/add_user.dart b/mnemo_cards/lib/admin/add_user.dart deleted file mode 100644 index 930d9a3..0000000 --- a/mnemo_cards/lib/admin/add_user.dart +++ /dev/null @@ -1,228 +0,0 @@ -import 'dart:async'; - -import 'package:flutter/material.dart'; - -import 'package:flutter/services.dart'; -import 'package:mnemo_cards/admin/admin_api.dart'; -import 'package:mnemo_cards_common/mnemo_cards_common.dart'; -import 'package:mnemo_cards_frontend_common/mnemo_cards_frontend_common.dart'; - -import '../main.dart'; - -class EditUser { - UserDto userDto; - AdminApi adminApi; - bool imageChanged = false; - - EditUser(UserDto userDto, this.adminApi) : userDto = userDto; - - void _saveUser() async { - final dto = userDto; - final result = await adminApi.editUser(dto); - if (!result) { - ScaffoldMessenger.of(scaffoldKey.currentContext!).showSnackBar(SnackBar( - content: Text('ERROR'), - )); - } else { - ScaffoldMessenger.of(scaffoldKey.currentContext!).showSnackBar(SnackBar( - content: Text('Success!!!'), - )); - appRouter.maybePop(); - } - } - - void _deleteCard() async { - final result = await adminApi.deleteUser(userDto); - if (!result) { - ScaffoldMessenger.of(scaffoldKey.currentContext!).showSnackBar(SnackBar( - content: Text('ERROR'), - )); - } else { - ScaffoldMessenger.of(scaffoldKey.currentContext!).showSnackBar(SnackBar( - content: Text('Success!!!'), - )); - appRouter.maybePop(); - } - } - - void addUser(BuildContext context) { - final theme = Theme.of(context).textTheme; - - final TextEditingController nameController = - TextEditingController(text: userDto.name); - - final TextEditingController packsController = - TextEditingController(text: userDto.packs.join(',')); - - showDialog( - context: context, - builder: (c) { - return Center( - child: Scaffold( - body: Material( - child: ListView( - children: [ - Header( - '${userDto.id}', - hasPopButton: true, - trail: Row( - children: [ - IconButton( - onPressed: _saveUser, - icon: Icon(Icons.save), - ), - if (userDto.id != null && userDto.id! >= 0) - GestureDetector( - onLongPress: _deleteCard, - child: Icon(Icons.delete), - ) - ], - ), - ), - StatefulBuilder(builder: (context, setState) { - return Padding( - padding: EdgeInsets.all(8.0), - child: Column( - children: [ - GestureDetector( - onTap: () { - if (userDto.id != null) { - Clipboard.setData(ClipboardData( - text: userDto.id.toString())); - } - }, - child: Text('ID: ${userDto.id}'), - ), - Text('Admin: ${userDto.admin}'), - TextField( - controller: nameController, - onChanged: (v) { - userDto = userDto.copyWith(name: v); - }, - decoration: InputDecoration(hintText: 'Name'), - maxLines: 1, - style: theme.displayMedium?.copyWith( - fontSize: theme.displayMedium!.fontSize!, - ), - ), - Row( - children: [ - Expanded(child: Text('Subscription ')), - StatefulBuilder(builder: (context, setState) { - return Switch( - value: userDto.subscription ?? false, - onChanged: (v) { - setState(() { - userDto = - userDto.copyWith.subscription(v); - }); - }); - }), - ], - ), - TextField( - controller: packsController, - onChanged: (v) { - final packs = v - .split(',') - .map((s) => - int.tryParse(s.trim())?.toString()) - .whereNotNull() - .toList(); - userDto = userDto.copyWith(packs: packs); - final packsText = packs.join(','); - if (!packsController.text - .startsWith(packsText)) { - packsController.text = packsText; - } - }, - decoration: InputDecoration(hintText: 'Packs'), - maxLines: 1, - style: theme.displayMedium?.copyWith( - fontSize: theme.displayMedium!.fontSize!, - ), - ), - ], - ), - ); - }), - _Payments(adminApi, userDto), - Text( - 'Stats: ${userDto.userDataDto?.allWordsStatistics?.total} words', - ), - Text( - 'Stats: ${userDto.userDataDto?.allTestsStatistics?.tests.length} tests', - ), - Text( - 'Last test session: ${userDto.userDataDto?.allTestsStatistics?.lastSessionToken}', - ), - ], - ), - ), - ), - ); - }); - } -} - -class _Payments extends StatelessWidget { - final AdminApi adminApi; - final UserDto userDto; - - _Payments(this.adminApi, this.userDto); - - @override - Widget build(BuildContext context) { - final sc = StreamController?>(); - final stream = sc.stream; - - return ExpansionTile( - title: Text('Транзакции'), - maintainState: true, - onExpansionChanged: (v) async { - if (v) { - sc.add(null); - final payments = - await adminApi.getUserPurchases(userDto.id.toString()); - sc.add(payments); - } - }, - children: [ - StreamBuilder?>( - stream: stream, - builder: (context, snapshot) { - final payments = snapshot.data; - if (payments == null) { - return Text('Loading...'); - } - if (payments.isEmpty) { - return Text('Нет покупок'); - } - return Column( - children: payments.map((p) { - return ListTile( - title: Text('${p.amount} ${p.currency}'), - subtitle: Text(dateString(p.date)), - trailing: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.end, - children: [ - Text(p.status.name), - Text(p.paymentSystem.name), - Text( - p.products.map((p) => '${p.type}: ${p.id}').join('\n'), - ), - ], - ), - ); - }).toList(), - ); - }, - ), - ], - ); - } - - String dateString(DateTime date) => - '${date.year}.${date.month.toString().padLeft(2, '0')}.${date.day.toString().padLeft(2, '0')} ${date.hour.toString().padLeft(2, '0')}:${date.minute.toString().padLeft(2, '0')}:${date.second.toString().padLeft(2, '0')}'; -} diff --git a/mnemo_cards/lib/admin/admin_api.dart b/mnemo_cards/lib/admin/admin_api.dart deleted file mode 100644 index d0c86a9..0000000 --- a/mnemo_cards/lib/admin/admin_api.dart +++ /dev/null @@ -1,196 +0,0 @@ -import 'dart:async'; -import 'dart:convert'; -import 'dart:developer'; - -import 'package:dio/dio.dart'; -import 'package:mnemo_cards/di/injector.dart'; -import 'package:mnemo_cards/features/packs/packs_api.dart'; -import 'package:mnemo_cards/features/worker/worker_ext.dart'; -import 'package:mnemo_cards/managers/repository/api.dart'; -import 'package:mnemo_cards_common/mnemo_cards_common.dart'; - -class AdminApi with Api { - final Dio _dio; - - AdminApi(this._dio); - - Future addCard( - GameCardDto dto, { - ProgressCallback? progressCallback, - }) async { - final r = await _dio.post( - '$path/cards/add', - data: jsonEncode(dto.toJson()), - options: Options(sendTimeout: Duration(seconds: 30)), - onSendProgress: (a, b) { - log('Card send progress $a/$b'); - progressCallback?.call(a, b); - }, - onReceiveProgress: (a, b) { - log('Card receive progress $a/$b'); - progressCallback?.call(a, b); - }, - ); - return r.statusCode == 200; - } - - Future deleteCard(GameCardDto dto) async { - final r = await _dio.post( - '$path/cards/delete', - data: jsonEncode({'id': dto.id.toString()}), - ); - return r.statusCode == 200; - } - - Future> getCardIds() async { - final r = await _dio.get('$path/cards/ids'); - return (jsonDecode(r.data!)['ids'] as String).split(',').cast(); - } - - Future> getCards(List ids) async { - final r = await _dio.get( - '$path/cards', - queryParameters: {'ids': ids.join(',')}, - ); - return (r.data as String).decodeList(GameCardDto.fromJson); - } - - Future> getUsers(List ids) async { - final r = await _dio.get( - '$path/users', - queryParameters: {'ids': ids.join(',')}, - ); - return (jsonDecode(r.data!) as List) - .map((e) => UserDto.fromJson(e as Map)) - .toList() - .cast(); - } - - Future> getUserIds() async { - final r = await _dio.get('$path/users/ids'); - return (jsonDecode(r.data!)['ids'] as String).split(',').cast(); - } - - Future> getUserPurchases(String userId) async { - final r = await _dio.get( - '$path/user/purchases', - queryParameters: {'id': userId}, - ); - return (jsonDecode(r.data!)['payments'] as List) - .cast>() - .map(PaymentDto.fromJson) - .toList(); - } - - Future deleteUser(UserDto dto) async { - final r = await _dio.post( - '$path/users/delete', - data: jsonEncode({'id': dto.id.toString()}), - ); - return r.statusCode == 200; - } - - Future editUser(UserDto dto) async { - final r = await _dio.post( - '$path/users/add', - data: jsonEncode(dto.toJson()), - ); - return r.statusCode == 200; - } - - Future getEditPack(String id) async { - final r = await _dio.get('$path/pack/edit/$id'); - return (r.data as String).decode(EditCardPackDto.fromJson); - } - - Future deletePack(EditCardPackDto dto) async { - final r = await _dio.post( - '$path/pack/delete', - data: jsonEncode({'id': dto.id.toString()}), - ); - return r.statusCode == 200; - } - - Future editPack(EditCardPackDto dto) async { - final r = await _dio.post( - '$path/pack/edit', - data: jsonEncode(dto.toJson()), - ); - return r.statusCode == 200; - } - - Future> packs() => - getIt.get().getPacksPreviews(null); - - Future> getSubscriptionPlans() async { - final r = await _dio.get('$path/subscriptions'); - return (jsonDecode(r.data!)['plans'] as List) - .cast>() - .map(SubscriptionPlanAdminDto.fromJson) - .toList(); - } - - Future addSubscriptionPlan(SubscriptionPlanAdminDto dto) async { - final r = await _dio.post( - '$path/subscription/add', - data: jsonEncode(dto.toJson()), - ); - return r.statusCode == 200; - } - - Future deleteSubscriptionPlan(String id) async { - final r = await _dio.post('$path/subscription/delete/$id'); - return r.statusCode == 200; - } - - Future deletePromoCodeCampaign(String id) async { - final r = await _dio.post('$path/promocode/delete/$id'); - return r.statusCode == 200; - } - - Future addPromoCodeCampaign(PromoCodesCampaignDto dto) async { - final r = await _dio.post( - '$path/promocode/add', - data: dto.encode(), - ); - return r.statusCode == 200; - } - - Future> getPromoCodeCampaigns() async { - final r = await _dio.get('$path/promocode/list'); - return (jsonDecode(r.data!)['campaigns'] as List) - .cast>() - .map(PromoCodesCampaignDto.fromJson) - .toList(); - } - - Future getPromoCodeCampaign(String id) async { - final r = await _dio.get('$path/promocode/$id'); - return r.data?.isolatedDecode(PromoCodesCampaignDto.fromJson); - } - - Future addDiscountCampaign(DiscountCampaignDto dto) async { - final r = await _dio.post( - '$path/discounts/add', - data: dto.encode(), - ); - return r.statusCode == 200; - } - - Future> getDiscountCampaigns() async { - final r = await _dio.get('$path/discounts/list'); - return (jsonDecode(r.data!)['campaigns'] as List) - .cast>() - .map(DiscountCampaignDto.fromJson) - .toList(); - } - - Future deleteDiscountCampaign(String id) async { - try { - final r = await _dio.post('$path/discounts/delete/$id'); - return (jsonDecode(r.data!)['error'] as String?); - } catch (e, s) { - return e.toString(); - } - } -} diff --git a/mnemo_cards/lib/admin/all_cards.dart b/mnemo_cards/lib/admin/all_cards.dart deleted file mode 100644 index ceabd80..0000000 --- a/mnemo_cards/lib/admin/all_cards.dart +++ /dev/null @@ -1,367 +0,0 @@ -import 'dart:convert'; -import 'dart:math'; - -import 'package:dio/dio.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_screenutil/flutter_screenutil.dart'; -import 'package:mnemo_cards/admin/add_card.dart'; -import 'package:mnemo_cards/admin/admin_api.dart'; -import 'package:mnemo_cards/di/injector.dart'; -import 'package:mnemo_cards/managers/repository/dio_provider.dart'; -import 'package:mnemo_cards/theme/themes.dart'; -import 'package:mnemo_cards_common/mnemo_cards_common.dart'; -import 'package:mnemo_cards_frontend_common/mnemo_cards_frontend_common.dart'; - -import '../main.dart'; -import 'add_package.dart'; - -class AllCards extends StatefulWidget { - @override - State createState() => _AllCardsState(); - - const AllCards(); -} - -class _AllCardsState extends State { - static List ids = []; - static Set cards = {}; - static String filter = ''; - static List _packPreviews = []; - static EditCardPackDto? _currentPack; - static String? _currentId; - static List _selectedCards = []; - static Map _cache = {}; - - bool get selectingMode => _selectedCards.isNotEmpty; - - Dio get dio => getIt.get().dio; - - AdminApi get api => getIt.get(); - - Future loadCards() async { - var loadingIds = ids.toList(); - cards.clear(); - _cache.clear(); - while (loadingIds.isNotEmpty) { - try { - final ids = loadingIds.take(10).toList(); - loadingIds.removeRange(0, ids.length); - final cardsPage = await api.getCards(ids); - for (final card in cardsPage) { - final imageString = - card.image?.substring(0, min(100, card.image!.length)) ?? ''; - _cache[card.id.toString()] = - '${card.id}${card.mnemo}${card.transcription}${card.transcriptionMnemo}${card.original}${card.translation}${imageString}'; - } - cards.addAll(cardsPage); - setState(() {}); - } catch (e) { - print(e); - } - } - } - - Future loadIds() async { - ids = await api.getCardIds(); - setState(() {}); - } - - Future loadPacks() async { - _packPreviews = await api.packs(); - clearCurrentPack(); - } - - Future loadCurrentPack() async { - if (_currentId != null) { - _currentPack = await api.getEditPack(_currentId!); - setState(() {}); - } - } - - void clearCurrentPack() { - _currentId = null; - _currentPack = null; - setState(() {}); - } - - Future editPack(EditCardPackDto pack) async { - final result = await api.editPack(pack); - if (!result) { - ScaffoldMessenger.of(scaffoldKey.currentContext!).showSnackBar(SnackBar( - content: Text('ERROR'), - )); - } else { - ScaffoldMessenger.of(scaffoldKey.currentContext!).showSnackBar(SnackBar( - content: Text('Success!!!'), - )); - loadCurrentPack(); - _selectedCards.clear(); - } - } - - void addOrEditPack() => AddPackage(_currentPack, api).addPack(context); - - List buildCards() { - final filteredCards = cards.where((dto) { - final filterOk = - filter.isEmpty || _cache[dto.id.toString()]?.contains(filter) == true; - final packFilter = - _currentPack?.addCardIds?.contains(dto.id.toString()) ?? true; - return filterOk && packFilter; - }); - return filteredCards.toList(); - } - - @override - Widget build(BuildContext context) { - final filteredCards = buildCards(); - return Scaffold( - body: SafeArea( - child: Stack( - children: [ - ListView.builder( - itemExtentBuilder: (index, dims) => index >= 1 ? 160.h : 350, - itemBuilder: (context, index) { - if (index == 0) - return Column( - children: [ - Header( - _currentId == null - ? 'Все карточки' - : _currentPack?.title ?? - 'Пак ${_currentPack?.id}', - subtitle: filteredCards.isEmpty - ? 'Нет карточек' - : '${filteredCards.length} карточек', - hasPopButton: true, - trail: IconButton( - onPressed: () async { - setState(() {}); - await loadIds(); - await loadPacks(); - await loadCards(); - }, - icon: Icon(Icons.sync)), - ), - dropdownButton(context), - Padding( - padding: const EdgeInsets.all(8.0), - child: TextField( - decoration: InputDecoration(hintText: 'Поиск'), - onChanged: (v) { - if (filter != v.toLowerCase()) { - filter = v.toLowerCase(); - setState(() {}); - } - }, - ), - ), - Expanded( - child: GestureDetector( - onTap: () => EditCard(null, api).addCard(context), - child: Container( - color: Colors.green.withOpacity(0.1), - alignment: Alignment.center, - child: Icon(Icons.add, size: 30), - ), - ), - ), - ], - ); - if (filteredCards.length >= (index - 1) * 3) { - final cardIndex = (index - 1) * 3; - return Row( - children: [ - if (filteredCards.length > cardIndex) - cardWidget(filteredCards[cardIndex]), - if (filteredCards.length > cardIndex + 1) - cardWidget(filteredCards[cardIndex + 1]), - if (filteredCards.length > cardIndex + 2) - cardWidget(filteredCards[cardIndex + 2]), - ], - ); - } - return null; - }), - if (selectingMode) - Align( - alignment: Alignment.bottomCenter, - child: Container( - height: 100, - padding: EdgeInsets.all(10.0), - alignment: Alignment.center, - child: Row( - children: [ - GestureDetector( - onTap: () { - _selectedCards.clear(); - setState(() {}); - }, - child: Container( - color: Colors.blue, - padding: EdgeInsets.all(8.0), - child: Row( - children: [ - Text('${_selectedCards.length} '), - Icon(Icons.clear) - ], - ), - ), - ), - if (_currentPack != null) - if (_selectedCards.every((c) => - _currentPack!.addCardIds?.contains(c) ?? false)) - Row( - children: [ - SizedBox(width: 8.0), - GestureDetector( - onTap: () { - final updated = - _currentPack!.copyWith.removeCardIds( - _selectedCards.toList(), - ); - editPack(updated); - }, - child: Container( - padding: EdgeInsets.all(8.0), - color: Colors.blue, - child: Text('Убрать из пака'), - ), - ), - SizedBox(width: 8.0), - GestureDetector( - onTap: () { - final updated = - _currentPack!.copyWith.previewCards( - _selectedCards.toList(), - ); - editPack(updated); - }, - child: Container( - padding: EdgeInsets.all(8.0), - color: Colors.blue, - child: Text('Как превью'), - ), - ), - ], - ) - else - MaterialButton( - onPressed: () { - final updated = _currentPack!.copyWith.addCardIds( - _selectedCards.toList(), - ); - editPack(updated); - }, - child: Container( - padding: EdgeInsets.all(8.0), - color: Colors.blue, - child: Text('Добавить в пак'), - ), - ) - ], - ), - ), - ), - ], - ), - ), - ); - } - - Widget cardWidget(GameCardDto card) { - void toggleSelect() { - final id = card.id.toString(); - if (_selectedCards.contains(id)) { - _selectedCards.remove(id); - } else { - _selectedCards.add(card.id.toString()); - } - setState(() {}); - } - - return GestureDetector( - onTap: () { - if (selectingMode) { - toggleSelect(); - } else { - EditCard(card, api).addCard(context); - } - }, - onLongPress: toggleSelect, - child: _Card(card, api, _selectedCards.contains(card.id.toString())), - ); - } - - void _onPackChanged(String? id) { - if (id == null) { - clearCurrentPack(); - } else { - _currentId = id; - loadCurrentPack(); - } - } - - Widget dropdownButton(BuildContext context) { - return Row( - children: [ - Expanded( - child: DropdownButton( - items: [..._packPreviews, null] - .map((p) => DropdownMenuItem( - child: Padding( - padding: const EdgeInsets.all(8.0), - child: p == null - ? Text('Все паки') - : Text('${p.title} ${p.cards}'), - ), - value: p?.id, - )) - .toList(), - value: _currentId, - onChanged: (v) => _onPackChanged(v), - ), - ), - IconButton( - onPressed: addOrEditPack, - icon: _currentPack == null ? Icon(Icons.add) : Icon(Icons.edit), - ), - ], - ); - } -} - -class _Card extends StatelessWidget { - final GameCardDto cardDto; - final AdminApi api; - final bool selected; - - _Card(this.cardDto, this.api, this.selected); - - @override - Widget build(BuildContext context) { - final image = cardDto.image != null ? base64.decode(cardDto.image!) : null; - return Container( - padding: EdgeInsets.all(8.0), - width: MediaQuery.of(context).size.width / 3, - height: 160.h, - decoration: BoxDecoration( - border: Border.all(color: selected ? Colors.blue : borderGray), - color: selected ? Colors.blue.withOpacity(0.2) : null, - ), - child: Column(children: [ - Text(cardDto.translation ?? ''), - Text(cardDto.original ?? ''), - if (image != null) - Expanded( - child: Image.memory( - key: ObjectKey(cardDto.image), - gaplessPlayback: true, - image, - fit: BoxFit.scaleDown, - ), - ), - ]), - ); - } -} diff --git a/mnemo_cards/lib/admin/all_users.dart b/mnemo_cards/lib/admin/all_users.dart deleted file mode 100644 index bd58c30..0000000 --- a/mnemo_cards/lib/admin/all_users.dart +++ /dev/null @@ -1,230 +0,0 @@ - -import 'package:dio/dio.dart'; -import 'package:flutter/material.dart'; -import 'package:mnemo_cards/admin/add_user.dart'; -import 'package:mnemo_cards/admin/admin_api.dart'; -import 'package:mnemo_cards/di/injector.dart'; -import 'package:mnemo_cards/di/locator.dart'; -import 'package:mnemo_cards/managers/repository/dio_provider.dart'; -import 'package:mnemo_cards_common/mnemo_cards_common.dart'; -import 'package:mnemo_cards_frontend_common/mnemo_cards_frontend_common.dart'; - -import '../main.dart'; - -class AllUsers extends StatefulWidget { - @override - State createState() => _AllUsersState(); - - const AllUsers(); -} - -class _AllUsersState extends State { - static List ids = []; - static Set users = {}; - static String filter = ''; - static UserDto? _currentUser; - static String? _currentId; - - bool get selectingMode => false; //_selectedCards.isNotEmpty; - - Dio get dio => getIt.get().dio; - - AdminApi get api => getIt.get(); - - Future loadUsers() async { - var loadingIds = ids.toList(); - users.clear(); - while (loadingIds.isNotEmpty) { - try { - final ids = loadingIds.take(10).toList(); - loadingIds.removeRange(0, ids.length); - final usersPage = await api.getUsers(ids); - users.addAll(usersPage); - setState(() {}); - } catch (e) { - print(e); - } - } - } - - Future loadIds() async { - ids = await api.getUserIds(); - setState(() {}); - } - - Future loadCurrentUser() async { - if (_currentId != null) { - _currentUser = (await api.getUsers([_currentId!])).firstOrNull; - setState(() {}); - } - } - - void clearCurrentUser() { - _currentId = null; - _currentUser = null; - setState(() {}); - } - - Future editUser(UserDto user) async { - final result = await api.editUser(user); - if (!result) { - ScaffoldMessenger.of(scaffoldKey.currentContext!).showSnackBar(SnackBar( - content: Text('ERROR'), - )); - } else { - ScaffoldMessenger.of(scaffoldKey.currentContext!).showSnackBar(SnackBar( - content: Text('Success!!!'), - )); - } - } - - List buildUsersList() { - final filteredUsers = users.where((dto) { - final filterOk = filter.isEmpty || - dto.name.toString().toLowerCase().contains(filter) || - dto.id.toString().toLowerCase().contains(filter) || - dto.packs.any((p) => p.toLowerCase().contains(filter)); - return filterOk; - }); - return filteredUsers.toList(); - } - - @override - Widget build(BuildContext context) { - final filteredUsers = buildUsersList(); - return Scaffold( - body: SafeArea( - child: Stack( - children: [ - ListView.builder(itemBuilder: (context, index) { - if (index == 0) - return Container( - height: 270, - child: Column( - children: [ - Header( - _currentId == null - ? 'Все' - : _currentUser?.name ?? 'Пак ${_currentUser?.id}', - subtitle: filteredUsers.isEmpty - ? 'Нет пользователей' - : '${filteredUsers.length} пользователя', - hasPopButton: true, - trail: IconButton( - onPressed: () async { - setState(() {}); - await loadIds(); - await loadUsers(); - }, - icon: Icon(Icons.sync)), - ), - dropdownButton(context), - Padding( - padding: const EdgeInsets.all(8.0), - child: TextField( - decoration: InputDecoration(hintText: 'Поиск'), - onChanged: (v) { - if (filter != v.toLowerCase()) { - filter = v.toLowerCase(); - setState(() {}); - } - }, - ), - ), - // Expanded( - // child: GestureDetector( - // onTap: () => EditUser(null, api).addCard(context), - // child: Container( - // color: Colors.green.withOpacity(0.1), - // alignment: Alignment.center, - // child: Icon(Icons.add, size: 30), - // ), - // ), - // ), - ], - ), - ); - else if (filteredUsers.length > index - 1) - return userWidget(filteredUsers[index - 1]); - else - return null; - }), - if (selectingMode) - Align( - alignment: Alignment.bottomCenter, - child: Container( - height: 100, - padding: EdgeInsets.all(10.0), - alignment: Alignment.center, - child: Row( - children: [ - GestureDetector( - onTap: () { - setState(() {}); - }, - child: Container( - color: Colors.blue, - padding: EdgeInsets.all(8.0), - child: Row( - children: [Icon(Icons.clear)], - ), - ), - ), - ], - ), - ), - ), - ], - ), - ), - ); - } - - Widget userWidget(UserDto user) { - void toggleSelect() { - final id = user.id.toString(); - setState(() {}); - } - - return GestureDetector( - onTap: () { - if (selectingMode) { - toggleSelect(); - } else { - EditUser(user, api).addUser(context); - } - }, - onLongPress: toggleSelect, - child: _User(user, api, false), - ); - } - - Widget dropdownButton(BuildContext context) { - return Row( - children: [ - IconButton( - onPressed: null, - icon: _currentUser == null ? Icon(Icons.add) : Icon(Icons.edit), - ), - ], - ); - } -} - -class _User extends StatelessWidget { - final UserDto userDto; - final AdminApi api; - final bool selected; - - _User(this.userDto, this.api, this.selected); - - @override - Widget build(BuildContext context) { - final isCurrent = locator.userManager.userStateHolder.user?.id == userDto.id; - return ListTile( - title: Text('${userDto.id}${isCurrent ? ' (you)' : ''}'), - subtitle: Text(userDto.name ?? ''), - trailing: userDto.admin ? Text('admin') : null, - ); - } -} diff --git a/mnemo_cards/lib/admin/date_param.dart b/mnemo_cards/lib/admin/date_param.dart deleted file mode 100644 index eb3f013..0000000 --- a/mnemo_cards/lib/admin/date_param.dart +++ /dev/null @@ -1,77 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter/widgets.dart'; -import 'package:mnemo_cards_common/mnemo_cards_common.dart'; - -class DateParam extends StatelessWidget { - final String title; - final DateTime? initial; - final Function(DateTime? v) onChanged; - - DateParam(this.title, this.initial, this.onChanged); - - @override - Widget build(BuildContext context) { - return Padding( - padding: const EdgeInsets.all(4.0), - child: Row( - children: [ - Text(title), - SizedBox( - width: 8, - ), - Expanded( - child: Container( - padding: EdgeInsets.all(8.0), - decoration: BoxDecoration( - border: Border.all(), - borderRadius: BorderRadius.circular(8.0), - ), - child: GestureDetector( - behavior: HitTestBehavior.opaque, - onTap: () async { - final date = await showDatePicker( - context: context, - initialEntryMode: DatePickerEntryMode.calendar, - initialDate: initial ?? DateTime.now(), - firstDate: DateTime.utc(2000), - lastDate: DateTime.utc(2050), - ).then((selectedDate) { - // After selecting the date, display the time picker. - if (selectedDate != null) { - return showTimePicker( - context: context, - initialTime: TimeOfDay.now(), - ).then((selectedTime) { - // Handle the selected date and time here. - if (selectedTime != null) { - DateTime selectedDateTime = DateTime( - selectedDate.year, - selectedDate.month, - selectedDate.day, - selectedTime.hour, - selectedTime.minute, - ); - return selectedDateTime; - } - return null; - }); - } - return null; - }); - onChanged(date); - }, - child: Text( - initial?.let( - (d) => - '${d.year}.${d.month}.${d.day} ${d.hour}:${d.minute}', - ) ?? - 'No date', - ), - ), - ), - ), - ], - ), - ); - } -} diff --git a/mnemo_cards/lib/admin/enum_param.dart b/mnemo_cards/lib/admin/enum_param.dart deleted file mode 100644 index 6b380e1..0000000 --- a/mnemo_cards/lib/admin/enum_param.dart +++ /dev/null @@ -1,68 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter/widgets.dart'; - -class EnumParam extends StatelessWidget { - final String title; - final String? description; - final T initial; - final List values; - final Function(T v) onChanged; - final Function(T v)? getName; - - EnumParam( - this.title, - this.values, - this.initial, - this.onChanged, { - this.description, - this.getName, - }); - - String _defaultName(T v) => ((v is Enum) ? v.name : v.toString()); - - @override - Widget build(BuildContext context) { - T value = initial; - return Padding( - padding: const EdgeInsets.all(8.0), - child: Row( - children: [ - Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text(title), - if (description != null) - Text( - description!, - style: TextStyle(fontSize: 12), - ) - ], - ), - SizedBox( - width: 2, - ), - Expanded( - child: StatefulBuilder(builder: (context, setState) { - return DropdownButton( - value: value, - items: values - .map( - (v) => DropdownMenuItem( - child: Text(getName?.call(v) ?? _defaultName(v)), - value: v, - ), - ) - .toList(), - onChanged: (v) => setState(() { - value = v!; - onChanged(v); - }), - ); - }), - ) - ], - ), - ); - } -} diff --git a/mnemo_cards/lib/admin/int_param.dart b/mnemo_cards/lib/admin/int_param.dart deleted file mode 100644 index 3c65127..0000000 --- a/mnemo_cards/lib/admin/int_param.dart +++ /dev/null @@ -1,32 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter/widgets.dart'; - -class IntParam extends StatelessWidget { - final String title; - final int? initial; - final Function(int? v) onChanged; - - IntParam(this.title, this.initial, this.onChanged); - - @override - Widget build(BuildContext context) { - return Padding( - padding: const EdgeInsets.all(8.0), - child: Row( - children: [ - Text(title+':'), - SizedBox( - width: 3, - ), - Expanded( - child: TextField( - controller: - TextEditingController(text: initial?.toString() ?? ''), - onChanged: (v) => onChanged(int.tryParse(v)), - ), - ), - ], - ), - ); - } -} diff --git a/mnemo_cards/lib/admin/text_param.dart b/mnemo_cards/lib/admin/text_param.dart deleted file mode 100644 index b6e8ffe..0000000 --- a/mnemo_cards/lib/admin/text_param.dart +++ /dev/null @@ -1,43 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter/widgets.dart'; - -class TextParam extends StatelessWidget { - final String title; - final String? description; - final String? initial; - final Function(String v) onChanged; - - TextParam(this.title, this.initial, this.onChanged, {this.description}); - - @override - Widget build(BuildContext context) { - return Padding( - padding: const EdgeInsets.all(8.0), - child: Row( - children: [ - Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text(title), - if (description != null) - Text( - description!, - style: TextStyle(fontSize: 12), - ) - ], - ), - SizedBox( - width: 2, - ), - Expanded( - child: TextField( - controller: TextEditingController(text: initial), - onChanged: onChanged, - ), - ), - ], - ), - ); - } -} diff --git a/mnemo_cards/lib/common_device_info.dart b/mnemo_cards/lib/common_device_info.dart deleted file mode 100644 index 06dc55e..0000000 --- a/mnemo_cards/lib/common_device_info.dart +++ /dev/null @@ -1,7 +0,0 @@ -class CommonDeviceInfo { - final bool isPhysicalDevice; - - CommonDeviceInfo({ - required this.isPhysicalDevice, - }); -} diff --git a/mnemo_cards/lib/di/injector.dart b/mnemo_cards/lib/di/injector.dart deleted file mode 100644 index 0f9af71..0000000 --- a/mnemo_cards/lib/di/injector.dart +++ /dev/null @@ -1,199 +0,0 @@ -import 'package:app_links/app_links.dart'; -import 'package:flutter/foundation.dart'; -import 'package:get_it/get_it.dart'; -import 'package:mnemo_cards/features/games/games_repository.dart'; -import 'package:mnemo_cards/features/packs/pack_cache_manager.dart'; -import 'package:mnemo_cards/features/packs/packs_api.dart'; -import 'package:mnemo_cards/features/purchase/google_purchase_handler.dart'; -import 'package:mnemo_cards/features/purchase/yookassa_purchase_handler.dart'; -import 'package:mnemo_cards/features/subscription/subscription_api.dart'; -import 'package:mnemo_cards/main.dart'; -import 'package:mnemo_cards/managers/favorite_cards.dart'; -import 'package:mnemo_cards/managers/repository/dio_provider.dart'; -import 'package:mnemo_cards/managers/repository/http_repository.dart'; - -import '../features/deeplinks/deeplinks_manager_impl.dart'; -import '../features/games/games_api.dart'; -import '../features/games/games_manager.dart'; -import '../features/packs/active_pack_cubit.dart'; -import '../features/packs/images_holder.dart'; -import '../features/packs/pack_updater.dart'; -import '../features/packs/packs_holder.dart'; -import '../features/packs/preview_packs_poller.dart'; -import '../features/packs/web_pack_cache_manager.dart'; -import '../features/purchase/in_app_purchase.dart'; -import '../features/purchase/purchase_deeplink_handler.dart'; -import '../features/purchase/purchase_manager.dart'; -import '../features/subscription/subscription_deeplink_handler.dart'; -import '../features/subscription/subscription_manager.dart'; -import '../features/tests/test_manager.dart'; -import '../features/packs/pack_manager.dart'; -import '../features/packs/preview_pack_holder.dart'; -import '../features/tests/tests_cache.dart'; -import '../features/yandex_ads/ads_deeplink_handler.dart'; -import '../features/yandex_ads/yandex_rewarded_ads.dart'; -import '../managers/user_manager.dart'; - -GetIt getIt = GetIt.I; - -Future setInjections() async { - final _dio = await DioProvider().init(); - getIt.registerSingleton(_dio); - print('set dio'); - - getIt.registerLazySingleton( - () => HttpRepository(getIt.get().dio), - ); - print('set repo'); - - getIt.registerLazySingleton( - () => PacksApi(getIt.get().dio), - ); - print('set pack'); - - getIt.registerLazySingleton( - () => GamesApi(getIt.get().dio), - ); - - getIt.registerLazySingleton( - () => GamesRepository(globalSharedPreferences, getIt.get()), - ); - - getIt.registerLazySingleton( - () => GamesManager(getIt.get()), - ); - - print('set games'); - - getIt.registerLazySingleton( - () => SubscriptionApi(getIt.get().dio), - ); - - getIt.registerLazySingleton( - () => SubscriptionManager( - getIt.get(), - getIt.get(), - ), - ); - print('set subscription'); - - getIt.registerLazySingleton( - () => PacksHolder(), - ); - print('set loading pack holder'); - - getIt.registerLazySingleton( - () => PreviewPackHolder(), - ); - print('set preview'); - - getIt.registerLazySingleton( - () => kIsWeb ? WebPackCacheManager() : PackCacheManager(), - ); - print('set cache'); - - getIt.registerLazySingleton( - () => ImagesHolder(), - ); - print('set images holder'); - - getIt.registerLazySingleton( - () => PreviewPacksPoller( - getIt.get(), - getIt.get(), - ), - ); - print('set preview poller'); - - getIt.registerLazySingleton( - () => PackManager( - getIt.get(), - getIt.get(), - getIt.get(), - ), - ); - print('set pack manager'); - - getIt.registerLazySingleton( - () => ActivePackCubit( - getIt.get(), - getIt.get(), - getIt.get(), - ), - ); - print('set active pack cubit'); - - getIt.registerLazySingleton( - () => PackUpdater( - getIt.get(), - getIt.get(), - getIt.get(), - getIt.get(), - getIt.get(), - ), - ); - print('set pack updater'); - - getIt.registerLazySingleton( - () => UserManager( - getIt.get(), - ), - ); - print('set user manager'); - - getIt.registerLazySingleton( - () => FavoriteCardsController(), - ); - print('set fav cards container'); - - getIt.registerLazySingleton( - () => TestsCache(), - ); - - getIt.registerLazySingleton( - () => TestManager( - getIt.get(), - getIt.get(), - getIt.get(), - ), - ); - print('set test manager'); - - getIt.registerLazySingleton( - () => YandexRewardedAds()..init(), - ); - print('set rewarded ads'); - - getIt.registerLazySingleton( - () => InAppPurchaseService(), - ); - - getIt.registerLazySingleton( - () => PurchaseDetailsStreamSubscription(), - ); - - getIt.registerLazySingleton( - () => PurchaseManager( - GooglePurchaseHandler(getIt.get()), - YookassaPurchaseHandler(getIt.get()), - ), - ); - - getIt.registerLazySingleton( - () => DeeplinkManager( - AppLinks(), - [ - PurchaseDeeplinkHandler(getIt.get()), - SubscriptionDeeplinkHandler(), - AdsDeeplinkHandler(getIt.get()), - ], - ), - ); - - try { - await getIt.allReady(); - print('injector all ready'); - } catch (e, s) { - print('injector error $e $s'); - } -} diff --git a/mnemo_cards/lib/di/locator.dart b/mnemo_cards/lib/di/locator.dart deleted file mode 100644 index a564216..0000000 --- a/mnemo_cards/lib/di/locator.dart +++ /dev/null @@ -1,68 +0,0 @@ -import 'package:get_it/get_it.dart'; -import 'package:mnemo_cards/features/games/games_manager.dart'; -import 'package:mnemo_cards/features/packs/active_pack_cubit.dart'; -import 'package:mnemo_cards/features/packs/packs_holder.dart'; -import 'package:mnemo_cards/features/packs/preview_pack_holder.dart'; -import 'package:mnemo_cards/features/packs/preview_packs_poller.dart'; -import 'package:mnemo_cards/features/purchase/purchase_manager.dart'; -import 'package:mnemo_cards/features/subscription/subscription_manager.dart'; -import 'package:mnemo_cards/managers/favorite_cards.dart'; -import 'package:mnemo_cards/managers/repository/http_repository.dart'; - -import '../features/deeplinks/deeplinks_manager_impl.dart'; -import '../features/packs/images_holder.dart'; -import '../features/packs/pack_cache_manager.dart'; -import '../features/packs/pack_updater.dart'; -import '../features/purchase/in_app_purchase.dart'; -import '../features/packs/pack_manager.dart'; -import '../features/subscription/subscription_api.dart'; -import '../features/tests/test_manager.dart'; -import '../managers/user_manager.dart'; -import 'injector.dart'; - -const locator = Locator(); - -class Locator { - GetIt get _getIt => getIt; - - const Locator(); - - HttpRepository get repository => _getIt.get(); - - PackManager get packManager => _getIt.get(); - - ActivePackCubit get activePackCubit => _getIt.get(); - - UserManager get userManager => _getIt.get(); - - SubscriptionApi get subscriptionApi => _getIt.get(); - - FavoriteCardsController get favoriteCardsController => - _getIt.get(); - - PackCacheManager get packCacheManager => _getIt.get(); - - PackUpdater get packUpdater => _getIt.get(); - - PacksHolder get packsHolder => _getIt.get(); - - DeeplinkManager get deeplinkManager => _getIt.get(); - - PreviewPackHolder get previewPackHolder => _getIt.get(); - - PreviewPacksPoller get previewPackPoller => _getIt.get(); - - SubscriptionManager get subscriptionManager => - _getIt.get(); - - TestManager get testManager => _getIt.get(); - - GamesManager get gamesManager => _getIt.get(); - - ImagesHolder get imagesHolder => _getIt.get(); - - InAppPurchaseService get purchaseService => - _getIt.get(); - - PurchaseManager get purchaseManager => _getIt.get(); -} diff --git a/mnemo_cards/lib/domain/router/app_router.dart b/mnemo_cards/lib/domain/router/app_router.dart deleted file mode 100644 index 43751d7..0000000 --- a/mnemo_cards/lib/domain/router/app_router.dart +++ /dev/null @@ -1,103 +0,0 @@ -import 'package:auto_route/auto_route.dart'; - -import '../../di/locator.dart'; -import '../../main.dart' as main; -import 'app_router.gr.dart'; - -@AutoRouterConfig( - replaceInRouteName: 'Route,Screen', -) -class AppRouter extends RootStackRouter { - final bool admin; - - AppRouter(this.admin); - - @override - List get routes => [ - CustomRoute( - initial: true, - page: MainTabsPage.page, - transitionsBuilder: TransitionsBuilders.noTransition, - children: _getMainTabRoutes()), - CustomRoute( - page: SettingsPage.page, - transitionsBuilder: TransitionsBuilders.slideLeftWithFade, - durationInMilliseconds: 200, - ), - CustomRoute( - page: AuthPage.page, - transitionsBuilder: TransitionsBuilders.slideLeftWithFade, - durationInMilliseconds: 200, - ), - CustomRoute( - page: TestPage.page, - transitionsBuilder: TransitionsBuilders.slideLeftWithFade, - durationInMilliseconds: 200, - ), - CustomRoute( - page: CardGamePage.page, - transitionsBuilder: TransitionsBuilders.fadeIn, - durationInMilliseconds: 400, - ), - CustomRoute( - page: CardPackPage.page, - transitionsBuilder: TransitionsBuilders.fadeIn, - durationInMilliseconds: 200, - ), - ]; - - List _getMainTabRoutes() { - final routes = [ - CustomRoute( - page: HomePage.page, - transitionsBuilder: TransitionsBuilders.noTransition, - ), - CustomRoute( - page: VocabularyPage.page, - transitionsBuilder: TransitionsBuilders.noTransition, - ), - CustomRoute( - page: GamesPage.page, - transitionsBuilder: TransitionsBuilders.noTransition, - ), - CustomRoute( - page: ProfilePage.page, - transitionsBuilder: TransitionsBuilders.slideLeftWithFade, - ), - ]; - - return routes; - } - - static void openAuth() { - final router = main.appRouter; - if (!router.isRouteActive(AuthPage.name)) { - router.replace(PageRouteInfo(AuthPage.name)); - } - } - - static void closeAuthPage() { - final router = main.appRouter; - if (router.isRouteActive(AuthPage.name)) { - router.replace(PageRouteInfo(HomePage.name)); - } - } - - static void openAuthOrProfile() { - if (locator.userManager.hasUser) { - openProfile(); - } else { - openAuth(); - } - } - - static void openProfile() { - final router = main.appRouter; - if (!router.isRouteActive(ProfilePage.name)) { - if (router.current.name == AuthPage.name) { - router.maybePop(); - } - router.push(PageRouteInfo(ProfilePage.name)); - } - } -} diff --git a/mnemo_cards/lib/domain/router/app_router.gr.dart b/mnemo_cards/lib/domain/router/app_router.gr.dart deleted file mode 100644 index 609ee2a..0000000 --- a/mnemo_cards/lib/domain/router/app_router.gr.dart +++ /dev/null @@ -1,401 +0,0 @@ -// GENERATED CODE - DO NOT MODIFY BY HAND - -// ************************************************************************** -// AutoRouterGenerator -// ************************************************************************** - -// ignore_for_file: type=lint -// coverage:ignore-file - -// ignore_for_file: no_leading_underscores_for_library_prefixes -import 'package:auto_route/auto_route.dart' as _i14; -import 'package:flutter/material.dart' as _i16; -import 'package:mnemo_cards/features/chat/chat_page.dart' as _i4; -import 'package:mnemo_cards/features/games/games_page.dart' as _i6; -import 'package:mnemo_cards/features/games/payloads/integration_example.dart' - as _i5; -import 'package:mnemo_cards/features/games/payloads_demo_page.dart' as _i9; -import 'package:mnemo_cards/features/tests/test_page.dart' as _i12; -import 'package:mnemo_cards/main.dart' as _i8; -import 'package:mnemo_cards/pages/auth_page.dart' as _i1; -import 'package:mnemo_cards/pages/home_page.dart' as _i7; -import 'package:mnemo_cards/pages/profile_page.dart' as _i10; -import 'package:mnemo_cards/pages/settgins_page.dart' as _i11; -import 'package:mnemo_cards/pages/vocabulary_page.dart' as _i13; -import 'package:mnemo_cards/widgets/card_game/card_game_page.dart' as _i2; -import 'package:mnemo_cards/widgets/card_pack/card_pack_page.dart' as _i3; -import 'package:mnemo_cards_common/mnemo_cards_common.dart' as _i15; - -/// generated route for -/// [_i1.AuthPage] -class AuthPage extends _i14.PageRouteInfo { - const AuthPage({List<_i14.PageRouteInfo>? children}) - : super( - AuthPage.name, - initialChildren: children, - ); - - static const String name = 'AuthPage'; - - static _i14.PageInfo page = _i14.PageInfo( - name, - builder: (data) { - return _i1.AuthPage(); - }, - ); -} - -/// generated route for -/// [_i2.CardGamePage] -class CardGamePage extends _i14.PageRouteInfo { - CardGamePage({ - required List<_i15.GameCardDto> cards, - required _i16.Color? color, - int? startCardId, - bool infinite = false, - bool shuffle = true, - _i16.Key? key, - List<_i14.PageRouteInfo>? children, - }) : super( - CardGamePage.name, - args: CardGamePageArgs( - cards: cards, - color: color, - startCardId: startCardId, - infinite: infinite, - shuffle: shuffle, - key: key, - ), - initialChildren: children, - ); - - static const String name = 'CardGamePage'; - - static _i14.PageInfo page = _i14.PageInfo( - name, - builder: (data) { - final args = data.argsAs(); - return _i2.CardGamePage( - cards: args.cards, - color: args.color, - startCardId: args.startCardId, - infinite: args.infinite, - shuffle: args.shuffle, - key: args.key, - ); - }, - ); -} - -class CardGamePageArgs { - const CardGamePageArgs({ - required this.cards, - required this.color, - this.startCardId, - this.infinite = false, - this.shuffle = true, - this.key, - }); - - final List<_i15.GameCardDto> cards; - - final _i16.Color? color; - - final int? startCardId; - - final bool infinite; - - final bool shuffle; - - final _i16.Key? key; - - @override - String toString() { - return 'CardGamePageArgs{cards: $cards, color: $color, startCardId: $startCardId, infinite: $infinite, shuffle: $shuffle, key: $key}'; - } -} - -/// generated route for -/// [_i3.CardPackPage] -class CardPackPage extends _i14.PageRouteInfo { - CardPackPage({ - required _i15.CardPackPreviewDto previewDto, - _i16.Key? key, - List<_i14.PageRouteInfo>? children, - }) : super( - CardPackPage.name, - args: CardPackPageArgs( - previewDto: previewDto, - key: key, - ), - initialChildren: children, - ); - - static const String name = 'CardPackPage'; - - static _i14.PageInfo page = _i14.PageInfo( - name, - builder: (data) { - final args = data.argsAs(); - return _i3.CardPackPage( - args.previewDto, - key: args.key, - ); - }, - ); -} - -class CardPackPageArgs { - const CardPackPageArgs({ - required this.previewDto, - this.key, - }); - - final _i15.CardPackPreviewDto previewDto; - - final _i16.Key? key; - - @override - String toString() { - return 'CardPackPageArgs{previewDto: $previewDto, key: $key}'; - } -} - -/// generated route for -/// [_i4.ChatPage] -class ChatPage extends _i14.PageRouteInfo { - const ChatPage({List<_i14.PageRouteInfo>? children}) - : super( - ChatPage.name, - initialChildren: children, - ); - - static const String name = 'ChatPage'; - - static _i14.PageInfo page = _i14.PageInfo( - name, - builder: (data) { - return _i4.ChatPage(); - }, - ); -} - -/// generated route for -/// [_i5.GameWithPayloadsRoute] -class GameWithPayloadsScreen - extends _i14.PageRouteInfo { - GameWithPayloadsScreen({ - _i16.Key? key, - required String gameId, - required String gameUrl, - List<_i14.PageRouteInfo>? children, - }) : super( - GameWithPayloadsScreen.name, - args: GameWithPayloadsScreenArgs( - key: key, - gameId: gameId, - gameUrl: gameUrl, - ), - initialChildren: children, - ); - - static const String name = 'GameWithPayloadsScreen'; - - static _i14.PageInfo page = _i14.PageInfo( - name, - builder: (data) { - final args = data.argsAs(); - return _i5.GameWithPayloadsRoute( - key: args.key, - gameId: args.gameId, - gameUrl: args.gameUrl, - ); - }, - ); -} - -class GameWithPayloadsScreenArgs { - const GameWithPayloadsScreenArgs({ - this.key, - required this.gameId, - required this.gameUrl, - }); - - final _i16.Key? key; - - final String gameId; - - final String gameUrl; - - @override - String toString() { - return 'GameWithPayloadsScreenArgs{key: $key, gameId: $gameId, gameUrl: $gameUrl}'; - } -} - -/// generated route for -/// [_i6.GamesPage] -class GamesPage extends _i14.PageRouteInfo { - const GamesPage({List<_i14.PageRouteInfo>? children}) - : super( - GamesPage.name, - initialChildren: children, - ); - - static const String name = 'GamesPage'; - - static _i14.PageInfo page = _i14.PageInfo( - name, - builder: (data) { - return _i6.GamesPage(); - }, - ); -} - -/// generated route for -/// [_i7.HomePage] -class HomePage extends _i14.PageRouteInfo { - const HomePage({List<_i14.PageRouteInfo>? children}) - : super( - HomePage.name, - initialChildren: children, - ); - - static const String name = 'HomePage'; - - static _i14.PageInfo page = _i14.PageInfo( - name, - builder: (data) { - return _i7.HomePage(); - }, - ); -} - -/// generated route for -/// [_i8.MainTabsPage] -class MainTabsPage extends _i14.PageRouteInfo { - const MainTabsPage({List<_i14.PageRouteInfo>? children}) - : super( - MainTabsPage.name, - initialChildren: children, - ); - - static const String name = 'MainTabsPage'; - - static _i14.PageInfo page = _i14.PageInfo( - name, - builder: (data) { - return const _i8.MainTabsPage(); - }, - ); -} - -/// generated route for -/// [_i9.PayloadsDemoPage] -class PayloadsDemoPage extends _i14.PageRouteInfo { - const PayloadsDemoPage({List<_i14.PageRouteInfo>? children}) - : super( - PayloadsDemoPage.name, - initialChildren: children, - ); - - static const String name = 'PayloadsDemoPage'; - - static _i14.PageInfo page = _i14.PageInfo( - name, - builder: (data) { - return const _i9.PayloadsDemoPage(); - }, - ); -} - -/// generated route for -/// [_i10.ProfilePage] -class ProfilePage extends _i14.PageRouteInfo { - const ProfilePage({List<_i14.PageRouteInfo>? children}) - : super( - ProfilePage.name, - initialChildren: children, - ); - - static const String name = 'ProfilePage'; - - static _i14.PageInfo page = _i14.PageInfo( - name, - builder: (data) { - return _i10.ProfilePage(); - }, - ); -} - -/// generated route for -/// [_i11.SettingsPage] -class SettingsPage extends _i14.PageRouteInfo { - const SettingsPage({List<_i14.PageRouteInfo>? children}) - : super( - SettingsPage.name, - initialChildren: children, - ); - - static const String name = 'SettingsPage'; - - static _i14.PageInfo page = _i14.PageInfo( - name, - builder: (data) { - return _i11.SettingsPage(); - }, - ); -} - -/// generated route for -/// [_i12.TestPage] -class TestPage extends _i14.PageRouteInfo { - TestPage({ - required String testId, - List<_i14.PageRouteInfo>? children, - }) : super( - TestPage.name, - args: TestPageArgs(testId: testId), - initialChildren: children, - ); - - static const String name = 'TestPage'; - - static _i14.PageInfo page = _i14.PageInfo( - name, - builder: (data) { - final args = data.argsAs(); - return _i12.TestPage(args.testId); - }, - ); -} - -class TestPageArgs { - const TestPageArgs({required this.testId}); - - final String testId; - - @override - String toString() { - return 'TestPageArgs{testId: $testId}'; - } -} - -/// generated route for -/// [_i13.VocabularyPage] -class VocabularyPage extends _i14.PageRouteInfo { - const VocabularyPage({List<_i14.PageRouteInfo>? children}) - : super( - VocabularyPage.name, - initialChildren: children, - ); - - static const String name = 'VocabularyPage'; - - static _i14.PageInfo page = _i14.PageInfo( - name, - builder: (data) { - return const _i13.VocabularyPage(); - }, - ); -} diff --git a/mnemo_cards/lib/domain/router/dialogs.dart b/mnemo_cards/lib/domain/router/dialogs.dart deleted file mode 100644 index 35cdbaf..0000000 --- a/mnemo_cards/lib/domain/router/dialogs.dart +++ /dev/null @@ -1,109 +0,0 @@ -import 'dart:async'; - -import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; -import 'package:flutter_screenutil/flutter_screenutil.dart'; -import 'package:mnemo_cards/theme/themes.dart'; - -import '../../main.dart'; - -Future showInfoDialog( - String message, { - Widget? child, - String? secondMessage, - Completer? completer, -}) { - final context = scaffoldKey.currentContext!; - completer ??= Completer(); - final result = showDialog( - context: context, - useRootNavigator: false, - builder: (context) { - return Center( - child: Material( - color: Colors.transparent, - child: Container( - margin: EdgeInsets.all(4.0.h), - padding: EdgeInsets.all(4.0.h), - height: 200.h, - width: MediaQuery.of(context).size.width * 0.8, - decoration: BoxDecoration( - color: Theme.of(context).cardColor, - border: Border.all( - color: Colors.grey.withOpacity(0.5), - width: 1, - ), - borderRadius: BorderRadius.circular(12.0), - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Expanded( - child: Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - mainAxisSize: MainAxisSize.min, - children: [ - GestureDetector( - child: Text( - message, - textAlign: TextAlign.center, - style: TextStyle(fontWeight: FontWeight.w600), - ), - onTap: () => - Clipboard.setData(ClipboardData(text: message)), - ), - if (secondMessage != null) - Padding( - padding: EdgeInsets.only(top: 4.h), - child: GestureDetector( - child: Text( - secondMessage, - textAlign: TextAlign.center, - ), - onTap: () => Clipboard.setData( - ClipboardData(text: secondMessage), - ), - ), - ), - if (child != null) child, - ], - ), - ), - ), - GestureDetector( - onTap: Navigator.of(context).pop, - child: Container( - height: 40.h, - decoration: BoxDecoration( - color: testBlue, - border: Border.all( - color: Colors.grey.withOpacity(0.5), - width: 1, - ), - borderRadius: BorderRadius.circular(8.0), - ), - alignment: Alignment.center, - child: Text('Ок'), - ), - ), - ], - ), - ), - ), - ); - }, - ); - bool dialogClosed = false; - completer.future.then((_) { - if (!dialogClosed) { - return Navigator.of(context).pop(); - } - }); - return result.then((_) { - dialogClosed = true; - if (completer?.isCompleted == false) { - completer!.complete(); - } - }); -} diff --git a/mnemo_cards/lib/features/analytics/analytics.dart b/mnemo_cards/lib/features/analytics/analytics.dart deleted file mode 100644 index 18240c2..0000000 --- a/mnemo_cards/lib/features/analytics/analytics.dart +++ /dev/null @@ -1,247 +0,0 @@ -import 'package:firebase_analytics/firebase_analytics.dart'; -import 'package:firebase_crashlytics/firebase_crashlytics.dart'; -import 'package:mnemo_cards_common/mnemo_cards_common.dart'; - -class Analytics { - static final _analytics = FirebaseAnalytics.instance; - static final _crashlytics = FirebaseCrashlytics.instance; - - static Future setUser(UserDto user) { - return _analytics.setUserId(id: user.id?.toString()); - } - - static Future login(ExternalIdType idType) { - return _analytics.logLogin(loginMethod: idType.name); - } - - static Future logout(UserDto? dto) async { - await _analytics.logEvent( - name: 'logout', - parameters: { - 'id': dto?.id, - }.asFirebaseMap, - ); - return _analytics.setUserId(id: dto?.id?.toString()); - } - - static Future profilePageOpened(UserDto? dto) { - return _analytics.logScreenView( - screenClass: 'profile', - screenName: 'profile', - parameters: { - 'id': dto?.id, - }.asFirebaseMap); - } - - static Future gamesPageOpened(UserDto? dto) { - return _analytics.logScreenView( - screenClass: 'games', - screenName: 'games', - parameters: { - 'id': dto?.id, - }.asFirebaseMap); - } - - static Future chatPageOpened(UserDto? dto) { - return _analytics.logScreenView( - screenClass: 'chat', - screenName: 'chat', - parameters: { - 'id': dto?.id, - }.asFirebaseMap); - } - - static Future settingsPageOpened(UserDto? dto) { - return _analytics.logScreenView( - screenClass: 'settings', - screenName: 'settings', - parameters: { - 'id': dto?.id, - }.asFirebaseMap); - } - - static Future availablePackOpened(CardPackDto dto) { - return _analytics.logScreenView( - screenClass: 'pack', - screenName: 'available', - parameters: { - 'id': dto.id, - 'title': dto.title, - 'version': dto.version, - }.asFirebaseMap); - } - - static Future buyPackOpened(CardPackBuyDto dto) { - return _analytics.logScreenView( - screenClass: 'pack', - screenName: 'buy', - parameters: { - 'id': dto.id, - 'title': dto.title, - 'version': dto.version, - 'price': dto.price, - }.asFirebaseMap); - } - - static Future buyPackPressed(CardPackBuyDto dto, PaymentSystem system) { - return _analytics.logEvent( - name: 'buy', - parameters: { - 'id': dto.id, - 'title': dto.title, - 'version': dto.version, - 'price': dto.price, - 'system': system.name, - }.asFirebaseMap); - } - - static Future buyDeeplinkError( - Uri? uri, { - Map? data, - String? message, - }) { - return _analytics.logEvent( - name: 'buy_deeplink_error', - parameters: { - 'uri': uri.toString(), - if (message != null) 'message': message, - if (data != null) ...data, - }.asFirebaseMap); - } - - static Future buyError( - CardPackBuyDto? dto, - PaymentSystem system, { - String? id, - String? paymentId, - Map? data, - String? message, - }) { - return _analytics.logEvent( - name: 'buy_error', - parameters: { - 'id': id ?? dto?.id.toString(), - 'paymentId': paymentId, - 'system': system.name, - 'version': dto?.version.toString(), - 'price': dto?.price.toString(), - if (message != null) 'message': message, - if (data != null) ...data, - }.asFirebaseMap); - } - - static Future buySubscriptionError( - SubscriptionPlanDto? dto, - PaymentSystem system, { - Map? data, - String? message, - }) { - return _analytics.logEvent( - name: 'buy_sub_error', - parameters: { - 'id': dto?.id.toString(), - 'system': system.name, - 'currency': dto?.currency, - 'price': dto?.price.toString(), - if (message != null) 'message': message, - if (data != null) ...data, - }.asFirebaseMap, - ); - } - - static Future buyEvent( - CardPackBuyDto? dto, - PaymentSystem system, { - Map? data, - String? message, - }) { - return _analytics.logEvent( - name: 'buy_event', - parameters: { - 'id': dto?.id, - 'system': system.name, - 'version': dto?.version, - 'price': dto?.price, - if (message != null) 'message': message, - if (data != null) ...data, - }.asFirebaseMap); - } - - static Future buyComplete( - CardPackBuyDto? dto, - PaymentSystem system, { - String? id, - Map? data, - String? message, - }) { - return _analytics.logEvent( - name: 'buy_complete', - parameters: { - 'id': id ?? dto?.id, - 'system': system.name, - 'version': dto?.version, - 'price': dto?.price, - if (message != null) 'message': message, - if (data != null) ...data, - }.asFirebaseMap, - ); - } - - static Future loadingPackOpened(CardPackDto dto, int timeMillis) { - return _analytics.logScreenView( - screenClass: 'pack', - screenName: 'loading', - parameters: { - 'id': dto.id, - 'title': dto.title, - 'version': dto.version, - 'time': timeMillis, - }.asFirebaseMap); - } - - static Future testOpened(TestDto dto) { - return _analytics.logScreenView( - screenClass: 'test', - screenName: 'test', - parameters: { - 'id': dto.id, - 'name': dto.name, - 'version': dto.version, - 'questions': dto.questions.length, - }.asFirebaseMap); - } - - static crashlyticsError({ - Object? e, - StackTrace? s, - String? message, - Map? data, - }) => - _crashlytics.recordError( - e, - s, - reason: message, - information: data?.asFirebaseMap.entries.toList() ?? [], - ); - - static Future deeplinkError( - Uri uri, { - Map? data, - String? message, - }) { - return _analytics.logEvent( - name: 'deeplink_error', - parameters: { - 'uri': uri.toString(), - if (message != null) 'message': message, - if (data != null) ...data, - }.asFirebaseMap, - ); - } -} - -extension on Map { - Map get asFirebaseMap => (Map.from(this) - ..removeWhere((k, v) => v == null)) - .map((k, v) => MapEntry(k, (v is String || v is num) ? v : v.toString())); -} diff --git a/mnemo_cards/lib/features/card_flipper/flip_card.dart b/mnemo_cards/lib/features/card_flipper/flip_card.dart deleted file mode 100644 index 9b5a87e..0000000 --- a/mnemo_cards/lib/features/card_flipper/flip_card.dart +++ /dev/null @@ -1,142 +0,0 @@ -import 'dart:async'; - -import 'package:flutter/material.dart'; -import 'flip_side.dart'; -import 'flip_card_controllers.dart'; -import 'dart:math'; - -/// [FlipCard] A component that provides a flip card animation - -class FlipCard extends StatefulWidget { - /// [controller] used to ccontrol the flip - final FlipCardController controller; - - ///[frontWidget] The Front side widget of the card - final Widget frontWidget; - - ///[backWidget] The Back side widget of the card - final Widget backWidget; - - /// [onTapFlipping] When enabled, the card will flip automatically when touched. - final bool onTapFlipping; - - /// [axis] The flip axis [Horizontal] and [Vertical] - final FlipAxis axis; - - /// [rotateSide] The card rotate side - final RotateSide rotateSide; - - /// [animationDuration] The amount of milliseconds a turn animation will take. - final Duration animationDuration; - - /// [disableSplashEffect] The option for disable Inkwell widget's splash effect. - final bool disableSplashEffect; - - /// [splashColor] The option for Inkwell widget's splashColor. - final Color? splashColor; - - /// [focusColor] The option for Inkwell widget's focusColor. - final Color? focusColor; - - const FlipCard({ - Key? key, - this.focusColor, - this.splashColor, - this.onTapFlipping = false, - this.disableSplashEffect = false, - required this.frontWidget, - required this.backWidget, - required this.controller, - this.axis = FlipAxis.vertical, - required this.rotateSide, - this.animationDuration = const Duration(milliseconds: 800), - }) : super(key: key); - - @override - FlipCardState createState() => FlipCardState(); -} - -class FlipCardState extends State with TickerProviderStateMixin { - late AnimationController animationController; - double anglePlus = 0; - late bool _isFront; - StreamSubscription? _sub; - - @override - void initState() { - super.initState(); - _isFront = widget.controller.isFront; - animationController = - AnimationController(duration: widget.animationDuration, vsync: this); - if (!_isFront) { - animationController.value = 1.0; - anglePlus = pi; - } - _sub ??= widget.controller.asStream.distinct().listen((isFront) async { - if (this._isFront != isFront) { - if (animationController.isAnimating) return; - this._isFront = isFront; - await animationController - .forward(from: 0) - .then((value) => anglePlus = pi); - } - }); - } - - @override - void dispose() { - animationController.dispose(); - _sub?.cancel(); - _sub = null; - super.dispose(); - } - - @override - Widget build(BuildContext context) => AnimatedBuilder( - animation: animationController, - builder: (context, child) { - double piValue = 0.0; - if (widget.rotateSide == RotateSide.top || - widget.rotateSide == RotateSide.left) { - piValue = pi; - } else { - piValue = -pi; - } - print('animation controller ${animationController.value}'); - double angle = animationController.value * piValue; - late Matrix4 transform; - late Matrix4 transformForBack; - if (_isFront) angle += anglePlus; - if (widget.axis == FlipAxis.horizontal) { - transform = Matrix4.identity() - ..setEntry(3, 2, 0.001) - ..rotateX(angle); - transformForBack = Matrix4.identity()..rotateX(pi); - } else { - transform = Matrix4.identity() - ..setEntry(3, 2, 0.001) - ..rotateY(angle); - transformForBack = Matrix4.identity()..rotateY(pi); - } - - final isFrontWidget = _isFrontWidget(angle.abs()); - - return Transform( - alignment: Alignment.center, - transform: transform, - child: isFrontWidget - ? widget.frontWidget - : Transform( - transform: transformForBack, - alignment: Alignment.center, - child: widget.backWidget, - ), - ); - }); - - bool _isFrontWidget(double angle) { - const degrees90 = pi / 2; - const degrees270 = 3 * pi / 2; - return angle <= degrees90 || angle >= degrees270; - } -} diff --git a/mnemo_cards/lib/features/card_flipper/flip_card_controllers.dart b/mnemo_cards/lib/features/card_flipper/flip_card_controllers.dart deleted file mode 100644 index a0e53c2..0000000 --- a/mnemo_cards/lib/features/card_flipper/flip_card_controllers.dart +++ /dev/null @@ -1,23 +0,0 @@ -import 'dart:async'; - -import 'package:rxdart/rxdart.dart'; - - -///This controller used to call Fliping -class FlipCardController { - final StreamController _controller = StreamController.broadcast(); - bool isFront = true; - - FlipCardController(); - - /// Flip the card - Future flipcard() async { - isFront = !isFront; - _controller.add(isFront); - } - - bool get state => isFront; - - Stream get asStream => - _controller.stream.asBroadcastStream().startWith(state); -} diff --git a/mnemo_cards/lib/features/card_flipper/flip_side.dart b/mnemo_cards/lib/features/card_flipper/flip_side.dart deleted file mode 100644 index 66dcde9..0000000 --- a/mnemo_cards/lib/features/card_flipper/flip_side.dart +++ /dev/null @@ -1,13 +0,0 @@ -/// [FlipAxis] The flip axis [Horizontal] and [Vertical] -enum FlipAxis { - horizontal, - vertical, -} - -/// [rotateSide] The card rotate side -enum RotateSide { - right, - left, - top, - bottom, -} diff --git a/mnemo_cards/lib/features/chat/chat_page.dart b/mnemo_cards/lib/features/chat/chat_page.dart deleted file mode 100644 index db09995..0000000 --- a/mnemo_cards/lib/features/chat/chat_page.dart +++ /dev/null @@ -1,28 +0,0 @@ -import 'package:auto_route/auto_route.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_screenutil/flutter_screenutil.dart'; -import 'package:mnemo_cards/features/games/game_button.dart'; -import 'package:mnemo_cards_common/mnemo_cards_common.dart'; -import 'package:mnemo_cards_frontend_common/mnemo_cards_frontend_common.dart'; - -import '../../di/locator.dart'; -import '../analytics/analytics.dart'; - -@RoutePage() -class ChatPage extends StatelessWidget { - @override - Widget build(BuildContext context) { - Analytics.chatPageOpened(locator.userManager.userStateHolder.user); - final theme = Theme.of(context).textTheme; - return Scaffold( - body: SafeArea( - child: Padding( - padding: const EdgeInsets.all(8.0), - child: Center( - child: Text('Chat Page'), - )), - ), - ); - } -} diff --git a/mnemo_cards/lib/features/deeplinks/deeplinks_manager.dart b/mnemo_cards/lib/features/deeplinks/deeplinks_manager.dart deleted file mode 100644 index 29df710..0000000 --- a/mnemo_cards/lib/features/deeplinks/deeplinks_manager.dart +++ /dev/null @@ -1,5 +0,0 @@ -abstract interface class DeeplinkHandler { - bool canHandle(Uri uri); - - void handle(Uri uri); -} diff --git a/mnemo_cards/lib/features/deeplinks/deeplinks_manager_impl.dart b/mnemo_cards/lib/features/deeplinks/deeplinks_manager_impl.dart deleted file mode 100644 index c25e46a..0000000 --- a/mnemo_cards/lib/features/deeplinks/deeplinks_manager_impl.dart +++ /dev/null @@ -1,51 +0,0 @@ -import 'dart:async'; -import 'dart:developer'; - -import 'package:app_links/app_links.dart'; -import 'package:mnemo_cards/features/analytics/analytics.dart'; - -import 'deeplinks_manager.dart'; - -class DeeplinkManager implements DeeplinkHandler { - final AppLinks _appLinks; - final List _handlers; - - StreamSubscription? _subscription; - - DeeplinkManager( - this._appLinks, - this._handlers, - ); - - Future init() async { - _subscription ??= _appLinks.uriLinkStream.listen(_handleDeeplink); - } - - Future dispose() async { - await _subscription?.cancel(); - _subscription = null; - } - - @override - bool canHandle(Uri uri) { - for (final handler in _handlers) { - if (handler.canHandle(uri)) { - return true; - } - } - return false; - } - - @override - void handle(Uri uri) => _handleDeeplink(uri); - - void _handleDeeplink(Uri uri) { - for (final handler in _handlers) { - if (handler.canHandle(uri)) { - return handler.handle(uri); - } - } - log('Deeplink not handled! ${uri}'); - Analytics.deeplinkError(uri); - } -} diff --git a/mnemo_cards/lib/features/games/funny_letters/funny_letters_settings.dart b/mnemo_cards/lib/features/games/funny_letters/funny_letters_settings.dart deleted file mode 100644 index 4ee3b16..0000000 --- a/mnemo_cards/lib/features/games/funny_letters/funny_letters_settings.dart +++ /dev/null @@ -1,84 +0,0 @@ -// import 'package:flutter/material.dart'; -// // import 'package:funny_letters/funny_letters.dart'; -// -// import '../../../di/locator.dart'; -// import '../../../main.dart'; -// import '../../../widgets/choose_cards.dart'; -// -// class FunnyLettersSettingsImpl implements FunnyLettersSettings { -// final ThemeData _themeData; -// final ValueGetter _contextGetter; -// Map? _backgrounds; -// Map? _wordsWithTranslations; -// -// FunnyLettersSettingsImpl( -// this._themeData, -// this._contextGetter, -// ); -// -// Future init({String? packId}) async { -// final packCacheManager = locator.packCacheManager; -// final packs = packId == null -// ? await packCacheManager.loadAllPacks() -// : [await packCacheManager.loadPackFromCache(packId)]; -// _wordsWithTranslations = Map.fromEntries( -// packs.expand( -// (p) => p.cards -// .where((c) => c.original != null && c.translation != null) -// .map((c) => MapEntry(c.original!, c.translation!)), -// ), -// ); -// -// _backgrounds = Map.fromEntries( -// packs -// .expand( -// (p) => p.cards.map( -// (c) => MapEntry( -// c.original, -// packCacheManager.getPackImageFile(p.id, c.id).path, -// ), -// ), -// ) -// .where((e) => e.key != null), -// ).cast(); -// } -// -// @override -// Map get backgrounds => _backgrounds!; -// -// @override -// bool get musicEnabled => globalSharedPreferences.getBool('sound_on') ?? true; -// -// @override -// bool get soundEnabled => globalSharedPreferences.getBool('sound_on') ?? true; -// -// @override -// Map get wordsWithTranslations => _wordsWithTranslations!; -// -// @override -// FunnyLettersThemeData get themeData => FunnyLettersThemeData( -// brightness: _themeData.brightness, -// ); -// -// @override -// Future> updateWordsWithTranslations() async { -// await showDialog( -// context: _contextGetter(), -// builder: (context) => FutureBuilder( -// future: locator.packCacheManager.loadAllPacks(), -// builder: (context, packs) { -// if (!packs.hasData) { -// return Center( -// child: CircularProgressIndicator(), -// ); -// } -// return ChooseCards(packs.requireData); -// }, -// ), -// ); -// return {}; -// } -// -// @override -// Map toJson() => {}; -// } diff --git a/mnemo_cards/lib/features/games/game_assets_loader.dart b/mnemo_cards/lib/features/games/game_assets_loader.dart deleted file mode 100644 index c66bb88..0000000 --- a/mnemo_cards/lib/features/games/game_assets_loader.dart +++ /dev/null @@ -1,24 +0,0 @@ -import 'package:flutter_tts/flutter_tts.dart'; -import 'package:universal_io/io.dart'; - -// import 'package:funny_letters/main.dart'; - -import '../../managers/audio_player.dart'; -import 'games_manager.dart'; - -class AssetLoaderImpl { - final gameId; - final GamesManager _gamesManager; - - AssetLoaderImpl(this.gameId, this._gamesManager); - - @override - File loadFile(String path) { - return _gamesManager.getGameFile(gameId, path); - } - - @override - Future playWord(String word, {String? lang}) async { - AudioPlayer.playAudio(word, lang: lang); - } -} diff --git a/mnemo_cards/lib/features/games/game_button.dart b/mnemo_cards/lib/features/games/game_button.dart deleted file mode 100644 index e5946a5..0000000 --- a/mnemo_cards/lib/features/games/game_button.dart +++ /dev/null @@ -1,168 +0,0 @@ -import 'dart:convert'; - -import 'package:auto_route/auto_route.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_screenutil/flutter_screenutil.dart'; -// import 'package:funny_letters/funny_letters.dart'; -import 'package:mnemo_cards_common/mnemo_cards_common.dart'; -import 'package:mnemo_cards/utils/string_helper.dart'; - -import '../../di/locator.dart'; -// import 'funny_letters/funny_letters_settings.dart'; -import 'game_assets_loader.dart'; -import 'payloads/payloads.dart'; - -class GameButton extends StatelessWidget { - final double cardHeight; - final GameDto gameDto; - - const GameButton( - this.gameDto, - this.cardHeight, - ); - - @override - Widget build(BuildContext context) { - final theme = Theme.of(context); - - return Material( - child: Hero( - tag: 'game_${gameDto.id}', - child: GestureDetector( - key: ValueKey(gameDto.hashCode), - onTap: () => _openGame(context), - child: Container( - margin: EdgeInsets.all(4.0.h), - alignment: Alignment.center, - height: cardHeight, - decoration: BoxDecoration( - color: gameDto.color?.asColor?.withOpacity(0.0), - border: Border.all( - color: gameDto.color?.asColor?.withOpacity(0.9) ?? - Colors.grey.withOpacity(0.5), - width: 1, - ), - borderRadius: BorderRadius.circular(12.0), - ), - clipBehavior: Clip.antiAliasWithSaveLayer, - child: Row( - mainAxisSize: MainAxisSize.max, - children: [ - Container( - decoration: BoxDecoration( - image: gameDto.imageBase64 == null - ? null - : DecorationImage( - image: locator.imagesHolder - .get('game_${gameDto.id}') ?? - MemoryImage(base64Decode(gameDto.imageBase64!)), - ), - borderRadius: BorderRadius.circular(11), - ), - width: cardHeight - 2.h, - height: cardHeight - 2.h, - ), - SizedBox( - width: 4.w, - ), - Expanded( - child: Padding( - padding: const EdgeInsets.all(8.0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - FittedBox( - fit: BoxFit.scaleDown, - child: Text( - gameDto.title, - style: TextStyle( - fontWeight: FontWeight.w700, - fontSize: 24.sp, - height: 0.9, - ), - ), - ), - if (gameDto.subtitle.isNotEmpty) - FittedBox( - fit: BoxFit.scaleDown, - child: Text( - gameDto.subtitle, - style: TextStyle( - fontWeight: FontWeight.w300, - fontSize: 16.sp, - ), - ), - ), - IconButton( - onPressed: () { - locator.gamesManager.loadAssets('funny_letters'); - }, - icon: Icon( - Icons.download, - ), - ), - ], - ), - ), - ), - ], - ), - ), - ), - ), - ); - } - - void _openGame(BuildContext context) async { - // Create bridge controller - final bridgeController = MnemoCardsBridgeWebViewController(); - - // Load game assets if needed - await locator.gamesManager.loadAssets(gameDto.id); - - AutoRouter.of(context).pushWidget( - Hero( - tag: 'game_${gameDto.id}', - flightShuttleBuilder: - (flightContext, animation, direction, fromContext, toContext) { - return Material( - child: AnimatedBuilder( - builder: (c, child) => Opacity( - opacity: direction == HeroFlightDirection.pop - ? 1.0 - animation.value - : animation.value, - child: child!, - ), - animation: animation, - child: toContext.widget, - ), - ); - }, - child: MnemoCardsBridgeWebView( - controller: bridgeController, - initialUrl: 'http://localhost:8080', // TODO: Replace with actual game URL - title: gameDto.title, - ), - ), - ); - } - - Widget _gameWrapper(Widget child) => Container( - alignment: Alignment.center, - height: cardHeight, - decoration: BoxDecoration( - color: gameDto.color?.asColor?.withOpacity(0.0), - border: Border.all( - color: gameDto.color?.asColor?.withOpacity(0.9) ?? - Colors.grey.withOpacity(0.5), - width: 1, - ), - borderRadius: BorderRadius.circular(12.0), - ), - clipBehavior: Clip.none, - child: ClipRRect( - borderRadius: BorderRadius.circular(12.0), - child: child, - ), - ); -} diff --git a/mnemo_cards/lib/features/games/games_api.dart b/mnemo_cards/lib/features/games/games_api.dart deleted file mode 100644 index 31b8084..0000000 --- a/mnemo_cards/lib/features/games/games_api.dart +++ /dev/null @@ -1,29 +0,0 @@ -import 'dart:typed_data'; - -import 'package:dio/dio.dart'; -import 'package:mnemo_cards_common/mnemo_cards_common.dart'; - -import '../../managers/repository/api.dart'; - -class GamesApi with Api { - final Dio _dio; - - GamesApi(this._dio); - - Future getGameAssets(String gameId) async { - final r = await _dio.get( - '$path/games/$gameId/assets', - options: Options( - responseType: ResponseType.bytes, - ), - ); - return r.data as Uint8List; - } - - Future> getGamesList() async { - final r = await _dio.get( - '$path/games/list', - ); - return r.data!.decodeList(GameDto.fromJson); - } -} diff --git a/mnemo_cards/lib/features/games/games_bloc.dart b/mnemo_cards/lib/features/games/games_bloc.dart deleted file mode 100644 index 6963621..0000000 --- a/mnemo_cards/lib/features/games/games_bloc.dart +++ /dev/null @@ -1,45 +0,0 @@ -import 'package:bloc/bloc.dart'; -import 'package:mnemo_cards_common/mnemo_cards_common.dart'; - -import 'games_repository.dart'; - -class GamesCubit extends Cubit { - final GamesRepository gamesRepository; - - GamesCubit(this.gamesRepository) : super(GamesLoading()); - - Future loadGames() async { - print('Load games'); - try { - emit(GamesLoading()); - final games = await gamesRepository.updateAvailableGames(); - emit(GamesLoaded(games, null)); - } catch (e) { - emit(GamesError(e.toString())); - } - } - - void setActiveGame(GameDto game) { - if (state is GamesLoaded) { - final loadedState = state as GamesLoaded; - emit(GamesLoaded(loadedState.games, game)); - } - } -} - -abstract interface class GamesState {} - -class GamesLoading implements GamesState {} - -class GamesError implements GamesState { - String error; - - GamesError(this.error); -} - -class GamesLoaded implements GamesState { - final List games; - final GameDto? activeGame; - - GamesLoaded(this.games, this.activeGame); -} diff --git a/mnemo_cards/lib/features/games/games_manager.dart b/mnemo_cards/lib/features/games/games_manager.dart deleted file mode 100644 index 73226ae..0000000 --- a/mnemo_cards/lib/features/games/games_manager.dart +++ /dev/null @@ -1,38 +0,0 @@ -import 'dart:developer'; -import 'package:mnemo_cards/features/games/games_repository.dart'; -import 'package:universal_io/io.dart'; - -import 'package:flutter/foundation.dart'; -import 'package:path_provider/path_provider.dart'; - -import 'games_api.dart'; - -class GamesManager { - late final String? _docsDirectory; - - final GamesRepository _gamesRepository; - - GamesManager(this._gamesRepository); - - Future init() async { - _gamesRepository.init(); - _docsDirectory = - kIsWeb ? null : (await getApplicationDocumentsDirectory()).path; - } - - File getGameFile(String gameId, String path) { - // if (path.contains('')) { - // return File(path.replaceAll('', '')); - // } - final realFile = File(path); - if (realFile.existsSync()) { - return realFile; - } - final dir = _gameDirectory(gameId); - return File('${dir.path}/$path'); - } - - Future loadAssets(String id) => _gamesRepository.loadAssets(id); - - Directory _gameDirectory(String id) => Directory('$_docsDirectory/games/$id'); -} diff --git a/mnemo_cards/lib/features/games/games_page.dart b/mnemo_cards/lib/features/games/games_page.dart deleted file mode 100644 index 2c5ded9..0000000 --- a/mnemo_cards/lib/features/games/games_page.dart +++ /dev/null @@ -1,65 +0,0 @@ -import 'package:auto_route/auto_route.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:flutter_screenutil/flutter_screenutil.dart'; -import 'package:mnemo_cards/features/games/game_button.dart'; -import 'package:mnemo_cards/features/games/games_repository.dart'; -import 'package:mnemo_cards_common/mnemo_cards_common.dart'; - -import '../../di/injector.dart'; -import '../../di/locator.dart'; -import '../../widgets/choose_cards.dart'; -import '../analytics/analytics.dart'; -import 'games_bloc.dart'; - -@RoutePage() -class GamesPage extends StatelessWidget { - @override - Widget build(BuildContext context) { - Analytics.gamesPageOpened(locator.userManager.userStateHolder.user); - final theme = Theme.of(context); - final cubit = GamesCubit(getIt()); - return Scaffold( - body: SafeArea( - child: Padding( - padding: const EdgeInsets.all(8.0), - child: RefreshIndicator( - onRefresh: () => cubit.loadGames(), - backgroundColor: theme.colorScheme.primary, - displacement: 20.h, - color: Colors.black, - child: BlocBuilder( - bloc: cubit..loadGames(), - builder: (context, state) { - if (state is GamesLoaded) - return ListView( - children: [ - GameButton( - GameDto( - id: 'id', - title: 'title', - subtitle: 'subtitle', - color: '0xff0000ff', - version: 'version', - imageBase64: null, - ), - 180.h, - ), - ], - ); - else - return Center( - child: (state is GamesError) - ? Text('Не получилось загрузить игры') - : (state is GamesLoading) - ? CircularProgressIndicator() - : SizedBox(), - ); - }, - ), - ), - ), - ), - ); - } -} diff --git a/mnemo_cards/lib/features/games/games_repository.dart b/mnemo_cards/lib/features/games/games_repository.dart deleted file mode 100644 index 54c055c..0000000 --- a/mnemo_cards/lib/features/games/games_repository.dart +++ /dev/null @@ -1,79 +0,0 @@ -import 'dart:developer'; -import 'dart:io'; -import 'dart:typed_data'; - -import 'package:flutter/foundation.dart'; -import 'package:mnemo_cards/features/games/games_api.dart'; -import 'package:mnemo_cards_common/mnemo_cards_common.dart'; -import 'package:package_info_plus/package_info_plus.dart'; -import 'package:path_provider/path_provider.dart'; -import 'package:shared_preferences/shared_preferences.dart'; - -import '../../managers/repository/dio_provider.dart'; -import '../../utils/archive_decoder.dart'; - -class GamesRepository { - final SharedPreferences sharedPreferences; - final GamesApi _api; - - late final String? _docsDirectory; - - GamesRepository(this.sharedPreferences, this._api); - - Future init() async { - _docsDirectory = - kIsWeb ? null : (await getApplicationDocumentsDirectory()).path; - } - - Future> updateAvailableGames() async { - final games = await _api.getGamesList(); - return games; - } - - Future updateGameCache(String gameId) async { - final cache = _api.getGameAssets(gameId); - } - - Future loadAssets(String gameId) async { - try { - final data = await _api.getGameAssets(gameId); - await saveGameAssets(gameId, data); - } catch (e, s) { - log('Failed to load game $gameId', error: e, stackTrace: s); - } - } - - Future saveGameAssets(String gameId, Uint8List data) async { - log('Saving game $gameId'); - if (kIsWeb) { - log('Not saving game in web $gameId'); - return; - } - final dir = _gameDirectory(gameId); - final assetsDir = Directory('${dir.path}/assets'); - if (assetsDir.existsSync()) { - assetsDir.deleteSync(recursive: true); - } - await assetsDir.create(recursive: true); - final appVersion = - (await PackageInfo.fromPlatform(baseUrl: versionUrl)).version; - final assets = - await ArchiveDecoder().decodeArchive(data, gameId, appVersion); - if (assets == null) { - log('Failed to decode archive'); - return; - } - for (final entry in assets.entries) { - if (entry.value.isEmpty) { - continue; - } - final file = File('${assetsDir.path}/${entry.key}'); - await file.create(recursive: true); - await file.writeAsBytes(entry.value); - log('Saved ${entry.key} -> ${file.path}'); - } - log('Saved ${gameId} to ${assetsDir.path}'); - } - - Directory _gameDirectory(String id) => Directory('$_docsDirectory/games/$id'); -} diff --git a/mnemo_cards/lib/features/games/payloads/INTEGRATION_GUIDE.md b/mnemo_cards/lib/features/games/payloads/INTEGRATION_GUIDE.md deleted file mode 100644 index 36319d0..0000000 --- a/mnemo_cards/lib/features/games/payloads/INTEGRATION_GUIDE.md +++ /dev/null @@ -1,252 +0,0 @@ -# Руководство по интеграции Payloads System - -## ✅ Что было реализовано - -Система payloads для mnemo_cards успешно интегрирована с использованием существующих payloads из `payloads_shared`: - -### 📦 Используемые Payloads -- `PingPayload` / `PingPayload.toPong()` - базовая коммуникация -- `GetUserInfoPayload` / `UserInfoResponsePayload` - информация о пользователе -- `UserCardsRequestPayload` / `UserCardsPayload` - пользовательские карточки - -### 🔧 Handlers -- `PingHandler` - обработка ping/pong -- `UserInfoHandler` - обработка запросов информации о пользователе -- `UserCardsHandler` - обработка запросов карточек - -### 🌉 Bridge Components -- `MnemoCardsBridgeWebViewController` - контроллер WebView с bridge -- `MnemoCardsBridgeWebView` - виджет WebView с bridge функциональностью - -## 🚀 Как использовать - -### 1. Базовое использование - -```dart -import 'package:mnemo_cards/features/games/payloads/payloads.dart'; - -// Создание контроллера -final bridgeController = MnemoCardsBridgeWebViewController(); - -// Инициализация -PayloadHandlersManager.initialize(); - -// Использование в WebView -MnemoCardsBridgeWebView( - controller: bridgeController, - initialUrl: 'http://your-game-url.com', - title: 'Game Title', -) -``` - -### 2. Отправка данных в игру - -```dart -// Отправка карточек -final cards = [ - GameCard( - id: 1, - mnemo: 'apple', - original: 'apple', - translation: 'яблоко', - transcription: 'ˈæpəl', - ) -]; -await bridgeController.sendUserCards(cards); - -// Отправка информации о пользователе -await bridgeController.sendUserInfo({ - 'userId': '12345', - 'username': 'user', - 'isPremium': true, -}); -``` - -### 3. Обработка входящих запросов - -Система автоматически обрабатывает входящие payloads через handlers: - -- `UserCardsRequestPayload` → `UserCardsHandler` → `UserCardsPayload` -- `GetUserInfoPayload` → `UserInfoHandler` → `UserInfoResponsePayload` -- `PingPayload` → `PingHandler` → `PingPayload.toPong()` - -## 🔧 Интеграция с существующим кодом - -### Обновление GameButton - -```dart -// В game_button.dart -void _openGame(BuildContext context) async { - final bridgeController = MnemoCardsBridgeWebViewController(); - - AutoRouter.of(context).pushWidget( - MnemoCardsBridgeWebView( - controller: bridgeController, - initialUrl: 'http://your-game-url.com', - title: gameDto.title, - ), - ); -} -``` - -### Интеграция с системой карточек - -```dart -// В UserCardsHandler -Future> _getUserCards(UserCardsRequestPayload payload) async { - // TODO: Интегрировать с существующей системой карточек - // Пример интеграции: - // final cardsRepository = locator.cardsRepository; - // final cards = await cardsRepository.getCards(packIds: payload.packIds); - // return cards.map((card) => GameCard.fromCard(card)).toList(); -} -``` - -### Интеграция с системой пользователей - -```dart -// В UserInfoHandler уже интегрировано с locator.userManager -final user = locator.userManager.userStateHolder.user; -// Возвращает данные пользователя в формате payloads_shared -``` - -## 🧪 Тестирование - -### Демо страница - -Используйте `PayloadsDemoPage` для тестирования: - -```dart -AutoRouter.of(context).push(const PayloadsDemoPageRoute()); -``` - -### Логирование - -Система включает подробное логирование: - -```dart -// Включение debug логов -debugPrint('📥 [Bridge] Получен payload: ${payload.runtimeType}'); -debugPrint('📤 [Bridge] Отправка payload: ${payload.runtimeType}'); -``` - -## 🔄 Добавление новых payloads - -### 1. Добавьте payload в payloads_shared (если это общий payload) - -```dart -// В games/packages/payloads_shared/lib/src/payloads/ -@CopyWith() -@JsonSerializable() -class MyCustomPayload extends BridgePayload { - final String data; - - MyCustomPayload({required this.data}); - - @override - String get type => 'my_custom'; - - @override - Map toJson() => _$MyCustomPayloadToJson(this); - - factory MyCustomPayload.fromJson(Map json) => - _$MyCustomPayloadFromJson(json); -} -``` - -### 2. Создайте handler - -```dart -// В mnemo_cards/lib/features/games/payloads/handlers/ -class MyCustomHandler implements PayloadHandler { - @override - Future handle(BridgePayload payload) async { - if (payload is MyCustomPayload) { - // Обработка payload - return MyCustomResponsePayload(success: true); - } - return null; - } -} -``` - -### 3. Зарегистрируйте в PayloadHandlersManager - -```dart -// В payload_handlers_manager.dart -static final List _handlers = [ - // ... существующие handlers - MyCustomHandler(), -]; -``` - -### 4. Зарегистрируйте payload - -```dart -// В registration.dart -PayloadRegistry.register('my_custom', (json) => MyCustomPayload.fromJson(json)); -``` - -### 5. Сгенерируйте код - -```bash -flutter packages pub run build_runner build -``` - -## 🎮 Интеграция с веб-играми - -### В веб-игре (JavaScript) - -```javascript -// Отправка запроса карточек -window.webAppBridge.sendMessage({ - type: 'user_cards_request_payload', - data: { - pack_ids: ['basic', 'advanced'] - } -}); - -// Получение ответа -window.dartHandler = function(message) { - const payload = JSON.parse(message); - if (payload.type === 'user_cards_payload') { - console.log('Received cards:', payload.data.cards); - } -}; -``` - -## 🔒 Безопасность - -- Все payloads типизированы и валидируются -- Изоляция payloads между приложениями -- Безопасная WebView коммуникация -- Обработка ошибок и исключений - -## 📊 Мониторинг и отладка - -### Логи - -Система логирует все операции: - -``` -🔄 [MnemoCardsBridgeWebViewController] Установка WebView контроллера -📥 [MnemoCardsBridgeWebViewController] Получен payload: UserCardsRequestPayload -📤 [MnemoCardsBridgeWebViewController] Отправка payload: UserCardsPayload -``` - -### Отладка - -1. **Проблемы с WebView**: Проверьте JavaScript и bridge script -2. **Проблемы с payloads**: Проверьте регистрацию в PayloadRegistry -3. **Проблемы с коммуникацией**: Проверьте URL и логи bridge системы - -## ✅ Готово к использованию - -Система payloads полностью интегрирована и готова к использованию в mnemo_cards. Все необходимые компоненты созданы и протестированы. - -### Следующие шаги: - -1. Интегрировать с существующей системой карточек -2. Добавить дополнительные payloads по необходимости -3. Протестировать с реальными веб-играми -4. Добавить аналитику и мониторинг \ No newline at end of file diff --git a/mnemo_cards/lib/features/games/payloads/README.md b/mnemo_cards/lib/features/games/payloads/README.md deleted file mode 100644 index 7845f5b..0000000 --- a/mnemo_cards/lib/features/games/payloads/README.md +++ /dev/null @@ -1,232 +0,0 @@ -# Payloads System для mnemo_cards - -Система безопасной коммуникации между мобильным приложением mnemo_cards и веб-играми через WebView. - -## 🏗️ Архитектура - -Система использует payloads из пакета `payloads_shared` и состоит из следующих компонентов: - -### 📦 Payloads (Типизированные сообщения) -- **Shared Payloads** - все payloads из `payloads_shared`: - - `PingPayload` / `PingPayload.toPong()` - ping/pong коммуникация - - `GetUserInfoPayload` / `UserInfoResponsePayload` - информация о пользователе - - `UserCardsRequestPayload` / `UserCardsPayload` - пользовательские карточки - -### 🔧 Handlers (Обработчики) -- **PingHandler** - обработка ping/pong запросов -- **UserInfoHandler** - обработка запросов информации о пользователе -- **UserCardsHandler** - обработка запросов пользовательских карточек - -### 🌉 Bridge (Мост) -- **MnemoCardsBridgeWebViewController** - контроллер WebView с поддержкой bridge -- **MnemoCardsBridgeWebView** - виджет WebView с bridge функциональностью - -## 🚀 Быстрый старт - -### 1. Инициализация - -```dart -import 'package:mnemo_cards/features/games/payloads/payloads.dart'; - -// Создание контроллера -final bridgeController = MnemoCardsBridgeWebViewController(); - -// Инициализация handlers -PayloadHandlersManager.initialize(); -``` - -### 2. Использование в WebView - -```dart -MnemoCardsBridgeWebView( - controller: bridgeController, - initialUrl: 'http://your-game-url.com', - title: 'Game Title', -) -``` - -### 3. Отправка payloads - -```dart -// Отправка пользовательских карточек -final cards = [ - GameCard( - id: 1, - mnemo: 'apple', - original: 'apple', - translation: 'яблоко', - transcription: 'ˈæpəl', - ) -]; -await bridgeController.sendUserCards(cards); - -// Отправка информации о пользователе -await bridgeController.sendUserInfo({ - 'userId': '12345', - 'username': 'user', - 'isPremium': true, -}); - -// Отправка ping -final pingPayload = PingPayload(message: 'Hello!'); -await bridgeController.sendPayload(pingPayload); -``` - -## 📋 Доступные Payloads - -Все payloads из `payloads_shared`: - -- `PingPayload` / `PingPayload.toPong()` - ping/pong коммуникация -- `GetUserInfoPayload` / `UserInfoResponsePayload` - информация о пользователе -- `UserCardsRequestPayload` / `UserCardsPayload` - пользовательские карточки - -## 🔧 Создание новых Handlers - -### 1. Создайте handler - -```dart -class MyCustomHandler implements PayloadHandler { - @override - Future handle(BridgePayload payload) async { - if (payload is MyCustomPayload) { - // Обработка payload - return MyCustomResponsePayload(success: true); - } - return null; - } -} -``` - -### 2. Зарегистрируйте в PayloadHandlersManager - -```dart -// В payload_handlers_manager.dart -static final List _handlers = [ - // ... существующие handlers - MyCustomHandler(), -]; -``` - -### 3. Зарегистрируйте payload в registration.dart - -```dart -// В registration.dart -PayloadRegistry.register('my_custom', (json) => MyCustomPayload.fromJson(json)); -``` - -## 🎮 Интеграция с играми - -### В веб-игре (JavaScript) - -```javascript -// Отправка payload в mnemo_cards -window.webAppBridge.sendMessage({ - type: 'user_cards_request_payload', - data: { - pack_ids: ['basic', 'advanced'] - } -}); - -// Получение ответа -window.dartHandler = function(message) { - const payload = JSON.parse(message); - if (payload.type === 'user_cards_payload') { - console.log('Received cards:', payload.data.cards); - } -}; -``` - -### В mnemo_cards (Dart) - -```dart -// Обработка входящих payloads автоматически через handlers -// Отправка данных в игру -final cards = [GameCard(...)]; -await bridgeController.sendUserCards(cards); -``` - -## 🔒 Безопасность - -- Все payloads типизированы и валидируются -- Изоляция payloads между приложениями -- Безопасная WebView коммуникация -- Обработка ошибок и исключений - -## 📊 Мониторинг - -Система включает подробное логирование: - -```dart -// Включение debug логов -debugPrint('📥 [Bridge] Получен payload: ${payload.runtimeType}'); -debugPrint('📤 [Bridge] Отправка payload: ${payload.runtimeType}'); -``` - -## 🧪 Тестирование - -Для тестирования используйте `PayloadsDemoPage`: - -```dart -// Переход к демо странице -AutoRouter.of(context).push(const PayloadsDemoPageRoute()); -``` - -## 📝 Примеры использования - -### Получение карточек пользователя - -```dart -// В веб-игре -window.webAppBridge.sendMessage({ - type: 'user_cards_request_payload', - data: { - pack_ids: ['basic'] - } -}); - -// В mnemo_cards (автоматически через UserCardsHandler) -// Возвращает UserCardsPayload с карточками -``` - -### Получение информации о пользователе - -```dart -// В веб-игре -window.webAppBridge.sendMessage({ - type: 'get_user_info', - data: { - fields: ['userId', 'username', 'isPremium'] - } -}); - -// В mnemo_cards (автоматически через UserInfoHandler) -// Возвращает UserInfoResponsePayload с данными пользователя -``` - -## 🔄 Обновления - -При добавлении новых payloads: - -1. Добавьте payload в `payloads_shared` (если это общий payload) -2. Создайте handler -3. Зарегистрируйте в PayloadHandlersManager -4. Зарегистрируйте в registration.dart -5. Сгенерируйте код: `flutter packages pub run build_runner build` -6. Обновите документацию - -## 🐛 Отладка - -### Проблемы с WebView -- Проверьте, что JavaScript включен -- Убедитесь, что bridge script загружен -- Проверьте логи в консоли - -### Проблемы с payloads -- Проверьте регистрацию payload в PayloadRegistry -- Убедитесь, что handler зарегистрирован -- Проверьте типы payloads - -### Проблемы с коммуникацией -- Проверьте URL веб-игры -- Убедитесь, что WebView загрузился -- Проверьте логи bridge системы \ No newline at end of file diff --git a/mnemo_cards/lib/features/games/payloads/bridge_webview.dart b/mnemo_cards/lib/features/games/payloads/bridge_webview.dart deleted file mode 100644 index 77cf5da..0000000 --- a/mnemo_cards/lib/features/games/payloads/bridge_webview.dart +++ /dev/null @@ -1,73 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:webview_flutter/webview_flutter.dart'; -import 'bridge_webview_controller.dart'; - -/// Flutter widget that wraps WebView with bridge functionality for mnemo_cards -class MnemoCardsBridgeWebView extends StatefulWidget { - final MnemoCardsBridgeWebViewController controller; - final String initialUrl; - final String? title; - final bool safeArea; - - const MnemoCardsBridgeWebView({ - super.key, - required this.controller, - required this.initialUrl, - this.title, - this.safeArea = false, - }); - - @override - State createState() => _MnemoCardsBridgeWebViewState(); -} - -class _MnemoCardsBridgeWebViewState extends State { - @override - void initState() { - super.initState(); - // Load initial URL - widget.controller.loadUrl(widget.initialUrl); - } - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: widget.title != null - ? AppBar( - title: Text(widget.title!), - backgroundColor: Theme.of(context).colorScheme.inversePrimary, - ) - : null, - body: SafeArea( - child: ListenableBuilder( - listenable: widget.controller, - builder: (context, child) { - late final WebViewController webViewController; - - webViewController = WebViewController() - ..setJavaScriptMode(JavaScriptMode.unrestricted) - ..setBackgroundColor(Colors.white) - ..setNavigationDelegate( - NavigationDelegate( - onPageStarted: (url) { - debugPrint('WebView load started: $url'); - }, - onPageFinished: (url) { - debugPrint('WebView load finished: $url'); - // Set WebView controller after page is loaded - widget.controller.setWebViewController(webViewController); - }, - onWebResourceError: (error) { - debugPrint('WebView load error: ${error.description}'); - }, - ), - ) - ..loadRequest(Uri.parse(widget.initialUrl)); - - return WebViewWidget(controller: webViewController); - }, - ), - ), - ); - } -} \ No newline at end of file diff --git a/mnemo_cards/lib/features/games/payloads/bridge_webview_controller.dart b/mnemo_cards/lib/features/games/payloads/bridge_webview_controller.dart deleted file mode 100644 index c34cd5a..0000000 --- a/mnemo_cards/lib/features/games/payloads/bridge_webview_controller.dart +++ /dev/null @@ -1,119 +0,0 @@ -import 'dart:developer'; -import 'package:flutter/material.dart'; -import 'package:webview_flutter/webview_flutter.dart'; -import 'package:bridge_core/bridge_core.dart'; -import 'package:payloads_shared/payloads_shared.dart'; -import 'package:mnemo_cards/features/games/payloads/handlers/payload_handlers_manager.dart'; - -/// Controller for managing WebView and bridge communication in mnemo_cards -class MnemoCardsBridgeWebViewController extends ChangeNotifier { - WebViewController? _webViewController; - bool _isWebViewReady = false; - BridgeManager? _bridgeManager; - - WebViewController? get webViewController => _webViewController; - bool get isWebViewReady => _isWebViewReady; - - /// Set the WebView controller - void setWebViewController(WebViewController controller) { - debugPrint('🔄 [MnemoCardsBridgeWebViewController] Установка WebView контроллера, инициализация bridge...'); - _webViewController = controller; - _isWebViewReady = true; - - // Initialize bridge manager - _initializeBridgeManager(); - - notifyListeners(); - } - - void _initializeBridgeManager() { - if (_webViewController == null) return; - - // Initialize payload handlers - PayloadHandlersManager.initialize(); - - // Create bridge manager using factory - _bridgeManager = BridgeManagerFactory.createHostManager( - evaluateJavaScript: (script) => _webViewController!.runJavaScript(script), - addJavaScriptHandler: (name, callback) => _webViewController!.addJavaScriptChannel( - name, - onMessageReceived: (message) => callback([message.message]), - ), - ); - - // Set up payload received callback - _bridgeManager!.onPayloadReceived = (payload) { - debugPrint('📥 [MnemoCardsBridgeWebViewController] Получен payload: ${payload.runtimeType}'); - _handlePayload(payload); - }; - - // Initialize bridge manager - _bridgeManager!.initialize(); - } - - Future _handlePayload(BridgePayload payload) async { - try { - final response = await PayloadHandlersManager.processPayload(payload); - if (response != null) { - _sendPayload(response); - } - } catch (e) { - debugPrint('❌ [MnemoCardsBridgeWebViewController] Error handling payload: $e'); - } - } - - void _sendPayload(BridgePayload payload) { - if (_bridgeManager != null) { - _bridgeManager!.sendPayload(payload); - } - } - - /// Load a URL in the WebView - Future loadUrl(String url) async { - if (_webViewController != null) { - debugPrint('🔄 [MnemoCardsBridgeWebViewController] Загрузка URL: $url'); - - await _webViewController!.loadRequest(Uri.parse(url)); - - // Wait a bit for page to load, then initialize bridge - Future.delayed(const Duration(milliseconds: 500), () { - if (_isWebViewReady) { - debugPrint('🔄 [MnemoCardsBridgeWebViewController] Инициализация bridge после загрузки страницы'); - _initializeBridgeManager(); - } - }); - } - } - - /// Send a payload to the web application - Future sendPayload(BridgePayload payload) async { - if (_bridgeManager != null) { - _bridgeManager!.sendPayload(payload); - } - } - - /// High-level API - send user cards - Future sendUserCards(List cards) async { - final payload = UserCardsPayload(gameCards: cards); - await sendPayload(payload); - } - - /// High-level API - send user info - Future sendUserInfo(Map userInfo) async { - final payload = UserInfoResponsePayload( - userInfo: userInfo, - success: true, - ); - await sendPayload(payload); - } - - /// Dispose resources - @override - void dispose() { - _webViewController = null; - _isWebViewReady = false; - _bridgeManager?.dispose(); - _bridgeManager = null; - super.dispose(); - } -} \ No newline at end of file diff --git a/mnemo_cards/lib/features/games/payloads/handlers/payload_handlers_manager.dart b/mnemo_cards/lib/features/games/payloads/handlers/payload_handlers_manager.dart deleted file mode 100644 index dfd7763..0000000 --- a/mnemo_cards/lib/features/games/payloads/handlers/payload_handlers_manager.dart +++ /dev/null @@ -1,109 +0,0 @@ -import 'package:bridge_core/bridge_core.dart'; -import 'package:payloads_shared/payloads_shared.dart'; -import 'package:mnemo_cards/features/games/payloads/registration.dart'; -import 'package:mnemo_cards/di/locator.dart'; -import 'user_cards_handler.dart'; - -/// Manager for all payload handlers in mnemo_cards -class PayloadHandlersManager { - static final List _handlers = [ - // Shared handlers - PingHandler(), - UserInfoHandler(), - - // Mnemo cards specific handlers - UserCardsHandler(), - ]; - - /// Get all registered handlers - static List get handlers => _handlers; - - /// Process a payload through all handlers - static Future processPayload(BridgePayload payload) async { - for (final handler in _handlers) { - try { - final response = await handler.handle(payload); - if (response != null) { - return response; - } - } catch (e) { - print('Error processing payload with handler ${handler.runtimeType}: $e'); - } - } - return null; - } - - /// Initialize all handlers - static void initialize() { - // Register all payload types - registerMnemoCardsPayloads(); - - print('Payload handlers manager initialized with ${_handlers.length} handlers'); - } -} - -/// Handler for ping payloads (shared) -class PingHandler implements PayloadHandler { - @override - Future handle(BridgePayload payload) async { - if (payload is PingPayload) { - await Future.delayed(const Duration(seconds: 1)); - return payload.toPong(); - } - return null; - } -} - -/// Handler for user info requests (shared) -class UserInfoHandler implements PayloadHandler { - @override - Future handle(BridgePayload payload) async { - if (payload is GetUserInfoPayload) { - try { - // Get user from locator - final user = locator.userManager.userStateHolder.user; - - // Check if user exists - if (user == null) { - return UserInfoResponsePayload( - userInfo: {}, - success: false, - error: 'User not found', - ); - } - - // Create profile data - final profileData = { - 'userId': user.id, - 'username': user.name, - 'email': user.email, - 'isAdmin': user.admin, - 'isPremium': user.subscription ?? false, - 'packs': user.packs, - 'purchases': user.purchases, - 'subscriptionFeatures': user.subscriptionFeatures.map((e) => e.name).toList(), - }; - - // Filter requested fields - final filteredProfile = {}; - for (final field in payload.fields) { - if (profileData.containsKey(field)) { - filteredProfile[field] = profileData[field]; - } - } - - return UserInfoResponsePayload( - userInfo: filteredProfile, - success: true, - ); - } catch (e) { - return UserInfoResponsePayload( - userInfo: {}, - success: false, - error: e.toString(), - ); - } - } - return null; - } -} \ No newline at end of file diff --git a/mnemo_cards/lib/features/games/payloads/handlers/user_cards_handler.dart b/mnemo_cards/lib/features/games/payloads/handlers/user_cards_handler.dart deleted file mode 100644 index e362ffd..0000000 --- a/mnemo_cards/lib/features/games/payloads/handlers/user_cards_handler.dart +++ /dev/null @@ -1,53 +0,0 @@ -import 'package:bridge_core/bridge_core.dart'; -import 'package:payloads_shared/payloads_shared.dart'; -import 'package:mnemo_cards/di/locator.dart'; - -/// Handler for user cards requests -class UserCardsHandler implements PayloadHandler { - @override - Future handle(BridgePayload payload) async { - if (payload is UserCardsRequestPayload) { - try { - // Get user cards from the app's data source - final cards = await _getUserCards(payload); - - return UserCardsPayload( - gameCards: cards, - ); - } catch (e) { - // В случае ошибки возвращаем пустой список карточек - return UserCardsPayload( - gameCards: [], - ); - } - } - return null; - } - - Future> _getUserCards(UserCardsRequestPayload payload) async { - // TODO: Implement actual card retrieval logic - // This should integrate with your existing card management system - - // Mock implementation for now - final mockCards = [ - GameCard( - id: 1, - mnemo: 'apple', - original: 'apple', - translation: 'яблоко', - transcription: 'ˈæpəl', - transcriptionMnemo: 'эпл', - ), - GameCard( - id: 2, - mnemo: 'house', - original: 'house', - translation: 'дом', - transcription: 'haʊs', - transcriptionMnemo: 'хаус', - ), - ]; - - return mockCards; - } -} \ No newline at end of file diff --git a/mnemo_cards/lib/features/games/payloads/integration_example.dart b/mnemo_cards/lib/features/games/payloads/integration_example.dart deleted file mode 100644 index 63792db..0000000 --- a/mnemo_cards/lib/features/games/payloads/integration_example.dart +++ /dev/null @@ -1,180 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:auto_route/auto_route.dart'; -import 'package:payloads_shared/payloads_shared.dart'; -import 'package:mnemo_cards/features/games/payloads/payloads.dart'; -import 'package:mnemo_cards/di/locator.dart'; - -/// Пример интеграции payloads системы в существующий код mnemo_cards -class PayloadsIntegrationExample { - - /// Пример интеграции в существующую игру - static Widget createGameWithPayloads(String gameId, String gameUrl) { - final bridgeController = MnemoCardsBridgeWebViewController(); - - // Инициализация payload handlers - PayloadHandlersManager.initialize(); - - return MnemoCardsBridgeWebView( - controller: bridgeController, - initialUrl: gameUrl, - title: 'Game: $gameId', - ); - } - - /// Пример отправки данных в игру при загрузке - static Future sendInitialDataToGame( - MnemoCardsBridgeWebViewController controller, - ) async { - try { - // Отправляем информацию о пользователе - final user = locator.userManager.userStateHolder.user; - if (user != null) { - await controller.sendUserInfo({ - 'userId': user.id?.toString(), - 'username': user.name, - 'email': user.email, - 'isPremium': user.subscription ?? false, - 'packs': user.packs, - }); - } - - } catch (e) { - debugPrint('Error sending initial data to game: $e'); - } - } - - /// Пример получения карточек для игры - static Future> getUserCardsForGame( - List packIds, - ) async { - // TODO: Интегрировать с существующей системой карточек - // Это пример, который нужно адаптировать под вашу архитектуру - - final mockCards = [ - GameCard( - id: 1, - mnemo: 'apple', - original: 'apple', - translation: 'яблоко', - transcription: 'ˈæpəl', - transcriptionMnemo: 'эпл', - ), - GameCard( - id: 2, - mnemo: 'house', - original: 'house', - translation: 'дом', - transcription: 'haʊs', - transcriptionMnemo: 'хаус', - ), - ]; - - return mockCards; - } - - /// Пример отправки карточек в игру - static Future sendCardsToGame( - MnemoCardsBridgeWebViewController controller, - List cards, - ) async { - await controller.sendUserCards(cards); - } -} - -/// Пример использования в существующем коде -class GameWithPayloadsPage extends StatefulWidget { - final String gameId; - final String gameUrl; - - const GameWithPayloadsPage({ - super.key, - required this.gameId, - required this.gameUrl, - }); - - @override - State createState() => _GameWithPayloadsPageState(); -} - -class _GameWithPayloadsPageState extends State { - late MnemoCardsBridgeWebViewController _bridgeController; - bool _isDataSent = false; - - @override - void initState() { - super.initState(); - _bridgeController = MnemoCardsBridgeWebViewController(); - - // Инициализация payload handlers - PayloadHandlersManager.initialize(); - - // Слушаем готовность bridge - _bridgeController.addListener(_onBridgeStateChanged); - } - - void _onBridgeStateChanged() { - if (_bridgeController.isWebViewReady && !_isDataSent) { - _sendInitialData(); - } - } - - Future _sendInitialData() async { - await PayloadsIntegrationExample.sendInitialDataToGame(_bridgeController); - setState(() { - _isDataSent = true; - }); - } - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - title: Text('Game: ${widget.gameId}'), - backgroundColor: Theme.of(context).colorScheme.inversePrimary, - actions: [ - if (_isDataSent) - const Icon(Icons.check_circle, color: Colors.green) - else - const SizedBox( - width: 20, - height: 20, - child: CircularProgressIndicator(strokeWidth: 2), - ), - ], - ), - body: MnemoCardsBridgeWebView( - controller: _bridgeController, - initialUrl: widget.gameUrl, - title: 'Game: ${widget.gameId}', - ), - ); - } - - @override - void dispose() { - _bridgeController.removeListener(_onBridgeStateChanged); - _bridgeController.dispose(); - super.dispose(); - } -} - -/// Пример маршрута для игры с payloads -@RoutePage() -class GameWithPayloadsRoute extends StatelessWidget { - final String gameId; - final String gameUrl; - - const GameWithPayloadsRoute({ - super.key, - required this.gameId, - required this.gameUrl, - }); - - @override - Widget build(BuildContext context) { - return GameWithPayloadsPage( - gameId: gameId, - gameUrl: gameUrl, - ); - } -} \ No newline at end of file diff --git a/mnemo_cards/lib/features/games/payloads/payloads.dart b/mnemo_cards/lib/features/games/payloads/payloads.dart deleted file mode 100644 index 5547a8b..0000000 --- a/mnemo_cards/lib/features/games/payloads/payloads.dart +++ /dev/null @@ -1,6 +0,0 @@ -// Export all payloads and handlers -export 'registration.dart'; -export 'handlers/payload_handlers_manager.dart'; -export 'handlers/user_cards_handler.dart'; -export 'bridge_webview_controller.dart'; -export 'bridge_webview.dart'; \ No newline at end of file diff --git a/mnemo_cards/lib/features/games/payloads/registration.dart b/mnemo_cards/lib/features/games/payloads/registration.dart deleted file mode 100644 index af9cc73..0000000 --- a/mnemo_cards/lib/features/games/payloads/registration.dart +++ /dev/null @@ -1,11 +0,0 @@ -import 'package:bridge_core/bridge_core.dart'; -import 'package:payloads_shared/payloads_shared.dart'; - -/// Register all mnemo_cards payload types -void registerMnemoCardsPayloads() { - // Register shared payloads (включает все необходимые payloads) - registerSharedPayloads(); - - // Дополнительные payloads можно добавить здесь, если понадобятся - // PayloadRegistry.register('custom_payload', (json) => CustomPayload.fromJson(json)); -} \ No newline at end of file diff --git a/mnemo_cards/lib/features/games/payloads_demo_page.dart b/mnemo_cards/lib/features/games/payloads_demo_page.dart deleted file mode 100644 index deaf090..0000000 --- a/mnemo_cards/lib/features/games/payloads_demo_page.dart +++ /dev/null @@ -1,222 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:auto_route/auto_route.dart'; -import 'package:payloads_shared/payloads_shared.dart'; -import 'payloads/payloads.dart'; - -@RoutePage() -class PayloadsDemoPage extends StatefulWidget { - const PayloadsDemoPage({super.key}); - - @override - State createState() => _PayloadsDemoPageState(); -} - -class _PayloadsDemoPageState extends State { - late MnemoCardsBridgeWebViewController _bridgeController; - final List _logs = []; - - @override - void initState() { - super.initState(); - _bridgeController = MnemoCardsBridgeWebViewController(); - - // Initialize payload handlers - PayloadHandlersManager.initialize(); - - // Add listener for bridge events - _bridgeController.addListener(() { - if (_bridgeController.isWebViewReady) { - _addLog('Bridge ready'); - } - }); - } - - void _addLog(String message) { - setState(() { - _logs.insert(0, '${DateTime.now().toString().substring(11, 19)}: $message'); - if (_logs.length > 20) { - _logs.removeLast(); - } - }); - } - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - title: const Text('Payloads Demo'), - backgroundColor: Theme.of(context).colorScheme.inversePrimary, - ), - body: Column( - children: [ - // Bridge WebView - Expanded( - flex: 2, - child: MnemoCardsBridgeWebView( - controller: _bridgeController, - initialUrl: 'http://localhost:8080', // TODO: Replace with actual demo URL - title: 'Bridge Demo', - ), - ), - - // Controls - Container( - padding: const EdgeInsets.all(16), - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - const Text( - 'Bridge Controls', - style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold), - ), - const SizedBox(height: 8), - Row( - children: [ - Expanded( - child: ElevatedButton( - onPressed: _sendPing, - child: const Text('Send Ping'), - ), - ), - const SizedBox(width: 8), - Expanded( - child: ElevatedButton( - onPressed: _sendUserCards, - child: const Text('Send Cards'), - ), - ), - ], - ), - const SizedBox(height: 8), - Row( - children: [ - Expanded( - child: ElevatedButton( - onPressed: _sendUserInfo, - child: const Text('Send User Info'), - ), - ), - const SizedBox(width: 8), - Expanded( - child: ElevatedButton( - onPressed: _sendUserCardsRequest, - child: const Text('Request Cards'), - ), - ), - ], - ), - ], - ), - ), - - // Logs - Container( - height: 150, - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - color: Colors.grey[100], - border: Border(top: BorderSide(color: Colors.grey[300]!)), - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text( - 'Bridge Logs', - style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold), - ), - const SizedBox(height: 8), - Expanded( - child: ListView.builder( - itemCount: _logs.length, - itemBuilder: (context, index) { - return Padding( - padding: const EdgeInsets.symmetric(vertical: 2), - child: Text( - _logs[index], - style: const TextStyle(fontSize: 12, fontFamily: 'monospace'), - ), - ); - }, - ), - ), - ], - ), - ), - ], - ), - ); - } - - void _sendPing() async { - try { - final pingPayload = PingPayload(message: 'Hello from mnemo_cards!'); - await _bridgeController.sendPayload(pingPayload); - _addLog('Sent ping payload'); - } catch (e) { - _addLog('Error sending ping: $e'); - } - } - - void _sendUserCards() async { - try { - final mockCards = [ - GameCard( - id: 1, - mnemo: 'apple', - original: 'apple', - translation: 'яблоко', - transcription: 'ˈæpəl', - transcriptionMnemo: 'эпл', - ), - GameCard( - id: 2, - mnemo: 'house', - original: 'house', - translation: 'дом', - transcription: 'haʊs', - transcriptionMnemo: 'хаус', - ), - ]; - - await _bridgeController.sendUserCards(mockCards); - _addLog('Sent user cards payload'); - } catch (e) { - _addLog('Error sending user cards: $e'); - } - } - - void _sendUserInfo() async { - try { - final mockUserInfo = { - 'userId': '12345', - 'username': 'demo_user', - 'email': 'demo@example.com', - 'isPremium': true, - 'packs': ['basic', 'advanced'], - }; - - await _bridgeController.sendUserInfo(mockUserInfo); - _addLog('Sent user info payload'); - } catch (e) { - _addLog('Error sending user info: $e'); - } - } - - void _sendUserCardsRequest() async { - try { - final requestPayload = UserCardsRequestPayload( - packIds: ['basic', 'advanced'], - ); - await _bridgeController.sendPayload(requestPayload); - _addLog('Sent user cards request'); - } catch (e) { - _addLog('Error sending user cards request: $e'); - } - } - - @override - void dispose() { - _bridgeController.dispose(); - super.dispose(); - } -} \ No newline at end of file diff --git a/mnemo_cards/lib/features/packs/active_pack.dart b/mnemo_cards/lib/features/packs/active_pack.dart deleted file mode 100644 index 37e5e5f..0000000 --- a/mnemo_cards/lib/features/packs/active_pack.dart +++ /dev/null @@ -1,2 +0,0 @@ -export 'active_pack_cubit.dart'; -export 'active_pack_state.dart'; \ No newline at end of file diff --git a/mnemo_cards/lib/features/packs/active_pack_cubit.dart b/mnemo_cards/lib/features/packs/active_pack_cubit.dart deleted file mode 100644 index 7880d99..0000000 --- a/mnemo_cards/lib/features/packs/active_pack_cubit.dart +++ /dev/null @@ -1,187 +0,0 @@ -import 'dart:async'; -import 'dart:developer'; - -import 'package:copy_with_extension/copy_with_extension.dart'; -import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:mnemo_cards_common/mnemo_cards_common.dart'; - -import '../../di/locator.dart'; -import 'active_pack_state.dart'; -import 'pack_cache_manager.dart'; -import 'packs_api.dart'; -import 'packs_holder.dart'; - -extension on GetCardPackResponse { - ActivePackCubitState asState() => ActivePackCubitState.withPack(this); -} - -/// Manages the state and operations for the currently active pack -class ActivePackCubit extends Cubit { - final PackCacheManager _cacheManager; - final PacksHolder _packsHolder; - final PacksApi _packsApi; - - StreamSubscription? _sub; - String? _activePackId; - - ActivePackCubit( - this._cacheManager, - this._packsHolder, - this._packsApi, - ) : super(null); - - /// Loads a pack and manages its state - Future loadPack(CardPackPreviewDto preview) async { - if (!_isValidPackId(preview.id)) { - _handleError('Invalid pack ID', preview); - return; - } - - _activePackId = preview.id; - emit(ActivePackCubitState.loading()); - - await _cancelCurrentSubscription(); - - try { - if (preview.isAvailable) { - await _loadAvailablePack(preview); - } else { - await _handleUnavailablePack(preview); - } - } catch (e, s) { - _handleError(e.toString(), preview, s); - } - } - - /// Cancels current operations and cleans up resources - Future cancelCurrentOperation() async { - await _cancelCurrentSubscription(); - _activePackId = null; - emit(null); - } - - @override - Future close() async { - await _cancelCurrentSubscription(); - super.close(); - } - - /// Loads an available pack from cache or fetches it if needed - Future _loadAvailablePack(CardPackPreviewDto preview) async { - try { - final pack = await _cacheManager.loadPackFromCache(preview.id); - _emitPackState(pack); - _setupPackSubscription(preview.id); - } catch (err) { - await _handleCacheError(preview, err); - } - } - - /// Handles loading of an unavailable pack - Future _handleUnavailablePack(CardPackPreviewDto preview) async { - try { - final buyDto = await _packsApi.getPackBuy(preview.id); - if (buyDto != null) { - _emitBuyState(buyDto); - _packsHolder.setBuyPack(buyDto); - } else { - await _fetchPack(preview); - } - } catch (e, s) { - _handleError(e.toString(), preview, s); - } - } - - /// Handles cache errors by attempting to fetch the pack - Future _handleCacheError( - CardPackPreviewDto packPreview, dynamic error) async { - final packId = packPreview.id; - log('Cache error for pack $packId', error: error); - emit(ActivePackCubitState.loading()); - - try { - final loadingState = _packsHolder.state[packId]; - if (loadingState is! CardPackLoadingDto) { - await locator.packUpdater.updatePackAndSaveImages(packId); - } - } catch (e, s) { - _handleError(e.toString(), packPreview, s); - } - } - - /// Fetches a pack from the server - Future _fetchPack(CardPackPreviewDto preview) async { - final packId = preview.id; - try { - final loadingState = _packsHolder.state[packId]; - if (loadingState is! CardPackLoadingDto) { - await locator.packUpdater.updatePackAndSaveImages(packId); - } - } catch (e, s) { - _handleError(e.toString(), preview, s); - } - } - - /// Handles errors and updates state accordingly - void _handleError( - String error, - CardPackPreviewDto preview, [ - StackTrace? stackTrace, - ]) { - log('Error in ActivePackCubit', error: error, stackTrace: stackTrace); - emit(ActivePackCubitState.error( - error, - CardPackLoadingDto.fromPreviewDto(preview).copyWith( - message: 'Не получается загрузить', - ), - )); - } - - /// Cancels the current subscription - Future _cancelCurrentSubscription() async { - await _sub?.cancel(); - _sub = null; - } - - /// Sets up subscription for pack updates - void _setupPackSubscription(String packId) { - _sub = _packsHolder.streamPack(packId).asyncMap((data) async { - if (data is CardPackDto) { - final pack = await _cacheManager.loadPackFromCache(packId); - _emitPackState(pack); - } else { - _emitState(data.asState()); - } - }).listen( - (_) {}, - onError: (error, stackTrace) => - _handleError(error.toString(), stackTrace), - ); - } - - /// Emits pack state if the pack ID matches - void _emitPackState(CardPackDto pack) { - if (pack.id == _activePackId) { - emit(ActivePackCubitState.withPack(pack)); - } - } - - /// Emits buy state if the pack ID matches - void _emitBuyState(CardPackBuyDto buyDto) { - if (buyDto.id == _activePackId) { - emit(ActivePackCubitState.withBuy(buyDto)); - } - } - - /// Emits state if the pack ID matches - void _emitState(ActivePackCubitState state) { - if (state.getCardPackResponse?.id == _activePackId) { - emit(state); - } - } - - /// Validates pack ID - bool _isValidPackId(String? packId) { - return packId != null && packId.isNotEmpty; - } -} diff --git a/mnemo_cards/lib/features/packs/active_pack_state.dart b/mnemo_cards/lib/features/packs/active_pack_state.dart deleted file mode 100644 index c21b431..0000000 --- a/mnemo_cards/lib/features/packs/active_pack_state.dart +++ /dev/null @@ -1,52 +0,0 @@ -import 'package:copy_with_extension/copy_with_extension.dart'; -import 'package:mnemo_cards_common/mnemo_cards_common.dart'; - -part 'active_pack_state.g.dart'; - -/// Represents the current state of the active pack -@CopyWith() -class ActivePackCubitState { - final GetCardPackResponse? getCardPackResponse; - final bool isLoading; - final String? error; - final bool isAvailable; - - const ActivePackCubitState({ - this.getCardPackResponse, - this.isLoading = false, - this.error, - this.isAvailable = true, - }); - - /// Creates a loading state - factory ActivePackCubitState.loading() { - return const ActivePackCubitState(isLoading: true); - } - - /// Creates an error state - factory ActivePackCubitState.error(String error, CardPackLoadingDto loading) { - return ActivePackCubitState( - getCardPackResponse: loading, - error: error, - isLoading: false, - ); - } - - /// Creates a state with pack data - factory ActivePackCubitState.withPack(GetCardPackResponse pack) { - return ActivePackCubitState( - getCardPackResponse: pack, - isLoading: false, - isAvailable: true, - ); - } - - /// Creates a state with buy data - factory ActivePackCubitState.withBuy(CardPackBuyDto buyDto) { - return ActivePackCubitState( - getCardPackResponse: buyDto, - isLoading: false, - isAvailable: false, - ); - } -} diff --git a/mnemo_cards/lib/features/packs/active_pack_state.g.dart b/mnemo_cards/lib/features/packs/active_pack_state.g.dart deleted file mode 100644 index 28a3a7e..0000000 --- a/mnemo_cards/lib/features/packs/active_pack_state.g.dart +++ /dev/null @@ -1,96 +0,0 @@ -// GENERATED CODE - DO NOT MODIFY BY HAND - -part of 'active_pack_state.dart'; - -// ************************************************************************** -// CopyWithGenerator -// ************************************************************************** - -abstract class _$ActivePackCubitStateCWProxy { - ActivePackCubitState getCardPackResponse( - GetCardPackResponse? getCardPackResponse); - - ActivePackCubitState isLoading(bool isLoading); - - ActivePackCubitState error(String? error); - - ActivePackCubitState isAvailable(bool isAvailable); - - /// This function **does support** nullification of nullable fields. All `null` values passed to `non-nullable` fields will be ignored. You can also use `ActivePackCubitState(...).copyWith.fieldName(...)` to override fields one at a time with nullification support. - /// - /// Usage - /// ```dart - /// ActivePackCubitState(...).copyWith(id: 12, name: "My name") - /// ```` - ActivePackCubitState call({ - GetCardPackResponse? getCardPackResponse, - bool? isLoading, - String? error, - bool? isAvailable, - }); -} - -/// Proxy class for `copyWith` functionality. This is a callable class and can be used as follows: `instanceOfActivePackCubitState.copyWith(...)`. Additionally contains functions for specific fields e.g. `instanceOfActivePackCubitState.copyWith.fieldName(...)` -class _$ActivePackCubitStateCWProxyImpl - implements _$ActivePackCubitStateCWProxy { - const _$ActivePackCubitStateCWProxyImpl(this._value); - - final ActivePackCubitState _value; - - @override - ActivePackCubitState getCardPackResponse( - GetCardPackResponse? getCardPackResponse) => - this(getCardPackResponse: getCardPackResponse); - - @override - ActivePackCubitState isLoading(bool isLoading) => this(isLoading: isLoading); - - @override - ActivePackCubitState error(String? error) => this(error: error); - - @override - ActivePackCubitState isAvailable(bool isAvailable) => - this(isAvailable: isAvailable); - - @override - - /// This function **does support** nullification of nullable fields. All `null` values passed to `non-nullable` fields will be ignored. You can also use `ActivePackCubitState(...).copyWith.fieldName(...)` to override fields one at a time with nullification support. - /// - /// Usage - /// ```dart - /// ActivePackCubitState(...).copyWith(id: 12, name: "My name") - /// ```` - ActivePackCubitState call({ - Object? getCardPackResponse = const $CopyWithPlaceholder(), - Object? isLoading = const $CopyWithPlaceholder(), - Object? error = const $CopyWithPlaceholder(), - Object? isAvailable = const $CopyWithPlaceholder(), - }) { - return ActivePackCubitState( - getCardPackResponse: getCardPackResponse == const $CopyWithPlaceholder() - ? _value.getCardPackResponse - // ignore: cast_nullable_to_non_nullable - : getCardPackResponse as GetCardPackResponse?, - isLoading: isLoading == const $CopyWithPlaceholder() || isLoading == null - ? _value.isLoading - // ignore: cast_nullable_to_non_nullable - : isLoading as bool, - error: error == const $CopyWithPlaceholder() - ? _value.error - // ignore: cast_nullable_to_non_nullable - : error as String?, - isAvailable: - isAvailable == const $CopyWithPlaceholder() || isAvailable == null - ? _value.isAvailable - // ignore: cast_nullable_to_non_nullable - : isAvailable as bool, - ); - } -} - -extension $ActivePackCubitStateCopyWith on ActivePackCubitState { - /// Returns a callable class that can be used as follows: `instanceOfActivePackCubitState.copyWith(...)` or like so:`instanceOfActivePackCubitState.copyWith.fieldName(...)`. - // ignore: library_private_types_in_public_api - _$ActivePackCubitStateCWProxy get copyWith => - _$ActivePackCubitStateCWProxyImpl(this); -} diff --git a/mnemo_cards/lib/features/packs/images_holder.dart b/mnemo_cards/lib/features/packs/images_holder.dart deleted file mode 100644 index f6f677a..0000000 --- a/mnemo_cards/lib/features/packs/images_holder.dart +++ /dev/null @@ -1,64 +0,0 @@ -import 'package:flutter/cupertino.dart'; -import 'package:mnemo_cards/di/locator.dart'; -import 'package:mnemo_cards_common/mnemo_cards_common.dart'; - -class ImagesHolder { - Map _images = {}; - Map _packImages = {}; - String? packId; - DateTime? unlockTime; - - ImagesHolder(); - - void setPackImages(Map images, - String packId, { - bool clear = true, - }) { - if (clear) { - _packImages.clear(); - } - _packImages.addAll(images); - this.packId = packId; - } - - void setImage(String key, MemoryImage image) { - _images[key] = image; - } - - void clear() { - _images.clear(); - _packImages.clear(); - packId = null; - } - - MemoryImage? get(String id) { - final memoryImage = getPackImage(id) ?? _images[id]; - - return memoryImage; - } - - MemoryImage? getPackImage(String id) { - final memoryImage = _packImages[id]; - return memoryImage; - } - - bool havePackImage(String id) => _packImages[id] != null; - - bool haveImage(String id) => _images[id] != null || havePackImage(id); -} - -extension ImagesHolderStringExt on String { - MemoryImage? get memoryImage => locator.imagesHolder.get(this); -} - -extension ImagesHolderCardExt on GameCardDto { - MemoryImage? get memoryImage => locator.imagesHolder.get(id.toString()); - - // MemoryImage? requireMemoryImage(String packId) { - // final image = locator.imagesHolder.get(id.toString()); - // if (image != null) { - // return image; - // } - // locator.packCacheManager.loadPackImage(packId, id); - // } -} diff --git a/mnemo_cards/lib/features/packs/pack_cache_manager.dart b/mnemo_cards/lib/features/packs/pack_cache_manager.dart deleted file mode 100644 index dc4bed2..0000000 --- a/mnemo_cards/lib/features/packs/pack_cache_manager.dart +++ /dev/null @@ -1,219 +0,0 @@ -import 'dart:async'; -import 'dart:convert'; -import 'dart:developer'; -import 'package:universal_io/io.dart'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/widgets.dart'; -import 'package:mnemo_cards_common/mnemo_cards_common.dart'; - -import 'package:path_provider/path_provider.dart'; -import 'package:shared_preferences/shared_preferences.dart'; - -import '../../di/locator.dart'; -import '../analytics/analytics.dart'; - -// persist -class PackCacheManager { - late final SharedPreferences _sharedPreferences; - late final String _cacheDirectory; - - PackCacheManager(); - - Future init() async { - _sharedPreferences = await SharedPreferences.getInstance(); - _cacheDirectory = (await getApplicationDocumentsDirectory()).path; - } - - Future isPackCached(String id) async { - try { - await loadPackFromCache(id, withCardImages: false); - } catch (e, s) { - return false; - } - return true; - } - - Future markPackForUpdate(String packId) async { - try { - final dir = _packDirectory(packId); - final file = File('${dir.path}/pack.json'); - if (file.existsSync()) { - final json = (await file.readAsString()).decode(); - json['id'] = '0'; - await file.writeAsString(jsonEncode(json)); - } - } catch (e, s) { - log('Cant mark pack for update', error: e, stackTrace: s); - Analytics.crashlyticsError( - e: e, - s: s, - message: 'Cant mark pack for update', - ); - } - } - - Future loadPackFromCache( - String packId, { - bool withCardImages = true, - bool clearCardImages = true, - }) async { - log('Loading from cache ${packId}'); - try { - final packDir = _packDirectory(packId); - final packFile = File('${packDir.path}/pack.json'); - if (!packFile.existsSync()) { - log('Pack file not exist'); - return throw Exception('Pack file not exist'); - } - var pack = packFile.readAsStringSync().decode(CardPackDto.fromJson); - if (withCardImages) { - Map images = {}; - log('Cards ${packId}: ${pack.cards.length}'); - if (pack.cards.isNotEmpty) { - log('Loading cards ${packId}'); - await Future.wait( - pack.cards.map((dto) async { - final image = await loadPackImage(packId, dto.id); - if (image != null) { - images[dto.id.toString()] = image; - } - }), - ); - } - log('Pack loaded ${packId}'); - locator.imagesHolder.setPackImages( - images, - packId, - clear: clearCardImages, - ); - } - return pack; - } catch (e, s) { - log('Cant load from cache ${packId} ${e} ${s}'); - deletePack(packId); - rethrow; - } - } - - Future> _updateSavedPacks() async { - if (kIsWeb) { - return []; - } - final packsDir = Directory('${_cacheDirectory}/packs'); - List savedPackIds = []; - if (packsDir.existsSync()) { - for (final packDir in packsDir.listSync()) { - if (File('${packDir.path}/pack.json').existsSync()) { - savedPackIds.add(packDir.path.split('/').last); - } - } - } - _sharedPreferences.setStringList('packs', savedPackIds); - return savedPackIds; - } - - Future loadPackImage(String packId, int id) async { - final file = getPackImageFile(packId, id); - if (await file.exists()) { - try { - final image = MemoryImage(await file.readAsBytes()); - // locator.imagesHolder.setImage(id.toString(), image); - return image; - } catch (e) { - markPackForUpdate(packId); - throw Exception('Cant read file $packId $e'); - } - } else { - log('Cant load card ${id} from $packId, skiping'); - } - return null; - } - - Future> loadAllPacks({bool withCardImages = false}) async { - final ids = await _updateSavedPacks(); - final List packs = []; - for (final id in ids) { - try { - final pack = await loadPackFromCache( - id, - withCardImages: withCardImages, - clearCardImages: false, - ); - packs.add(pack); - } catch (e) { - log('Pack $id doesnt exist anymore'); - } - } - return packs; - } - - Future deletePack(String packId) async { - try { - final dir = _packDirectory(packId); - dir.deleteSync(recursive: true); - } catch (e) { - log('Deletion failed $e'); - } - _updateSavedPacks(); - } - - Future loadPackFile(String packId, String path) async { - final bytes = getPackFile(packId, path).readAsBytes(); - return bytes; - } - - File getPackFile(String packId, String path) { - return File('${(_packDirectory(packId)).path}/$path'); - } - - File getPackImageFile(String packId, int id) { - return getPackFile(packId, 'images/$id'); - } - - Future clearCache() async { - final saved = await _updateSavedPacks(); - for (final p in saved) { - await deletePack(p); - } - await _sharedPreferences.remove('packs'); - } - - Future savePack( - CardPackDto dto, { - Map>? images, - }) async { - log('Saving pack ${dto.id}'); - final dir = _packDirectory(dto.id); - final json = dto.encode(); - log('Saving dto ${dto.id}'); - final file = File('${dir.path}/pack.json'); - await file.create(recursive: true); - await file.writeAsString(json); - - if (images != null) { - log('Saving card images ${dto.id}'); - final imageDir = Directory('${dir.path}/images'); - if (imageDir.existsSync()) { - imageDir.deleteSync(recursive: true); - } - for (final card in dto.cards) { - final bytes = images[card.id.toString()]; - if (bytes != null && bytes.isNotEmpty) { - File('${imageDir.path}/${card.id}') - ..createSync(recursive: true) - ..writeAsBytesSync(bytes); - } else { - Analytics.crashlyticsError( - message: 'Cant save image ${card.id} for ${dto.id} - no bytes!', - ); - } - } - } - - log('Saved ${dto.id}'); - } - - Directory _packDirectory(String id) => - Directory('$_cacheDirectory/packs/$id'); -} diff --git a/mnemo_cards/lib/features/packs/pack_manager.dart b/mnemo_cards/lib/features/packs/pack_manager.dart deleted file mode 100644 index 59104bb..0000000 --- a/mnemo_cards/lib/features/packs/pack_manager.dart +++ /dev/null @@ -1,46 +0,0 @@ -import 'dart:async'; - -import 'package:mnemo_cards/features/packs/pack_cache_manager.dart'; -import 'package:mnemo_cards/features/packs/preview_pack_holder.dart'; -import 'package:mnemo_cards_common/mnemo_cards_common.dart'; -import 'package:rxdart/rxdart.dart'; - -import '../../di/injector.dart'; -import '../../managers/repository/dio_provider.dart'; -import 'packs_holder.dart'; - -class PackManager { - final PacksHolder _packHolder; - final PreviewPackHolder _previewPackHolder; - final PackCacheManager _cacheManager; - - PackManager( - this._packHolder, - this._previewPackHolder, - this._cacheManager, - ); - - Future init() async { - final packs = await _cacheManager.loadAllPacks(); - _packHolder.setReady(packs); - } - - Future clearCache() async { - _packHolder.clear(); - getIt.get().cancelAll(); - await _cacheManager.clearCache(); - } - - Stream?> get packsPreviewStream => - _previewPackHolder.asStream - .map((event) => event?.previewPacks) - .whereNotNull() - .distinct((prev, next) { - // if (prev.length != next.length) return false; - // for (int i = 0; i < prev.length; i++) { - // if (prev[i] != next[i]) return false; - // } - // return true; - return false; - }); -} diff --git a/mnemo_cards/lib/features/packs/pack_updater.dart b/mnemo_cards/lib/features/packs/pack_updater.dart deleted file mode 100644 index 9ed149b..0000000 --- a/mnemo_cards/lib/features/packs/pack_updater.dart +++ /dev/null @@ -1,235 +0,0 @@ -import 'dart:async'; -import 'dart:developer'; - -import 'package:mnemo_cards/features/packs/preview_packs_poller.dart'; -import 'package:mnemo_cards/utils/archive_decoder.dart'; -import 'package:mnemo_cards_common/mnemo_cards_common.dart'; -import 'package:package_info_plus/package_info_plus.dart'; -import 'package:rxdart/rxdart.dart'; -import '../../managers/repository/dio_provider.dart'; -import '../analytics/analytics.dart'; -import 'pack_cache_manager.dart'; -import 'packs_api.dart'; -import 'packs_holder.dart'; -import 'preview_pack_holder.dart'; - -/// Updates cache and state holders for available packs -/// Does polling -class PackUpdater { - final PacksApi _packsApi; - final PackCacheManager _cacheManager; - final PreviewPackHolder _previewPackHolder; - final PacksHolder _packsHolder; - final PreviewPacksPoller _previewPacksPoller; - - final List _downloadQueue = []; - - Completer? _updateCompleter; - - PackUpdater( - this._packsApi, - this._cacheManager, - this._previewPackHolder, - this._packsHolder, - this._previewPacksPoller, - ); - - void clear() { - _previewPackHolder.clear(); - _packsHolder.clear(); - } - - Future init() async { - final pollStream = Stream.periodic(const Duration(seconds: 600)); - pollStream.startWith(0).listen((event) async { - await updateAvailablePacks(); - await _previewPacksPoller.poll(); - }); - } - - Future updateAvailablePacks() async { - if (_updateCompleter?.isCompleted ?? true) { - _updateCompleter = Completer(); - } - try { - print('Updating packs started'); - await _updateAvailablePacks(); - } catch (e, s) { - log('Error when updating packs', error: e, stackTrace: s); - print('Error when updating pack: ${e}'); - // Future.delayed(Duration(seconds: 5), () => updateAvailablePacks()); - } finally { - print('Updating packs complete'); - if (_updateCompleter?.isCompleted == false) { - _updateCompleter?.complete(); - } - } - return _updateCompleter!.future; - } - - Future _updateAvailablePacks() async { - final savedList = await _cacheManager.loadAllPacks(); - final packData = Map.fromEntries( - savedList.map( - (e) => MapEntry( - e.id.toString(), - e.version, - ), - ), - ); - _packsHolder.setReady(savedList); - // emit(PackUpdaterState.ready(savedList)); - final actions = await _packsApi.getPacksActions(packData); - Map updatedPacks = {}; - bool shouldUpdateHolder = false; - - // final downloadingPacks = PackUpdaterState.fromActions(actions); - // emit( - // PackUpdaterState( - // Map.fromEntries({ - // ...state.packStates.entries - // .where((e) => downloadingPacks.packStates[e.key] == null), - // ...downloadingPacks.packStates.entries, - // }), - // ), - // ); - - List futures = []; - for (final action in actions) { - switch (action.action) { - case PackAction.delete: - log('DELETE ${action.id}'); - shouldUpdateHolder = true; - futures.add( - () async { - await _cacheManager.deletePack(action.id); - savedList.removeWhere((p) => p.id == action.id); - // emit(state.updateState( - // action.id, PackUpdateState.status(PackStatus.notExist))); - }.call(), - ); - break; - case PackAction.update: - log('UPDATE ${action.id}'); - shouldUpdateHolder = true; - _downloadQueue.add(action.id); - // futures.add( - // () async { - // try { - // await _updatePackAndSaveImages(action.id); - // } catch (e) { - // log('Error while download cards for ${action.id} $e'); - // } - // }.call(), - // ); - break; - case PackAction.unknown: - log('Unknown action on update ${action.id}'); - break; - } - } - while (_downloadQueue.isNotEmpty) { - final id = _downloadQueue.removeAt(0); - try { - await _updatePackAndSaveImages( - id, - shouldUpdateHolder: shouldUpdateHolder, - ); - } catch (e) { - log('Error while download cards for ${id} $e'); - } - } - - //await Future.wait(futures); - if (shouldUpdateHolder) { - //todo Doesnt work - // Always updating holder - List packs = []; - for (final saved in savedList) { - if (updatedPacks[saved.id] != null) { - packs.add(updatedPacks[saved.id]!); - updatedPacks.remove(saved.id); - } else { - packs.add(saved); - } - } - packs.addAll(updatedPacks.values); - _packsHolder.setReady(packs); - } - } - - Future updatePackAndSaveImages( - String packId, { - bool shouldUpdateHolder = false, - }) { - _previewPacksPoller.poll(); - return _updatePackAndSaveImages( - packId, - shouldUpdateHolder: shouldUpdateHolder, - ); - } - - Future _updatePackAndSaveImages( - String packId, { - bool shouldUpdateHolder = false, - }) async { - if (_downloadQueue.contains(packId)) { - _downloadQueue.remove(packId); - } - if (_packsHolder.state[packId] is CardPackLoadingDto) { - log('Already downloading $packId'); - return; - } - final loadingDto = _previewPackHolder.state?.previewPacks - .firstWhereOrNull((p) => p.id == packId) - ?.let(CardPackLoadingDto.fromPreviewDto) ?? - CardPackLoadingDto.fromId(packId, message: 'Загружаем карточки...'); - try { - _packsHolder.setLoadingPack(loadingDto); - log('Updating with cards ${packId}', name: 'updatePackWithCards'); - final s = Stopwatch()..start(); - final packDto = await _packsApi.getPackDto(packId); - // emit(state.setProgress(packId, 1.0)); - print('get from api ${s.elapsedMilliseconds} mills'); - if (packDto == null) { - throw Exception('Cant update pack $packId'); - } - final imagesData = await _packsApi.packImagesArchive( - packId, - progressCallback: (count, total) { - _packsHolder.setLoadingPackProgress( - packId, - count.toDouble() / (total + 0.1), - ); - }, - ); - print('get cards from api ${s.elapsedMilliseconds} mills'); - _packsHolder.setLoadingPack( - loadingDto.copyWith(message: 'Обновляем данные...'), - ); - final appVersion = - (await PackageInfo.fromPlatform(baseUrl: versionUrl)).version; - final images = await ArchiveDecoder().decodeArchive( - imagesData, - packId, - appVersion, - ); - _packsHolder.setLoadingPack( - loadingDto.copyWith(message: 'Почти всё...'), - ); - await _cacheManager.savePack(packDto, images: images); - print('saved pack ${s.elapsedMilliseconds} mills'); - log('Pack ${packId} updated with cards'); - _packsHolder.setReady([packDto]); - } catch (e, s) { - log('Cant update pack', error: e, stackTrace: s); - Analytics.crashlyticsError( - message: 'Cant update pack', - e: e, - s: s, - ); - _packsHolder.removeIfLoading(packId); - rethrow; - } - } -} diff --git a/mnemo_cards/lib/features/packs/packs_api.dart b/mnemo_cards/lib/features/packs/packs_api.dart deleted file mode 100644 index 3c60529..0000000 --- a/mnemo_cards/lib/features/packs/packs_api.dart +++ /dev/null @@ -1,76 +0,0 @@ -import 'dart:typed_data'; - -import 'package:dio/dio.dart'; -import 'package:mnemo_cards/features/worker/worker_ext.dart'; -import 'package:mnemo_cards_common/mnemo_cards_common.dart'; - -import '../../di/locator.dart'; -import '../../managers/repository/api.dart'; - -class PacksApi with Api { - final Dio _dio; - - PacksApi(this._dio); - - // previews for the main page - Future> getPacksPreviews( - Map? packData, - ) async { - final r = await _dio.get( - '$path/packs/previews', - queryParameters: packData, - ); - final previews = - (r.data! as String).isolatedDecodeList(CardPackPreviewDto.fromJson); - return previews; - } - - // previews for the main page - Future> getPacksActions( - Map? packData, - ) async { - final r = await _dio.get( - '$path/packs/actions', - queryParameters: packData, - ); - final actions = - (r.data! as String).isolatedDecodeList(CardPackAction.fromJson); - return actions; - } - - // pack dto for available packs or null - Future getPackDto(String id) async { - final r = await _dio.get( - '$path/pack/$id', - ); - return (r.data as String).isolatedDecode(CardPackDto.fromJson); - } - - // buy page dto if not available - Future getPackBuy(String id) async { - final r = await _dio.get( - '$path/pack/buy/$id', - ); - return (r.data as String).isolatedDecode(CardPackBuyDto.fromJson); - } - - /// cards zip archive for available pack - /// unavailable packs transfer images by base64 - Future packImagesArchive( - String packId, { - ProgressCallback? progressCallback, - }) async { - final response = await _dio.get( - '$path/pack/cards/$packId', - options: Options( - responseType: ResponseType.bytes, - ), - onReceiveProgress: progressCallback, - ); - final data = response.data; - if (data == null) { - return Uint8List.fromList([]); - } - return data; - } -} diff --git a/mnemo_cards/lib/features/packs/packs_holder.dart b/mnemo_cards/lib/features/packs/packs_holder.dart deleted file mode 100644 index e9843bf..0000000 --- a/mnemo_cards/lib/features/packs/packs_holder.dart +++ /dev/null @@ -1,78 +0,0 @@ -import 'dart:async'; - -import 'package:copy_with_extension/copy_with_extension.dart'; -import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:mnemo_cards_common/mnemo_cards_common.dart'; -import 'package:rxdart/rxdart.dart'; - -class PacksHolder extends Cubit> { - PacksHolder() : super({}); - - void emitClone( - Map state, - ) => - emit(Map.from(state)); - - void setLoadingPack( - CardPackLoadingDto dto, - ) => - emitClone(state..[dto.id] = dto); - - void setLoadingPackProgress(String id, double progress) { - final dto = state[id]; - if (dto is CardPackLoadingDto) { - emitClone(state..[dto.id] = dto.copyWith(loadingProgress: progress)); - } - } - - DateTime _nextEmitTime = DateTime(1999); - Timer? timer; - - void emitThrottled({ - Duration duration = const Duration(milliseconds: 500), - }) async { - if (timer?.isActive == true) { - return; - } - final now = DateTime.now(); - if (now.isAfter(_nextEmitTime)) { - emitClone(state); - _nextEmitTime = now.add(duration); - return; - } - final diff = _nextEmitTime.difference(now).abs(); - timer = Timer(diff, () => emitClone(state)); - } - - void setBuyPack( - CardPackBuyDto dto, - ) => - emitClone(state..[dto.id] = dto); - - void removeIfLoading( - String id, - ) { - if (state[id] is CardPackLoadingDto) { - remove(id); - } - } - - void remove( - String id, - ) => - emitClone(state..remove(id)); - - void setReady(List savedList) => emitClone( - state - ..addEntries( - savedList.map((dto) => MapEntry(dto.id, dto)), - ), - ); - - void clear() { - emitClone({}); - } - - Stream streamPack(String id) => - stream.startWith(state).map((m) => m[id]).whereNotNull().distinct(); -} diff --git a/mnemo_cards/lib/features/packs/preview_pack_holder.dart b/mnemo_cards/lib/features/packs/preview_pack_holder.dart deleted file mode 100644 index ef1d4e2..0000000 --- a/mnemo_cards/lib/features/packs/preview_pack_holder.dart +++ /dev/null @@ -1,71 +0,0 @@ -import 'dart:async'; -import 'dart:convert'; -import 'dart:developer'; - -import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:mnemo_cards_common/mnemo_cards_common.dart'; - -import 'package:rxdart/rxdart.dart'; - -import '../../main.dart'; - -class PreviewPackHolder extends Cubit { - PreviewPackHolder() : super(null); - - Future init() async { - if (state == null) { - await loadFromCache(); - } - } - - Future loadFromCache() async { - final sp = globalSharedPreferences; - final previewPacksStrings = sp.getStringList('preview_packs'); - if (previewPacksStrings == null || previewPacksStrings.isEmpty) { - return; - } - final List previewPacks = []; - previewPacksStrings.forEach((string) { - try { - final pack = string.decode(CardPackPreviewDto.fromJson); - previewPacks.add(pack); - } catch (e, s) { - log('Cant load preview pack', error: e, stackTrace: s); - } - }); - setPreviewPacks(previewPacks); - } - - Future savePreviewPacks(PreviewPackState? state) async { - final packs = state?.previewPacks ?? []; - final stringsList = []; - packs.forEach((pack) { - try { - final string = jsonEncode(pack); - stringsList.add(string); - } catch (e, s) { - log('Cant load preview pack', error: e, stackTrace: s); - } - }); - final sp = globalSharedPreferences; - sp.setStringList('preview_packs', stringsList); - } - - void setPreviewPacks(List packs, {bool save = false}) { - final nextState = PreviewPackState(packs); - if (save) { - savePreviewPacks(nextState); - } - emit(nextState); - } - - void clear() => emit(null); - - Stream get asStream => stream.startWith(state); -} - -class PreviewPackState { - final List previewPacks; - - PreviewPackState(this.previewPacks); -} diff --git a/mnemo_cards/lib/features/packs/preview_packs_poller.dart b/mnemo_cards/lib/features/packs/preview_packs_poller.dart deleted file mode 100644 index 8d4d006..0000000 --- a/mnemo_cards/lib/features/packs/preview_packs_poller.dart +++ /dev/null @@ -1,38 +0,0 @@ -import 'dart:developer'; - -import 'package:mnemo_cards/features/packs/packs_api.dart'; - -import 'preview_pack_holder.dart'; - -class PreviewPacksPoller { - PacksApi _api; - PreviewPackHolder _previewPackHolder; - bool polling = false; - - PreviewPacksPoller(this._api, this._previewPackHolder); - - Future init() async { - Stream.periodic(Duration(seconds: 600), (_) async { - poll(); - }); - } - - Future poll({int retry = 0}) async { - if (!polling) { - try { - polling = true; - final r = await _api.getPacksPreviews(null); - _previewPackHolder.setPreviewPacks(r, save: true); - } catch (e, s) { - log('preview packs poller', error: e, stackTrace: s); - if (retry < 2) { - Future.delayed( - Duration(seconds: 2 * retry), - () => poll(retry: retry + 1), - ); - } - } - polling = false; - } - } -} diff --git a/mnemo_cards/lib/features/packs/web_pack_cache_manager.dart b/mnemo_cards/lib/features/packs/web_pack_cache_manager.dart deleted file mode 100644 index 8701151..0000000 --- a/mnemo_cards/lib/features/packs/web_pack_cache_manager.dart +++ /dev/null @@ -1,206 +0,0 @@ -import 'dart:async'; -import 'dart:convert'; -import 'dart:developer'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/widgets.dart'; -import 'package:mnemo_cards_common/mnemo_cards_common.dart'; - -import 'package:shared_preferences/shared_preferences.dart'; -import 'package:universal_io/io.dart'; - -import '../../di/locator.dart'; -import '../analytics/analytics.dart'; -import 'pack_cache_manager.dart'; - -// persist -class WebPackCacheManager implements PackCacheManager { - late final SharedPreferences _sharedPreferences; - late final String? _cacheDirectory; - - WebPackCacheManager(); - - Future init() async { - _sharedPreferences = await SharedPreferences.getInstance(); - } - - Future isPackCached(String id) async { - try { - await loadPackFromCache(id, withCardImages: false); - } catch (e, s) { - return false; - } - return true; - } - - Future markPackForUpdate(String packId) async { - try { - final cacheId = await _packCacheId(packId); - final jsonString = _sharedPreferences.getString(cacheId); - if (jsonString != null) { - final json = jsonString.decode(); - json['id'] = '0'; - await _sharedPreferences.setString(cacheId, jsonEncode(json)); - } - } catch (e, s) { - log('Cant mark pack for update', error: e, stackTrace: s); - Analytics.crashlyticsError( - e: e, - s: s, - message: 'Cant mark pack for update', - ); - } - } - - Future loadPackFromCache( - String packId, { - bool withCardImages = true, - bool clearCardImages = true, - }) async { - log('Loading from cache ${packId}'); - try { - final packCacheId = _packCacheId(packId); - final json = _sharedPreferences.getString(packCacheId); - if (json == null) { - log('Pack cache not exist'); - return throw Exception('Pack cache not exist'); - } - var pack = json.decode(CardPackDto.fromJson); - if (withCardImages) { - Map images = {}; - log('Cards ${packId}: ${pack.cards.length}'); - if (pack.cards.isNotEmpty) { - // log('Loading cards ${packId}'); - // await Future.wait( - // pack.cards.map((dto) async { - // final file = File('${packDir.path}/images/${dto.id}'); - // if (await file.exists()) { - // try { - // images[dto.id.toString()] = - // MemoryImage(await file.readAsBytes()); - // } catch (e) { - // markPackForUpdate(packId); - // throw Exception('Cant read file $packId $e'); - // } - // } else { - // log('Cant load card ${dto.id} from $packId, skiping'); - // } - // }), - // ); - } - log('Pack loaded ${packId}'); - locator.imagesHolder.setPackImages(images, packId); - } - return pack; - } catch (e, s) { - log('Cant load from cache ${packId} ${e} ${s}'); - deletePack(packId); - rethrow; - } - } - - Future> _updateSavedPacks() async { - if (kIsWeb) { - return []; - } - final packsDir = Directory('${_cacheDirectory}/packs'); - List savedPackIds = []; - if (packsDir.existsSync()) { - for (final packDir in packsDir.listSync()) { - if (File('${packDir.path}/pack.json').existsSync()) { - savedPackIds.add(packDir.path.split('/').last); - } - } - } - _sharedPreferences.setStringList('packs', savedPackIds); - return savedPackIds; - } - - Future> loadAllPacks({bool withCardImages = false}) async { - final ids = await _updateSavedPacks(); - final List packs = []; - for (final id in ids) { - try { - final pack = await loadPackFromCache( - id, - withCardImages: withCardImages, - ); - packs.add(pack); - } catch (e) { - log('Pack $id doesnt exist anymore'); - } - } - return packs; - } - - Future deletePack(String packId) async { - try { - final id = await _packCacheId(packId); - _sharedPreferences.remove(id); - // dir.deleteSync(recursive: true); - } catch (e) { - log('Deletion failed $e'); - } - _updateSavedPacks(); - } - - Future loadPackFile(String packId, String path) async { - // final bytes = - // File('${(await _packDirectory(packId)).path}/$path').readAsBytesSync(); - // return bytes; - return null; - } - - Future clearCache() async { - final saved = await _updateSavedPacks(); - for (final p in saved) { - await deletePack(p); - } - await _sharedPreferences.remove('packs'); - } - - Future savePack( - CardPackDto dto, { - Map>? images, - }) async { - log('Saving pack ${dto.id}'); - final packCacheId = _packCacheId(dto.id); - final json = dto.encode(); - log('Saving dto ${dto.id}'); - _sharedPreferences.setString(packCacheId, jsonEncode(json)); - - // if (images != null) { - // log('Saving card images ${dto.id}'); - // for (final card in dto.cards) { - // final bytes = images[card.id.toString()]; - // if (bytes != null) { - // File('${imageDir.path}/${card.id}') - // ..createSync(recursive: true) - // ..writeAsBytesSync(bytes); - // } - // } - // } - - log('Saved ${dto.id}'); - } - - String _packCacheId(String dtoId) => 'pack_cache_${dtoId}'; - - @override - File getPackFile(String packId, String path) { - // TODO: implement getPackFile - throw UnimplementedError(); - } - - @override - File getPackImageFile(String packId, int id) { - // TODO: implement getPackImageFile - throw UnimplementedError(); - } - - @override - Future loadPackImage(String packId, int id) { - // TODO: implement loadPackImage - throw UnimplementedError(); - } -} diff --git a/mnemo_cards/lib/features/purchase/google_purchase_handler.dart b/mnemo_cards/lib/features/purchase/google_purchase_handler.dart deleted file mode 100644 index e0ca8ed..0000000 --- a/mnemo_cards/lib/features/purchase/google_purchase_handler.dart +++ /dev/null @@ -1,208 +0,0 @@ -import 'dart:async'; -import 'dart:developer'; -import 'package:universal_io/io.dart'; - -import 'package:in_app_purchase/in_app_purchase.dart'; -import 'package:in_app_purchase_android/billing_client_wrappers.dart'; -import 'package:in_app_purchase_android/in_app_purchase_android.dart'; -import 'package:mnemo_cards/features/analytics/analytics.dart'; -import 'package:mnemo_cards/managers/repository/repository.dart'; -import 'package:mnemo_cards_common/mnemo_cards_common.dart'; - -import 'purchase_handler.dart'; - -class GooglePurchaseHandler implements PurchaseHandler { - final InAppPurchase _inAppPurchase = InAppPurchase.instance; - final Repository _repository; - - StreamSubscription? _subscription; - - GooglePurchaseHandler(this._repository); - - Future initPurchase({ - required String id, - required MnemoCardsProductType productType, - required String paymentId, - String? source, - }) async { - if (productType == MnemoCardsProductType.unknown) { - log('unknown product type'); - return; - } - if (!await isAvailable) { - log('Google play payment not available'); - return; - } - final productId = paymentId.split('/').first; - final subscriptionId = paymentId.split('/').last; - final products = await _getStoreProduct(productId); - if (products.isEmpty) { - Analytics.buyError( - null, - paymentSystem, - paymentId: paymentId, - id: id, - message: 'No products', - ); - return; - } - - switch (productType) { - case MnemoCardsProductType.pack: - final product = products.first; - await _buyInStore(product); - return; - case MnemoCardsProductType.subscription: - // choosing the right subscription plan - final subs = products.first.productDetails.subscriptionOfferDetails; - final index = subs?.indexWhere((s) => s.basePlanId == subscriptionId); - if (index == null) { - Analytics.buyError( - null, - paymentSystem, - paymentId: paymentId, - id: id, - message: 'Unknown subscription id', - ); - return; - } - await _buyInStore(products[index]); - return; - case MnemoCardsProductType.discount: - return; - case MnemoCardsProductType.game: - return; - case MnemoCardsProductType.unknown: - Analytics.buyError( - null, - paymentSystem, - paymentId: paymentId, - id: id, - message: 'Unknown product type', - ); - return; - } - } - - Future> _getStoreProduct( - String googlePlayId) async { - final productDetailResponse = await _inAppPurchase.queryProductDetails({ - googlePlayId, - }); - - if (productDetailResponse.error != null || - productDetailResponse.productDetails.isEmpty) { - Analytics.buyError( - null, - paymentSystem, - paymentId: googlePlayId, - data: { - 'msg': 'cant get product details ${productDetailResponse.error}', - 'not_found': productDetailResponse.notFoundIDs.join(','), - }, - ); - return []; - } - - return productDetailResponse.productDetails.cast(); - } - - Future _buyInStore(ProductDetails product) async { - final PurchaseParam purchaseParam = PurchaseParam(productDetails: product); - product as GooglePlayProductDetails; - if (product.productDetails.productType == ProductType.inapp) { - final result = await InAppPurchase.instance.buyConsumable( - purchaseParam: purchaseParam, - ); - return result; - } else { - final result = InAppPurchase.instance.buyNonConsumable( - purchaseParam: purchaseParam, - ); - return result; - } - } - - Future completePurchase(PurchaseDetails purchaseDetails) async { - await InAppPurchase.instance.completePurchase(purchaseDetails); - } - - Future _onPurchased(PurchaseDetails purchaseDetails) async { - try { - final result = await checkPurchase( - product: MnemoCardsProductDto( - id: purchaseDetails.productID, - type: MnemoCardsProductType.unknown, - ), - paymentToken: purchaseDetails.verificationData.serverVerificationData, - ); - if (result) { - Analytics.buyComplete( - null, - paymentSystem, - message: purchaseDetails.productID, - ); - log('Purchased'); - } else { - Analytics.buyError( - null, - PaymentSystem.yookassa, - message: 'payment not verified ${purchaseDetails.productID}', - ); - } - } catch (e, s) { - log(e.toString(), stackTrace: s); - } - } - - Future get isAvailable => _inAppPurchase.isAvailable(); - - @override - PaymentSystem get paymentSystem => PaymentSystem.google; - - @override - Future checkPurchase({ - required MnemoCardsProductDto product, - required String paymentToken, - }) async { - final result = await _repository.checkPayment( - product: product, - key: paymentToken, - paymentSystem: paymentSystem, - ); - return result; - } - - Future init() async { - if (Platform.isAndroid) { - _subscription = _inAppPurchase.purchaseStream.listen( - (List events) { - Future.forEach( - events, - (PurchaseDetails purchaseDetails) async { - if (purchaseDetails.pendingCompletePurchase || - purchaseDetails.status == PurchaseStatus.purchased) { - Analytics.buyEvent( - null, - paymentSystem, - message: 'onPurchased', - data: { - 'status': purchaseDetails.status.name, - 'product': purchaseDetails.productID, - 'date': purchaseDetails.transactionDate, - }, - ); - _onPurchased(purchaseDetails); - } - }, - ); - }, - ); - } - } - - Future dispose() async { - await _subscription?.cancel(); - _subscription = null; - } -} diff --git a/mnemo_cards/lib/features/purchase/in_app_purchase.dart b/mnemo_cards/lib/features/purchase/in_app_purchase.dart deleted file mode 100644 index b0472aa..0000000 --- a/mnemo_cards/lib/features/purchase/in_app_purchase.dart +++ /dev/null @@ -1,257 +0,0 @@ -import 'dart:async'; -import 'dart:developer'; -import 'package:universal_io/io.dart'; - -import 'package:flutter/material.dart'; -import 'package:in_app_purchase/in_app_purchase.dart'; -import 'package:in_app_purchase_android/in_app_purchase_android.dart'; -import 'package:mnemo_cards_common/mnemo_cards_common.dart'; -import 'package:url_launcher/url_launcher_string.dart'; -import 'package:webview_flutter/webview_flutter.dart'; -import '../../di/injector.dart'; -import '../../di/locator.dart'; -import '../../flags.dart'; -import '../../main.dart'; -import '../analytics/analytics.dart'; -import 'rustore/mnemo_rustore.dart'; - -enum StoreItemType { - ads, - subscription, - pack, -} - -class InAppPurchaseService { - final InAppPurchase _inAppPurchase = InAppPurchase.instance; - final Stream> storeSubscription = - InAppPurchase.instance.purchaseStream; - - InAppPurchase get instance => _inAppPurchase; - - // Future buySubscription(SubscriptionPlanDto dto) async { - // if (dto.paymentSystem == PaymentSystem.yookassa) { - // return false; - // } - // - // final subscriptionProducts = await _getSubscriptionStoreProduct(dto); - // ProductDetails? product; - // if (Platform.isAndroid && !RUSTORE_BUILD) { - // // final googlePlayProducts = subscriptionProducts.whereType(); - // product = subscriptionProducts.firstWhereOrNull( - // (p) => p.rawPrice == double.parse(dto.price), - // ); - // } else { - // product = subscriptionProducts.first; - // } - // if (product == null) { - // Analytics.buySubscriptionError( - // dto, - // androidPaymentSystem, - // message: 'cant find plan with price ${dto.price}', - // data: { - // 'plans': subscriptionProducts.join(';'), - // }, - // ); - // return false; - // } - // final result = await _buySubscriptionInStore(product); - // return result; - // } - - Future buyPack(CardPackBuyDto dto) async { - try { - if (RUSTORE_BUILD) { - // return RustorePurchaseService().buyPack(dto); - return false; - } else { - final pack = await _getPackStoreProduct(dto); - final result = await _buyItemInStore(pack.first); - return result; - } - } catch (e, s) { - log('err', error: e, stackTrace: s); - Analytics.buyError( - dto, - androidPaymentSystem, - data: { - 'e': e.toString(), - 's': s.toString(), - }, - ); - return false; - } - } - - Future> _getPackStoreProduct(CardPackBuyDto dto) async { - final bool isAvailable = await _inAppPurchase.isAvailable(); - if (!isAvailable) { - Analytics.buyError( - dto, - androidPaymentSystem, - message: 'in app purchase not available', - ); - return []; - } - final ids = { - if (Platform.isAndroid) RUSTORE_BUILD ? dto.rustoreId : dto.googlePlayId, - if (Platform.isIOS) dto.appStoreId, - }.whereNotNull().toSet(); - if (ids.isEmpty) { - Analytics.buyError( - dto, - androidPaymentSystem, - message: 'product id not set', - ); - return []; - } - - final ProductDetailsResponse productDetailResponse = - await _inAppPurchase.queryProductDetails(ids); - - if (productDetailResponse.error != null || - productDetailResponse.productDetails.isEmpty) { - Analytics.buyError( - dto, - androidPaymentSystem, - data: { - 'msg': 'cant get product details ${productDetailResponse.error}', - 'not_found': productDetailResponse.notFoundIDs.join(','), - }, - ); - return []; - } - - return productDetailResponse.productDetails; - } - - // Future> _getSubscriptionStoreProduct( - // SubscriptionPlanDto dto, - // ) async { - // final bool isAvailable = await _inAppPurchase.isAvailable(); - // if (!isAvailable) { - // Analytics.buySubscriptionError( - // dto, - // androidPaymentSystem, - // message: 'in app purchase not available', - // ); - // return []; - // } - // final ids = { - // if (Platform.isAndroid) - // if (RUSTORE_BUILD && dto.paymentSystem == PaymentSystem.rustore) - // dto.paymentId, - // if (!RUSTORE_BUILD && dto.paymentSystem == PaymentSystem.google) - // dto.googlePlaySubscriptionId, - // if (dto.paymentSystem == PaymentSystem.yookassa) dto.paymentId, - // if (Platform.isIOS && dto.paymentSystem == PaymentSystem.apple) - // dto.paymentId, - // }.whereNotNull().toSet(); - // if (ids.isEmpty) { - // Analytics.buySubscriptionError( - // dto, - // androidPaymentSystem, - // message: 'product id not set', - // ); - // return []; - // } - // - // final productDetailResponse = await _inAppPurchase.queryProductDetails(ids); - // if (productDetailResponse.error != null || - // productDetailResponse.productDetails.isEmpty) { - // Analytics.buySubscriptionError( - // dto, - // androidPaymentSystem, - // data: { - // 'msg': 'cant get product details ${productDetailResponse.error}', - // 'not_found': productDetailResponse.notFoundIDs.join(','), - // }, - // ); - // return []; - // } - // - // return productDetailResponse.productDetails; - // } - - Future _buyItemInStore(ProductDetails product) async { - final PurchaseParam purchaseParam = PurchaseParam(productDetails: product); - return InAppPurchase.instance.buyConsumable(purchaseParam: purchaseParam); - } - - Future _buySubscriptionInStore(ProductDetails product) async { - final PurchaseParam purchaseParam = PurchaseParam(productDetails: product); - return InAppPurchase.instance - .buyNonConsumable(purchaseParam: purchaseParam); - } - - Future completePurchase(PurchaseDetails purchaseDetails) async { - await InAppPurchase.instance.completePurchase(purchaseDetails); - } -} - -class PurchaseDetailsStreamSubscription { - final InAppPurchaseService inAppPurchaseService = getIt.get(); - - Future onPurchased(PurchaseDetails purchaseDetails) async { - try { - Analytics.buyEvent( - null, - androidPaymentSystem, - message: 'onPurchased', - data: { - 'status': purchaseDetails.status.name, - 'product': purchaseDetails.productID, - 'date': purchaseDetails.transactionDate, - }, - ); - final result = await locator.repository.checkPayment( - product: MnemoCardsProductDto( - id: purchaseDetails.productID, - type: MnemoCardsProductType.unknown, - ), - key: purchaseDetails.verificationData.serverVerificationData, - paymentSystem: androidPaymentSystem, - ); - if (result) { - Analytics.buyComplete( - null, - androidPaymentSystem, - message: purchaseDetails.productID, - ); - log('Purchased'); - } else { - Analytics.buyError( - null, - PaymentSystem.yookassa, - message: 'payment not verified ${purchaseDetails.productID}', - ); - throw Exception('Cant verify purchase'); - } - } catch (e, s) { - log(e.toString(), stackTrace: s); - } - } - - StreamSubscription>? _streamSubscription; - - PurchaseDetailsStreamSubscription(); - - Future init() async { - _streamSubscription = inAppPurchaseService.storeSubscription.listen( - (List events) { - Future.forEach( - events, - (PurchaseDetails purchaseDetails) async { - if (purchaseDetails.pendingCompletePurchase || - purchaseDetails.status == PurchaseStatus.purchased) { - onPurchased(purchaseDetails); - } - }, - ); - }, - ); - } - - void close() { - _streamSubscription?.cancel(); - } -} diff --git a/mnemo_cards/lib/features/purchase/purchase_deeplink_handler.dart b/mnemo_cards/lib/features/purchase/purchase_deeplink_handler.dart deleted file mode 100644 index 809bd08..0000000 --- a/mnemo_cards/lib/features/purchase/purchase_deeplink_handler.dart +++ /dev/null @@ -1,66 +0,0 @@ -import 'package:mnemo_cards/di/locator.dart'; -import 'package:mnemo_cards/domain/router/dialogs.dart'; -import 'package:mnemo_cards/features/analytics/analytics.dart'; -import 'package:mnemo_cards/features/deeplinks/deeplinks_manager.dart'; -import 'package:mnemo_cards/main.dart'; -import 'package:mnemo_cards_common/mnemo_cards_common.dart'; - -import 'purchase_manager.dart'; - -class PurchaseDeeplinkHandler implements DeeplinkHandler { - final PurchaseManager _purchaseManager; - - PurchaseDeeplinkHandler(this._purchaseManager); - - @override - bool canHandle(Uri uri) => uri.host == 'purchase'; - - @override - void handle(Uri uri) { - final path = uri.path.replaceFirst('/', ''); - switch (path) { - case PurchaseInitDeeplink.deeplinkPath: - return _initPurchase(uri); - case PurchaseCheckDeeplink.deeplinkPath: - return _checkPurchase(uri); - } - Analytics.buyDeeplinkError(uri, message: 'Unknown path: ${path}'); - } - - void _initPurchase(Uri uri) { - final model = PurchaseInitDeeplink.parse(uri); - _purchaseManager.initPurchase( - id: model.id, - productType: model.productType, - paymentId: model.paymentId, - paymentSystem: model.paymentSystem, - source: model.source?.notEmptyOrNull, - ); - } - - void _checkPurchase(Uri uri) async { - final model = PurchaseCheckDeeplink.parse(uri); - final success = await _purchaseManager.checkPurchase( - product: MnemoCardsProductDto( - id: model.id, - type: model.productType, - ), - token: model.token, - paymentSystem: model.paymentSystem, - ); - if (success) { - if (model.productType == MnemoCardsProductType.pack) { - locator.packUpdater.updatePackAndSaveImages( - model.id, - shouldUpdateHolder: true, - ); - } else { - locator.packUpdater.updateAvailablePacks(); - locator.userManager.updateUser(); - showInfoDialog('Ура! Теперь у вас есть подписка!'); - } - } else { - // showErrorDialog('Не уда'); - } - } -} diff --git a/mnemo_cards/lib/features/purchase/purchase_handler.dart b/mnemo_cards/lib/features/purchase/purchase_handler.dart deleted file mode 100644 index 1c288d7..0000000 --- a/mnemo_cards/lib/features/purchase/purchase_handler.dart +++ /dev/null @@ -1,17 +0,0 @@ -import 'package:mnemo_cards_common/mnemo_cards_common.dart'; - -abstract interface class PurchaseHandler { - PaymentSystem get paymentSystem; - - Future initPurchase({ - required String id, - required MnemoCardsProductType productType, - required String paymentId, - String? source, - }); - - Future checkPurchase({ - required MnemoCardsProductDto product, - required String paymentToken, - }); -} diff --git a/mnemo_cards/lib/features/purchase/purchase_manager.dart b/mnemo_cards/lib/features/purchase/purchase_manager.dart deleted file mode 100644 index 43a46d6..0000000 --- a/mnemo_cards/lib/features/purchase/purchase_manager.dart +++ /dev/null @@ -1,124 +0,0 @@ -import 'package:mnemo_cards/features/analytics/analytics.dart'; -import 'package:mnemo_cards/features/purchase/yookassa_purchase_handler.dart'; -import 'package:mnemo_cards_common/mnemo_cards_common.dart'; - -import 'google_purchase_handler.dart'; - -class PurchaseManager { - final GooglePurchaseHandler _googlePurchaseHandler; - final YookassaPurchaseHandler _yookassaPurchaseHandler; - - PurchaseManager( - this._googlePurchaseHandler, - this._yookassaPurchaseHandler, - ); - - Future initPurchaseFromDto({ - required CardPackBuyDto dto, - required PaymentSystem paymentSystem, - String? source = 'dto', - }) async { - String? paymentId; - - switch (paymentSystem) { - case PaymentSystem.google: - paymentId = dto.googlePlayId; - break; - case PaymentSystem.apple: - paymentId = dto.appStoreId; - break; - case PaymentSystem.rustore: - paymentId = dto.rustoreId; - break; - case PaymentSystem.yookassa: - paymentId = dto.id; - break; - case PaymentSystem.promoCode: - paymentId = dto.id; - break; - case PaymentSystem.adView: - paymentId = dto.id; - break; - case PaymentSystem.unknown: - break; - } - if (paymentId == null) { - Analytics.buyError( - dto, - paymentSystem, - message: 'Cant find payment id', - ); - return; - } - - return initPurchase( - id: dto.id, - productType: MnemoCardsProductType.pack, - paymentId: paymentId, - paymentSystem: paymentSystem, - ); - } - - Future initPurchase({ - required String id, - required MnemoCardsProductType productType, - required String paymentId, - required PaymentSystem paymentSystem, - String? source, - }) async { - switch (paymentSystem) { - case PaymentSystem.google: - return _googlePurchaseHandler.initPurchase( - id: id, - productType: productType, - paymentId: paymentId, - source: source, - ); - case PaymentSystem.apple: - return; - case PaymentSystem.rustore: - return; - case PaymentSystem.yookassa: - return _yookassaPurchaseHandler.initPurchase( - id: id, - productType: productType, - paymentId: paymentId, - ); - case PaymentSystem.promoCode: - return; - case PaymentSystem.adView: - return; - case PaymentSystem.unknown: - return; - } - } - - Future checkPurchase({ - required MnemoCardsProductDto product, - required String token, - required PaymentSystem paymentSystem, - }) async { - switch (paymentSystem) { - case PaymentSystem.google: - return _googlePurchaseHandler.checkPurchase( - product: product, - paymentToken: token, - ); - case PaymentSystem.apple: - return false; - case PaymentSystem.rustore: - return false; - case PaymentSystem.yookassa: - return _yookassaPurchaseHandler.checkPurchase( - product: product, - paymentToken: token, - ); - case PaymentSystem.unknown: - return false; - case PaymentSystem.promoCode: - return true; - case PaymentSystem.adView: - return true; - } - } -} diff --git a/mnemo_cards/lib/features/purchase/rustore/mnemo_rustore.dart b/mnemo_cards/lib/features/purchase/rustore/mnemo_rustore.dart deleted file mode 100644 index 4b43433..0000000 --- a/mnemo_cards/lib/features/purchase/rustore/mnemo_rustore.dart +++ /dev/null @@ -1,110 +0,0 @@ -// import 'dart:developer'; -// -// import 'package:flutter_rustore_billing/flutter_rustore_billing.dart'; -// import 'package:mnemo_cards/features/analytics/analytics.dart'; -// import 'package:mnemo_cards/flags.dart'; -// import 'package:mnemo_cards_common/mnemo_cards_common.dart'; -// -// import '../../../di/locator.dart'; -// import '../../../domain/router/dialogs.dart'; -// -// class RustorePurchaseService { -// Future init() async { -// return RustoreBillingClient.initialize( -// "2063563896", -// "mnemocards://iamback", -// true, -// ).then((value) { -// print("initialize success: $value"); -// return true; -// }, onError: (err) { -// print("initialize err: $err"); -// return false; -// }); -// } -// -// Future buyPack(CardPackBuyDto dto) async { -// if (dto.rustoreId == null) { -// return false; -// } -// if (!await init()) { -// return false; -// } -// if (!await RustoreBillingClient.available().then((value) { -// print("available success $value"); -// return true; -// }, onError: (err) { -// print("available err: $err"); -// return false; -// })) { -// return false; -// } -// final product = (await RustoreBillingClient.products([dto.rustoreId])) -// .products -// .firstOrNull; -// if (product == null) { -// return false; -// } -// try { -// final result = await RustoreBillingClient.purchase(dto.rustoreId!, null); -// try { -// try { -// // creating payment to check it later -// // in case there will be an error after confirmation -// await locator.repository.checkPayment( -// itemId: result.successPurchase!.productId, -// key: result.successPurchase!.subscriptionToken!, -// paymentSystem: androidPaymentSystem, -// ); -// } catch (e, s) { -// Analytics.buyError( -// dto, -// PaymentSystem.rustore, -// message: 'Error when creating payment', -// ); -// log('Error when creating payment', error: e, stackTrace: s); -// showErrorDialog( -// 'Технические шоколадки...\n\nПопробуйте позже или обновите приложение до последней версии'); -// return false; -// } -// final p = await RustoreBillingClient.confirm( -// result.successPurchase!.subscriptionToken!, -// ); -// if (p.success) { -// final r = await locator.repository.checkPayment( -// itemId: result.successPurchase!.productId, -// key: result.successPurchase!.subscriptionToken!, -// paymentSystem: androidPaymentSystem, -// ); -// if (r) { -// return r; -// } else { -// Analytics.buyError( -// dto, -// PaymentSystem.rustore, -// message: 'Error when confirming payment', -// ); -// showErrorDialog( -// 'Технические шоколадки...\n\nДоступ откроется в течение 5 мин', -// ); -// } -// } -// } catch (e, s) { -// log('Error when confirming purchase', error: e, stackTrace: s); -// Analytics.crashlyticsError( -// e: e, -// s: s, -// message: 'Error when confirming rustore purchase', -// ); -// } -// } catch (e, s) { -// log('Error when processing purchase', error: e, stackTrace: s); -// Analytics.crashlyticsError( -// e: e, -// s: s, -// message: 'Error when processing rustore purchase', -// ); -// } -// return false; -// } -// } diff --git a/mnemo_cards/lib/features/purchase/yookassa_purchase_handler.dart b/mnemo_cards/lib/features/purchase/yookassa_purchase_handler.dart deleted file mode 100644 index c160b04..0000000 --- a/mnemo_cards/lib/features/purchase/yookassa_purchase_handler.dart +++ /dev/null @@ -1,145 +0,0 @@ -import 'dart:async'; - -import 'package:flutter/material.dart'; -import 'package:mnemo_cards/features/deeplinks/deeplinks_manager_impl.dart'; -import 'package:mnemo_cards/managers/repository/repository.dart'; -import 'package:mnemo_cards_common/src/dtos/payment/payment_dto.dart'; - -import 'package:mnemo_cards_common/src/dtos/payment/product_type.dart'; -import 'package:url_launcher/url_launcher_string.dart'; -import 'package:webview_flutter/webview_flutter.dart'; - -import '../../di/locator.dart'; -import '../../main.dart'; -import '../analytics/analytics.dart'; -import 'purchase_handler.dart'; - -class YookassaPurchaseHandler implements PurchaseHandler { - final Repository _repository; - - const YookassaPurchaseHandler(this._repository); - - @override - Future checkPurchase({ - required MnemoCardsProductDto product, - required String paymentToken, - }) async { - return await _repository.checkPayment( - product: product, - key: paymentToken, - paymentSystem: paymentSystem, - ); - } - - @override - Future initPurchase({ - required String id, - required MnemoCardsProductType productType, - required String paymentId, - String? source, - }) async { - await _buyWithYooMoney(id, productType, scaffoldKey.currentContext); - } - - Future _buyWithYooMoney( - String id, - MnemoCardsProductType productType, - BuildContext? context, - ) async { - final dto = await _repository.createPayment( - id, - productType, - PaymentSystem.yookassa, - ); - if (dto == null) { - Analytics.buyError( - null, - id: id, - PaymentSystem.yookassa, - message: 'payment dto is null', - ); - return; - } - final purchaseUrl = dto.purchaseUrl; - final checkUrl = dto.checkUrl; - final completer = Completer(); - bool dialogClosed = false; - final realContext = (context ?? scaffoldKey.currentContext)!; - completer.future.then((_) { - if (!dialogClosed) { - return Navigator.of(realContext).pop(); - } - }); - final controller = WebViewController() - ..setJavaScriptMode(JavaScriptMode.unrestricted) - ..loadRequest(Uri.parse(purchaseUrl)) - ..setNavigationDelegate( - NavigationDelegate( - onNavigationRequest: (request) async { - final url = request.url; - if (url.startsWith('http')) { - return NavigationDecision.navigate; - } else if (url.startsWith('mnemocards')) { - locator.deeplinkManager.handle(Uri.parse(url)); - if (!completer.isCompleted) { - completer.complete(); - } - return NavigationDecision.prevent; - } else { - launchUrlString(url); - return NavigationDecision.prevent; - } - }, - ), - ); - final result = showModalBottomSheet( - context: realContext, - enableDrag: false, - showDragHandle: true, - useSafeArea: true, - isScrollControlled: true, - backgroundColor: Colors.white, - builder: (context) { - return Container( - child: WebViewWidget(controller: controller), - padding: EdgeInsets.only( - bottom: MediaQuery.of(context).viewInsets.bottom, - ), - ); - }, - ).then((_) async { - // final success = await checkPurchase( - // productId: id, - // productType: MnemoCardsProductType.pack, - // paymentToken: id, - // ); - return locator.deeplinkManager.handle(Uri.parse(checkUrl)); - - // if (success) { - // Analytics.buyComplete( - // null, - // id: id, - // PaymentSystem.yookassa, - // ); - // locator.packUpdater.updateAvailablePacks(); - // return true; - // } - // Analytics.buyError( - // null, - // id: id, - // PaymentSystem.yookassa, - // message: 'payment not verified', - // ); - // return false; - }); - await result.then((_) { - dialogClosed = true; - if (!completer.isCompleted) { - completer.complete(); - } - }); - } - - @override - PaymentSystem get paymentSystem => PaymentSystem.yookassa; -} diff --git a/mnemo_cards/lib/features/stories/stories_page.dart b/mnemo_cards/lib/features/stories/stories_page.dart deleted file mode 100644 index a21057d..0000000 --- a/mnemo_cards/lib/features/stories/stories_page.dart +++ /dev/null @@ -1,49 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:story/story.dart'; - -class StoriesPage extends StatelessWidget { - StoriesPage(); - - @override - Widget build(BuildContext context) { - final topPadding = MediaQuery.of(context).padding.top; - return Scaffold( - body: StoryPageView( - indicatorHeight: 4.0, - indicatorPadding: EdgeInsets.symmetric( - vertical: topPadding + 8.0, - horizontal: 8.0, - ), - onPageLimitReached: () { - Navigator.pop(context); - }, - gestureItemBuilder: (context, story, page) => Stack( - children: [ - Positioned( - top: topPadding + 24.0, - left: 12.0, - child: IconButton( - onPressed: () { - Navigator.pop(context); - }, - icon: Icon(Icons.clear), - ), - ), - ], - ), - itemBuilder: (c, pageIndex, storyIndex) { - return Container( - color: Colors.redAccent, - alignment: Alignment.center, - child: Text( - "Index of PageView: $pageIndex Index of story on each page: $storyIndex"), - ); - }, - storyLength: (pageIndex) { - return 1; - }, - pageLength: 2, - ), - ); - } -} diff --git a/mnemo_cards/lib/features/stories/stories_row.dart b/mnemo_cards/lib/features/stories/stories_row.dart deleted file mode 100644 index 630dd57..0000000 --- a/mnemo_cards/lib/features/stories/stories_row.dart +++ /dev/null @@ -1,29 +0,0 @@ -import 'package:flutter/cupertino.dart'; - -import 'stories_widget.dart'; - -class StoriesRow extends StatelessWidget { - final double height; - - StoriesRow(this.height); - - @override - Widget build(BuildContext context) { - return Container( - height: height, - alignment: Alignment.center, - child: ListView( - scrollDirection: Axis.horizontal, - children: [1, 2, 3, 4] - .map((e) => Padding( - padding: const EdgeInsets.all(4.0), - child: StoriesWidget( - width: height - 8, - height: height - 8, - ), - )) - .toList(), - ), - ); - } -} diff --git a/mnemo_cards/lib/features/stories/stories_widget.dart b/mnemo_cards/lib/features/stories/stories_widget.dart deleted file mode 100644 index 14a392e..0000000 --- a/mnemo_cards/lib/features/stories/stories_widget.dart +++ /dev/null @@ -1,40 +0,0 @@ -import 'package:auto_route/auto_route.dart'; -import 'package:flutter/material.dart'; -import 'package:mnemo_cards/features/stories/stories_page.dart'; - -class StoriesWidget extends StatefulWidget { - final double width; - final double height; - - const StoriesWidget({required this.width, required this.height, super.key}); - - @override - State createState() => _StoriesWidgetState(); -} - -class _StoriesWidgetState extends State { - @override - Widget build(BuildContext context) { - return InkWell( - onTap: () { - AutoRouter.of(context).pushWidget(StoriesPage()); - }, - child: SizedBox( - width: widget.width, - height: widget.height, - child: Container( - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(32.0), - border: Border.all( - color: Colors.blue, - width: 4.0, - ), - ), - child: Center( - child: Text('Story'), - ), - ), - ), - ); - } -} diff --git a/mnemo_cards/lib/features/subscription/subscription_api.dart b/mnemo_cards/lib/features/subscription/subscription_api.dart deleted file mode 100644 index 85ba167..0000000 --- a/mnemo_cards/lib/features/subscription/subscription_api.dart +++ /dev/null @@ -1,39 +0,0 @@ -import 'dart:typed_data'; - -import 'package:dio/dio.dart'; -import 'package:mnemo_cards_common/mnemo_cards_common.dart'; - -import '../../managers/repository/api.dart'; - -class SubscriptionApi with Api { - final Dio _dio; - - SubscriptionApi(this._dio); - - Future getBuySubscription() async { - final r = await _dio.get( - '$path/subscription/page', - options: Options( - sendTimeout: Duration(seconds: 5), - receiveTimeout: Duration(seconds: 5), - ), - ); - return (r.data as String).decode(SubscriptionDto.fromJson); - } - - /// cards zip archive for available pack - /// unavailable packs transfer images by base64 - Future packImagesArchive(String packId) async { - final response = await _dio.get( - '$path/pack/cards/$packId', - options: Options( - responseType: ResponseType.bytes, - ), - ); - final data = response.data; - if (data == null) { - return Uint8List.fromList([]); - } - return data; - } -} diff --git a/mnemo_cards/lib/features/subscription/subscription_deeplink_handler.dart b/mnemo_cards/lib/features/subscription/subscription_deeplink_handler.dart deleted file mode 100644 index d310a9f..0000000 --- a/mnemo_cards/lib/features/subscription/subscription_deeplink_handler.dart +++ /dev/null @@ -1,12 +0,0 @@ -import 'package:mnemo_cards/features/deeplinks/deeplinks_manager.dart'; -import 'package:mnemo_cards_common/mnemo_cards_common.dart'; - -import '../../di/locator.dart'; - -class SubscriptionDeeplinkHandler implements DeeplinkHandler { - @override - bool canHandle(Uri uri) => uri.host == 'subscription'; - - @override - void handle(Uri uri) => locator.subscriptionManager.openSubscriptionPage(); -} diff --git a/mnemo_cards/lib/features/subscription/subscription_manager.dart b/mnemo_cards/lib/features/subscription/subscription_manager.dart deleted file mode 100644 index 8a452b2..0000000 --- a/mnemo_cards/lib/features/subscription/subscription_manager.dart +++ /dev/null @@ -1,34 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:mnemo_cards/features/subscription/subscription_api.dart'; -import 'package:mnemo_cards/managers/user_state_holder.dart'; - -import '../../domain/router/app_router.dart'; -import '../../main.dart'; -import '../../managers/user_manager.dart'; -import 'subscription_page.dart'; - -class SubscriptionManager { - final UserManager _userManager; - final SubscriptionApi _subscriptionApi; - - SubscriptionManager( - this._userManager, - this._subscriptionApi, - ); - - Future openSubscriptionPage() async { - final user = _userManager.user; - if (user == null) { - AppRouter.openAuthOrProfile(); - return; - } - final buyDto = - await _subscriptionApi.getBuySubscription().catchError((_) => null); - if (buyDto != null) { - showDialog( - context: scaffoldKey.currentContext!, - builder: (_) => SubscriptionPage(buyDto.page!), - ); - } - } -} diff --git a/mnemo_cards/lib/features/subscription/subscription_page.dart b/mnemo_cards/lib/features/subscription/subscription_page.dart deleted file mode 100644 index a05058d..0000000 --- a/mnemo_cards/lib/features/subscription/subscription_page.dart +++ /dev/null @@ -1,187 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_screenutil/flutter_screenutil.dart'; -import 'package:mnemo_cards_common/mnemo_cards_common.dart'; -import 'package:mnemo_cards_frontend_common/mnemo_cards_frontend_common.dart'; -import 'package:url_launcher/url_launcher_string.dart'; -import 'package:mnemo_cards/utils/string_helper.dart'; - -import '../../theme/themes.dart'; - -class SubscriptionPage extends StatelessWidget { - final SubscriptionPageDto dto; - - SubscriptionPage(this.dto); - - @override - Widget build(BuildContext context) { - return Scaffold( - body: Column( - children: [ - Header(dto.title, hasPopButton: true, center: true), - Expanded( - child: Column( - // shrinkWrap: true, - // physics: PageScrollPhysics(), - children: [ - ...dto.items.build(), - ...dto.plans.map(_SubscriptionPlanWidget.new), - ], - ), - ), - BigBackButton(), - ], - ), - ); - } -} - -class _SubscriptionPlanWidget extends StatelessWidget { - final SubscriptionPlanDto plan; - - _SubscriptionPlanWidget(this.plan); - - @override - Widget build(BuildContext context) { - return Container( - padding: EdgeInsets.only(left: 10.0, right: 10.0), - height: (90 + (plan.tip == null ? 0 : 13)).h, - child: GestureDetector( - onTap: () => plan.deeplink?.let((d) => launchUrlString(d)), - child: Stack( - alignment: Alignment.topCenter, - children: [ - Padding( - padding: EdgeInsets.only(top: plan.tip == null ? 0 : 13.h), - child: Container( - height: 80.h, - decoration: BoxDecoration( - color: Theme.of(context).scaffoldBackgroundColor, - border: Border.all(color: borderGray), - borderRadius: BorderRadius.circular(12.0), - ), - padding: EdgeInsets.only( - left: 10.0.w, - right: 20.w, - top: 10.h, - bottom: 10.h, - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Expanded(child: _lead(plan)), - SizedBox( - width: 85.w, - child: _trail(plan), - ), - ], - ), - ), - ), - if (plan.tip != null) - Container( - height: 26.h, - width: 110.w, - alignment: Alignment.center, - decoration: BoxDecoration( - color: plan.tipColor?.asColor ?? progressBlue, - border: Border.all(color: borderGray), - borderRadius: BorderRadius.circular(16.0), - ), - padding: EdgeInsets.all(2.0.w), - child: Text( - plan.tip!, - style: TextStyle(color: white), - ), - ), - ], - ), - ), - ); - } - - Widget _lead(SubscriptionPlanDto plan) { - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text.rich( - TextSpan( - children: [ - if (plan.titleLead != null) - TextSpan( - text: plan.titleLead, - style: TextStyle(fontSize: 32), - ), - if (plan.title != null) - TextSpan( - text: ' ${plan.title}', - style: TextStyle( - fontSize: 16, - ), - ), - ], - style: TextStyle( - height: 0.85, - )), - ), - Text.rich( - TextSpan( - children: [ - if (plan.subtitleCrossed != null) - TextSpan( - text: plan.subtitleCrossed, - style: TextStyle( - fontSize: 20, - color: borderGray, - decoration: TextDecoration.lineThrough, - height: 0.85, - ), - ), - if (plan.subtitleCrossed != null && plan.subtitle != null) - TextSpan(text: ' '), - if (plan.subtitle != null) - TextSpan( - text: plan.subtitle, - style: TextStyle( - fontSize: 20.h, - height: 0.85, - ), - ), - ], - ), - ) - ], - ); - } - - Widget _trail(SubscriptionPlanDto plan) { - if (plan.pricePerMonth != null) - return Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.end, - children: [ - Text.rich( - TextSpan(children: [ - TextSpan( - text: plan.pricePerMonth!, - style: TextStyle(fontSize: 24), - ), - TextSpan( - text: ' ${plan.currency}', - style: TextStyle( - fontSize: 14, - ), - ), - ], style: TextStyle(height: 0.85)), - ), - Text( - 'в месяц', - style: TextStyle( - fontSize: 14, - ), - ), - ], - ); - return SizedBox.shrink(); - } -} diff --git a/mnemo_cards/lib/features/tests/progress_widget.dart b/mnemo_cards/lib/features/tests/progress_widget.dart deleted file mode 100644 index 82d510a..0000000 --- a/mnemo_cards/lib/features/tests/progress_widget.dart +++ /dev/null @@ -1,213 +0,0 @@ - -import 'package:auto_route/auto_route.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_screenutil/flutter_screenutil.dart'; - - -class ProgressWidget extends StatefulWidget { - final Color color; - final List? results; - final int length; - final Stream? timer; - final bool showMic; - final bool showSound; - final String? popText; - final ValueGetter? popValue; - - @override - State createState() => _ProgressWidgetState(); - - factory ProgressWidget.value(int value, int length, Color color) => - ProgressWidget( - List.generate( - length, - (i) => i < value ? Result.correct : Result.not_visited, - ), - length, - color, - ); - - ProgressWidget( - this.results, - this.length, - this.color, { - this.timer, - this.popValue, - this.showMic = false, - this.showSound = false, - this.popText, - super.key, - }); -} - -enum Result { - correct, - wrong, - skiped, - not_visited, -} - -class _ProgressWidgetState extends State { - List get results => widget.results!; - - int get length => widget.length; - - @override - Widget build(BuildContext context) { - return Row( - children: [ - TapRegion( - onTapInside: AutoRouter.of(context).maybePop, - behavior: HitTestBehavior.opaque, - child: Container( - height: 30.h, - child: Row( - children: [ - Image.asset( - 'icons/back.webp', - color: Theme.of(context).colorScheme.primary, - width: 17, - height: 23.h, - ), - if (widget.popText != null) - Padding( - padding: const EdgeInsets.only(left: 4.0), - child: Text( - widget.popText!, - style: TextStyle( - fontSize: 16, - fontWeight: FontWeight.w700, - ), - ), - ), - ], - ), - ), - ), - Expanded( - child: widget.results == null - ? SizedBox.shrink() - : Padding( - padding: EdgeInsets.only(left: 10.0.w), - child: ClipRRect( - borderRadius: BorderRadius.circular(16.h), - child: Container( - height: 16.h, - color: Theme.of(context).scaffoldBackgroundColor, - child: Stack( - alignment: Alignment.center, - children: [ - Row( - children: [ - Expanded( - child: AnimatedFractionallySizedBox( - alignment: Alignment.centerLeft, - widthFactor: length == 0 - ? 0 - : (results - .where((r) => - r != Result.not_visited) - .length) / - length, - duration: Duration(milliseconds: 300), - child: Container( - color: widget.color, - ), - ), - ), - ], - ), - ], - ), - ), - ), - ), - ), - if (widget.showMic) - Padding( - padding: EdgeInsets.symmetric(horizontal: 10.0.w), - child: Image.asset( - 'icons/mic_on.webp', - height: 18.h, - width: 13.w, - color: Theme.of(context).colorScheme.primary, - ), - ), - if (widget.showSound) - Padding( - padding: EdgeInsets.symmetric(horizontal: 10.0.w), - child: Image.asset( - 'icons/sound_on.webp', - height: 18.h, - width: 24.w, - color: Theme.of(context).colorScheme.primary, - ), - ), - if (widget.timer != null) - Padding( - padding: EdgeInsets.only(left: 10.0.w), - child: _TimeWidget(widget.timer), - ), - ], - ); - } - - Widget _text() { - return Text( - results.where((r) => r != Result.skiped).length < length - ? '${results.where((r) => r != Result.skiped).length + 1} из ${length}' - : '$length', - style: Theme.of(context).textTheme.titleLarge?.copyWith( - fontWeight: FontWeight.w800, - ), - ); - } - - _ProgressWidgetState(); -} - -class _TimeWidget extends StatelessWidget { - final Stream? timer; - - _TimeWidget(Stream? timer) : this.timer = timer; - - @override - Widget build(BuildContext context) { - return SizedBox( - width: 68.w, - child: StreamBuilder( - stream: timer, - builder: (context, snapshot) { - var text = '-:-'; - if (snapshot.hasData) { - final minutes = snapshot.data?.inMinutes ?? 0; - final seconds = (snapshot.data?.inSeconds ?? 0) - 60 * minutes; - text = - "${minutes.toString().padLeft(2, '0')}:${seconds.toString().padLeft(2, '0')}"; - } - return Row( - mainAxisAlignment: MainAxisAlignment.start, - mainAxisSize: MainAxisSize.max, - children: [ - Image.asset( - 'icons/clock.webp', - width: 15.w, - height: 15.h, - color: Theme.of(context).colorScheme.primary - ), - SizedBox( - width: 4.0.w, - ), - Text( - text, - style: TextStyle( - fontSize: 16, - fontWeight: FontWeight.w400, - ), - ) - ], - ); - }), - ); - } -} diff --git a/mnemo_cards/lib/features/tests/question_states/input_buttons_test_state.dart b/mnemo_cards/lib/features/tests/question_states/input_buttons_test_state.dart deleted file mode 100644 index 76b420d..0000000 --- a/mnemo_cards/lib/features/tests/question_states/input_buttons_test_state.dart +++ /dev/null @@ -1,29 +0,0 @@ - -import 'package:copy_with_extension/copy_with_extension.dart'; -import 'package:json_annotation/json_annotation.dart'; -import 'package:mnemo_cards/features/tests/question_states/test_question_state.dart'; -import 'package:mnemo_cards_common/mnemo_cards_common.dart'; - -part 'input_buttons_test_state.g.dart'; - -@JsonSerializable() -@CopyWith() -class InputButtonsTestState extends TestQuestionState { - final List answer; - final List answerIds; - final bool isCorrect; - final bool isAnswered; - final bool isSkipped; - final int seed; - - InputButtonsTestState({ - required this.seed, - required super.word, - this.answer = const [], - this.answerIds = const [], - this.isCorrect = false, - this.isAnswered = false, - this.isSkipped = false, - super.testType = TestQuestionType.input_buttons, - }); -} diff --git a/mnemo_cards/lib/features/tests/question_states/input_buttons_test_state.g.dart b/mnemo_cards/lib/features/tests/question_states/input_buttons_test_state.g.dart deleted file mode 100644 index 3735531..0000000 --- a/mnemo_cards/lib/features/tests/question_states/input_buttons_test_state.g.dart +++ /dev/null @@ -1,185 +0,0 @@ -// GENERATED CODE - DO NOT MODIFY BY HAND - -part of 'input_buttons_test_state.dart'; - -// ************************************************************************** -// CopyWithGenerator -// ************************************************************************** - -abstract class _$InputButtonsTestStateCWProxy { - InputButtonsTestState seed(int seed); - - InputButtonsTestState word(String word); - - InputButtonsTestState answer(List answer); - - InputButtonsTestState answerIds(List answerIds); - - InputButtonsTestState isCorrect(bool isCorrect); - - InputButtonsTestState isAnswered(bool isAnswered); - - InputButtonsTestState isSkipped(bool isSkipped); - - InputButtonsTestState testType(TestQuestionType testType); - - /// This function **does support** nullification of nullable fields. All `null` values passed to `non-nullable` fields will be ignored. You can also use `InputButtonsTestState(...).copyWith.fieldName(...)` to override fields one at a time with nullification support. - /// - /// Usage - /// ```dart - /// InputButtonsTestState(...).copyWith(id: 12, name: "My name") - /// ```` - InputButtonsTestState call({ - int? seed, - String? word, - List? answer, - List? answerIds, - bool? isCorrect, - bool? isAnswered, - bool? isSkipped, - TestQuestionType? testType, - }); -} - -/// Proxy class for `copyWith` functionality. This is a callable class and can be used as follows: `instanceOfInputButtonsTestState.copyWith(...)`. Additionally contains functions for specific fields e.g. `instanceOfInputButtonsTestState.copyWith.fieldName(...)` -class _$InputButtonsTestStateCWProxyImpl - implements _$InputButtonsTestStateCWProxy { - const _$InputButtonsTestStateCWProxyImpl(this._value); - - final InputButtonsTestState _value; - - @override - InputButtonsTestState seed(int seed) => this(seed: seed); - - @override - InputButtonsTestState word(String word) => this(word: word); - - @override - InputButtonsTestState answer(List answer) => this(answer: answer); - - @override - InputButtonsTestState answerIds(List answerIds) => - this(answerIds: answerIds); - - @override - InputButtonsTestState isCorrect(bool isCorrect) => this(isCorrect: isCorrect); - - @override - InputButtonsTestState isAnswered(bool isAnswered) => - this(isAnswered: isAnswered); - - @override - InputButtonsTestState isSkipped(bool isSkipped) => this(isSkipped: isSkipped); - - @override - InputButtonsTestState testType(TestQuestionType testType) => - this(testType: testType); - - @override - - /// This function **does support** nullification of nullable fields. All `null` values passed to `non-nullable` fields will be ignored. You can also use `InputButtonsTestState(...).copyWith.fieldName(...)` to override fields one at a time with nullification support. - /// - /// Usage - /// ```dart - /// InputButtonsTestState(...).copyWith(id: 12, name: "My name") - /// ```` - InputButtonsTestState call({ - Object? seed = const $CopyWithPlaceholder(), - Object? word = const $CopyWithPlaceholder(), - Object? answer = const $CopyWithPlaceholder(), - Object? answerIds = const $CopyWithPlaceholder(), - Object? isCorrect = const $CopyWithPlaceholder(), - Object? isAnswered = const $CopyWithPlaceholder(), - Object? isSkipped = const $CopyWithPlaceholder(), - Object? testType = const $CopyWithPlaceholder(), - }) { - return InputButtonsTestState( - seed: seed == const $CopyWithPlaceholder() || seed == null - ? _value.seed - // ignore: cast_nullable_to_non_nullable - : seed as int, - word: word == const $CopyWithPlaceholder() || word == null - ? _value.word - // ignore: cast_nullable_to_non_nullable - : word as String, - answer: answer == const $CopyWithPlaceholder() || answer == null - ? _value.answer - // ignore: cast_nullable_to_non_nullable - : answer as List, - answerIds: answerIds == const $CopyWithPlaceholder() || answerIds == null - ? _value.answerIds - // ignore: cast_nullable_to_non_nullable - : answerIds as List, - isCorrect: isCorrect == const $CopyWithPlaceholder() || isCorrect == null - ? _value.isCorrect - // ignore: cast_nullable_to_non_nullable - : isCorrect as bool, - isAnswered: - isAnswered == const $CopyWithPlaceholder() || isAnswered == null - ? _value.isAnswered - // ignore: cast_nullable_to_non_nullable - : isAnswered as bool, - isSkipped: isSkipped == const $CopyWithPlaceholder() || isSkipped == null - ? _value.isSkipped - // ignore: cast_nullable_to_non_nullable - : isSkipped as bool, - testType: testType == const $CopyWithPlaceholder() || testType == null - ? _value.testType - // ignore: cast_nullable_to_non_nullable - : testType as TestQuestionType, - ); - } -} - -extension $InputButtonsTestStateCopyWith on InputButtonsTestState { - /// Returns a callable class that can be used as follows: `instanceOfInputButtonsTestState.copyWith(...)` or like so:`instanceOfInputButtonsTestState.copyWith.fieldName(...)`. - // ignore: library_private_types_in_public_api - _$InputButtonsTestStateCWProxy get copyWith => - _$InputButtonsTestStateCWProxyImpl(this); -} - -// ************************************************************************** -// JsonSerializableGenerator -// ************************************************************************** - -InputButtonsTestState _$InputButtonsTestStateFromJson( - Map json) => - InputButtonsTestState( - seed: (json['seed'] as num).toInt(), - word: json['word'] as String, - answer: (json['answer'] as List?) - ?.map((e) => e as String) - .toList() ?? - const [], - answerIds: (json['answerIds'] as List?) - ?.map((e) => e as String) - .toList() ?? - const [], - isCorrect: json['isCorrect'] as bool? ?? false, - isAnswered: json['isAnswered'] as bool? ?? false, - isSkipped: json['isSkipped'] as bool? ?? false, - testType: - $enumDecodeNullable(_$TestQuestionTypeEnumMap, json['testType']) ?? - TestQuestionType.input_buttons, - ); - -Map _$InputButtonsTestStateToJson( - InputButtonsTestState instance) => - { - 'testType': _$TestQuestionTypeEnumMap[instance.testType]!, - 'word': instance.word, - 'answer': instance.answer, - 'answerIds': instance.answerIds, - 'isCorrect': instance.isCorrect, - 'isAnswered': instance.isAnswered, - 'isSkipped': instance.isSkipped, - 'seed': instance.seed, - }; - -const _$TestQuestionTypeEnumMap = { - TestQuestionType.simple: 'simple', - TestQuestionType.input_buttons: 'input_buttons', - TestQuestionType.matrix: 'matrix', - TestQuestionType.match: 'match', - TestQuestionType.undefined: 'undefined', -}; diff --git a/mnemo_cards/lib/features/tests/question_states/simple_test_state.dart b/mnemo_cards/lib/features/tests/question_states/simple_test_state.dart deleted file mode 100644 index 368e317..0000000 --- a/mnemo_cards/lib/features/tests/question_states/simple_test_state.dart +++ /dev/null @@ -1,27 +0,0 @@ - -import 'package:copy_with_extension/copy_with_extension.dart'; -import 'package:json_annotation/json_annotation.dart'; -import 'package:mnemo_cards/features/tests/question_states/test_question_state.dart'; -import 'package:mnemo_cards_common/mnemo_cards_common.dart'; - -part 'simple_test_state.g.dart'; - -@JsonSerializable() -@CopyWith() -class SimpleTestState extends TestQuestionState { - final String answer; - final bool isCorrect; - final bool isAnswered; - final bool isSkipped; - final int seed; - - SimpleTestState({ - required this.seed, - required super.word, - this.answer = '', - this.isCorrect = false, - this.isAnswered = false, - this.isSkipped = false, - super.testType = TestQuestionType.simple, - }); -} diff --git a/mnemo_cards/lib/features/tests/question_states/simple_test_state.g.dart b/mnemo_cards/lib/features/tests/question_states/simple_test_state.g.dart deleted file mode 100644 index 6219d63..0000000 --- a/mnemo_cards/lib/features/tests/question_states/simple_test_state.g.dart +++ /dev/null @@ -1,160 +0,0 @@ -// GENERATED CODE - DO NOT MODIFY BY HAND - -part of 'simple_test_state.dart'; - -// ************************************************************************** -// CopyWithGenerator -// ************************************************************************** - -abstract class _$SimpleTestStateCWProxy { - SimpleTestState seed(int seed); - - SimpleTestState word(String word); - - SimpleTestState answer(String answer); - - SimpleTestState isCorrect(bool isCorrect); - - SimpleTestState isAnswered(bool isAnswered); - - SimpleTestState isSkipped(bool isSkipped); - - SimpleTestState testType(TestQuestionType testType); - - /// This function **does support** nullification of nullable fields. All `null` values passed to `non-nullable` fields will be ignored. You can also use `SimpleTestState(...).copyWith.fieldName(...)` to override fields one at a time with nullification support. - /// - /// Usage - /// ```dart - /// SimpleTestState(...).copyWith(id: 12, name: "My name") - /// ```` - SimpleTestState call({ - int? seed, - String? word, - String? answer, - bool? isCorrect, - bool? isAnswered, - bool? isSkipped, - TestQuestionType? testType, - }); -} - -/// Proxy class for `copyWith` functionality. This is a callable class and can be used as follows: `instanceOfSimpleTestState.copyWith(...)`. Additionally contains functions for specific fields e.g. `instanceOfSimpleTestState.copyWith.fieldName(...)` -class _$SimpleTestStateCWProxyImpl implements _$SimpleTestStateCWProxy { - const _$SimpleTestStateCWProxyImpl(this._value); - - final SimpleTestState _value; - - @override - SimpleTestState seed(int seed) => this(seed: seed); - - @override - SimpleTestState word(String word) => this(word: word); - - @override - SimpleTestState answer(String answer) => this(answer: answer); - - @override - SimpleTestState isCorrect(bool isCorrect) => this(isCorrect: isCorrect); - - @override - SimpleTestState isAnswered(bool isAnswered) => this(isAnswered: isAnswered); - - @override - SimpleTestState isSkipped(bool isSkipped) => this(isSkipped: isSkipped); - - @override - SimpleTestState testType(TestQuestionType testType) => - this(testType: testType); - - @override - - /// This function **does support** nullification of nullable fields. All `null` values passed to `non-nullable` fields will be ignored. You can also use `SimpleTestState(...).copyWith.fieldName(...)` to override fields one at a time with nullification support. - /// - /// Usage - /// ```dart - /// SimpleTestState(...).copyWith(id: 12, name: "My name") - /// ```` - SimpleTestState call({ - Object? seed = const $CopyWithPlaceholder(), - Object? word = const $CopyWithPlaceholder(), - Object? answer = const $CopyWithPlaceholder(), - Object? isCorrect = const $CopyWithPlaceholder(), - Object? isAnswered = const $CopyWithPlaceholder(), - Object? isSkipped = const $CopyWithPlaceholder(), - Object? testType = const $CopyWithPlaceholder(), - }) { - return SimpleTestState( - seed: seed == const $CopyWithPlaceholder() || seed == null - ? _value.seed - // ignore: cast_nullable_to_non_nullable - : seed as int, - word: word == const $CopyWithPlaceholder() || word == null - ? _value.word - // ignore: cast_nullable_to_non_nullable - : word as String, - answer: answer == const $CopyWithPlaceholder() || answer == null - ? _value.answer - // ignore: cast_nullable_to_non_nullable - : answer as String, - isCorrect: isCorrect == const $CopyWithPlaceholder() || isCorrect == null - ? _value.isCorrect - // ignore: cast_nullable_to_non_nullable - : isCorrect as bool, - isAnswered: - isAnswered == const $CopyWithPlaceholder() || isAnswered == null - ? _value.isAnswered - // ignore: cast_nullable_to_non_nullable - : isAnswered as bool, - isSkipped: isSkipped == const $CopyWithPlaceholder() || isSkipped == null - ? _value.isSkipped - // ignore: cast_nullable_to_non_nullable - : isSkipped as bool, - testType: testType == const $CopyWithPlaceholder() || testType == null - ? _value.testType - // ignore: cast_nullable_to_non_nullable - : testType as TestQuestionType, - ); - } -} - -extension $SimpleTestStateCopyWith on SimpleTestState { - /// Returns a callable class that can be used as follows: `instanceOfSimpleTestState.copyWith(...)` or like so:`instanceOfSimpleTestState.copyWith.fieldName(...)`. - // ignore: library_private_types_in_public_api - _$SimpleTestStateCWProxy get copyWith => _$SimpleTestStateCWProxyImpl(this); -} - -// ************************************************************************** -// JsonSerializableGenerator -// ************************************************************************** - -SimpleTestState _$SimpleTestStateFromJson(Map json) => - SimpleTestState( - seed: (json['seed'] as num).toInt(), - word: json['word'] as String, - answer: json['answer'] as String? ?? '', - isCorrect: json['isCorrect'] as bool? ?? false, - isAnswered: json['isAnswered'] as bool? ?? false, - isSkipped: json['isSkipped'] as bool? ?? false, - testType: - $enumDecodeNullable(_$TestQuestionTypeEnumMap, json['testType']) ?? - TestQuestionType.simple, - ); - -Map _$SimpleTestStateToJson(SimpleTestState instance) => - { - 'testType': _$TestQuestionTypeEnumMap[instance.testType]!, - 'word': instance.word, - 'answer': instance.answer, - 'isCorrect': instance.isCorrect, - 'isAnswered': instance.isAnswered, - 'isSkipped': instance.isSkipped, - 'seed': instance.seed, - }; - -const _$TestQuestionTypeEnumMap = { - TestQuestionType.simple: 'simple', - TestQuestionType.input_buttons: 'input_buttons', - TestQuestionType.matrix: 'matrix', - TestQuestionType.match: 'match', - TestQuestionType.undefined: 'undefined', -}; diff --git a/mnemo_cards/lib/features/tests/question_states/test_question_state.dart b/mnemo_cards/lib/features/tests/question_states/test_question_state.dart deleted file mode 100644 index 647d975..0000000 --- a/mnemo_cards/lib/features/tests/question_states/test_question_state.dart +++ /dev/null @@ -1,23 +0,0 @@ -import 'package:copy_with_extension/copy_with_extension.dart'; -import 'package:mnemo_cards_common/mnemo_cards_common.dart'; - -part 'test_question_state.g.dart'; - -@CopyWith() -class TestQuestionState { - final TestQuestionType testType; - - bool get isCorrect => false; - - // isAnswered == not skipped by scrolling - final bool isAnswered; - final bool isSkipped; - final String word; - - const TestQuestionState({ - required this.testType, - required this.word, - this.isAnswered = false, - this.isSkipped = false, - }); -} diff --git a/mnemo_cards/lib/features/tests/question_states/test_question_state.g.dart b/mnemo_cards/lib/features/tests/question_states/test_question_state.g.dart deleted file mode 100644 index ca225d9..0000000 --- a/mnemo_cards/lib/features/tests/question_states/test_question_state.g.dart +++ /dev/null @@ -1,92 +0,0 @@ -// GENERATED CODE - DO NOT MODIFY BY HAND - -part of 'test_question_state.dart'; - -// ************************************************************************** -// CopyWithGenerator -// ************************************************************************** - -abstract class _$TestQuestionStateCWProxy { - TestQuestionState testType(TestQuestionType testType); - - TestQuestionState word(String word); - - TestQuestionState isAnswered(bool isAnswered); - - TestQuestionState isSkipped(bool isSkipped); - - /// This function **does support** nullification of nullable fields. All `null` values passed to `non-nullable` fields will be ignored. You can also use `TestQuestionState(...).copyWith.fieldName(...)` to override fields one at a time with nullification support. - /// - /// Usage - /// ```dart - /// TestQuestionState(...).copyWith(id: 12, name: "My name") - /// ```` - TestQuestionState call({ - TestQuestionType? testType, - String? word, - bool? isAnswered, - bool? isSkipped, - }); -} - -/// Proxy class for `copyWith` functionality. This is a callable class and can be used as follows: `instanceOfTestQuestionState.copyWith(...)`. Additionally contains functions for specific fields e.g. `instanceOfTestQuestionState.copyWith.fieldName(...)` -class _$TestQuestionStateCWProxyImpl implements _$TestQuestionStateCWProxy { - const _$TestQuestionStateCWProxyImpl(this._value); - - final TestQuestionState _value; - - @override - TestQuestionState testType(TestQuestionType testType) => - this(testType: testType); - - @override - TestQuestionState word(String word) => this(word: word); - - @override - TestQuestionState isAnswered(bool isAnswered) => this(isAnswered: isAnswered); - - @override - TestQuestionState isSkipped(bool isSkipped) => this(isSkipped: isSkipped); - - @override - - /// This function **does support** nullification of nullable fields. All `null` values passed to `non-nullable` fields will be ignored. You can also use `TestQuestionState(...).copyWith.fieldName(...)` to override fields one at a time with nullification support. - /// - /// Usage - /// ```dart - /// TestQuestionState(...).copyWith(id: 12, name: "My name") - /// ```` - TestQuestionState call({ - Object? testType = const $CopyWithPlaceholder(), - Object? word = const $CopyWithPlaceholder(), - Object? isAnswered = const $CopyWithPlaceholder(), - Object? isSkipped = const $CopyWithPlaceholder(), - }) { - return TestQuestionState( - testType: testType == const $CopyWithPlaceholder() || testType == null - ? _value.testType - // ignore: cast_nullable_to_non_nullable - : testType as TestQuestionType, - word: word == const $CopyWithPlaceholder() || word == null - ? _value.word - // ignore: cast_nullable_to_non_nullable - : word as String, - isAnswered: - isAnswered == const $CopyWithPlaceholder() || isAnswered == null - ? _value.isAnswered - // ignore: cast_nullable_to_non_nullable - : isAnswered as bool, - isSkipped: isSkipped == const $CopyWithPlaceholder() || isSkipped == null - ? _value.isSkipped - // ignore: cast_nullable_to_non_nullable - : isSkipped as bool, - ); - } -} - -extension $TestQuestionStateCopyWith on TestQuestionState { - /// Returns a callable class that can be used as follows: `instanceOfTestQuestionState.copyWith(...)` or like so:`instanceOfTestQuestionState.copyWith.fieldName(...)`. - // ignore: library_private_types_in_public_api - _$TestQuestionStateCWProxy get copyWith => - _$TestQuestionStateCWProxyImpl(this); -} diff --git a/mnemo_cards/lib/features/tests/scroll_physics.dart b/mnemo_cards/lib/features/tests/scroll_physics.dart deleted file mode 100644 index 831a957..0000000 --- a/mnemo_cards/lib/features/tests/scroll_physics.dart +++ /dev/null @@ -1,167 +0,0 @@ -import 'package:flutter/material.dart'; - -/// This [ScrollPhysics] allows you to block the movement in the horizontal axis. -/// You can block both right and left movements. -/// -/// {@tool sample} -/// -/// This sample shows a [HorizontalBlockedScrollPhysics] blocking left movement -/// -/// ```dart -/// HorizontalBlockedScrollPhysics(blockLeftMovent: true, blockRightMovement: false); -/// ``` -/// {@end-tool} -class HorizontalBlockedScrollPhysics extends ScrollPhysics { - /// If [true] it blocks the left movement. - final bool blockLeftMovement; - - /// If [true] it blocks the right movement. - final bool blockRightMovement; - - final ValueGetter? canScroll; - - const HorizontalBlockedScrollPhysics({ - ScrollPhysics? parent, - this.blockLeftMovement = false, - this.blockRightMovement = false, - this.canScroll, - }) : super(parent: parent); - - @override - HorizontalBlockedScrollPhysics applyTo(ScrollPhysics? ancestor) { - return HorizontalBlockedScrollPhysics( - parent: buildParent(ancestor), - blockLeftMovement: blockLeftMovement, - blockRightMovement: blockRightMovement, - ); - } - - @override - bool get allowUserScrolling => (canScroll == null || canScroll!.call()); - - @override - bool get allowImplicitScrolling => (canScroll == null || canScroll!.call()); - - @override - double applyBoundaryConditions(ScrollMetrics position, double value) { - assert(() { - if (value == position.pixels) { - throw FlutterError( - '$runtimeType.applyBoundaryConditions() was called redundantly.\n' - 'The proposed new position, $value, is exactly equal to the current position of the ' - 'given ${position.runtimeType}, ${position.pixels}.\n' - 'The applyBoundaryConditions method should only be called when the value is ' - 'going to actually change the pixels, otherwise it is redundant.\n' - 'The physics object in question was:\n' - ' $this\n' - 'The position object in question was:\n' - ' $position\n'); - } - return true; - }()); - - if (value < position.pixels && - position.pixels <= position.minScrollExtent) { - return value - position.pixels; - } - - if (position.maxScrollExtent <= position.pixels && - position.pixels < value) { - // overscroll - return value - position.pixels; - } - - if (value < position.minScrollExtent && - position.minScrollExtent < position.pixels) { - // hit top edge - return value - position.minScrollExtent; - } - - if (position.pixels < position.maxScrollExtent && - position.maxScrollExtent < value) { - // hit bottom edge - return value - position.maxScrollExtent; - } - - // If true, movement goes to the left. If it's a swipe, it goes to the left. - var isMovingLeft = value > position.pixels; - var screenIndex = (value / position.viewportDimension).floor(); - var pointInScreen = value - (screenIndex * position.viewportDimension); - // If true, the middle point of the screen is in the left side of the screen. - // This will be useful in order to not block some movements when in returning position. - var isPointInScreenLeftRange = - pointInScreen < (position.viewportDimension / 2); - var delta = value - position.pixels; - - // We're moving left and we want to block. - if (isMovingLeft && blockLeftMovement && isPointInScreenLeftRange) { - if (pointInScreen.abs() < delta.abs()) { - // fix for strong movements - return pointInScreen; - } - return delta; - } - - // We're moving right and we want to block. - if (!isMovingLeft && blockRightMovement && !isPointInScreenLeftRange) { - if (pointInScreen.abs() < delta.abs()) { - // fix for strong movements - return pointInScreen; - } - return delta; - } - - if (canScroll != null && !canScroll!.call()) { - return delta; - } - - return super.applyBoundaryConditions(position, value); - } -} - -/// This [ScrollPhysics] blocks the left movement in the horizontal axis allowing only movements to the right. -/// -/// {@tool sample} -/// -/// This sample shows a [LeftBlockedScrollPhysics] blocking left movement -/// -/// ```dart -/// LeftBlockedScrollPhysics(); -/// ``` -/// {@end-tool} -class LeftBlockedScrollPhysics extends HorizontalBlockedScrollPhysics { - const LeftBlockedScrollPhysics({ - ScrollPhysics? parent, - }) : super(parent: parent, blockLeftMovement: true); - - @override - LeftBlockedScrollPhysics applyTo(ScrollPhysics? ancestor) { - return LeftBlockedScrollPhysics( - parent: buildParent(ancestor), - ); - } -} - -// This [ScrollPhysics] blocks the right movement in the horizontal axis allowing only movements to the left. -/// -/// {@tool sample} -/// -/// This sample shows a [RightBlockedScrollPhysics] blocking right movement -/// -/// ```dart -/// RightBlockedScrollPhysics(); -/// ``` -/// {@end-tool} -class RightBlockedScrollPhysics extends HorizontalBlockedScrollPhysics { - const RightBlockedScrollPhysics({ - ScrollPhysics? parent, - ValueGetter? canScroll, - }) : super(parent: parent, canScroll: canScroll, blockRightMovement: true); - - @override - RightBlockedScrollPhysics applyTo(ScrollPhysics? ancestor) { - return RightBlockedScrollPhysics( - parent: buildParent(ancestor), - ); - } -} diff --git a/mnemo_cards/lib/features/tests/test_complete_widget.dart b/mnemo_cards/lib/features/tests/test_complete_widget.dart deleted file mode 100644 index d000fc0..0000000 --- a/mnemo_cards/lib/features/tests/test_complete_widget.dart +++ /dev/null @@ -1,206 +0,0 @@ -import 'dart:math'; - -import 'package:fl_chart/fl_chart.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_screenutil/flutter_screenutil.dart'; -import 'package:mnemo_cards/utils/color_helper.dart'; -import 'package:mnemo_cards_frontend_common/mnemo_cards_frontend_common.dart'; -import 'package:rxdart/rxdart.dart'; - -import '../../di/locator.dart'; -import 'question_states/test_question_state.dart'; - -class TestCompleteWidget extends StatelessWidget { - final Iterable states; - final Color successColor; - - static final _pieChartKey = GlobalKey(); - - TestCompleteWidget( - this.states, - this.successColor, - ); - - @override - Widget build(BuildContext context) { - final total = states.length; - final correct = states.where((e) => e.isCorrect).length; - final incorrect = states.where((e) => !e.isCorrect && e.isAnswered).length; - final skipped = states.where((e) => !e.isAnswered).length; - - final words = states - .fold( - Map(), - (map, state) => map - ..[state.word] = (map[state.word] ?? WordStat.zero(state.word)) - .inc(state.isCorrect), - ) - .values - .toList() - ..sort( - (p, n) => (p.correctCount.toDouble() / p.totalCount) - .compareTo(n.correctCount.toDouble() / n.totalCount), - ); - return PopScope( - onPopInvoked: (v) async { - if (v) { - await locator.testManager.sendStatistics(); - // locator.testManager.pollTests(packId: ); - } - }, - child: Column( - children: [ - Expanded( - flex: 20, - child: Padding( - padding: const EdgeInsets.only(top: 12.0), - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Container( - width: MediaQuery.of(context).size.width / 1.8, - height: MediaQuery.of(context).size.width / 1.8, - padding: const EdgeInsets.all(20.0), - child: StreamBuilder( - stream: Stream.fromIterable([5]) - .interval(Duration(milliseconds: 0)), - initialData: 0, - builder: (context, snapshot) { - final a = min(snapshot.requireData / 5.0, 1.0); - return PieChart( - key: _pieChartKey, - swapAnimationDuration: Duration(milliseconds: 600), - PieChartData( - pieTouchData: PieTouchData(), - borderData: FlBorderData( - show: false, - ), - sectionsSpace: 0, - centerSpaceRadius: - MediaQuery.of(context).size.width / 8, - sections: [ - PieChartSectionData( - color: successColor, - showTitle: false, - value: correct.toDouble() * a, - badgeWidget: Image.asset( - 'icons/crown.webp', - width: 20.w, - color: Theme.of(context).colorScheme.primary - ), - ), - PieChartSectionData( - color: successColor.lighten(0.15), - showTitle: false, - value: incorrect.toDouble() * a, - badgeWidget: Image.asset( - 'icons/skull.webp', - width: 20.w, - color: Theme.of(context).colorScheme.primary - ), - ), - PieChartSectionData( - color: Theme.of(context).scaffoldBackgroundColor, - showTitle: false, - value: skipped.toDouble(), - badgeWidget: Image.asset( - 'icons/small_circle.webp', - width: 20.w, - color: Theme.of(context).colorScheme.primary, - ), - ), - ], - ), - ); - }), - ), - Text( - '$correct/$total', - style: TextStyle( - fontSize: 36, - fontWeight: FontWeight.w700, - ), - ), - // Text( - // '1:47', - // style: TextStyle( - // fontSize: 20, - // fontWeight: FontWeight.w700, - // height: 0.85, - // ), - // ), - ], - ), - ), - ), - Expanded( - flex: 20, - child: Container( - alignment: Alignment.bottomCenter, - child: ListView.builder( - shrinkWrap: true, - itemCount: words.length, - itemBuilder: (context, index) { - final word = words[index]; - return Padding( - padding: const EdgeInsets.only( - left: 12.0, - right: 24, - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - '${word.word}', - style: TextStyle( - fontSize: 24, - fontWeight: FontWeight.w700, - ), - ), - Flexible( - child: SizedBox( - width: MediaQuery.of(context).size.width / 2.5, - child: HorizontalProgressWidget( - word.correctCount, - word.totalCount, - successColor, - ), - ), - ), - ], - ), - ); - }, - ), - ), - ), - const BigBackButton(), - ], - ), - ); - } -} - -class WordStat { - String word; - int correctCount; - int totalCount; - - WordStat(this.word, this.correctCount, this.totalCount); - - factory WordStat.zero(String word) => WordStat(word, 0, 0); - - WordStat inc(bool isCorrect) => isCorrect ? correct(this) : incorrect(this); - - WordStat correct(WordStat stat) => WordStat( - stat.word, - stat.correctCount + 1, - stat.totalCount + 1, - ); - - WordStat incorrect(WordStat stat) => WordStat( - stat.word, - stat.correctCount, - stat.totalCount + 1, - ); -} diff --git a/mnemo_cards/lib/features/tests/test_manager.dart b/mnemo_cards/lib/features/tests/test_manager.dart deleted file mode 100644 index 57e2b1f..0000000 --- a/mnemo_cards/lib/features/tests/test_manager.dart +++ /dev/null @@ -1,183 +0,0 @@ -import 'dart:async'; -import 'dart:developer'; -import 'package:collection/collection.dart' show ListEquality; - -import 'package:flutter/widgets.dart'; -import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:mnemo_cards/features/tests/test_state_holder.dart'; -import 'package:mnemo_cards/features/tests/test_widgets/test_image.dart'; -import 'package:mnemo_cards/features/packs/pack_cache_manager.dart'; -import 'package:mnemo_cards/features/tests/tests_cache.dart'; -import 'package:mnemo_cards/main.dart'; -import 'package:mnemo_cards/theme/themes.dart'; -import 'package:mnemo_cards/utils/string_helper.dart'; -import 'package:mnemo_cards_common/mnemo_cards_common.dart'; -import 'package:rxdart/rxdart.dart'; - -import '../../managers/repository/http_repository.dart'; -import 'question_states/test_question_state.dart'; - -class TestManager extends Cubit { - final PackCacheManager packCacheManager; - final HttpRepository _repository; - final TestsCache _testsCache; - - final PageController pageController = PageController(); - final ActiveTestHolder testHolder = ActiveTestHolder(); - - TestDto? _activeTest; - - Color get color => _activeTest?.color?.asColor ?? borderGray; - - List get questions => _activeTest?.questions ?? []; - - Future pollTests({required String packId}) async { - emit(PackTestState.empty()); - final cache = await _testsCache.loadTestFromCache(packId); - if (cache != null) { - emit(PackTestState(cache)); - } - print('polling tests'); - final tests = (await _repository.getTests(packId: packId)); - _testsCache.savePackTests(packId, tests); - if (!const ListEquality().equals(cache, tests)) { - emit(PackTestState(tests)); - } - } - - void skip(int id) => testHolder.skip(id); - - TestQuestionState? getState(int id) => testHolder.testQuestionState(id); - - Iterable get states => testHolder.state.questions.values; - - Future setActiveTest(String id, {String? packId}) async { - clearStates(); - if (packId != null) { - await packCacheManager.loadPackFromCache(packId); - } - try { - _activeTest = await _repository.getTest(id); - } on Object catch (e, s) { - log('error when loading test ${id}', error: e, stackTrace: s); - } - if (_activeTest == null) { - appRouter.maybePop(); - return; - } - // todo use uuid - testHolder.setQuestions( - _activeTest!.questions, - DateTime.timestamp().toString(), - ); - } - - void setState(int id, TestQuestionState state) { - testHolder.setQuestionState(id, state); - log('Set state $id $state'); - } - - TestManager( - this.packCacheManager, - this._repository, - this._testsCache, - ) : super(PackTestState.empty()); - - void clearStates() => testHolder.clear(); - - AbstractTestQuestion getTest(int index) => questions[index]; - - void nextTest() { - pageController.animateToPage( - pageController.page!.toInt() + 1, - duration: Duration(milliseconds: 300), - curve: Curves.ease, - ); - } - - void prevTest() { - pageController.animateToPage( - pageController.page!.toInt() - 1, - duration: Duration(milliseconds: 300), - curve: Curves.ease, - ); - } - - Future preloadImages(BuildContext context) async { - for (final question in questions) { - switch (question.questionType) { - case TestQuestionType.simple: - final images = [ - (question as SimpleTestQuestionBody).image, - ...question.buttons.map((e) => e.image) - ].whereNotNull(); - for (final image in images) { - try { - final testImage = TestImage.image(image); - await precacheImage( - (await testImage.loadImage())!, - context, - ); - } catch (e) { - rethrow; - } - } - case TestQuestionType.input_buttons: - final images = [ - (question as InputButtonsTestQuestionBody).image, - ].whereNotNull(); - for (final image in images) { - try { - final testImage = TestImage.image(image); - await precacheImage( - (await testImage.loadImage())!, - context, - ); - } catch (e) { - rethrow; - } - } - case TestQuestionType.matrix: - case TestQuestionType.match: - case TestQuestionType.undefined: - } - } - } - - Future loadImage(String packId, String path) async { - final bytes = await packCacheManager.loadPackFile(packId, path); - return MemoryImage(bytes!); - } - - Future sendStatistics() { - final words = states - .fold({}, (stats, s) { - final existStat = stats[s.word] ?? WordStatisticsDto.empty(s.word); - stats[s.word] = existStat.copyWith( - correct: existStat.correct + (s.isCorrect ? 1 : 0), - incorrect: - existStat.incorrect + ((!s.isCorrect && s.isAnswered) ? 1 : 0), - skipped: existStat.skipped + (s.isAnswered ? 0 : 1), - questionTypes: {...existStat.questionTypes, s.testType}, - ); - return stats; - }) - .values - .toList(); - - final dto = TestStatisticsDto( - testId: int.tryParse(_activeTest?.id ?? '') ?? -1, - words: AllWordsStatisticsDto(words: words), - sessionToken: testHolder.state.sessionToken, - ); - return _repository.addTestStatistics(dto); - } -} - -class PackTestState { - final List dtos; - - PackTestState(this.dtos); - - PackTestState.empty() : dtos = []; -} diff --git a/mnemo_cards/lib/features/tests/test_page.dart b/mnemo_cards/lib/features/tests/test_page.dart deleted file mode 100644 index 5942c16..0000000 --- a/mnemo_cards/lib/features/tests/test_page.dart +++ /dev/null @@ -1,207 +0,0 @@ -import 'package:auto_route/auto_route.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:flutter_screenutil/flutter_screenutil.dart'; -import 'package:mnemo_cards/features/tests/test_state_holder.dart'; -import 'package:mnemo_cards/main.dart'; -import 'package:mnemo_cards/managers/audio_player.dart'; -import 'package:mnemo_cards_common/mnemo_cards_common.dart'; - -import '../../di/locator.dart'; -import 'scroll_physics.dart'; -import 'test_complete_widget.dart'; -import 'test_progress_widget.dart'; -import 'test_widgets/input_buttons_test.dart'; -import 'test_widgets/simple_test.dart'; - -@RoutePage() -class TestPage extends StatefulWidget { - final String testId; - - @override - State createState() => _TestPageState(); - - TestPage(this.testId); -} - -class _TestPageState extends State { - PageController get pageController => locator.testManager.pageController; - - int? lastSkipIndex; - int? _lastAudioQuestionId; - - @override - void initState() { - super.initState(); - locator.testManager.setActiveTest(widget.testId); - locator.testManager.preloadImages(context); - pageController.addListener(_pageScrollListener); - } - - @override - void dispose() { - pageController.removeListener(_pageScrollListener); - super.dispose(); - } - - void _pageScrollListener() { - if (!pageController.hasClients) { - return; - } - final index = pageController.page!.floor(); - print('Current index $index, lastAudio $_lastAudioQuestionId'); - - if (index < locator.testManager.questions.length) { - final question = locator.testManager.questions[index]; - if (question.id != _lastAudioQuestionId) { - print('AUDIO $_lastAudioQuestionId ${question.id}'); - _lastAudioQuestionId = question.id; - try { - if (globalSharedPreferences.getBool('auto_play_sound_tests') != - false) { - String? audio; - if (question is SimpleTestQuestionBody) { - audio = question.audio; - } else if (question is InputButtonsTestQuestionBody) { - audio = question.audio; - } - if (audio != null) { - AudioPlayer.playAudio(audio); - } - } - } catch (e) {} - } - } - - if (index == lastSkipIndex) { - return; - } - print('Will try to skip $index, ${locator.testManager.questions.length}'); - if (index > 0 && index <= locator.testManager.questions.length) { - final prevId = locator.testManager.questions[index - 1].id!; - final state = locator.testManager.getState(prevId); - if (state?.isAnswered == false) { - print('Skipping $index ${state?.word}'); - locator.testManager.skip(prevId); - lastSkipIndex = index; - } - } - } - - @override - Widget build(BuildContext context) { - return Scaffold( - body: BlocBuilder( - buildWhen: (p, n) => p.isEmpty != n.isEmpty, - bloc: locator.testManager.testHolder, - builder: (context, activeState) { - if (activeState.isEmpty) { - return Scaffold( - body: Center( - child: Text('Загружаю тест...'), - ), - ); - } - - WidgetsBinding.instance.addPostFrameCallback((_) { - _pageScrollListener(); - }); - - final keys = List.generate( - locator.testManager.questions.length, - (v) => GlobalKey( - debugLabel: locator.testManager.questions[v].word, - ), - ); - - return Scaffold( - backgroundColor: locator.testManager.color.withOpacity(0.25), - body: SafeArea( - child: Builder(builder: (context) { - return Column( - children: [ - SizedBox( - height: (64.h - - 20.h - - MediaQuery.of(context).padding.top) / - 2, - ), - Padding( - padding: EdgeInsets.symmetric(horizontal: 10.0.w), - child: const TestProgressWidget(), - ), - Expanded( - child: PageView.builder( - physics: RightBlockedScrollPhysics( - canScroll: _canScroll, - ), - controller: locator.testManager.pageController, - itemBuilder: (context, index) { - if (index > - locator.testManager.questions.length) { - return null; - } - if (index == - locator.testManager.questions.length) { - return TestCompleteWidget( - locator.testManager.states, - locator.testManager.color, - - ); - } - final question = - locator.testManager.getTest(index); - return switch (question.questionType) { - TestQuestionType.simple => SimpleTestWidget( - question as SimpleTestQuestionBody, - key: keys[index], - ), - TestQuestionType.input_buttons => - InputButtonsTestWidget( - question as InputButtonsTestQuestionBody, - key: keys[index], - ), - TestQuestionType.matrix => Container(), - TestQuestionType.match => Container(), - // TODO: Handle this case. - TestQuestionType.undefined => - throw UnimplementedError(), - }; - }, - ), - ), - ], - ); - }), - ), - ); - }), - ); - } - - bool _canScroll() { - return locator.testManager.pageController.hasClients && - locator.testManager.pageController.page != - locator.testManager.questions.length; - } -} - -class _LifeWidget extends StatelessWidget { - @override - Widget build(BuildContext context) { - return Row( - mainAxisAlignment: MainAxisAlignment.end, - mainAxisSize: MainAxisSize.max, - children: [ - Icon(Icons.ac_unit_outlined), - SizedBox( - width: 2, - ), - Text( - '30', - style: TextStyle(fontSize: 22), - ) - ], - ); - } -} diff --git a/mnemo_cards/lib/features/tests/test_progress_widget.dart b/mnemo_cards/lib/features/tests/test_progress_widget.dart deleted file mode 100644 index 9d28210..0000000 --- a/mnemo_cards/lib/features/tests/test_progress_widget.dart +++ /dev/null @@ -1,80 +0,0 @@ -import 'dart:async'; - -import 'package:flutter/cupertino.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter/widgets.dart'; -import 'package:mnemo_cards/features/tests/progress_widget.dart'; - -import '../../di/locator.dart'; - -class TestProgressWidget extends StatefulWidget { - @override - State createState() => _TestProgressWidgetState(); - - const TestProgressWidget({super.key}); -} - -class _TestProgressWidgetState extends State { - List results = []; - int length = 0; - - Stream? timer; - - bool _active = false; - - void _updateDataListener() { - if (!_active) { - _active = true; - Timer(Duration(milliseconds: 100), () => _updateData()); - } - } - - void _updateData() { - results = [ - Result.correct, - ]; - length = locator.testManager.questions.length + 1; - final pageController = locator.testManager.pageController; - for (final state in locator.testManager.states) { - if (state.isAnswered) { - if (state.isCorrect) { - results.add(Result.correct); - } else { - // results.add(Result.wrong); - results.add(Result.wrong); - } - } else if (state.isSkipped) { - results.add(Result.skiped); - } else { - results.add(Result.not_visited); - } - } - print('Update data ${results.map((e) => e.name).join(' ')}'); - if (mounted) { - setState(() {}); - } - _active = false; - } - - @override - void initState() { - super.initState(); - locator.testManager.pageController.removeListener(_updateDataListener); - locator.testManager.pageController.addListener(_updateDataListener); - // timer = Stream.periodic( - // Duration(seconds: 1), - // (tick) => Duration(seconds: 300 - tick - 1), - // ).startWith(Duration(seconds: 300)).take(300); - _updateData(); - } - - @override - Widget build(BuildContext context) { - return ProgressWidget( - results, - length, - locator.testManager.color, - timer: timer, - ); - } -} diff --git a/mnemo_cards/lib/features/tests/test_state_holder.dart b/mnemo_cards/lib/features/tests/test_state_holder.dart deleted file mode 100644 index 0fd2847..0000000 --- a/mnemo_cards/lib/features/tests/test_state_holder.dart +++ /dev/null @@ -1,100 +0,0 @@ -import 'dart:async'; -import 'dart:math'; - -import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:mnemo_cards_common/mnemo_cards_common.dart'; -import 'package:rxdart/rxdart.dart'; - -import 'question_states/input_buttons_test_state.dart'; -import 'question_states/simple_test_state.dart'; -import 'question_states/test_question_state.dart'; - -class ActiveTestHolder extends Cubit { - ActiveTestHolder() : super(ActiveTestState.empty()); - - void skip(int id) { - final state = testQuestionState(id); - print('Skipping $id ${state} ${state?.testType}'); - switch (state?.testType) { - case TestQuestionType.simple: - state as SimpleTestState; - print('Skipped $id ${state.word}'); - setQuestionState(id, state.copyWith(isSkipped: true)); - break; - case TestQuestionType.input_buttons: - state as InputButtonsTestState; - print('Skipped $id ${state.word}'); - setQuestionState(id, state.copyWith(isSkipped: true)); - break; - case TestQuestionType.matrix: - // TODO: Handle this case. - break; - case TestQuestionType.match: - // TODO: Handle this case. - break; - case TestQuestionType.undefined: - // TODO: Handle this case. - case null: - // TODO: Handle this case. - break; - } - } - - void setQuestionState(int id, TestQuestionState questionState) { - emit( - ActiveTestState( - Map.from(state.questions)..[id] = questionState, - state.sessionToken, - ), - ); - } - - void clear() { - emit(ActiveTestState({}, null)); - } - - void setQuestions( - List questions, - String? sessionToken, - ) { - final stateQuestions = {}; - final seed = Random().nextInt(999); - for (final question in questions) { - switch (question.questionType) { - case TestQuestionType.simple: - stateQuestions[question.id!] = SimpleTestState( - seed: seed, - word: question.word, - ); - case TestQuestionType.input_buttons: - stateQuestions[question.id!] = InputButtonsTestState( - seed: seed, - word: question.word, - ); - case TestQuestionType.matrix: - case TestQuestionType.match: - case TestQuestionType.undefined: - // not supported - } - } - emit(ActiveTestState(stateQuestions, sessionToken)); - } - - TestQuestionState? testQuestionState(int id) => state.questions[id]; - - Stream get asStream => stream.startWith(state); - - Stream questionStream(int id) => - asStream.map((state) => state.questions[id]).distinct(); -} - -class ActiveTestState { - final String? sessionToken; - final Map questions; - - bool get isEmpty => sessionToken == null; - - ActiveTestState(this.questions, this.sessionToken); - - factory ActiveTestState.empty() => ActiveTestState({}, null); -} diff --git a/mnemo_cards/lib/features/tests/test_widgets/common_test_question_widget.dart b/mnemo_cards/lib/features/tests/test_widgets/common_test_question_widget.dart deleted file mode 100644 index ffa08a1..0000000 --- a/mnemo_cards/lib/features/tests/test_widgets/common_test_question_widget.dart +++ /dev/null @@ -1,118 +0,0 @@ -import 'package:auto_size_text/auto_size_text.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_screenutil/flutter_screenutil.dart'; -import 'package:mnemo_cards/managers/audio_player.dart'; - -import '../../../widgets/game_card_widget.dart'; -import 'test_image.dart'; - -class CommonTestQuestionWidget extends StatelessWidget { - final String? text; - final String? image; - final String? audio; - - const CommonTestQuestionWidget({ - this.text, - this.image, - this.audio, - super.key, - }); - - @override - Widget build(BuildContext context) { - final theme = Theme.of(context).textTheme; - - return Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - if (image != null) - Flexible( - child: Container( - alignment: Alignment.center, - margin: const EdgeInsets.all(4.0), - decoration: BoxDecoration( - borderRadius: - BorderRadius.circular(GameCardWidget.borderRadius), - ), - child: AspectRatio( - aspectRatio: text == null ? 1 : 1.5, - child: Stack( - alignment: Alignment.center, - children: [ - TestImageWidget( - TestImage.image(image!), - ), - if (audio != null && text == null) - Container( - padding: EdgeInsets.all(4.0.h), - alignment: Alignment.topRight, - child: IconButton( - icon: Image.asset( - 'icons/sound_on.webp', - width: 26, - color: Theme.of(context).colorScheme.primary, - ), - onPressed: () => AudioPlayer.playAudio(audio), - ), - ), - ], - ), - ), - ), - ) - else if (text == null && audio != null) - Flexible( - child: Center( - child: IconButton( - icon: Image.asset( - 'icons/sound_on.webp', - width: 80, - height: 80, - color: Theme.of(context).colorScheme.primary, - ), - onPressed: () => AudioPlayer.playAudio(audio), - ), - ), - ), - if (text != null && audio != null) - Container( - alignment: Alignment.center, - padding: const EdgeInsets.only(top: 8.0), - child: Row( - mainAxisSize: MainAxisSize.min, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text( - text!, - style: theme.headlineLarge, - ), - if (audio != null) - Container( - padding: EdgeInsets.only(left: 4.w, top: 4.h), - child: IconButton( - icon: Image.asset( - 'icons/sound_on.webp', - width: 26, - color: Theme.of(context).colorScheme.primary, - height: theme.headlineLarge?.fontSize, - ), - onPressed: () => AudioPlayer.playAudio(audio), - ), - ) - ], - ), - ) - else if (text != null) - Container( - alignment: Alignment.center, - padding: const EdgeInsets.only(top: 8.0), - child: AutoSizeText( - text!, - style: theme.headlineLarge, - textAlign: TextAlign.center, - ), - ), - ], - ); - } -} diff --git a/mnemo_cards/lib/features/tests/test_widgets/input_buttons_test.dart b/mnemo_cards/lib/features/tests/test_widgets/input_buttons_test.dart deleted file mode 100644 index be860c5..0000000 --- a/mnemo_cards/lib/features/tests/test_widgets/input_buttons_test.dart +++ /dev/null @@ -1,310 +0,0 @@ -import 'package:collection/collection.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:mnemo_cards/features/tests/test_manager.dart'; -import 'package:mnemo_cards/features/tests/test_widgets/common_test_question_widget.dart'; -import 'package:mnemo_cards_common/mnemo_cards_common.dart' - hide NullableIterableHelper; -import '../../../di/locator.dart'; -import '../question_states/input_buttons_test_state.dart'; -import '../test_state_holder.dart'; -import 'test_button.dart'; - -class InputButtonsTestWidget extends StatelessWidget { - final InputButtonsTestQuestionBody _inputButtonModel; - - InputButtonsTestQuestionBody get model => _inputButtonModel; - - InputButtonsTestState get state => - manager.getState(model.id!) as InputButtonsTestState; - - TestManager get manager => locator.testManager; - - InputButtonsTestWidget(this._inputButtonModel, {super.key}); - - @override - Widget build(BuildContext context) { - return BlocBuilder( - buildWhen: (p, n) => p.questions[model.id] != n.questions[model.id], - bloc: locator.testManager.testHolder, - builder: (context, activeTestState) { - return Padding( - padding: const EdgeInsets.all(8.0), - child: LayoutBuilder( - builder: (context, constraints) { - return Column( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Expanded( - flex: 2, - child: CommonTestQuestionWidget( - text: model.text, - image: model.image, - audio: model.audio, - ), - ), - Expanded( - flex: 3, - child: _InputButtons( - activeTestState, - model, - manager, - ), - ), - ], - ); - }, - ), - ); - }, - ); - } -} - -class _InputButtons extends StatelessWidget { - final ActiveTestState activeTestState; - final InputButtonsTestQuestionBody model; - final TestManager manager; - - bool isCorrect(List answer) => - stateAnswer(answer).toLowerCase() == model.answer.toLowerCase(); - - String stateAnswer(List answer) => answer.fold( - model.template, (template, answer) => template.replaceFirst('_', answer)); - - Color get testColor => manager.color; - - _InputButtons(this.activeTestState, this.model, this.manager); - - InputButtonsTestState get state => - manager.getState(model.id!) as InputButtonsTestState; - - void buttonTapped(int index, TestButtonDto button) { - if (state.answer.length >= '_'.allMatches(model.template).length) { - return; - } - var answer = [...state.answer, button.text!]; - final isCorrect = model.answer == stateAnswer(answer); - manager.setState( - model.id!, - state.copyWith( - answer: answer, - answerIds: [...state.answerIds, button.id], - isAnswered: isCorrect, - isCorrect: isCorrect, - ), - ); - print('${state.answer} ${model.answer} ${state.isCorrect}'); - if (isCorrect) { - Future.delayed( - Duration(milliseconds: 300), - manager.nextTest, - ); - } - } - - @override - Widget build(BuildContext context) { - final buttons = model.buttons; //..shuffle(random); - return LayoutBuilder( - builder: (context, constraints) { - final splitIndex = splitRow(constraints); - final stringRows = [ - if (splitIndex > 0) model.template.substring(0, splitIndex), - model.template.substring(splitIndex), - ]; - int stateAnswerIndex = 0; - final letters = stringRows.map( - (row) => row.split(RegExp('(?=_)|(?<=_)')).map( - (letter) => letter == '_' - ? _Letter( - text: state.answer.length > stateAnswerIndex - ? state.answer[stateAnswerIndex++] - : ' ', - borderColor: testColor, - width: (model.buttons - .map((b) => b.text?.length ?? 0) - .maxOrNull ?? - 1.0) - .let((count) => count == 1 ? 26 : count * 18) + - 8.0, - ) - : _Letter.readOnly( - text: letter, - ), - ), - ); - final rows = [ - if (splitIndex > 0) - Padding( - padding: const EdgeInsets.only(bottom: 8.0), - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: letters.first.toList(), - ), - ), - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: letters.last.toList(), - ) - ]; - - return Column( - children: [ - Expanded( - child: GestureDetector( - onTap: () { - var answer = state.answer.toList(); - var answerIds = state.answerIds.toList(); - if (answer.isNotEmpty) { - answer.removeLast(); - answerIds.removeLast(); - } - - manager.setState( - model.id!, - state.copyWith( - // isAnswered: false, - // isCorrect: false, - answer: answer, - answerIds: answerIds, - ), - ); - }, - behavior: HitTestBehavior.opaque, - child: Column( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: MainAxisAlignment.center, - mainAxisSize: MainAxisSize.min, - children: rows, - ), - ), - ), - SizedBox( - height: 16.0, - ), - AbsorbPointer( - absorbing: state.isCorrect, - child: Wrap( - children: buttons - .mapIndexed( - (index, button) => Container( - margin: EdgeInsets.all(4.0), - width: button.text!.length > 3 - ? null - : constraints.maxWidth / 6, - height: 50, - child: state.answerIds.contains(button.id) - ? SizedBox( - height: 50, - width: constraints.maxWidth / 6, - ) - : TestButton( - text: button.text, - onTap: () => buttonTapped(index, button), - color: state.answer == button - ? isCorrect(state.answer) - ? Colors.green.withOpacity(0.5) - : Colors.red.withOpacity(0.5) - : Theme.of(context).scaffoldBackgroundColor, - ), - ), - ) - .toList(), - ), - ), - ], - ); - }, - ); - } - - int splitRow(BoxConstraints constraints) { - int splitIndex = 0; - if (model.template.characters.where((c) => c == '_').length * 32 + - model.template.characters.where((c) => c != '_').length * 18 > - constraints.maxWidth * 0.9) { - splitIndex = model.template.indexOf( - ' ', - (model.template.length / 2).ceil(), - ); - if (splitIndex < 10) { - splitIndex = model.template.indexOf( - ' ', - (model.template.length / 3).ceil(), - ); - } - if (splitIndex == -1) { - splitIndex = model.template.indexOf( - ' ', - 0, - ); - } - } - if (splitIndex < 0) { - splitIndex = 0; - } - return splitIndex; - } -} - -class _Letter extends StatelessWidget { - final String text; - final Color? borderColor; - final Color? backgroundColor; - final double? _width; - final double _padding; - final double _innerPadding; - final double _innerMargin; - - _Letter({ - this.text = '', - this.borderColor, - this.backgroundColor, - double width = 32.0, - }) : this._width = width, - this._padding = 0, - this._innerPadding = 5, - this._innerMargin = 2.0; - - _Letter.readOnly({ - this.text = '', - }) : this.borderColor = null, - this.backgroundColor = Colors.transparent, - this._width = text == ' ' - ? 10 - : text.length == 1 - ? 20 - : null, - this._padding = 5.0, - this._innerPadding = 0.0, - this._innerMargin = 0.0; - - @override - Widget build(BuildContext context) { - return Container( - width: _width, - height: 45, - alignment: Alignment.center, - margin: EdgeInsets.all(_innerMargin), - padding: EdgeInsets.all(_innerPadding) - .copyWith(right: _padding + _innerPadding), - clipBehavior: Clip.antiAlias, - decoration: BoxDecoration( - color: backgroundColor ?? Theme.of(context).scaffoldBackgroundColor, - borderRadius: BorderRadius.circular(6.0), - border: borderColor != null ? Border.all(color: borderColor!) : null, - ), - child: Material( - color: backgroundColor ?? Theme.of(context).scaffoldBackgroundColor, - child: Text( - text, - style: Theme.of(context).textTheme.titleLarge?.copyWith( - letterSpacing: 1.1, - ), - textAlign: TextAlign.center, - ), - ), - ); - } -} diff --git a/mnemo_cards/lib/features/tests/test_widgets/simple_test.dart b/mnemo_cards/lib/features/tests/test_widgets/simple_test.dart deleted file mode 100644 index 94897ae..0000000 --- a/mnemo_cards/lib/features/tests/test_widgets/simple_test.dart +++ /dev/null @@ -1,134 +0,0 @@ -import 'dart:math'; - -import 'package:flutter/material.dart'; -import 'package:flutter_screenutil/flutter_screenutil.dart'; -import 'package:mnemo_cards/features/tests/test_manager.dart'; -import 'package:mnemo_cards/features/tests/test_widgets/common_test_question_widget.dart'; -import 'package:mnemo_cards/features/tests/test_widgets/test_image.dart'; -import 'package:mnemo_cards_common/mnemo_cards_common.dart'; - -import '../../../di/locator.dart'; -import '../question_states/simple_test_state.dart'; -import 'test_button.dart'; - -class SimpleTestWidget extends StatelessWidget { - final SimpleTestQuestionBody _simpleTestModel; - - SimpleTestQuestionBody get model => _simpleTestModel; - - bool get isCorrect => state.answer.startsWith(model.answer); - - SimpleTestState get state => manager.getState(model.id!) as SimpleTestState; - - TestManager get manager => locator.testManager; - - Color get testColor => manager.color; - - const SimpleTestWidget(this._simpleTestModel, {super.key}); - - @override - Widget build(BuildContext context) { - final random = Random(state.seed); - final buttons = [...model.buttons]..shuffle(random); - - return LayoutBuilder(builder: (context, constraints) { - return Padding( - padding: const EdgeInsets.all(8.0), - child: Column( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Expanded( - child: CommonTestQuestionWidget( - text: model.text, - image: model.image, - audio: model.audio, - ), - ), - SizedBox( - height: 16.0, - ), - StatefulBuilder(builder: (context, setState) { - void setAnswer(String answer) { - setState(() { - manager.setState( - model.id!, - state.copyWith( - answer: answer, - ), - ); - // only setting isCorrect once - manager.setState( - model.id!, - state.copyWith( - isAnswered: true, - isCorrect: state.isAnswered ? state.isCorrect : isCorrect, - ), - ); - }); - if (isCorrect) { - Future.delayed( - Duration(milliseconds: 300), - manager.nextTest, - ); - } - } - - bool buttonLine = (model.image != null && - buttons.where((element) => element.image != null).length != - 2); - final imageSide = buttonLine - ? constraints.maxWidth / 4 - 8 - : constraints.maxWidth / 2 - 16; - final spacing = buttonLine ? 4.0 : 8.0; - - return AbsorbPointer( - absorbing: state.isCorrect, - child: Wrap( - spacing: spacing, - runSpacing: 8.0, - children: buttons - .map( - (e) => e.isTextButton - ? Container( - width: constraints.maxWidth / 2 - 16, - height: 90.h, - child: TestButton( - text: e.text, - onTap: () { - setAnswer(e.id); - }, - // borderColor: testColor, - color: state.answer == e.id - ? isCorrect - ? Colors.green.withOpacity(0.5) - : Colors.red.withOpacity(0.5) - : Theme.of(context).scaffoldBackgroundColor, - ), - ) - : SizedBox( - width: imageSide, - height: imageSide, - child: TestButton( - image: TestImage.image(e.image!), - onTap: () { - setAnswer(e.id); - }, - // borderColor: testColor, - color: e.id == state.answer - ? isCorrect - ? Colors.green.withOpacity(0.5) - : Colors.red.withOpacity(0.5) - : Theme.of(context).scaffoldBackgroundColor, - ), - ), - ) - .toList(), - ), - ); - }) - ], - ), - ); - }); - } -} diff --git a/mnemo_cards/lib/features/tests/test_widgets/test_button.dart b/mnemo_cards/lib/features/tests/test_widgets/test_button.dart deleted file mode 100644 index 32844a4..0000000 --- a/mnemo_cards/lib/features/tests/test_widgets/test_button.dart +++ /dev/null @@ -1,71 +0,0 @@ -import 'package:flutter/material.dart'; - -import 'test_image.dart'; - -class TestButton extends StatelessWidget { - final String? text; - final TestImage? image; - final VoidCallback onTap; - final Color? color; - final Color? borderColor; - final bool isVisible; - - TestButton({ - this.text, - this.image, - this.color, - this.borderColor, - required this.onTap, - this.isVisible = true - }); - - @override - Widget build(BuildContext context) { - final theme = Theme.of(context).textTheme; - return Visibility( - visible: isVisible, - child: Material( - borderRadius: BorderRadius.circular(12.0), - child: Container( - padding: const EdgeInsets.all(4.0), - decoration: BoxDecoration( - color: color, - // border: Border.all(color: borderColor ?? borderGray), - borderRadius: BorderRadius.circular(12.0), - boxShadow: const [ - // BoxShadow( - // color: Colors.black26, - // blurRadius: 4.0, - // ), - ], - ), - child: GestureDetector( - // borderRadius: BorderRadius.circular(10.0), - onTap: onTap, - behavior: HitTestBehavior.opaque, - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - if (image != null) - TestImageWidget( - image!, - key: ValueKey(image), - ), - if (image != null && text != null) - SizedBox( - height: 4.0, - ), - if (text != null) - Text( - text!, - textAlign: TextAlign.center, - style: theme.titleLarge, - ) - ], - ), - ), - ), - ), - ); - } -} diff --git a/mnemo_cards/lib/features/tests/test_widgets/test_image.dart b/mnemo_cards/lib/features/tests/test_widgets/test_image.dart deleted file mode 100644 index 9e95f6d..0000000 --- a/mnemo_cards/lib/features/tests/test_widgets/test_image.dart +++ /dev/null @@ -1,115 +0,0 @@ -import 'dart:convert'; -import 'dart:developer'; -import 'dart:math' as m; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/material.dart'; -import 'package:mnemo_cards/features/packs/images_holder.dart'; - -import '../../../di/locator.dart'; - -class TestImageWidget extends StatefulWidget { - final TestImage _testImage; - - const TestImageWidget(this._testImage, {super.key}); - - @override - State createState() => _TestImageWidgetState(); -} - -class _TestImageWidgetState extends State { - TestImage get _testImage => widget._testImage; - bool same = false; - Widget? cached; - - @override - void didUpdateWidget(TestImageWidget oldWidget) { - super.didUpdateWidget(oldWidget); - same = oldWidget._testImage == _testImage; - } - - Future _preloadImage() async { - try { - // final cache = _TestImageCache(); - // final cachedImage = cache.image(_testImage); - // if (cachedImage != null) { - // return cachedImage; - // } - final imageProvider = await _testImage.loadImage(); - if (imageProvider == null) { - return SizedBox.shrink(); - } - // cache.setImage(_testImage, imageProvider); - return Image(image: imageProvider); - } catch (e) { - log('Cant load image ${_testImage}packId: $e'); - } - return SizedBox(); - } - - @override - Widget build(BuildContext context) { - // final cache = _TestImageCache(); - if (same && cached != null) { - return cached!; - } - return FutureBuilder( - future: _preloadImage(), - // initialData: cache.image(_testImage), - builder: (_, s) { - if (s.data == null) { - return Container( - alignment: Alignment.center, - ); - } - cached = Container( - clipBehavior: Clip.antiAlias, - decoration: BoxDecoration( - color: Theme.of(context).scaffoldBackgroundColor, - borderRadius: BorderRadius.circular(12), - ), - child: s.data, - ); - return cached!; - }, - ); - } -} - -class TestImage { - final String data; - final String key; - - TestImage({ - required this.data, - required this.key, - }); - - @override - bool operator ==(Object other) { - return other is TestImage && key == other.key; - } - - Future loadImage() async { - if (data.length > 50) { - Uint8List? bytes; - try { - bytes = await compute(base64Decode, data); - return MemoryImage(bytes!); - } catch (e) { - log('Cant decode base64 test image'); - return null; - } - } else if (data.contains(':')) { - final packId = data.split(':').first; - final path = data.split(':').last; - return await locator.testManager.loadImage(packId, path); - } else { - return data.memoryImage; - } - } - - TestImage.image(String image) - : data = image, - key = image.substring(0, m.min(image.length, 50)); -} \ No newline at end of file diff --git a/mnemo_cards/lib/features/tests/tests_cache.dart b/mnemo_cards/lib/features/tests/tests_cache.dart deleted file mode 100644 index 74a7bda..0000000 --- a/mnemo_cards/lib/features/tests/tests_cache.dart +++ /dev/null @@ -1,20 +0,0 @@ -import 'package:mnemo_cards/features/worker/worker_ext.dart'; -import 'package:mnemo_cards_common/mnemo_cards_common.dart'; - -import '../../main.dart'; - -class TestsCache { - Future savePackTests(String packId, List tests) async { - final sp = globalSharedPreferences; - sp.setString('tests_${packId}', tests.encode()); - } - - Future?> loadTestFromCache(String packId) async { - final sp = globalSharedPreferences; - final test = sp.getString('tests_${packId}'); - if (test != null) { - return test.isolatedDecodeList(TestDto.fromJson); - } - return null; - } -} diff --git a/mnemo_cards/lib/features/vocabulary/COLORS_UPDATE_REPORT.md b/mnemo_cards/lib/features/vocabulary/COLORS_UPDATE_REPORT.md deleted file mode 100644 index 383da03..0000000 --- a/mnemo_cards/lib/features/vocabulary/COLORS_UPDATE_REPORT.md +++ /dev/null @@ -1,109 +0,0 @@ -# Отчет об обновлении цветовой схемы Vocabulary Feature - -## ✅ Выполненные изменения - -### 1. Обновление моделей данных - -#### VocabularyCategory -- Изменен тип поля `color` с `Color` на `String?` -- Добавлен метод `getColor(BuildContext context)` для получения цвета -- Использует `color?.asColor ?? Theme.of(context).colorScheme.primary` как fallback - -#### VocabularyWord -- Добавлено поле `packColor: String?` для цвета пака -- Добавлен метод `getPackColor(BuildContext context)` для получения цвета пака -- Использует `packColor?.asColor ?? Theme.of(context).colorScheme.primary` как fallback - -### 2. Обновление Cubit - -#### Mock данные -- Обновлены mock категории с цветами в формате hex: - - Животные: `#FF6B6B` (красный) - - Еда: `#FFD93D` (желтый) - - Дом: `#4ECDC4` (бирюзовый) -- Обновлены mock слова с цветами паков: - - gato, perro: `#FF6B6B` (красный для животных) - - casa: `#4ECDC4` (бирюзовый для дома) - -### 3. Обновление виджетов - -#### VocabularyCategories -- Использует `category.getColor(context)` для активного состояния -- Цвета категорий теперь берутся из паков или темы - -#### VocabularyProgress -- Использует `golden` из темы для прогресс-бара -- Импортирует `mnemo_cards/theme/themes.dart` - -#### VocabularyWordCard -- Использует `golden` из темы для изученных слов -- Использует `word.getPackColor(context)` для прогресса не изученных слов -- Использует `borderGray` из темы для границ -- Передает `BuildContext` в метод `_buildWordActions()` - -### 4. Интеграция с существующей системой - -#### Использование StringHelper -- Импортирует `mnemo_cards/utils/string_helper.dart` -- Использует extension `asColor` для конвертации String в Color -- Поддерживает форматы: `#FF6B6B`, `0xFF6B6B`, `FF6B6B` - -#### Использование тем -- Импортирует `mnemo_cards/theme/themes.dart` -- Использует константы: `golden`, `borderGray`, `progressBlue` -- Fallback на `Theme.of(context).colorScheme.primary` - -## 🎨 Цветовая схема - -### Цвета из темы -- `golden` - для изученных слов и прогресса -- `borderGray` - для границ и неактивных элементов -- `progressBlue` - для прогресса (альтернатива) - -### Цвета паков (примеры) -- `#FF6B6B` - красный для животных -- `#FFD93D` - желтый для еды -- `#4ECDC4` - бирюзовый для дома - -### Fallback цвета -- `Theme.of(context).colorScheme.primary` - основной цвет темы -- `Colors.grey[100]` - для неактивных состояний -- `Colors.grey[300]` - для границ - -## 🔧 Технические детали - -### Методы получения цветов -```dart -// В VocabularyCategory -Color getColor(BuildContext context) { - return color?.asColor ?? Theme.of(context).colorScheme.primary; -} - -// В VocabularyWord -Color getPackColor(BuildContext context) { - return packColor?.asColor ?? Theme.of(context).colorScheme.primary; -} -``` - -### Использование в виджетах -```dart -// Категории -color: isSelected ? category.getColor(context) : Colors.grey[100] - -// Прогресс слов -color: word.isLearned ? golden : word.getPackColor(context) - -// Изученные слова -color: word.isLearned ? golden.withOpacity(0.1) : Colors.white -``` - -## 📱 Результат - -Теперь Vocabulary Feature полностью интегрирована с цветовой системой проекта: -- ✅ Использует цвета из паков через `pack.color?.asColor` -- ✅ Использует цвета из темы как fallback -- ✅ Поддерживает все форматы цветов (hex, 0x, без префикса) -- ✅ Адаптивна к изменениям темы -- ✅ Консистентна с остальным приложением - -Все цвета теперь динамически получаются из паков и темы, что обеспечивает единообразный дизайн во всем приложении. diff --git a/mnemo_cards/lib/features/vocabulary/DESIGN_FIXES_COMPLETED.md b/mnemo_cards/lib/features/vocabulary/DESIGN_FIXES_COMPLETED.md deleted file mode 100644 index 0c33366..0000000 --- a/mnemo_cards/lib/features/vocabulary/DESIGN_FIXES_COMPLETED.md +++ /dev/null @@ -1,69 +0,0 @@ -# Отчет о выполненных исправлениях дизайна - -## ✅ Все задачи выполнены! - -### 1. Обновление категорий -- ✅ Добавлена логика подсчета изученных слов в категории -- ✅ Обновлены цвета категорий согласно дизайну: - - Животные: `#9C27B0` (фиолетовый) - - Еда: `#FF9800` (оранжевый) - - Дом: `#8BC34A` (желто-зеленый) - -### 2. Прогресс-бар -- ✅ Изменен текст на "Выучено: X из Y слов" -- ✅ Использован фиолетовый цвет для прогресс-бара -- ✅ Убрано процентное отображение - -### 3. Карточки слов -- ✅ Создан виджет `DifficultyChart` для волнистых графиков -- ✅ Заменен прогресс-бар на настоящий график сложности -- ✅ Убраны кнопки избранного и аудио -- ✅ Увеличен размер изображений (80x80 вместо 60x60) -- ✅ Убраны транскрипция и мнемоника из отображения -- ✅ Убраны тени у карточек - -### 4. Размеры и стилизация -- ✅ Скорректированы размеры элементов -- ✅ Убраны тени у карточек -- ✅ Обновлена цветовая схема - -## 🎨 Новые компоненты - -### DifficultyChart -Создан новый виджет для отображения волнистых графиков сложности: -- **Легко**: плавная волна (зеленый цвет) -- **Средне**: средняя волна (оранжевый цвет) -- **Сложно**: сложная волна (красный цвет) - -### Обновленные модели -- `VocabularyCategory.updateLearnedWords()` - подсчет изученных слов -- `VocabularyPageState.updatedCategories` - обновленные категории - -## 🔧 Технические изменения - -### Удаленные компоненты -- Кнопки избранного и аудио из карточек слов -- Прогресс-бар из карточек слов -- Тени у карточек -- Транскрипция и мнемоника из отображения - -### Добавленные компоненты -- `DifficultyChart` - виджет для волнистых графиков -- `DifficultyChartPainter` - кастомный painter для рисования волн -- Логика подсчета изученных слов по категориям - -### Обновленные размеры -- Изображения слов: 80x80 (было 60x60) -- График сложности: 40x20 - -## 📱 Результат - -Vocabulary Feature теперь полностью соответствует дизайну: -- ✅ Категории с правильными цветами и подсчетом слов -- ✅ Прогресс-бар с фиолетовым цветом и правильным текстом -- ✅ Карточки слов с волнистыми графиками сложности -- ✅ Увеличенные изображения без теней -- ✅ Упрощенный интерфейс без лишних кнопок -- ✅ Чистый дизайн без транскрипции и мнемоники - -Все исправления выполнены успешно и Vocabulary Feature готова к использованию! diff --git a/mnemo_cards/lib/features/vocabulary/IMPLEMENTATION_REPORT.md b/mnemo_cards/lib/features/vocabulary/IMPLEMENTATION_REPORT.md deleted file mode 100644 index 7f7fd42..0000000 --- a/mnemo_cards/lib/features/vocabulary/IMPLEMENTATION_REPORT.md +++ /dev/null @@ -1,136 +0,0 @@ -# Отчет о реализации Vocabulary Feature - -## ✅ Выполненные этапы - -### Этап 1: Базовая структура -- [x] **Создать новые модели данных** - `VocabularyCategory`, `VocabularyWord`, `VocabularyPageState`, `WordDifficulty` -- [x] **Настроить Cubit для управления состоянием** - `VocabularyCubit` с полным набором методов -- [x] **Создать базовую структуру страницы** - `VocabularyPage` с BlocProvider -- [x] **Добавить заголовок и поиск** - `VocabularyHeader` и `VocabularySearchBar` - -### Этап 2: Категории -- [x] **Создать виджет CategoryTab** - встроен в `VocabularyCategories` -- [x] **Реализовать горизонтальный скролл категорий** - `ListView.builder` с `Axis.horizontal` -- [x] **Добавить логику переключения категорий** - `onCategorySelected` callback -- [x] **Стилизовать активное состояние** - `AnimatedContainer` с цветовой схемой - -### Этап 3: Прогресс -- [x] **Адаптировать логику из UserStatistics** - используется логика определения изученных слов -- [x] **Использовать существующий HorizontalProgressWidget** - интеграция с `mnemo_cards_frontend_common` -- [x] **Добавить анимацию прогресс-бара** - встроена в `HorizontalProgressWidget` -- [x] **Интегрировать с данными** - подсчет прогресса в `VocabularyPageState` - -### Этап 4: Список слов -- [x] **Расширить _WordListItem из UserStatistics** - `VocabularyWordCard` основан на существующей логике -- [x] **Добавить изображения из GameCardDto.image** - `NetworkImage` с обработкой ошибок -- [x] **Интегрировать с GameCardDto данными** - полная интеграция с `original`, `translation`, `transcription`, `mnemo` -- [x] **Стилизовать карточки** - современный дизайн с тенями и анимациями - -### Этап 5: Функциональность -- [x] **Реализовать поиск по GameCardDto полям** - поиск по `original` и `translation` -- [x] **Добавить управление избранным** - `toggleFavorite` с анимацией -- [x] **Использовать логику изученных слов из UserStatistics** - `correct > 3 && correct/total > 0.8` -- [x] **Добавить аудио воспроизведение** - заглушка для `playAudio` - -## 🏗️ Архитектура - -### Модели данных -```dart -VocabularyCategory // Категория с иконкой, цветом и статистикой -VocabularyWord // Слово с GameCardDto + WordStatisticsDto + isFavorite -VocabularyPageState // Состояние страницы с фильтрацией и поиском -WordDifficulty // Enum сложности (easy/medium/hard) -``` - -### State Management -```dart -VocabularyCubit // Управление состоянием с методами: - - loadWords() // Загрузка карточек - - loadUserData() // Загрузка статистики - - loadCategories() // Загрузка категорий - - selectCategory() // Выбор категории - - searchWords() // Поиск - - toggleFavorite() // Избранное - - playAudio() // Аудио -``` - -### UI Компоненты -```dart -VocabularyPage // Основная страница -VocabularyHeader // Заголовок с подсчетом слов -VocabularySearchBar // Поиск с debounce -VocabularyProgress // Прогресс-бар -VocabularyCategories // Горизонтальные табы категорий -VocabularyWordsList // Список слов -VocabularyWordCard // Карточка слова -``` - -## 🔗 Интеграция с существующим кодом - -### Используемые компоненты -- `UserDataDto` - данные пользователя -- `WordStatisticsDto` - статистика слов -- `GameCardDto` - карточки с переводами -- `HorizontalProgressWidget` - прогресс-бар -- `UserStatistics` - логика определения изученных слов - -### Переиспользованная логика -- Определение изученных слов: `correct > 3 && correct/total > 0.8` -- Сортировка по прогрессу: `(n.correct / n.total).compareTo(p.correct / p.total)` -- Текст заголовка с правильным склонением -- Анимации и стилизация - -## 📱 Функциональность - -### Основные возможности -- ✅ Отображение слов с изображениями -- ✅ Поиск по испанским и русским словам -- ✅ Категории с горизонтальным скроллом -- ✅ Прогресс изучения -- ✅ Отметка избранных слов -- ✅ Определение изученных слов -- ✅ Адаптивный дизайн -- ✅ Анимации переходов - -### UI/UX особенности -- Современный Material Design -- Плавные анимации (200-600ms) -- Адаптивные размеры с `flutter_screenutil` -- Обработка ошибок загрузки -- Пустые состояния с иконками -- Цветовая индикация прогресса - -## 🧪 Тестирование - -Создан `TestVocabularyPage` для проверки функциональности: -```dart -import 'package:mnemo_cards/features/vocabulary/test_vocabulary_page.dart'; - -Navigator.push(context, MaterialPageRoute( - builder: (context) => const TestVocabularyPage(), -)); -``` - -## 📦 Структура файлов - -``` -vocabulary/ -├── models/ # Модели данных -├── cubit/ # Управление состоянием -├── pages/ # Страницы -├── widgets/ # UI компоненты -├── vocabulary.dart # Экспорт -├── test_vocabulary_page.dart # Тестирование -├── README.md # Документация -└── IMPLEMENTATION_REPORT.md # Этот отчет -``` - -## 🚀 Готовность к использованию - -Страница словаря полностью готова к использованию и интегрирована с существующей архитектурой проекта. Все компоненты следуют принципам Clean Architecture и максимально переиспользуют существующий код. - -### Следующие шаги -1. Интеграция с реальным API -2. Добавление аудио функциональности -3. Реализация фильтрации по категориям -4. Тестирование на реальных данных diff --git a/mnemo_cards/lib/features/vocabulary/README.md b/mnemo_cards/lib/features/vocabulary/README.md deleted file mode 100644 index f775613..0000000 --- a/mnemo_cards/lib/features/vocabulary/README.md +++ /dev/null @@ -1,121 +0,0 @@ -# Vocabulary Feature - -Страница словаря для изучения испанских слов с русскими переводами. - -## Структура - -``` -vocabulary/ -├── models/ -│ ├── vocabulary_category.dart # Модель категории -│ ├── vocabulary_word.dart # Модель слова -│ ├── vocabulary_page_state.dart # Состояние страницы -│ └── word_difficulty.dart # Уровни сложности -├── cubit/ -│ └── vocabulary_cubit.dart # Управление состоянием -├── pages/ -│ └── vocabulary_page.dart # Основная страница -├── widgets/ -│ ├── vocabulary_header.dart # Заголовок -│ ├── vocabulary_search_bar.dart # Поиск -│ ├── vocabulary_progress.dart # Прогресс -│ ├── vocabulary_categories.dart # Категории -│ ├── vocabulary_words_list.dart # Список слов -│ └── vocabulary_word_card.dart # Карточка слова -├── vocabulary.dart # Экспорт всех компонентов -└── test_vocabulary_page.dart # Тестовая страница -``` - -## Использование - -### Базовое использование - -```dart -import 'package:mnemo_cards/features/vocabulary/vocabulary.dart'; - -// В вашем приложении -Navigator.push( - context, - MaterialPageRoute( - builder: (context) => const VocabularyPage(), - ), -); -``` - -### Интеграция с существующими данными - -Страница автоматически интегрируется с: -- `UserDataDto` - для статистики пользователя -- `WordStatisticsDto` - для прогресса изучения слов -- `GameCardDto` - для карточек с переводами -- `HorizontalProgressWidget` - для отображения прогресса - -### Кастомизация - -#### Цвета и темы -Используются стандартные цвета Flutter: -- `Colors.amber` - для изученных слов -- `Colors.blue` - для прогресса -- `Colors.grey` - для границ и неактивных элементов - -#### Анимации -- Переключение категорий: 200ms -- Карточки слов: 300ms -- Прогресс-бар: 600ms - -## Функциональность - -### ✅ Реализовано -- [x] Отображение списка слов с изображениями -- [x] Поиск по испанским и русским словам -- [x] Категории с горизонтальным скроллом -- [x] Прогресс изучения -- [x] Отметка избранных слов -- [x] Определение изученных слов -- [x] Адаптивный дизайн -- [x] Анимации - -### 🔄 В разработке -- [ ] Реальная интеграция с API -- [ ] Аудио воспроизведение -- [ ] Фильтрация по категориям -- [ ] Офлайн режим - -### 📋 Планируется -- [ ] Голосовой поиск -- [ ] Экспорт словаря -- [ ] Социальные функции -- [ ] Геймификация - -## Тестирование - -Для тестирования используйте `TestVocabularyPage`: - -```dart -import 'package:mnemo_cards/features/vocabulary/test_vocabulary_page.dart'; - -// В вашем приложении -Navigator.push( - context, - MaterialPageRoute( - builder: (context) => const TestVocabularyPage(), - ), -); -``` - -## Зависимости - -- `flutter_bloc` - управление состоянием -- `flutter_screenutil` - адаптивный дизайн -- `mnemo_cards_common` - общие модели данных -- `mnemo_cards_frontend_common` - общие виджеты - -## Архитектура - -Страница следует принципам Clean Architecture: -- **Models** - бизнес-логика и данные -- **Cubit** - управление состоянием -- **Pages** - координация UI -- **Widgets** - переиспользуемые компоненты - -Все компоненты максимально переиспользуют существующий код проекта. diff --git a/mnemo_cards/lib/features/vocabulary/REAL_DATA_INTEGRATION_REPORT.md b/mnemo_cards/lib/features/vocabulary/REAL_DATA_INTEGRATION_REPORT.md deleted file mode 100644 index 28fe38c..0000000 --- a/mnemo_cards/lib/features/vocabulary/REAL_DATA_INTEGRATION_REPORT.md +++ /dev/null @@ -1,126 +0,0 @@ -# Отчет о интеграции реальных данных - -## ✅ Все задачи выполнены! - -### 🔄 Замена мок данных на реальные - -Успешно заменил все мок данные в VocabularyCubit на реальные данные из системы: - -#### 1. **Статистика слов из UserDataDto** -- ✅ Получение данных из `locator.userManager.userStateHolder.user?.userDataDto?.allWordsStatistics` -- ✅ Использование реальной статистики изучения слов -- ✅ Автоматическое обновление при изменении данных пользователя - -#### 2. **Карточки из активного пакета** -- ✅ Получение карточек из `locator.activePackCubit.state` -- ✅ Поддержка разных типов ответов: `CardPackDto`, `CardPackBuyDto` -- ✅ Автоматическое обновление при смене активного пакета - -#### 3. **Объединение данных** -- ✅ Создание `VocabularyWord` из `GameCardDto` + `WordStatisticsDto` -- ✅ Автоматическое сопоставление слов по названию -- ✅ Fallback для слов без статистики - -#### 4. **Категории на основе реальных данных** -- ✅ Создание категорий из активного пакета -- ✅ Использование реальных цветов, названий и размеров пакетов -- ✅ Автоматический выбор иконок на основе названия пакета - -## 🛠️ Технические изменения - -### Новые методы в VocabularyCubit: - -#### `_combineCardsWithStatistics()` -```dart -List _combineCardsWithStatistics( - List gameCards, - List wordsStatistics, -) -``` -- Объединяет карточки с их статистикой -- Сопоставляет слова по названию -- Создает fallback статистику для новых слов - -#### `_getCardsFromResponse()` -```dart -List _getCardsFromResponse(GetCardPackResponse? response) -``` -- Извлекает карточки из разных типов ответов -- Поддерживает `CardPackDto` и `CardPackBuyDto` - -#### `_getPackColorFromResponse()` -```dart -String? _getPackColorFromResponse(GetCardPackResponse? response) -``` -- Получает цвет пакета из ответа -- Возвращает null если цвет недоступен - -#### `_getPackInfoFromResponse()` -```dart -Map? _getPackInfoFromResponse(GetCardPackResponse? response) -``` -- Извлекает полную информацию о пакете -- Возвращает id, title, color, size - -#### `_createCategoriesFromPacks()` -```dart -List _createCategoriesFromPacks() -``` -- Создает категории на основе активного пакета -- Использует реальные данные пакета - -#### `_getIconForPack()` -```dart -IconData _getIconForPack(String title) -``` -- Выбирает иконку на основе названия пакета -- Поддерживает русские и английские названия - -### Обновленные методы: - -#### `loadWords()` -- Теперь получает реальные данные из UserDataDto и ActivePackCubit -- Объединяет карточки со статистикой -- Создает категории на основе реальных данных - -#### `loadUserData()` -- Получает данные из `locator.userManager.userStateHolder.user?.userDataDto` - -#### `loadCategories()` -- Создает категории на основе активного пакета - -## 📊 Источники данных - -### UserDataDto -```dart -locator.userManager.userStateHolder.user?.userDataDto?.allWordsStatistics?.words -``` -- Статистика изучения слов -- Количество правильных/неправильных ответов -- Пропущенные слова - -### ActivePackCubit -```dart -locator.activePackCubit.state?.getCardPackResponse -``` -- Активный пакет карточек -- Информация о пакете (название, цвет, размер) -- Список карточек - -## 🔄 Автоматическое обновление - -Vocabulary Feature теперь автоматически обновляется при: -- ✅ Изменении данных пользователя -- ✅ Смене активного пакета -- ✅ Обновлении статистики изучения - -## 🎯 Результат - -Vocabulary Feature теперь полностью интегрирована с реальными данными: -- ✅ Показывает реальную статистику изучения -- ✅ Отображает карточки из активного пакета -- ✅ Использует реальные цвета и названия пакетов -- ✅ Автоматически обновляется при изменениях -- ✅ Не требует мок данных для работы - -Все мок данные удалены, Vocabulary Feature готова к продакшену! diff --git a/mnemo_cards/lib/features/vocabulary/cubit/vocabulary_cubit.dart b/mnemo_cards/lib/features/vocabulary/cubit/vocabulary_cubit.dart deleted file mode 100644 index bc3efc0..0000000 --- a/mnemo_cards/lib/features/vocabulary/cubit/vocabulary_cubit.dart +++ /dev/null @@ -1,179 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:mnemo_cards_common/mnemo_cards_common.dart'; -import 'package:mnemo_cards/di/locator.dart'; -import '../models/vocabulary_page_state.dart'; -import '../models/vocabulary_word.dart'; -import '../models/vocabulary_category.dart'; - -class VocabularyCubit extends Cubit { - VocabularyCubit() : super(const VocabularyPageState()); - - /// Загрузка карточек из API - Future loadWords() async { - emit(state.copyWith(isLoading: true, error: null)); - - try { - // Получаем реальные данные из UserDataDto - final userData = locator.userManager.userStateHolder.user?.userDataDto; - final wordsStatistics = userData?.allWordsStatistics?.words ?? []; - - // Loading packs to cache - final packs = await locator.packCacheManager.loadAllPacks(); - // Объединяем Packs с WordStatisticsDto - final words = _combineCardsWithStatistics(packs, wordsStatistics); - - // Создаем категории на основе реальных данных - final categories = _createCategoriesFromPacks(packs); - - emit( - state.copyWith( - words: words, - userData: userData, - categories: categories, - isLoading: false, - ), - ); - } catch (e) { - emit(state.copyWith(isLoading: false, error: e.toString())); - } - } - - /// Загрузка данных пользователя - Future loadUserData() async { - try { - // Получаем реальные данные пользователя - final userData = locator.userManager.userStateHolder.user?.userDataDto; - emit(state.copyWith(userData: userData)); - } catch (e) { - emit(state.copyWith(error: e.toString())); - } - } - - /// Загрузка категорий - Future loadCategories() async { - try { - // // Создаем категории на основе реальных данных пакетов - // final categories = _createCategoriesFromPacks(); - // emit(state.copyWith(categories: categories)); - } catch (e) { - // emit(state.copyWith(error: e.toString())); - } - } - - /// Выбор категории - void selectCategory(String? category) { - emit(state.copyWith(selectedCategory: category)); - } - - /// Поиск слов - void searchWords(String query) { - emit(state.copyWith(searchQuery: query)); - } - - /// Переключение избранного - void toggleFavorite(String wordId) { - final updatedWords = state.words.map((word) { - if (word.gameCard.id.toString() == wordId) { - return word.copyWith(isFavorite: !word.isFavorite); - } - return word; - }).toList(); - - emit(state.copyWith(words: updatedWords)); - } - - /// Воспроизведение аудио - Future playAudio(String wordId) async { - // TODO: Реализовать воспроизведение аудио - print('Playing audio for word: $wordId'); - } - - /// Очистка ошибки - void clearError() { - emit(state.copyWith(error: null)); - } - - /// Объединяет GameCardDto с WordStatisticsDto - List _combineCardsWithStatistics( - List packs, - List wordsStatistics, - ) { - return packs.expand((p) => p.cards).map((card) { - // Ищем статистику для этого слова - final statistics = wordsStatistics.firstWhere( - (stat) => stat.word == card.original, - orElse: () => WordStatisticsDto( - word: card.original ?? '', - correct: 0, - incorrect: 0, - skipped: 0, - ), - ); - - // Получаем цвет пакета - final activePackState = locator.activePackCubit.state; - final response = activePackState?.getCardPackResponse; - final packColor = _getPackColorFromResponse(response); - - return VocabularyWord( - gameCard: card, - statistics: statistics, - isFavorite: locator.favoriteCardsController.isFavoriteCard(card.id), - packColor: packColor, - ); - }).toList(); - } - - /// Создает категории на основе реальных данных пакетов - List _createCategoriesFromPacks(List packs) { - if (packs.isEmpty) { - return []; - } - - // Создаем категорию на основе активного пакета - return [ - ...packs.map( - (p) => VocabularyCategory( - id: p.id, - name: p.title, - icon: _getIconForPack(''), - color: p.color, - totalWords: p.cards.length, - learnedWords: 0, // Будет обновлено через updateLearnedWords - ), - ), - ]; - } - - /// Получает цвет пакета из GetCardPackResponse - String? _getPackColorFromResponse(GetCardPackResponse? response) { - if (response == null) return null; - - if (response is CardPackDto) { - return response.color; - } else if (response is CardPackBuyDto) { - return response.color; - } - - return null; - } - - /// Получает иконку для пакета на основе названия - IconData _getIconForPack(String title) { - final lowerTitle = title.toLowerCase(); - if (lowerTitle.contains('животн') || lowerTitle.contains('animal')) { - return Icons.pets; - } else if (lowerTitle.contains('еда') || lowerTitle.contains('food')) { - return Icons.restaurant; - } else if (lowerTitle.contains('дом') || lowerTitle.contains('home')) { - return Icons.home; - } else if (lowerTitle.contains('цвет') || lowerTitle.contains('color')) { - return Icons.palette; - } else if (lowerTitle.contains('числ') || lowerTitle.contains('number')) { - return Icons.numbers; - } else { - return Icons.category; - } - } -} diff --git a/mnemo_cards/lib/features/vocabulary/design_fixes.md b/mnemo_cards/lib/features/vocabulary/design_fixes.md deleted file mode 100644 index 6be3f58..0000000 --- a/mnemo_cards/lib/features/vocabulary/design_fixes.md +++ /dev/null @@ -1,43 +0,0 @@ -# План исправлений дизайна Vocabulary Feature - -## Анализ несоответствий с дизайном - -### 2. Категории (Category Tabs) -**Проблема:** -- Категории имеют счетчики слов (например, "45/120") -- Цвета категорий отличаются от текущих - -**Исправление:** -- Добавить логику подсчета изученных слов в категории -- Обновить цвета категорий согласно дизайну - -### 3. Прогресс-бар -**Проблема:** -- На дизайне показан текст "Выучено: 45 из 120 слов" -- Прогресс-бар имеет фиолетовый цвет - -**Исправление:** -- Изменить текст на "Выучено: X из Y слов" -- Использовать фиолетовый цвет для прогресс-бара - -### 4. Карточки слов -**Проблема:** -- На дизайне справа показаны волнистые графики (difficulty indicators - line charts) вместо прогресс-бара -- Нет кнопок избранного и аудио -- Изображения имеют другой размер и стиль -- Нет транскрипции и мнемоники - -**Исправление:** -- Заменить прогресс-бар на настоящий график -- Убрать кнопки избранного и аудио -- Увеличить размер изображений -- Убрать транскрипцию и мнемонику из отображения - -### 5. Цвета и стилизация -**Проблема:** -- Отсутствуют тени у карточек -- Размеры элементов отличаются - -**Исправление:** -- Убрать тени у карточек -- Скорректировать размеры элементов diff --git a/mnemo_cards/lib/features/vocabulary/models/vocabulary_category.dart b/mnemo_cards/lib/features/vocabulary/models/vocabulary_category.dart deleted file mode 100644 index b312c4e..0000000 --- a/mnemo_cards/lib/features/vocabulary/models/vocabulary_category.dart +++ /dev/null @@ -1,79 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:mnemo_cards/utils/string_helper.dart'; -import 'vocabulary_word.dart'; - -class VocabularyCategory { - final String id; - final String name; - final IconData icon; - final String? color; - final int totalWords; - final int learnedWords; - - const VocabularyCategory({ - required this.id, - required this.name, - required this.icon, - this.color, - this.totalWords = 0, - this.learnedWords = 0, - }); - - VocabularyCategory copyWith({ - String? id, - String? name, - IconData? icon, - String? color, - int? totalWords, - int? learnedWords, - }) { - return VocabularyCategory( - id: id ?? this.id, - name: name ?? this.name, - icon: icon ?? this.icon, - color: color ?? this.color, - totalWords: totalWords ?? this.totalWords, - learnedWords: learnedWords ?? this.learnedWords, - ); - } - - /// Получить цвет категории или цвет по умолчанию - Color getColor(BuildContext context) { - return color?.asColor ?? Theme.of(context).colorScheme.primary; - } - - double get progressPercentage { - if (totalWords == 0) return 0.0; - return learnedWords / totalWords; - } - - /// Обновить количество изученных слов на основе списка слов - VocabularyCategory updateLearnedWords(List words) { - final learnedCount = words.where((word) { - if (word is VocabularyWord) { - return word.isLearned; - } - return false; - }).length; - - return copyWith(learnedWords: learnedCount); - } - - @override - bool operator ==(Object other) { - if (identical(this, other)) return true; - return other is VocabularyCategory && - other.id == id && - other.name == name && - other.totalWords == totalWords && - other.learnedWords == learnedWords; - } - - @override - int get hashCode { - return id.hashCode ^ - name.hashCode ^ - totalWords.hashCode ^ - learnedWords.hashCode; - } -} diff --git a/mnemo_cards/lib/features/vocabulary/models/vocabulary_page_state.dart b/mnemo_cards/lib/features/vocabulary/models/vocabulary_page_state.dart deleted file mode 100644 index e09a642..0000000 --- a/mnemo_cards/lib/features/vocabulary/models/vocabulary_page_state.dart +++ /dev/null @@ -1,111 +0,0 @@ -import 'package:mnemo_cards_common/mnemo_cards_common.dart'; -import 'vocabulary_category.dart'; -import 'vocabulary_word.dart'; - -class VocabularyPageState { - final String? selectedCategory; - final List words; - final List categories; - final bool isLoading; - final String searchQuery; - final UserDataDto? userData; - final String? error; - - const VocabularyPageState({ - this.selectedCategory, - this.words = const [], - this.categories = const [], - this.isLoading = false, - this.searchQuery = '', - this.userData, - this.error, - }); - - VocabularyPageState copyWith({ - String? selectedCategory, - List? words, - List? categories, - bool? isLoading, - String? searchQuery, - UserDataDto? userData, - String? error, - }) { - return VocabularyPageState( - selectedCategory: selectedCategory ?? this.selectedCategory, - words: words ?? this.words, - categories: categories ?? this.categories, - isLoading: isLoading ?? this.isLoading, - searchQuery: searchQuery ?? this.searchQuery, - userData: userData ?? this.userData, - error: error ?? this.error, - ); - } - - /// Отфильтрованные слова по выбранной категории - List get filteredWords { - if (selectedCategory == null) return words; - return words.where((word) { - // Здесь можно добавить логику фильтрации по категории - // Пока возвращаем все слова - return true; - }).toList(); - } - - /// Обновленные категории с актуальным количеством изученных слов - List get updatedCategories { - return categories.map((category) { - return category.updateLearnedWords(words); - }).toList(); - } - - /// Отфильтрованные слова по поисковому запросу - List get searchedWords { - if (searchQuery.isEmpty) return filteredWords; - - final query = searchQuery.toLowerCase(); - return filteredWords.where((word) { - return word.original.toLowerCase().contains(query) || - word.translation.toLowerCase().contains(query); - }).toList(); - } - - /// Количество изученных слов - int get learnedWordsCount { - return words.where((word) => word.isLearned).length; - } - - /// Общее количество слов - int get totalWordsCount { - return words.length; - } - - /// Процент изученных слов - double get progressPercentage { - if (totalWordsCount == 0) return 0.0; - return learnedWordsCount / totalWordsCount; - } - - @override - bool operator ==(Object other) { - if (identical(this, other)) return true; - return other is VocabularyPageState && - other.selectedCategory == selectedCategory && - other.words.length == words.length && - other.categories.length == categories.length && - other.isLoading == isLoading && - other.searchQuery == searchQuery && - other.userData == userData && - other.error == error; - } - - @override - int get hashCode { - return selectedCategory.hashCode ^ - words.length.hashCode ^ - categories.length.hashCode ^ - isLoading.hashCode ^ - searchQuery.hashCode ^ - userData.hashCode ^ - error.hashCode; - } -} diff --git a/mnemo_cards/lib/features/vocabulary/models/vocabulary_word.dart b/mnemo_cards/lib/features/vocabulary/models/vocabulary_word.dart deleted file mode 100644 index ec5f7e1..0000000 --- a/mnemo_cards/lib/features/vocabulary/models/vocabulary_word.dart +++ /dev/null @@ -1,95 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:mnemo_cards_common/mnemo_cards_common.dart'; -import 'package:mnemo_cards/utils/string_helper.dart'; -import '../../../theme/themes.dart' show borderGray; -import 'word_difficulty.dart'; - -class VocabularyWord { - final GameCardDto gameCard; - final WordStatisticsDto? statistics; - final bool isFavorite; - final String? packColor; - - const VocabularyWord({ - required this.gameCard, - this.statistics, - this.isFavorite = false, - this.packColor, - }); - - /// Испанское слово - String get original => gameCard.original ?? ''; - - /// Русский перевод - String get translation => gameCard.translation ?? ''; - - /// URL изображения - String? get imageUrl => gameCard.image; - - /// Транскрипция - String? get transcription => gameCard.transcription; - - /// Мнемоника - String? get mnemo => gameCard.mnemo; - - /// Изучено ли слово (логика из UserStatistics) - bool get isLearned { - if (statistics == null) return false; - return statistics!.correct > 3 && - statistics!.correct / statistics!.total > 0.8; - } - - /// Уровень сложности (computed) - WordDifficulty get difficulty { - if (statistics == null || statistics!.total == 0) { - return WordDifficulty.hard; - } - final correctRatio = statistics!.correct / statistics!.total; - return WordDifficultyHelper.calculateDifficulty(correctRatio); - } - - /// Прогресс изучения (0.0 - 1.0) - double get progress { - if (statistics == null || statistics!.total == 0) return 0.0; - return statistics!.correct / statistics!.total; - } - - /// Количество правильных ответов - double get correctAnswers => statistics?.correct ?? 0.0; - - /// Общее количество ответов - double get totalAnswers => statistics?.total ?? 0.0; - - VocabularyWord copyWith({ - GameCardDto? gameCard, - WordStatisticsDto? statistics, - bool? isFavorite, - String? packColor, - }) { - return VocabularyWord( - gameCard: gameCard ?? this.gameCard, - statistics: statistics ?? this.statistics, - isFavorite: isFavorite ?? this.isFavorite, - packColor: packColor ?? this.packColor, - ); - } - - /// Получить цвет пака или цвет по умолчанию - Color getPackColor() { - return packColor?.asColor ?? borderGray; - } - - @override - bool operator ==(Object other) { - if (identical(this, other)) return true; - return other is VocabularyWord && - other.gameCard.id == gameCard.id && - other.isFavorite == isFavorite && - other.statistics == statistics; - } - - @override - int get hashCode { - return gameCard.id.hashCode ^ isFavorite.hashCode ^ statistics.hashCode; - } -} diff --git a/mnemo_cards/lib/features/vocabulary/models/word_difficulty.dart b/mnemo_cards/lib/features/vocabulary/models/word_difficulty.dart deleted file mode 100644 index e3b738e..0000000 --- a/mnemo_cards/lib/features/vocabulary/models/word_difficulty.dart +++ /dev/null @@ -1,43 +0,0 @@ -import 'package:flutter/material.dart'; - -enum WordDifficulty { - easy, - medium, - hard, -} - -extension WordDifficultyExtension on WordDifficulty { - Color get color { - switch (this) { - case WordDifficulty.easy: - return Colors.green; - case WordDifficulty.medium: - return Colors.orange; - case WordDifficulty.hard: - return Colors.red; - } - } - - String get displayName { - switch (this) { - case WordDifficulty.easy: - return 'Легко'; - case WordDifficulty.medium: - return 'Средне'; - case WordDifficulty.hard: - return 'Сложно'; - } - } -} - -class WordDifficultyHelper { - static WordDifficulty calculateDifficulty(double correctRatio) { - if (correctRatio > 0.8) { - return WordDifficulty.easy; - } else if (correctRatio > 0.5) { - return WordDifficulty.medium; - } else { - return WordDifficulty.hard; - } - } -} diff --git a/mnemo_cards/lib/features/vocabulary/pages/vocabulary_page.dart b/mnemo_cards/lib/features/vocabulary/pages/vocabulary_page.dart deleted file mode 100644 index b2e5696..0000000 --- a/mnemo_cards/lib/features/vocabulary/pages/vocabulary_page.dart +++ /dev/null @@ -1,156 +0,0 @@ -import 'dart:async'; - -import 'package:flutter/material.dart'; -import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:flutter_screenutil/flutter_screenutil.dart'; - -import '../cubit/vocabulary_cubit.dart'; -import '../models/vocabulary_page_state.dart'; -import '../widgets/vocabulary_header.dart'; -import '../widgets/vocabulary_search_bar.dart'; -import '../widgets/vocabulary_categories.dart'; -import '../widgets/vocabulary_progress.dart'; -import '../widgets/vocabulary_words_list.dart'; - -class VocabularyPage extends StatefulWidget { - const VocabularyPage({super.key}); - - @override - State createState() => _VocabularyPageState(); -} - -class _VocabularyPageState extends State { - late final VocabularyCubit _cubit; - bool _isSearchVisible = false; - StreamSubscription? _subscription; - - @override - void initState() { - super.initState(); - _cubit = VocabularyCubit(); - _subscription ??= Stream.periodic(const Duration(seconds: 1), (v) => v) - .asyncMap((_) { - if (mounted) { - return _loadData(); - } - }) - .listen((_) {}); - } - - @override - void dispose() { - _subscription?.cancel(); - _cubit.close(); - super.dispose(); - } - - Future _loadData() async { - await Future.wait([ - _cubit.loadWords(), - _cubit.loadUserData(), - _cubit.loadCategories(), - ]); - } - - @override - Widget build(BuildContext context) { - return BlocProvider( - create: (context) => _cubit, - child: Scaffold( - appBar: AppBar( - title: const Text('Знания'), - actions: [ - IconButton( - icon: Icon(_isSearchVisible ? Icons.close : Icons.search), - onPressed: () { - setState(() { - _isSearchVisible = !_isSearchVisible; - }); - if (!_isSearchVisible) { - _cubit.searchWords(''); - } - }, - ), - ], - ), - body: BlocBuilder( - builder: (context, state) { - if (state.isLoading) { - return const Center(child: CircularProgressIndicator()); - } - - if (state.error != null) { - return Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Icon(Icons.error_outline, size: 64.sp, color: Colors.red), - SizedBox(height: 16.h), - Text( - 'Ошибка загрузки', - style: TextStyle( - fontSize: 18.sp, - fontWeight: FontWeight.w600, - ), - ), - SizedBox(height: 8.h), - Text( - state.error!, - textAlign: TextAlign.center, - style: TextStyle( - fontSize: 14.sp, - color: Colors.grey[600], - ), - ), - SizedBox(height: 16.h), - ElevatedButton( - onPressed: _loadData, - child: const Text('Повторить'), - ), - ], - ), - ); - } - - return Column( - children: [ - if (_isSearchVisible) ...[ - VocabularySearchBar(onSearchChanged: _cubit.searchWords), - SizedBox(height: 16.h), - ], - Expanded( - child: SingleChildScrollView( - padding: EdgeInsets.all(16.w), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - VocabularyHeader( - learnedWordsCount: state.learnedWordsCount, - totalWordsCount: state.totalWordsCount, - ), - SizedBox(height: 24.h), - VocabularyProgress( - progress: state.progressPercentage, - learnedWords: state.learnedWordsCount, - totalWords: state.totalWordsCount, - ), - SizedBox(height: 24.h), - VocabularyCategories( - categories: state.updatedCategories, - selectedCategory: state.selectedCategory, - onCategorySelected: _cubit.selectCategory, - ), - SizedBox(height: 24.h), - VocabularyWordsList(words: state.searchedWords), - ], - ), - ), - ), - ], - ); - }, - ), - ), - ); - } -} diff --git a/mnemo_cards/lib/features/vocabulary/test_vocabulary_page.dart b/mnemo_cards/lib/features/vocabulary/test_vocabulary_page.dart deleted file mode 100644 index 086c6bf..0000000 --- a/mnemo_cards/lib/features/vocabulary/test_vocabulary_page.dart +++ /dev/null @@ -1,14 +0,0 @@ -import 'package:flutter/material.dart'; -import 'pages/vocabulary_page.dart'; - -/// Тестовая страница для проверки VocabularyPage -class TestVocabularyPage extends StatelessWidget { - const TestVocabularyPage({super.key}); - - @override - Widget build(BuildContext context) { - return const Scaffold( - body: VocabularyPage(), - ); - } -} diff --git a/mnemo_cards/lib/features/vocabulary/vocabulary.dart b/mnemo_cards/lib/features/vocabulary/vocabulary.dart deleted file mode 100644 index 18297f6..0000000 --- a/mnemo_cards/lib/features/vocabulary/vocabulary.dart +++ /dev/null @@ -1,20 +0,0 @@ -// Models -export 'models/vocabulary_category.dart'; -export 'models/vocabulary_word.dart'; -export 'models/vocabulary_page_state.dart'; -export 'models/word_difficulty.dart'; - -// Cubit -export 'cubit/vocabulary_cubit.dart'; - -// Pages -export 'pages/vocabulary_page.dart'; - -// Widgets -export 'widgets/vocabulary_header.dart'; -export 'widgets/vocabulary_search_bar.dart'; -export 'widgets/vocabulary_progress.dart'; -export 'widgets/vocabulary_categories.dart'; -export 'widgets/vocabulary_words_list.dart'; -export 'widgets/vocabulary_word_card.dart'; -export 'widgets/difficulty_chart.dart'; diff --git a/mnemo_cards/lib/features/vocabulary/widgets/difficulty_chart.dart b/mnemo_cards/lib/features/vocabulary/widgets/difficulty_chart.dart deleted file mode 100644 index 4d5a879..0000000 --- a/mnemo_cards/lib/features/vocabulary/widgets/difficulty_chart.dart +++ /dev/null @@ -1,117 +0,0 @@ -import 'dart:math'; -import 'package:flutter/material.dart'; -import 'package:flutter_screenutil/flutter_screenutil.dart'; -import '../models/word_difficulty.dart'; - -class DifficultyChart extends StatelessWidget { - final WordDifficulty difficulty; - final double? width; - final double? height; - - const DifficultyChart({ - super.key, - required this.difficulty, - this.width, - this.height, - }); - - @override - Widget build(BuildContext context) { - return SizedBox( - width: width ?? 40.w, - height: height ?? 20.h, - child: CustomPaint( - painter: DifficultyChartPainter(difficulty), - ), - ); - } -} - -class DifficultyChartPainter extends CustomPainter { - final WordDifficulty difficulty; - - DifficultyChartPainter(this.difficulty); - - @override - void paint(Canvas canvas, Size size) { - final paint = Paint() - ..color = difficulty.color - ..strokeWidth = 2.0 - ..style = PaintingStyle.stroke - ..strokeCap = StrokeCap.round; - - final path = Path(); - - // Создаем волнистую линию в зависимости от сложности - switch (difficulty) { - case WordDifficulty.easy: - _drawEasyWave(path, size); - break; - case WordDifficulty.medium: - _drawMediumWave(path, size); - break; - case WordDifficulty.hard: - _drawHardWave(path, size); - break; - } - - canvas.drawPath(path, paint); - } - - void _drawEasyWave(Path path, Size size) { - // Плавная волна для легкого уровня - final waveHeight = size.height * 0.3; - final waveLength = size.width / 3; - - path.moveTo(0, size.height / 2); - - for (double x = 0; x <= size.width; x += waveLength / 2) { - final y = size.height / 2 + waveHeight * sin(x / size.width - 0.5); - if (x == 0) { - path.moveTo(x, y); - } else { - path.lineTo(x, y); - } - } - } - - void _drawMediumWave(Path path, Size size) { - // Средняя волна для среднего уровня - final waveHeight = size.height * 0.4; - final waveLength = size.width / 4; - - path.moveTo(0, size.height / 2); - - for (double x = 0; x <= size.width; x += waveLength / 2) { - final y = size.height / 2 + waveHeight * sin(x / size.width * 2 - 0.5); - if (x == 0) { - path.moveTo(x, y); - } else { - path.lineTo(x, y); - } - } - } - - void _drawHardWave(Path path, Size size) { - // Сложная волна для трудного уровня - final waveHeight = size.height * 0.5; - final waveLength = size.width / 5; - - path.moveTo(0, size.height / 2); - - for (double x = 0; x <= size.width; x += waveLength / 2) { - final y = size.height / 2 + waveHeight * sin(x / size.width * 3 - 0.5); - if (x == 0) { - path.moveTo(x, y); - } else { - path.lineTo(x, y); - } - } - } - - @override - bool shouldRepaint(covariant CustomPainter oldDelegate) { - return oldDelegate is DifficultyChartPainter && - oldDelegate.difficulty != difficulty; - } -} diff --git a/mnemo_cards/lib/features/vocabulary/widgets/vocabulary_categories.dart b/mnemo_cards/lib/features/vocabulary/widgets/vocabulary_categories.dart deleted file mode 100644 index 12aef2d..0000000 --- a/mnemo_cards/lib/features/vocabulary/widgets/vocabulary_categories.dart +++ /dev/null @@ -1,154 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_screenutil/flutter_screenutil.dart'; -import '../models/vocabulary_category.dart'; - -class VocabularyCategories extends StatelessWidget { - final List categories; - final String? selectedCategory; - final Function(String?) onCategorySelected; - - const VocabularyCategories({ - super.key, - required this.categories, - required this.selectedCategory, - required this.onCategorySelected, - }); - - @override - Widget build(BuildContext context) { - if (categories.isEmpty) { - return const SizedBox.shrink(); - } - - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - 'Категории', - style: TextStyle( - fontSize: 16.sp, - fontWeight: FontWeight.w600, - ), - ), - SizedBox(height: 12.h), - SizedBox( - height: 40.h, - child: ListView.builder( - scrollDirection: Axis.horizontal, - itemCount: categories.length + 1, // +1 для "Все" - itemBuilder: (context, index) { - if (index == 0) { - return _buildAllCategoryTab(); - } - - final category = categories[index - 1]; - return _buildCategoryTab(category, context); - }, - ), - ), - ], - ); - } - - Widget _buildAllCategoryTab() { - final isSelected = selectedCategory == null; - - return Padding( - padding: EdgeInsets.only(right: 8.w), - child: GestureDetector( - onTap: () => onCategorySelected(null), - child: AnimatedContainer( - duration: const Duration(milliseconds: 200), - padding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 8.h), - decoration: BoxDecoration( - color: isSelected ? Colors.blue : Colors.grey[100], - borderRadius: BorderRadius.circular(20.r), - border: Border.all( - color: isSelected ? Colors.blue : Colors.grey[300]!, - width: 1, - ), - ), - child: Row( - mainAxisSize: MainAxisSize.min, - children: [ - Icon( - Icons.all_inclusive, - size: 16.sp, - color: isSelected ? Colors.white : Colors.grey[600], - ), - SizedBox(width: 4.w), - Text( - 'Все', - style: TextStyle( - fontSize: 12.sp, - fontWeight: FontWeight.w500, - color: isSelected ? Colors.white : Colors.grey[600], - ), - ), - ], - ), - ), - ), - ); - } - - Widget _buildCategoryTab(VocabularyCategory category, BuildContext context) { - final isSelected = selectedCategory == category.id; - - return Padding( - padding: EdgeInsets.only(right: 8.w), - child: GestureDetector( - onTap: () => onCategorySelected(category.id), - child: AnimatedContainer( - duration: const Duration(milliseconds: 200), - padding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 8.h), - decoration: BoxDecoration( - color: isSelected ? category.getColor(context) : Colors.grey[100], - borderRadius: BorderRadius.circular(20.r), - border: Border.all( - color: isSelected ? category.getColor(context) : Colors.grey[300]!, - width: 1, - ), - ), - child: Row( - mainAxisSize: MainAxisSize.min, - children: [ - Icon( - category.icon, - size: 16.sp, - color: isSelected ? Colors.white : Colors.grey[600], - ), - SizedBox(width: 4.w), - Text( - category.name, - style: TextStyle( - fontSize: 12.sp, - fontWeight: FontWeight.w500, - color: isSelected ? Colors.white : Colors.grey[600], - ), - ), - SizedBox(width: 4.w), - Container( - padding: EdgeInsets.symmetric(horizontal: 6.w, vertical: 2.h), - decoration: BoxDecoration( - color: isSelected - ? Colors.white.withOpacity(0.2) - : Colors.grey[300], - borderRadius: BorderRadius.circular(10.r), - ), - child: Text( - '${category.learnedWords}/${category.totalWords}', - style: TextStyle( - fontSize: 10.sp, - fontWeight: FontWeight.w500, - color: isSelected ? Colors.white : Colors.grey[600], - ), - ), - ), - ], - ), - ), - ), - ); - } -} diff --git a/mnemo_cards/lib/features/vocabulary/widgets/vocabulary_header.dart b/mnemo_cards/lib/features/vocabulary/widgets/vocabulary_header.dart deleted file mode 100644 index f637ddb..0000000 --- a/mnemo_cards/lib/features/vocabulary/widgets/vocabulary_header.dart +++ /dev/null @@ -1,46 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_screenutil/flutter_screenutil.dart'; - -class VocabularyHeader extends StatelessWidget { - final int learnedWordsCount; - final int totalWordsCount; - - const VocabularyHeader({ - super.key, - required this.learnedWordsCount, - required this.totalWordsCount, - }); - - /// Определяет текст для отображения на основе количества изученных слов - String _getLearnedWordsText(int learnedWordsCount) { - if (learnedWordsCount == 0) return 'Словарик'; - - final lastDigit = learnedWordsCount % 10; - if (lastDigit == 0 || lastDigit >= 5) { - return 'Ты уже знаешь $learnedWordsCount слов!'; - } else if (lastDigit == 1) { - return 'Ты уже знаешь $learnedWordsCount слово!'; - } else { - return 'Ты уже знаешь $learnedWordsCount слова!'; - } - } - - @override - Widget build(BuildContext context) { - return Container( - alignment: Alignment.centerLeft, - padding: EdgeInsets.symmetric(vertical: 4.0.h), - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(16), - ), - child: Text( - _getLearnedWordsText(learnedWordsCount), - style: TextStyle( - fontSize: 18.sp, - fontWeight: FontWeight.w600, - ), - maxLines: 1, - ), - ); - } -} diff --git a/mnemo_cards/lib/features/vocabulary/widgets/vocabulary_progress.dart b/mnemo_cards/lib/features/vocabulary/widgets/vocabulary_progress.dart deleted file mode 100644 index 6dd7fd6..0000000 --- a/mnemo_cards/lib/features/vocabulary/widgets/vocabulary_progress.dart +++ /dev/null @@ -1,56 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_screenutil/flutter_screenutil.dart'; -import 'package:mnemo_cards_frontend_common/mnemo_cards_frontend_common.dart'; - -class VocabularyProgress extends StatelessWidget { - final double progress; - final int learnedWords; - final int totalWords; - - const VocabularyProgress({ - super.key, - required this.progress, - required this.learnedWords, - required this.totalWords, - }); - - @override - Widget build(BuildContext context) { - return Container( - padding: EdgeInsets.all(16.w), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(16.r), - boxShadow: [ - BoxShadow( - color: Colors.black.withOpacity(0.05), - blurRadius: 10, - offset: const Offset(0, 2), - ), - ], - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - 'Выучено: $learnedWords из $totalWords слов', - style: TextStyle( - fontSize: 16.sp, - fontWeight: FontWeight.w600, - ), - ), - SizedBox(height: 16.h), - SizedBox( - height: 8.h, - child: HorizontalProgressWidget( - (progress * 100).toInt(), - 100, - Colors.purple, - height: 8.h, - ), - ), - ], - ), - ); - } -} diff --git a/mnemo_cards/lib/features/vocabulary/widgets/vocabulary_search_bar.dart b/mnemo_cards/lib/features/vocabulary/widgets/vocabulary_search_bar.dart deleted file mode 100644 index 57ddfbc..0000000 --- a/mnemo_cards/lib/features/vocabulary/widgets/vocabulary_search_bar.dart +++ /dev/null @@ -1,89 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_screenutil/flutter_screenutil.dart'; - -class VocabularySearchBar extends StatefulWidget { - final Function(String) onSearchChanged; - - const VocabularySearchBar({ - super.key, - required this.onSearchChanged, - }); - - @override - State createState() => _VocabularySearchBarState(); -} - -class _VocabularySearchBarState extends State { - late final TextEditingController _controller; - String _lastSearchQuery = ''; - - @override - void initState() { - super.initState(); - _controller = TextEditingController(); - } - - @override - void dispose() { - _controller.dispose(); - super.dispose(); - } - - void _onSearchChanged(String query) { - if (query != _lastSearchQuery) { - _lastSearchQuery = query; - widget.onSearchChanged(query); - } - } - - void _clearSearch() { - _controller.clear(); - _onSearchChanged(''); - } - - @override - Widget build(BuildContext context) { - return Container( - margin: EdgeInsets.symmetric(horizontal: 16.w), - decoration: BoxDecoration( - color: Colors.grey[100], - borderRadius: BorderRadius.circular(12.r), - border: Border.all(color: Colors.grey[300]!), - ), - child: TextField( - controller: _controller, - onChanged: _onSearchChanged, - decoration: InputDecoration( - hintText: 'Поиск слов...', - hintStyle: TextStyle( - color: Colors.grey[500], - fontSize: 14.sp, - ), - prefixIcon: Icon( - Icons.search, - color: Colors.grey[500], - size: 20.sp, - ), - suffixIcon: _controller.text.isNotEmpty - ? IconButton( - icon: Icon( - Icons.clear, - color: Colors.grey[500], - size: 20.sp, - ), - onPressed: _clearSearch, - ) - : null, - border: InputBorder.none, - contentPadding: EdgeInsets.symmetric( - horizontal: 16.w, - vertical: 12.h, - ), - ), - style: TextStyle( - fontSize: 14.sp, - ), - ), - ); - } -} diff --git a/mnemo_cards/lib/features/vocabulary/widgets/vocabulary_word_card.dart b/mnemo_cards/lib/features/vocabulary/widgets/vocabulary_word_card.dart deleted file mode 100644 index 614a60c..0000000 --- a/mnemo_cards/lib/features/vocabulary/widgets/vocabulary_word_card.dart +++ /dev/null @@ -1,108 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_screenutil/flutter_screenutil.dart'; -import 'package:mnemo_cards/di/locator.dart'; -import 'package:mnemo_cards/features/packs/images_holder.dart'; -import 'package:mnemo_cards/theme/themes.dart'; -import 'package:mnemo_cards_common/mnemo_cards_common.dart'; -import '../models/vocabulary_word.dart'; -import 'difficulty_chart.dart'; - -class VocabularyWordCard extends StatelessWidget { - final VocabularyWord word; - final VoidCallback onFavoriteToggle; - final VoidCallback onAudioPlay; - - const VocabularyWordCard({ - super.key, - required this.word, - required this.onFavoriteToggle, - required this.onAudioPlay, - }); - - @override - Widget build(BuildContext context) { - return AnimatedContainer( - duration: const Duration(milliseconds: 300), - padding: EdgeInsets.all(16.w), - decoration: BoxDecoration( - color: word.isLearned ? golden.withOpacity(0.1) : Colors.white, - borderRadius: BorderRadius.circular(12.r), - border: Border.all( - color: word.isLearned ? golden.withOpacity(0.3) : borderGray, - width: 1, - ), - ), - child: Row( - children: [ - // Изображение слова - _buildWordImage(), - SizedBox(width: 16.w), - - // Основная информация о слове - Expanded(child: _buildWordInfo()), - - // График сложности - DifficultyChart( - difficulty: word.difficulty, - width: 40.w, - height: 20.h, - ), - ], - ), - ); - } - - Widget _buildWordImage() { - return Container( - width: 80.w, - height: 80.h, - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(8.r), - color: Colors.grey[100], - ), - child: - word.gameCard.memoryImage?.let((m) => Image(image: m)) ?? - SizedBox.shrink(), - ); - } - - Widget _buildWordInfo() { - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - // Статус изучения - if (word.isLearned) ...[ - Row( - children: [ - Icon(Icons.check_circle, size: 16.sp, color: golden), - SizedBox(width: 4.w), - Text( - 'Изучено', - style: TextStyle( - fontSize: 12.sp, - fontWeight: FontWeight.w500, - color: golden, - ), - ), - ], - ), - SizedBox(height: 4.h), - ], - - // Испанское слово - Text( - word.original, - style: TextStyle(fontSize: 18.sp, fontWeight: FontWeight.w600), - ), - - SizedBox(height: 4.h), - - // Русский перевод - Text( - word.translation, - style: TextStyle(fontSize: 14.sp, color: Colors.grey[700]), - ), - ], - ); - } -} diff --git a/mnemo_cards/lib/features/vocabulary/widgets/vocabulary_words_list.dart b/mnemo_cards/lib/features/vocabulary/widgets/vocabulary_words_list.dart deleted file mode 100644 index 4077b7d..0000000 --- a/mnemo_cards/lib/features/vocabulary/widgets/vocabulary_words_list.dart +++ /dev/null @@ -1,77 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_screenutil/flutter_screenutil.dart'; -import '../models/vocabulary_word.dart'; -import 'vocabulary_word_card.dart'; - -class VocabularyWordsList extends StatelessWidget { - final List words; - - const VocabularyWordsList({ - super.key, - required this.words, - }); - - @override - Widget build(BuildContext context) { - if (words.isEmpty) { - return Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Icon( - Icons.book, - size: 48.sp, - color: Colors.grey[400], - ), - SizedBox(height: 16.h), - Text( - 'Слова не найдены', - textAlign: TextAlign.center, - style: TextStyle( - fontSize: 16.sp, - color: Colors.grey[600], - ), - ), - SizedBox(height: 8.h), - Text( - 'Попробуйте изменить поисковый запрос или выберите другую категорию', - textAlign: TextAlign.center, - style: TextStyle( - fontSize: 14.sp, - color: Colors.grey[500], - ), - ), - ], - ), - ); - } - - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - 'Слова (${words.length})', - style: TextStyle( - fontSize: 16.sp, - fontWeight: FontWeight.w600, - ), - ), - SizedBox(height: 12.h), - ListView.separated( - shrinkWrap: true, - physics: const NeverScrollableScrollPhysics(), - itemCount: words.length, - separatorBuilder: (context, index) => SizedBox(height: 8.h), - itemBuilder: (context, index) { - final word = words[index]; - return VocabularyWordCard( - word: word, - onFavoriteToggle: () {}, // Заглушка - onAudioPlay: () {}, // Заглушка - ); - }, - ), - ], - ); - } -} diff --git a/mnemo_cards/lib/features/worker/worker_ext.dart b/mnemo_cards/lib/features/worker/worker_ext.dart deleted file mode 100644 index fd69a3f..0000000 --- a/mnemo_cards/lib/features/worker/worker_ext.dart +++ /dev/null @@ -1,29 +0,0 @@ -import 'dart:convert'; - -import 'package:flutter/foundation.dart'; -import 'package:mnemo_cards_common/mnemo_cards_common.dart'; - -extension JsonStringExt on String { - Future isolatedDecode([T Function(Map)? fromJson]) => - compute( - (_) => this.decode(fromJson), - null, - debugLabel: 'decode: $T', - ); - - Future> isolatedDecodeList( - [T Function(Map)? fromJson]) => - compute( - (_) => this.decodeList(fromJson), - null, - debugLabel: 'decodeList: $T', - ); -} - -extension JsonStringExt2 on T { - Future isolatedEncode() => compute( - (_) => this.encode(), - null, - debugLabel: 'encode: $T', - ); -} diff --git a/mnemo_cards/lib/features/yandex_ads/ads_deeplink_handler.dart b/mnemo_cards/lib/features/yandex_ads/ads_deeplink_handler.dart deleted file mode 100644 index 0df0008..0000000 --- a/mnemo_cards/lib/features/yandex_ads/ads_deeplink_handler.dart +++ /dev/null @@ -1,58 +0,0 @@ -import 'dart:async'; - -import 'package:mnemo_cards/di/locator.dart'; -import 'package:mnemo_cards/domain/router/dialogs.dart'; -import 'package:mnemo_cards/features/analytics/analytics.dart'; -import 'package:mnemo_cards/features/deeplinks/deeplinks_manager.dart'; -import 'package:mnemo_cards/features/yandex_ads/yandex_ads.dart'; -import 'package:mnemo_cards_common/mnemo_cards_common.dart'; - -import 'yandex_rewarded_ads.dart'; - -class AdsDeeplinkHandler implements DeeplinkHandler { - YandexRewardedAds _yandexRewardedAds; - - AdsDeeplinkHandler(this._yandexRewardedAds); - - @override - bool canHandle(Uri uri) => uri.host == 'ad'; - - @override - FutureOr handle(Uri uri) { - final path = uri.path.replaceFirst('/', ''); - switch (path) { - case ProductForAdDeeplink.deeplinkPath: - return _productForAd(uri); - } - Analytics.buyDeeplinkError(uri, message: 'Unknown path: ${path}'); - } - - Future _productForAd(Uri uri) async { - final model = ProductForAdDeeplink.parse(uri); - _yandexRewardedAds.showRewardedAd((r) async { - try { - final success = await locator.userManager.acquireProductForAd(model.key, model.product); - if (success) { - locator.packUpdater.updateAvailablePacks(); - // showInfoDialog('Вы получили награду!'); - // showInfoDialog('${r.message}'); - // } else if (r.success == true) { - // showInfoDialog('Вы получили награду!'); - // } else if (r.success == false) { - // showInfoDialog( - // 'Что-то пошло не так\nПопробуйте ввести промокод:', - // secondMessage: model.key, - // ); - } else { - showInfoDialog('Не удалось зачислить награду'); - } - } catch (e, s) { - showInfoDialog( - "Что-то пошло не так" - // 'Что-то пошло не так\nПопробуйте ввести промокод:', - // secondMessage: model.key, - ); - } - }); - } -} diff --git a/mnemo_cards/lib/features/yandex_ads/yandex_ads.dart b/mnemo_cards/lib/features/yandex_ads/yandex_ads.dart deleted file mode 100644 index 67eda27..0000000 --- a/mnemo_cards/lib/features/yandex_ads/yandex_ads.dart +++ /dev/null @@ -1,48 +0,0 @@ -import 'dart:async'; -import 'dart:developer'; - -import 'package:auto_route/auto_route.dart'; -import 'package:flutter/widgets.dart'; -import 'package:mnemo_cards/domain/router/dialogs.dart'; -import 'package:mnemo_cards/features/analytics/analytics.dart'; -import 'package:yandex_mobileads/mobile_ads.dart'; - -import '../../main.dart'; - -class YandexAds { - static BannerAd createBanner( - BoxConstraints constraints, { - required String id, - String? key, - VoidCallback? onLoaded, - }) { - return BannerAd( - adUnitId: id, - // or 'demo-banner-yandex' - adSize: BannerAdSize.inline( - width: constraints.maxWidth.round(), - maxHeight: constraints.maxHeight.round(), - ), - adRequest: const AdRequest(), - onAdLoaded: () { - log('Loaded $key'); - onLoaded?.call(); - }, - onAdFailedToLoad: (error) { - // Ad failed to load with AdRequestError. - // Attempting to load a new ad from the onAdFailedToLoad() method is strongly discouraged. - }, - onAdClicked: () { - // Called when a click is recorded for an ad. - }, - onLeftApplication: () { - // Called when user is about to leave application (e.g., to go to the browser), as a result of clicking on the ad. - }, - onReturnedToApplication: () { - // Called when user returned to application after click. - }, - onImpression: (impressionData) { - // Called when an impression is recorded for an ad. - }); - } -} diff --git a/mnemo_cards/lib/features/yandex_ads/yandex_rewarded_ads.dart b/mnemo_cards/lib/features/yandex_ads/yandex_rewarded_ads.dart deleted file mode 100644 index 175d60d..0000000 --- a/mnemo_cards/lib/features/yandex_ads/yandex_rewarded_ads.dart +++ /dev/null @@ -1,99 +0,0 @@ -import 'dart:async'; - -import 'package:flutter/widgets.dart'; -import 'package:yandex_mobileads/mobile_ads.dart'; - -import '../../domain/router/dialogs.dart'; -import '../analytics/analytics.dart'; - -typedef RewardCallback = Function(Reward reward); - -class Event { - RewardedAd? ad; - RewardCallback onRewarded; - String? message; - - Event(this.ad, this.onRewarded, this.message); -} - -class YandexRewardedAds { - RewardedAdLoader? _adLoader; - Completer? _dialogCompleter; - StreamSubscription? _subscription; - - final StreamController _streamController = - StreamController.broadcast(); - - Future init() async { - _subscription ??= _streamController.stream.asyncMap((event) async { - final ad = event.ad; - final message = event.message; - if (ad != null) { - await ad.setAdEventListener( - eventListener: RewardedAdEventListener( - onAdDismissed: () { - ad.destroy(); - }, - onAdFailedToShow: (e) { - ad.destroy(); - }, - onAdShown: () {}, - onRewarded: (r) { - ad.destroy(); - event.onRewarded(r); - }, - ), - ); - ad.show(); - _dialogCompleter?.complete(); - } else if (message != null) { - _dialogCompleter?.complete(); - _dialogCompleter = Completer(); - showInfoDialog(message, completer: _dialogCompleter); - await waitForFrame(); - } - }).listen((_) {}); - } - - Future _createAdLoader(RewardCallback onRewarded) async { - return await RewardedAdLoader.create( - onAdLoaded: (RewardedAd ad) { - _streamController.add(Event(ad, onRewarded, null)); - }, - onAdFailedToLoad: (error) { - _streamController.add( - Event(null, onRewarded, 'Что-то пошло не так'), - ); - Analytics.crashlyticsError( - e: error, - s: null, - message: 'onAdFailedToLoad when loading rewarded ad ', - ); - }, - ); - } - - Future showRewardedAd(RewardCallback onRewarded) async { - try { - _streamController.add( - Event(null, onRewarded, 'Загрузка...'), - ); - _adLoader = await _createAdLoader(onRewarded); - _adLoader!.loadAd( - adRequestConfiguration: AdRequestConfiguration( - adUnitId: 'R-M-3761037-1', - ), - ); - } catch (e, s) { - Analytics.crashlyticsError(e: e, s: s, message: 'showRewardedAd'); - } - } - - static Future waitForFrame() { - final completer = Completer(); - WidgetsBinding.instance.addPostFrameCallback((_) { - completer.complete(); - }); - return completer.future; - } -} diff --git a/mnemo_cards/lib/firebase_options.dart b/mnemo_cards/lib/firebase_options.dart deleted file mode 100644 index f0ff4d2..0000000 --- a/mnemo_cards/lib/firebase_options.dart +++ /dev/null @@ -1,86 +0,0 @@ -// File generated by FlutterFire CLI. -// ignore_for_file: lines_longer_than_80_chars, avoid_classes_with_only_static_members -import 'package:firebase_core/firebase_core.dart' show FirebaseOptions; -import 'package:flutter/foundation.dart' - show defaultTargetPlatform, kIsWeb, TargetPlatform; - -/// Default [FirebaseOptions] for use with your Firebase apps. -/// -/// Example: -/// ```dart -/// import 'firebase_options.dart'; -/// // ... -/// await Firebase.initializeApp( -/// options: DefaultFirebaseOptions.currentPlatform, -/// ); -/// ``` -class DefaultFirebaseOptions { - static FirebaseOptions get currentPlatform { - if (kIsWeb) { - return web; - } - switch (defaultTargetPlatform) { - case TargetPlatform.android: - return android; - case TargetPlatform.iOS: - return ios; - case TargetPlatform.macOS: - return macos; - case TargetPlatform.windows: - throw UnsupportedError( - 'DefaultFirebaseOptions have not been configured for windows - ' - 'you can reconfigure this by running the FlutterFire CLI again.', - ); - case TargetPlatform.linux: - throw UnsupportedError( - 'DefaultFirebaseOptions have not been configured for linux - ' - 'you can reconfigure this by running the FlutterFire CLI again.', - ); - default: - throw UnsupportedError( - 'DefaultFirebaseOptions are not supported for this platform.', - ); - } - } - - static const FirebaseOptions web = FirebaseOptions( - apiKey: 'AIzaSyCq0V8JebjtqSgGSueouoLiprBROgPRBQw', - appId: '1:701767851968:web:714eb4fb5e3fd1ab2f7225', - messagingSenderId: '701767851968', - projectId: 'mnemo-cards', - authDomain: 'mnemo-cards.firebaseapp.com', - storageBucket: 'mnemo-cards.appspot.com', - measurementId: 'G-C37MMWS6WC', - ); - - static const FirebaseOptions android = FirebaseOptions( - apiKey: 'AIzaSyBGn7PVVDX-o7WipivtuBjdoH5nYEPsHms', - appId: '1:701767851968:android:6190df55346394732f7225', - messagingSenderId: '701767851968', - projectId: 'mnemo-cards', - storageBucket: 'mnemo-cards.appspot.com', - ); - - static const FirebaseOptions ios = FirebaseOptions( - apiKey: 'AIzaSyAodY8s0ntALNeeGiUiTx6eg4g2Ar6C1to', - appId: '1:701767851968:ios:5c9040634eac8c152f7225', - messagingSenderId: '701767851968', - projectId: 'mnemo-cards', - storageBucket: 'mnemo-cards.appspot.com', - androidClientId: '701767851968-3jgootslus3ie76t682j4v7glletloud.apps.googleusercontent.com', - iosClientId: '701767851968-8dqcmk706p08gujqbl2m9s4sq1aljibs.apps.googleusercontent.com', - iosBundleId: 'com.cinnabarflower.mnemoCards', - ); - - static const FirebaseOptions macos = FirebaseOptions( - apiKey: 'AIzaSyAodY8s0ntALNeeGiUiTx6eg4g2Ar6C1to', - appId: '1:701767851968:ios:5c9040634eac8c152f7225', - messagingSenderId: '701767851968', - projectId: 'mnemo-cards', - storageBucket: 'mnemo-cards.appspot.com', - androidClientId: '701767851968-dvbvmte4m90dkqitp013s4nd5c0df1n8.apps.googleusercontent.com', - iosClientId: '701767851968-8dqcmk706p08gujqbl2m9s4sq1aljibs.apps.googleusercontent.com', - iosBundleId: 'com.cinnabarflower.mnemoCards', - ); - -} \ No newline at end of file diff --git a/mnemo_cards/lib/flags.dart b/mnemo_cards/lib/flags.dart deleted file mode 100644 index be4236b..0000000 --- a/mnemo_cards/lib/flags.dart +++ /dev/null @@ -1,25 +0,0 @@ -import 'dart:io'; - -import 'package:flutter/foundation.dart'; -import 'package:mnemo_cards/admin/admin_api.dart'; -import 'package:mnemo_cards/di/injector.dart'; -import 'package:mnemo_cards/main.dart'; -import 'package:mnemo_cards_frontend_common/mnemo_cards_frontend_common.dart'; - -import 'di/locator.dart'; -import 'managers/user_manager.dart'; - -bool get ADMIN_BUILD => - kDebugMode || - (getIt.isRegistered() && - locator.userManager.user?.admin == true); -const RUSTORE_BUILD = CommonPrefs.RUSTORE_BUILD; - -final androidPaymentSystem = CommonPrefs.androidPaymentSystem; - -bool get SHOW_ADMIN => - getIt.isRegistered() && - ADMIN_BUILD && - (globalSharedPreferences.getBool('show_admin') ?? true); - -bool get isMobile => Platform.isAndroid || Platform.isIOS; diff --git a/mnemo_cards/lib/main.dart b/mnemo_cards/lib/main.dart deleted file mode 100644 index 6b7b743..0000000 --- a/mnemo_cards/lib/main.dart +++ /dev/null @@ -1,545 +0,0 @@ -import 'dart:async'; -import 'dart:developer'; -import 'package:google_sign_in/google_sign_in.dart'; -import 'package:universal_io/io.dart'; -import 'dart:math' as math; - -import 'package:auto_route/auto_route.dart'; -import 'package:device_info_plus/device_info_plus.dart'; -import 'package:firebase_core/firebase_core.dart'; -import 'package:firebase_crashlytics/firebase_crashlytics.dart'; -import 'package:firebase_messaging/firebase_messaging.dart'; -import 'package:flutter/foundation.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter/scheduler.dart'; -import 'package:flutter/services.dart'; -import 'package:flutter_local_notifications/flutter_local_notifications.dart'; -import 'package:flutter_screenutil/flutter_screenutil.dart'; -import 'package:flutter_secure_storage/flutter_secure_storage.dart'; -import 'package:jailbreak_root_detection/jailbreak_root_detection.dart'; -import 'package:mnemo_cards/di/locator.dart'; -import 'package:mnemo_cards/domain/router/app_router.dart'; -import 'package:mnemo_cards/managers/repository/firebase_config_repository.dart'; -import 'package:mnemo_cards/managers/remote_config_manager.dart'; -import 'package:mnemo_cards/features/packs/pack_manager.dart'; -import 'package:mnemo_cards/theme/themes.dart'; -import 'package:mnemo_cards_common/mnemo_cards_common.dart'; -import 'package:shared_preferences/shared_preferences.dart'; - -// import 'package:telegram_web_app/telegram_web_app.dart' as tg; -import 'package:yandex_mobileads/mobile_ads.dart'; - -import 'common_device_info.dart'; -import 'di/injector.dart'; -import 'domain/router/app_router.gr.dart'; -import 'firebase_options.dart'; -import 'flags.dart'; -import 'managers/repository/repository.dart'; - -final scaffoldKey = GlobalKey(); -final scaffoldMessengerKey = GlobalKey(); -// final telegramWebApp = tg.TelegramWebAppFake(); - -late final SharedPreferences globalSharedPreferences; -late final FlutterSecureStorage secureStorage; - -final appRouter = AppRouter(ADMIN_BUILD); - -CommonDeviceInfo? deviceInfo; - -Future _screenOff() async => true; -// Future _screenOff() async => !isMobile -// ? true -// : ADMIN_BUILD -// ? await NoScreenshot.instance.screenshotOn() -// : await NoScreenshot.instance.screenshotOff(); - -void main() async { - try { - // if (telegramWebApp.isSupported) { - // telegramWebApp.ready(); - // Future.delayed( - // const Duration(seconds: 1), - // telegramWebApp.expand, - // ); - // // tg.TelegramWebApp.instance.set - // } - } catch (e) { - print("Error happened in Flutter while loading Telegram $e"); - // add delay for 'Telegram seldom not loading' bug - await Future.delayed(const Duration(milliseconds: 200)); - main(); - return; - } - - FlutterError.onError = (details) { - print("Flutter error happened: $details"); - }; - - WidgetsFlutterBinding.ensureInitialized(); - final stopwatch = Stopwatch()..start(); - print('ensureInitialized ${stopwatch.elapsedMilliseconds}'); - SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]); - await _fillDeviceInfo(); - print('deviceInfo ${stopwatch.elapsedMilliseconds}'); - if (!kDebugMode && !kIsWeb) { - final isNotTrust = await JailbreakRootDetection.instance.isNotTrust; - print('No trusted ${stopwatch.elapsedMilliseconds}'); - if (isNotTrust && !ADMIN_BUILD) { - print('Not trusted'); - return; - } - final off = await _screenOff(); - print('screenshot off ${stopwatch.elapsedMilliseconds}'); - if (!off) { - print('Cant disable screenhsot'); - return; - } - } - - FlutterError.onError = (errorDetails) { - FirebaseCrashlytics.instance.recordFlutterFatalError(errorDetails); - }; - - try { - secureStorage = FlutterSecureStorage( - aOptions: const AndroidOptions(encryptedSharedPreferences: true), - ); - globalSharedPreferences = await SharedPreferences.getInstance(); - - await _fillSp(); - print('global sp ${stopwatch.elapsedMilliseconds}'); - await setInjections(); - - final darkTheme = globalSharedPreferences.getBool('dark_theme') ?? false; - themeNotifier.value = darkTheme ? ThemeMode.dark : ThemeMode.light; - - print('injections ${stopwatch.elapsedMilliseconds}'); - if (isMobile) { - unawaited(initFirebase()); - } - print('initing... ${stopwatch.elapsedMilliseconds}'); - await locator.packCacheManager.init().then( - (_) => print('packCacheManager inited ${stopwatch.elapsedMilliseconds}'), - ); - await Future.wait([ - locator.gamesManager.init().then( - (_) => print('gameManager inited ${stopwatch.elapsedMilliseconds}'), - ), - locator.previewPackHolder.init().then( - (_) => - print('previewPackHolder inited ${stopwatch.elapsedMilliseconds}'), - ), - locator.previewPackPoller.init().then( - (_) => - print('previewPackPoller inited ${stopwatch.elapsedMilliseconds}'), - ), - locator.packManager.init().then( - (_) => print('packManager inited ${stopwatch.elapsedMilliseconds}'), - ), - locator.userManager.init().then( - (_) => print('userManager inited ${stopwatch.elapsedMilliseconds}'), - ), - locator.favoriteCardsController.init().then( - (_) => print( - 'favoriteCardsController inited ${stopwatch.elapsedMilliseconds}', - ), - ), - locator.previewPackPoller.init().then( - (_) => - print('previewPackPoller inited ${stopwatch.elapsedMilliseconds}'), - ), - locator.deeplinkManager.init().then( - (_) => print('deeplinkManager inited ${stopwatch.elapsedMilliseconds}'), - ), - ]); - await locator.packUpdater.init().then( - (_) => print('packUpdater inited ${stopwatch.elapsedMilliseconds}'), - ); - print('initing complete ${stopwatch.elapsedMilliseconds}'); - if (isMobile) unawaited(MobileAds.initialize()); - print('mobile ads ${stopwatch.elapsedMilliseconds}'); - print('runApp ${stopwatch.elapsedMilliseconds}'); - runApp(const MyApp()); - } on Object catch (e, s) { - print('err: ${e.toString()}'); - print('stacktrace: ${s.toString()}'); - log(e.toString(), stackTrace: s); - exit(0); - } -} - -Future _fillDeviceInfo() async { - final info = await DeviceInfoPlugin().deviceInfo; - if (Platform.isAndroid) { - info as AndroidDeviceInfo; - deviceInfo = CommonDeviceInfo(isPhysicalDevice: info.isPhysicalDevice); - } else if (Platform.isIOS) { - info as IosDeviceInfo; - deviceInfo = CommonDeviceInfo(isPhysicalDevice: info.isPhysicalDevice); - } else if (Platform.isMacOS) { - info as MacOsDeviceInfo; - deviceInfo = CommonDeviceInfo(isPhysicalDevice: true); - } -} - -Future _fillSp() async { - final showAdmin = globalSharedPreferences.getBool('show_admin'); - if (showAdmin == null && ADMIN_BUILD) { - await globalSharedPreferences.setBool('show_admin', true); - } - final soundOn = globalSharedPreferences.getBool('sound_on'); - if (soundOn == null) { - await globalSharedPreferences.setBool('sound_on', true); - } - final soundSpeed = globalSharedPreferences.getDouble('sound_speed'); - if (soundSpeed == null) { - await globalSharedPreferences.setDouble('sound_speed', 0.8); - } - final autoPlay = globalSharedPreferences.getBool('auto_play_sound_tests'); - if (autoPlay == null) { - await globalSharedPreferences.setBool('auto_play_sound_tests', true); - } - final autoPlayView = globalSharedPreferences.getBool('auto_play_sound_view'); - if (autoPlayView == null) { - await globalSharedPreferences.setBool('auto_play_sound_view', false); - } - final darkTheme = globalSharedPreferences.getBool('dark_theme'); - if (darkTheme == null) { - var brightness = - SchedulerBinding.instance.platformDispatcher.platformBrightness; - bool isDarkMode = brightness == Brightness.dark; - await globalSharedPreferences.setBool('dark_theme', isDarkMode); - } -} - -Future initFirebase() async { - try { - await Firebase.initializeApp( - options: DefaultFirebaseOptions.currentPlatform, - ); - await FirebaseRepository.update(); - await RemoteConfigManager().initialize(); - log('Firebase inited'); - log('Initing messages and auth...'); - await Future.wait([ - FirebaseMessaging.instance.setAutoInitEnabled(true), - GoogleSignIn.instance.initialize( - clientId: kIsWeb - ? '701767851968-bud97rud1d9qtqju96addn31nhm0oofu.apps.googleusercontent.com' - : null, - // "701767851968-bud97rud1d9qtqju96addn31nhm0oofu.apps.googleusercontent.com", - ), - ]); - String? token = await FirebaseMessaging.instance.getToken(); - print('Token: $token'); - await FirebaseMessaging.instance.requestPermission(provisional: true); - - FirebaseMessaging.instance.onTokenRefresh - .listen((fcmToken) { - print('FCM Token: $token'); - }) - .onError((err) { - // Error getting token. - }); - var initializationSettingsAndroid = AndroidInitializationSettings( - '@mipmap/launcher_icon', - ); - var initializationSettings = InitializationSettings( - android: initializationSettingsAndroid, - ); - await _flutterLocalNotificationsPlugin.initialize(initializationSettings); - - FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler); - // For apple platforms, ensure the APNS token is available before making any FCM plugin API calls - // final apnsToken = await FirebaseMessaging.instance.getAPNSToken(); - // if (apnsToken != null) { - // // APNS token is available, make FCM plugin API requests... - // } - log('Messages inited'); - } on Object catch (e, s) { - log('Firebase not inited', error: e, stackTrace: s); - } -} - -final _flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin(); - -Future _firebaseMessagingBackgroundHandler(RemoteMessage message) async { - await Firebase.initializeApp(); - print('Handling a background message: ${message.messageId}'); - - if (message.notification == null) { - await _flutterLocalNotificationsPlugin.show( - 0, - message.notification?.title, - message.notification?.body, - null, - payload: 'item x', - ); - } -} - -class MyApp extends StatelessWidget with WidgetsBindingObserver { - const MyApp({super.key}); - - @override - Widget build(BuildContext context) { - WidgetsBinding.instance.addObserver(this); - return ScreenUtilInit( - designSize: const Size(370, 800), - minTextAdapt: true, - splitScreenMode: true, - child: ValueListenableBuilder( - builder: (context, themeMode, child) { - return MaterialApp.router( - theme: theme2, - darkTheme: darkTheme2, - themeMode: themeMode, - routerConfig: appRouter.config( - deepLinkBuilder: (link) { - return DeepLink.defaultPath; - }, - ), - scaffoldMessengerKey: scaffoldMessengerKey, - debugShowCheckedModeBanner: false, - ); - }, - valueListenable: themeNotifier, - ), - ); - } - - @override - void didChangeAppLifecycleState(AppLifecycleState state) { - switch (state) { - case AppLifecycleState.resumed: - _screenOff(); - break; - case AppLifecycleState.inactive: - _screenOff(); - break; - case AppLifecycleState.paused: - _screenOff(); - break; - case AppLifecycleState.detached: - break; - case AppLifecycleState.hidden: - break; - } - } -} - -@RoutePage() -class MainTabsPage extends StatefulWidget { - const MainTabsPage({super.key}); - - @override - State createState() => _MainTabsPageState(); -} - -class _MainTabsPageState extends State - with TickerProviderStateMixin { - late List cardPacks; - late List cards; - CardPackDto? pack; - - late Repository repository; - late PackManager packManager; - late RemoteConfigManager remoteConfigManager; - bool _gamesEnabled = false; - - @override - void didChangeDependencies() { - super.didChangeDependencies(); - print('CHANGE DEPS'); - } - - @override - void initState() { - super.initState(); - repository = locator.repository; - packManager = locator.packManager; - remoteConfigManager = RemoteConfigManager(); - _gamesEnabled = remoteConfigManager.gamesEnabled; - - // Обновляем конфигурацию периодически - _refreshRemoteConfig(); - } - - Future _refreshRemoteConfig() async { - await remoteConfigManager.refresh(); - if (mounted) { - setState(() { - _gamesEnabled = remoteConfigManager.gamesEnabled; - }); - } - - // Обновляем конфигурацию каждые 5 минут - Future.delayed(const Duration(minutes: 5), () { - if (mounted) { - _refreshRemoteConfig(); - } - }); - } - - @override - Widget build(BuildContext context) { - final screenWidth = MediaQuery.of(context).size.width; - - // Создаем список маршрутов в зависимости от конфигурации - final routes = [ - PageRouteInfo(HomePage.name), - PageRouteInfo(VocabularyPage.name), - ]; - - // Добавляем вкладку игр только если она включена в Remote Config - if (_gamesEnabled) { - routes.add(PageRouteInfo(GamesPage.name)); - } - - routes.add(PageRouteInfo(ProfilePage.name)); - - return AutoTabsRouter.tabBar( - key: scaffoldKey, - homeIndex: 0, - routes: routes, - builder: (context, child, tabsController) { - final theme = Theme.of(context); - return Theme( - data: theme.copyWith( - tabBarTheme: theme.tabBarTheme.copyWith( - indicatorColor: Colors.transparent, - dividerHeight: 0, - tabAlignment: TabAlignment.fill, - // labelColor: MaterialColor(0xFF000000, color), - labelStyle: TextStyle( - fontFamily: 'Nunito', - fontSize: 36, - fontWeight: FontWeight.w700, - height: 0.85, - ), - unselectedLabelStyle: TextStyle( - fontFamily: 'Nunito', - fontSize: 16, - // fontWeight: FontWeight.w700, - height: 0.85, - ), - ), - ), - child: Scaffold( - body: child, - extendBody: true, - appBar: AppBar( - elevation: 0, - leadingWidth: 0, - centerTitle: false, - titleSpacing: 0, - leading: null, - automaticallyImplyLeading: false, - title: TabBar( - tabAlignment: TabAlignment.start, - isScrollable: true, - controller: tabsController, - padding: EdgeInsets.only(left: 4.w), - splashBorderRadius: BorderRadius.zero, - labelPadding: EdgeInsets.symmetric(horizontal: 8.w), - splashFactory: NoSplash.splashFactory, - tabs: _buildTabs(tabsController, screenWidth), - ), - ), - ), - ); - }, - ); - } - - List _buildTabs(TabController tabsController, double screenWidth) { - final tabs = [ - Container( - height: 50.h, - alignment: Alignment.bottomLeft, - child: Text('Темы'), - ), - Container( - height: 50.h, - alignment: Alignment.bottomLeft, - child: Text('Слова'), - ), - ]; - - // Добавляем вкладку игр только если она включена в Remote Config - if (_gamesEnabled) { - tabs.add( - Container( - height: 50.h, - alignment: Alignment.bottomLeft, - child: Text('Игры'), - ), - ); - } - - // Добавляем вкладку профиля - tabs.add( - Container( - height: 50.h, - alignment: Alignment.bottomLeft, - child: Row( - crossAxisAlignment: CrossAxisAlignment.end, - children: [ - Text('Профиль'), - AnimatedBuilder( - animation: tabsController.animation!, - builder: (_, child) { - final progress = tabsController.let((c) { - final profileIndex = c.length - 1; - - final offset = math.max( - (c.index - c.previousIndex).abs(), - 1.0, - ); - - if (c.previousIndex == profileIndex) { - return c.offset / offset; - } - if (c.index == profileIndex) { - return (1.0 - c.offset.abs() / offset); - } - return 0.0; - }).abs(); - return Transform.translate( - offset: Offset((1 - progress) * screenWidth, 0), - child: Opacity( - opacity: progress, - child: Container( - padding: EdgeInsets.only(left: 12.0.w, bottom: 6.0.h), - alignment: Alignment.bottomLeft, - child: GestureDetector( - onTap: () async { - await locator.userManager.logout(); - final showAdmin = SHOW_ADMIN; - final sp = await SharedPreferences.getInstance(); - sp.clear(); - if (showAdmin) { - globalSharedPreferences.setBool('show_admin', true); - } - AppRouter.openAuthOrProfile(); - }, - child: Image.asset( - 'icons/exit3.webp', - width: 24.w, - color: Theme.of(context).colorScheme.primary, - ), - ), - ), - ), - ); - }, - ), - ], - ), - ), - ); - - return tabs; - } -} diff --git a/mnemo_cards/lib/managers/audio_player.dart b/mnemo_cards/lib/managers/audio_player.dart deleted file mode 100644 index a4754c1..0000000 --- a/mnemo_cards/lib/managers/audio_player.dart +++ /dev/null @@ -1,32 +0,0 @@ -import 'package:flutter_tts/flutter_tts.dart'; - -import '../main.dart'; - -class AudioPlayer { - static bool get soundOn => - globalSharedPreferences.getBool('sound_on') ?? true; - - static Future playAudio(String? audio, {String? lang}) async { - if (soundOn && audio != null) { - FlutterTts flutterTts = FlutterTts(); - var playText = audio; - if (audio.contains('_')) { - final language = audio.split('_').first; - playText = audio.replaceFirst('${language}_', ''); - if (lang == null) { - await flutterTts.setLanguage(language); - } - } - if (lang != null) { - await flutterTts.setLanguage(lang); - } - var speed = globalSharedPreferences.getDouble('sound_speed'); - if (speed == null) { - speed = 0.8; - globalSharedPreferences.setDouble('sound_speed', speed); - } - await flutterTts.setSpeechRate(speed); - flutterTts.speak(playText); - } - } -} diff --git a/mnemo_cards/lib/managers/favorite_cards.dart b/mnemo_cards/lib/managers/favorite_cards.dart deleted file mode 100644 index 25fa0fc..0000000 --- a/mnemo_cards/lib/managers/favorite_cards.dart +++ /dev/null @@ -1,50 +0,0 @@ -import 'dart:async'; - -import 'package:mnemo_cards_common/mnemo_cards_common.dart'; -import 'package:rxdart/rxdart.dart'; -import 'package:shared_preferences/shared_preferences.dart'; - -class FavoriteCardsController { - late final SharedPreferences _sharedPreferences; - final StreamController> controller = - StreamController.broadcast(); - List _state = []; - - FavoriteCardsController(); - - void set state(List cards) { - _state = cards; - _sharedPreferences.setStringList( - 'favorites', - cards.toList(), - ); - controller.add(_state); - } - - List get state { - _state = (_sharedPreferences.getStringList('favorites') ?? []); - return _state; - } - - Future init() async { - _sharedPreferences = await SharedPreferences.getInstance(); - } - - Future switchFavoriteCard(GameCardDto cardDto) async { - final favorites = _sharedPreferences.getStringList('favorites') ?? []; - Set updatedFavorites = favorites.toSet(); - if (favorites.contains(cardDto.id.toString())) { - updatedFavorites.remove(cardDto.id.toString()); - } else { - updatedFavorites.add(cardDto.id.toString()); - } - state = updatedFavorites.toList(); - } - - bool isFavoriteCardString(String id) => state.contains(id); - - bool isFavoriteCard(int? id) => - id == null ? false : isFavoriteCardString(id.toString()); - - Stream> get asStream => controller.stream.startWith(_state); -} diff --git a/mnemo_cards/lib/managers/remote_config_manager.dart b/mnemo_cards/lib/managers/remote_config_manager.dart deleted file mode 100644 index 697572c..0000000 --- a/mnemo_cards/lib/managers/remote_config_manager.dart +++ /dev/null @@ -1,90 +0,0 @@ -import 'dart:convert'; -import 'package:firebase_remote_config/firebase_remote_config.dart'; -import 'package:flutter/foundation.dart'; - -class RemoteConfigManager { - static final RemoteConfigManager _instance = RemoteConfigManager._internal(); - - factory RemoteConfigManager() => _instance; - - RemoteConfigManager._internal(); - - late FirebaseRemoteConfig _remoteConfig; - bool _isInitialized = false; - - // Кэш для конфигурации игр - bool _gamesEnabled = false; - - bool get gamesEnabled => _gamesEnabled; - - Future initialize() async { - if (_isInitialized) return; - - _remoteConfig = FirebaseRemoteConfig.instance; - - // Настройка параметров - await _remoteConfig.setConfigSettings( - RemoteConfigSettings( - fetchTimeout: const Duration(minutes: 1), - minimumFetchInterval: const Duration(hours: 1), - ), - ); - - // Установка значений по умолчанию - await _remoteConfig.setDefaults({ - 'games': jsonEncode({'enabled': false}), - }); - - // Получение и активация конфигурации - try { - await _remoteConfig.fetchAndActivate(); - _updateGamesConfig(); - _isInitialized = true; - - if (kDebugMode) { - print('Remote Config initialized successfully'); - print('Games enabled: $_gamesEnabled'); - } - } catch (e) { - if (kDebugMode) { - print('Error initializing Remote Config: $e'); - } - // В случае ошибки используем значения по умолчанию - _isInitialized = true; - } - } - - Future refresh() async { - if (!_isInitialized) { - await initialize(); - return; - } - - try { - await _remoteConfig.fetchAndActivate(); - _updateGamesConfig(); - - if (kDebugMode) { - print('Remote Config refreshed'); - print('Games enabled: $_gamesEnabled'); - } - } catch (e) { - if (kDebugMode) { - print('Error refreshing Remote Config: $e'); - } - } - } - - void _updateGamesConfig() { - try { - final gamesConfigString = _remoteConfig.getString('games'); - final gamesConfig = jsonDecode(gamesConfigString) as Map; - _gamesEnabled = gamesConfig['enabled'] as bool? ?? false; - } catch (e) { - if (kDebugMode) { - print('Error parsing games config: $e'); - } - _gamesEnabled = false; - } - } -} diff --git a/mnemo_cards/lib/managers/repository/api.dart b/mnemo_cards/lib/managers/repository/api.dart deleted file mode 100644 index cc4582d..0000000 --- a/mnemo_cards/lib/managers/repository/api.dart +++ /dev/null @@ -1,18 +0,0 @@ -import 'package:flutter/foundation.dart'; -import 'package:mnemo_cards/flags.dart'; - -import '../../main.dart'; - -mixin Api { - String get path => kIsWeb - ? 'http://localhost:8000' - : !ADMIN_BUILD || (globalSharedPreferences.getBool('env') ?? true) - //prod - ? 'https://api.mnemo-cards.online:8080' // Production API endpoint - : deviceInfo!.isPhysicalDevice - //device to localhost - ? 'https://192.168.31.193:8080' - // ? 'https://192.168.1.101:8080' - : //emulator to localhost - 'https://10.0.2.2:8080'; -} diff --git a/mnemo_cards/lib/managers/repository/certificates.dart b/mnemo_cards/lib/managers/repository/certificates.dart deleted file mode 100644 index 201c9ef..0000000 --- a/mnemo_cards/lib/managers/repository/certificates.dart +++ /dev/null @@ -1,36 +0,0 @@ -import 'dart:convert'; - -class Certificates { - static get spKey => - 'qAcZM68Q7cR6gmxvB0ar0tr6axm520BNRLv66vmpWZnMHLCmzvEKNZkqL1VD1XHt'; - - static final crt = utf8.encode( - ''' ------BEGIN CERTIFICATE----- -MIIB8zCCAZmgAwIBAgIUHgV3sAY8MClrgLTwmO5OG4JsMyAwCgYIKoZIzj0EAwIw -UTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxFDASBgNVBAoMC01u -ZW1vIGNhcmRzMRcwFQYDVQQDDA4xOTIuMTY4LjMxLjE1ODAeFw0yNDA1MTgxMTUy -MTJaFw0yNzAyMTIxMTUyMTJaMF4xCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21l -LVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQxFzAVBgNV -BAMMDjE5Mi4xNjguMzEuMTU4MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEvO1/ -PU/ayMFgZw9KBLKpLHUpKQseY6Q6R4G51DaT8LBMfxMgAALf7PMj5IMNcW8ThjLY -MpYL8jZhufOtxCXdPKNCMEAwHQYDVR0OBBYEFBHLVqG6EfK9nrOeE1+JpUcUiEHv -MB8GA1UdIwQYMBaAFDJb2MW2vBxpKETey+ful5v7Jp3nMAoGCCqGSM49BAMCA0gA -MEUCIDwUzh9oXPE2xhArNimIpkCNyJViUf7B4kt9dgZtMLAtAiEAg3rqCqZXyys4 -mozimzUqDNc811KH3IFhC/Je4zQ3g68= ------END CERTIFICATE----- -''' - .trim(), - ); - - static final key = utf8.encode( - ''' ------BEGIN EC PRIVATE KEY----- -MHcCAQEEIDFGWXnWiqxMCYs34r5pJq2YVT3x1MoA07fnaj9iy1SYoAoGCCqGSM49 -AwEHoUQDQgAEvO1/PU/ayMFgZw9KBLKpLHUpKQseY6Q6R4G51DaT8LBMfxMgAALf -7PMj5IMNcW8ThjLYMpYL8jZhufOtxCXdPA== ------END EC PRIVATE KEY----- -''' - .trim(), - ); -} diff --git a/mnemo_cards/lib/managers/repository/dio_provider.dart b/mnemo_cards/lib/managers/repository/dio_provider.dart deleted file mode 100644 index 6620cc0..0000000 --- a/mnemo_cards/lib/managers/repository/dio_provider.dart +++ /dev/null @@ -1,149 +0,0 @@ -import 'dart:developer'; -import 'package:universal_io/io.dart'; - -import 'package:dio/dio.dart'; -import 'package:dio/io.dart'; -import 'package:flutter/foundation.dart'; -import 'package:flutter/material.dart'; -import 'package:mnemo_cards/managers/repository/dio_throttler.dart'; -import 'package:mnemo_cards_common/mnemo_cards_common.dart'; -import 'package:package_info_plus/package_info_plus.dart'; -import 'package:collection/collection.dart'; - -import '../../di/locator.dart'; -import '../../main.dart'; - -const versionUrl = 'http://localhost:8000/version.json'; - -class DioProvider { - late final Dio _dio; - - late CancelToken _cancelToken; - - DioProvider(); - - Dio get dio => _dio; - - Future init() async { - _cancelToken = CancelToken(); - PackageInfo appPackageInfo = - await PackageInfo.fromPlatform(baseUrl: versionUrl); - String appVersion = appPackageInfo.version; - - _dio = Dio( - - ) - ..interceptors.addAll([ - // CertificatePinningInterceptor(allowedSHAFingerprints: [ - // '28:21:5C:FB:54:4F:4A:DC:F8:5E:4C:FE:44:C8:E0:7B:0B:09:9D:D0:A9:FA:60:1D:3B:03:FF:EC:25:1A:C5:CC', - // ]), - InterceptorsWrapper(onRequest: (request, handler) { - handler.next( - // request, - request.copyWith(cancelToken: _cancelToken), - ); - }), - DioThrottler(const Duration(milliseconds: 100)), - InterceptorsWrapper(onError: (exception, handler) { - if (kDebugMode) { - log(exception.requestOptions.path ?? ''); - log(exception.toString()); - final snackBar = SnackBar( - content: Text( - '${exception.requestOptions.path}\n${exception.requestOptions.data}\n${exception.toString()}'), - ); - ScaffoldMessenger.of(scaffoldKey.currentContext!) - .showSnackBar(snackBar); - } - // if (exception.response?.statusCode == 401 && - // !locator.userManager.hasUser) { - // try { - // if (!AutoRouter.of(scaffoldKey.currentContext!) - // .isRouteActive(ProfilePage.name)) { - // AutoRouter.of(scaffoldKey.currentContext!).push( - // PageRouteInfo(ProfilePage.name), - // ); - // } - // } catch (e) {} - // } - handler.next(exception); - }), - InterceptorsWrapper(onRequest: (request, handler) async { - final String? requestToken; - try { - requestToken = TokenGenerator.generateRequestToken( - requestBody: (request.data as Object?)?.encode() ?? '', - appVersion: appVersion, - requestPath: request.uri.path, - userToken: await locator.userManager.getAuthToken(), - ); - } catch (e, s) { - log( - 'Exception while generating request token', - error: e, - stackTrace: s, - ); - throw Exception( - 'Exception while generating request token ${e} ${s}', - ); - } - request.headers = { - ...request.headers, - AppHeaders.appVersion: appVersion, - AppHeaders.requestToken: requestToken, - }; - handler.next(request); - }), - if (kIsWeb) - InterceptorsWrapper(onRequest: (request, handler) async { - request.headers = { - ...request.headers, - 'Access-Control-Allow-Origin': '*', - }; - handler.next(request); - }), - ]); - - if (!kIsWeb) { - final securityContext = SecurityContext(withTrustedRoots: true); - - // securityContext.setTrustedCertificatesBytes(Certificates.crt); - // securityContext.usePrivateKeyBytes(Certificates.key); - - _dio.httpClientAdapter = IOHttpClientAdapter( - createHttpClient: () { - HttpClient httpClient = HttpClient(context: securityContext) - ..badCertificateCallback = - (X509Certificate cert, String host, int port) { - print(cert.issuer); - print('$host $port'); - final now = DateTime.now(); - final valid = cert.startValidity.isBefore(now) && - cert.endValidity.isAfter(now); - return valid && - const DeepCollectionEquality().equals( - cert.sha1, - _cert, - ); - }; - return httpClient; - }, - ); - } - - _dio.options.connectTimeout = Duration(seconds: 10); - - return this; - } - - void cancelAll() { - _cancelToken.cancel(); - _cancelToken = CancelToken(); - } - - static final _cert = - '0A:82:77:1E:97:98:05:76:FC:ED:76:89:87:12:E8:9E:92:14:94:D3' - .split(':') - .map((v) => int.parse(v, radix: 16)) - .toList(); -} diff --git a/mnemo_cards/lib/managers/repository/dio_throttler.dart b/mnemo_cards/lib/managers/repository/dio_throttler.dart deleted file mode 100644 index 93eee97..0000000 --- a/mnemo_cards/lib/managers/repository/dio_throttler.dart +++ /dev/null @@ -1,59 +0,0 @@ -import 'dart:async'; - -import 'package:dio/dio.dart'; -import 'package:mutex/mutex.dart'; - -/// A simple request throttler (rate limiter) for Dio. -class DioThrottler extends Interceptor { - /// The interval between which requests are fired. - final Duration interval; - - /// A predicate to check whether a certain request should be throttled. - /// - /// If null, every request is throttled by default. - bool Function(RequestOptions req)? shouldThrottle; - - /// Called when a request has been delayed execution. Useful for debugging. - /// - /// The second argument represents the time that the request is scheduled - /// to be fired. - void Function(RequestOptions req, DateTime until)? onThrottled; - - DateTime _nextAvailable = DateTime.now(); - final Mutex _mutex = Mutex(); - - DioThrottler(this.interval, {this.shouldThrottle, this.onThrottled}); - - @override - void onRequest(RequestOptions options, RequestInterceptorHandler handler) { - if (shouldThrottle?.call(options) == false) { - handler.next(options); - return; - } - - var now = DateTime.now(); - _mutex.protect(() async { - if (now.isBefore(_nextAvailable)) { - // Throttle this request - var scheduledTime = _nextAvailable; - // Compute the next time a request is able to be fired - _nextAvailable = _nextAvailable.add(interval); - return scheduledTime; - } else { - // Not throttled, fire the request immediately - _nextAvailable = now.add(interval); - return null; - } - }).then((scheduledTime) { - if (scheduledTime != null) { - onThrottled?.call(options, scheduledTime); - Future.delayed( - scheduledTime.difference(now), - () => handler.next(options), - ); - } else { - handler.next(options); - } - }); - } -} \ No newline at end of file diff --git a/mnemo_cards/lib/managers/repository/firebase_config_repository.dart b/mnemo_cards/lib/managers/repository/firebase_config_repository.dart deleted file mode 100644 index 8713c8e..0000000 --- a/mnemo_cards/lib/managers/repository/firebase_config_repository.dart +++ /dev/null @@ -1,28 +0,0 @@ - -import 'package:cloud_firestore/cloud_firestore.dart'; - -class FirebaseRepository { - static FirebaseFirestore get _firestore => FirebaseFirestore.instance; - - static ConfigModel? _lastConfig; - - static ConfigModel get appConfig { - // update(); - return _lastConfig!; - } - - static Future update() async { - _lastConfig = await _firestore - .collection('config') - .get() - .then((v) => v.docs.first) - .then((value) => value.data()) - .then((value) => ConfigModel(value['path'] as String)); - } -} - -class ConfigModel { - final String path; - - ConfigModel(this.path); -} diff --git a/mnemo_cards/lib/managers/repository/http_repository.dart b/mnemo_cards/lib/managers/repository/http_repository.dart deleted file mode 100644 index 4393a54..0000000 --- a/mnemo_cards/lib/managers/repository/http_repository.dart +++ /dev/null @@ -1,192 +0,0 @@ -import 'dart:convert'; -import 'dart:developer'; -import 'package:universal_io/io.dart'; -import 'package:dio/dio.dart'; -import 'package:mnemo_cards/features/worker/worker_ext.dart'; -import 'package:mnemo_cards/managers/repository/repository.dart'; -import 'package:mnemo_cards/managers/user_manager.dart'; -import 'package:mnemo_cards_common/mnemo_cards_common.dart'; - -import 'api.dart'; - -class HttpRepository extends Repository with Api { - final Dio _dio; - - HttpRepository(this._dio); - - @override - Future get user async => UserDto.empty; - - @override - Stream get userStream => - Stream.periodic(const Duration(seconds: 5)).map((event) => UserDto.empty); - - @override - Future updateUser(UserDto dto) async {} - - @override - Future applyPromocode(String code) async { - try { - final r = await _dio.post( - '$path/user/promocode', - data: PromoCodeDto(code: code).encode(), - ); - return (r.data as String).isolatedDecode(PromoCodeDto.fromJson); - } on DioException catch (e, s) { - log('User create error', error: e, stackTrace: s); - rethrow; - } - } - - @override - Future acquireProductForAd( - String key, - MnemoCardsProductDto product, - ) async { - try { - final r = await _dio.post( - '$path/ads/product/acquire/$key', - data: product.encode(), - ); - return r.statusCode == 200; - } on DioException catch (e, s) { - log('User create error', error: e, stackTrace: s); - rethrow; - } - } - - @override - Future<(UserDto, String)> createOrGetUser( - String externalId, - ExternalIdType idType, - String email, - String? name, - ) async { - try { - final r = await _dio.post('$path/user/create', data: { - 'token': externalId, - 'tokenType': idType.name, - 'email': email, - 'name': name, - }); - //todo add client header encryption ?? - final authToken = r.headers[HttpHeaders.authorizationHeader]!.last; - return ((r.data as String).decode(UserDto.fromJson), authToken); - } on DioException catch (e, s) { - log('User create error', error: e, stackTrace: s); - rethrow; - } - } - - @override - void setAuthToken(String? authToken) { - _dio.interceptors.add( - InterceptorsWrapper(onRequest: (options, handler) { - options.headers[AppHeaders.userToken] = authToken; - handler.next(options); - }), - ); - } - - @override - Future getUser() async { - final r = await _dio.get( - '$path/user', - options: Options( - sendTimeout: Duration(seconds: 3), - ), - ); - if (r.statusCode == 200) { - return await (r.data as String).isolatedDecode(UserDto.fromJson); - } - return null; - } - - @override - Future updateUserData(UserDataDto data) async { - final r = await _dio.post('$path/user/data', data: data.encode()); - } - - @override - Future updateUserSettings(UserSettingsDto settings) async { - final r = await _dio.post('$path/user/settings', data: settings.encode()); - } - - @override - Future addTestStatistics(TestStatisticsDto testStatistics) async { - final r = await _dio.post( - '$path/user/data/add/test-statistics', - data: testStatistics.encode(), - ); - } - - @override - Future> getTests({String packId = ''}) async { - final r = await _dio.get( - '$path/tests/$packId', - ); - return (r.data as String).isolatedDecodeList(TestDto.fromJson); - } - - @override - Future getTest(String id) async { - final r = await _dio.get( - '$path/test/$id', - ); - try { - return (r.data as String).isolatedDecode(TestDto.fromJson); - } catch (e, s) { - log(e.toString(), stackTrace: s); - return null; - } - } - - @override - Future checkPayment({ - required MnemoCardsProductDto product, - required String key, - required PaymentSystem paymentSystem, - }) async { - final r = await _dio.get( - '$path/check_payment/', - queryParameters: { - 'type': product.type.name, - 'id': product.id, - 'token': key, - 'system': paymentSystem.name, - }, - ); - return jsonDecode(r.data ?? '{}')['result'] ?? false; - } - - @override - Future checkUserPayment() async { - final r = await _dio.get('$path/check_payments/'); - final result = jsonDecode(r.data ?? '{}')?['result'] ?? false; - return result; - } - - Future createPayment( - String id, - MnemoCardsProductType productType, - PaymentSystem paymentSystem, - ) async { - final r = await _dio.get( - '$path/create_payment/', - queryParameters: { - 'id': id, - 'type': productType.name, - 'system': paymentSystem.name, - }, - ); - return (r.data as String).isolatedDecode(YookassaPaymentDto.fromJson); - } - - Future deleteUser(String id) async { - final r = await _dio.post( - '$path/users/delete', - data: jsonEncode({'id': id}), - ); - return r.statusCode == 200; - } -} diff --git a/mnemo_cards/lib/managers/repository/repository.dart b/mnemo_cards/lib/managers/repository/repository.dart deleted file mode 100644 index 085e9fb..0000000 --- a/mnemo_cards/lib/managers/repository/repository.dart +++ /dev/null @@ -1,54 +0,0 @@ -import 'package:mnemo_cards/managers/user_manager.dart'; -import 'package:mnemo_cards_common/mnemo_cards_common.dart'; - -abstract class Repository { - Future get user; - - Stream get userStream; - - Future updateUser(UserDto dto); - - Future applyPromocode(String promocode); - - Future acquireProductForAd( - String key, - MnemoCardsProductDto product, - ); - - Future<(UserDto, String)> createOrGetUser( - String externalId, - ExternalIdType idType, - String email, - String? name, - ); - - Future getUser(); - - void setAuthToken(String? authToken); - - Future updateUserData(UserDataDto data); - - Future updateUserSettings(UserSettingsDto settings); - - Future addTestStatistics(TestStatisticsDto testStatistics); - - Future> getTests(); - - Future getTest(String id); - - Future checkPayment({ - required MnemoCardsProductDto product, - required String key, - required PaymentSystem paymentSystem, - }); - - Future checkUserPayment(); - - Future createPayment( - String id, - MnemoCardsProductType productType, - PaymentSystem type, - ); - - Future deleteUser(String id); -} diff --git a/mnemo_cards/lib/managers/user_manager.dart b/mnemo_cards/lib/managers/user_manager.dart deleted file mode 100644 index f38a254..0000000 --- a/mnemo_cards/lib/managers/user_manager.dart +++ /dev/null @@ -1,252 +0,0 @@ -import 'dart:async'; -import 'dart:developer'; - -import 'package:dio/dio.dart'; -import 'package:google_sign_in/google_sign_in.dart'; -import 'package:mnemo_cards/di/injector.dart'; -import 'package:mnemo_cards/di/locator.dart'; -import 'package:mnemo_cards/main.dart'; -import 'package:mnemo_cards/managers/repository/http_repository.dart'; -import 'package:mnemo_cards_common/mnemo_cards_common.dart'; -import 'package:rxdart/rxdart.dart'; -import 'package:shared_preferences/shared_preferences.dart'; -// import 'package:telegram_web_app/telegram_web_app.dart'; - -import '../domain/router/app_router.dart'; -import '../features/analytics/analytics.dart'; -import 'repository/dio_provider.dart'; -import 'user_state_holder.dart'; - -class UserManager { - CompositeSubscription? _subscription; - final HttpRepository _repository; - late final GoogleSignIn _googleSignIn; - - late final SharedPreferences? _sharedPreferences; - final UserStateHolder userStateHolder; - - UserManager(this._repository) : userStateHolder = UserStateHolder(); - - bool get hasUser => user != null; - - UserDto? get user => userStateHolder.user; - - int? get userId => userStateHolder.user?.id; - - Future loginWithGoogle() async { - try { - log('Starting Google Sign-In', name: 'UserManager'); - - // Сначала попробуем легкую аутентификацию - try { - await _googleSignIn.attemptLightweightAuthentication( - reportAllExceptions: true, - ); - log('Lightweight authentication successful', name: 'UserManager'); - await Future.delayed(const Duration(milliseconds: 300)); - return; - } catch (e, s) { - log('Lightweight authentication failed, trying full sign-in', - error: e, stackTrace: s, name: 'UserManager'); - } - - // Если легкая аутентификация не удалась, делаем полный вход - await _googleSignIn.signOut(); - await _googleSignIn.authenticate(scopeHint: ['email']); - - log('Google Sign-In completed successfully', name: 'UserManager'); - await Future.delayed(const Duration(milliseconds: 300)); - } catch (e, s) { - log('Error in Google Sign-In', error: e, stackTrace: s, name: 'UserManager'); - rethrow; - } - } - - Future loginWithTelegram() async { - try { - final userId = "123"; // telegramWebApp.initData.user.id; - final externalId = userId.toString(); - final idType = ExternalIdType.device; // todo - final email = 'no-email-tg'; - final name = "name"; //telegramWebApp.initData.user.username; - _createUser(externalId, idType, email, name); - await Future.delayed(Duration(milliseconds: 300)); - } catch (e, s) { - log('Error in login', error: e, stackTrace: s); - } - } - - Future logout() async { - await _googleSignIn.signOut(); - Analytics.logout(userStateHolder.user); - userStateHolder.clear(); - locator.packUpdater.clear(); - } - - Future _createUser( - String externalId, - ExternalIdType idType, - String email, - String? name, - ) async { - final (user, token) = await _repository.createOrGetUser( - externalId, - idType, - email, - name, - ); - await _setAuthToken(token); - userStateHolder.setUser(user); - } - - Future _setAuthToken(String authToken) async { - _repository.setAuthToken(authToken); - await secureStorage.write(key: 'authToken', value: authToken); - } - - Future _clearAuthToken() async { - await secureStorage.delete(key: 'authToken'); - } - - Future getAuthToken() async { - return secureStorage.read(key: 'authToken'); - } - - Future applyPromocode(String code) async { - final data = await _repository.applyPromocode(code); - return data; - } - - Future acquireProductForAd( - String key, - MnemoCardsProductDto product, - ) async { - final success = await _repository.acquireProductForAd(key, product); - return success; - } - - Future updateUser() async { - String? authToken = await getAuthToken(); - if (authToken != null) { - await _setAuthToken(authToken); - try { - final fetchedUser = await _repository.getUser(); - userStateHolder.setUser(fetchedUser!); - return fetchedUser; - } catch (e) { - _clearAuthToken(); - AppRouter.openAuthOrProfile(); - } - } - // not creating empty user - // if (Platform.isAndroid) { - // final deviceInfoPlugin = DeviceInfoPlugin(); - // final deviceInfo = await deviceInfoPlugin.androidInfo; - // final id = deviceInfo.id; - // await _createUser(id, ExternalIdType.device); - // } - return null; - } - - Future deleteUser() async { - final user = await updateUser(); - if (user?.id != null) { - final result = await _repository.deleteUser(user!.id.toString()); - if (result) { - logout(); - _clearAuthToken(); - } - return result; - } - return false; - } - - Future init() async { - _sharedPreferences = await SharedPreferences.getInstance(); - - // Инициализируем GoogleSignIn - _googleSignIn = GoogleSignIn.instance; - - try { - await updateUser(); - } on Object catch (e, s) { - log('User manager init error', error: e, stackTrace: s); - } - var firstSkipped = false; - _subscription = CompositeSubscription() - ..add( - _googleSignIn.authenticationEvents - .map( - (event) => switch (event) { - GoogleSignInAuthenticationEventSignIn() => event.user, - GoogleSignInAuthenticationEventSignOut() => null, - }, - ) - .distinct((p, n) => p?.id == n?.id) - .listen((account) async { - if (account != null) { - try { - final email = account.email; - final name = account.displayName; - final auth = await account.authentication; - final externalToken = auth.idToken; - - log('Google user signed in: $email', name: 'UserManager'); - Analytics.login(ExternalIdType.google); - - await _createUser( - externalToken!, - ExternalIdType.google, - email, - name, - ); - } catch (e, s) { - log('Error processing Google sign-in', - error: e, stackTrace: s, name: 'UserManager'); - } - } else { - log('Google user signed out', name: 'UserManager'); - userStateHolder.clear(); - _clearAuthToken(); - } - }), - ) - ..add( - userStateHolder.asNullableStream - .distinct((a, b) => a?.id == b?.id) - // don't want to clear cache on login - .skipWhile((user) => user != null && !firstSkipped) - .listen((user) async { - firstSkipped = true; - try { - if (user == null) { - AppRouter.openAuthOrProfile(); - } else { - try { - AppRouter.closeAuthPage(); - getIt.get().cancelAll(); - await locator.previewPackPoller.poll(); - await locator.packManager.clearCache(); - await locator.packUpdater.updateAvailablePacks(); - } catch (err, s) { - log('close', stackTrace: s, error: err); - } - } - } catch (e) { - log(e.toString()); - _clearAuthToken(); - if (e is DioException) { - if (e.response?.statusCode == 401) { - AppRouter.openProfile(); - } - } - } - }), - ); - } - - Future dispose() async { - await _subscription?.cancel(); - _subscription = null; - } -} diff --git a/mnemo_cards/lib/managers/user_state_holder.dart b/mnemo_cards/lib/managers/user_state_holder.dart deleted file mode 100644 index 777d1bd..0000000 --- a/mnemo_cards/lib/managers/user_state_holder.dart +++ /dev/null @@ -1,40 +0,0 @@ -import 'dart:async'; - -import 'package:flutter/widgets.dart'; -import 'package:mnemo_cards_common/mnemo_cards_common.dart'; -import 'package:rxdart/rxdart.dart'; - -import '../features/analytics/analytics.dart'; - - -class UserStateHolder extends ChangeNotifier { - UserDto? _dto; - final _streamController = StreamController.broadcast(); - - static final _instance = UserStateHolder._(); - - UserStateHolder._(); - - factory UserStateHolder() => _instance; - - void setUser(UserDto dto) { - _dto = dto.copyWith(); - Analytics.setUser(dto); - - notifyListeners(); - _streamController.add(_dto); - } - - void clear() { - _dto = null; - notifyListeners(); - _streamController.add(null); - } - - Stream get asStream => asNullableStream.whereNotNull(); - - Stream get asNullableStream => - _streamController.stream.startWith(_dto); - - UserDto? get user => _dto; -} diff --git a/mnemo_cards/lib/pages/auth_page.dart b/mnemo_cards/lib/pages/auth_page.dart deleted file mode 100644 index df0cf67..0000000 --- a/mnemo_cards/lib/pages/auth_page.dart +++ /dev/null @@ -1,135 +0,0 @@ -import 'package:auto_route/annotations.dart'; -import 'package:flutter/gestures.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_screenutil/flutter_screenutil.dart'; -import 'package:mnemo_cards/di/locator.dart'; -import 'package:mnemo_cards/flags.dart'; -import 'package:mnemo_cards/main.dart'; -// import 'package:telegram_web_app/telegram_web_app.dart'; -import 'package:url_launcher/url_launcher.dart'; - -import '../theme/themes.dart'; -import '../widgets/shared_pref_button.dart'; - -@RoutePage() -class AuthPage extends StatelessWidget { - @override - Widget build(BuildContext context) { - return Scaffold( - body: SafeArea( - child: Column( - children: [ - SizedBox( - height: 64.h - MediaQuery.of(context).padding.top, - ), - Text( - 'Mnemo cards', - style: TextStyle( - fontSize: 36.sp, - fontWeight: FontWeight.w700, - height: 0.85, - ), - textAlign: TextAlign.start, - ), - SizedBox( - height: 60.h, - ), - Expanded( - child: Image.asset( - Theme.of(context).brightness == Brightness.dark - ? 'images/luna.webp' - : 'images/cerdo.webp', - fit: BoxFit.fitWidth, - ), - ), - if (ADMIN_BUILD) - MobileSharedPrefButton( - builder: (v, _) => (v ?? false) ? Text('PROD') : Text('TEST'), - spKey: 'env', - setOnTap: (v) => !(v ?? false), - ), - // if (telegramWebApp.isActive) - if (false) - Padding( - padding: - EdgeInsets.symmetric(horizontal: 10.0.w, vertical: 5.0.h), - child: InkWell( - onTap: locator.userManager.loginWithTelegram, - child: Container( - height: 90.h, - alignment: Alignment.center, - decoration: BoxDecoration( - border: Border.all(color: borderGray), - borderRadius: BorderRadius.circular(16.0), - ), - padding: EdgeInsets.all(10.0.w), - child: Image.asset( - 'icons/telegram.webp', - height: 88.h, - ), - ), - ), - ), - // if (!telegramWebApp.isActive) - if (true) - Padding( - padding: - EdgeInsets.symmetric(horizontal: 10.0.w, vertical: 5.0.h), - child: InkWell( - onTap: locator.userManager.loginWithGoogle, - child: Container( - height: 90.h, - alignment: Alignment.center, - decoration: BoxDecoration( - border: Border.all(color: borderGray), - borderRadius: BorderRadius.circular(16.0), - ), - padding: EdgeInsets.all(10.0.w), - child: Image.asset( - 'icons/google.webp', - height: 88.h, - ), - ), - ), - ), - Padding( - padding: - EdgeInsets.symmetric(horizontal: 10.0.w, vertical: 10.0.h), - child: RichText( - text: TextSpan( - children: [ - TextSpan( - text: - 'Присоединяясь, я заявляю что прочитал и принимаю '), - // TextSpan( - // text: 'условия', - // recognizer: TapGestureRecognizer() - // ..onTap = - // () => launchUrl(Uri.parse('https://www.google.com')), - // style: TextStyle(decoration: TextDecoration.underline), - // ), - // TextSpan(text: ' и '), - TextSpan( - text: 'политику конфиденциальности', - recognizer: TapGestureRecognizer() - ..onTap = () => launchUrl(Uri.parse( - 'https://www.freeprivacypolicy.com/live/1c2bce51-86c6-4a36-b226-b6c6f50ebf0f')), - style: - TextStyle(decoration: TextDecoration.underline)), - TextSpan(text: '.'), - ], - style: TextStyle( - fontSize: 14.sp, - fontWeight: FontWeight.w300, - height: 1.1, - color: borderGray, - ), - ), - textAlign: TextAlign.center), - ), - ], - ), - ), - ); - } -} diff --git a/mnemo_cards/lib/pages/home_page.dart b/mnemo_cards/lib/pages/home_page.dart deleted file mode 100644 index 00b681a..0000000 --- a/mnemo_cards/lib/pages/home_page.dart +++ /dev/null @@ -1,20 +0,0 @@ -import 'package:auto_route/auto_route.dart'; -import 'package:flutter/material.dart'; -import 'package:mnemo_cards/di/locator.dart'; - -import '../widgets/packs_menu_widget.dart'; - -@RoutePage() -class HomePage extends StatelessWidget { - @override - Widget build(BuildContext context) { - return Scaffold( - body: PacksMenuWidget( - locator.repository, - locator.packManager, - ), - ); - } - - const HomePage(); -} diff --git a/mnemo_cards/lib/pages/profile_page.dart b/mnemo_cards/lib/pages/profile_page.dart deleted file mode 100644 index 5b5d3cc..0000000 --- a/mnemo_cards/lib/pages/profile_page.dart +++ /dev/null @@ -1,139 +0,0 @@ -import 'package:universal_io/io.dart'; - -import 'package:auto_route/auto_route.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_screenutil/flutter_screenutil.dart'; -import 'package:mnemo_cards/domain/router/app_router.dart'; -import 'package:mnemo_cards/domain/router/app_router.gr.dart'; -import 'package:mnemo_cards/flags.dart'; -import 'package:mnemo_cards/main.dart'; -import 'package:mnemo_cards_frontend_common/mnemo_cards_frontend_common.dart'; -import 'package:shared_preferences/shared_preferences.dart'; -import 'package:url_launcher/url_launcher.dart'; - -import '../di/locator.dart'; -import '../features/analytics/analytics.dart'; -import '../theme/themes.dart'; -import '../widgets/buy_subscription_widget.dart'; -import '../widgets/enter_promo_code_widget.dart'; - -@RoutePage() -class ProfilePage extends StatelessWidget { - @override - Widget build(BuildContext context) { - Analytics.profilePageOpened(locator.userManager.userStateHolder.user); - locator.userManager.updateUser(); - final theme = Theme.of(context).textTheme; - return Scaffold( - body: SafeArea( - child: Column( - children: [ - SizedBox( - height: 8.h, - ), - Expanded( - child: StreamBuilder( - stream: locator.userManager.userStateHolder.asStream, - builder: (context, snapshot) { - final userData = snapshot.data?.userDataDto; - return Padding( - padding: const EdgeInsets.only( - left: 10.0, - right: 10.0, - bottom: 8.0, - ), - child: UserStatistics(userDataDto: userData), - ); - }, - ), - ), - Padding( - padding: const EdgeInsets.symmetric(horizontal: 10.0), - child: Column( - children: [ - Divider( - height: 5, - color: borderGray.withOpacity(0.2), - ), - const MobileEnterPromoCodeWidget(), - Divider( - height: 5, - color: borderGray.withOpacity(0.2), - ), - const MobileBuySubscriptionWidget(), - Divider( - height: 5, - color: borderGray.withOpacity(0.2), - ), - if (SHOW_ADMIN) ...[ - SimpleTile( - title: Text('Посмотреть рекламу'), - onTap: () { - // YandexAds.showRewardedAd((r) { - // // showInfoDialog( - // // 'Вы получили\n${r.amount} ${r.type}'); - // }); - }, - ), - Divider( - height: 5, - color: borderGray.withOpacity(0.2), - ), - ], - SimpleTile.text( - text: 'Написать в телеграм', - onTap: () => launchUrl( - Uri.parse('https://t.me/mnemo_cards_bot'), - ), - ), - Divider( - height: 5, - color: borderGray.withOpacity(0.2), - ), - SimpleTile( - onTap: () => appRouter.push( - PageRouteInfo(SettingsPage.name), - ), - title: Row( - children: [ - Image.asset( - 'icons/settings.webp', - width: 16.w, - color: Theme.of(context).colorScheme.primary, - ), - SizedBox(width: 8.w), - Expanded(child: Text('Настройки там')), - ], - ), - trail: Image.asset( - 'icons/next.webp', - width: 16.w, - color: Theme.of(context).colorScheme.primary, - ), - ), - Divider( - height: 5, - color: borderGray.withOpacity(0.2), - ), - SizedBox( - height: 10.0.h, - ), - ], - ), - ), - // if (MediaQuery.of(context).viewInsets.bottom < 30.0) - // const BigBackButton(), - ], - ), - ), - ); - } - - Future clearAndExit() async { - final sp = await SharedPreferences.getInstance(); - sp.clear(); - exit(0); - } - - const ProfilePage(); -} diff --git a/mnemo_cards/lib/pages/settgins_page.dart b/mnemo_cards/lib/pages/settgins_page.dart deleted file mode 100644 index 1892833..0000000 --- a/mnemo_cards/lib/pages/settgins_page.dart +++ /dev/null @@ -1,241 +0,0 @@ -import 'package:universal_io/io.dart'; - -import 'package:auto_route/auto_route.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_screenutil/flutter_screenutil.dart'; -import 'package:mnemo_cards/admin/add_discount_campaign.dart'; -import 'package:mnemo_cards/domain/router/dialogs.dart'; -import 'package:mnemo_cards/flags.dart'; -import 'package:mnemo_cards_frontend_common/mnemo_cards_frontend_common.dart'; -import 'package:shared_preferences/shared_preferences.dart'; -import 'package:url_launcher/url_launcher.dart'; - -import '../admin/add_plan.dart'; -import '../admin/add_promocode_campaign.dart'; -import '../admin/admin_api.dart'; -import '../admin/all_cards.dart'; -import '../admin/all_users.dart'; -import '../di/injector.dart'; -import '../di/locator.dart'; -import '../features/analytics/analytics.dart'; -import '../managers/repository/dio_provider.dart'; -import '../theme/themes.dart'; -import '../widgets/shared_pref_button.dart'; - -@RoutePage() -class SettingsPage extends StatelessWidget { - void _initAdmin() { - if (!getIt.isRegistered()) { - getIt.registerLazySingleton( - () => AdminApi(getIt.get().dio)); - print('set admin'); - } - } - - @override - Widget build(BuildContext context) { - Analytics.settingsPageOpened(locator.userManager.userStateHolder.user); - return Scaffold( - body: SafeArea( - child: Column( - children: [ - Header( - 'Настройки', - popText: 'назад', - hasPopButton: true, - ), - SizedBox( - height: 8.h, - ), - Divider( - height: 1, - color: borderGray.withOpacity(0.2), - ), - Expanded( - child: Padding( - padding: EdgeInsets.symmetric(horizontal: 10.0.w), - child: SingleChildScrollView( - reverse: true, - child: Column( - children: [ - ...[ - SimpleTile.text( - onLongTap: () async { - final r = await locator.userManager.deleteUser(); - if (!r) { - showInfoDialog( - 'Не удалось удалить аккаунт\nПопробуйте перелогиниться', - ); - } - }, - text: 'Удалить аккаунт (зажми)', - ), - MobileSharedPrefButton.builder( - spKey: 'dark_theme', - builder: (enabled, _) => AbsorbPointer( - child: SwitchTile( - text: 'Темная тема', - value: enabled ?? false, - ), - ), - setOnTap: (v) { - final darkTheme = !(v ?? false); - themeNotifier.value = - darkTheme ? ThemeMode.dark : ThemeMode.light; - return darkTheme; - }, - ), - MobileSharedPrefButton.builder( - spKey: 'sound_on', - builder: (enabled, _) => AbsorbPointer( - child: SwitchTile( - text: 'Звук', - value: enabled ?? false, - ), - ), - setOnTap: (v) => !(v ?? false), - ), - MobileSharedPrefButton.builder( - spKey: 'auto_play_sound_view', - builder: (enabled, _) => AbsorbPointer( - child: SwitchTile( - text: 'Авто воспроизведение при просмотре', - value: enabled ?? false, - ), - ), - setOnTap: (v) => !(v ?? false), - ), - MobileSharedPrefButton.builder( - spKey: 'auto_play_sound_tests', - builder: (enabled, _) => AbsorbPointer( - child: SwitchTile( - text: 'Авто воспроизведение в тестах', - value: enabled ?? false, - ), - ), - setOnTap: (v) => !(v ?? false), - ), - SimpleTile.text( - text: 'Скорость чтения', - trail: MobileSharedPrefButton.builder( - spKey: 'sound_speed', - builder: (v, s) => MnemoSlider( - onChanged: (value) => s(value), - value: v ?? 1.0, - ), - shouldRebuild: (v) => false, - ), - ), - if (ADMIN_BUILD) - MobileSharedPrefButton.builder( - spKey: 'show_admin', - builder: (enabled, _) => AbsorbPointer( - child: SwitchTile( - text: 'Show admin', - value: enabled ?? false, - ), - ), - setOnTap: (v) { - final val = !(v ?? false); - if (val) { - _initAdmin(); - } - return val; - }, - ), - if (ADMIN_BUILD) ..._adminTiles(context), - ].expand((widget) => [ - widget, - Divider( - height: 1, - color: borderGray.withOpacity(0.2), - ), - ]), - Padding( - padding: EdgeInsets.only( - left: 10.0.w, right: 10.w, top: 32.h), - child: LinkButton( - 'Политика конфиденциальности', - () { - launchUrl( - Uri.parse( - 'https://www.freeprivacypolicy.com/live/1c2bce51-86c6-4a36-b226-b6c6f50ebf0f'), - ); - }, - ), - ), - ], - ), - ), - ), - ), - const BigBackButton(), - ], - ), - ), - ); - } - - List _adminTiles(BuildContext context) => [ - SimpleTile.text( - text: 'Cards', - onTap: () { - _initAdmin(); - showDialog(context: context, builder: (c) => const AllCards()); - }, - ), - SimpleTile.text( - text: 'Users', - onTap: () { - _initAdmin(); - showDialog(context: context, builder: (c) => const AllUsers()); - }, - ), - SimpleTile.text( - text: 'Plans', - onTap: () { - _initAdmin(); - AddPlan().addPlan(context); - }, - ), - SimpleTile.text( - text: 'Promo codes', - onTap: () { - _initAdmin(); - AddPromocodeCampaign().addCampaign(context); - }, - ), - SimpleTile.text( - text: 'Discounts', - onTap: () { - _initAdmin(); - AddDiscountCampaign().addCampaign(context); - }, - ), - SimpleTile.text( - text: 'Clear cache', - onTap: () { - locator.packManager.clearCache(); - locator.packUpdater.updateAvailablePacks(); - }, - ), - MobileSharedPrefButton( - builder: (enabled, _) => AbsorbPointer( - child: SwitchTile( - text: 'Use prod', - value: enabled ?? false, - ), - ), - spKey: 'env', - setOnTap: (v) => !(v ?? false), - ), - ]; - - Future clearAndExit() async { - final sp = await SharedPreferences.getInstance(); - sp.clear(); - exit(0); - } - - const SettingsPage(); -} diff --git a/mnemo_cards/lib/pages/vocabulary_page.dart b/mnemo_cards/lib/pages/vocabulary_page.dart deleted file mode 100644 index b656304..0000000 --- a/mnemo_cards/lib/pages/vocabulary_page.dart +++ /dev/null @@ -1,13 +0,0 @@ -import 'package:auto_route/auto_route.dart'; -import 'package:flutter/material.dart'; -import '../features/vocabulary/vocabulary.dart' as vocabulary; - -@RoutePage() -class VocabularyPage extends StatelessWidget { - const VocabularyPage({super.key}); - - @override - Widget build(BuildContext context) { - return vocabulary.VocabularyPage(); - } -} diff --git a/mnemo_cards/lib/theme/themes.dart b/mnemo_cards/lib/theme/themes.dart deleted file mode 100644 index dd74fc2..0000000 --- a/mnemo_cards/lib/theme/themes.dart +++ /dev/null @@ -1,103 +0,0 @@ -import 'package:flutter/material.dart'; -// import 'package:google_fonts/google_fonts.dart'; - -final ValueNotifier themeNotifier = ValueNotifier(ThemeMode.light); - -const Color peach = Color(0xffffc994); -const Color golden = Color(0xffffea00); -const Color green = Color(0xff3d5309); -const Color greenAccent = Color(0xff688d11); -const Color black = Color(0xff000000); -const Color mainBackgroundLight = Color(0xffffffff); -const Color mainBackgroundDark = Color(0xff000000); -const Color white = Color(0xffffffff); -const Color yellow = Colors.yellowAccent; -const Color progressBlue = Color(0xff8CCBFF); -const Color menuBlue = Color(0xff99C4E9); -const Color backgroundBlue = Color(0xFFf0f0f0); -const Color testBlue = Color(0xffD0EAFF); -const Color borderGray = Color(0xffABABAB); - -final Map color = { - 50: const Color.fromRGBO(0, 0, 0, .1), - 100: const Color.fromRGBO(0, 0, 0, .2), - 200: const Color.fromRGBO(0, 0, 0, .3), - 300: const Color.fromRGBO(0, 0, 0, .4), - 400: const Color.fromRGBO(0, 0, 0, .5), - 500: const Color.fromRGBO(0, 0, 0, .6), - 600: const Color.fromRGBO(0, 0, 0, .7), - 700: const Color.fromRGBO(0, 0, 0, .8), - 800: const Color.fromRGBO(0, 0, 0, .9), - 900: const Color.fromRGBO(0, 0, 0, 1), -}; - -final Map colorWhite = { - 50: const Color.fromRGBO(255, 255, 255, .1), - 100: const Color.fromRGBO(255, 255, 255, .2), - 200: const Color.fromRGBO(255, 255, 255, .3), - 300: const Color.fromRGBO(255, 255, 255, .4), - 400: const Color.fromRGBO(255, 255, 255, .5), - 500: const Color.fromRGBO(255, 255, 255, .6), - 600: const Color.fromRGBO(255, 255, 255, .7), - 700: const Color.fromRGBO(255, 255, 255, .8), - 800: const Color.fromRGBO(255, 255, 255, .9), - 900: const Color.fromRGBO(255, 255, 255, 1), -}; - -final theme2 = ThemeData( - useMaterial3: true, - brightness: Brightness.light, - fontFamily: 'Nunito', - // textTheme: GoogleFonts.exo2TextTheme(), - colorScheme: ColorScheme.light( - secondaryContainer: Colors.grey, - primary: MaterialColor(0xFF000000, color), - surface: MaterialColor(0xFFFFFFFF, colorWhite), - surfaceContainerHighest: MaterialColor(0xFFFFFFFF, colorWhite), - onSurface: Colors.black, - ), - appBarTheme: AppBarTheme( - iconTheme: IconThemeData( - color: MaterialColor(0xFF000000, color), - ), - ), - textTheme: TextTheme( - titleLarge: TextStyle(fontWeight: FontWeight.w700), - titleMedium: TextStyle(fontWeight: FontWeight.w700), - titleSmall: TextStyle(fontWeight: FontWeight.w700), - bodyLarge: TextStyle(fontWeight: FontWeight.w700), - bodyMedium: TextStyle(fontWeight: FontWeight.w700), - bodySmall: TextStyle(fontWeight: FontWeight.w700), - labelLarge: TextStyle(fontWeight: FontWeight.w700), - labelMedium: TextStyle(fontWeight: FontWeight.w700), - labelSmall: TextStyle(fontWeight: FontWeight.w700), - displayLarge: TextStyle(fontWeight: FontWeight.w700), - displayMedium: TextStyle(fontWeight: FontWeight.w700), - displaySmall: TextStyle(fontWeight: FontWeight.w700), - headlineLarge: TextStyle(fontWeight: FontWeight.w700), - headlineMedium: TextStyle(fontWeight: FontWeight.w700), - headlineSmall: TextStyle(fontWeight: FontWeight.w700), - ), - primarySwatch: MaterialColor(0xFF000000, color), - visualDensity: VisualDensity.adaptivePlatformDensity, -); -final darkTheme2 = ThemeData( - useMaterial3: true, - brightness: Brightness.dark, - fontFamily: 'Nunito', - // textTheme: GoogleFonts.exo2TextTheme(), - colorScheme: ColorScheme.dark( - primary: MaterialColor(0xFFFFFFFF, colorWhite), - secondary: Colors.lightBlue, - tertiary: Colors.lightBlue, - ), - tabBarTheme: TabBarThemeData( - labelColor: MaterialColor(0xFFFFFFFF, colorWhite), - ), - appBarTheme: AppBarTheme( - iconTheme: IconThemeData( - color: MaterialColor(0xFFFFFFFF, colorWhite), - )), - primarySwatch: MaterialColor(0xFFFFFFFF, colorWhite), - visualDensity: VisualDensity.adaptivePlatformDensity, -); diff --git a/mnemo_cards/lib/utils/archive_decoder.dart b/mnemo_cards/lib/utils/archive_decoder.dart deleted file mode 100644 index 86233bd..0000000 --- a/mnemo_cards/lib/utils/archive_decoder.dart +++ /dev/null @@ -1,54 +0,0 @@ -import 'package:archive/archive_io.dart'; -import 'package:flutter/foundation.dart'; -import 'package:mnemo_cards_common/mnemo_cards_common.dart'; - -class ArchiveDecoder { - const ArchiveDecoder(); - - Future>?> decodeArchive( - Uint8List data, - String id, - String appVersion, - ) async { - return await compute( - _decodeArchive, - _Envelope( - data: data, - id: id, - appVersion: appVersion, - ), - ); - } - - Map> _decodeArchive(_Envelope envelope) { - final s = Stopwatch()..start(); - final password = TokenGenerator.generateArchivePassword( - appVersion: envelope.appVersion, - id: envelope.id, - ); - print('generate token ${s.elapsedMilliseconds} mills'); - final imagesArchive = ZipDecoder().decodeBytes( - envelope.data, - password: password, - ); - print('deflate archive ${s.elapsedMilliseconds} mills'); - final images = Map>(); - for (final file in imagesArchive) { - images[file.name] = file.content as List; - } - print('loaded images ${s.elapsedMilliseconds} mills'); - return images; - } -} - -class _Envelope { - final List data; - final String id; - final String appVersion; - - _Envelope({ - required this.data, - required this.id, - required this.appVersion, - }); -} diff --git a/mnemo_cards/lib/utils/color_helper.dart b/mnemo_cards/lib/utils/color_helper.dart deleted file mode 100644 index 443b728..0000000 --- a/mnemo_cards/lib/utils/color_helper.dart +++ /dev/null @@ -1,22 +0,0 @@ -import 'package:flutter/painting.dart'; - -extension ColorBrightness on Color { - Color darken([double amount = .1]) { - assert(amount >= 0 && amount <= 1); - - final hsl = HSLColor.fromColor(this); - final hslDark = hsl.withLightness((hsl.lightness - amount).clamp(0.0, 1.0)); - - return hslDark.toColor(); - } - - Color lighten([double amount = .1]) { - assert(amount >= 0 && amount <= 1); - - final hsl = HSLColor.fromColor(this); - final hslLight = - hsl.withLightness((hsl.lightness + amount).clamp(0.0, 1.0)); - - return hslLight.toColor(); - } -} diff --git a/mnemo_cards/lib/utils/string_helper.dart b/mnemo_cards/lib/utils/string_helper.dart deleted file mode 100644 index bedf73a..0000000 --- a/mnemo_cards/lib/utils/string_helper.dart +++ /dev/null @@ -1,81 +0,0 @@ -import 'dart:convert'; -import 'dart:ui'; - -import 'package:auto_size_text/auto_size_text.dart'; -import 'package:flutter/foundation.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_screenutil/flutter_screenutil.dart'; -import 'package:mnemo_cards/features/analytics/analytics.dart'; -import 'package:mnemo_cards_common/mnemo_cards_common.dart'; - -extension StringHelper on String { - String get capitalize => - "${this[0].toUpperCase()}${this.substring(1).toLowerCase()}"; - - Color? get asColor { - if (startsWith('#')) { - return replaceFirst('#', '0x').asColor; - } - if (startsWith('0x')) { - if (length > '0x001122'.length) { - return Color(int.parse(this)); - } else { - return Color(0xff000000 + int.parse(this)); - } - } else { - if (length == 'aabbcc'.length || length == 'ffaabbcc'.length) { - return '0x$this'.asColor; - } - } - return Color(0xffffffff); - } -} - -extension PackTipExt on PackTip { - Widget build(BuildContext context) { - switch (type) { - case PackTipType.asset: - final asset = (this as AssetPackTip).asset; - return Image.asset( - asset, - errorBuilder: (_, __, ___) => Image.asset( - asset.replaceFirst('.png', '.webp'), - width: 23.w, - height: 23.h, - color: Theme.of(context).colorScheme.primary, - ), - width: 23.w, - height: 23.h, - color: Theme.of(context).colorScheme.primary, - ); - case PackTipType.base64: - return FutureBuilder( - future: compute( - base64Decode, - (this as Base64PackTip).base64, - ).onError( - (e, s) { - Analytics.crashlyticsError(e: e, s: s, message: 'tooltip build'); - return Uint8List.fromList([]); - }, - ), - builder: (context, snapshot) { - if (snapshot.data == null || snapshot.requireData.isEmpty) { - return SizedBox.shrink(); - } - return Image.memory(snapshot.requireData); - }, - ); - case PackTipType.text: - return AutoSizeText( - (this as TextPackTip).text, - minFontSize: 8, - textAlign: TextAlign.center, - wrapWords: false, - ); - case PackTipType.unknown: - return const SizedBox.shrink(); - } - } -} diff --git a/mnemo_cards/lib/widgets/buy_subscription_widget.dart b/mnemo_cards/lib/widgets/buy_subscription_widget.dart deleted file mode 100644 index c15400b..0000000 --- a/mnemo_cards/lib/widgets/buy_subscription_widget.dart +++ /dev/null @@ -1,19 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:mnemo_cards/main.dart'; -import 'package:mnemo_cards_frontend_common/mnemo_cards_frontend_common.dart'; - -import '../di/locator.dart'; -import '../domain/router/app_router.dart'; -import '../features/subscription/subscription_page.dart'; - -class MobileBuySubscriptionWidget extends StatelessWidget { - @override - Widget build(BuildContext context) { - return BuySubscriptionWidget( - onBuySubscription: () => - locator.subscriptionManager.openSubscriptionPage(), - ); - } - - const MobileBuySubscriptionWidget(); -} diff --git a/mnemo_cards/lib/widgets/card_game/card_game_header.dart b/mnemo_cards/lib/widgets/card_game/card_game_header.dart deleted file mode 100644 index ad7ad4a..0000000 --- a/mnemo_cards/lib/widgets/card_game/card_game_header.dart +++ /dev/null @@ -1,29 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:mnemo_cards_common/mnemo_cards_common.dart'; -import 'package:mnemo_cards_frontend_common/mnemo_cards_frontend_common.dart'; - -class CardGameHeader extends StatelessWidget { - final PageController controller; - final CardPackDto cardPackDto; - - const CardGameHeader( - this.controller, - this.cardPackDto, - ); - - @override - Widget build(BuildContext context) { - final theme = Theme.of(context).textTheme; - - return StreamBuilder( - stream: controller.asStream, - builder: (context, snapshot) => Header( - '${cardPackDto.title}', - // trailing: Text( - // '${snapshot.data}/${cardPackDto.size}', - // style: theme.headlineSmall, - // ), - ), - ); - } -} diff --git a/mnemo_cards/lib/widgets/card_game/card_game_main.dart b/mnemo_cards/lib/widgets/card_game/card_game_main.dart deleted file mode 100644 index 6d25e91..0000000 --- a/mnemo_cards/lib/widgets/card_game/card_game_main.dart +++ /dev/null @@ -1,167 +0,0 @@ -import 'dart:math'; - -import 'package:flutter/material.dart'; -import 'package:mnemo_cards/features/packs/images_holder.dart'; -import 'package:mnemo_cards_common/mnemo_cards_common.dart'; -import 'package:mnemo_cards_frontend_common/mnemo_cards_frontend_common.dart'; - -import '../../features/card_flipper/flip_card_controllers.dart'; -import '../../main.dart'; -import '../game_card_widget.dart'; - -class CardGameMainWidget extends StatelessWidget { - final List cards; - final Color? color; - final int? startCardId; - final PageController pageController; - final FlipCardController flipCardController; - final int length; - - const CardGameMainWidget( - this.cards, - this.color, - this.startCardId, - this.pageController, - this.flipCardController, - this.length, - ); - - @override - Widget build(BuildContext context) { - final numberOfCardsDisplayed = min(2, cards.length); - final initialScale = 0.9; - - GameCardDto? activeCard() => - cards[pageController.pageOrZero % cards.length]; - - return PopScope( - canPop: false, - onPopInvoked: (v) { - if (!v) { - appRouter.popForced(activeCard()?.id); - } - }, - child: Material( - type: MaterialType.transparency, - child: LayoutBuilder(builder: (context, constraints) { - final cardWidth = constraints.maxWidth; - final cardHeight = cardWidth; - bool enabled = true; - return StatefulBuilder(builder: (context, setState) { - return Stack( - children: [ - _EndWidget(), - if (enabled) - Hero( - tag: activeCard()?.id ?? 'empty', - child: PageView.builder( - controller: pageController, - itemBuilder: (context, cardIndex) { - final index = cardIndex % cards.length; - return AnimatedBuilder( - animation: pageController, - builder: (context, child) => Transform.scale( - scale: pageController.position.haveDimensions - ? max( - 0.9, - (1 - - ((pageController.page! - cardIndex) - .abs() / - 2)), - ) - : 1.0, - child: ConstrainedBox( - constraints: constraints, - child: Center( - child: GameCardWidget( - cards[index], - cards[index].memoryImage, - flipCardController, - flipCardController.state - // || cards[index].isAd - , - true, - color, - ), - ), - ), - ), - ); - }, - clipBehavior: Clip.none, - physics: BouncingScrollPhysics(), - ), - ), - ], - ); - }); - }), - ), - ); - } -} - -class _EndWidget extends StatelessWidget { - _EndWidget(); - - @override - Widget build(BuildContext context) { - return Container(); - } -} - -// void OldSwiper() { -// return AbsorbPointer( -// absorbing: snapshot.data ?? false, -// child: CardSwiper( -// controller: cardSwiperController, -// padding: const EdgeInsets.symmetric( -// vertical: 0.0, -// horizontal: 0.0, -// ), -// cardsCount: length, -// numberOfCardsDisplayed: numberOfCardsDisplayed, -// allowedSwipeDirection: -// AllowedSwipeDirection.all(), -// scale: initialScale, -// backCardOffset: Offset(0, cardHeight * 0.1 / 2), -// isLoop: false, -// cardBuilder: ( -// context, -// cardIndex, -// percentThresholdX, -// percentThresholdY, -// scale, -// ) { -// final index = cardIndex % cards.length; -// final isFirstCard = -// (cardSwiperController.currentIndex == -// cardIndex); -// if (cardSwiperController.currentIndex == -// index) { -// // lastThreshold = percentThresholdX; -// } -// print('${cards[index].translation} $scale'); -// final cardWidget = Center( -// child: GameCardWidget( -// cards[index], -// cards[index].memoryImage, -// flipCardController, -// flipCardController.state -// // || cards[index].isAd -// , -// isFirstCard, -// isFirstCard -// ? color -// : color?.darken( -// (scale - 1) / -// (initialScale - 1) * -// 0.075, -// ), -// ), -// ); -// return cardWidget; -// }, -// ), -// ); -// } diff --git a/mnemo_cards/lib/widgets/card_game/card_game_page.dart b/mnemo_cards/lib/widgets/card_game/card_game_page.dart deleted file mode 100644 index 0844e0c..0000000 --- a/mnemo_cards/lib/widgets/card_game/card_game_page.dart +++ /dev/null @@ -1,330 +0,0 @@ -import 'dart:async'; - -import 'package:auto_route/auto_route.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_screenutil/flutter_screenutil.dart'; -import 'package:mnemo_cards/features/tests/progress_widget.dart'; -import 'package:mnemo_cards/main.dart'; -import 'package:mnemo_cards/managers/audio_player.dart'; -import 'package:mnemo_cards/theme/themes.dart'; -import 'package:mnemo_cards/utils/color_helper.dart'; -import 'package:mnemo_cards_common/mnemo_cards_common.dart'; -import 'package:mnemo_cards_frontend_common/mnemo_cards_frontend_common.dart'; -import '../../di/locator.dart'; -import '../../features/card_flipper/flip_card_controllers.dart'; -import 'card_game_main.dart'; - -@RoutePage() -class CardGamePage extends StatefulWidget { - final int? startCardId; - final List cards; - final Color? color; - final bool infinite; - final bool shuffle; - - const CardGamePage({ - required this.cards, - required this.color, - this.startCardId, - this.infinite = false, - this.shuffle = true, - super.key, - }); - - @override - State createState() => _CardGamePageState(); -} - -class _CardGamePageState extends State { - final PageController cardPageController = PageController(); - final FlipCardController flipCardController = FlipCardController(); - - StreamSubscription? _sub; - - List shuffledCards = []; - - GameCardDto? get activeCard { - final index = cardPageController.pageOrZero; - // final index = cardSwiperController.currentIndex; - if (index >= 0) { - return shuffledCards[index % shuffledCards.length]; - } - return null; - } - - int get gameLength => widget.infinite ? 10000000 : shuffledCards.length; - - int lastCard = -1; - - void playSound() { - if (globalSharedPreferences.getBool('auto_play_sound_view') == true && - flipCardController.isFront) { - if (activeCard == null || activeCard?.id == lastCard) { - return; - } - lastCard = activeCard!.id; - final text = activeCard?.original; - if (text != null) { - AudioPlayer.playAudio(text, lang: 'es-ES'); - } - } - } - - @override - Widget build(BuildContext context) { - // todo move to controller - // final timer = Stream.periodic(Duration(seconds: 1), (tick) { - // return Duration(seconds: tick + 1); - // }).asBroadcastStream().take(3600).startWith(Duration.zero); - - WidgetsBinding.instance.addPostFrameCallback((_) async { - await Future.delayed(Duration(milliseconds: 50)); - if (mounted) { - playSound(); - } - }); - - return Scaffold( - body: PopScope( - child: SafeArea( - child: LayoutBuilder(builder: (context, constraints) { - return Column( - children: [ - Expanded( - child: LayoutBuilder( - builder: (context, constraints) { - final aspectRatio = - constraints.maxHeight / constraints.maxWidth; - return Column( - children: [ - if (aspectRatio > 14 / 9) - SizedBox( - height: (64.h - - 20.h - - MediaQuery.of(context).padding.top) / - 2, - ), - if (aspectRatio > 14 / 9) - Padding( - padding: EdgeInsets.symmetric(horizontal: 10.w), - child: StatefulBuilder( - builder: (context, setState) { - void _setState() { - setState(() {}); - } - - cardPageController.removeListener(_setState); - cardPageController.addListener(_setState); - return ProgressWidget( - widget.infinite - ? null - : List.filled( - cardPageController.pageOrZero, - Result.correct, - ), - shuffledCards.length, - widget.color ?? borderGray, - popText: widget.infinite ? 'к теме' : null, - key: ValueKey('CARDS PROGRESS'), - ); - }, - ), - ), - if (aspectRatio > 14 / 9) - SizedBox( - height: (64.h - - 20.h - - MediaQuery.of(context).padding.top) / - 2, - ), - Expanded( - child: Stack( - children: [ - CardGameMainWidget( - shuffledCards, - widget.color, - widget.startCardId, - cardPageController, - flipCardController, - gameLength, - ), - if (aspectRatio <= 14 / 9) - Align( - alignment: Alignment.topLeft, - child: IconButton( - onPressed: - AutoRouter.of(context).maybePop, - icon: Icon( - Icons.arrow_back_ios, - color: Colors.grey[400], - ), - ), - ) - ], - ), - ), - ], - ); - }, - ), - ), - if (constraints.maxHeight / constraints.maxWidth > 17 / 9) - Hero( - tag: 'bottom', - createRectTween: (a, b) => RectTween(begin: a, end: b), - child: Material( - color: Colors.transparent, - child: ListenableBuilder( - listenable: cardPageController, - builder: (context, snapshot) { - return AnimatedContainer( - duration: Duration(milliseconds: 200), - height: activeCard == null ? 0 : 90.h, - padding: EdgeInsets.only( - left: 10.0.w, - right: 10.0.w, - bottom: 10.0.h, - top: 10.0.h, - ), - child: Row( - children: [ - Expanded( - flex: 1, - child: GestureDetector( - onTap: () async { - if (activeCard != null) - await locator.favoriteCardsController - .switchFavoriteCard(activeCard!); - }, - child: StreamBuilder( - stream: locator - .favoriteCardsController.asStream, - initialData: locator - .favoriteCardsController.state, - builder: (context, snapshot) { - return Container( - alignment: Alignment.center, - decoration: BoxDecoration( - color: Theme.of(context) - .scaffoldBackgroundColor - .lighten(0.05), - border: Border.all( - color: borderGray), - borderRadius: - BorderRadius.circular(16.0), - ), - padding: EdgeInsets.all(10.0.w), - child: Image.asset( - locator.favoriteCardsController - .isFavoriteCard( - activeCard?.id, - ) - ? "icons/heart_fill.webp" - : "icons/heart.webp", - width: 29.w, - height: 29.h, - color: locator - .favoriteCardsController - .isFavoriteCard( - activeCard?.id, - ) - ? Colors.red - : Colors.grey, - ), - ); - }), - ), - ), - SizedBox( - width: 10.0.w, - ), - Expanded( - flex: 3, - child: GestureDetector( - onTap: () async { - // cardSwiperController.swipe( - // direction: CardSwiperState.swipeLeft, - // ); - cardPageController.nextPage( - duration: Duration(milliseconds: 300), - curve: Curves.ease, - ); - }, - child: Container( - alignment: Alignment.center, - decoration: BoxDecoration( - color: Theme.of(context) - .scaffoldBackgroundColor - .lighten(0.05), - border: Border.all(color: borderGray), - borderRadius: - BorderRadius.circular(16.0), - ), - padding: EdgeInsets.all(10.0.w), - child: Text( - 'Дальше', - style: TextStyle( - fontSize: 25.sp, - fontWeight: FontWeight.w700, - height: 0.85, - ), - ), - ), - ), - ), - ], - ), - ); - }), - ), - ) - ], - ); - }), - ), - ), - ); - } - - @override - void initState() { - super.initState(); - shuffledCards = widget.cards.toList(); - if (widget.shuffle) { - shuffledCards..shuffle(); - } - if (widget.startCardId != null) { - final startCardIndex = shuffledCards.indexWhere( - (card) => card.id == widget.startCardId, - ); - - if (startCardIndex >= 0) { - shuffledCards = [ - ...shuffledCards.sublist(startCardIndex), - ...shuffledCards.sublist(0, startCardIndex), - ]; - } else { - shuffledCards = []; - } - } else { - shuffledCards = widget.cards.toList(); - } - cardPageController.addListener(() { - if (cardPageController.hasClients && - ((cardPageController.page ?? -999) - cardPageController.pageOrZero) == - 0) { - playSound(); - } - }); - - // _sub = cardSwiperController.asStream.distinct().listen(playSound); - } - - @override - void dispose() { - _sub?.cancel().then((_) => _sub = null); - cardPageController.removeListener(playSound); - // cardSwiperController.removeListener(cardSwiperListener); - super.dispose(); - } -} diff --git a/mnemo_cards/lib/widgets/card_game/card_game_swipe_helper.dart b/mnemo_cards/lib/widgets/card_game/card_game_swipe_helper.dart deleted file mode 100644 index fa7abdc..0000000 --- a/mnemo_cards/lib/widgets/card_game/card_game_swipe_helper.dart +++ /dev/null @@ -1,66 +0,0 @@ -// import 'package:flutter/material.dart'; -// -// class CardGameSwipeHelper extends StatelessWidget { -// final PageController pageController; -// -// const CardGameSwipeHelper(this.pageController); -// -// @override -// Widget build(BuildContext context) { -// final theme = Theme.of(context).textTheme; -// -// return Container( -// padding: const EdgeInsets.only( -// left: 16.0, -// right: 16.0, -// bottom: 0.0, -// ), -// child: StreamBuilder( -// stream: pageController.asStream, -// builder: (context, snapshot) { -// return Row( -// mainAxisAlignment: MainAxisAlignment.spaceBetween, -// children: [ -// Row( -// children: [ -// Icon( -// Icons.circle, -// color: Colors.green, -// ), -// SizedBox( -// width: 4.0, -// ), -// Text( -// 'Помню ${cardSwiperController.swipedLeftIds.isEmpty ? '' : cardSwiperController.swipedLeftIds.length}', -// style: theme.labelMedium?.copyWith( -// color: Colors.green, -// fontWeight: FontWeight.w600, -// ), -// ) -// ], -// ), -// Row( -// children: [ -// Text( -// 'Повторить ${cardSwiperController.swipedRightIds.isEmpty ? '' : cardSwiperController.swipedRightIds.length}', -// style: theme.labelMedium?.copyWith( -// color: Colors.yellow[600], -// fontWeight: FontWeight.w600, -// ), -// ), -// SizedBox( -// width: 4.0, -// ), -// Icon( -// Icons.circle, -// color: Colors.yellow[600], -// ), -// ], -// ), -// ], -// ); -// } -// ), -// ); -// } -// } diff --git a/mnemo_cards/lib/widgets/card_pack/available_pack.dart b/mnemo_cards/lib/widgets/card_pack/available_pack.dart deleted file mode 100644 index 4e5cfdc..0000000 --- a/mnemo_cards/lib/widgets/card_pack/available_pack.dart +++ /dev/null @@ -1,492 +0,0 @@ -import 'dart:math'; - -import 'package:auto_route/auto_route.dart'; -import 'package:flutter/foundation.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:flutter_screenutil/flutter_screenutil.dart'; -import 'package:mnemo_cards/features/tests/test_manager.dart'; -import 'package:mnemo_cards/main.dart'; -import 'package:mnemo_cards_common/mnemo_cards_common.dart'; -import 'package:mnemo_cards_frontend_common/mnemo_cards_frontend_common.dart'; -import 'package:yandex_mobileads/mobile_ads.dart'; -import '../../domain/router/app_router.gr.dart'; -import '../../features/analytics/analytics.dart'; -import '../../features/yandex_ads/yandex_ads.dart'; - -import '../../di/locator.dart'; -import '../../theme/themes.dart'; -import 'card_pack_header.dart'; -import 'package:mnemo_cards/utils/string_helper.dart'; - -import 'cards_view.dart'; -import 'cards_view_controller.dart'; - -final _mainScrollController = ScrollController(); -final _reorderableTests = GlobalKey(); - -class AvailablePack extends StatelessWidget { - final CardPackDto cardPack; - late final CardsViewController _cardsViewController = - CardsViewController(cardPack); - - AvailablePack(this.cardPack); - - @override - Widget build(BuildContext context) { - Analytics.availablePackOpened(cardPack); - return Column( - children: [ - CardPackHeader.fromDto(cardPack), - Expanded( - child: ListView( - controller: _mainScrollController, - shrinkWrap: true, - children: [ - StatefulBuilder(builder: (context, setState) { - return Column( - children: [ - Container( - decoration: BoxDecoration( - color: cardPack.color?.asColor?.withOpacity(0.1), - ), - alignment: Alignment.center, - clipBehavior: Clip.antiAlias, - child: CardsView( - _cardsViewController, - color: cardPack.color?.asColor, - ), - ), - Container( - height: 1, - color: cardPack.color?.asColor ?? - Colors.grey.withOpacity(0.5), - ), - SizedBox( - height: 10.h, - ), - Padding( - padding: EdgeInsets.symmetric( - horizontal: 10.w, - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - StreamBuilder( - stream: _cardsViewController.asStream - .map((s) => s.expanded), - builder: (context, snapshot) { - return _DownButton( - !(snapshot.data ?? false), - () async { - if (snapshot.hasData) { - final expanded = snapshot.requireData; - _cardsViewController.setExpanded( - !expanded, - ); - if (expanded) { - await _mainScrollController.animateTo( - 0, - duration: Duration( - milliseconds: (100 * - _cardsViewController - .cards.length / - 3) - .ceil(), - ), - curve: Curves.easeInOut, - ); - } - } - }, - key: ValueKey('DownButton'), - ); - }), - _Button('shuffle.webp', () async { - final cards = _cardsViewController.state.packCards; - if (cards.isEmpty) return; - final index = (_cardsViewController.offsetCards + - Random().nextInt( - (cards.length / 2).ceil(), - ) + - 3) % - cards.length; - await _cardsViewController.animateTo(index); - AutoRouter.of(context).push( - PageRouteInfo( - CardGamePage.name, - args: CardGamePageArgs( - cards: cards, - color: cardPack.color?.asColor, - startCardId: cards[index].id, - infinite: true, - shuffle: true, - // id: cardPack.dto.id.toString(), - ), - ), - ); - }), - // _Button('chat.webp', () {}), - StreamBuilder( - stream: _cardsViewController.asStream, - builder: (context, snapshot) { - return _Button( - (snapshot.data?.favorite ?? false) - ? 'heart_fill.webp' - : 'heart.webp', - () { - if (snapshot.hasData) { - _cardsViewController.setFavorite( - !snapshot.requireData.favorite, - ); - } - }, - ); - }), - ], - ), - ), - ], - ); - }), - if (locator.userManager.user?.subscriptionFeatures - .contains(SubscriptionFeatureEnum.ads) != - true) - _AdTile(), - _TestsSection(cardPack.id.toString()), - ], - ), - ), - Hero( - tag: 'bottom', - child: SizedBox( - height: 0, - width: 300.w, - ), - ), - ], - ); - } -} - -class _TestsSection extends StatelessWidget { - final String packId; - - const _TestsSection(this.packId); - - @override - Widget build(BuildContext context) { - final testsOrder = (globalSharedPreferences - .getString('tests_order_${packId}') - ?.decodeList() ?? - []) - .toList(); - - locator.testManager.pollTests(packId: packId); - - void saveOrder() { - globalSharedPreferences.setString( - 'tests_order_${packId}', - testsOrder.encode(), - ); - } - - return BlocBuilder( - bloc: locator.testManager, - builder: (context, snapshot) { - final tests = snapshot.dtos; - if (tests.isEmpty) { - return SizedBox.shrink(); - } - - if (testsOrder.isEmpty) { - testsOrder.addAll(tests.map((t) => t.name)); - saveOrder(); - } - return FadeInWidget( - animationDuration: Duration(milliseconds: 400), - child: StatefulBuilder(builder: (context, setState) { - tests..sortInOrder(testsOrder, (t) => t.name); - return ReorderableListView.builder( - key: _reorderableTests, - itemExtent: 100.h + 2 * 5.h, - padding: EdgeInsets.symmetric( - horizontal: 10.w, - vertical: 5.h, - ), - shrinkWrap: true, - scrollController: _mainScrollController, - proxyDecorator: (_, index, animation) { - final dto = tests[index]; - return Material( - elevation: 5, - borderRadius: BorderRadius.circular(16), - color: Colors.transparent, - child: _PackTestButton( - title: dto.name, - subtitle: null, - stats: dto.statistics, - color: dto.color?.asColor ?? borderGray, - time: dto.time, - timeSubtitle: dto.timeSubtitle, - onTap: () {}, - ), - ); - }, - onReorder: (int from, int to) { - if (to - from > 1) { - to--; - } - testsOrder.move(from, to); - saveOrder(); - setState(() {}); - }, - itemCount: tests.length, - itemBuilder: (context, index) { - final dto = tests[index]; - return Padding( - key: ValueKey(dto.id), - padding: EdgeInsets.symmetric( - vertical: 5.0.h, - ), - child: _PackTestButton( - title: dto.name, - subtitle: null, - stats: dto.statistics, - color: dto.color?.asColor ?? borderGray, - time: dto.time, - timeSubtitle: dto.timeSubtitle, - onTap: () { - AutoRouter.of(context).push( - PageRouteInfo(TestPage.name, - args: TestPageArgs(testId: dto.id!)), - ); - }, - ), - ); - }, - ); - }), - ); - }, - ); - } -} - -class _AdTile extends StatelessWidget { - const _AdTile(); - - final height = 85.0; - - @override - Widget build(BuildContext context) { - if (locator.userManager.userStateHolder.user?.subscription == true) - return SizedBox.shrink(); - if (kIsWeb) return SizedBox.shrink(); - return LayoutBuilder(builder: (context, constraints) { - final banner = YandexAds.createBanner( - BoxConstraints.tight(Size(constraints.maxWidth - 16, height - 8)), - id: 'R-M-3761037-2', - ); - return FadeInWidget( - future: banner.loadAd(), - animationDuration: Duration(milliseconds: 1000), - child: Container( - height: height, - margin: const EdgeInsets.symmetric(vertical: 4.0, horizontal: 8.0), - decoration: BoxDecoration( - border: Border.all( - color: Theme.of(context).scaffoldBackgroundColor, - width: 4.0, - ), - borderRadius: BorderRadius.circular(12.0), - ), - child: Center( - child: AdWidget(bannerAd: banner), - ), - ), - ); - }); - } -} - -class _Button extends StatelessWidget { - final String asset; - final VoidCallback onTap; - - _Button(this.asset, this.onTap); - - @override - Widget build(BuildContext context) { - return GestureDetector( - onTap: onTap, - child: Container( - width: 110.w, - height: 60.h, - decoration: BoxDecoration( - color: Theme.of(context).scaffoldBackgroundColor, - border: Border.all(color: borderGray), - borderRadius: BorderRadius.circular(16.0), - ), - alignment: Alignment.center, - child: Image.asset( - 'icons/$asset', - width: 29.w, - color: Theme.of(context).colorScheme.primary, - // height: 29.h, - fit: BoxFit.scaleDown, - ), - ), - ); - } -} - -class _DownButton extends StatelessWidget { - final VoidCallback onTap; - final bool isDown; - - _DownButton(bool this.isDown, this.onTap, {super.key}); - - @override - Widget build(BuildContext context) { - return InkWell( - onTap: onTap, - child: Container( - width: 110.w, - height: 60.h, - decoration: BoxDecoration( - color: Theme.of(context).scaffoldBackgroundColor, - border: Border.all(color: borderGray), - borderRadius: BorderRadius.circular(16.0), - ), - alignment: Alignment.center, - child: AnimatedRotation( - duration: Duration(milliseconds: 300), - turns: isDown ? 0.0 : 0.5, - child: Image.asset( - 'icons/down.webp', - width: 29.w, - color: Theme.of(context).colorScheme.primary, - // height: 29.h, - fit: BoxFit.scaleDown, - ), - ), - ), - ); - } -} - -class _PackTestButton extends StatelessWidget { - final VoidCallback onTap; - final String title; - final String? subtitle; - final String? time; - final String? timeSubtitle; - final Color color; - final TestStatisticsDto? stats; - - _PackTestButton({ - required this.title, - required this.onTap, - required this.color, - this.subtitle, - this.time, - this.timeSubtitle, - this.stats, - }); - - @override - Widget build(BuildContext context) { - return GestureDetector( - onTap: onTap, - child: Container( - height: 80.h, - alignment: Alignment.center, - decoration: BoxDecoration( - color: Theme.of(context).scaffoldBackgroundColor, - border: Border.all(color: borderGray), - borderRadius: BorderRadius.circular(16.0), - ), - padding: EdgeInsets.only( - top: 12.0.h, - left: 10.0.w, - right: 10.0.w, - bottom: 20.h, - ), - child: Row( - children: [ - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - title, - style: TextStyle( - fontSize: 25.sp, - fontWeight: FontWeight.w700, - height: 0.85, - ), - ), - if (subtitle != null) - Padding( - padding: const EdgeInsets.only(top: 8.0), - child: Text( - subtitle!, - style: TextStyle( - fontSize: 16.sp, - fontWeight: FontWeight.w500, - height: 0.85, - ), - ), - ), - Spacer(), - if (stats != null) - Padding( - padding: const EdgeInsets.only(right: 50.0), - child: Row( - children: [ - Expanded( - child: HorizontalProgressWidget( - stats!.words.correct.round(), - stats!.words.total.round(), - color, - borderColor: color, - ), - ), - ], - ), - ), - ], - ), - ), - Container( - width: 75.w, - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - if (time != null) - Text( - time!, - style: TextStyle( - fontSize: 40.sp, - fontWeight: FontWeight.w700, - height: 0.85), - ), - if (timeSubtitle != null) - Text( - timeSubtitle!, - style: TextStyle( - fontSize: 24.sp, - fontWeight: FontWeight.w700, - height: 0.85), - ), - ], - ), - ), - ], - ), - ), - ); - } -} diff --git a/mnemo_cards/lib/widgets/card_pack/buy_pack_page.dart b/mnemo_cards/lib/widgets/card_pack/buy_pack_page.dart deleted file mode 100644 index 6788cf5..0000000 --- a/mnemo_cards/lib/widgets/card_pack/buy_pack_page.dart +++ /dev/null @@ -1,231 +0,0 @@ -import 'dart:convert'; -import 'dart:developer'; -import 'package:mnemo_cards/flags.dart'; -import 'package:mnemo_cards/utils/string_helper.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_screenutil/flutter_screenutil.dart'; -import 'package:mnemo_cards_common/mnemo_cards_common.dart'; -import 'package:mnemo_cards_frontend_common/mnemo_cards_frontend_common.dart'; -import '../../features/analytics/analytics.dart'; -import '../../main.dart'; - -import '../../di/locator.dart'; -import '../../domain/router/app_router.dart'; -import '../../theme/themes.dart'; -import 'card_pack_header.dart'; - -class BuyPack extends StatelessWidget { - final CardPackBuyDto dto; - - const BuyPack(this.dto); - - @override - Widget build(BuildContext context) { - bool loading = false; - Analytics.buyPackOpened(dto); - return Container( - // color: dto.color?.asColor, - child: StatefulBuilder(builder: (context, setState) { - if (loading) { - return _Loading(dto); - } - return Column( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - CardPackHeader(dto.title, dto.subtitle, dto.color?.asColor), - Expanded( - child: Column( - // physics: PageScrollPhysics(), - // shrinkWrap: true, - children: [ - Padding( - padding: EdgeInsets.symmetric( - horizontal: 10.0.w, vertical: 18.h), - child: LayoutBuilder(builder: (context, constraints) { - final cardWidth = constraints.maxWidth / 3; - final imageWidth = cardWidth * 0.9; - return SizedBox( - height: 150.h, - child: ListView.builder( - scrollDirection: Axis.horizontal, - itemCount: dto.cards.length, - itemExtent: cardWidth, - itemBuilder: (BuildContext context, int index) { - final card = dto.cards[index]; - if (card.image != null) { - return Container( - alignment: Alignment.center, - width: imageWidth, - margin: EdgeInsets.symmetric( - horizontal: cardWidth - imageWidth - 1, - vertical: 1, - ), - decoration: BoxDecoration( - color: Theme.of(context).cardColor, - borderRadius: BorderRadius.circular(8.0), - border: Border.all( - color: borderGray, - ), - ), - child: Image.memory(base64Decode(card.image!)), - ); - } - return SizedBox.shrink(); - }, - ), - ); - }), - ), - SizedBox( - height: 32.h, - ), - ...?dto.items?.build(), - ], - ), - ), - // _BuyButton( - // dto, - // (v) => setState(() { - // loading = v != null; - // }), - // ), - SizedBox( - height: 16.h, - ), - ], - ); - }), - ); - } -} - -class _Loading extends StatelessWidget { - final CardPackBuyDto dto; - - _Loading(this.dto); - - @override - Widget build(BuildContext context) { - final memoryImage = locator.imagesHolder.get('pack_${dto.id}'); - return Column( - children: [ - CardPackHeader(dto.title, dto.subtitle, dto.color?.asColor), - Expanded( - child: Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - if (memoryImage != null) - Padding( - padding: const EdgeInsets.all(8.0), - child: Image( - image: memoryImage, - width: 100, - ), - ), - Text('Загрузка...'), - ], - ), - ), - ), - ], - ); - } -} - -class _BuyButton extends StatelessWidget { - final CardPackBuyDto dto; - final Function(String? loadingText) callback; - - _BuyButton(this.dto, this.callback); - - @override - Widget build(BuildContext context) { - return Padding( - padding: EdgeInsets.symmetric( - vertical: 5.0.h, - ), - child: Column( - mainAxisAlignment: MainAxisAlignment.end, - mainAxisSize: MainAxisSize.max, - children: [ - TextButton( - style: ButtonStyle( - overlayColor: - WidgetStateColor.resolveWith((states) => Colors.white), - ), - onPressed: () async { - if (locator.userManager.hasUser) { - Analytics.buyPackPressed(dto, PaymentSystem.yookassa); - await locator.purchaseManager.initPurchaseFromDto( - dto: dto, - paymentSystem: PaymentSystem.yookassa, - ); - // if (result) { - // _updatePack(); - // } - } else { - AppRouter.openAuth(); - } - }, - child: Text( - 'Оплатить российской картой', - style: TextStyle( - fontSize: 16, - fontWeight: FontWeight.w400, - decoration: TextDecoration.underline, - ), - ), - ), - MnemoCardsButton( - onTap: () async { - if (locator.userManager.hasUser) { - Analytics.buyPackPressed(dto, androidPaymentSystem); - await locator.purchaseManager.initPurchaseFromDto( - dto: dto, - paymentSystem: androidPaymentSystem, - ); - } else { - AppRouter.openAuth(); - } - }, - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text( - 'Оплатить через', - style: TextStyle( - fontSize: 18.sp, - fontWeight: FontWeight.w700, - height: 1.0, - ), - ), - Text( - 'Google pay', - style: TextStyle( - fontSize: 18.sp, - fontWeight: FontWeight.w700, - height: 0.85, - ), - ), - SizedBox( - height: 10.0.h, - ), - if (dto.price != null) - Text( - dto.price!, - style: TextStyle( - fontSize: 17.sp, - fontWeight: FontWeight.w400, - height: 1.0, - ), - ), - ], - ), - height: 120.h, - ) - ], - ), - ); - } -} diff --git a/mnemo_cards/lib/widgets/card_pack/card_pack_header.dart b/mnemo_cards/lib/widgets/card_pack/card_pack_header.dart deleted file mode 100644 index 31960f2..0000000 --- a/mnemo_cards/lib/widgets/card_pack/card_pack_header.dart +++ /dev/null @@ -1,41 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_screenutil/flutter_screenutil.dart'; -import 'package:mnemo_cards_common/mnemo_cards_common.dart'; -import 'package:mnemo_cards/utils/string_helper.dart'; -import 'package:mnemo_cards_frontend_common/mnemo_cards_frontend_common.dart'; - -class CardPackHeader extends StatelessWidget { - final String? title; - final String? subtitle; - final Color? color; - - CardPackHeader(this.title, this.subtitle, this.color); - - CardPackHeader.fromDto(CardPackDto? dto) - : title = dto?.title, - subtitle = dto?.subtitle, - color = dto?.color?.asColor; - - @override - Widget build(BuildContext context) { - return Column( - children: [ - Header( - title, - subtitle: subtitle, - popText: 'к темам', - hasPopButton: true, - color: null,// color?.withOpacity(0.5), - ), - Container( - color: null, //color?.withOpacity(0.5), - height: 25.h, - ), - Container( - color: color ?? Colors.grey.withOpacity(0.5), - height: 1, - ) - ], - ); - } -} diff --git a/mnemo_cards/lib/widgets/card_pack/card_pack_page.dart b/mnemo_cards/lib/widgets/card_pack/card_pack_page.dart deleted file mode 100644 index fb9217e..0000000 --- a/mnemo_cards/lib/widgets/card_pack/card_pack_page.dart +++ /dev/null @@ -1,93 +0,0 @@ -import 'dart:convert'; - -import 'package:auto_route/annotations.dart'; -import 'package:auto_route/auto_route.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:mnemo_cards/features/packs/active_pack_cubit.dart'; -import 'package:mnemo_cards_common/mnemo_cards_common.dart'; -import '../../features/analytics/analytics.dart'; - -import '../../di/locator.dart'; -import '../../features/packs/active_pack.dart'; -import 'available_pack.dart'; -import 'buy_pack_page.dart'; -import 'card_pack_header.dart'; -import 'error_loading_pack.dart'; -import 'loading_pack.dart'; - -@RoutePage() -class CardPackPage extends StatefulWidget { - final CardPackPreviewDto previewDto; - - const CardPackPage(this.previewDto, {super.key}); - - @override - State createState() => _CardPackPage(); -} - -class _CardPackPage extends State { - @override - Widget build(BuildContext context) { - return Scaffold( - body: SafeArea( - child: BlocBuilder( - bloc: locator.activePackCubit, - buildWhen: (p, n) => p != n && n != null, - builder: (context, state) => AnimatedSwitcher( - duration: const Duration(milliseconds: 300), - child: _buildPackPage(state), - ), - ), - ), - ); - } - - Widget _buildPackPage(ActivePackCubitState? state) { - if (state == null) { - return SizedBox.shrink(); - } - final response = state.getCardPackResponse; - if (state.error != null) { - if (response == null) { - return Loading(null); - } - if (response is CardPackLoadingDto) { - return ErrorLoading(response); - } - } else if (state.isLoading) { - if (response is CardPackLoadingDto?) { - return Loading(response); - } - } else if (response is CardPackBuyDto) { - return BuyPack(response); - } else if (response is CardPackDto) { - return AvailablePack(response); - } - - Analytics.crashlyticsError( - data: {'response': jsonEncode(response?.toJson() ?? '{}')}, - message: 'cant load pack ${widget.previewDto.id}', - ); - // if (response == null) return SizedBox.shrink(); - - return Column( - children: [ - CardPackHeader.fromDto(null), - Expanded( - child: Center( - child: Text( - 'Ошибка, попробуйте еще раз или обновите приложение', - ), - ), - ), - ], - ); - } - - @override - void initState() { - super.initState(); - locator.activePackCubit.loadPack(widget.previewDto); - } -} diff --git a/mnemo_cards/lib/widgets/card_pack/cards_list.dart b/mnemo_cards/lib/widgets/card_pack/cards_list.dart deleted file mode 100644 index cff7cc9..0000000 --- a/mnemo_cards/lib/widgets/card_pack/cards_list.dart +++ /dev/null @@ -1,166 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter/widgets.dart'; -import 'package:mnemo_cards/features/packs/images_holder.dart'; -import 'package:mnemo_cards/widgets/card_pack/cards_view.dart'; -import 'package:mnemo_cards_common/mnemo_cards_common.dart'; -import 'package:mnemo_cards_frontend_common/mnemo_cards_frontend_common.dart' - as frontend; -import 'package:reorderables/reorderables.dart'; - - -import '../game_card_widget.dart'; - -class CardsList extends StatelessWidget { - final List cards; - final double cardWidth; - final double imageWidth; - final double cardRatio; - final Function(List, GameCardDto) onCardTap; - final Color? color; - final Animation animation; - final Function(int, int) onReorder; - final CardBuilder? cardBuilder; - - const CardsList({ - required this.cards, - required this.cardWidth, - required this.imageWidth, - required this.cardRatio, - required this.onCardTap, - required this.onReorder, - required this.color, - required this.animation, - this.cardBuilder, - }); - - @override - Widget build(BuildContext context) { - return ReorderableWrap( - scrollPhysics: - animation.value > 0 ? const NeverScrollableScrollPhysics() : null, - onReorder: (int from, int to) => onReorder(from, to), - buildDraggableFeedback: frontend.FeedbackBuilder.simple, - padding: EdgeInsets.symmetric( - horizontal: (cardWidth - imageWidth - 1), - vertical: (cardWidth - imageWidth - 1), - ), - runSpacing: (cardWidth - imageWidth - 1) * 2, - spacing: (cardWidth - imageWidth - 1) * 2, - children: cards.map((card) { - if (cardBuilder != null) { - return cardBuilder!( - card, - // color, - // imageWidth, - // cardWidth, - // cardRatio, - // () => onCardTap(cards, card), - ); - } - final memoryImage = card.memoryImage; - if (memoryImage == null) return const SizedBox(); - return _CardItem( - key: ValueKey(card.id), - card: card, - color: color, - image: memoryImage, - imageWidth: imageWidth, - cardWidth: cardWidth, - cardRatio: cardRatio, - onTap: () => onCardTap(cards, card), - ); - }).toList(), - ); - } -} - -class _CardItem extends StatelessWidget { - final GameCardDto card; - final Color? color; - final MemoryImage image; - final double imageWidth; - final double cardWidth; - final double cardRatio; - final VoidCallback onTap; - - const _CardItem({ - required this.card, - required this.color, - required this.image, - required this.imageWidth, - required this.cardWidth, - required this.cardRatio, - required this.onTap, - super.key, - }); - - @override - Widget build(BuildContext context) { - return Container( - height: 2 * imageWidth - cardWidth * cardRatio * 0.5 + 2, - width: 2 * imageWidth - cardWidth + 2, - alignment: Alignment.topCenter, - child: Container( - height: imageWidth * cardRatio, - child: _CardBuilder( - color, - card, - image, - onTap, - ), - ), - ); - } -} - -class _CardBuilder extends StatelessWidget { - final GameCardDto card; - final Color? color; - final MemoryImage image; - final VoidCallback onTap; - - _CardBuilder( - this.color, - this.card, - this.image, - this.onTap, - ); - - @override - Widget build(BuildContext context) { - return GestureDetector( - key: ObjectKey(card), - onTap: onTap, - child: Hero( - key: ValueKey('${card.id}'), - tag: card.id, - child: GameCardDecoration( - alpha: 0.0, - borderColor: color, - child: FrontCard( - card, - image, - alpha: 0, - ), - ), - createRectTween: (a, b) => RectTween(begin: a, end: b), - flightShuttleBuilder: (flightC, a, dir, fromC, toC) { - final animatedCard = dir == HeroFlightDirection.push ? card : card; - // todo resolve card from context - return AnimatedBuilder( - animation: a, - builder: (context, child) => GameCardDecoration( - alpha: a.value, - borderColor: color, - child: FrontCard( - animatedCard, - animatedCard.memoryImage!, - alpha: a.value, - ), - ), - ); - }, - ), - ); - } -} diff --git a/mnemo_cards/lib/widgets/card_pack/cards_view.dart b/mnemo_cards/lib/widgets/card_pack/cards_view.dart deleted file mode 100644 index cd286e1..0000000 --- a/mnemo_cards/lib/widgets/card_pack/cards_view.dart +++ /dev/null @@ -1,218 +0,0 @@ -import 'package:auto_route/auto_route.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_screenutil/flutter_screenutil.dart'; -import 'package:mnemo_cards_common/mnemo_cards_common.dart'; -import 'package:rxdart/rxdart.dart'; - -import '../../domain/router/app_router.gr.dart'; -import '../../main.dart'; -import 'cards_list.dart'; -import 'cards_view_controller.dart'; - -typedef CardTapCallback = Function(GameCardDto); -typedef CardBuilder = Widget Function(GameCardDto card); - -class CardsView extends StatefulWidget { - final Color? color; - final CardsViewController controller; - final List cardsOrder = []; - final Function(List cards, GameCardDto card)? onCardTap; - final double? cardWidth; - final CardBuilder? cardBuilder; - - CardsView( - this.controller, { - this.color, - this.onCardTap, - this.cardWidth, - this.cardBuilder, - }); - - @override - State createState() => _CardsViewState(); -} - -class _CardsViewState extends State - with SingleTickerProviderStateMixin { - Color? get color => widget.color; - - CardsViewController get controller => widget.controller; - var _subscription = CompositeSubscription(); - - late AnimationController _animationController; - - bool expanded = false; - bool favorite = false; - - final wrapKey = GlobalKey(); - - // Add animation curve for smoother transitions - static const _animationCurve = Curves.easeInOut; - - // Cache animation duration calculation - int _calculateAnimationDuration(int cardCount) { - return (100 * cardCount / 3).ceil(); - } - - void _onStateChanged(CardsViewState state) async { - favorite = state.favorite; - if (state.expanded != expanded) { - expanded = state.expanded; - final duration = _calculateAnimationDuration(state.packCards.length); - - if (expanded) { - await controller.animateTo(0); - _animationController.animateTo( - 1.0, - duration: Duration(milliseconds: duration), - curve: _animationCurve, - ); - } else { - _animationController.animateBack( - 0.0, - duration: Duration(milliseconds: duration), - curve: _animationCurve, - ); - } - } - } - - @override - void didUpdateWidget(CardsView oldWidget) { - super.didUpdateWidget(oldWidget); - _subscription.cancel(); - _subscription = CompositeSubscription(); - controller.asStream.listen(_onStateChanged).addTo(_subscription); - } - - @override - void initState() { - super.initState(); - expanded = controller.state.expanded; - favorite = controller.state.favorite; - _animationController = AnimationController( - vsync: this, - value: expanded ? 1.0 : 0.0, - ); - _subscription.cancel(); - _subscription = CompositeSubscription(); - controller.asStream.listen(_onStateChanged).addTo(_subscription); - } - - @override - void dispose() { - _subscription.cancel(); - _animationController.dispose(); - super.dispose(); - } - - void onCardTap(List cards, GameCardDto card) async { - if (widget.onCardTap != null) { - return widget.onCardTap!(cards, card); - } - final playing = appRouter.push( - PageRouteInfo( - CardGamePage.name, - args: CardGamePageArgs( - cards: cards, - color: color, - startCardId: card.id, - infinite: true, - shuffle: false, - // id: cardPack.dto.id.toString(), - ), - ), - ); - final id = await playing; - // if (id is int) { - // final index = cardPack.cards.indexWhere((c) => c.id == id); - // if (index >= 0) { - // print('jump to $index'); - // controller.jumpTo(index); - // } - // } - } - - @override - Widget build(BuildContext context) { - final cardWidth = widget.cardWidth ?? MediaQuery.of(context).size.width / 3; - final imageWidth = cardWidth * 0.93; - const cardRatio = 4.0 / 3.0; - - return StreamBuilder( - stream: controller.cardsStream, - builder: (context, snapshot) { - if (!snapshot.hasData) { - return SizedBox(); - } - final packCards = snapshot.requireData; - - if (packCards.isEmpty) { - return _NoCards( - favorite: favorite, - height: cardWidth * cardRatio, - ); - } - - controller.imageWidth = imageWidth; - final animation = _animationController.view; - return AnimatedBuilder( - animation: animation, - builder: (context, child) { - return SingleChildScrollView( - controller: controller.cardsScrollController, - scrollDirection: - animation.value > 0 ? Axis.vertical : Axis.horizontal, - physics: animation.value > 0 - ? NeverScrollableScrollPhysics() - : null, - child: Container( - alignment: Alignment.topCenter, - height: cardWidth * cardRatio + - ((packCards.length / 3).ceil() * cardRatio * cardWidth - - cardWidth * cardRatio) * - animation.value, - child: CardsList( - cards: packCards, - cardWidth: cardWidth, - imageWidth: imageWidth, - cardRatio: cardRatio, - onCardTap: onCardTap, - onReorder: controller.onOrderChanged, - color: color, - animation: _animationController, - cardBuilder: widget.cardBuilder, - ), - ), - ); - }); - }); - } -} - -class _NoCards extends StatelessWidget { - final bool favorite; - final double height; - - _NoCards({ - required this.favorite, - required this.height, - }); - - @override - Widget build(BuildContext context) { - return Container( - height: height, - alignment: Alignment.center, - child: Text( - favorite ? 'Нет любимых карточек' : 'Пока нет карточек', - style: TextStyle( - fontSize: 16.sp, - fontWeight: FontWeight.w700, - ), - textAlign: TextAlign.center, - ), - ); - } -} diff --git a/mnemo_cards/lib/widgets/card_pack/cards_view_controller.dart b/mnemo_cards/lib/widgets/card_pack/cards_view_controller.dart deleted file mode 100644 index 073c7e8..0000000 --- a/mnemo_cards/lib/widgets/card_pack/cards_view_controller.dart +++ /dev/null @@ -1,198 +0,0 @@ -import 'dart:async'; -import 'dart:math'; - -import 'package:flutter/widgets.dart'; -import 'package:mnemo_cards/main.dart'; -import 'package:mnemo_cards_common/mnemo_cards_common.dart'; -import 'package:rxdart/rxdart.dart'; - -import '../../di/locator.dart'; - -class CardsViewController extends ChangeNotifier { - bool _expanded = false; - bool _favorite = false; - double imageWidth = 0.0; - List cards = []; - List allCardsOrder = []; - List favoriteCardsOrder = []; - - List get cardsOrder => _favorite ? favoriteCardsOrder : allCardsOrder; - - final CardPackDto cardPack; - - final ScrollController _cardsScrollController = - ScrollController(keepScrollOffset: true); - - ScrollController get cardsScrollController => _cardsScrollController; - - StreamController _streamController = - StreamController.broadcast(); - - Stream get asStream => - _streamController.stream.startWith(state).distinct(); - - Stream get expandedStream => asStream.map((s) => s.expanded).distinct(); - - Stream get favoriteStream => asStream.map((s) => s.favorite).distinct(); - - Stream> get cardsStream => - asStream.map((s) => s.packCards).distinct((p, n) => - (p.length == n.length) && - p.indexed.every((p) => n[p.$1].id == p.$2.id)); - - CardsViewState get state => CardsViewState( - expanded: _expanded, - favorite: _favorite, - packCards: cards, - ); - - List _filterPackCards() => cardPack.cards - .where( - (card) => - !_favorite || - locator.favoriteCardsController.isFavoriteCard(card.id), - ) - .toList(); - - void setExpanded(bool expanded) { - if (cards.isNotEmpty) { - _expanded = expanded; - notifyListeners(); - } - } - - Future _saveCardsOrder() async { - if (_favorite) { - await globalSharedPreferences.setString( - 'sort_fav_${cardPack.id}', - favoriteCardsOrder.encode(), - ); - } else { - await globalSharedPreferences.setString( - 'sort_${cardPack.id}', - allCardsOrder.encode(), - ); - } - } - - void _loadCardsOrder() { - favoriteCardsOrder = globalSharedPreferences - .getString( - 'sort_fav_${cardPack.id}', - ) - ?.decodeList() ?? - []; - allCardsOrder = globalSharedPreferences - .getString( - 'sort_${cardPack.id}', - ) - ?.decodeList() ?? - []; - if (allCardsOrder.isEmpty) { - allCardsOrder = cardPack.cards.map((c) => c.id).toList(); - } - if (favoriteCardsOrder.isEmpty) { - favoriteCardsOrder = allCardsOrder.toList(); - } - } - - void setCardsOrder(List order) { - if (_favorite) { - favoriteCardsOrder = order.toList(); - } else { - allCardsOrder = order.toList(); - } - _saveCardsOrder(); - _updateCards(); - } - - void onOrderChanged(int from, int to) { - if (_favorite) { - favoriteCardsOrder.move(from, to); - } else { - allCardsOrder.move(from, to); - } - _saveCardsOrder(); - _updateCards(); - } - - void setFavorite(bool favorite) { - _favorite = favorite; - _updateCards(); - notifyListeners(); - } - - void _addToStream() { - _streamController.add(state); - } - - double get offset => _cardsScrollController.offset; - - int get offsetCards => (_cardsScrollController.offset / imageWidth).floor(); - - void toggleExpanded() => setExpanded(!_expanded); - - CardsViewController(this.cardPack, {bool expanded = false}) { - _expanded = expanded; - addListener(_addToStream); - _loadCardsOrder(); - _updateCards(); - } - - void _updateCards() { - cards = _filterPackCards(); - cards - ..sort((p, n) { - final pIndex = cardsOrder.indexOf(p.id); - final nIndex = cardsOrder.indexOf(n.id); - if (pIndex == -1) { - return nIndex == -1 ? p.id.compareTo(n.id) : 1; - } else if (nIndex == -1) { - return -1; - } - return pIndex.compareTo(nIndex); - }); - notifyListeners(); - } - - Future animateTo(int index) { - final millis = - ((_cardsScrollController.offset / imageWidth - index).abs() * 30.0) - .ceil(); - return _cardsScrollController.animateTo( - imageWidth * index, - duration: Duration(milliseconds: max(millis, 100)), - curve: Curves.easeInOut, - ); - } - - void jumpTo(int index) { - return _cardsScrollController.jumpTo( - imageWidth * index, - ); - } -} - -class CardsViewState { - final bool expanded; - final bool favorite; - final List packCards; - - CardsViewState({ - required this.expanded, - required this.favorite, - required this.packCards, - }); - - @override - int get hashCode => expanded.hashCode ^ expanded.hashCode ^ packCards.length; - - @override - bool operator ==(Object other) { - return (other is CardsViewState) && - expanded == other.expanded && - favorite == other.favorite && - (packCards.length == other.packCards.length) && - packCards.indexed.every((p) => other.packCards[p.$1].id == p.$2.id); - } -} diff --git a/mnemo_cards/lib/widgets/card_pack/error_loading_pack.dart b/mnemo_cards/lib/widgets/card_pack/error_loading_pack.dart deleted file mode 100644 index a30e3a9..0000000 --- a/mnemo_cards/lib/widgets/card_pack/error_loading_pack.dart +++ /dev/null @@ -1,59 +0,0 @@ -import 'dart:convert'; - -import 'package:flutter/material.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_screenutil/flutter_screenutil.dart'; -import 'package:mnemo_cards_common/mnemo_cards_common.dart'; -import 'package:mnemo_cards_frontend_common/mnemo_cards_frontend_common.dart'; - -import '../../di/locator.dart'; -import '../../utils/string_helper.dart'; -import 'card_pack_header.dart'; - -class ErrorLoading extends StatelessWidget { - final CardPackLoadingDto loadingDto; - - ErrorLoading(this.loadingDto); - - @override - Widget build(BuildContext context) { - final memoryImage = loadingDto.imageId?.let(locator.imagesHolder.get); - - return Column( - children: [ - CardPackHeader( - loadingDto.title, - loadingDto.subtitle, - loadingDto.color?.asColor, - ), - Expanded( - child: Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - if (memoryImage != null) - Container( - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(16.0), - ), - clipBehavior: Clip.antiAlias, - child: Image( - image: memoryImage, - width: 100, - ), - ), - if (loadingDto.message != null) - Padding( - padding: const EdgeInsets.only(top: 8.0), - child: Text(loadingDto.message!), - ), - SizedBox(height: 8.0.h), - ], - ), - ), - ), - BigBackButton(), - ], - ); - } -} diff --git a/mnemo_cards/lib/widgets/card_pack/heart_button.dart b/mnemo_cards/lib/widgets/card_pack/heart_button.dart deleted file mode 100644 index c9c1974..0000000 --- a/mnemo_cards/lib/widgets/card_pack/heart_button.dart +++ /dev/null @@ -1,10 +0,0 @@ -import 'package:flutter/cupertino.dart'; - -class HeartButton extends StatelessWidget { - @override - Widget build(BuildContext context) { - // TODO: implement build - throw UnimplementedError(); - } - -} \ No newline at end of file diff --git a/mnemo_cards/lib/widgets/card_pack/loading_pack.dart b/mnemo_cards/lib/widgets/card_pack/loading_pack.dart deleted file mode 100644 index 7e611a5..0000000 --- a/mnemo_cards/lib/widgets/card_pack/loading_pack.dart +++ /dev/null @@ -1,101 +0,0 @@ -import 'dart:convert'; - -import 'package:flutter/material.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_screenutil/flutter_screenutil.dart'; -import 'package:mnemo_cards_common/mnemo_cards_common.dart'; - -import '../../di/locator.dart'; -import '../../utils/string_helper.dart'; -import 'card_pack_header.dart'; - -class Loading extends StatelessWidget { - final CardPackLoadingDto? dto; - - const Loading(this.dto); - - @override - Widget build(BuildContext context) { - final loadingDto = dto; - if (loadingDto == null) { - return _empty(); - } - final memoryImage = loadingDto.imageId?.let(locator.imagesHolder.get); - return Column( - children: [ - if (dto != null) - CardPackHeader( - loadingDto.title, - loadingDto.subtitle, - loadingDto.color?.asColor, - ), - Expanded( - child: Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - if (memoryImage != null) - Container( - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(16.0), - ), - clipBehavior: Clip.antiAlias, - child: Image( - image: memoryImage, - width: 100, - ), - ), - if (loadingDto.message != null) - Padding( - padding: const EdgeInsets.only(top: 8.0), - child: Text(loadingDto.message!), - ), - SizedBox(height: 8.0.h), - SizedBox( - width: 100, - child: LinearProgressIndicator( - value: loadingDto.loadingProgress, - color: loadingDto.color?.asColor, - minHeight: 10.h, - backgroundColor: - loadingDto.color?.asColor?.withOpacity(0.15), - borderRadius: BorderRadius.circular(8.0), - ), - ), - ], - ), - ), - ), - ], - ); - } - - Widget _empty() { - return Column( - children: [ - CardPackHeader(null, null, null), - Expanded( - child: Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Padding( - padding: const EdgeInsets.only(top: 8.0), - child: Text('Загрузка...'), - ), - SizedBox(height: 8.0.h), - SizedBox( - width: 100, - child: LinearProgressIndicator( - minHeight: 10.h, - borderRadius: BorderRadius.circular(8.0), - ), - ), - ], - ), - ), - ), - ], - ); - } -} diff --git a/mnemo_cards/lib/widgets/choose_cards.dart b/mnemo_cards/lib/widgets/choose_cards.dart deleted file mode 100644 index 6ecb8ac..0000000 --- a/mnemo_cards/lib/widgets/choose_cards.dart +++ /dev/null @@ -1,145 +0,0 @@ -import 'dart:developer'; - -import 'package:collection/collection.dart'; -import 'package:flutter/cupertino.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_screenutil/flutter_screenutil.dart'; -import 'package:mnemo_cards/utils/string_helper.dart'; -import 'package:mnemo_cards/widgets/card_pack/cards_list.dart'; -import 'package:mnemo_cards_common/mnemo_cards_common.dart'; - -import '../di/locator.dart'; -import 'card_pack/cards_view.dart'; -import 'card_pack/cards_view_controller.dart'; - -class ChooseCards extends StatefulWidget { - final List _cardPacks; - - ChooseCards(this._cardPacks); - - @override - State createState() => ChooseCardsState(); -} - -class ChooseCardsState extends State { - late final List _cardControllers; - - @override - void initState() { - super.initState(); - _cardControllers = widget._cardPacks - .map( - (pack) => CardsViewController(pack, expanded: true), - ) - .toList(); - } - - @override - Widget build(BuildContext context) { - return FutureBuilder( - future: () async { - try { - final packs = await locator.packCacheManager.loadAllPacks( - withCardImages: true, - ); - print('Loaded ${packs.length} packs: ${packs}'); - return true; - } catch (e, s) { - log('Cant load packs', error: e, stackTrace: s); - } - }.call(), - builder: (context, snapshot) { - if (!snapshot.hasData) { - return const Center( - child: CircularProgressIndicator(), - ); - } - return Container( - child: ListView( - shrinkWrap: true, - children: [ - ..._cardControllers.mapIndexed((index, controller) { - final pack = controller.cardPack; - final color = controller.cardPack.color?.asColor; - return Container( - child: Column( - children: [ - Container( - height: 1, - color: color, - ), - DecoratedBox( - decoration: BoxDecoration( - color: color?.withOpacity(0.1), - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Padding( - padding: const EdgeInsets.only( - left: 12.0, - top: 8.0, - ).w, - child: _Title(controller.cardPack), - ), - CardsView( - controller, - color: color, - onCardTap: (cards, card) {}, - ), - ], - ), - ), - Container( - height: 1, - color: color, - ), - ], - ), - ); - }), - ], - ), - ); - }); - } -} - -class _Title extends StatelessWidget { - final CardPackDto pack; - - const _Title(this.pack); - - @override - Widget build(BuildContext context) { - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - FittedBox( - alignment: Alignment.centerLeft, - fit: BoxFit.scaleDown, - child: Text( - pack.title, - style: TextStyle( - fontWeight: FontWeight.w700, - fontSize: 24.sp, - height: 0.9, - ), - ), - ), - if (pack.subtitle.isNotEmpty) - FittedBox( - alignment: Alignment.centerLeft, - fit: BoxFit.scaleDown, - child: Text( - pack.subtitle, - style: TextStyle( - fontWeight: FontWeight.w300, - fontSize: 16.sp, - ), - ), - ), - ], - ); - } -} diff --git a/mnemo_cards/lib/widgets/enter_promo_code_widget.dart b/mnemo_cards/lib/widgets/enter_promo_code_widget.dart deleted file mode 100644 index 302493c..0000000 --- a/mnemo_cards/lib/widgets/enter_promo_code_widget.dart +++ /dev/null @@ -1,19 +0,0 @@ -import 'package:flutter/cupertino.dart'; -import 'package:mnemo_cards_frontend_common/mnemo_cards_frontend_common.dart'; - -import '../di/locator.dart'; - -class MobileEnterPromoCodeWidget extends StatelessWidget { - - @override - Widget build(BuildContext context) { - return EnterPromoCodeWidget(onApplyPromoCode: onApplyPromoCode); - } - - Future<(bool, String?)> onApplyPromoCode(String code) async { - final result = await locator.userManager.applyPromocode(code); - return (result.success ?? false, result.message); - } - - const MobileEnterPromoCodeWidget(); -} \ No newline at end of file diff --git a/mnemo_cards/lib/widgets/game_card_widget.dart b/mnemo_cards/lib/widgets/game_card_widget.dart deleted file mode 100644 index eeb9685..0000000 --- a/mnemo_cards/lib/widgets/game_card_widget.dart +++ /dev/null @@ -1,397 +0,0 @@ -import 'dart:math'; -import 'dart:typed_data'; - -import 'package:flutter/material.dart'; -import 'package:flutter_screenutil/flutter_screenutil.dart'; -import 'package:mnemo_cards/di/locator.dart'; -import 'package:mnemo_cards/managers/audio_player.dart'; -import 'package:mnemo_cards/utils/color_helper.dart'; -import 'package:mnemo_cards_common/mnemo_cards_common.dart'; -import 'package:mnemo_cards_frontend_common/mnemo_cards_frontend_common.dart'; -import 'package:universal_image/universal_image.dart'; - -import '../features/card_flipper/flip_card.dart'; -import '../features/card_flipper/flip_card_controllers.dart'; -import '../features/card_flipper/flip_side.dart'; -import '../theme/themes.dart'; - -class GameCardWidget extends StatefulWidget { - static const borderRadius = 32.0; - - final GameCardDto card; - final MemoryImage? image; - final bool showFront; - final bool isFirstCard; - final FlipCardController? flipCardController; - final Color? backColor; - - const GameCardWidget( - this.card, - this.image, - this.flipCardController, - this.showFront, - this.isFirstCard, - this.backColor, { - super.key, - }); - - @override - State createState() => _GameCardWidgetState(); -} - -class GameCardDecoration extends StatelessWidget { - final Widget child; - final double alpha; - final Color? borderColor; - - GameCardDecoration({required this.child, this.alpha = 1.0, this.borderColor}); - - @override - Widget build(BuildContext context) => Container( - padding: EdgeInsets.all(8.0 * alpha), - margin: EdgeInsets.only( - left: 10.0 * alpha, - right: 10.0 * alpha, - bottom: 2.0 * alpha, - top: 0.0 * alpha, - ), - decoration: BoxDecoration( - // color: Theme.of(context).scaffoldBackgroundColor, - color: Theme.of(context).scaffoldBackgroundColor.lighten(0.05), - // .withOpacity(alpha), - boxShadow: [ - BoxShadow( - color: Theme.of( - context, - ).colorScheme.primary.withOpacity(0.25 * alpha), - blurRadius: 4.0 * alpha, - ), - ], - borderRadius: BorderRadius.circular( - 12 + (GameCardWidget.borderRadius - 12) * alpha, - ), - border: Border.all( - color: (borderColor ?? borderGray).withOpacity( - Theme.of(context).brightness == Brightness.dark - ? 1.0 - : 1.0 - alpha * alpha, - ), - ), - ), - child: ClipRRect( - borderRadius: BorderRadius.circular( - 8 + (GameCardWidget.borderRadius - 8) * alpha, - ), - child: child, - ), - ); -} - -class _GameCardWidgetState extends State { - FlipCardController? get _flipCardController => widget.flipCardController; - - @override - Widget build(BuildContext context) { - final theme = Theme.of(context).textTheme; - print('${widget.card.original}'); - - final frontWidget = FrontCard(widget.card, widget.image); - final backWidget = _BackWidget(widget.card, widget.backColor); - Duration? dragStart; - Duration? dragUpdate; - - return GameCardDecoration( - child: Material( - color: Colors.transparent, - child: GestureDetector( - onVerticalDragStart: (start) { - dragStart = start.sourceTimeStamp; - }, - onVerticalDragUpdate: (update) { - dragUpdate = update.sourceTimeStamp; - }, - onVerticalDragEnd: (update) { - final pps = update.velocity.pixelsPerSecond; - if (widget.isFirstCard && - pps.dy.abs() > 2 * pps.dx.abs() && - pps.dy.abs() > 70 && - (dragStart != null && - dragUpdate != null && - (dragUpdate!.inMilliseconds - dragStart!.inMilliseconds) > - 50)) { - _flipCardController?.flipcard(); - } - }, - behavior: HitTestBehavior.deferToChild, - onDoubleTap: () { - _flipCardController?.flipcard(); - }, - onLongPress: () { - locator.favoriteCardsController.switchFavoriteCard(widget.card); - }, - child: (widget.isFirstCard) - ? FlipCard( - rotateSide: RotateSide.left, - onTapFlipping: false, - axis: FlipAxis.horizontal, - controller: _flipCardController!, - frontWidget: frontWidget, - backWidget: backWidget, - ) - : widget.showFront - ? frontWidget - : backWidget, - ), - ), - ); - } -} - -class _BackWidget extends StatelessWidget { - final GameCardDto card; - final Color? _backColor; - - const _BackWidget(this.card, this._backColor); - - @override - Widget build(BuildContext context) { - final theme = Theme.of(context).textTheme; - final backColor = _backColor ?? Colors.lightBlueAccent[200]; - return Container( - padding: const EdgeInsets.all(8.0), - decoration: BoxDecoration( - color: backColor, - boxShadow: const [BoxShadow()], - borderRadius: BorderRadius.circular(32.0), - ), - child: Center( - child: MnemoText( - card.back?.isNotEmpty == true ? card.back : card.translation ?? '', - textStyle: theme.displayMedium!.copyWith(color: Colors.white), - maxLines: 2, - softWrap: true, - ), - ), - ); - } -} - -class FrontCard extends StatelessWidget { - final GameCardDto card; - final MemoryImage? image; - final double alpha; - - FrontCard(this.card, this.image, {super.key, this.alpha = 1.0}); - - @override - Widget build(BuildContext context) { - final theme = Theme.of(context).textTheme; - return StatefulBuilder( - builder: (context, setState) { - return AbsorbPointer( - absorbing: alpha != 1, - child: LayoutBuilder( - builder: (context, constrains) { - const targetTextAr = 10 / 9; - const targetImageAr = 16 / 9; - double ar = constrains.maxHeight / constrains.maxWidth; - if (constrains.maxHeight.isInfinite) { - ar = 16 / 9; - } - final textScale = min(1.0, ar / targetTextAr) * alpha * alpha; - final imageScale = - 0.9 * min(1.0, pow(ar / targetImageAr, 1.5 * alpha)); - return Material( - borderOnForeground: false, - type: MaterialType.transparency, - child: Stack( - alignment: Alignment.center, - children: [ - Padding( - padding: EdgeInsets.all( - 8.0 * imageScale * (alpha / 2 + 0.5), - ), - child: Column( - mainAxisSize: MainAxisSize.max, - mainAxisAlignment: ar > 1 - ? MainAxisAlignment.spaceEvenly - : MainAxisAlignment.spaceAround, - children: [ - Column( - children: [ - GestureDetector( - child: MnemoText( - card.original ?? '', - textStyle: TextStyle( - fontSize: 15 * textScale + 12, - fontWeight: FontWeight.w600, - ), - maxLines: 1, - ), - onTap: () async { - if (card.original != null) { - AudioPlayer.playAudio( - card.original!, - lang: 'es-ES', - ); - } - }, - ), - GestureDetector( - onTap: () async { - if (card.translation != null) { - if (card.original != null) { - AudioPlayer.playAudio( - card.translation!, - lang: 'ru', - ); - } - } - }, - child: MnemoText( - card.translation, - textStyle: TextStyle( - fontSize: 12 * textScale * alpha + 8, - fontWeight: FontWeight.w700, - color: theme.headlineSmall!.color! - .withOpacity(0.5), - ), - maxLines: null, - ), - ), - if (alpha > 0 && - ar > 1 && - card.transcription != null && - card.transcriptionMnemo != null) - Padding( - padding: EdgeInsets.only(top: 4.0.h * alpha), - child: GestureDetector( - onTap: () async { - if (card.transcription != null && - card.transcriptionMnemo != null) { - AudioPlayer.playAudio( - '${card.transcription} - ${card.transcriptionMnemo}', - lang: 'ru', - ); - } - }, - child: MnemoText( - "[${card.transcription}] - ${card.transcriptionMnemo}", - textStyle: TextStyle( - fontSize: 20 * textScale * alpha, - fontWeight: FontWeight.w700, - ), - textAlign: TextAlign.center, - maxLines: 2, - // group: smallSize, - ), - ), - ), - ], - ), - Container( - width: constrains.maxHeight / ar * imageScale, - height: constrains.maxHeight / ar * imageScale, - clipBehavior: Clip.antiAlias, - decoration: BoxDecoration( - borderRadius: BorderRadius.circular( - GameCardWidget.borderRadius * - imageScale * - imageScale * - imageScale, - ), - ), - child: Image( - key: ValueKey(card.id), - image: image!, - gaplessPlayback: true, - filterQuality: FilterQuality.none, - // fix for elapsedInSeconds < 0 in debug mode - // syncDuration: Duration.zero, - ), - ), - GestureDetector( - onTap: () async { - if (card.mnemo?.trim().isNotEmpty != true) { - return; - } - AudioPlayer.playAudio( - card.mnemo!.replaceAll(RegExp(r'[\]\[]'), ''), - lang: 'ru', - ); - }, - child: MnemoText( - card.mnemo?.isNotEmpty == true - ? card.mnemo - : ' ', - textStyle: TextStyle( - fontSize: 20 * textScale, - fontWeight: FontWeight.w700, - ), - ), - ), - ], - ), - ), - if (alpha > 0) - Align( - alignment: ar > 4 / 3 - ? Alignment.bottomCenter - : Alignment.topCenter, - child: Text( - "mnemo cards", - style: TextStyle( - fontSize: 10 * textScale, - color: Colors.grey[400], - ), - maxLines: 1, - // group: smallSize, - ), - ), - if (false && - alpha > 0 && - locator.favoriteCardsController.isFavoriteCard(card.id)) - Align( - alignment: ar > 4 / 3 - ? Alignment.bottomLeft - : Alignment.topLeft, - child: Padding( - padding: EdgeInsets.all(8.0.w), - child: Image.asset( - "icons/heart.webp", - width: 8.w, - height: 8.h, - ), - ), - ), - if (alpha > 0 && AudioPlayer.soundOn) - Opacity( - opacity: alpha, - child: Container( - padding: EdgeInsets.all(4.0.h * alpha), - alignment: Alignment.topRight, - child: IconButton( - icon: Image.asset( - 'icons/sound_on.webp', - width: 24 * textScale, - color: Theme.of(context).colorScheme.primary, - ), - onPressed: () async { - AudioPlayer.playAudio( - card.original, - lang: 'es-ES', - ); - }, - ), - ), - ), - ], - ), - ); - }, - ), - ); - }, - ); - } -} diff --git a/mnemo_cards/lib/widgets/pack_button.dart b/mnemo_cards/lib/widgets/pack_button.dart deleted file mode 100644 index 35801b7..0000000 --- a/mnemo_cards/lib/widgets/pack_button.dart +++ /dev/null @@ -1,266 +0,0 @@ -import 'dart:convert'; -import 'dart:math' as math; - -import 'package:auto_route/auto_route.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:flutter_screenutil/flutter_screenutil.dart'; -import 'package:mnemo_cards/utils/string_helper.dart'; -import 'package:mnemo_cards_common/mnemo_cards_common.dart'; - -import '../di/locator.dart'; -import '../domain/router/app_router.gr.dart'; -import '../features/packs/packs_holder.dart'; -import '../main.dart'; - -class PackButton extends StatelessWidget { - final CardPackPreviewDto pack; - final double cardHeight; - - const PackButton( - this.pack, - this.cardHeight, - ); - - @override - Widget build(BuildContext context) { - final theme = Theme.of(context); - - return GestureDetector( - key: ValueKey(pack.hashCode), - onTap: _openPack, - child: Container( - margin: EdgeInsets.all(4.0.h), - alignment: Alignment.center, - height: cardHeight, - decoration: BoxDecoration( - color: pack.color?.asColor?.withOpacity(0.0), - border: Border.all( - color: pack.color?.asColor?.withOpacity(0.9) ?? - Colors.grey.withOpacity(0.5), - width: 1, - ), - borderRadius: BorderRadius.circular(12.0), - ), - clipBehavior: Clip.antiAliasWithSaveLayer, - child: Row( - mainAxisSize: MainAxisSize.max, - children: [ - Container( - decoration: BoxDecoration( - image: pack.imageBase64 == null - ? null - : DecorationImage( - image: locator.imagesHolder.get('pack_${pack.id}') ?? - MemoryImage(base64Decode(pack.imageBase64!)), - ), - borderRadius: BorderRadius.circular(11), - ), - width: cardHeight - 2.h, - height: cardHeight - 2.h, - ), - SizedBox(width: 4.w,), - Expanded( - child: Padding( - padding: const EdgeInsets.all(8.0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - FittedBox( - fit: BoxFit.scaleDown, - child: Text( - pack.title, - style: TextStyle( - fontWeight: FontWeight.w700, - fontSize: 24.sp, - height: 0.9, - ), - ), - ), - if (pack.subtitle != null && pack.subtitle!.isNotEmpty) - FittedBox( - fit: BoxFit.scaleDown, - child: Text( - pack.subtitle!, - style: TextStyle( - fontWeight: FontWeight.w300, - fontSize: 16.sp, - ), - ), - ), - Spacer(), - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Expanded( - child: Row( - children: [ - Text( - pack.cards.toString(), - style: TextStyle( - fontWeight: FontWeight.w200, - fontSize: 15.sp, - ), - ), - Image.asset( - 'icons/cards.webp', - width: 18.w, - height: 16.h, - color: Theme.of(context).colorScheme.primary, - ) - ], - ), - ), - if (pack.isAvailable && - (pack.tip?.position == PackTipPosition.fullRight || - pack.tip?.position == - PackTipPosition.bottomRight)) - _PackIsLoadingIndicator(pack) - ], - ) - ], - ), - ), - ), - Stack( - children: [ - if (pack.tip != null) - _PackTip( - pack.tip!, - pack.color?.asColor, - cardHeight, - ), - if (pack.isAvailable && - (pack.tip == null || - pack.tip!.position == PackTipPosition.topRight)) - _PackIsLoadingIndicator(pack) - ], - ), - ], - ), - ), - ); - } - - void _openPack() => appRouter.push( - PageRouteInfo( - CardPackPage.name, - args: CardPackPageArgs( - previewDto: pack, - ), - ), - ); -} - -class _PackIsLoadingIndicator extends StatelessWidget { - final CardPackPreviewDto pack; - - _PackIsLoadingIndicator(this.pack); - - @override - Widget build(BuildContext context) { - return BlocBuilder>( - bloc: locator.packsHolder, - // buildWhen: (p, n) => p[pack.id] != n[pack.id], - builder: (context, updaterState) { - final packState = updaterState[pack.id]; - final loadingDto = packState.tryAs(); - - if (packState is CardPackDto) { - return const SizedBox.shrink(); - } - - return Align( - alignment: Alignment.bottomCenter, - child: Container( - width: 40, - height: 40, - alignment: Alignment.center, - child: SizedBox( - width: 16.w, - height: 16.w, - child: loadingDto?.let( - (loading) => CircularProgressIndicator( - backgroundColor: loading.loadingProgress == null - ? Colors.transparent - : pack.color?.asColor?.withOpacity(0.1), - strokeWidth: 3, - strokeCap: StrokeCap.round, - color: pack.color?.asColor ?? Colors.black, - value: loading.loadingProgress, - ), - ) ?? - GestureDetector( - onTap: () { - locator.packUpdater.updatePackAndSaveImages( - pack.id, - shouldUpdateHolder: true, - ); - }, - child: Image.asset( - 'icons/download.webp', - width: 16.w, - height: 16.w, - color: pack.color?.asColor ?? Colors.black, - ), - ), - ), - ), - ); - }, - ); - } -} - -class _PackTip extends StatelessWidget { - final PackTip tip; - final Color? color; - final double cardHeight; - - _PackTip(this.tip, this.color, this.cardHeight); - - late final double _height = switch (tip.position) { - PackTipPosition.topRight => math.max(cardHeight / 2.5, 40), - PackTipPosition.bottomRight => math.max(cardHeight / 2.5, 40), - PackTipPosition.fullRight => cardHeight, - PackTipPosition.unknown => 0, - }; - - late final _alignment = switch (tip.position) { - PackTipPosition.topRight => Alignment.topCenter, - PackTipPosition.bottomRight => Alignment.bottomCenter, - PackTipPosition.fullRight => Alignment.center, - PackTipPosition.unknown => Alignment.center, - }; - - late final _borderRadius = switch (tip.position) { - PackTipPosition.topRight => BorderRadius.only( - bottomLeft: Radius.circular(12.0), - ), - PackTipPosition.bottomRight => BorderRadius.only( - topLeft: Radius.circular(12.0), - ), - PackTipPosition.fullRight => BorderRadius.zero, - PackTipPosition.unknown => BorderRadius.zero, - }; - - @override - Widget build(BuildContext context) { - return Align( - alignment: _alignment, - child: Container( - width: 40, - height: _height, - alignment: Alignment.center, - decoration: BoxDecoration( - color: tip.bgColor?.asColor ?? - color?.withOpacity(0.4) ?? - Colors.transparent, - borderRadius: _borderRadius, - ), - child: tip.build(context), - ), - ); - } -} diff --git a/mnemo_cards/lib/widgets/packs_menu_widget.dart b/mnemo_cards/lib/widgets/packs_menu_widget.dart deleted file mode 100644 index fb56215..0000000 --- a/mnemo_cards/lib/widgets/packs_menu_widget.dart +++ /dev/null @@ -1,139 +0,0 @@ -import 'dart:convert'; -import 'dart:developer'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_screenutil/flutter_screenutil.dart'; -import 'package:mnemo_cards/features/packs/pack_manager.dart'; -import 'package:mnemo_cards/utils/string_helper.dart'; -import 'package:mnemo_cards_common/mnemo_cards_common.dart'; - -import '../di/locator.dart'; -import '../managers/repository/repository.dart'; -import 'package:collection/collection.dart'; - -import 'pack_button.dart'; - -class PacksMenuWidget extends StatefulWidget { - final Repository repository; - final PackManager packManager; - final ScrollController? scrollController; - - const PacksMenuWidget( - this.repository, - this.packManager, { - this.scrollController, - super.key, - }); - - @override - State createState() => _PacksMenuWidgetState(); -} - -class _PacksMenuWidgetState extends State { - @override - Widget build(BuildContext context) { - final cardHeight = 110.h; - bool isFirstElement = true; - final theme = Theme.of(context); - return Column( - children: [ - StreamBuilder( - stream: widget.packManager.packsPreviewStream.asyncMap((packs) async { - if (packs != null) { - if (isFirstElement) { - isFirstElement = false; - _precache(packs); - } else { - await _precache(packs); - } - } - return packs; - }), - builder: (context, snapshot) { - return Expanded( - child: Padding( - padding: EdgeInsets.all(8.0.w), - child: RefreshIndicator( - onRefresh: locator.previewPackPoller.poll, - backgroundColor: theme.colorScheme.primary, - displacement: 20.h, - color: snapshot.data?.firstOrNull?.color?.asColor ?? - Colors.black, - child: (!snapshot.hasData) - ? Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Padding( - padding: const EdgeInsets.all(8.0), - child: Image.asset( - Theme.of(context).brightness == - Brightness.dark - ? 'images/luna.webp' - : 'images/cerdo.webp', - width: 100, - ), - ), - Text('Загрузка...'), - ], - ), - ) - : ListView( - physics: BouncingScrollPhysics( - decelerationRate: ScrollDecelerationRate.fast, - parent: AlwaysScrollableScrollPhysics(), - ), - scrollDirection: Axis.vertical, - children: snapshot.requireData! - .map( - (pack) => PackButton( - pack, - cardHeight, - ), - ) - .toList(), - ), - ), - ), - ); - }, - ), - ], - ); - } - - Future _precache(List packs) async { - for (final pack in packs) { - if (pack.imageBase64 != null) { - try { - final packImageId = 'pack_${pack.id}'; - // - if (locator.imagesHolder.havePackImage(packImageId)) { - _decodeImage(pack, packImageId).then((image) { - locator.imagesHolder.setImage(packImageId, image); - precacheImage(image, context); - }); - final image = locator.imagesHolder.getPackImage(packImageId)!; - await precacheImage(image, context); - } else { - final image = await _decodeImage(pack, packImageId); - locator.imagesHolder.setImage(packImageId, image); - await precacheImage(image, context); - } - } catch (e) { - log('${pack.id} cover not cached'); - } - } - } - } - - Future _decodeImage( - CardPackPreviewDto pack, - String packImageId, - ) async { - final bytes = await compute(base64Decode, pack.imageBase64!); - final image = MemoryImage(bytes); - return image; - } -} diff --git a/mnemo_cards/lib/widgets/shared_pref_button.dart b/mnemo_cards/lib/widgets/shared_pref_button.dart deleted file mode 100644 index 1e0ff86..0000000 --- a/mnemo_cards/lib/widgets/shared_pref_button.dart +++ /dev/null @@ -1,41 +0,0 @@ -import 'dart:async'; - -import 'package:flutter/cupertino.dart'; -import 'package:mnemo_cards/main.dart'; -import 'package:mnemo_cards_common/mnemo_cards_common.dart'; -import 'package:mnemo_cards_frontend_common/mnemo_cards_frontend_common.dart'; -import 'package:shared_preferences/shared_preferences.dart'; - -class MobileSharedPrefButton extends StatelessWidget { - final Function(T)? onClick; - final String spKey; - final T Function(T? current)? setOnTap; - final bool Function(T? current)? shouldRebuild; - final Widget Function(T? value, ValueSetter setValue)? builder; - - MobileSharedPrefButton({ - this.builder, - required this.spKey, - this.setOnTap, - this.onClick, - this.shouldRebuild, - }); - - MobileSharedPrefButton.builder({ - this.builder, - required this.spKey, - this.setOnTap, - this.onClick, - this.shouldRebuild, - }); - - @override - Widget build(BuildContext context) => SharedPrefButton( - sharedPreferences: globalSharedPreferences, - spKey: spKey, - setOnTap: setOnTap, - onClick: onClick, - shouldRebuild: shouldRebuild, - builder: builder, - ); -} diff --git a/mnemo_cards/macos/.gitignore b/mnemo_cards/macos/.gitignore deleted file mode 100644 index 746adbb..0000000 --- a/mnemo_cards/macos/.gitignore +++ /dev/null @@ -1,7 +0,0 @@ -# Flutter-related -**/Flutter/ephemeral/ -**/Pods/ - -# Xcode-related -**/dgph -**/xcuserdata/ diff --git a/mnemo_cards/macos/Flutter/Flutter-Debug.xcconfig b/mnemo_cards/macos/Flutter/Flutter-Debug.xcconfig deleted file mode 100644 index 4b81f9b..0000000 --- a/mnemo_cards/macos/Flutter/Flutter-Debug.xcconfig +++ /dev/null @@ -1,2 +0,0 @@ -#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" -#include "ephemeral/Flutter-Generated.xcconfig" diff --git a/mnemo_cards/macos/Flutter/Flutter-Release.xcconfig b/mnemo_cards/macos/Flutter/Flutter-Release.xcconfig deleted file mode 100644 index 5caa9d1..0000000 --- a/mnemo_cards/macos/Flutter/Flutter-Release.xcconfig +++ /dev/null @@ -1,2 +0,0 @@ -#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" -#include "ephemeral/Flutter-Generated.xcconfig" diff --git a/mnemo_cards/macos/Flutter/GeneratedPluginRegistrant.swift b/mnemo_cards/macos/Flutter/GeneratedPluginRegistrant.swift deleted file mode 100644 index 6e56055..0000000 --- a/mnemo_cards/macos/Flutter/GeneratedPluginRegistrant.swift +++ /dev/null @@ -1,52 +0,0 @@ -// -// Generated file. Do not edit. -// - -import FlutterMacOS -import Foundation - -import app_links -import cloud_firestore -import device_info_plus -import file_picker -import firebase_analytics -import firebase_core -import firebase_crashlytics -import firebase_messaging -import firebase_remote_config -import flutter_local_notifications -import flutter_secure_storage_macos -import flutter_tts -import google_sign_in_ios -import in_app_purchase_storekit -import no_screenshot -import package_info_plus -import path_provider_foundation -import patrol -import shared_preferences_foundation -import url_launcher_macos -import webview_flutter_wkwebview - -func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { - AppLinksMacosPlugin.register(with: registry.registrar(forPlugin: "AppLinksMacosPlugin")) - FLTFirebaseFirestorePlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseFirestorePlugin")) - DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin")) - FilePickerPlugin.register(with: registry.registrar(forPlugin: "FilePickerPlugin")) - FirebaseAnalyticsPlugin.register(with: registry.registrar(forPlugin: "FirebaseAnalyticsPlugin")) - FLTFirebaseCorePlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseCorePlugin")) - FLTFirebaseCrashlyticsPlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseCrashlyticsPlugin")) - FLTFirebaseMessagingPlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseMessagingPlugin")) - FLTFirebaseRemoteConfigPlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseRemoteConfigPlugin")) - FlutterLocalNotificationsPlugin.register(with: registry.registrar(forPlugin: "FlutterLocalNotificationsPlugin")) - FlutterSecureStoragePlugin.register(with: registry.registrar(forPlugin: "FlutterSecureStoragePlugin")) - FlutterTtsPlugin.register(with: registry.registrar(forPlugin: "FlutterTtsPlugin")) - FLTGoogleSignInPlugin.register(with: registry.registrar(forPlugin: "FLTGoogleSignInPlugin")) - InAppPurchasePlugin.register(with: registry.registrar(forPlugin: "InAppPurchasePlugin")) - NoScreenshotPlugin.register(with: registry.registrar(forPlugin: "NoScreenshotPlugin")) - FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin")) - PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) - PatrolPlugin.register(with: registry.registrar(forPlugin: "PatrolPlugin")) - SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) - UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin")) - WebViewFlutterPlugin.register(with: registry.registrar(forPlugin: "WebViewFlutterPlugin")) -} diff --git a/mnemo_cards/macos/Podfile b/mnemo_cards/macos/Podfile deleted file mode 100644 index b52666a..0000000 --- a/mnemo_cards/macos/Podfile +++ /dev/null @@ -1,43 +0,0 @@ -platform :osx, '10.15' - -# CocoaPods analytics sends network stats synchronously affecting flutter build latency. -ENV['COCOAPODS_DISABLE_STATS'] = 'true' - -project 'Runner', { - 'Debug' => :debug, - 'Profile' => :release, - 'Release' => :release, -} - -def flutter_root - generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'ephemeral', 'Flutter-Generated.xcconfig'), __FILE__) - unless File.exist?(generated_xcode_build_settings_path) - raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure \"flutter pub get\" is executed first" - end - - File.foreach(generated_xcode_build_settings_path) do |line| - matches = line.match(/FLUTTER_ROOT\=(.*)/) - return matches[1].strip if matches - end - raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Flutter-Generated.xcconfig, then run \"flutter pub get\"" -end - -require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) - -flutter_macos_podfile_setup - -target 'Runner' do - use_frameworks! - use_modular_headers! - - flutter_install_all_macos_pods File.dirname(File.realpath(__FILE__)) - target 'RunnerTests' do - inherit! :search_paths - end -end - -post_install do |installer| - installer.pods_project.targets.each do |target| - flutter_additional_macos_build_settings(target) - end -end diff --git a/mnemo_cards/macos/Podfile.lock b/mnemo_cards/macos/Podfile.lock deleted file mode 100644 index 3400980..0000000 --- a/mnemo_cards/macos/Podfile.lock +++ /dev/null @@ -1,1614 +0,0 @@ -PODS: - - abseil/algorithm (1.20240116.2): - - abseil/algorithm/algorithm (= 1.20240116.2) - - abseil/algorithm/container (= 1.20240116.2) - - abseil/algorithm/algorithm (1.20240116.2): - - abseil/base/config - - abseil/xcprivacy - - abseil/algorithm/container (1.20240116.2): - - abseil/algorithm/algorithm - - abseil/base/core_headers - - abseil/base/nullability - - abseil/meta/type_traits - - abseil/xcprivacy - - abseil/base (1.20240116.2): - - abseil/base/atomic_hook (= 1.20240116.2) - - abseil/base/base (= 1.20240116.2) - - abseil/base/base_internal (= 1.20240116.2) - - abseil/base/config (= 1.20240116.2) - - abseil/base/core_headers (= 1.20240116.2) - - abseil/base/cycleclock_internal (= 1.20240116.2) - - abseil/base/dynamic_annotations (= 1.20240116.2) - - abseil/base/endian (= 1.20240116.2) - - abseil/base/errno_saver (= 1.20240116.2) - - abseil/base/fast_type_id (= 1.20240116.2) - - abseil/base/log_severity (= 1.20240116.2) - - abseil/base/malloc_internal (= 1.20240116.2) - - abseil/base/no_destructor (= 1.20240116.2) - - abseil/base/nullability (= 1.20240116.2) - - abseil/base/prefetch (= 1.20240116.2) - - abseil/base/pretty_function (= 1.20240116.2) - - abseil/base/raw_logging_internal (= 1.20240116.2) - - abseil/base/spinlock_wait (= 1.20240116.2) - - abseil/base/strerror (= 1.20240116.2) - - abseil/base/throw_delegate (= 1.20240116.2) - - abseil/base/atomic_hook (1.20240116.2): - - abseil/base/config - - abseil/base/core_headers - - abseil/xcprivacy - - abseil/base/base (1.20240116.2): - - abseil/base/atomic_hook - - abseil/base/base_internal - - abseil/base/config - - abseil/base/core_headers - - abseil/base/cycleclock_internal - - abseil/base/dynamic_annotations - - abseil/base/log_severity - - abseil/base/nullability - - abseil/base/raw_logging_internal - - abseil/base/spinlock_wait - - abseil/meta/type_traits - - abseil/xcprivacy - - abseil/base/base_internal (1.20240116.2): - - abseil/base/config - - abseil/meta/type_traits - - abseil/xcprivacy - - abseil/base/config (1.20240116.2): - - abseil/xcprivacy - - abseil/base/core_headers (1.20240116.2): - - abseil/base/config - - abseil/xcprivacy - - abseil/base/cycleclock_internal (1.20240116.2): - - abseil/base/base_internal - - abseil/base/config - - abseil/xcprivacy - - abseil/base/dynamic_annotations (1.20240116.2): - - abseil/base/config - - abseil/base/core_headers - - abseil/xcprivacy - - abseil/base/endian (1.20240116.2): - - abseil/base/base - - abseil/base/config - - abseil/base/core_headers - - abseil/base/nullability - - abseil/xcprivacy - - abseil/base/errno_saver (1.20240116.2): - - abseil/base/config - - abseil/xcprivacy - - abseil/base/fast_type_id (1.20240116.2): - - abseil/base/config - - abseil/xcprivacy - - abseil/base/log_severity (1.20240116.2): - - abseil/base/config - - abseil/base/core_headers - - abseil/xcprivacy - - abseil/base/malloc_internal (1.20240116.2): - - abseil/base/base - - abseil/base/base_internal - - abseil/base/config - - abseil/base/core_headers - - abseil/base/dynamic_annotations - - abseil/base/raw_logging_internal - - abseil/xcprivacy - - abseil/base/no_destructor (1.20240116.2): - - abseil/base/config - - abseil/xcprivacy - - abseil/base/nullability (1.20240116.2): - - abseil/base/core_headers - - abseil/meta/type_traits - - abseil/xcprivacy - - abseil/base/prefetch (1.20240116.2): - - abseil/base/config - - abseil/base/core_headers - - abseil/xcprivacy - - abseil/base/pretty_function (1.20240116.2): - - abseil/xcprivacy - - abseil/base/raw_logging_internal (1.20240116.2): - - abseil/base/atomic_hook - - abseil/base/config - - abseil/base/core_headers - - abseil/base/errno_saver - - abseil/base/log_severity - - abseil/xcprivacy - - abseil/base/spinlock_wait (1.20240116.2): - - abseil/base/base_internal - - abseil/base/core_headers - - abseil/base/errno_saver - - abseil/xcprivacy - - abseil/base/strerror (1.20240116.2): - - abseil/base/config - - abseil/base/core_headers - - abseil/base/errno_saver - - abseil/xcprivacy - - abseil/base/throw_delegate (1.20240116.2): - - abseil/base/config - - abseil/base/raw_logging_internal - - abseil/xcprivacy - - abseil/cleanup/cleanup (1.20240116.2): - - abseil/base/config - - abseil/base/core_headers - - abseil/cleanup/cleanup_internal - - abseil/xcprivacy - - abseil/cleanup/cleanup_internal (1.20240116.2): - - abseil/base/base_internal - - abseil/base/core_headers - - abseil/utility/utility - - abseil/xcprivacy - - abseil/container/common (1.20240116.2): - - abseil/meta/type_traits - - abseil/types/optional - - abseil/xcprivacy - - abseil/container/common_policy_traits (1.20240116.2): - - abseil/meta/type_traits - - abseil/xcprivacy - - abseil/container/compressed_tuple (1.20240116.2): - - abseil/utility/utility - - abseil/xcprivacy - - abseil/container/container_memory (1.20240116.2): - - abseil/base/config - - abseil/memory/memory - - abseil/meta/type_traits - - abseil/utility/utility - - abseil/xcprivacy - - abseil/container/fixed_array (1.20240116.2): - - abseil/algorithm/algorithm - - abseil/base/config - - abseil/base/core_headers - - abseil/base/dynamic_annotations - - abseil/base/throw_delegate - - abseil/container/compressed_tuple - - abseil/memory/memory - - abseil/xcprivacy - - abseil/container/flat_hash_map (1.20240116.2): - - abseil/algorithm/container - - abseil/base/core_headers - - abseil/container/container_memory - - abseil/container/hash_function_defaults - - abseil/container/raw_hash_map - - abseil/memory/memory - - abseil/xcprivacy - - abseil/container/flat_hash_set (1.20240116.2): - - abseil/algorithm/container - - abseil/base/core_headers - - abseil/container/container_memory - - abseil/container/hash_function_defaults - - abseil/container/raw_hash_set - - abseil/memory/memory - - abseil/xcprivacy - - abseil/container/hash_function_defaults (1.20240116.2): - - abseil/base/config - - abseil/hash/hash - - abseil/strings/cord - - abseil/strings/strings - - abseil/xcprivacy - - abseil/container/hash_policy_traits (1.20240116.2): - - abseil/container/common_policy_traits - - abseil/meta/type_traits - - abseil/xcprivacy - - abseil/container/hashtable_debug_hooks (1.20240116.2): - - abseil/base/config - - abseil/xcprivacy - - abseil/container/hashtablez_sampler (1.20240116.2): - - abseil/base/base - - abseil/base/config - - abseil/base/core_headers - - abseil/base/raw_logging_internal - - abseil/debugging/stacktrace - - abseil/memory/memory - - abseil/profiling/exponential_biased - - abseil/profiling/sample_recorder - - abseil/synchronization/synchronization - - abseil/time/time - - abseil/utility/utility - - abseil/xcprivacy - - abseil/container/inlined_vector (1.20240116.2): - - abseil/algorithm/algorithm - - abseil/base/core_headers - - abseil/base/throw_delegate - - abseil/container/inlined_vector_internal - - abseil/memory/memory - - abseil/meta/type_traits - - abseil/xcprivacy - - abseil/container/inlined_vector_internal (1.20240116.2): - - abseil/base/config - - abseil/base/core_headers - - abseil/container/compressed_tuple - - abseil/memory/memory - - abseil/meta/type_traits - - abseil/types/span - - abseil/xcprivacy - - abseil/container/layout (1.20240116.2): - - abseil/base/config - - abseil/base/core_headers - - abseil/debugging/demangle_internal - - abseil/meta/type_traits - - abseil/strings/strings - - abseil/types/span - - abseil/utility/utility - - abseil/xcprivacy - - abseil/container/raw_hash_map (1.20240116.2): - - abseil/base/config - - abseil/base/core_headers - - abseil/base/throw_delegate - - abseil/container/container_memory - - abseil/container/raw_hash_set - - abseil/xcprivacy - - abseil/container/raw_hash_set (1.20240116.2): - - abseil/base/config - - abseil/base/core_headers - - abseil/base/dynamic_annotations - - abseil/base/endian - - abseil/base/prefetch - - abseil/base/raw_logging_internal - - abseil/container/common - - abseil/container/compressed_tuple - - abseil/container/container_memory - - abseil/container/hash_policy_traits - - abseil/container/hashtable_debug_hooks - - abseil/container/hashtablez_sampler - - abseil/hash/hash - - abseil/memory/memory - - abseil/meta/type_traits - - abseil/numeric/bits - - abseil/utility/utility - - abseil/xcprivacy - - abseil/crc/cpu_detect (1.20240116.2): - - abseil/base/base - - abseil/base/config - - abseil/xcprivacy - - abseil/crc/crc32c (1.20240116.2): - - abseil/base/config - - abseil/base/core_headers - - abseil/base/endian - - abseil/base/prefetch - - abseil/crc/cpu_detect - - abseil/crc/crc_internal - - abseil/crc/non_temporal_memcpy - - abseil/strings/str_format - - abseil/strings/strings - - abseil/xcprivacy - - abseil/crc/crc_cord_state (1.20240116.2): - - abseil/base/config - - abseil/crc/crc32c - - abseil/numeric/bits - - abseil/strings/strings - - abseil/xcprivacy - - abseil/crc/crc_internal (1.20240116.2): - - abseil/base/config - - abseil/base/core_headers - - abseil/base/endian - - abseil/base/prefetch - - abseil/base/raw_logging_internal - - abseil/crc/cpu_detect - - abseil/memory/memory - - abseil/numeric/bits - - abseil/xcprivacy - - abseil/crc/non_temporal_arm_intrinsics (1.20240116.2): - - abseil/base/config - - abseil/xcprivacy - - abseil/crc/non_temporal_memcpy (1.20240116.2): - - abseil/base/config - - abseil/base/core_headers - - abseil/crc/non_temporal_arm_intrinsics - - abseil/xcprivacy - - abseil/debugging/debugging_internal (1.20240116.2): - - abseil/base/config - - abseil/base/core_headers - - abseil/base/dynamic_annotations - - abseil/base/errno_saver - - abseil/base/raw_logging_internal - - abseil/xcprivacy - - abseil/debugging/demangle_internal (1.20240116.2): - - abseil/base/base - - abseil/base/config - - abseil/base/core_headers - - abseil/xcprivacy - - abseil/debugging/examine_stack (1.20240116.2): - - abseil/base/config - - abseil/base/core_headers - - abseil/base/raw_logging_internal - - abseil/debugging/stacktrace - - abseil/debugging/symbolize - - abseil/xcprivacy - - abseil/debugging/stacktrace (1.20240116.2): - - abseil/base/config - - abseil/base/core_headers - - abseil/base/dynamic_annotations - - abseil/base/raw_logging_internal - - abseil/debugging/debugging_internal - - abseil/xcprivacy - - abseil/debugging/symbolize (1.20240116.2): - - abseil/base/base - - abseil/base/config - - abseil/base/core_headers - - abseil/base/dynamic_annotations - - abseil/base/malloc_internal - - abseil/base/raw_logging_internal - - abseil/debugging/debugging_internal - - abseil/debugging/demangle_internal - - abseil/strings/strings - - abseil/xcprivacy - - abseil/flags/commandlineflag (1.20240116.2): - - abseil/base/config - - abseil/base/fast_type_id - - abseil/flags/commandlineflag_internal - - abseil/strings/strings - - abseil/types/optional - - abseil/xcprivacy - - abseil/flags/commandlineflag_internal (1.20240116.2): - - abseil/base/config - - abseil/base/fast_type_id - - abseil/xcprivacy - - abseil/flags/config (1.20240116.2): - - abseil/base/config - - abseil/base/core_headers - - abseil/flags/path_util - - abseil/flags/program_name - - abseil/strings/strings - - abseil/synchronization/synchronization - - abseil/xcprivacy - - abseil/flags/flag (1.20240116.2): - - abseil/base/base - - abseil/base/config - - abseil/base/core_headers - - abseil/flags/config - - abseil/flags/flag_internal - - abseil/flags/reflection - - abseil/strings/strings - - abseil/xcprivacy - - abseil/flags/flag_internal (1.20240116.2): - - abseil/base/base - - abseil/base/config - - abseil/base/core_headers - - abseil/base/dynamic_annotations - - abseil/flags/commandlineflag - - abseil/flags/commandlineflag_internal - - abseil/flags/config - - abseil/flags/marshalling - - abseil/flags/reflection - - abseil/memory/memory - - abseil/meta/type_traits - - abseil/strings/strings - - abseil/synchronization/synchronization - - abseil/utility/utility - - abseil/xcprivacy - - abseil/flags/marshalling (1.20240116.2): - - abseil/base/config - - abseil/base/core_headers - - abseil/base/log_severity - - abseil/numeric/int128 - - abseil/strings/str_format - - abseil/strings/strings - - abseil/types/optional - - abseil/xcprivacy - - abseil/flags/path_util (1.20240116.2): - - abseil/base/config - - abseil/strings/strings - - abseil/xcprivacy - - abseil/flags/private_handle_accessor (1.20240116.2): - - abseil/base/config - - abseil/flags/commandlineflag - - abseil/flags/commandlineflag_internal - - abseil/strings/strings - - abseil/xcprivacy - - abseil/flags/program_name (1.20240116.2): - - abseil/base/config - - abseil/base/core_headers - - abseil/flags/path_util - - abseil/strings/strings - - abseil/synchronization/synchronization - - abseil/xcprivacy - - abseil/flags/reflection (1.20240116.2): - - abseil/base/config - - abseil/base/core_headers - - abseil/base/no_destructor - - abseil/container/flat_hash_map - - abseil/flags/commandlineflag - - abseil/flags/commandlineflag_internal - - abseil/flags/config - - abseil/flags/private_handle_accessor - - abseil/strings/strings - - abseil/synchronization/synchronization - - abseil/xcprivacy - - abseil/functional/any_invocable (1.20240116.2): - - abseil/base/base_internal - - abseil/base/config - - abseil/base/core_headers - - abseil/meta/type_traits - - abseil/utility/utility - - abseil/xcprivacy - - abseil/functional/bind_front (1.20240116.2): - - abseil/base/base_internal - - abseil/container/compressed_tuple - - abseil/meta/type_traits - - abseil/utility/utility - - abseil/xcprivacy - - abseil/functional/function_ref (1.20240116.2): - - abseil/base/base_internal - - abseil/base/core_headers - - abseil/functional/any_invocable - - abseil/meta/type_traits - - abseil/xcprivacy - - abseil/hash/city (1.20240116.2): - - abseil/base/config - - abseil/base/core_headers - - abseil/base/endian - - abseil/xcprivacy - - abseil/hash/hash (1.20240116.2): - - abseil/base/config - - abseil/base/core_headers - - abseil/base/endian - - abseil/container/fixed_array - - abseil/functional/function_ref - - abseil/hash/city - - abseil/hash/low_level_hash - - abseil/meta/type_traits - - abseil/numeric/bits - - abseil/numeric/int128 - - abseil/strings/strings - - abseil/types/optional - - abseil/types/variant - - abseil/utility/utility - - abseil/xcprivacy - - abseil/hash/low_level_hash (1.20240116.2): - - abseil/base/config - - abseil/base/endian - - abseil/base/prefetch - - abseil/numeric/int128 - - abseil/xcprivacy - - abseil/log/absl_check (1.20240116.2): - - abseil/log/internal/check_impl - - abseil/xcprivacy - - abseil/log/absl_log (1.20240116.2): - - abseil/log/internal/log_impl - - abseil/xcprivacy - - abseil/log/absl_vlog_is_on (1.20240116.2): - - abseil/base/config - - abseil/base/core_headers - - abseil/log/internal/vlog_config - - abseil/strings/strings - - abseil/xcprivacy - - abseil/log/check (1.20240116.2): - - abseil/log/internal/check_impl - - abseil/log/internal/check_op - - abseil/log/internal/conditions - - abseil/log/internal/log_message - - abseil/log/internal/strip - - abseil/xcprivacy - - abseil/log/globals (1.20240116.2): - - abseil/base/atomic_hook - - abseil/base/config - - abseil/base/core_headers - - abseil/base/log_severity - - abseil/base/raw_logging_internal - - abseil/hash/hash - - abseil/log/internal/vlog_config - - abseil/strings/strings - - abseil/xcprivacy - - abseil/log/internal/append_truncated (1.20240116.2): - - abseil/base/config - - abseil/strings/strings - - abseil/types/span - - abseil/xcprivacy - - abseil/log/internal/check_impl (1.20240116.2): - - abseil/base/core_headers - - abseil/log/internal/check_op - - abseil/log/internal/conditions - - abseil/log/internal/log_message - - abseil/log/internal/strip - - abseil/xcprivacy - - abseil/log/internal/check_op (1.20240116.2): - - abseil/base/config - - abseil/base/core_headers - - abseil/log/internal/nullguard - - abseil/log/internal/nullstream - - abseil/log/internal/strip - - abseil/strings/strings - - abseil/xcprivacy - - abseil/log/internal/conditions (1.20240116.2): - - abseil/base/base - - abseil/base/config - - abseil/base/core_headers - - abseil/log/internal/voidify - - abseil/xcprivacy - - abseil/log/internal/config (1.20240116.2): - - abseil/base/config - - abseil/base/core_headers - - abseil/xcprivacy - - abseil/log/internal/fnmatch (1.20240116.2): - - abseil/base/config - - abseil/strings/strings - - abseil/xcprivacy - - abseil/log/internal/format (1.20240116.2): - - abseil/base/config - - abseil/base/core_headers - - abseil/base/log_severity - - abseil/log/internal/append_truncated - - abseil/log/internal/config - - abseil/log/internal/globals - - abseil/strings/str_format - - abseil/strings/strings - - abseil/time/time - - abseil/types/span - - abseil/xcprivacy - - abseil/log/internal/globals (1.20240116.2): - - abseil/base/config - - abseil/base/core_headers - - abseil/base/log_severity - - abseil/base/raw_logging_internal - - abseil/strings/strings - - abseil/time/time - - abseil/xcprivacy - - abseil/log/internal/log_impl (1.20240116.2): - - abseil/log/absl_vlog_is_on - - abseil/log/internal/conditions - - abseil/log/internal/log_message - - abseil/log/internal/strip - - abseil/xcprivacy - - abseil/log/internal/log_message (1.20240116.2): - - abseil/base/base - - abseil/base/config - - abseil/base/core_headers - - abseil/base/errno_saver - - abseil/base/log_severity - - abseil/base/raw_logging_internal - - abseil/base/strerror - - abseil/container/inlined_vector - - abseil/debugging/examine_stack - - abseil/log/globals - - abseil/log/internal/append_truncated - - abseil/log/internal/format - - abseil/log/internal/globals - - abseil/log/internal/log_sink_set - - abseil/log/internal/nullguard - - abseil/log/internal/proto - - abseil/log/log_entry - - abseil/log/log_sink - - abseil/log/log_sink_registry - - abseil/memory/memory - - abseil/strings/strings - - abseil/time/time - - abseil/types/span - - abseil/xcprivacy - - abseil/log/internal/log_sink_set (1.20240116.2): - - abseil/base/base - - abseil/base/config - - abseil/base/core_headers - - abseil/base/log_severity - - abseil/base/no_destructor - - abseil/base/raw_logging_internal - - abseil/cleanup/cleanup - - abseil/log/globals - - abseil/log/internal/config - - abseil/log/internal/globals - - abseil/log/log_entry - - abseil/log/log_sink - - abseil/strings/strings - - abseil/synchronization/synchronization - - abseil/types/span - - abseil/xcprivacy - - abseil/log/internal/nullguard (1.20240116.2): - - abseil/base/config - - abseil/base/core_headers - - abseil/xcprivacy - - abseil/log/internal/nullstream (1.20240116.2): - - abseil/base/config - - abseil/base/core_headers - - abseil/base/log_severity - - abseil/strings/strings - - abseil/xcprivacy - - abseil/log/internal/proto (1.20240116.2): - - abseil/base/base - - abseil/base/config - - abseil/base/core_headers - - abseil/strings/strings - - abseil/types/span - - abseil/xcprivacy - - abseil/log/internal/strip (1.20240116.2): - - abseil/base/log_severity - - abseil/log/internal/log_message - - abseil/log/internal/nullstream - - abseil/xcprivacy - - abseil/log/internal/vlog_config (1.20240116.2): - - abseil/base/base - - abseil/base/config - - abseil/base/core_headers - - abseil/base/no_destructor - - abseil/log/internal/fnmatch - - abseil/memory/memory - - abseil/strings/strings - - abseil/synchronization/synchronization - - abseil/types/optional - - abseil/xcprivacy - - abseil/log/internal/voidify (1.20240116.2): - - abseil/base/config - - abseil/xcprivacy - - abseil/log/log (1.20240116.2): - - abseil/log/internal/log_impl - - abseil/log/vlog_is_on - - abseil/xcprivacy - - abseil/log/log_entry (1.20240116.2): - - abseil/base/config - - abseil/base/core_headers - - abseil/base/log_severity - - abseil/log/internal/config - - abseil/strings/strings - - abseil/time/time - - abseil/types/span - - abseil/xcprivacy - - abseil/log/log_sink (1.20240116.2): - - abseil/base/config - - abseil/log/log_entry - - abseil/xcprivacy - - abseil/log/log_sink_registry (1.20240116.2): - - abseil/base/config - - abseil/log/internal/log_sink_set - - abseil/log/log_sink - - abseil/xcprivacy - - abseil/log/vlog_is_on (1.20240116.2): - - abseil/log/absl_vlog_is_on - - abseil/xcprivacy - - abseil/memory (1.20240116.2): - - abseil/memory/memory (= 1.20240116.2) - - abseil/memory/memory (1.20240116.2): - - abseil/base/core_headers - - abseil/meta/type_traits - - abseil/xcprivacy - - abseil/meta (1.20240116.2): - - abseil/meta/type_traits (= 1.20240116.2) - - abseil/meta/type_traits (1.20240116.2): - - abseil/base/config - - abseil/base/core_headers - - abseil/xcprivacy - - abseil/numeric/bits (1.20240116.2): - - abseil/base/config - - abseil/base/core_headers - - abseil/xcprivacy - - abseil/numeric/int128 (1.20240116.2): - - abseil/base/config - - abseil/base/core_headers - - abseil/numeric/bits - - abseil/xcprivacy - - abseil/numeric/representation (1.20240116.2): - - abseil/base/config - - abseil/xcprivacy - - abseil/profiling/exponential_biased (1.20240116.2): - - abseil/base/config - - abseil/base/core_headers - - abseil/xcprivacy - - abseil/profiling/sample_recorder (1.20240116.2): - - abseil/base/config - - abseil/base/core_headers - - abseil/synchronization/synchronization - - abseil/time/time - - abseil/xcprivacy - - abseil/random/bit_gen_ref (1.20240116.2): - - abseil/base/core_headers - - abseil/base/fast_type_id - - abseil/meta/type_traits - - abseil/random/internal/distribution_caller - - abseil/random/internal/fast_uniform_bits - - abseil/random/random - - abseil/xcprivacy - - abseil/random/distributions (1.20240116.2): - - abseil/base/base_internal - - abseil/base/config - - abseil/base/core_headers - - abseil/meta/type_traits - - abseil/numeric/bits - - abseil/random/internal/distribution_caller - - abseil/random/internal/fast_uniform_bits - - abseil/random/internal/fastmath - - abseil/random/internal/generate_real - - abseil/random/internal/iostream_state_saver - - abseil/random/internal/traits - - abseil/random/internal/uniform_helper - - abseil/random/internal/wide_multiply - - abseil/strings/strings - - abseil/xcprivacy - - abseil/random/internal/distribution_caller (1.20240116.2): - - abseil/base/config - - abseil/base/fast_type_id - - abseil/utility/utility - - abseil/xcprivacy - - abseil/random/internal/fast_uniform_bits (1.20240116.2): - - abseil/base/config - - abseil/meta/type_traits - - abseil/random/internal/traits - - abseil/xcprivacy - - abseil/random/internal/fastmath (1.20240116.2): - - abseil/numeric/bits - - abseil/xcprivacy - - abseil/random/internal/generate_real (1.20240116.2): - - abseil/meta/type_traits - - abseil/numeric/bits - - abseil/random/internal/fastmath - - abseil/random/internal/traits - - abseil/xcprivacy - - abseil/random/internal/iostream_state_saver (1.20240116.2): - - abseil/meta/type_traits - - abseil/numeric/int128 - - abseil/xcprivacy - - abseil/random/internal/nonsecure_base (1.20240116.2): - - abseil/base/core_headers - - abseil/container/inlined_vector - - abseil/meta/type_traits - - abseil/random/internal/pool_urbg - - abseil/random/internal/salted_seed_seq - - abseil/random/internal/seed_material - - abseil/types/span - - abseil/xcprivacy - - abseil/random/internal/pcg_engine (1.20240116.2): - - abseil/base/config - - abseil/meta/type_traits - - abseil/numeric/bits - - abseil/numeric/int128 - - abseil/random/internal/fastmath - - abseil/random/internal/iostream_state_saver - - abseil/xcprivacy - - abseil/random/internal/platform (1.20240116.2): - - abseil/base/config - - abseil/xcprivacy - - abseil/random/internal/pool_urbg (1.20240116.2): - - abseil/base/base - - abseil/base/config - - abseil/base/core_headers - - abseil/base/endian - - abseil/base/raw_logging_internal - - abseil/random/internal/randen - - abseil/random/internal/seed_material - - abseil/random/internal/traits - - abseil/random/seed_gen_exception - - abseil/types/span - - abseil/xcprivacy - - abseil/random/internal/randen (1.20240116.2): - - abseil/base/raw_logging_internal - - abseil/random/internal/platform - - abseil/random/internal/randen_hwaes - - abseil/random/internal/randen_slow - - abseil/xcprivacy - - abseil/random/internal/randen_engine (1.20240116.2): - - abseil/base/endian - - abseil/meta/type_traits - - abseil/random/internal/iostream_state_saver - - abseil/random/internal/randen - - abseil/xcprivacy - - abseil/random/internal/randen_hwaes (1.20240116.2): - - abseil/base/config - - abseil/random/internal/platform - - abseil/random/internal/randen_hwaes_impl - - abseil/xcprivacy - - abseil/random/internal/randen_hwaes_impl (1.20240116.2): - - abseil/base/config - - abseil/base/core_headers - - abseil/numeric/int128 - - abseil/random/internal/platform - - abseil/xcprivacy - - abseil/random/internal/randen_slow (1.20240116.2): - - abseil/base/config - - abseil/base/core_headers - - abseil/base/endian - - abseil/numeric/int128 - - abseil/random/internal/platform - - abseil/xcprivacy - - abseil/random/internal/salted_seed_seq (1.20240116.2): - - abseil/container/inlined_vector - - abseil/meta/type_traits - - abseil/random/internal/seed_material - - abseil/types/optional - - abseil/types/span - - abseil/xcprivacy - - abseil/random/internal/seed_material (1.20240116.2): - - abseil/base/core_headers - - abseil/base/dynamic_annotations - - abseil/base/raw_logging_internal - - abseil/random/internal/fast_uniform_bits - - abseil/strings/strings - - abseil/types/optional - - abseil/types/span - - abseil/xcprivacy - - abseil/random/internal/traits (1.20240116.2): - - abseil/base/config - - abseil/numeric/bits - - abseil/numeric/int128 - - abseil/xcprivacy - - abseil/random/internal/uniform_helper (1.20240116.2): - - abseil/base/config - - abseil/meta/type_traits - - abseil/numeric/int128 - - abseil/random/internal/traits - - abseil/xcprivacy - - abseil/random/internal/wide_multiply (1.20240116.2): - - abseil/base/config - - abseil/numeric/bits - - abseil/numeric/int128 - - abseil/random/internal/traits - - abseil/xcprivacy - - abseil/random/random (1.20240116.2): - - abseil/random/distributions - - abseil/random/internal/nonsecure_base - - abseil/random/internal/pcg_engine - - abseil/random/internal/pool_urbg - - abseil/random/internal/randen_engine - - abseil/random/seed_sequences - - abseil/xcprivacy - - abseil/random/seed_gen_exception (1.20240116.2): - - abseil/base/config - - abseil/xcprivacy - - abseil/random/seed_sequences (1.20240116.2): - - abseil/base/config - - abseil/random/internal/pool_urbg - - abseil/random/internal/salted_seed_seq - - abseil/random/internal/seed_material - - abseil/random/seed_gen_exception - - abseil/types/span - - abseil/xcprivacy - - abseil/status/status (1.20240116.2): - - abseil/base/atomic_hook - - abseil/base/config - - abseil/base/core_headers - - abseil/base/no_destructor - - abseil/base/nullability - - abseil/base/raw_logging_internal - - abseil/base/strerror - - abseil/container/inlined_vector - - abseil/debugging/stacktrace - - abseil/debugging/symbolize - - abseil/functional/function_ref - - abseil/memory/memory - - abseil/strings/cord - - abseil/strings/str_format - - abseil/strings/strings - - abseil/types/optional - - abseil/types/span - - abseil/xcprivacy - - abseil/status/statusor (1.20240116.2): - - abseil/base/base - - abseil/base/config - - abseil/base/core_headers - - abseil/base/nullability - - abseil/base/raw_logging_internal - - abseil/meta/type_traits - - abseil/status/status - - abseil/strings/has_ostream_operator - - abseil/strings/str_format - - abseil/strings/strings - - abseil/types/variant - - abseil/utility/utility - - abseil/xcprivacy - - abseil/strings/charset (1.20240116.2): - - abseil/base/core_headers - - abseil/strings/string_view - - abseil/xcprivacy - - abseil/strings/cord (1.20240116.2): - - abseil/base/base - - abseil/base/config - - abseil/base/core_headers - - abseil/base/endian - - abseil/base/nullability - - abseil/base/raw_logging_internal - - abseil/container/inlined_vector - - abseil/crc/crc32c - - abseil/crc/crc_cord_state - - abseil/functional/function_ref - - abseil/meta/type_traits - - abseil/numeric/bits - - abseil/strings/cord_internal - - abseil/strings/cordz_functions - - abseil/strings/cordz_info - - abseil/strings/cordz_statistics - - abseil/strings/cordz_update_scope - - abseil/strings/cordz_update_tracker - - abseil/strings/internal - - abseil/strings/strings - - abseil/types/optional - - abseil/types/span - - abseil/xcprivacy - - abseil/strings/cord_internal (1.20240116.2): - - abseil/base/base_internal - - abseil/base/config - - abseil/base/core_headers - - abseil/base/endian - - abseil/base/raw_logging_internal - - abseil/base/throw_delegate - - abseil/container/compressed_tuple - - abseil/container/container_memory - - abseil/container/inlined_vector - - abseil/container/layout - - abseil/crc/crc_cord_state - - abseil/functional/function_ref - - abseil/meta/type_traits - - abseil/strings/strings - - abseil/types/span - - abseil/xcprivacy - - abseil/strings/cordz_functions (1.20240116.2): - - abseil/base/config - - abseil/base/core_headers - - abseil/base/raw_logging_internal - - abseil/profiling/exponential_biased - - abseil/xcprivacy - - abseil/strings/cordz_handle (1.20240116.2): - - abseil/base/base - - abseil/base/config - - abseil/base/raw_logging_internal - - abseil/synchronization/synchronization - - abseil/xcprivacy - - abseil/strings/cordz_info (1.20240116.2): - - abseil/base/base - - abseil/base/config - - abseil/base/core_headers - - abseil/base/raw_logging_internal - - abseil/container/inlined_vector - - abseil/debugging/stacktrace - - abseil/strings/cord_internal - - abseil/strings/cordz_functions - - abseil/strings/cordz_handle - - abseil/strings/cordz_statistics - - abseil/strings/cordz_update_tracker - - abseil/synchronization/synchronization - - abseil/time/time - - abseil/types/span - - abseil/xcprivacy - - abseil/strings/cordz_statistics (1.20240116.2): - - abseil/base/config - - abseil/strings/cordz_update_tracker - - abseil/xcprivacy - - abseil/strings/cordz_update_scope (1.20240116.2): - - abseil/base/config - - abseil/base/core_headers - - abseil/strings/cord_internal - - abseil/strings/cordz_info - - abseil/strings/cordz_update_tracker - - abseil/xcprivacy - - abseil/strings/cordz_update_tracker (1.20240116.2): - - abseil/base/config - - abseil/xcprivacy - - abseil/strings/has_ostream_operator (1.20240116.2): - - abseil/base/config - - abseil/xcprivacy - - abseil/strings/internal (1.20240116.2): - - abseil/base/config - - abseil/base/core_headers - - abseil/base/endian - - abseil/base/raw_logging_internal - - abseil/meta/type_traits - - abseil/xcprivacy - - abseil/strings/str_format (1.20240116.2): - - abseil/base/config - - abseil/base/core_headers - - abseil/base/nullability - - abseil/strings/str_format_internal - - abseil/strings/string_view - - abseil/types/span - - abseil/xcprivacy - - abseil/strings/str_format_internal (1.20240116.2): - - abseil/base/config - - abseil/base/core_headers - - abseil/container/fixed_array - - abseil/container/inlined_vector - - abseil/functional/function_ref - - abseil/meta/type_traits - - abseil/numeric/bits - - abseil/numeric/int128 - - abseil/numeric/representation - - abseil/strings/strings - - abseil/types/optional - - abseil/types/span - - abseil/utility/utility - - abseil/xcprivacy - - abseil/strings/string_view (1.20240116.2): - - abseil/base/base - - abseil/base/config - - abseil/base/core_headers - - abseil/base/nullability - - abseil/base/throw_delegate - - abseil/xcprivacy - - abseil/strings/strings (1.20240116.2): - - abseil/base/base - - abseil/base/config - - abseil/base/core_headers - - abseil/base/endian - - abseil/base/nullability - - abseil/base/raw_logging_internal - - abseil/base/throw_delegate - - abseil/memory/memory - - abseil/meta/type_traits - - abseil/numeric/bits - - abseil/numeric/int128 - - abseil/strings/charset - - abseil/strings/internal - - abseil/strings/string_view - - abseil/xcprivacy - - abseil/synchronization/graphcycles_internal (1.20240116.2): - - abseil/base/base - - abseil/base/base_internal - - abseil/base/config - - abseil/base/core_headers - - abseil/base/malloc_internal - - abseil/base/raw_logging_internal - - abseil/xcprivacy - - abseil/synchronization/kernel_timeout_internal (1.20240116.2): - - abseil/base/base - - abseil/base/config - - abseil/base/core_headers - - abseil/base/raw_logging_internal - - abseil/time/time - - abseil/xcprivacy - - abseil/synchronization/synchronization (1.20240116.2): - - abseil/base/atomic_hook - - abseil/base/base - - abseil/base/base_internal - - abseil/base/config - - abseil/base/core_headers - - abseil/base/dynamic_annotations - - abseil/base/malloc_internal - - abseil/base/raw_logging_internal - - abseil/debugging/stacktrace - - abseil/debugging/symbolize - - abseil/synchronization/graphcycles_internal - - abseil/synchronization/kernel_timeout_internal - - abseil/time/time - - abseil/xcprivacy - - abseil/time (1.20240116.2): - - abseil/time/internal (= 1.20240116.2) - - abseil/time/time (= 1.20240116.2) - - abseil/time/internal (1.20240116.2): - - abseil/time/internal/cctz (= 1.20240116.2) - - abseil/time/internal/cctz (1.20240116.2): - - abseil/time/internal/cctz/civil_time (= 1.20240116.2) - - abseil/time/internal/cctz/time_zone (= 1.20240116.2) - - abseil/time/internal/cctz/civil_time (1.20240116.2): - - abseil/base/config - - abseil/xcprivacy - - abseil/time/internal/cctz/time_zone (1.20240116.2): - - abseil/base/config - - abseil/time/internal/cctz/civil_time - - abseil/xcprivacy - - abseil/time/time (1.20240116.2): - - abseil/base/base - - abseil/base/config - - abseil/base/core_headers - - abseil/base/raw_logging_internal - - abseil/numeric/int128 - - abseil/strings/strings - - abseil/time/internal/cctz/civil_time - - abseil/time/internal/cctz/time_zone - - abseil/types/optional - - abseil/xcprivacy - - abseil/types (1.20240116.2): - - abseil/types/any (= 1.20240116.2) - - abseil/types/bad_any_cast (= 1.20240116.2) - - abseil/types/bad_any_cast_impl (= 1.20240116.2) - - abseil/types/bad_optional_access (= 1.20240116.2) - - abseil/types/bad_variant_access (= 1.20240116.2) - - abseil/types/compare (= 1.20240116.2) - - abseil/types/optional (= 1.20240116.2) - - abseil/types/span (= 1.20240116.2) - - abseil/types/variant (= 1.20240116.2) - - abseil/types/any (1.20240116.2): - - abseil/base/config - - abseil/base/core_headers - - abseil/base/fast_type_id - - abseil/meta/type_traits - - abseil/types/bad_any_cast - - abseil/utility/utility - - abseil/xcprivacy - - abseil/types/bad_any_cast (1.20240116.2): - - abseil/base/config - - abseil/types/bad_any_cast_impl - - abseil/xcprivacy - - abseil/types/bad_any_cast_impl (1.20240116.2): - - abseil/base/config - - abseil/base/raw_logging_internal - - abseil/xcprivacy - - abseil/types/bad_optional_access (1.20240116.2): - - abseil/base/config - - abseil/base/raw_logging_internal - - abseil/xcprivacy - - abseil/types/bad_variant_access (1.20240116.2): - - abseil/base/config - - abseil/base/raw_logging_internal - - abseil/xcprivacy - - abseil/types/compare (1.20240116.2): - - abseil/base/config - - abseil/base/core_headers - - abseil/meta/type_traits - - abseil/xcprivacy - - abseil/types/optional (1.20240116.2): - - abseil/base/base_internal - - abseil/base/config - - abseil/base/core_headers - - abseil/base/nullability - - abseil/memory/memory - - abseil/meta/type_traits - - abseil/types/bad_optional_access - - abseil/utility/utility - - abseil/xcprivacy - - abseil/types/span (1.20240116.2): - - abseil/algorithm/algorithm - - abseil/base/core_headers - - abseil/base/nullability - - abseil/base/throw_delegate - - abseil/meta/type_traits - - abseil/xcprivacy - - abseil/types/variant (1.20240116.2): - - abseil/base/base_internal - - abseil/base/config - - abseil/base/core_headers - - abseil/meta/type_traits - - abseil/types/bad_variant_access - - abseil/utility/utility - - abseil/xcprivacy - - abseil/utility/utility (1.20240116.2): - - abseil/base/base_internal - - abseil/base/config - - abseil/meta/type_traits - - abseil/xcprivacy - - abseil/xcprivacy (1.20240116.2) - - app_links (1.0.0): - - FlutterMacOS - - AppAuth (1.7.6): - - AppAuth/Core (= 1.7.6) - - AppAuth/ExternalUserAgent (= 1.7.6) - - AppAuth/Core (1.7.6) - - AppAuth/ExternalUserAgent (1.7.6): - - AppAuth/Core - - audioplayers_darwin (0.0.1): - - FlutterMacOS - - BoringSSL-GRPC (0.0.36): - - BoringSSL-GRPC/Implementation (= 0.0.36) - - BoringSSL-GRPC/Interface (= 0.0.36) - - BoringSSL-GRPC/Implementation (0.0.36): - - BoringSSL-GRPC/Interface (= 0.0.36) - - BoringSSL-GRPC/Interface (0.0.36) - - cloud_firestore (5.2.1): - - Firebase/CoreOnly (~> 11.2.0) - - Firebase/Firestore (~> 11.2.0) - - firebase_core - - FlutterMacOS - - device_info_plus (0.0.1): - - FlutterMacOS - - Firebase/Analytics (11.2.0): - - Firebase/Core - - Firebase/Core (11.2.0): - - Firebase/CoreOnly - - FirebaseAnalytics (~> 11.2.0) - - Firebase/CoreOnly (11.2.0): - - FirebaseCore (= 11.2.0) - - Firebase/Crashlytics (11.2.0): - - Firebase/CoreOnly - - FirebaseCrashlytics (~> 11.2.0) - - Firebase/Firestore (11.2.0): - - Firebase/CoreOnly - - FirebaseFirestore (~> 11.2.0) - - Firebase/Messaging (11.2.0): - - Firebase/CoreOnly - - FirebaseMessaging (~> 11.2.0) - - firebase_analytics (11.2.1): - - Firebase/Analytics (= 11.2.0) - - firebase_core - - FlutterMacOS - - firebase_core (3.6.0): - - Firebase/CoreOnly (~> 11.2.0) - - FlutterMacOS - - firebase_crashlytics (4.0.4): - - Firebase/CoreOnly (~> 11.2.0) - - Firebase/Crashlytics (~> 11.2.0) - - firebase_core - - FlutterMacOS - - firebase_messaging (15.1.3): - - Firebase/CoreOnly (~> 11.2.0) - - Firebase/Messaging (~> 11.2.0) - - firebase_core - - FlutterMacOS - - FirebaseAnalytics (11.2.0): - - FirebaseAnalytics/AdIdSupport (= 11.2.0) - - FirebaseCore (~> 11.0) - - FirebaseInstallations (~> 11.0) - - GoogleUtilities/AppDelegateSwizzler (~> 8.0) - - GoogleUtilities/MethodSwizzler (~> 8.0) - - GoogleUtilities/Network (~> 8.0) - - "GoogleUtilities/NSData+zlib (~> 8.0)" - - nanopb (~> 3.30910.0) - - FirebaseAnalytics/AdIdSupport (11.2.0): - - FirebaseCore (~> 11.0) - - FirebaseInstallations (~> 11.0) - - GoogleAppMeasurement (= 11.2.0) - - GoogleUtilities/AppDelegateSwizzler (~> 8.0) - - GoogleUtilities/MethodSwizzler (~> 8.0) - - GoogleUtilities/Network (~> 8.0) - - "GoogleUtilities/NSData+zlib (~> 8.0)" - - nanopb (~> 3.30910.0) - - FirebaseAppCheckInterop (11.7.0) - - FirebaseCore (11.2.0): - - FirebaseCoreInternal (~> 11.0) - - GoogleUtilities/Environment (~> 8.0) - - GoogleUtilities/Logger (~> 8.0) - - FirebaseCoreExtension (11.4.1): - - FirebaseCore (~> 11.0) - - FirebaseCoreInternal (11.7.0): - - "GoogleUtilities/NSData+zlib (~> 8.0)" - - FirebaseCrashlytics (11.2.0): - - FirebaseCore (~> 11.0) - - FirebaseInstallations (~> 11.0) - - FirebaseRemoteConfigInterop (~> 11.0) - - FirebaseSessions (~> 11.0) - - GoogleDataTransport (~> 10.0) - - GoogleUtilities/Environment (~> 8.0) - - nanopb (~> 3.30910.0) - - PromisesObjC (~> 2.4) - - FirebaseFirestore (11.2.0): - - FirebaseCore (~> 11.0) - - FirebaseCoreExtension (~> 11.0) - - FirebaseFirestoreInternal (= 11.2.0) - - FirebaseSharedSwift (~> 11.0) - - FirebaseFirestoreInternal (11.2.0): - - abseil/algorithm (~> 1.20240116.1) - - abseil/base (~> 1.20240116.1) - - abseil/container/flat_hash_map (~> 1.20240116.1) - - abseil/memory (~> 1.20240116.1) - - abseil/meta (~> 1.20240116.1) - - abseil/strings/strings (~> 1.20240116.1) - - abseil/time (~> 1.20240116.1) - - abseil/types (~> 1.20240116.1) - - FirebaseAppCheckInterop (~> 11.0) - - FirebaseCore (~> 11.0) - - "gRPC-C++ (~> 1.65.0)" - - gRPC-Core (~> 1.65.0) - - leveldb-library (~> 1.22) - - nanopb (~> 3.30910.0) - - FirebaseInstallations (11.4.0): - - FirebaseCore (~> 11.0) - - GoogleUtilities/Environment (~> 8.0) - - GoogleUtilities/UserDefaults (~> 8.0) - - PromisesObjC (~> 2.4) - - FirebaseMessaging (11.2.0): - - FirebaseCore (~> 11.0) - - FirebaseInstallations (~> 11.0) - - GoogleDataTransport (~> 10.0) - - GoogleUtilities/AppDelegateSwizzler (~> 8.0) - - GoogleUtilities/Environment (~> 8.0) - - GoogleUtilities/Reachability (~> 8.0) - - GoogleUtilities/UserDefaults (~> 8.0) - - nanopb (~> 3.30910.0) - - FirebaseRemoteConfigInterop (11.7.0) - - FirebaseSessions (11.3.0): - - FirebaseCore (~> 11.0) - - FirebaseCoreExtension (~> 11.0) - - FirebaseInstallations (~> 11.0) - - GoogleDataTransport (~> 10.0) - - GoogleUtilities/Environment (~> 8.0) - - GoogleUtilities/UserDefaults (~> 8.0) - - nanopb (~> 3.30910.0) - - PromisesSwift (~> 2.1) - - FirebaseSharedSwift (11.7.0) - - flutter_local_notifications (0.0.1): - - FlutterMacOS - - flutter_secure_storage_macos (6.1.1): - - FlutterMacOS - - flutter_tts (0.0.1): - - FlutterMacOS - - FlutterMacOS (1.0.0) - - google_sign_in_ios (0.0.1): - - AppAuth (>= 1.7.4) - - Flutter - - FlutterMacOS - - GoogleSignIn (~> 7.1) - - GTMSessionFetcher (>= 3.4.0) - - GoogleAppMeasurement (11.2.0): - - GoogleAppMeasurement/AdIdSupport (= 11.2.0) - - GoogleUtilities/AppDelegateSwizzler (~> 8.0) - - GoogleUtilities/MethodSwizzler (~> 8.0) - - GoogleUtilities/Network (~> 8.0) - - "GoogleUtilities/NSData+zlib (~> 8.0)" - - nanopb (~> 3.30910.0) - - GoogleAppMeasurement/AdIdSupport (11.2.0): - - GoogleAppMeasurement/WithoutAdIdSupport (= 11.2.0) - - GoogleUtilities/AppDelegateSwizzler (~> 8.0) - - GoogleUtilities/MethodSwizzler (~> 8.0) - - GoogleUtilities/Network (~> 8.0) - - "GoogleUtilities/NSData+zlib (~> 8.0)" - - nanopb (~> 3.30910.0) - - GoogleAppMeasurement/WithoutAdIdSupport (11.2.0): - - GoogleUtilities/AppDelegateSwizzler (~> 8.0) - - GoogleUtilities/MethodSwizzler (~> 8.0) - - GoogleUtilities/Network (~> 8.0) - - "GoogleUtilities/NSData+zlib (~> 8.0)" - - nanopb (~> 3.30910.0) - - GoogleDataTransport (10.1.0): - - nanopb (~> 3.30910.0) - - PromisesObjC (~> 2.4) - - GoogleSignIn (7.1.0): - - AppAuth (< 2.0, >= 1.7.3) - - GTMAppAuth (< 5.0, >= 4.1.1) - - GTMSessionFetcher/Core (~> 3.3) - - GoogleUtilities/AppDelegateSwizzler (8.0.2): - - GoogleUtilities/Environment - - GoogleUtilities/Logger - - GoogleUtilities/Network - - GoogleUtilities/Privacy - - GoogleUtilities/Environment (8.0.2): - - GoogleUtilities/Privacy - - GoogleUtilities/Logger (8.0.2): - - GoogleUtilities/Environment - - GoogleUtilities/Privacy - - GoogleUtilities/MethodSwizzler (8.0.2): - - GoogleUtilities/Logger - - GoogleUtilities/Privacy - - GoogleUtilities/Network (8.0.2): - - GoogleUtilities/Logger - - "GoogleUtilities/NSData+zlib" - - GoogleUtilities/Privacy - - GoogleUtilities/Reachability - - "GoogleUtilities/NSData+zlib (8.0.2)": - - GoogleUtilities/Privacy - - GoogleUtilities/Privacy (8.0.2) - - GoogleUtilities/Reachability (8.0.2): - - GoogleUtilities/Logger - - GoogleUtilities/Privacy - - GoogleUtilities/UserDefaults (8.0.2): - - GoogleUtilities/Logger - - GoogleUtilities/Privacy - - "gRPC-C++ (1.65.5)": - - "gRPC-C++/Implementation (= 1.65.5)" - - "gRPC-C++/Interface (= 1.65.5)" - - "gRPC-C++/Implementation (1.65.5)": - - abseil/algorithm/container (~> 1.20240116.2) - - abseil/base/base (~> 1.20240116.2) - - abseil/base/config (~> 1.20240116.2) - - abseil/base/core_headers (~> 1.20240116.2) - - abseil/base/log_severity (~> 1.20240116.2) - - abseil/base/no_destructor (~> 1.20240116.2) - - abseil/cleanup/cleanup (~> 1.20240116.2) - - abseil/container/flat_hash_map (~> 1.20240116.2) - - abseil/container/flat_hash_set (~> 1.20240116.2) - - abseil/container/inlined_vector (~> 1.20240116.2) - - abseil/flags/flag (~> 1.20240116.2) - - abseil/flags/marshalling (~> 1.20240116.2) - - abseil/functional/any_invocable (~> 1.20240116.2) - - abseil/functional/bind_front (~> 1.20240116.2) - - abseil/functional/function_ref (~> 1.20240116.2) - - abseil/hash/hash (~> 1.20240116.2) - - abseil/log/absl_check (~> 1.20240116.2) - - abseil/log/absl_log (~> 1.20240116.2) - - abseil/log/check (~> 1.20240116.2) - - abseil/log/globals (~> 1.20240116.2) - - abseil/log/log (~> 1.20240116.2) - - abseil/memory/memory (~> 1.20240116.2) - - abseil/meta/type_traits (~> 1.20240116.2) - - abseil/random/bit_gen_ref (~> 1.20240116.2) - - abseil/random/distributions (~> 1.20240116.2) - - abseil/random/random (~> 1.20240116.2) - - abseil/status/status (~> 1.20240116.2) - - abseil/status/statusor (~> 1.20240116.2) - - abseil/strings/cord (~> 1.20240116.2) - - abseil/strings/str_format (~> 1.20240116.2) - - abseil/strings/strings (~> 1.20240116.2) - - abseil/synchronization/synchronization (~> 1.20240116.2) - - abseil/time/time (~> 1.20240116.2) - - abseil/types/optional (~> 1.20240116.2) - - abseil/types/span (~> 1.20240116.2) - - abseil/types/variant (~> 1.20240116.2) - - abseil/utility/utility (~> 1.20240116.2) - - "gRPC-C++/Interface (= 1.65.5)" - - "gRPC-C++/Privacy (= 1.65.5)" - - gRPC-Core (= 1.65.5) - - "gRPC-C++/Interface (1.65.5)" - - "gRPC-C++/Privacy (1.65.5)" - - gRPC-Core (1.65.5): - - gRPC-Core/Implementation (= 1.65.5) - - gRPC-Core/Interface (= 1.65.5) - - gRPC-Core/Implementation (1.65.5): - - abseil/algorithm/container (~> 1.20240116.2) - - abseil/base/base (~> 1.20240116.2) - - abseil/base/config (~> 1.20240116.2) - - abseil/base/core_headers (~> 1.20240116.2) - - abseil/base/log_severity (~> 1.20240116.2) - - abseil/base/no_destructor (~> 1.20240116.2) - - abseil/cleanup/cleanup (~> 1.20240116.2) - - abseil/container/flat_hash_map (~> 1.20240116.2) - - abseil/container/flat_hash_set (~> 1.20240116.2) - - abseil/container/inlined_vector (~> 1.20240116.2) - - abseil/flags/flag (~> 1.20240116.2) - - abseil/flags/marshalling (~> 1.20240116.2) - - abseil/functional/any_invocable (~> 1.20240116.2) - - abseil/functional/bind_front (~> 1.20240116.2) - - abseil/functional/function_ref (~> 1.20240116.2) - - abseil/hash/hash (~> 1.20240116.2) - - abseil/log/check (~> 1.20240116.2) - - abseil/log/globals (~> 1.20240116.2) - - abseil/log/log (~> 1.20240116.2) - - abseil/memory/memory (~> 1.20240116.2) - - abseil/meta/type_traits (~> 1.20240116.2) - - abseil/random/bit_gen_ref (~> 1.20240116.2) - - abseil/random/distributions (~> 1.20240116.2) - - abseil/random/random (~> 1.20240116.2) - - abseil/status/status (~> 1.20240116.2) - - abseil/status/statusor (~> 1.20240116.2) - - abseil/strings/cord (~> 1.20240116.2) - - abseil/strings/str_format (~> 1.20240116.2) - - abseil/strings/strings (~> 1.20240116.2) - - abseil/synchronization/synchronization (~> 1.20240116.2) - - abseil/time/time (~> 1.20240116.2) - - abseil/types/optional (~> 1.20240116.2) - - abseil/types/span (~> 1.20240116.2) - - abseil/types/variant (~> 1.20240116.2) - - abseil/utility/utility (~> 1.20240116.2) - - BoringSSL-GRPC (= 0.0.36) - - gRPC-Core/Interface (= 1.65.5) - - gRPC-Core/Privacy (= 1.65.5) - - gRPC-Core/Interface (1.65.5) - - gRPC-Core/Privacy (1.65.5) - - GTMAppAuth (4.1.1): - - AppAuth/Core (~> 1.7) - - GTMSessionFetcher/Core (< 4.0, >= 3.3) - - GTMSessionFetcher (3.5.0): - - GTMSessionFetcher/Full (= 3.5.0) - - GTMSessionFetcher/Core (3.5.0) - - GTMSessionFetcher/Full (3.5.0): - - GTMSessionFetcher/Core - - in_app_purchase_storekit (0.0.1): - - Flutter - - FlutterMacOS - - leveldb-library (1.22.6) - - nanopb (3.30910.0): - - nanopb/decode (= 3.30910.0) - - nanopb/encode (= 3.30910.0) - - nanopb/decode (3.30910.0) - - nanopb/encode (3.30910.0) - - package_info_plus (0.0.1): - - FlutterMacOS - - path_provider_foundation (0.0.1): - - Flutter - - FlutterMacOS - - PromisesObjC (2.4.0) - - PromisesSwift (2.4.0): - - PromisesObjC (= 2.4.0) - - shared_preferences_foundation (0.0.1): - - Flutter - - FlutterMacOS - - url_launcher_macos (0.0.1): - - FlutterMacOS - -DEPENDENCIES: - - app_links (from `Flutter/ephemeral/.symlinks/plugins/app_links/macos`) - - audioplayers_darwin (from `Flutter/ephemeral/.symlinks/plugins/audioplayers_darwin/macos`) - - cloud_firestore (from `Flutter/ephemeral/.symlinks/plugins/cloud_firestore/macos`) - - device_info_plus (from `Flutter/ephemeral/.symlinks/plugins/device_info_plus/macos`) - - firebase_analytics (from `Flutter/ephemeral/.symlinks/plugins/firebase_analytics/macos`) - - firebase_core (from `Flutter/ephemeral/.symlinks/plugins/firebase_core/macos`) - - firebase_crashlytics (from `Flutter/ephemeral/.symlinks/plugins/firebase_crashlytics/macos`) - - firebase_messaging (from `Flutter/ephemeral/.symlinks/plugins/firebase_messaging/macos`) - - flutter_local_notifications (from `Flutter/ephemeral/.symlinks/plugins/flutter_local_notifications/macos`) - - flutter_secure_storage_macos (from `Flutter/ephemeral/.symlinks/plugins/flutter_secure_storage_macos/macos`) - - flutter_tts (from `Flutter/ephemeral/.symlinks/plugins/flutter_tts/macos`) - - FlutterMacOS (from `Flutter/ephemeral`) - - google_sign_in_ios (from `Flutter/ephemeral/.symlinks/plugins/google_sign_in_ios/darwin`) - - in_app_purchase_storekit (from `Flutter/ephemeral/.symlinks/plugins/in_app_purchase_storekit/darwin`) - - package_info_plus (from `Flutter/ephemeral/.symlinks/plugins/package_info_plus/macos`) - - path_provider_foundation (from `Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin`) - - shared_preferences_foundation (from `Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin`) - - url_launcher_macos (from `Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos`) - -SPEC REPOS: - trunk: - - abseil - - AppAuth - - BoringSSL-GRPC - - Firebase - - FirebaseAnalytics - - FirebaseAppCheckInterop - - FirebaseCore - - FirebaseCoreExtension - - FirebaseCoreInternal - - FirebaseCrashlytics - - FirebaseFirestore - - FirebaseFirestoreInternal - - FirebaseInstallations - - FirebaseMessaging - - FirebaseRemoteConfigInterop - - FirebaseSessions - - FirebaseSharedSwift - - GoogleAppMeasurement - - GoogleDataTransport - - GoogleSignIn - - GoogleUtilities - - "gRPC-C++" - - gRPC-Core - - GTMAppAuth - - GTMSessionFetcher - - leveldb-library - - nanopb - - PromisesObjC - - PromisesSwift - -EXTERNAL SOURCES: - app_links: - :path: Flutter/ephemeral/.symlinks/plugins/app_links/macos - audioplayers_darwin: - :path: Flutter/ephemeral/.symlinks/plugins/audioplayers_darwin/macos - cloud_firestore: - :path: Flutter/ephemeral/.symlinks/plugins/cloud_firestore/macos - device_info_plus: - :path: Flutter/ephemeral/.symlinks/plugins/device_info_plus/macos - firebase_analytics: - :path: Flutter/ephemeral/.symlinks/plugins/firebase_analytics/macos - firebase_core: - :path: Flutter/ephemeral/.symlinks/plugins/firebase_core/macos - firebase_crashlytics: - :path: Flutter/ephemeral/.symlinks/plugins/firebase_crashlytics/macos - firebase_messaging: - :path: Flutter/ephemeral/.symlinks/plugins/firebase_messaging/macos - flutter_local_notifications: - :path: Flutter/ephemeral/.symlinks/plugins/flutter_local_notifications/macos - flutter_secure_storage_macos: - :path: Flutter/ephemeral/.symlinks/plugins/flutter_secure_storage_macos/macos - flutter_tts: - :path: Flutter/ephemeral/.symlinks/plugins/flutter_tts/macos - FlutterMacOS: - :path: Flutter/ephemeral - google_sign_in_ios: - :path: Flutter/ephemeral/.symlinks/plugins/google_sign_in_ios/darwin - in_app_purchase_storekit: - :path: Flutter/ephemeral/.symlinks/plugins/in_app_purchase_storekit/darwin - package_info_plus: - :path: Flutter/ephemeral/.symlinks/plugins/package_info_plus/macos - path_provider_foundation: - :path: Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin - shared_preferences_foundation: - :path: Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin - url_launcher_macos: - :path: Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos - -SPEC CHECKSUMS: - abseil: d121da9ef7e2ff4cab7666e76c5a3e0915ae08c3 - app_links: 10e0a0ab602ffaf34d142cd4862f29d34b303b2a - AppAuth: d4f13a8fe0baf391b2108511793e4b479691fb73 - audioplayers_darwin: dcad41de4fbd0099cb3749f7ab3b0cb8f70b810c - BoringSSL-GRPC: ca6a8e5d04812fce8ffd6437810c2d46f925eaeb - cloud_firestore: 4a8d1fb3c8f97ac1b7bbd235e6b42151d1971042 - device_info_plus: ce1b7762849d3ec103d0e0517299f2db7ad60720 - Firebase: 98e6bf5278170668a7983e12971a66b2cd57fc8c - firebase_analytics: d976bfc2f44dab7bc8b52ce8a621eac8cdf7b824 - firebase_core: e88f946a4601cb1854178cb07da241bba5a6508e - firebase_crashlytics: 83c1cb31df9525edfed38a79688591f692d7d9f7 - firebase_messaging: e1b1c1504659e13d66131f62ec22919293cd0d11 - FirebaseAnalytics: c36efd5710c60c17558650fa58c2066eca7e9265 - FirebaseAppCheckInterop: 2376d3ec5cb4267facad4fe754ab4f301a5a519b - FirebaseCore: a282032ae9295c795714ded2ec9c522fc237f8da - FirebaseCoreExtension: f1bc67a4702931a7caa097d8e4ac0a1b0d16720e - FirebaseCoreInternal: d6c17dafc8dc33614733a8b52df78fcb4394c881 - FirebaseCrashlytics: cfc69af5b53565dc6a5e563788809b5778ac4eac - FirebaseFirestore: 62708adbc1dfcd6d165a7c0a202067b441912dc9 - FirebaseFirestoreInternal: ad9b9ee2d3d430c8f31333a69b3b6737a7206232 - FirebaseInstallations: 6ef4a1c7eb2a61ee1f74727d7f6ce2e72acf1414 - FirebaseMessaging: c9ec7b90c399c7a6100297e9d16f8a27fc7f7152 - FirebaseRemoteConfigInterop: ca12abf9da0003efd3a476b2dff4f7a04fd31b4f - FirebaseSessions: 655ff17f3cc1a635cbdc2d69b953878001f9e25b - FirebaseSharedSwift: a45efd84d60ebbfdcdbaebc66948af3630459e62 - flutter_local_notifications: 3805ca215b2fb7f397d78b66db91f6a747af52e4 - flutter_secure_storage_macos: 59459653abe1adb92abbc8ea747d79f8d19866c9 - flutter_tts: 64651204e5d276ffea5a910f942d5e9785a96085 - FlutterMacOS: 8f6f14fa908a6fb3fba0cd85dbd81ec4b251fb24 - google_sign_in_ios: 07375bfbf2620bc93a602c0e27160d6afc6ead38 - GoogleAppMeasurement: 76d4f8b36b03bd8381fa9a7fe2cc7f99c0a2e93a - GoogleDataTransport: aae35b7ea0c09004c3797d53c8c41f66f219d6a7 - GoogleSignIn: d4281ab6cf21542b1cfaff85c191f230b399d2db - GoogleUtilities: 26a3abef001b6533cf678d3eb38fd3f614b7872d - "gRPC-C++": 2fa52b3141e7789a28a737f251e0c45b4cb20a87 - gRPC-Core: a27c294d6149e1c39a7d173527119cfbc3375ce4 - GTMAppAuth: f69bd07d68cd3b766125f7e072c45d7340dea0de - GTMSessionFetcher: 5aea5ba6bd522a239e236100971f10cb71b96ab6 - in_app_purchase_storekit: 8c3b0b3eb1b0f04efbff401c3de6266d4258d433 - leveldb-library: cc8b8f8e013647a295ad3f8cd2ddf49a6f19be19 - nanopb: fad817b59e0457d11a5dfbde799381cd727c1275 - package_info_plus: fa739dd842b393193c5ca93c26798dff6e3d0e0c - path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46 - PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47 - PromisesSwift: 9d77319bbe72ebf6d872900551f7eeba9bce2851 - shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78 - url_launcher_macos: 5f437abeda8c85500ceb03f5c1938a8c5a705399 - -PODFILE CHECKSUM: 9ebaf0ce3d369aaa26a9ea0e159195ed94724cf3 - -COCOAPODS: 1.15.2 diff --git a/mnemo_cards/macos/Runner.xcodeproj/project.pbxproj b/mnemo_cards/macos/Runner.xcodeproj/project.pbxproj deleted file mode 100644 index f227cf5..0000000 --- a/mnemo_cards/macos/Runner.xcodeproj/project.pbxproj +++ /dev/null @@ -1,819 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 54; - objects = { - -/* Begin PBXAggregateTarget section */ - 33CC111A2044C6BA0003C045 /* Flutter Assemble */ = { - isa = PBXAggregateTarget; - buildConfigurationList = 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */; - buildPhases = ( - 33CC111E2044C6BF0003C045 /* ShellScript */, - ); - dependencies = ( - ); - name = "Flutter Assemble"; - productName = FLX; - }; -/* End PBXAggregateTarget section */ - -/* Begin PBXBuildFile section */ - 1D655A2027AC9156DDFC3E0B /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 127EBB21BED36AE4023E17CA /* Pods_RunnerTests.framework */; }; - 331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C80D7294CF71000263BE5 /* RunnerTests.swift */; }; - 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */; }; - 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC10F02044A3C60003C045 /* AppDelegate.swift */; }; - 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; }; - 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; }; - 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; }; - 478C45547A0E7EF873F0F729 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0E38805BA1DA56B14B171CF4 /* Pods_Runner.framework */; }; -/* End PBXBuildFile section */ - -/* Begin PBXContainerItemProxy section */ - 331C80D9294CF71000263BE5 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 33CC10E52044A3C60003C045 /* Project object */; - proxyType = 1; - remoteGlobalIDString = 33CC10EC2044A3C60003C045; - remoteInfo = Runner; - }; - 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 33CC10E52044A3C60003C045 /* Project object */; - proxyType = 1; - remoteGlobalIDString = 33CC111A2044C6BA0003C045; - remoteInfo = FLX; - }; -/* End PBXContainerItemProxy section */ - -/* Begin PBXCopyFilesBuildPhase section */ - 33CC110E2044A8840003C045 /* Bundle Framework */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = ""; - dstSubfolderSpec = 10; - files = ( - ); - name = "Bundle Framework"; - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXCopyFilesBuildPhase section */ - -/* Begin PBXFileReference section */ - 0E38805BA1DA56B14B171CF4 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 127EBB21BED36AE4023E17CA /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 2836729307E7DBB22E50CC47 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; - 2CD7ADD4778B1135BC0BB3F1 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; - 303095D17C36B08BC167DD68 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; - 331C80D5294CF71000263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; - 331C80D7294CF71000263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; - 333000ED22D3DE5D00554162 /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = ""; }; - 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneratedPluginRegistrant.swift; sourceTree = ""; }; - 33CC10ED2044A3C60003C045 /* mnemo_cards.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = mnemo_cards.app; sourceTree = BUILT_PRODUCTS_DIR; }; - 33CC10F02044A3C60003C045 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; - 33CC10F22044A3C60003C045 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = Runner/Assets.xcassets; sourceTree = ""; }; - 33CC10F52044A3C60003C045 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; - 33CC10F72044A3C60003C045 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Info.plist; path = Runner/Info.plist; sourceTree = ""; }; - 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainFlutterWindow.swift; sourceTree = ""; }; - 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Debug.xcconfig"; sourceTree = ""; }; - 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Release.xcconfig"; sourceTree = ""; }; - 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = "Flutter-Generated.xcconfig"; path = "ephemeral/Flutter-Generated.xcconfig"; sourceTree = ""; }; - 33E51913231747F40026EE4D /* DebugProfile.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DebugProfile.entitlements; sourceTree = ""; }; - 33E51914231749380026EE4D /* Release.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Release.entitlements; sourceTree = ""; }; - 33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = ""; }; - 38C01EEB58A2011E83940B15 /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = ""; }; - 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = ""; }; - 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = ""; }; - D3A6E5F779F83D17223F6470 /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = ""; }; - FE8B579F30BF0322A9964DB8 /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = ""; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - 331C80D2294CF70F00263BE5 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 1D655A2027AC9156DDFC3E0B /* Pods_RunnerTests.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 33CC10EA2044A3C60003C045 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 478C45547A0E7EF873F0F729 /* Pods_Runner.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 331C80D6294CF71000263BE5 /* RunnerTests */ = { - isa = PBXGroup; - children = ( - 331C80D7294CF71000263BE5 /* RunnerTests.swift */, - ); - path = RunnerTests; - sourceTree = ""; - }; - 33BA886A226E78AF003329D5 /* Configs */ = { - isa = PBXGroup; - children = ( - 33E5194F232828860026EE4D /* AppInfo.xcconfig */, - 9740EEB21CF90195004384FC /* Debug.xcconfig */, - 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, - 333000ED22D3DE5D00554162 /* Warnings.xcconfig */, - ); - path = Configs; - sourceTree = ""; - }; - 33CC10E42044A3C60003C045 = { - isa = PBXGroup; - children = ( - 33FAB671232836740065AC1E /* Runner */, - 33CEB47122A05771004F2AC0 /* Flutter */, - 331C80D6294CF71000263BE5 /* RunnerTests */, - 33CC10EE2044A3C60003C045 /* Products */, - D73912EC22F37F3D000D13A0 /* Frameworks */, - 3C985D5FA5015C7E97D58D2B /* Pods */, - ); - sourceTree = ""; - }; - 33CC10EE2044A3C60003C045 /* Products */ = { - isa = PBXGroup; - children = ( - 33CC10ED2044A3C60003C045 /* mnemo_cards.app */, - 331C80D5294CF71000263BE5 /* RunnerTests.xctest */, - ); - name = Products; - sourceTree = ""; - }; - 33CC11242044D66E0003C045 /* Resources */ = { - isa = PBXGroup; - children = ( - 33CC10F22044A3C60003C045 /* Assets.xcassets */, - 33CC10F42044A3C60003C045 /* MainMenu.xib */, - 33CC10F72044A3C60003C045 /* Info.plist */, - ); - name = Resources; - path = ..; - sourceTree = ""; - }; - 33CEB47122A05771004F2AC0 /* Flutter */ = { - isa = PBXGroup; - children = ( - 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */, - 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */, - 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */, - 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */, - ); - path = Flutter; - sourceTree = ""; - }; - 33FAB671232836740065AC1E /* Runner */ = { - isa = PBXGroup; - children = ( - 33CC10F02044A3C60003C045 /* AppDelegate.swift */, - 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */, - 33E51913231747F40026EE4D /* DebugProfile.entitlements */, - 33E51914231749380026EE4D /* Release.entitlements */, - 33CC11242044D66E0003C045 /* Resources */, - 33BA886A226E78AF003329D5 /* Configs */, - ); - path = Runner; - sourceTree = ""; - }; - 3C985D5FA5015C7E97D58D2B /* Pods */ = { - isa = PBXGroup; - children = ( - 303095D17C36B08BC167DD68 /* Pods-Runner.debug.xcconfig */, - 2CD7ADD4778B1135BC0BB3F1 /* Pods-Runner.release.xcconfig */, - 2836729307E7DBB22E50CC47 /* Pods-Runner.profile.xcconfig */, - D3A6E5F779F83D17223F6470 /* Pods-RunnerTests.debug.xcconfig */, - FE8B579F30BF0322A9964DB8 /* Pods-RunnerTests.release.xcconfig */, - 38C01EEB58A2011E83940B15 /* Pods-RunnerTests.profile.xcconfig */, - ); - name = Pods; - path = Pods; - sourceTree = ""; - }; - D73912EC22F37F3D000D13A0 /* Frameworks */ = { - isa = PBXGroup; - children = ( - 0E38805BA1DA56B14B171CF4 /* Pods_Runner.framework */, - 127EBB21BED36AE4023E17CA /* Pods_RunnerTests.framework */, - ); - name = Frameworks; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXNativeTarget section */ - 331C80D4294CF70F00263BE5 /* RunnerTests */ = { - isa = PBXNativeTarget; - buildConfigurationList = 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; - buildPhases = ( - 35872747888E30E6A0595C6E /* [CP] Check Pods Manifest.lock */, - 331C80D1294CF70F00263BE5 /* Sources */, - 331C80D2294CF70F00263BE5 /* Frameworks */, - 331C80D3294CF70F00263BE5 /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - 331C80DA294CF71000263BE5 /* PBXTargetDependency */, - ); - name = RunnerTests; - productName = RunnerTests; - productReference = 331C80D5294CF71000263BE5 /* RunnerTests.xctest */; - productType = "com.apple.product-type.bundle.unit-test"; - }; - 33CC10EC2044A3C60003C045 /* Runner */ = { - isa = PBXNativeTarget; - buildConfigurationList = 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */; - buildPhases = ( - 68BD5ED31F3D4BFE1F803D6F /* [CP] Check Pods Manifest.lock */, - 33CC10E92044A3C60003C045 /* Sources */, - 33CC10EA2044A3C60003C045 /* Frameworks */, - 33CC10EB2044A3C60003C045 /* Resources */, - 33CC110E2044A8840003C045 /* Bundle Framework */, - 3399D490228B24CF009A79C7 /* ShellScript */, - 55A7A0B2944CAC643C309578 /* [CP] Embed Pods Frameworks */, - DD4FADA2786ADD2741453C20 /* [CP] Copy Pods Resources */, - ); - buildRules = ( - ); - dependencies = ( - 33CC11202044C79F0003C045 /* PBXTargetDependency */, - ); - name = Runner; - productName = Runner; - productReference = 33CC10ED2044A3C60003C045 /* mnemo_cards.app */; - productType = "com.apple.product-type.application"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - 33CC10E52044A3C60003C045 /* Project object */ = { - isa = PBXProject; - attributes = { - BuildIndependentTargetsInParallel = YES; - LastSwiftUpdateCheck = 0920; - LastUpgradeCheck = 1510; - ORGANIZATIONNAME = ""; - TargetAttributes = { - 331C80D4294CF70F00263BE5 = { - CreatedOnToolsVersion = 14.0; - TestTargetID = 33CC10EC2044A3C60003C045; - }; - 33CC10EC2044A3C60003C045 = { - CreatedOnToolsVersion = 9.2; - LastSwiftMigration = 1100; - ProvisioningStyle = Automatic; - SystemCapabilities = { - com.apple.Sandbox = { - enabled = 1; - }; - }; - }; - 33CC111A2044C6BA0003C045 = { - CreatedOnToolsVersion = 9.2; - ProvisioningStyle = Manual; - }; - }; - }; - buildConfigurationList = 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */; - compatibilityVersion = "Xcode 9.3"; - developmentRegion = en; - hasScannedForEncodings = 0; - knownRegions = ( - en, - Base, - ); - mainGroup = 33CC10E42044A3C60003C045; - productRefGroup = 33CC10EE2044A3C60003C045 /* Products */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - 33CC10EC2044A3C60003C045 /* Runner */, - 331C80D4294CF70F00263BE5 /* RunnerTests */, - 33CC111A2044C6BA0003C045 /* Flutter Assemble */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXResourcesBuildPhase section */ - 331C80D3294CF70F00263BE5 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 33CC10EB2044A3C60003C045 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */, - 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXResourcesBuildPhase section */ - -/* Begin PBXShellScriptBuildPhase section */ - 3399D490228B24CF009A79C7 /* ShellScript */ = { - isa = PBXShellScriptBuildPhase; - alwaysOutOfDate = 1; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - ); - inputPaths = ( - ); - outputFileListPaths = ( - ); - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "echo \"$PRODUCT_NAME.app\" > \"$PROJECT_DIR\"/Flutter/ephemeral/.app_filename && \"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh embed\n"; - }; - 33CC111E2044C6BF0003C045 /* ShellScript */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - Flutter/ephemeral/FlutterInputs.xcfilelist, - ); - inputPaths = ( - Flutter/ephemeral/tripwire, - ); - outputFileListPaths = ( - Flutter/ephemeral/FlutterOutputs.xcfilelist, - ); - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh && touch Flutter/ephemeral/tripwire"; - }; - 35872747888E30E6A0595C6E /* [CP] Check Pods Manifest.lock */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - ); - inputPaths = ( - "${PODS_PODFILE_DIR_PATH}/Podfile.lock", - "${PODS_ROOT}/Manifest.lock", - ); - name = "[CP] Check Pods Manifest.lock"; - outputFileListPaths = ( - ); - outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-RunnerTests-checkManifestLockResult.txt", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; - showEnvVarsInLog = 0; - }; - 55A7A0B2944CAC643C309578 /* [CP] Embed Pods Frameworks */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", - ); - name = "[CP] Embed Pods Frameworks"; - outputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; - showEnvVarsInLog = 0; - }; - 68BD5ED31F3D4BFE1F803D6F /* [CP] Check Pods Manifest.lock */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - ); - inputPaths = ( - "${PODS_PODFILE_DIR_PATH}/Podfile.lock", - "${PODS_ROOT}/Manifest.lock", - ); - name = "[CP] Check Pods Manifest.lock"; - outputFileListPaths = ( - ); - outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; - showEnvVarsInLog = 0; - }; - DD4FADA2786ADD2741453C20 /* [CP] Copy Pods Resources */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-input-files.xcfilelist", - ); - name = "[CP] Copy Pods Resources"; - outputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-output-files.xcfilelist", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n"; - showEnvVarsInLog = 0; - }; -/* End PBXShellScriptBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - 331C80D1294CF70F00263BE5 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 33CC10E92044A3C60003C045 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */, - 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */, - 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin PBXTargetDependency section */ - 331C80DA294CF71000263BE5 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 33CC10EC2044A3C60003C045 /* Runner */; - targetProxy = 331C80D9294CF71000263BE5 /* PBXContainerItemProxy */; - }; - 33CC11202044C79F0003C045 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 33CC111A2044C6BA0003C045 /* Flutter Assemble */; - targetProxy = 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */; - }; -/* End PBXTargetDependency section */ - -/* Begin PBXVariantGroup section */ - 33CC10F42044A3C60003C045 /* MainMenu.xib */ = { - isa = PBXVariantGroup; - children = ( - 33CC10F52044A3C60003C045 /* Base */, - ); - name = MainMenu.xib; - path = Runner; - sourceTree = ""; - }; -/* End PBXVariantGroup section */ - -/* Begin XCBuildConfiguration section */ - 331C80DB294CF71000263BE5 /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = D3A6E5F779F83D17223F6470 /* Pods-RunnerTests.debug.xcconfig */; - buildSettings = { - BUNDLE_LOADER = "$(TEST_HOST)"; - CURRENT_PROJECT_VERSION = 1; - GENERATE_INFOPLIST_FILE = YES; - MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = com.cinnabarflower.mnemoCards.RunnerTests; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 5.0; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/mnemo_cards.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/mnemo_cards"; - }; - name = Debug; - }; - 331C80DC294CF71000263BE5 /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = FE8B579F30BF0322A9964DB8 /* Pods-RunnerTests.release.xcconfig */; - buildSettings = { - BUNDLE_LOADER = "$(TEST_HOST)"; - CURRENT_PROJECT_VERSION = 1; - GENERATE_INFOPLIST_FILE = YES; - MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = com.cinnabarflower.mnemoCards.RunnerTests; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 5.0; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/mnemo_cards.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/mnemo_cards"; - }; - name = Release; - }; - 331C80DD294CF71000263BE5 /* Profile */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 38C01EEB58A2011E83940B15 /* Pods-RunnerTests.profile.xcconfig */; - buildSettings = { - BUNDLE_LOADER = "$(TEST_HOST)"; - CURRENT_PROJECT_VERSION = 1; - GENERATE_INFOPLIST_FILE = YES; - MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = com.cinnabarflower.mnemoCards.RunnerTests; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 5.0; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/mnemo_cards.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/mnemo_cards"; - }; - name = Profile; - }; - 338D0CE9231458BD00FA5F75 /* Profile */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CODE_SIGN_IDENTITY = "-"; - COPY_PHASE_STRIP = NO; - DEAD_CODE_STRIPPING = YES; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_USER_SCRIPT_SANDBOXING = NO; - GCC_C_LANGUAGE_STANDARD = gnu11; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.15; - MTL_ENABLE_DEBUG_INFO = NO; - SDKROOT = macosx; - SWIFT_COMPILATION_MODE = wholemodule; - SWIFT_OPTIMIZATION_LEVEL = "-O"; - }; - name = Profile; - }; - 338D0CEA231458BD00FA5F75 /* Profile */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ENABLE_MODULES = YES; - CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; - CODE_SIGN_STYLE = Automatic; - COMBINE_HIDPI_IMAGES = YES; - INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/../Frameworks", - ); - PROVISIONING_PROFILE_SPECIFIER = ""; - SWIFT_VERSION = 5.0; - }; - name = Profile; - }; - 338D0CEB231458BD00FA5F75 /* Profile */ = { - isa = XCBuildConfiguration; - buildSettings = { - CODE_SIGN_STYLE = Manual; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Profile; - }; - 33CC10F92044A3C60003C045 /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CODE_SIGN_IDENTITY = "-"; - COPY_PHASE_STRIP = NO; - DEAD_CODE_STRIPPING = YES; - DEBUG_INFORMATION_FORMAT = dwarf; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_TESTABILITY = YES; - ENABLE_USER_SCRIPT_SANDBOXING = NO; - GCC_C_LANGUAGE_STANDARD = gnu11; - GCC_DYNAMIC_NO_PIC = NO; - GCC_NO_COMMON_BLOCKS = YES; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.15; - MTL_ENABLE_DEBUG_INFO = YES; - ONLY_ACTIVE_ARCH = YES; - SDKROOT = macosx; - SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - }; - name = Debug; - }; - 33CC10FA2044A3C60003C045 /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CODE_SIGN_IDENTITY = "-"; - COPY_PHASE_STRIP = NO; - DEAD_CODE_STRIPPING = YES; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_USER_SCRIPT_SANDBOXING = NO; - GCC_C_LANGUAGE_STANDARD = gnu11; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.15; - MTL_ENABLE_DEBUG_INFO = NO; - SDKROOT = macosx; - SWIFT_COMPILATION_MODE = wholemodule; - SWIFT_OPTIMIZATION_LEVEL = "-O"; - }; - name = Release; - }; - 33CC10FC2044A3C60003C045 /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ENABLE_MODULES = YES; - CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; - CODE_SIGN_STYLE = Automatic; - COMBINE_HIDPI_IMAGES = YES; - INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/../Frameworks", - ); - PROVISIONING_PROFILE_SPECIFIER = ""; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 5.0; - }; - name = Debug; - }; - 33CC10FD2044A3C60003C045 /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ENABLE_MODULES = YES; - CODE_SIGN_ENTITLEMENTS = Runner/Release.entitlements; - CODE_SIGN_STYLE = Automatic; - COMBINE_HIDPI_IMAGES = YES; - INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/../Frameworks", - ); - PROVISIONING_PROFILE_SPECIFIER = ""; - SWIFT_VERSION = 5.0; - }; - name = Release; - }; - 33CC111C2044C6BA0003C045 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - CODE_SIGN_STYLE = Manual; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Debug; - }; - 33CC111D2044C6BA0003C045 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - CODE_SIGN_STYLE = Automatic; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 331C80DB294CF71000263BE5 /* Debug */, - 331C80DC294CF71000263BE5 /* Release */, - 331C80DD294CF71000263BE5 /* Profile */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 33CC10F92044A3C60003C045 /* Debug */, - 33CC10FA2044A3C60003C045 /* Release */, - 338D0CE9231458BD00FA5F75 /* Profile */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 33CC10FC2044A3C60003C045 /* Debug */, - 33CC10FD2044A3C60003C045 /* Release */, - 338D0CEA231458BD00FA5F75 /* Profile */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 33CC111C2044C6BA0003C045 /* Debug */, - 33CC111D2044C6BA0003C045 /* Release */, - 338D0CEB231458BD00FA5F75 /* Profile */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - }; - rootObject = 33CC10E52044A3C60003C045 /* Project object */; -} diff --git a/mnemo_cards/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/mnemo_cards/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist deleted file mode 100644 index 18d9810..0000000 --- a/mnemo_cards/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +++ /dev/null @@ -1,8 +0,0 @@ - - - - - IDEDidComputeMac32BitWarning - - - diff --git a/mnemo_cards/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/mnemo_cards/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme deleted file mode 100644 index fa67bc0..0000000 --- a/mnemo_cards/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ /dev/null @@ -1,99 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/mnemo_cards/macos/Runner.xcworkspace/contents.xcworkspacedata b/mnemo_cards/macos/Runner.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index 21a3cc1..0000000 --- a/mnemo_cards/macos/Runner.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - diff --git a/mnemo_cards/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/mnemo_cards/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist deleted file mode 100644 index 18d9810..0000000 --- a/mnemo_cards/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +++ /dev/null @@ -1,8 +0,0 @@ - - - - - IDEDidComputeMac32BitWarning - - - diff --git a/mnemo_cards/macos/Runner/AppDelegate.swift b/mnemo_cards/macos/Runner/AppDelegate.swift deleted file mode 100644 index b3c1761..0000000 --- a/mnemo_cards/macos/Runner/AppDelegate.swift +++ /dev/null @@ -1,13 +0,0 @@ -import Cocoa -import FlutterMacOS - -@main -class AppDelegate: FlutterAppDelegate { - override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { - return true - } - - override func applicationSupportsSecureRestorableState(_ app: NSApplication) -> Bool { - return true - } -} diff --git a/mnemo_cards/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/mnemo_cards/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json deleted file mode 100644 index a2ec33f..0000000 --- a/mnemo_cards/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json +++ /dev/null @@ -1,68 +0,0 @@ -{ - "images" : [ - { - "size" : "16x16", - "idiom" : "mac", - "filename" : "app_icon_16.png", - "scale" : "1x" - }, - { - "size" : "16x16", - "idiom" : "mac", - "filename" : "app_icon_32.png", - "scale" : "2x" - }, - { - "size" : "32x32", - "idiom" : "mac", - "filename" : "app_icon_32.png", - "scale" : "1x" - }, - { - "size" : "32x32", - "idiom" : "mac", - "filename" : "app_icon_64.png", - "scale" : "2x" - }, - { - "size" : "128x128", - "idiom" : "mac", - "filename" : "app_icon_128.png", - "scale" : "1x" - }, - { - "size" : "128x128", - "idiom" : "mac", - "filename" : "app_icon_256.png", - "scale" : "2x" - }, - { - "size" : "256x256", - "idiom" : "mac", - "filename" : "app_icon_256.png", - "scale" : "1x" - }, - { - "size" : "256x256", - "idiom" : "mac", - "filename" : "app_icon_512.png", - "scale" : "2x" - }, - { - "size" : "512x512", - "idiom" : "mac", - "filename" : "app_icon_512.png", - "scale" : "1x" - }, - { - "size" : "512x512", - "idiom" : "mac", - "filename" : "app_icon_1024.png", - "scale" : "2x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} diff --git a/mnemo_cards/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png b/mnemo_cards/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png deleted file mode 100644 index 82b6f9d..0000000 Binary files a/mnemo_cards/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png and /dev/null differ diff --git a/mnemo_cards/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png b/mnemo_cards/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png deleted file mode 100644 index 13b35eb..0000000 Binary files a/mnemo_cards/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png and /dev/null differ diff --git a/mnemo_cards/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png b/mnemo_cards/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png deleted file mode 100644 index 0a3f5fa..0000000 Binary files a/mnemo_cards/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png and /dev/null differ diff --git a/mnemo_cards/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png b/mnemo_cards/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png deleted file mode 100644 index bdb5722..0000000 Binary files a/mnemo_cards/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png and /dev/null differ diff --git a/mnemo_cards/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png b/mnemo_cards/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png deleted file mode 100644 index f083318..0000000 Binary files a/mnemo_cards/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png and /dev/null differ diff --git a/mnemo_cards/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png b/mnemo_cards/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png deleted file mode 100644 index 326c0e7..0000000 Binary files a/mnemo_cards/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png and /dev/null differ diff --git a/mnemo_cards/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png b/mnemo_cards/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png deleted file mode 100644 index 2f1632c..0000000 Binary files a/mnemo_cards/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png and /dev/null differ diff --git a/mnemo_cards/macos/Runner/Base.lproj/MainMenu.xib b/mnemo_cards/macos/Runner/Base.lproj/MainMenu.xib deleted file mode 100644 index 80e867a..0000000 --- a/mnemo_cards/macos/Runner/Base.lproj/MainMenu.xib +++ /dev/null @@ -1,343 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/mnemo_cards/macos/Runner/Configs/AppInfo.xcconfig b/mnemo_cards/macos/Runner/Configs/AppInfo.xcconfig deleted file mode 100644 index 158ae5e..0000000 --- a/mnemo_cards/macos/Runner/Configs/AppInfo.xcconfig +++ /dev/null @@ -1,14 +0,0 @@ -// Application-level settings for the Runner target. -// -// This may be replaced with something auto-generated from metadata (e.g., pubspec.yaml) in the -// future. If not, the values below would default to using the project name when this becomes a -// 'flutter create' template. - -// The application's name. By default this is also the title of the Flutter window. -PRODUCT_NAME = mnemo_cards - -// The application's bundle identifier -PRODUCT_BUNDLE_IDENTIFIER = com.cinnabarflower.mnemoCards - -// The copyright displayed in application information -PRODUCT_COPYRIGHT = Copyright © 2025 com.cinnabarflower. All rights reserved. diff --git a/mnemo_cards/macos/Runner/Configs/Debug.xcconfig b/mnemo_cards/macos/Runner/Configs/Debug.xcconfig deleted file mode 100644 index 36b0fd9..0000000 --- a/mnemo_cards/macos/Runner/Configs/Debug.xcconfig +++ /dev/null @@ -1,2 +0,0 @@ -#include "../../Flutter/Flutter-Debug.xcconfig" -#include "Warnings.xcconfig" diff --git a/mnemo_cards/macos/Runner/Configs/Release.xcconfig b/mnemo_cards/macos/Runner/Configs/Release.xcconfig deleted file mode 100644 index dff4f49..0000000 --- a/mnemo_cards/macos/Runner/Configs/Release.xcconfig +++ /dev/null @@ -1,2 +0,0 @@ -#include "../../Flutter/Flutter-Release.xcconfig" -#include "Warnings.xcconfig" diff --git a/mnemo_cards/macos/Runner/Configs/Warnings.xcconfig b/mnemo_cards/macos/Runner/Configs/Warnings.xcconfig deleted file mode 100644 index 42bcbf4..0000000 --- a/mnemo_cards/macos/Runner/Configs/Warnings.xcconfig +++ /dev/null @@ -1,13 +0,0 @@ -WARNING_CFLAGS = -Wall -Wconditional-uninitialized -Wnullable-to-nonnull-conversion -Wmissing-method-return-type -Woverlength-strings -GCC_WARN_UNDECLARED_SELECTOR = YES -CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES -CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE -CLANG_WARN__DUPLICATE_METHOD_MATCH = YES -CLANG_WARN_PRAGMA_PACK = YES -CLANG_WARN_STRICT_PROTOTYPES = YES -CLANG_WARN_COMMA = YES -GCC_WARN_STRICT_SELECTOR_MATCH = YES -CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES -CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES -GCC_WARN_SHADOW = YES -CLANG_WARN_UNREACHABLE_CODE = YES diff --git a/mnemo_cards/macos/Runner/DebugProfile.entitlements b/mnemo_cards/macos/Runner/DebugProfile.entitlements deleted file mode 100644 index dddb8a3..0000000 --- a/mnemo_cards/macos/Runner/DebugProfile.entitlements +++ /dev/null @@ -1,12 +0,0 @@ - - - - - com.apple.security.app-sandbox - - com.apple.security.cs.allow-jit - - com.apple.security.network.server - - - diff --git a/mnemo_cards/macos/Runner/Info.plist b/mnemo_cards/macos/Runner/Info.plist deleted file mode 100644 index 4789daa..0000000 --- a/mnemo_cards/macos/Runner/Info.plist +++ /dev/null @@ -1,32 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIconFile - - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - APPL - CFBundleShortVersionString - $(FLUTTER_BUILD_NAME) - CFBundleVersion - $(FLUTTER_BUILD_NUMBER) - LSMinimumSystemVersion - $(MACOSX_DEPLOYMENT_TARGET) - NSHumanReadableCopyright - $(PRODUCT_COPYRIGHT) - NSMainNibFile - MainMenu - NSPrincipalClass - NSApplication - - diff --git a/mnemo_cards/macos/Runner/MainFlutterWindow.swift b/mnemo_cards/macos/Runner/MainFlutterWindow.swift deleted file mode 100644 index 3cc05eb..0000000 --- a/mnemo_cards/macos/Runner/MainFlutterWindow.swift +++ /dev/null @@ -1,15 +0,0 @@ -import Cocoa -import FlutterMacOS - -class MainFlutterWindow: NSWindow { - override func awakeFromNib() { - let flutterViewController = FlutterViewController() - let windowFrame = self.frame - self.contentViewController = flutterViewController - self.setFrame(windowFrame, display: true) - - RegisterGeneratedPlugins(registry: flutterViewController) - - super.awakeFromNib() - } -} diff --git a/mnemo_cards/macos/Runner/Release.entitlements b/mnemo_cards/macos/Runner/Release.entitlements deleted file mode 100644 index 852fa1a..0000000 --- a/mnemo_cards/macos/Runner/Release.entitlements +++ /dev/null @@ -1,8 +0,0 @@ - - - - - com.apple.security.app-sandbox - - - diff --git a/mnemo_cards/macos/RunnerTests/RunnerTests.swift b/mnemo_cards/macos/RunnerTests/RunnerTests.swift deleted file mode 100644 index 61f3bd1..0000000 --- a/mnemo_cards/macos/RunnerTests/RunnerTests.swift +++ /dev/null @@ -1,12 +0,0 @@ -import Cocoa -import FlutterMacOS -import XCTest - -class RunnerTests: XCTestCase { - - func testExample() { - // If you add code to the Runner application, consider adding tests here. - // See https://developer.apple.com/documentation/xctest for more information about using XCTest. - } - -} diff --git a/mnemo_cards/patrol.yaml b/mnemo_cards/patrol.yaml deleted file mode 100644 index 2281b36..0000000 --- a/mnemo_cards/patrol.yaml +++ /dev/null @@ -1,61 +0,0 @@ -# Patrol configuration for Mnemo Cards e2e testing -app_name: mnemo_cards -package_name: com.mnemo.cards -bundle_id: com.mnemo.cards - -# Test configuration -test_timeout: 300s -test_retries: 2 - -# Platform-specific settings -android: - app_apk: build/app/outputs/flutter-apk/app-debug.apk - test_apk: build/app/outputs/apk/androidTest/app-debug-androidTest.apk - -ios: - app_bundle: build/ios/iphonesimulator/Runner.app - test_bundle: build/ios/iphonesimulator/RunnerUITests-Runner.app - -# Test directories -test_dirs: - - integration_test/ - - test/e2e/ - -# Environment variables for tests -env: - - FLUTTER_TEST: true - - MNEMO_TEST_MODE: e2e - - API_BASE_URL: http://localhost:8080 - -# Test patterns -test_patterns: - - "**/*_test.dart" - - "**/*_e2e_test.dart" - - "**/*_patrol_test.dart" - -# Reporting -reports: - - format: json - output: debug_report/patrol_report.json - - format: html - output: debug_report/patrol_report.html - - format: junit - output: debug_report/patrol_report.xml - -# Screenshots and videos -screenshots: - enabled: true - directory: debug_report/screenshots/ - -videos: - enabled: true - directory: debug_report/videos/ - -# Performance monitoring -performance: - enabled: true - metrics: - - memory_usage - - cpu_usage - - network_requests - - frame_rate diff --git a/mnemo_cards/pubspec.lock b/mnemo_cards/pubspec.lock deleted file mode 100644 index aed49c9..0000000 --- a/mnemo_cards/pubspec.lock +++ /dev/null @@ -1,1805 +0,0 @@ -# Generated by pub -# See https://dart.dev/tools/pub/glossary#lockfile -packages: - _fe_analyzer_shared: - dependency: transitive - description: - name: _fe_analyzer_shared - sha256: "0b2f2bd91ba804e53a61d757b986f89f1f9eaed5b11e4b2f5a2468d86d6c9fc7" - url: "https://pub.dev" - source: hosted - version: "67.0.0" - _flutterfire_internals: - dependency: transitive - description: - name: _flutterfire_internals - sha256: a5788040810bd84400bc209913fbc40f388cded7cdf95ee2f5d2bff7e38d5241 - url: "https://pub.dev" - source: hosted - version: "1.3.58" - analyzer: - dependency: transitive - description: - name: analyzer - sha256: "37577842a27e4338429a1cbc32679d508836510b056f1eedf0c8d20e39c1383d" - url: "https://pub.dev" - source: hosted - version: "6.4.1" - ansicolor: - dependency: transitive - description: - name: ansicolor - sha256: "50e982d500bc863e1d703448afdbf9e5a72eb48840a4f766fa361ffd6877055f" - url: "https://pub.dev" - source: hosted - version: "2.0.3" - app_links: - dependency: "direct main" - description: - name: app_links - sha256: "85ed8fc1d25a76475914fff28cc994653bd900bc2c26e4b57a49e097febb54ba" - url: "https://pub.dev" - source: hosted - version: "6.4.0" - app_links_linux: - dependency: transitive - description: - name: app_links_linux - sha256: f5f7173a78609f3dfd4c2ff2c95bd559ab43c80a87dc6a095921d96c05688c81 - url: "https://pub.dev" - source: hosted - version: "1.0.3" - app_links_platform_interface: - dependency: transitive - description: - name: app_links_platform_interface - sha256: "05f5379577c513b534a29ddea68176a4d4802c46180ee8e2e966257158772a3f" - url: "https://pub.dev" - source: hosted - version: "2.0.2" - app_links_web: - dependency: transitive - description: - name: app_links_web - sha256: af060ed76183f9e2b87510a9480e56a5352b6c249778d07bd2c95fc35632a555 - url: "https://pub.dev" - source: hosted - version: "1.0.4" - archive: - dependency: "direct main" - description: - name: archive - sha256: cb6a278ef2dbb298455e1a713bda08524a175630ec643a242c399c932a0a1f7d - url: "https://pub.dev" - source: hosted - version: "3.6.1" - args: - dependency: transitive - description: - name: args - sha256: d0481093c50b1da8910eb0bb301626d4d8eb7284aa739614d2b394ee09e3ea04 - url: "https://pub.dev" - source: hosted - version: "2.7.0" - async: - dependency: transitive - description: - name: async - sha256: "758e6d74e971c3e5aceb4110bfd6698efc7f501675bcfe0c775459a8140750eb" - url: "https://pub.dev" - source: hosted - version: "2.13.0" - auto_route: - dependency: "direct main" - description: - name: auto_route - sha256: "1d1bd908a1fec327719326d5d0791edd37f16caff6493c01003689fb03315ad7" - url: "https://pub.dev" - source: hosted - version: "9.3.0+1" - auto_route_generator: - dependency: "direct dev" - description: - name: auto_route_generator - sha256: c9086eb07271e51b44071ad5cff34e889f3156710b964a308c2ab590769e79e6 - url: "https://pub.dev" - source: hosted - version: "9.0.0" - auto_size_text: - dependency: "direct main" - description: - name: auto_size_text - sha256: "3f5261cd3fb5f2a9ab4e2fc3fba84fd9fcaac8821f20a1d4e71f557521b22599" - url: "https://pub.dev" - source: hosted - version: "3.0.0" - bloc: - dependency: transitive - description: - name: bloc - sha256: "52c10575f4445c61dd9e0cafcc6356fdd827c4c64dd7945ef3c4105f6b6ac189" - url: "https://pub.dev" - source: hosted - version: "9.0.0" - boolean_selector: - dependency: transitive - description: - name: boolean_selector - sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea" - url: "https://pub.dev" - source: hosted - version: "2.1.2" - bridge_core: - dependency: "direct main" - description: - path: "../games/packages/bridge_core" - relative: true - source: path - version: "0.0.1" - build: - dependency: transitive - description: - name: build - sha256: "80184af8b6cb3e5c1c4ec6d8544d27711700bc3e6d2efad04238c7b5290889f0" - url: "https://pub.dev" - source: hosted - version: "2.4.1" - build_config: - dependency: transitive - description: - name: build_config - sha256: "4ae2de3e1e67ea270081eaee972e1bd8f027d459f249e0f1186730784c2e7e33" - url: "https://pub.dev" - source: hosted - version: "1.1.2" - build_daemon: - dependency: transitive - description: - name: build_daemon - sha256: "8e928697a82be082206edb0b9c99c5a4ad6bc31c9e9b8b2f291ae65cd4a25daa" - url: "https://pub.dev" - source: hosted - version: "4.0.4" - build_resolvers: - dependency: transitive - description: - name: build_resolvers - sha256: "339086358431fa15d7eca8b6a36e5d783728cf025e559b834f4609a1fcfb7b0a" - url: "https://pub.dev" - source: hosted - version: "2.4.2" - build_runner: - dependency: "direct dev" - description: - name: build_runner - sha256: "028819cfb90051c6b5440c7e574d1896f8037e3c96cf17aaeb054c9311cfbf4d" - url: "https://pub.dev" - source: hosted - version: "2.4.13" - build_runner_core: - dependency: transitive - description: - name: build_runner_core - sha256: f8126682b87a7282a339b871298cc12009cb67109cfa1614d6436fb0289193e0 - url: "https://pub.dev" - source: hosted - version: "7.3.2" - built_collection: - dependency: transitive - description: - name: built_collection - sha256: "376e3dd27b51ea877c28d525560790aee2e6fbb5f20e2f85d5081027d94e2100" - url: "https://pub.dev" - source: hosted - version: "5.1.1" - built_value: - dependency: transitive - description: - name: built_value - sha256: "0b1b12a0a549605e5f04476031cd0bc91ead1d7c8e830773a18ee54179b3cb62" - url: "https://pub.dev" - source: hosted - version: "8.11.0" - characters: - dependency: transitive - description: - name: characters - sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803 - url: "https://pub.dev" - source: hosted - version: "1.4.0" - checked_yaml: - dependency: transitive - description: - name: checked_yaml - sha256: "959525d3162f249993882720d52b7e0c833978df229be20702b33d48d91de70f" - url: "https://pub.dev" - source: hosted - version: "2.0.4" - cli_util: - dependency: transitive - description: - name: cli_util - sha256: ff6785f7e9e3c38ac98b2fb035701789de90154024a75b6cb926445e83197d1c - url: "https://pub.dev" - source: hosted - version: "0.4.2" - clock: - dependency: transitive - description: - name: clock - sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b - url: "https://pub.dev" - source: hosted - version: "1.1.2" - cloud_firestore: - dependency: "direct main" - description: - name: cloud_firestore - sha256: "39be8bf17e55d1211d8e2142ba1551bbcf30e272fe90adb36d54a9b1ae97bd30" - url: "https://pub.dev" - source: hosted - version: "5.6.11" - cloud_firestore_platform_interface: - dependency: transitive - description: - name: cloud_firestore_platform_interface - sha256: a8a1ce4f8da07225b8fe37ee3eeff3bde019e0607bab93329091f5491ee2f62f - url: "https://pub.dev" - source: hosted - version: "6.6.11" - cloud_firestore_web: - dependency: transitive - description: - name: cloud_firestore_web - sha256: a3c0c5913860abfa0c9af68e245feb24d51ffebf07910780efc0d01ac463dc92 - url: "https://pub.dev" - source: hosted - version: "4.4.11" - code_builder: - dependency: transitive - description: - name: code_builder - sha256: "0ec10bf4a89e4c613960bf1e8b42c64127021740fb21640c29c909826a5eea3e" - url: "https://pub.dev" - source: hosted - version: "4.10.1" - collection: - dependency: "direct main" - description: - name: collection - sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76" - url: "https://pub.dev" - source: hosted - version: "1.19.1" - convert: - dependency: transitive - description: - name: convert - sha256: b30acd5944035672bc15c6b7a8b47d773e41e2f17de064350988c5d02adb1c68 - url: "https://pub.dev" - source: hosted - version: "3.1.2" - copy_with_extension: - dependency: "direct main" - description: - name: copy_with_extension - sha256: fbcf890b0c34aedf0894f91a11a579994b61b4e04080204656b582708b5b1125 - url: "https://pub.dev" - source: hosted - version: "5.0.4" - copy_with_extension_gen: - dependency: "direct main" - description: - name: copy_with_extension_gen - sha256: "51cd11094096d40824c8da629ca7f16f3b7cea5fc44132b679617483d43346b0" - url: "https://pub.dev" - source: hosted - version: "5.0.4" - cross_file: - dependency: transitive - description: - name: cross_file - sha256: "7caf6a750a0c04effbb52a676dce9a4a592e10ad35c34d6d2d0e4811160d5670" - url: "https://pub.dev" - source: hosted - version: "0.3.4+2" - crypto: - dependency: transitive - description: - name: crypto - sha256: "1e445881f28f22d6140f181e07737b22f1e099a5e1ff94b0af2f9e4a463f4855" - url: "https://pub.dev" - source: hosted - version: "3.0.6" - csslib: - dependency: transitive - description: - name: csslib - sha256: "09bad715f418841f976c77db72d5398dc1253c21fb9c0c7f0b0b985860b2d58e" - url: "https://pub.dev" - source: hosted - version: "1.0.2" - cupertino_icons: - dependency: "direct main" - description: - name: cupertino_icons - sha256: ba631d1c7f7bef6b729a622b7b752645a2d076dba9976925b8f25725a30e1ee6 - url: "https://pub.dev" - source: hosted - version: "1.0.8" - dart_style: - dependency: transitive - description: - name: dart_style - sha256: "99e066ce75c89d6b29903d788a7bb9369cf754f7b24bf70bf4b6d6d6b26853b9" - url: "https://pub.dev" - source: hosted - version: "2.3.6" - dbus: - dependency: transitive - description: - name: dbus - sha256: "79e0c23480ff85dc68de79e2cd6334add97e48f7f4865d17686dd6ea81a47e8c" - url: "https://pub.dev" - source: hosted - version: "0.7.11" - device_info_plus: - dependency: "direct main" - description: - name: device_info_plus - sha256: a7fd703482b391a87d60b6061d04dfdeab07826b96f9abd8f5ed98068acc0074 - url: "https://pub.dev" - source: hosted - version: "10.1.2" - device_info_plus_platform_interface: - dependency: transitive - description: - name: device_info_plus_platform_interface - sha256: e1ea89119e34903dca74b883d0dd78eb762814f97fb6c76f35e9ff74d261a18f - url: "https://pub.dev" - source: hosted - version: "7.0.3" - dio: - dependency: "direct main" - description: - name: dio - sha256: "253a18bbd4851fecba42f7343a1df3a9a4c1d31a2c1b37e221086b4fa8c8dbc9" - url: "https://pub.dev" - source: hosted - version: "5.8.0+1" - dio_web_adapter: - dependency: transitive - description: - name: dio_web_adapter - sha256: "7586e476d70caecaf1686d21eee7247ea43ef5c345eab9e0cc3583ff13378d78" - url: "https://pub.dev" - source: hosted - version: "2.1.1" - dispose_scope: - dependency: transitive - description: - name: dispose_scope - sha256: "48ec38ca2631c53c4f8fa96b294c801e55c335db5e3fb9f82cede150cfe5a2af" - url: "https://pub.dev" - source: hosted - version: "2.1.0" - dot_navigation_bar: - dependency: "direct main" - description: - name: dot_navigation_bar - sha256: "753e1d91644e39beddd0a4ed7e366f37a95e38cafb601c3b7496120ae0532f63" - url: "https://pub.dev" - source: hosted - version: "1.0.2" - equatable: - dependency: transitive - description: - name: equatable - sha256: "567c64b3cb4cf82397aac55f4f0cbd3ca20d77c6c03bedbc4ceaddc08904aef7" - url: "https://pub.dev" - source: hosted - version: "2.0.7" - extended_image: - dependency: transitive - description: - name: extended_image - sha256: f6cbb1d798f51262ed1a3d93b4f1f2aa0d76128df39af18ecb77fa740f88b2e0 - url: "https://pub.dev" - source: hosted - version: "10.0.1" - extended_image_library: - dependency: transitive - description: - name: extended_image_library - sha256: "1f9a24d3a00c2633891c6a7b5cab2807999eb2d5b597e5133b63f49d113811fe" - url: "https://pub.dev" - source: hosted - version: "5.0.1" - fake_async: - dependency: transitive - description: - name: fake_async - sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44" - url: "https://pub.dev" - source: hosted - version: "1.3.3" - ffi: - dependency: transitive - description: - name: ffi - sha256: "289279317b4b16eb2bb7e271abccd4bf84ec9bdcbe999e278a94b804f5630418" - url: "https://pub.dev" - source: hosted - version: "2.1.4" - file: - dependency: transitive - description: - name: file - sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4 - url: "https://pub.dev" - source: hosted - version: "7.0.1" - file_picker: - dependency: "direct main" - description: - name: file_picker - sha256: ef9908739bdd9c476353d6adff72e88fd00c625f5b959ae23f7567bd5137db0a - url: "https://pub.dev" - source: hosted - version: "10.2.0" - firebase_analytics: - dependency: "direct main" - description: - name: firebase_analytics - sha256: "178b0275c0b3a53daf3350757856fee4fadc8e324f5fddbc86a1b939074f903b" - url: "https://pub.dev" - source: hosted - version: "11.5.2" - firebase_analytics_platform_interface: - dependency: transitive - description: - name: firebase_analytics_platform_interface - sha256: "13ed951a99a53da0c38e9991e077b0c8b8b739e77ed7933a6942e275874d571a" - url: "https://pub.dev" - source: hosted - version: "4.4.2" - firebase_analytics_web: - dependency: transitive - description: - name: firebase_analytics_web - sha256: a9d6323b2bd7c2b5189088070ead0dfc8b16cf79e8603a1fc7fe4d661de0d123 - url: "https://pub.dev" - source: hosted - version: "0.5.10+15" - firebase_core: - dependency: transitive - description: - name: firebase_core - sha256: c6e8a6bf883d8ddd0dec39be90872daca65beaa6f4cff0051ed3b16c56b82e9f - url: "https://pub.dev" - source: hosted - version: "3.15.1" - firebase_core_platform_interface: - dependency: transitive - description: - name: firebase_core_platform_interface - sha256: "5dbc900677dcbe5873d22ad7fbd64b047750124f1f9b7ebe2a33b9ddccc838eb" - url: "https://pub.dev" - source: hosted - version: "6.0.0" - firebase_core_web: - dependency: transitive - description: - name: firebase_core_web - sha256: "0ed0dc292e8f9ac50992e2394e9d336a0275b6ae400d64163fdf0a8a8b556c37" - url: "https://pub.dev" - source: hosted - version: "2.24.1" - firebase_crashlytics: - dependency: "direct main" - description: - name: firebase_crashlytics - sha256: c441c40317bbea4380ee6b0df83bdb408e9000f7f9ebbc683f9ed71c366f0a97 - url: "https://pub.dev" - source: hosted - version: "4.3.9" - firebase_crashlytics_platform_interface: - dependency: transitive - description: - name: firebase_crashlytics_platform_interface - sha256: bb948241a48d497bf39af5cf19b0d9b28bb6b26274164141a203ff3c3202d41b - url: "https://pub.dev" - source: hosted - version: "3.8.9" - firebase_messaging: - dependency: "direct main" - description: - name: firebase_messaging - sha256: "0f3363f97672eb9f65609fa00ed2f62cc8ec93e7e2d4def99726f9165d3d8a73" - url: "https://pub.dev" - source: hosted - version: "15.2.9" - firebase_messaging_platform_interface: - dependency: transitive - description: - name: firebase_messaging_platform_interface - sha256: "7a05ef119a14c5f6a9440d1e0223bcba20c8daf555450e119c4c477bf2c3baa9" - url: "https://pub.dev" - source: hosted - version: "4.6.9" - firebase_messaging_web: - dependency: transitive - description: - name: firebase_messaging_web - sha256: a4547f76da2a905190f899eb4d0150e1d0fd52206fce469d9f05ae15bb68b2c5 - url: "https://pub.dev" - source: hosted - version: "3.10.9" - firebase_remote_config: - dependency: "direct main" - description: - name: firebase_remote_config - sha256: acd93f72cbfc49b43ccf5eb114aecfe8be0720a0f2e7a1d8d4bd5b206ffdf8ac - url: "https://pub.dev" - source: hosted - version: "5.4.7" - firebase_remote_config_platform_interface: - dependency: transitive - description: - name: firebase_remote_config_platform_interface - sha256: "8c21aa8723e605f4a35805b105145c7edf50df391b3d05a4dadc3b921aa6aec2" - url: "https://pub.dev" - source: hosted - version: "1.5.7" - firebase_remote_config_web: - dependency: transitive - description: - name: firebase_remote_config_web - sha256: b2400ed56197ac43493a19c0468a325bded97f0bd5b064042c189c4a658f6674 - url: "https://pub.dev" - source: hosted - version: "1.8.7" - fixnum: - dependency: transitive - description: - name: fixnum - sha256: b6dc7065e46c974bc7c5f143080a6764ec7a4be6da1285ececdc37be96de53be - url: "https://pub.dev" - source: hosted - version: "1.1.1" - fl_chart: - dependency: "direct main" - description: - name: fl_chart - sha256: d0f0d49112f2f4b192481c16d05b6418bd7820e021e265a3c22db98acf7ed7fb - url: "https://pub.dev" - source: hosted - version: "0.68.0" - flutter: - dependency: "direct main" - description: flutter - source: sdk - version: "0.0.0" - flutter_bloc: - dependency: "direct main" - description: - name: flutter_bloc - sha256: cf51747952201a455a1c840f8171d273be009b932c75093020f9af64f2123e38 - url: "https://pub.dev" - source: hosted - version: "9.1.1" - flutter_colorpicker: - dependency: "direct main" - description: - name: flutter_colorpicker - sha256: "969de5f6f9e2a570ac660fb7b501551451ea2a1ab9e2097e89475f60e07816ea" - url: "https://pub.dev" - source: hosted - version: "1.1.0" - flutter_driver: - dependency: transitive - description: flutter - source: sdk - version: "0.0.0" - flutter_launcher_icons: - dependency: "direct dev" - description: - name: flutter_launcher_icons - sha256: "10f13781741a2e3972126fae08393d3c4e01fa4cd7473326b94b72cf594195e7" - url: "https://pub.dev" - source: hosted - version: "0.14.4" - flutter_lints: - dependency: "direct dev" - description: - name: flutter_lints - sha256: "3105dc8492f6183fb076ccf1f351ac3d60564bff92e20bfc4af9cc1651f4e7e1" - url: "https://pub.dev" - source: hosted - version: "6.0.0" - flutter_local_notifications: - dependency: "direct main" - description: - name: flutter_local_notifications - sha256: "81350df6cb90196390b0b175c645968620d508a4fc9db5996215a1cfa4135a03" - url: "https://pub.dev" - source: hosted - version: "19.3.1" - flutter_local_notifications_linux: - dependency: transitive - description: - name: flutter_local_notifications_linux - sha256: e3c277b2daab8e36ac5a6820536668d07e83851aeeb79c446e525a70710770a5 - url: "https://pub.dev" - source: hosted - version: "6.0.0" - flutter_local_notifications_platform_interface: - dependency: transitive - description: - name: flutter_local_notifications_platform_interface - sha256: "277d25d960c15674ce78ca97f57d0bae2ee401c844b6ac80fcd972a9c99d09fe" - url: "https://pub.dev" - source: hosted - version: "9.1.0" - flutter_local_notifications_windows: - dependency: transitive - description: - name: flutter_local_notifications_windows - sha256: ed46d7ae4ec9d19e4c8fa2badac5fe27ba87a3fe387343ce726f927af074ec98 - url: "https://pub.dev" - source: hosted - version: "1.0.2" - flutter_native_splash: - dependency: "direct dev" - description: - name: flutter_native_splash - sha256: "7062602e0dbd29141fb8eb19220b5871ca650be5197ab9c1f193a28b17537bc7" - url: "https://pub.dev" - source: hosted - version: "2.4.4" - flutter_plugin_android_lifecycle: - dependency: transitive - description: - name: flutter_plugin_android_lifecycle - sha256: f948e346c12f8d5480d2825e03de228d0eb8c3a737e4cdaa122267b89c022b5e - url: "https://pub.dev" - source: hosted - version: "2.0.28" - flutter_screenutil: - dependency: "direct main" - description: - name: flutter_screenutil - sha256: "8239210dd68bee6b0577aa4a090890342d04a136ce1c81f98ee513fc0ce891de" - url: "https://pub.dev" - source: hosted - version: "5.9.3" - flutter_secure_storage: - dependency: "direct main" - description: - name: flutter_secure_storage - sha256: "9cad52d75ebc511adfae3d447d5d13da15a55a92c9410e50f67335b6d21d16ea" - url: "https://pub.dev" - source: hosted - version: "9.2.4" - flutter_secure_storage_linux: - dependency: transitive - description: - name: flutter_secure_storage_linux - sha256: be76c1d24a97d0b98f8b54bce6b481a380a6590df992d0098f868ad54dc8f688 - url: "https://pub.dev" - source: hosted - version: "1.2.3" - flutter_secure_storage_macos: - dependency: transitive - description: - name: flutter_secure_storage_macos - sha256: "6c0a2795a2d1de26ae202a0d78527d163f4acbb11cde4c75c670f3a0fc064247" - url: "https://pub.dev" - source: hosted - version: "3.1.3" - flutter_secure_storage_platform_interface: - dependency: transitive - description: - name: flutter_secure_storage_platform_interface - sha256: cf91ad32ce5adef6fba4d736a542baca9daf3beac4db2d04be350b87f69ac4a8 - url: "https://pub.dev" - source: hosted - version: "1.1.2" - flutter_secure_storage_web: - dependency: transitive - description: - name: flutter_secure_storage_web - sha256: f4ebff989b4f07b2656fb16b47852c0aab9fed9b4ec1c70103368337bc1886a9 - url: "https://pub.dev" - source: hosted - version: "1.2.1" - flutter_secure_storage_windows: - dependency: transitive - description: - name: flutter_secure_storage_windows - sha256: b20b07cb5ed4ed74fc567b78a72936203f587eba460af1df11281c9326cd3709 - url: "https://pub.dev" - source: hosted - version: "3.1.2" - flutter_svg: - dependency: transitive - description: - name: flutter_svg - sha256: cd57f7969b4679317c17af6fd16ee233c1e60a82ed209d8a475c54fd6fd6f845 - url: "https://pub.dev" - source: hosted - version: "2.2.0" - flutter_test: - dependency: "direct dev" - description: flutter - source: sdk - version: "0.0.0" - flutter_tts: - dependency: "direct main" - description: - name: flutter_tts - sha256: bdf2fc4483e74450dc9fc6fe6a9b6a5663e108d4d0dad3324a22c8e26bf48af4 - url: "https://pub.dev" - source: hosted - version: "4.2.3" - flutter_web_plugins: - dependency: transitive - description: flutter - source: sdk - version: "0.0.0" - flutter_widget_from_html_core: - dependency: "direct main" - description: - name: flutter_widget_from_html_core - sha256: "1120ee6ed3509ceff2d55aa6c6cbc7b6b1291434422de2411b5a59364dd6ff03" - url: "https://pub.dev" - source: hosted - version: "0.17.0" - freezed_annotation: - dependency: transitive - description: - name: freezed_annotation - sha256: c2e2d632dd9b8a2b7751117abcfc2b4888ecfe181bd9fca7170d9ef02e595fe2 - url: "https://pub.dev" - source: hosted - version: "2.4.4" - frontend_server_client: - dependency: transitive - description: - name: frontend_server_client - sha256: f64a0333a82f30b0cca061bc3d143813a486dc086b574bfb233b7c1372427694 - url: "https://pub.dev" - source: hosted - version: "4.0.0" - fuchsia_remote_debug_protocol: - dependency: transitive - description: flutter - source: sdk - version: "0.0.0" - get_it: - dependency: "direct main" - description: - name: get_it - sha256: f126a3e286b7f5b578bf436d5592968706c4c1de28a228b870ce375d9f743103 - url: "https://pub.dev" - source: hosted - version: "8.0.3" - glob: - dependency: transitive - description: - name: glob - sha256: c3f1ee72c96f8f78935e18aa8cecced9ab132419e8625dc187e1c2408efc20de - url: "https://pub.dev" - source: hosted - version: "2.1.3" - google_identity_services_web: - dependency: transitive - description: - name: google_identity_services_web - sha256: "5d187c46dc59e02646e10fe82665fc3884a9b71bc1c90c2b8b749316d33ee454" - url: "https://pub.dev" - source: hosted - version: "0.3.3+1" - google_sign_in: - dependency: "direct main" - description: - name: google_sign_in - sha256: "939a8b58f84c4053811b8c1bc9adbcb59449a15b37958264bbf60020698cca0e" - url: "https://pub.dev" - source: hosted - version: "7.1.1" - google_sign_in_android: - dependency: transitive - description: - name: google_sign_in_android - sha256: "8cb9bc7ab17e4514cf0f682fa391768eb5df23fd03c54eed73bbd5352980f3c3" - url: "https://pub.dev" - source: hosted - version: "7.0.2" - google_sign_in_ios: - dependency: transitive - description: - name: google_sign_in_ios - sha256: "44032e86ecff2d4ba4671f26f8dbecd2ca52cdbcc4458525191b8889b3b10ea3" - url: "https://pub.dev" - source: hosted - version: "6.0.1" - google_sign_in_platform_interface: - dependency: transitive - description: - name: google_sign_in_platform_interface - sha256: "8736443134d2cccadd4f228d600177cb3947e36683466a6ab96877ce6932885a" - url: "https://pub.dev" - source: hosted - version: "3.0.0" - google_sign_in_web: - dependency: transitive - description: - name: google_sign_in_web - sha256: "09ac306b2787b48f19c857b9f93375b654f774643c75bd6a1a078c85f4f7b468" - url: "https://pub.dev" - source: hosted - version: "1.0.0" - graphs: - dependency: transitive - description: - name: graphs - sha256: "741bbf84165310a68ff28fe9e727332eef1407342fca52759cb21ad8177bb8d0" - url: "https://pub.dev" - source: hosted - version: "2.3.2" - gtk: - dependency: transitive - description: - name: gtk - sha256: e8ce9ca4b1df106e4d72dad201d345ea1a036cc12c360f1a7d5a758f78ffa42c - url: "https://pub.dev" - source: hosted - version: "2.1.0" - html: - dependency: transitive - description: - name: html - sha256: "6d1264f2dffa1b1101c25a91dff0dc2daee4c18e87cd8538729773c073dbf602" - url: "https://pub.dev" - source: hosted - version: "0.15.6" - http: - dependency: transitive - description: - name: http - sha256: "2c11f3f94c687ee9bad77c171151672986360b2b001d109814ee7140b2cf261b" - url: "https://pub.dev" - source: hosted - version: "1.4.0" - http_certificate_pinning: - dependency: transitive - description: - name: http_certificate_pinning - sha256: "1501c69142a3906a5ad4876d7e71696fa6a6a187fc6f4a746d7a5ba32f9f8fcf" - url: "https://pub.dev" - source: hosted - version: "3.0.1" - http_client_helper: - dependency: transitive - description: - name: http_client_helper - sha256: "8a9127650734da86b5c73760de2b404494c968a3fd55602045ffec789dac3cb1" - url: "https://pub.dev" - source: hosted - version: "3.0.0" - http_multi_server: - dependency: transitive - description: - name: http_multi_server - sha256: aa6199f908078bb1c5efb8d8638d4ae191aac11b311132c3ef48ce352fb52ef8 - url: "https://pub.dev" - source: hosted - version: "3.2.2" - http_parser: - dependency: transitive - description: - name: http_parser - sha256: "178d74305e7866013777bab2c3d8726205dc5a4dd935297175b19a23a2e66571" - url: "https://pub.dev" - source: hosted - version: "4.1.2" - image: - dependency: transitive - description: - name: image - sha256: f31d52537dc417fdcde36088fdf11d191026fd5e4fae742491ebd40e5a8bea7d - url: "https://pub.dev" - source: hosted - version: "4.3.0" - in_app_purchase: - dependency: "direct main" - description: - name: in_app_purchase - sha256: "5cddd7f463f3bddb1d37a72b95066e840d5822d66291331d7f8f05ce32c24b6c" - url: "https://pub.dev" - source: hosted - version: "3.2.3" - in_app_purchase_android: - dependency: "direct main" - description: - name: in_app_purchase_android - sha256: fd76e5612da6facadcfe8a3477da092908227260a9f6ec7db9a66dd989c69b02 - url: "https://pub.dev" - source: hosted - version: "0.4.0+2" - in_app_purchase_platform_interface: - dependency: transitive - description: - name: in_app_purchase_platform_interface - sha256: "1d353d38251da5b9fea6635c0ebfc6bb17a2d28d0e86ea5e083bf64244f1fb4c" - url: "https://pub.dev" - source: hosted - version: "1.4.0" - in_app_purchase_storekit: - dependency: transitive - description: - name: in_app_purchase_storekit - sha256: a9bc29f5e67701192cc6ea2c4dc99efc1f25fcdc63e052af9b271d479626319b - url: "https://pub.dev" - source: hosted - version: "0.4.3" - injectable: - dependency: transitive - description: - name: injectable - sha256: "5e1556ea1d374fe44cbe846414d9bab346285d3d8a1da5877c01ad0774006068" - url: "https://pub.dev" - source: hosted - version: "2.5.0" - injectable_generator: - dependency: "direct dev" - description: - name: injectable_generator - sha256: af403d76c7b18b4217335e0075e950cd0579fd7f8d7bd47ee7c85ada31680ba1 - url: "https://pub.dev" - source: hosted - version: "2.6.2" - integration_test: - dependency: "direct dev" - description: flutter - source: sdk - version: "0.0.0" - io: - dependency: transitive - description: - name: io - sha256: dfd5a80599cf0165756e3181807ed3e77daf6dd4137caaad72d0b7931597650b - url: "https://pub.dev" - source: hosted - version: "1.0.5" - jailbreak_root_detection: - dependency: "direct main" - description: - name: jailbreak_root_detection - sha256: c611229940a09785bd686364e92a40b07724926d2496c931527805101eb3da86 - url: "https://pub.dev" - source: hosted - version: "1.1.6" - js: - dependency: transitive - description: - name: js - sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3 - url: "https://pub.dev" - source: hosted - version: "0.6.7" - json_annotation: - dependency: "direct main" - description: - name: json_annotation - sha256: "1ce844379ca14835a50d2f019a3099f419082cfdd231cd86a142af94dd5c6bb1" - url: "https://pub.dev" - source: hosted - version: "4.9.0" - json_serializable: - dependency: "direct main" - description: - name: json_serializable - sha256: ea1432d167339ea9b5bb153f0571d0039607a873d6e04e0117af043f14a1fd4b - url: "https://pub.dev" - source: hosted - version: "6.8.0" - leak_tracker: - dependency: transitive - description: - name: leak_tracker - sha256: "33e2e26bdd85a0112ec15400c8cbffea70d0f9c3407491f672a2fad47915e2de" - url: "https://pub.dev" - source: hosted - version: "11.0.2" - leak_tracker_flutter_testing: - dependency: transitive - description: - name: leak_tracker_flutter_testing - sha256: "1dbc140bb5a23c75ea9c4811222756104fbcd1a27173f0c34ca01e16bea473c1" - url: "https://pub.dev" - source: hosted - version: "3.0.10" - leak_tracker_testing: - dependency: transitive - description: - name: leak_tracker_testing - sha256: "8d5a2d49f4a66b49744b23b018848400d23e54caf9463f4eb20df3eb8acb2eb1" - url: "https://pub.dev" - source: hosted - version: "3.0.2" - lints: - dependency: transitive - description: - name: lints - sha256: a5e2b223cb7c9c8efdc663ef484fdd95bb243bff242ef5b13e26883547fce9a0 - url: "https://pub.dev" - source: hosted - version: "6.0.0" - logging: - dependency: transitive - description: - name: logging - sha256: c8245ada5f1717ed44271ed1c26b8ce85ca3228fd2ffdb75468ab01979309d61 - url: "https://pub.dev" - source: hosted - version: "1.3.0" - matcher: - dependency: transitive - description: - name: matcher - sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2 - url: "https://pub.dev" - source: hosted - version: "0.12.17" - material_color_utilities: - dependency: transitive - description: - name: material_color_utilities - sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec - url: "https://pub.dev" - source: hosted - version: "0.11.1" - meta: - dependency: transitive - description: - name: meta - sha256: e3641ec5d63ebf0d9b41bd43201a66e3fc79a65db5f61fc181f04cd27aab950c - url: "https://pub.dev" - source: hosted - version: "1.16.0" - mime: - dependency: transitive - description: - name: mime - sha256: "41a20518f0cb1256669420fdba0cd90d21561e560ac240f26ef8322e45bb7ed6" - url: "https://pub.dev" - source: hosted - version: "2.0.0" - mnemo_cards_common: - dependency: "direct main" - description: - path: "../mnemo_cards_common" - relative: true - source: path - version: "0.0.1" - mnemo_cards_frontend_common: - dependency: "direct main" - description: - path: "../mnemo_cards_frontend_common" - relative: true - source: path - version: "0.0.1" - mutex: - dependency: "direct main" - description: - name: mutex - sha256: "8827da25de792088eb33e572115a5eb0d61d61a3c01acbc8bcbe76ed78f1a1f2" - url: "https://pub.dev" - source: hosted - version: "3.1.0" - nested: - dependency: transitive - description: - name: nested - sha256: "03bac4c528c64c95c722ec99280375a6f2fc708eec17c7b3f07253b626cd2a20" - url: "https://pub.dev" - source: hosted - version: "1.0.0" - no_screenshot: - dependency: "direct main" - description: - name: no_screenshot - sha256: ec3d86d7ee89a09c3a3939c1003012536ba4b3fcb4f8cbd23d87ada595c99258 - url: "https://pub.dev" - source: hosted - version: "0.3.1" - package_config: - dependency: transitive - description: - name: package_config - sha256: f096c55ebb7deb7e384101542bfba8c52696c1b56fca2eb62827989ef2353bbc - url: "https://pub.dev" - source: hosted - version: "2.2.0" - package_info_plus: - dependency: "direct main" - description: - name: package_info_plus - sha256: "7976bfe4c583170d6cdc7077e3237560b364149fcd268b5f53d95a991963b191" - url: "https://pub.dev" - source: hosted - version: "8.3.0" - package_info_plus_platform_interface: - dependency: transitive - description: - name: package_info_plus_platform_interface - sha256: "6c935fb612dff8e3cc9632c2b301720c77450a126114126ffaafe28d2e87956c" - url: "https://pub.dev" - source: hosted - version: "3.2.0" - path: - dependency: transitive - description: - name: path - sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5" - url: "https://pub.dev" - source: hosted - version: "1.9.1" - path_parsing: - dependency: transitive - description: - name: path_parsing - sha256: "883402936929eac138ee0a45da5b0f2c80f89913e6dc3bf77eb65b84b409c6ca" - url: "https://pub.dev" - source: hosted - version: "1.1.0" - path_provider: - dependency: "direct main" - description: - name: path_provider - sha256: "50c5dd5b6e1aaf6fb3a78b33f6aa3afca52bf903a8a5298f53101fdaee55bbcd" - url: "https://pub.dev" - source: hosted - version: "2.1.5" - path_provider_android: - dependency: transitive - description: - name: path_provider_android - sha256: d0d310befe2c8ab9e7f393288ccbb11b60c019c6b5afc21973eeee4dda2b35e9 - url: "https://pub.dev" - source: hosted - version: "2.2.17" - path_provider_foundation: - dependency: transitive - description: - name: path_provider_foundation - sha256: "4843174df4d288f5e29185bd6e72a6fbdf5a4a4602717eed565497429f179942" - url: "https://pub.dev" - source: hosted - version: "2.4.1" - path_provider_linux: - dependency: transitive - description: - name: path_provider_linux - sha256: f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279 - url: "https://pub.dev" - source: hosted - version: "2.2.1" - path_provider_platform_interface: - dependency: transitive - description: - name: path_provider_platform_interface - sha256: "88f5779f72ba699763fa3a3b06aa4bf6de76c8e5de842cf6f29e2e06476c2334" - url: "https://pub.dev" - source: hosted - version: "2.1.2" - path_provider_windows: - dependency: transitive - description: - name: path_provider_windows - sha256: bd6f00dbd873bfb70d0761682da2b3a2c2fccc2b9e84c495821639601d81afe7 - url: "https://pub.dev" - source: hosted - version: "2.3.0" - patrol: - dependency: "direct dev" - description: - name: patrol - sha256: "782988d05af24427296e48417c36c520598656e00ba73c401a19ecd65262ee0b" - url: "https://pub.dev" - source: hosted - version: "3.35.5" - patrol_finders: - dependency: transitive - description: - name: patrol_finders - sha256: "4a658d7d560de523f92deb3fa3326c78747ca0bf7e7f4b8788c012463138b628" - url: "https://pub.dev" - source: hosted - version: "2.9.0" - patrol_log: - dependency: transitive - description: - name: patrol_log - sha256: "9fed4143980df1e3bbcfa00d0b443c7d68f04f9132317b7698bbc37f8a5a58c5" - url: "https://pub.dev" - source: hosted - version: "0.5.0" - payloads_shared: - dependency: "direct main" - description: - path: "../games/packages/payloads_shared" - relative: true - source: path - version: "0.0.1" - petitparser: - dependency: transitive - description: - name: petitparser - sha256: "07c8f0b1913bcde1ff0d26e57ace2f3012ccbf2b204e070290dad3bb22797646" - url: "https://pub.dev" - source: hosted - version: "6.1.0" - platform: - dependency: transitive - description: - name: platform - sha256: "5d6b1b0036a5f331ebc77c850ebc8506cbc1e9416c27e59b439f917a902a4984" - url: "https://pub.dev" - source: hosted - version: "3.1.6" - plugin_platform_interface: - dependency: transitive - description: - name: plugin_platform_interface - sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02" - url: "https://pub.dev" - source: hosted - version: "2.1.8" - pool: - dependency: transitive - description: - name: pool - sha256: "20fe868b6314b322ea036ba325e6fc0711a22948856475e2c2b6306e8ab39c2a" - url: "https://pub.dev" - source: hosted - version: "1.5.1" - process: - dependency: transitive - description: - name: process - sha256: "107d8be718f120bbba9dcd1e95e3bd325b1b4a4f07db64154635ba03f2567a0d" - url: "https://pub.dev" - source: hosted - version: "5.0.3" - provider: - dependency: transitive - description: - name: provider - sha256: "4abbd070a04e9ddc287673bf5a030c7ca8b685ff70218720abab8b092f53dd84" - url: "https://pub.dev" - source: hosted - version: "6.1.5" - pub_semver: - dependency: transitive - description: - name: pub_semver - sha256: "5bfcf68ca79ef689f8990d1160781b4bad40a3bd5e5218ad4076ddb7f4081585" - url: "https://pub.dev" - source: hosted - version: "2.2.0" - pubspec_parse: - dependency: transitive - description: - name: pubspec_parse - sha256: "0560ba233314abbed0a48a2956f7f022cce7c3e1e73df540277da7544cad4082" - url: "https://pub.dev" - source: hosted - version: "1.5.0" - recase: - dependency: transitive - description: - name: recase - sha256: e4eb4ec2dcdee52dcf99cb4ceabaffc631d7424ee55e56f280bc039737f89213 - url: "https://pub.dev" - source: hosted - version: "4.1.0" - reorderables: - dependency: "direct main" - description: - name: reorderables - sha256: "004a886e4878df1ee27321831c838bc1c976311f4ca6a74ce7d561e506540a77" - url: "https://pub.dev" - source: hosted - version: "0.6.0" - retrofit: - dependency: transitive - description: - name: retrofit - sha256: "84d70114a5b6bae5f4c1302335f9cb610ebeb1b02023d5e7e87697aaff52926a" - url: "https://pub.dev" - source: hosted - version: "4.6.0" - rxdart: - dependency: "direct main" - description: - name: rxdart - sha256: "5c3004a4a8dbb94bd4bf5412a4def4acdaa12e12f269737a5751369e12d1a962" - url: "https://pub.dev" - source: hosted - version: "0.28.0" - shared_preferences: - dependency: "direct main" - description: - name: shared_preferences - sha256: "6e8bf70b7fef813df4e9a36f658ac46d107db4b4cfe1048b477d4e453a8159f5" - url: "https://pub.dev" - source: hosted - version: "2.5.3" - shared_preferences_android: - dependency: transitive - description: - name: shared_preferences_android - sha256: "20cbd561f743a342c76c151d6ddb93a9ce6005751e7aa458baad3858bfbfb6ac" - url: "https://pub.dev" - source: hosted - version: "2.4.10" - shared_preferences_foundation: - dependency: transitive - description: - name: shared_preferences_foundation - sha256: "6a52cfcdaeac77cad8c97b539ff688ccfc458c007b4db12be584fbe5c0e49e03" - url: "https://pub.dev" - source: hosted - version: "2.5.4" - shared_preferences_linux: - dependency: transitive - description: - name: shared_preferences_linux - sha256: "580abfd40f415611503cae30adf626e6656dfb2f0cee8f465ece7b6defb40f2f" - url: "https://pub.dev" - source: hosted - version: "2.4.1" - shared_preferences_platform_interface: - dependency: transitive - description: - name: shared_preferences_platform_interface - sha256: "57cbf196c486bc2cf1f02b85784932c6094376284b3ad5779d1b1c6c6a816b80" - url: "https://pub.dev" - source: hosted - version: "2.4.1" - shared_preferences_web: - dependency: transitive - description: - name: shared_preferences_web - sha256: c49bd060261c9a3f0ff445892695d6212ff603ef3115edbb448509d407600019 - url: "https://pub.dev" - source: hosted - version: "2.4.3" - shared_preferences_windows: - dependency: transitive - description: - name: shared_preferences_windows - sha256: "94ef0f72b2d71bc3e700e025db3710911bd51a71cefb65cc609dd0d9a982e3c1" - url: "https://pub.dev" - source: hosted - version: "2.4.1" - shelf: - dependency: transitive - description: - name: shelf - sha256: e7dd780a7ffb623c57850b33f43309312fc863fb6aa3d276a754bb299839ef12 - url: "https://pub.dev" - source: hosted - version: "1.4.2" - shelf_web_socket: - dependency: transitive - description: - name: shelf_web_socket - sha256: cc36c297b52866d203dbf9332263c94becc2fe0ceaa9681d07b6ef9807023b67 - url: "https://pub.dev" - source: hosted - version: "2.0.1" - shimmer: - dependency: "direct main" - description: - name: shimmer - sha256: "5f88c883a22e9f9f299e5ba0e4f7e6054857224976a5d9f839d4ebdc94a14ac9" - url: "https://pub.dev" - source: hosted - version: "3.0.0" - sky_engine: - dependency: transitive - description: flutter - source: sdk - version: "0.0.0" - source_gen: - dependency: transitive - description: - name: source_gen - sha256: "14658ba5f669685cd3d63701d01b31ea748310f7ab854e471962670abcf57832" - url: "https://pub.dev" - source: hosted - version: "1.5.0" - source_helper: - dependency: transitive - description: - name: source_helper - sha256: "86d247119aedce8e63f4751bd9626fc9613255935558447569ad42f9f5b48b3c" - url: "https://pub.dev" - source: hosted - version: "1.3.5" - source_span: - dependency: transitive - description: - name: source_span - sha256: "254ee5351d6cb365c859e20ee823c3bb479bf4a293c22d17a9f1bf144ce86f7c" - url: "https://pub.dev" - source: hosted - version: "1.10.1" - sprintf: - dependency: transitive - description: - name: sprintf - sha256: "1fc9ffe69d4df602376b52949af107d8f5703b77cda567c4d7d86a0693120f23" - url: "https://pub.dev" - source: hosted - version: "7.0.0" - stack_trace: - dependency: transitive - description: - name: stack_trace - sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1" - url: "https://pub.dev" - source: hosted - version: "1.12.1" - story: - dependency: "direct main" - description: - name: story - sha256: "0cff3c02d5ad1d9c1cf79481b8fe4a4f2f859e56b351644e96b8b209e6a110a5" - url: "https://pub.dev" - source: hosted - version: "1.1.0" - stream_channel: - dependency: transitive - description: - name: stream_channel - sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d" - url: "https://pub.dev" - source: hosted - version: "2.1.4" - stream_transform: - dependency: transitive - description: - name: stream_transform - sha256: ad47125e588cfd37a9a7f86c7d6356dde8dfe89d071d293f80ca9e9273a33871 - url: "https://pub.dev" - source: hosted - version: "2.1.1" - string_scanner: - dependency: transitive - description: - name: string_scanner - sha256: "921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43" - url: "https://pub.dev" - source: hosted - version: "1.4.1" - sync_http: - dependency: transitive - description: - name: sync_http - sha256: "7f0cd72eca000d2e026bcd6f990b81d0ca06022ef4e32fb257b30d3d1014a961" - url: "https://pub.dev" - source: hosted - version: "0.3.1" - term_glyph: - dependency: transitive - description: - name: term_glyph - sha256: "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e" - url: "https://pub.dev" - source: hosted - version: "1.2.2" - test_api: - dependency: transitive - description: - name: test_api - sha256: "522f00f556e73044315fa4585ec3270f1808a4b186c936e612cab0b565ff1e00" - url: "https://pub.dev" - source: hosted - version: "0.7.6" - timezone: - dependency: transitive - description: - name: timezone - sha256: dd14a3b83cfd7cb19e7888f1cbc20f258b8d71b54c06f79ac585f14093a287d1 - url: "https://pub.dev" - source: hosted - version: "0.10.1" - timing: - dependency: transitive - description: - name: timing - sha256: "62ee18aca144e4a9f29d212f5a4c6a053be252b895ab14b5821996cff4ed90fe" - url: "https://pub.dev" - source: hosted - version: "1.0.2" - typed_data: - dependency: transitive - description: - name: typed_data - sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006 - url: "https://pub.dev" - source: hosted - version: "1.4.0" - universal_image: - dependency: "direct main" - description: - name: universal_image - sha256: "8f4aa6eaaf68cf8b033101e4c1a03390baa31b9f84bd66c14472107e35ccb037" - url: "https://pub.dev" - source: hosted - version: "1.0.10" - universal_io: - dependency: "direct main" - description: - name: universal_io - sha256: "1722b2dcc462b4b2f3ee7d188dad008b6eb4c40bbd03a3de451d82c78bba9aad" - url: "https://pub.dev" - source: hosted - version: "2.2.2" - url_launcher: - dependency: "direct main" - description: - name: url_launcher - sha256: f6a7e5c4835bb4e3026a04793a4199ca2d14c739ec378fdfe23fc8075d0439f8 - url: "https://pub.dev" - source: hosted - version: "6.3.2" - url_launcher_android: - dependency: transitive - description: - name: url_launcher_android - sha256: "8582d7f6fe14d2652b4c45c9b6c14c0b678c2af2d083a11b604caeba51930d79" - url: "https://pub.dev" - source: hosted - version: "6.3.16" - url_launcher_ios: - dependency: transitive - description: - name: url_launcher_ios - sha256: "7f2022359d4c099eea7df3fdf739f7d3d3b9faf3166fb1dd390775176e0b76cb" - url: "https://pub.dev" - source: hosted - version: "6.3.3" - url_launcher_linux: - dependency: transitive - description: - name: url_launcher_linux - sha256: "4e9ba368772369e3e08f231d2301b4ef72b9ff87c31192ef471b380ef29a4935" - url: "https://pub.dev" - source: hosted - version: "3.2.1" - url_launcher_macos: - dependency: transitive - description: - name: url_launcher_macos - sha256: "17ba2000b847f334f16626a574c702b196723af2a289e7a93ffcb79acff855c2" - url: "https://pub.dev" - source: hosted - version: "3.2.2" - url_launcher_platform_interface: - dependency: transitive - description: - name: url_launcher_platform_interface - sha256: "552f8a1e663569be95a8190206a38187b531910283c3e982193e4f2733f01029" - url: "https://pub.dev" - source: hosted - version: "2.3.2" - url_launcher_web: - dependency: transitive - description: - name: url_launcher_web - sha256: "4bd2b7b4dc4d4d0b94e5babfffbca8eac1a126c7f3d6ecbc1a11013faa3abba2" - url: "https://pub.dev" - source: hosted - version: "2.4.1" - url_launcher_windows: - dependency: transitive - description: - name: url_launcher_windows - sha256: "3284b6d2ac454cf34f114e1d3319866fdd1e19cdc329999057e44ffe936cfa77" - url: "https://pub.dev" - source: hosted - version: "3.1.4" - uuid: - dependency: transitive - description: - name: uuid - sha256: a5be9ef6618a7ac1e964353ef476418026db906c4facdedaa299b7a2e71690ff - url: "https://pub.dev" - source: hosted - version: "4.5.1" - vector_graphics: - dependency: transitive - description: - name: vector_graphics - sha256: a4f059dc26fc8295b5921376600a194c4ec7d55e72f2fe4c7d2831e103d461e6 - url: "https://pub.dev" - source: hosted - version: "1.1.19" - vector_graphics_codec: - dependency: transitive - description: - name: vector_graphics_codec - sha256: "99fd9fbd34d9f9a32efd7b6a6aae14125d8237b10403b422a6a6dfeac2806146" - url: "https://pub.dev" - source: hosted - version: "1.1.13" - vector_graphics_compiler: - dependency: transitive - description: - name: vector_graphics_compiler - sha256: "557a315b7d2a6dbb0aaaff84d857967ce6bdc96a63dc6ee2a57ce5a6ee5d3331" - url: "https://pub.dev" - source: hosted - version: "1.1.17" - vector_math: - dependency: transitive - description: - name: vector_math - sha256: d530bd74fea330e6e364cda7a85019c434070188383e1cd8d9777ee586914c5b - url: "https://pub.dev" - source: hosted - version: "2.2.0" - version: - dependency: transitive - description: - name: version - sha256: "3d4140128e6ea10d83da32fef2fa4003fccbf6852217bb854845802f04191f94" - url: "https://pub.dev" - source: hosted - version: "3.0.2" - vm_service: - dependency: transitive - description: - name: vm_service - sha256: ddfa8d30d89985b96407efce8acbdd124701f96741f2d981ca860662f1c0dc02 - url: "https://pub.dev" - source: hosted - version: "15.0.0" - watcher: - dependency: transitive - description: - name: watcher - sha256: "0b7fd4a0bbc4b92641dbf20adfd7e3fd1398fe17102d94b674234563e110088a" - url: "https://pub.dev" - source: hosted - version: "1.1.2" - web: - dependency: transitive - description: - name: web - sha256: "868d88a33d8a87b18ffc05f9f030ba328ffefba92d6c127917a2ba740f9cfe4a" - url: "https://pub.dev" - source: hosted - version: "1.1.1" - web_socket: - dependency: transitive - description: - name: web_socket - sha256: "34d64019aa8e36bf9842ac014bb5d2f5586ca73df5e4d9bf5c936975cae6982c" - url: "https://pub.dev" - source: hosted - version: "1.0.1" - web_socket_channel: - dependency: transitive - description: - name: web_socket_channel - sha256: d645757fb0f4773d602444000a8131ff5d48c9e47adfe9772652dd1a4f2d45c8 - url: "https://pub.dev" - source: hosted - version: "3.0.3" - webdriver: - dependency: transitive - description: - name: webdriver - sha256: "2f3a14ca026957870cfd9c635b83507e0e51d8091568e90129fbf805aba7cade" - url: "https://pub.dev" - source: hosted - version: "3.1.0" - webview_flutter: - dependency: "direct main" - description: - name: webview_flutter - sha256: c3e4fe614b1c814950ad07186007eff2f2e5dd2935eba7b9a9a1af8e5885f1ba - url: "https://pub.dev" - source: hosted - version: "4.13.0" - webview_flutter_android: - dependency: transitive - description: - name: webview_flutter_android - sha256: "9573ad97890d199ac3ab32399aa33a5412163b37feb573eb5b0a76b35e9ffe41" - url: "https://pub.dev" - source: hosted - version: "4.8.2" - webview_flutter_platform_interface: - dependency: transitive - description: - name: webview_flutter_platform_interface - sha256: f0dc2dc3a2b1e3a6abdd6801b9355ebfeb3b8f6cde6b9dc7c9235909c4a1f147 - url: "https://pub.dev" - source: hosted - version: "2.13.1" - webview_flutter_wkwebview: - dependency: transitive - description: - name: webview_flutter_wkwebview - sha256: "71523b9048cf510cfa1fd4e0a3fa5e476a66e0884d5df51d59d5023dba237107" - url: "https://pub.dev" - source: hosted - version: "3.22.1" - win32: - dependency: transitive - description: - name: win32 - sha256: "66814138c3562338d05613a6e368ed8cfb237ad6d64a9e9334be3f309acfca03" - url: "https://pub.dev" - source: hosted - version: "5.14.0" - win32_registry: - dependency: transitive - description: - name: win32_registry - sha256: "21ec76dfc731550fd3e2ce7a33a9ea90b828fdf19a5c3bcf556fa992cfa99852" - url: "https://pub.dev" - source: hosted - version: "1.1.5" - xdg_directories: - dependency: transitive - description: - name: xdg_directories - sha256: "7a3f37b05d989967cdddcbb571f1ea834867ae2faa29725fd085180e0883aa15" - url: "https://pub.dev" - source: hosted - version: "1.1.0" - xml: - dependency: transitive - description: - name: xml - sha256: b015a8ad1c488f66851d762d3090a21c600e479dc75e68328c52774040cf9226 - url: "https://pub.dev" - source: hosted - version: "6.5.0" - yaml: - dependency: transitive - description: - name: yaml - sha256: b9da305ac7c39faa3f030eccd175340f968459dae4af175130b3fc47e40d76ce - url: "https://pub.dev" - source: hosted - version: "3.1.3" - yandex_mobileads: - dependency: "direct main" - description: - name: yandex_mobileads - sha256: f7612c9d499bf5d594fda6d74c2b30a8120099586eb9b03799d7cc0af32c6345 - url: "https://pub.dev" - source: hosted - version: "7.13.0" - yookassa_client: - dependency: "direct main" - description: - name: yookassa_client - sha256: e801e1bb22f21f883adbee15645e2c9b21c4a640f8e096006a6295c335c588aa - url: "https://pub.dev" - source: hosted - version: "1.0.5" -sdks: - dart: ">=3.8.1 <4.0.0" - flutter: ">=3.32.0" diff --git a/mnemo_cards/pubspec.yaml b/mnemo_cards/pubspec.yaml deleted file mode 100644 index 1ffd063..0000000 --- a/mnemo_cards/pubspec.yaml +++ /dev/null @@ -1,194 +0,0 @@ -name: mnemo_cards -description: Mnemo -publish_to: 'none' - -version: 1.0.0+22 - -environment: - sdk: '>=3.8.0 <4.0.0' - -dependencies: - flutter: - sdk: flutter - - mnemo_cards_common: - path: ../mnemo_cards_common - - mnemo_cards_frontend_common: - path: ../mnemo_cards_frontend_common - -# funny_letters: -# path: ../funny_letters - - universal_image: ^1.0.10 - - get_it: - flutter_bloc: ^9.1.1 - shared_preferences: ^2.2.3 - flutter_secure_storage: ^9.2.2 - rxdart: -# firebase_core: ^3.3.0 - # firebase_crashlytics: - # firebase_storage: - cloud_firestore: ^5.2.1 - json_serializable: - json_annotation: ^4.7.0 - auto_size_text: ^3.0.0 - path_provider: -# google_fonts: - auto_route: ^9.2.0 - flutter_tts: ^4.0.2 - dio: ^5.3.3 - universal_io: ^2.2.2 - mutex: ^3.1.0 - copy_with_extension_gen: ^5.0.4 - archive: ^3.4.6 - shimmer: ^3.0.0 - google_sign_in: -# telegram_web_app: ^0.3.1 - device_info_plus: ^10.1.1 - package_info_plus: ^8.0.0 - yandex_mobileads: ^7.4.0 - firebase_crashlytics: ^4.0.4 - firebase_analytics: ^11.2.1 - firebase_messaging: ^15.2.9 - firebase_remote_config: ^5.4.7 - flutter_local_notifications: ^19.3.1 - in_app_purchase: ^3.2.0 - in_app_purchase_android: - dot_navigation_bar: ^1.0.2 - reorderables: ^0.6.0 - story: ^1.1.0 - flutter_screenutil: ^5.9.0 - fl_chart: ^0.68.0 - yookassa_client: ^1.0.2 - # The following adds the Cupertino Icons font to your application. - # Use with the CupertinoIcons class for iOS style icons. - cupertino_icons: ^1.0.2 - webview_flutter: ^4.7.0 - flutter_colorpicker: ^1.1.0 - jailbreak_root_detection: ^1.1.1 - no_screenshot: ^0.3.1 - flutter_widget_from_html_core: ^0.17.0 - - file_picker: - url_launcher: ^6.2.6 - app_links: ^6.2.0 - - # Payloads system dependencies - payloads_shared: - path: ../games/packages/payloads_shared - bridge_core: - path: ../games/packages/bridge_core - -# RUSTORE -# flutter_rustore_billing: ^6.0.1 - - collection: any - copy_with_extension: any -dev_dependencies: - flutter_test: - sdk: flutter - auto_route_generator: - build_runner: - injectable_generator: - flutter_lints: ^6.0.0 - - flutter_launcher_icons: ^0.14.4 - flutter_native_splash: ^2.4.0 - - # E2E Testing with Patrol - patrol: ^3.0.0 - integration_test: - sdk: flutter - -# The following section is specific to Flutter packages. -flutter: - uses-material-design: true - - # To add assets to your application, add an assets section, like this: - assets: - - images/ - - assets/ - - icons/ - - fonts: - - family: Nunito - fonts: - - asset: fonts/Nunito-VariableFont_wght.ttf - -flutter_launcher_icons: - android: "launcher_icon" - ios: true - image_path: "gen_images/icon.png" - min_sdk_android: 21 # android min sdk min:16, default 21 - -flutter_native_splash: - # Only one parameter can be used, color and background_image cannot both be set. - color: "#ffffff" - color_dark: "#121212" - #background_image: "assets/background.png" - - # Optional parameters are listed below. To enable a parameter, uncomment the line by removing - # the leading # character. - - # The image parameter allows you to specify an image used in the splash screen. It must be a - # png file and should be sized for 4x pixel density. - image: gen_images/cerdo_big.jpg - image_dark: gen_images/luna_big_dark.jpg - - # The branding property allows you to specify an image used as branding in the splash screen. - # It must be a png file. It is supported for Android, iOS and the Web. For Android 12, - # see the Android 12 section below. - #branding: assets/dart.png - - # To position the branding image at the bottom of the screen you can use bottom, bottomRight, - # and bottomLeft. The default values is bottom if not specified or specified something else. - #branding_mode: bottom - - # The color_dark, background_image_dark, image_dark, branding_dark are parameters that set the background - # and image when the device is in dark mode. If they are not specified, the app will use the - # parameters from above. If the image_dark parameter is specified, color_dark or - # background_image_dark must be specified. color_dark and background_image_dark cannot both be - # set. - #color_dark: "#042a49" - #background_image_dark: "assets/dark-background.png" - #image_dark: assets/splash-invert.png - #branding_dark: assets/dart_dark.png - - # From Android 12 onwards, the splash screen is handled differently than in previous versions. - # Please visit https://developer.android.com/guide/topics/ui/splash-screen - # Following are specific parameters for Android 12+. - android_12: - # The image parameter sets the splash screen icon image. If this parameter is not specified, - # the app's launcher icon will be used instead. - # Please note that the splash screen will be clipped to a circle on the center of the screen. - # App icon with an icon background: This should be 960×960 pixels, and fit within a circle - # 640 pixels in diameter. - # App icon without an icon background: This should be 1152×1152 pixels, and fit within a circle - # 768 pixels in diameter. - image: gen_images/cerdo_big.jpg - image_dark: gen_images/luna_big_dark.jpg - - # Splash screen background color. - color: "#ffffff" - color_dark: "#121212" - - # App icon background color. - #icon_background_color: "#111111" - - # The branding property allows you to specify an image used as branding in the splash screen. - #branding: assets/dart.png - - # The image_dark, color_dark, icon_background_color_dark, and branding_dark set values that - # apply when the device is in dark mode. If they are not specified, the app will use the - # parameters from above. - #image_dark: assets/android12splash-invert.png - #color_dark: "#042a49" - #icon_background_color_dark: "#eeeeee" - - # The android, ios and web parameters can be used to disable generating a splash screen on a given - # platform. - #android: false - #ios: false - #web: false diff --git a/mnemo_cards/sha.sh b/mnemo_cards/sha.sh deleted file mode 100644 index 91846cd..0000000 --- a/mnemo_cards/sha.sh +++ /dev/null @@ -1,2 +0,0 @@ -cd android -./gradlew signingReport \ No newline at end of file diff --git a/mnemo_cards/some.json b/mnemo_cards/some.json deleted file mode 100644 index a2adec2..0000000 --- a/mnemo_cards/some.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "admin": true, - "id": 3, - "name": null, - "purchases": [ - "27", - "28" - ], - "subscription": false -} \ No newline at end of file diff --git a/mnemo_cards/test.json b/mnemo_cards/test.json deleted file mode 100644 index 54fbffa..0000000 --- a/mnemo_cards/test.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "cards": [ - 1, - 2, - -1, - 3, - 4, - 5, - 6 - ], - "color": "0xff8CCBFF", - "cover": "cards/pata.jpg", - "id": 91906190, - "name": "Original", - "size": 7, - "version": "10" -} \ No newline at end of file diff --git a/mnemo_cards/test/google_signin_test.dart b/mnemo_cards/test/google_signin_test.dart deleted file mode 100644 index 8b9980a..0000000 --- a/mnemo_cards/test/google_signin_test.dart +++ /dev/null @@ -1,17 +0,0 @@ -import 'package:flutter_test/flutter_test.dart'; -import 'package:google_sign_in/google_sign_in.dart'; - -void main() { - group('Google Sign-In Tests', () { - test('GoogleSignIn should be available', () { - // Проверяем, что GoogleSignIn доступен - expect(GoogleSignIn.instance, isNotNull); - }); - - test('GoogleSignIn should have correct scopes', () { - // Проверяем, что GoogleSignIn может быть создан с правильными параметрами - final googleSignIn = GoogleSignIn.instance; - expect(googleSignIn, isNotNull); - }); - }); -} diff --git a/mnemo_cards/test/widget_test.dart b/mnemo_cards/test/widget_test.dart deleted file mode 100644 index 278d67e..0000000 --- a/mnemo_cards/test/widget_test.dart +++ /dev/null @@ -1,30 +0,0 @@ -// This is a basic Flutter widget test. -// -// To perform an interaction with a widget in your test, use the WidgetTester -// utility in the flutter_test package. For example, you can send tap and scroll -// gestures. You can also use WidgetTester to find child widgets in the widget -// tree, read text, and verify that the values of widget properties are correct. - -import 'package:flutter/material.dart'; -import 'package:flutter_test/flutter_test.dart'; - -import 'package:mnemo_cards/main.dart'; - -void main() { - testWidgets('Counter increments smoke test', (WidgetTester tester) async { - // Build our app and trigger a frame. - await tester.pumpWidget(const MyApp()); - - // Verify that our counter starts at 0. - expect(find.text('0'), findsOneWidget); - expect(find.text('1'), findsNothing); - - // Tap the '+' icon and trigger a frame. - await tester.tap(find.byIcon(Icons.add)); - await tester.pump(); - - // Verify that our counter has incremented. - expect(find.text('0'), findsNothing); - expect(find.text('1'), findsOneWidget); - }); -} diff --git a/mnemo_cards/v b/mnemo_cards/v deleted file mode 100644 index e69de29..0000000 diff --git a/mnemo_cards/vocabulary_plan.md b/mnemo_cards/vocabulary_plan.md deleted file mode 100644 index 7381b03..0000000 --- a/mnemo_cards/vocabulary_plan.md +++ /dev/null @@ -1,307 +0,0 @@ -# План разработки страницы словаря (Vocabulary Page) - -## Обзор дизайна -Страница представляет собой интерфейс для изучения испанских слов с русскими переводами. Включает категории, прогресс изучения и список слов с изображениями. Использует существующую архитектуру проекта с `WordStatisticsDto`, `UserDataDto` и готовыми виджетами. - -## 1. Структура данных - -### 1.1 Существующие модели данных -- **WordStatisticsDto** - уже существует в `mnemo_cards_common` - - `word: String` - слово - - `correct: double` - количество правильных ответов - - `incorrect: double` - количество неправильных ответов - - `skipped: double` - количество пропущенных - - `questionTypes: Set` - типы вопросов - - `total: double` - общее количество (computed property) - -- **UserDataDto** - уже существует - - `allWordsStatistics: AllWordsStatisticsDto?` - статистика всех слов - - `allTestsStatistics: AllTestsStatisticsDto?` - статистика тестов - -- **AllWordsStatisticsDto** - уже существует - - `words: List` - список статистики слов - -- **GameCardDto** - уже существует для карточек - - `id: int` - уникальный идентификатор - - `original: String?` - оригинальное слово (испанское) - - `translation: String?` - перевод (русский) - - `image: String?` - URL изображения - - `transcription: String?` - транскрипция - - `mnemo: String?` - мнемоника - -### 1.2 Новые модели для словаря -- **VocabularyCategory** - модель категории - - `id: String` - - `name: String` - название категории - - `icon: IconData` - иконка категории - - `color: Color?` - цвет категории из `CardPackDto.color?.asColor` - - `totalWords: int` - общее количество слов - - `learnedWords: int` - количество изученных слов - - `packId: String?` - ID связанного пакета карточек - -- **VocabularyWord** - расширенная модель слова для UI - - `gameCard: GameCardDto` - базовая карточка - - `statistics: WordStatisticsDto?` - статистика изучения - - `isLearned: bool` - изучено ли слово (computed) - - `isFavorite: bool` - добавлено ли в избранное - - `difficulty: WordDifficulty` - уровень сложности (computed) - -- **WordDifficulty** - enum уровней сложности (computed) - - `easy` - зеленый цвет (correct/total > 0.8) - - `medium` - оранжевый цвет (0.5 < correct/total <= 0.8) - - `hard` - красный цвет (correct/total <= 0.5) - -### 1.3 Состояние страницы -- **VocabularyPageState** - состояние страницы - - `selectedCategory: String?` - выбранная категория - - `words: List` - список слов - - `categories: List` - список категорий - - `isLoading: bool` - состояние загрузки - - `searchQuery: String` - поисковый запрос - - `userData: UserDataDto?` - данные пользователя - -## 2. Компоненты UI - -### 2.1 Заголовок страницы -- **AppBar** с заголовком "Знания" / "Vocabulario" -- **SearchIcon** в правом верхнем углу для поиска -- **SearchBar** (появляется при нажатии на поиск) - -### 2.2 Категории (Category Tabs) -- **HorizontalScrollable** список категорий -- **CategoryTab** - виджет вкладки категории - - Pill-shaped дизайн - - Цветовая схема: `category.color ?? Theme.of(context).colorScheme.secondary` - - Иконка категории - - Активное состояние: `Theme.of(context).colorScheme.primary` - - Счетчик слов в категории - - Текст: `Theme.of(context).colorScheme.onSurface` - -### 2.3 Прогресс-бар -- **ProgressContainer** - контейнер с прогрессом - - Текст "Выучено: X из Y слов" (используя логику из `UserStatistics`) - - **HorizontalProgressWidget** - уже существует в `mnemo_cards_frontend_common` - - Процентное отображение прогресса - -### 2.4 Список слов -- **ListView** с карточками слов -- **WordCard** - карточка слова (расширение `_WordListItem` из `UserStatistics`) - - **Background**: `Theme.of(context).colorScheme.surfaceContainer` - - **Left side**: Изображение слова (NetworkImage из `GameCardDto.image`) - - **Middle**: - - Испанское слово (`GameCardDto.original`) - крупный шрифт, `Theme.of(context).colorScheme.onSurface` - - Русский перевод (`GameCardDto.translation`) - мелкий шрифт, `Theme.of(context).colorScheme.onSurfaceVariant` - - **Right side**: - - **HorizontalProgressWidget** - уже существует для отображения прогресса - - **FavoriteButton** - звездочка (заполненная/пустая) - - Активная: `Theme.of(context).colorScheme.primary` - - Неактивная: `Theme.of(context).colorScheme.outline` - -## 3. Функциональность - -### 3.1 Навигация по категориям -- Переключение между категориями -- Фильтрация слов по выбранной категории -- Анимация переключения - -### 3.2 Поиск -- Поиск по испанским словам (`GameCardDto.original`) -- Поиск по русским переводам (`GameCardDto.translation`) -- Реальное время поиска (debounced) -- Очистка поиска - -### 3.3 Управление словами -- Отметка слова как изученного (используя логику из `UserStatistics._getLearnedWords`) -- Добавление/удаление из избранного -- Воспроизведение аудио произношения -- Переход к детальному просмотру слова - -### 3.4 Прогресс -- Подсчет изученных слов (используя логику из `UserStatistics._getLearnedWords`) -- Обновление прогресс-бара -- Статистика по категориям - -## 4. Техническая реализация - -### 4.1 State Management -- **Cubit/Bloc** для управления состоянием -- **VocabularyCubit** с методами: - - `loadWords()` - загрузка карточек из API - - `loadUserData()` - загрузка `UserDataDto` - - `loadCategories()` - загрузка категорий - - `selectCategory(String category)` - - `searchWords(String query)` - - `toggleFavorite(String wordId)` - - `playAudio(String wordId)` - -### 4.2 Данные -- **VocabularyRepository** - репозиторий для работы с данными - - Интеграция с существующими API для `GameCardDto` - - Использование `UserDataDto` для статистики -- **LocalStorage** - локальное хранение избранных слов -- **API** - загрузка карточек и изображений -- **MockData** - тестовые данные для разработки - -### 4.3 Анимации -- **AnimatedSwitcher** для переключения категорий -- **Hero** анимации для переходов -- **FadeIn** анимации для карточек -- **Scale** анимации для кнопок - -## 5. Этапы разработки - -### Этап 1: Базовая структура -1. Создать новые модели данных (`VocabularyCategory`, `VocabularyWord`) -2. Настроить Cubit для управления состоянием -3. Создать базовую структуру страницы -4. Добавить заголовок и поиск - -### Этап 2: Категории -1. Создать виджет CategoryTab с использованием `pack.color?.asColor` -2. Реализовать горизонтальный скролл категорий -3. Добавить логику переключения категорий -4. Стилизовать активное состояние с цветами из темы -5. Интегрировать цвета пакетов с категориями - -### Этап 3: Прогресс -1. Адаптировать логику из `UserStatistics` для подсчета прогресса -2. Использовать существующий `HorizontalProgressWidget` -3. Добавить анимацию прогресс-бара -4. Интегрировать с данными - -### Этап 4: Список слов -1. Расширить `_WordListItem` из `UserStatistics` для создания `WordCard` -2. Добавить изображения из `GameCardDto.image` -3. Интегрировать с `GameCardDto` данными -4. Стилизовать карточки - -### Этап 5: Функциональность -1. Реализовать поиск по `GameCardDto` полям -2. Добавить управление избранным -3. Использовать логику изученных слов из `UserStatistics` -4. Добавить аудио воспроизведение - -### Этап 6: Полировка -1. Добавить анимации -2. Оптимизировать производительность -3. Добавить обработку ошибок -4. Тестирование - -## 6. Стилизация - -### 6.1 Цветовая схема -- **Primary**: `Theme.of(context).colorScheme.primary` -- **Category Colors**: Использовать `pack.color?.asColor` из `CardPackDto` - - Каждая категория наследует цвет от соответствующего пакета карточек - - Fallback на `Theme.of(context).colorScheme.secondary` если цвет не задан -- **Difficulty Colors** (computed): - - Easy: `Theme.of(context).colorScheme.primary` (correct/total > 0.8) - - Medium: `Theme.of(context).colorScheme.tertiary` (0.5 < correct/total <= 0.8) - - Hard: `Theme.of(context).colorScheme.error` (correct/total <= 0.5) -- **Background**: `Theme.of(context).colorScheme.surface` -- **Card Background**: `Theme.of(context).colorScheme.surfaceContainer` -- **Text Colors**: - - Primary text: `Theme.of(context).colorScheme.onSurface` - - Secondary text: `Theme.of(context).colorScheme.onSurfaceVariant` - -### 6.2 Типографика -- **Заголовки**: Крупный, жирный шрифт (как в `UserStatistics`) -- **Испанские слова**: Средний размер, жирный -- **Русские переводы**: Мелкий размер, обычный -- **Счетчики**: Мелкий размер, жирный - -### 6.3 Отступы и размеры -- **Card padding**: 16px (как в `_WordListItem`) -- **Category tab height**: 40px -- **Image size**: 60x60px -- **Icon size**: 24px -- **Border radius**: 12px для карточек, 20px для табов - -### 6.4 Примеры использования цветов -```dart -// Цвет категории -final categoryColor = category.color ?? Theme.of(context).colorScheme.secondary; - -// Цвет сложности слова -Color getDifficultyColor(WordStatisticsDto stats) { - final ratio = stats.correct / stats.total; - if (ratio > 0.8) return Theme.of(context).colorScheme.primary; - if (ratio > 0.5) return Theme.of(context).colorScheme.tertiary; - return Theme.of(context).colorScheme.error; -} - -// Цвет фона карточки -final cardBackground = Theme.of(context).colorScheme.surfaceContainer; - -// Цвет текста -final primaryTextColor = Theme.of(context).colorScheme.onSurface; -final secondaryTextColor = Theme.of(context).colorScheme.onSurfaceVariant; -``` - -## 7. Интеграция с существующими компонентами - -### 7.1 Использование UserStatistics -- Логика определения изученных слов: `w.correct > 3 && w.correct / w.total > 0.8` -- Сортировка слов по прогрессу: `(n.correct / n.total).compareTo(p.correct / p.total)` -- Текст для заголовка с правильным склонением - -### 7.2 Использование HorizontalProgressWidget -- Уже готовый виджет для отображения прогресса -- Поддержка анимаций -- Настраиваемые цвета и размеры - -### 7.3 Использование GameCardDto -- Интеграция с существующей системой карточек -- Использование полей `original`, `translation`, `image` -- Поддержка транскрипции и мнемоники - -### 7.4 Интеграция цветов пакетов -- Связывание категорий с пакетами карточек через `CardPackDto` -- Использование `pack.color?.asColor` для цветов категорий -- Fallback на цвета темы если цвет пакета не задан -- Создание маппинга категорий к пакетам для получения цветов - -## 8. Тестирование - -### 8.1 Unit тесты -- Тестирование Cubit логики -- Тестирование новых моделей данных -- Тестирование утилит для вычисления сложности - -### 8.2 Widget тесты -- Тестирование компонентов UI -- Тестирование взаимодействий -- Тестирование анимаций - -### 8.3 Integration тесты -- Тестирование полного флоу -- Тестирование навигации -- Тестирование производительности - -## 9. Оптимизация - -### 9.1 Производительность -- Lazy loading для изображений -- Виртуализация списка -- Кэширование данных -- Debounced поиск - -### 9.2 Доступность -- Semantic labels -- Screen reader поддержка -- Keyboard navigation -- High contrast режим - -## 10. Будущие улучшения - -### 10.1 Дополнительные функции -- Голосовой ввод для поиска -- Офлайн режим -- Синхронизация прогресса -- Геймификация (очки, достижения) - -### 10.2 Расширения -- Добавление новых языков -- Пользовательские категории -- Импорт/экспорт словаря -- Социальные функции (обмен словарями) \ No newline at end of file diff --git a/mnemo_cards/web/favicon.png b/mnemo_cards/web/favicon.png deleted file mode 100644 index 8aaa46a..0000000 Binary files a/mnemo_cards/web/favicon.png and /dev/null differ diff --git a/mnemo_cards/web/icons/Icon-192.png b/mnemo_cards/web/icons/Icon-192.png deleted file mode 100644 index b749bfe..0000000 Binary files a/mnemo_cards/web/icons/Icon-192.png and /dev/null differ diff --git a/mnemo_cards/web/icons/Icon-512.png b/mnemo_cards/web/icons/Icon-512.png deleted file mode 100644 index 88cfd48..0000000 Binary files a/mnemo_cards/web/icons/Icon-512.png and /dev/null differ diff --git a/mnemo_cards/web/icons/Icon-maskable-192.png b/mnemo_cards/web/icons/Icon-maskable-192.png deleted file mode 100644 index eb9b4d7..0000000 Binary files a/mnemo_cards/web/icons/Icon-maskable-192.png and /dev/null differ diff --git a/mnemo_cards/web/icons/Icon-maskable-512.png b/mnemo_cards/web/icons/Icon-maskable-512.png deleted file mode 100644 index d69c566..0000000 Binary files a/mnemo_cards/web/icons/Icon-maskable-512.png and /dev/null differ diff --git a/mnemo_cards/web/index.html b/mnemo_cards/web/index.html deleted file mode 100644 index f2dbdfa..0000000 --- a/mnemo_cards/web/index.html +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - mnemo_cards - - - - - - diff --git a/mnemo_cards/web/manifest.json b/mnemo_cards/web/manifest.json deleted file mode 100644 index 74a94cd..0000000 --- a/mnemo_cards/web/manifest.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "name": "mnemo_cards", - "short_name": "mnemo_cards", - "start_url": ".", - "display": "standalone", - "background_color": "#0175C2", - "theme_color": "#0175C2", - "description": "A new Flutter project.", - "orientation": "portrait-primary", - "prefer_related_applications": false, - "icons": [ - { - "src": "icons/Icon-192.png", - "sizes": "192x192", - "type": "image/png" - }, - { - "src": "icons/Icon-512.png", - "sizes": "512x512", - "type": "image/png" - }, - { - "src": "icons/Icon-maskable-192.png", - "sizes": "192x192", - "type": "image/png", - "purpose": "maskable" - }, - { - "src": "icons/Icon-maskable-512.png", - "sizes": "512x512", - "type": "image/png", - "purpose": "maskable" - } - ] -} diff --git a/mnemo_cards/web_server.py b/mnemo_cards/web_server.py deleted file mode 100644 index bfa0173..0000000 --- a/mnemo_cards/web_server.py +++ /dev/null @@ -1,88 +0,0 @@ -# Directory to serve your website files -WEBSITE_DIRECTORY = "/Users/dmitry/StudioProjects/mnemo_cards/mnemo_cards/build/web" - - -import http.server -import socketserver -import os -import urllib.request - -class ProxyHTTPRequestHandler(http.server.CGIHTTPRequestHandler): - def end_headers(self): - # Add CORS headers - self.send_header("Access-Control-Allow-Origin", "*") # Allow all origins - self.send_header("Access-Control-Allow-Methods", "GET, POST, OPTIONS") # Allowed methods - self.send_header("Access-Control-Allow-Headers", "Content-Type, Authorization") # Allowed headers - super().end_headers() - - def do_OPTIONS(self): - # Handle preflight requests - self.send_response(204) # No Content - self.end_headers() - - def do_GET(self): - # Check if the request is for a local file - local_file_path = os.path.join(WEBSITE_DIRECTORY, self.path.lstrip("/")) - if 'version.json' in local_file_path: - local_file_path = local_file_path.split('?')[0] - if self.path == '/': - local_file_path = os.path.join(WEBSITE_DIRECTORY, 'index.html') - if os.path.isfile(local_file_path): - self.serve_local_file(local_file_path) - else: - # Otherwise, act as a proxy - self.handle_proxy_request() - - def do_POST(self): - content_length = int(self.headers.get('Content-Length', 0)) - post_data = self.rfile.read(content_length) # Read the POST body - - # Extract target URL (Remove the leading '/') - target_url = 'http://localhost:8080/' + self.path[1:] - - try: - # Forward the POST request - request = urllib.request.Request(target_url, data=post_data, method="POST") - for header in self.headers: - request.add_header(header, self.headers[header]) # Copy headers - - with urllib.request.urlopen(request) as response: - content = response.read() - self.send_response(response.getcode()) - self.send_header("Content-Type", response.headers.get("Content-Type", "text/html")) - self.end_headers() - self.wfile.write(content) - except Exception as e: - self.send_error(500, f"Error forwarding POST request: {e}") - - def serve_local_file(self, local_file_path): - self.send_response(200) - self.send_header("Content-Type", self.guess_type(local_file_path)) - self.end_headers() - with open(local_file_path, "rb") as file: - self.wfile.write(file.read()) - - def handle_proxy_request(self): - try: - # Remove the leading '/' to get the actual URL - target_url = 'http://localhost:8080/' + self.path[1:] - with urllib.request.urlopen(target_url) as response: - content = response.read() - self.send_response(response.getcode()) - self.send_header("Content-Type", response.headers.get("Content-Type", "text/html")) - self.end_headers() - self.wfile.write(content) - except Exception as e: - self.send_error(500, f"Error fetching URL: {e}") - -if __name__ == "__main__": - PORT = 8000 - - # Change the working directory to the website directory - os.chdir(WEBSITE_DIRECTORY) - - # Start the server - with socketserver.TCPServer(("", PORT), ProxyHTTPRequestHandler) as httpd: - print(f"Serving on port {PORT}") - print(f"Serving website from: {os.path.abspath(WEBSITE_DIRECTORY)}") - httpd.serve_forever() \ No newline at end of file diff --git a/mnemo_cards/zanahoria.png b/mnemo_cards/zanahoria.png deleted file mode 100644 index b2cd9b6..0000000 Binary files a/mnemo_cards/zanahoria.png and /dev/null differ diff --git a/mnemo_cards_backend/lib/api/v2/users_api_v2.dart b/mnemo_cards_backend/lib/api/v2/users_api_v2.dart index 552420e..8116098 100644 --- a/mnemo_cards_backend/lib/api/v2/users_api_v2.dart +++ b/mnemo_cards_backend/lib/api/v2/users_api_v2.dart @@ -1,4 +1,5 @@ import 'dart:convert'; +import 'dart:math'; import 'package:injectable/injectable.dart'; import 'package:mnemo_cards_backend/api/authorize/helpers.dart'; @@ -457,9 +458,43 @@ class UsersApiV2 { jsonDecode(body) as Map, ); - // Here we would typically save the session to database - // For now, we'll just acknowledge receipt - // In a full implementation, this would update user statistics + await backend_main.isar.writeTxn(() async { + final current = await backend_main.isar.userModels.get(user.id!); + if (current == null) { + throw StateError('User not found'); + } + + final userData = current.userData.value; + if (userData == null) { + throw StateError('User data not found'); + } + + // Update study dates + final now = DateTime.now(); + final studyDates = List.from(userData.studyDates); + studyDates.add(now); + + // Update total study time + final totalStudyTime = userData.totalStudyTimeMinutes + sessionDto.duration.inMinutes; + + // Recalculate streak + final currentStreak = _statisticsCalculator.calculateStreak(studyDates); + final longestStreak = max(userData.longestStreak, currentStreak); + + // Update user data + final updatedUserData = userData.copyWith( + studyDates: studyDates, + totalStudyTimeMinutes: totalStudyTime, + currentStreak: currentStreak, + longestStreak: longestStreak, + lastTimeOnline: now, + ); + + // Save updated user data + await backend_main.isar.userDataModels.put(updatedUserData); + current.userData.value = updatedUserData; + await current.userData.save(); + }); return _json({'result': true, 'sessionId': sessionDto.sessionId}); } catch (e) { diff --git a/mnemo_cards_backend/lib/packs/pack_dto_converter.dart b/mnemo_cards_backend/lib/packs/pack_dto_converter.dart index 15bcc7e..91b0217 100644 --- a/mnemo_cards_backend/lib/packs/pack_dto_converter.dart +++ b/mnemo_cards_backend/lib/packs/pack_dto_converter.dart @@ -134,7 +134,7 @@ class PackDtoConverter { ).uri.toString(), ), ], - if (model.googlePlayId != null) + if (model.googlePlayId != null && false) ButtonItem( height: 110, children: [ diff --git a/mnemo_cards_web_v2/build/unit_test_assets/NOTICES.Z b/mnemo_cards_web_v2/build/unit_test_assets/NOTICES.Z index 3ee5e1a..ecc0f79 100644 Binary files a/mnemo_cards_web_v2/build/unit_test_assets/NOTICES.Z and b/mnemo_cards_web_v2/build/unit_test_assets/NOTICES.Z differ diff --git a/mnemo_cards_web_v2/lib/presentation/pages/profile/profile_page.dart b/mnemo_cards_web_v2/lib/presentation/pages/profile/profile_page.dart index 827bf5d..10d3ae7 100644 --- a/mnemo_cards_web_v2/lib/presentation/pages/profile/profile_page.dart +++ b/mnemo_cards_web_v2/lib/presentation/pages/profile/profile_page.dart @@ -9,6 +9,8 @@ import 'package:yx_state_flutter/yx_state_flutter.dart'; import 'package:mnemo_cards_web_v2/di/app_scope/app_scope_container.dart'; +import '../../widgets/theme_toggle_widget.dart'; + /// Profile page /// /// Shows user information, statistics, and settings @@ -22,6 +24,34 @@ class ProfilePage extends StatefulWidget { class _ProfilePageState extends State { bool _isLoggingOut = false; + Future _showLogoutConfirmation(BuildContext context) async { + final theme = Theme.of(context); + final result = await showDialog( + context: context, + builder: (context) => AlertDialog( + title: const Text('Подтверждение выхода'), + content: const Text('Вы действительно хотите выйти из аккаунта?'), + actions: [ + TextButton( + onPressed: () => Navigator.of(context).pop(false), + child: const Text('Отмена'), + ), + TextButton( + onPressed: () => Navigator.of(context).pop(true), + style: TextButton.styleFrom( + foregroundColor: theme.colorScheme.error, + ), + child: const Text('Выйти'), + ), + ], + ), + ); + + if (result == true && mounted) { + await _logout(context); + } + } + Future _logout(BuildContext context) async { setState(() => _isLoggingOut = true); @@ -63,7 +93,7 @@ class _ProfilePageState extends State { // Show success message messenger.showSnackBar( - const SnackBar(content: Text('Logged out successfully')), + const SnackBar(content: Text('Вы успешно вышли из аккаунта')), ); } catch (e, s) { log( @@ -73,10 +103,10 @@ class _ProfilePageState extends State { name: 'ProfilePage', ); if (!mounted) return; - + messenger.showSnackBar( SnackBar( - content: Text('Logout failed: ${e.toString()}'), + content: Text('Ошибка при выходе: ${e.toString()}'), backgroundColor: Colors.red, ), ); @@ -106,7 +136,9 @@ class _ProfilePageState extends State { stateReadable: userScope.userStateManager, builder: (context, userState, _) { return userState.when( - guest: () => _buildGuestView(context), + guest: () => const Center( + child: Text('Please sign in to access profile'), + ), authenticated: (user) => _buildAuthenticatedView(context, user), loading: () => const Center( child: CircularProgressIndicator(), @@ -119,32 +151,6 @@ class _ProfilePageState extends State { ); } - Widget _buildGuestView(BuildContext context) { - return Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - const Icon(Icons.person_outline, size: 80), - const SizedBox(height: 32), - const Text( - 'Guest Mode', - style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold), - ), - const SizedBox(height: 16), - const Text( - 'Sign in to save your progress', - textAlign: TextAlign.center, - ), - const SizedBox(height: 32), - ElevatedButton.icon( - onPressed: () => context.go('/auth'), - icon: const Icon(Icons.login), - label: const Text('Sign in'), - ), - ], - ), - ); - } Widget _buildAuthenticatedView(BuildContext context, UserDto user) { return ScopeBuilder( @@ -159,31 +165,51 @@ class _ProfilePageState extends State { crossAxisAlignment: CrossAxisAlignment.stretch, children: [ // User header - _buildUserHeader(context, user), - const SizedBox(height: 24), - - // Account info card - _buildAccountInfoCard(context, user), + _buildAnimatedCard( + context, + _buildUserHeader(context, user), + delay: const Duration(milliseconds: 100), + ), const SizedBox(height: 24), // Subscription section - _buildSubscriptionSection(context, user), + _buildAnimatedCard( + context, + _buildSubscriptionSection(context, user), + delay: const Duration(milliseconds: 200), + ), const SizedBox(height: 24), // Settings section - _buildSettingsSection(context), + _buildAnimatedCard( + context, + _buildSettingsSection(context), + delay: const Duration(milliseconds: 300), + ), const SizedBox(height: 24), // Data & Privacy section - _buildDataPrivacySection(context), + _buildAnimatedCard( + context, + _buildDataPrivacySection(context), + delay: const Duration(milliseconds: 400), + ), const SizedBox(height: 24), // About section - _buildAboutSection(context), + _buildAnimatedCard( + context, + _buildAboutSection(context), + delay: const Duration(milliseconds: 500), + ), const SizedBox(height: 24), // Logout button - _buildLogoutButton(context), + _buildAnimatedCard( + context, + _buildLogoutButton(context), + delay: const Duration(milliseconds: 600), + ), ], ), ); @@ -191,6 +217,25 @@ class _ProfilePageState extends State { ); } + Widget _buildAnimatedCard(BuildContext context, Widget child, {Duration delay = Duration.zero}) { + return FutureBuilder( + future: Future.delayed(delay), + builder: (context, snapshot) { + return AnimatedOpacity( + opacity: snapshot.connectionState == ConnectionState.done ? 1.0 : 0.0, + duration: const Duration(milliseconds: 300), + child: AnimatedSlide( + offset: snapshot.connectionState == ConnectionState.done + ? Offset.zero + : const Offset(0, 0.1), + duration: const Duration(milliseconds: 300), + child: child, + ), + ); + }, + ); + } + Widget _buildUserHeader(BuildContext context, UserDto user) { final theme = Theme.of(context); @@ -363,62 +408,145 @@ class _ProfilePageState extends State { Padding( padding: const EdgeInsets.all(16.0), child: user.subscription == true - ? Row( - children: [ - Icon( - Icons.check_circle, - color: Colors.green, - size: 24, + ? Container( + padding: const EdgeInsets.all(16), + decoration: BoxDecoration( + gradient: LinearGradient( + colors: [ + theme.colorScheme.primaryContainer.withOpacity(0.3), + theme.colorScheme.primaryContainer.withOpacity(0.1), + ], + begin: Alignment.topLeft, + end: Alignment.bottomRight, ), - const SizedBox(width: 12), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - 'Premium активна', - style: theme.textTheme.bodyLarge?.copyWith( - fontWeight: FontWeight.bold, - ), - ), - const SizedBox(height: 4), - Text( - 'У вас есть доступ ко всем функциям', - style: theme.textTheme.bodySmall?.copyWith( - color: theme.colorScheme.onSurfaceVariant, - ), - ), - ], + borderRadius: BorderRadius.circular(12), + border: Border.all( + color: theme.colorScheme.primary.withOpacity(0.2), + width: 1, + ), + ), + child: Row( + children: [ + Container( + padding: const EdgeInsets.all(8), + decoration: BoxDecoration( + color: Colors.green.withOpacity(0.2), + shape: BoxShape.circle, + ), + child: const Icon( + Icons.check_circle, + color: Colors.green, + size: 24, + ), ), - ), - ], + const SizedBox(width: 12), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + Text( + 'Premium активна', + style: theme.textTheme.bodyLarge?.copyWith( + fontWeight: FontWeight.bold, + ), + ), + const SizedBox(width: 8), + Container( + padding: const EdgeInsets.symmetric( + horizontal: 8, + vertical: 2, + ), + decoration: BoxDecoration( + gradient: LinearGradient( + colors: [ + theme.colorScheme.primary, + theme.colorScheme.primary.withOpacity(0.8), + ], + ), + borderRadius: BorderRadius.circular(12), + ), + child: Text( + 'PRO', + style: theme.textTheme.bodySmall?.copyWith( + color: theme.colorScheme.onPrimary, + fontWeight: FontWeight.bold, + fontSize: 10, + ), + ), + ), + ], + ), + const SizedBox(height: 4), + Text( + 'У вас есть доступ ко всем функциям', + style: theme.textTheme.bodySmall?.copyWith( + color: theme.colorScheme.onSurfaceVariant, + ), + ), + ], + ), + ), + ], + ), ) - : Row( + : Column( children: [ - Icon( - Icons.info_outline, - color: theme.colorScheme.onSurfaceVariant, - size: 24, + Row( + children: [ + Container( + padding: const EdgeInsets.all(8), + decoration: BoxDecoration( + color: theme.colorScheme.onSurfaceVariant.withOpacity(0.1), + shape: BoxShape.circle, + ), + child: Icon( + Icons.info_outline, + color: theme.colorScheme.onSurfaceVariant, + size: 24, + ), + ), + const SizedBox(width: 12), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Бесплатная версия', + style: theme.textTheme.bodyLarge?.copyWith( + fontWeight: FontWeight.bold, + ), + ), + const SizedBox(height: 4), + Text( + 'Обновитесь до Premium для доступа ко всем функциям', + style: theme.textTheme.bodySmall?.copyWith( + color: theme.colorScheme.onSurfaceVariant, + ), + ), + ], + ), + ), + ], ), - const SizedBox(width: 12), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - 'Бесплатная версия', - style: theme.textTheme.bodyLarge?.copyWith( - fontWeight: FontWeight.bold, - ), + const SizedBox(height: 16), + SizedBox( + width: double.infinity, + child: ElevatedButton.icon( + onPressed: () { + // TODO: Navigate to subscription purchase page + }, + icon: const Icon(Icons.star), + label: const Text('Обновить до Premium'), + style: ElevatedButton.styleFrom( + padding: const EdgeInsets.symmetric(vertical: 12), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12), ), - const SizedBox(height: 4), - Text( - 'Обновитесь до Premium для доступа ко всем функциям', - style: theme.textTheme.bodySmall?.copyWith( - color: theme.colorScheme.onSurfaceVariant, - ), - ), - ], + backgroundColor: theme.colorScheme.primary, + foregroundColor: theme.colorScheme.onPrimary, + ), ), ), ], @@ -555,61 +683,6 @@ class _ProfilePageState extends State { ); } - Widget _buildAccountInfoCard(BuildContext context, UserDto user) { - final theme = Theme.of(context); - - return Card( - elevation: 3, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(16), - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Padding( - padding: const EdgeInsets.all(20.0), - child: Row( - children: [ - Container( - padding: const EdgeInsets.all(8), - decoration: BoxDecoration( - color: theme.colorScheme.primary.withOpacity(0.1), - borderRadius: BorderRadius.circular(12), - ), - child: Icon( - Icons.account_circle, - color: theme.colorScheme.primary, - size: 24, - ), - ), - const SizedBox(width: 12), - Text( - 'Информация об аккаунте', - style: theme.textTheme.titleMedium?.copyWith( - fontWeight: FontWeight.bold, - ), - ), - ], - ), - ), - const Divider(height: 1), - _StatRow( - icon: Icons.collections_bookmark, - label: 'Паки', - value: user.packs.length.toString(), - color: Colors.blue, - ), - const Divider(height: 1), - _StatRow( - icon: Icons.shopping_bag, - label: 'Покупки', - value: user.purchases.length.toString(), - color: Colors.green, - ), - ], - ), - ); - } Widget _buildSettingsSection(BuildContext context) { final theme = Theme.of(context); @@ -665,21 +738,14 @@ class _ProfilePageState extends State { isDark ? Icons.dark_mode : Icons.light_mode, ), title: const Text('Dark Mode'), - trailing: Switch( - value: isDark, + trailing: ThemeToggleWidget( + isDark: isDark, onChanged: (_) { appScope.themeManager.toggleTheme(); }, ), ), const Divider(height: 1), - const ListTile( - leading: Icon(Icons.language), - title: Text('Language'), - trailing: Text('English'), - enabled: false, - ), - const Divider(height: 1), const ListTile( leading: Icon(Icons.volume_up), title: Text('Sound Effects'), @@ -701,7 +767,7 @@ class _ProfilePageState extends State { return SizedBox( width: double.infinity, child: ElevatedButton.icon( - onPressed: _isLoggingOut ? null : () => _logout(context), + onPressed: _isLoggingOut ? null : () => _showLogoutConfirmation(context), icon: _isLoggingOut ? const SizedBox( width: 20, @@ -730,63 +796,3 @@ class _ProfilePageState extends State { } } -/// Widget to display a stat row -class _StatRow extends StatelessWidget { - const _StatRow({ - required this.icon, - required this.label, - required this.value, - this.color, - }); - - final IconData icon; - final String label; - final String value; - final Color? color; - - @override - Widget build(BuildContext context) { - final theme = Theme.of(context); - final iconColor = color ?? theme.colorScheme.primary; - - return Padding( - padding: const EdgeInsets.symmetric(horizontal: 20.0, vertical: 16.0), - child: Row( - children: [ - Container( - padding: const EdgeInsets.all(8), - decoration: BoxDecoration( - color: iconColor.withOpacity(0.1), - borderRadius: BorderRadius.circular(10), - ), - child: Icon(icon, size: 22, color: iconColor), - ), - const SizedBox(width: 16), - Expanded( - child: Text( - label, - style: theme.textTheme.bodyLarge?.copyWith( - fontWeight: FontWeight.w500, - ), - ), - ), - Container( - padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6), - decoration: BoxDecoration( - color: iconColor.withOpacity(0.1), - borderRadius: BorderRadius.circular(12), - ), - child: Text( - value, - style: TextStyle( - fontSize: 16, - fontWeight: FontWeight.bold, - color: iconColor, - ), - ), - ), - ], - ), - ); - } -} diff --git a/mnemo_cards_web_v2/lib/presentation/pages/statistics/statistics_page.dart b/mnemo_cards_web_v2/lib/presentation/pages/statistics/statistics_page.dart index 4b7dde0..39b58b4 100644 --- a/mnemo_cards_web_v2/lib/presentation/pages/statistics/statistics_page.dart +++ b/mnemo_cards_web_v2/lib/presentation/pages/statistics/statistics_page.dart @@ -7,22 +7,14 @@ import '../../../domain/state/statistics_state_manager.dart'; import '../../widgets/error_view.dart'; import '../../widgets/loading_view.dart'; import 'widgets/statistics_overview_widget.dart'; -import 'widgets/words_statistics_widget.dart'; -import 'widgets/timeline_widget.dart'; -import 'widgets/achievements_widget.dart'; -import 'widgets/pack_progress_widget.dart'; /// Statistics page state manager type for refresh dialog typedef StatisticsStateManagerType = dynamic; -/// Main statistics page with tabbed interface +/// Main statistics page /// /// Displays comprehensive user statistics including: /// - Overview dashboard with key metrics -/// - Words learning progress and analytics -/// - Study timeline and activity charts -/// - Achievement progress and unlocks -/// - Pack completion progress class StatisticsPage extends StatefulWidget { const StatisticsPage({super.key}); @@ -30,19 +22,16 @@ class StatisticsPage extends StatefulWidget { State createState() => _StatisticsPageState(); } -class _StatisticsPageState extends State with TickerProviderStateMixin { - late TabController _tabController; +class _StatisticsPageState extends State { bool _hasLoaded = false; @override void initState() { super.initState(); - _tabController = TabController(length: 5, vsync: this); } @override void dispose() { - _tabController.dispose(); super.dispose(); } @@ -56,60 +45,6 @@ class _StatisticsPageState extends State with TickerProviderStat elevation: 0, backgroundColor: theme.colorScheme.surface, foregroundColor: theme.colorScheme.onSurface, - bottom: PreferredSize( - preferredSize: const Size.fromHeight(48), - child: Container( - decoration: BoxDecoration( - color: theme.colorScheme.surface, - border: Border( - bottom: BorderSide( - color: theme.dividerColor, - width: 1, - ), - ), - ), - child: TabBar( - controller: _tabController, - isScrollable: true, - tabAlignment: TabAlignment.start, - labelColor: theme.colorScheme.onSurface, - unselectedLabelColor: theme.colorScheme.onSurfaceVariant, - indicatorColor: theme.colorScheme.primary, - indicatorWeight: 3, - overlayColor: WidgetStateProperty.all(Colors.transparent), - dividerColor: Colors.transparent, - labelStyle: theme.textTheme.labelLarge?.copyWith( - fontWeight: FontWeight.w600, - color: theme.colorScheme.onSurface, - ), - unselectedLabelStyle: theme.textTheme.labelLarge?.copyWith( - color: theme.colorScheme.onSurfaceVariant, - ), - tabs: const [ - Tab( - icon: Icon(Icons.dashboard_outlined), - text: 'Обзор', - ), - Tab( - icon: Icon(Icons.library_books_outlined), - text: 'Слова', - ), - Tab( - icon: Icon(Icons.timeline_outlined), - text: 'Активность', - ), - Tab( - icon: Icon(Icons.emoji_events_outlined), - text: 'Достижения', - ), - Tab( - icon: Icon(Icons.inventory_2_outlined), - text: 'Паки', - ), - ], - ), - ), - ), ), body: ScopeBuilder( builder: (context, userScope) { @@ -147,52 +82,9 @@ class _StatisticsPageState extends State with TickerProviderStat return Stack( children: [ - TabBarView( - controller: _tabController, - children: [ - // Overview Tab - StatisticsOverviewWidget( - statisticsState: state, - onRefresh: () => userScope.statisticsStateManager.refreshStatistics(), - ), - - // Words Tab - WordsStatisticsWidget( - statisticsState: state, - onLoadWords: (params) => userScope.statisticsStateManager.loadWordsStatistics( - packId: params.packId, - limit: params.limit, - offset: params.offset, - sortBy: params.sortBy, - needsReview: params.needsReview, - ), - ), - - // Timeline/Activity Tab - TimelineWidget( - statisticsState: state, - onLoadTimeline: (period, from, to) => - userScope.statisticsStateManager.loadTimelineStatistics( - period: period, - from: from, - to: to, - ), - ), - - // Achievements Tab - AchievementsWidget( + StatisticsOverviewWidget( statisticsState: state, - statisticsStateManager: userScope.statisticsStateManager, - onLoadAchievements: () => userScope.statisticsStateManager.loadAchievements(), - ), - - // Packs Tab - PackProgressWidget( - statisticsState: state, - statisticsStateManager: userScope.statisticsStateManager, - onLoadPacks: (packId) => userScope.statisticsStateManager.loadPacksStatistics(packId: packId), - ), - ], + onRefresh: () => userScope.statisticsStateManager.refreshStatistics(), ), Positioned( bottom: 16, diff --git a/mnemo_cards_web_v2/lib/presentation/widgets/theme_toggle_widget.dart b/mnemo_cards_web_v2/lib/presentation/widgets/theme_toggle_widget.dart new file mode 100644 index 0000000..ab78610 --- /dev/null +++ b/mnemo_cards_web_v2/lib/presentation/widgets/theme_toggle_widget.dart @@ -0,0 +1,76 @@ +import 'package:flutter/material.dart'; + +/// Кастомный виджет для переключения темы с иконками солнца и луны +class ThemeToggleWidget extends StatelessWidget { + const ThemeToggleWidget({ + required this.isDark, + required this.onChanged, + super.key, + }); + + final bool isDark; + final ValueChanged onChanged; + + @override + Widget build(BuildContext context) { + final theme = Theme.of(context); + + return Container( + padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(24), + color: theme.colorScheme.surfaceContainerHighest.withOpacity(0.5), + ), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + // Иконка солнца + AnimatedContainer( + duration: const Duration(milliseconds: 200), + padding: const EdgeInsets.all(8), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(20), + color: !isDark + ? theme.colorScheme.primary.withOpacity(0.2) + : Colors.transparent, + ), + child: Icon( + Icons.wb_sunny, + color: !isDark + ? theme.colorScheme.primary + : theme.colorScheme.onSurfaceVariant, + size: 20, + ), + ), + + // Switch + Switch( + value: isDark, + onChanged: onChanged, + activeColor: theme.colorScheme.primary, + activeTrackColor: theme.colorScheme.primary.withOpacity(0.3), + ), + + // Иконка луны + AnimatedContainer( + duration: const Duration(milliseconds: 200), + padding: const EdgeInsets.all(8), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(20), + color: isDark + ? theme.colorScheme.primary.withOpacity(0.2) + : Colors.transparent, + ), + child: Icon( + Icons.nightlight_round, + color: isDark + ? theme.colorScheme.primary + : theme.colorScheme.onSurfaceVariant, + size: 20, + ), + ), + ], + ), + ); + } +} diff --git a/mnemo_cards_web_v2/test/presentation/widgets/theme_toggle_widget_test.dart b/mnemo_cards_web_v2/test/presentation/widgets/theme_toggle_widget_test.dart new file mode 100644 index 0000000..1cf5705 --- /dev/null +++ b/mnemo_cards_web_v2/test/presentation/widgets/theme_toggle_widget_test.dart @@ -0,0 +1,176 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mnemo_cards_web_v2/presentation/widgets/theme_toggle_widget.dart'; + +void main() { + group('ThemeToggleWidget', () { + testWidgets('displays sun and moon icons correctly', (tester) async { + bool isDark = false; + await tester.pumpWidget( + MaterialApp( + theme: ThemeData.light(), + home: Scaffold( + body: ThemeToggleWidget( + isDark: isDark, + onChanged: (value) => isDark = value, + ), + ), + ), + ); + + // Should display sun icon when light mode + expect(find.byIcon(Icons.wb_sunny), findsOneWidget); + // Should display moon icon + expect(find.byIcon(Icons.nightlight_round), findsOneWidget); + // Switch should be in light position + final switchFinder = find.byType(Switch); + expect(switchFinder, findsOneWidget); + Switch switchWidget = tester.widget(switchFinder); + expect(switchWidget.value, false); + }); + + testWidgets('displays correct icon highlights when dark mode', (tester) async { + bool isDark = true; + await tester.pumpWidget( + MaterialApp( + theme: ThemeData.dark(), + home: Scaffold( + body: ThemeToggleWidget( + isDark: isDark, + onChanged: (value) => isDark = value, + ), + ), + ), + ); + + // Switch should be in dark position + final switchFinder = find.byType(Switch); + Switch switchWidget = tester.widget(switchFinder); + expect(switchWidget.value, true); + }); + + testWidgets('calls onChanged when switch is toggled', (tester) async { + bool isDark = false; + bool callbackCalled = false; + bool callbackValue = false; + + await tester.pumpWidget( + MaterialApp( + theme: ThemeData.light(), + home: Scaffold( + body: ThemeToggleWidget( + isDark: isDark, + onChanged: (value) { + callbackCalled = true; + callbackValue = value; + }, + ), + ), + ), + ); + + // Tap the switch + await tester.tap(find.byType(Switch)); + await tester.pump(); + + // Verify callback was called with correct value + expect(callbackCalled, true); + expect(callbackValue, true); + }); + + testWidgets('has correct visual structure', (tester) async { + await tester.pumpWidget( + MaterialApp( + theme: ThemeData.light(), + home: Scaffold( + body: ThemeToggleWidget( + isDark: false, + onChanged: (_) {}, + ), + ), + ), + ); + + // Should have a container with rounded corners + final containerFinder = find.byType(Container); + expect(containerFinder, findsWidgets); + + // Should have a row with icons and switch + final rowFinder = find.byType(Row); + expect(rowFinder, findsOneWidget); + }); + + testWidgets('applies theme colors correctly', (tester) async { + await tester.pumpWidget( + MaterialApp( + theme: ThemeData( + colorScheme: const ColorScheme.light( + primary: Colors.blue, + onSurfaceVariant: Colors.grey, + ), + ), + home: Scaffold( + body: ThemeToggleWidget( + isDark: false, + onChanged: (_) {}, + ), + ), + ), + ); + + // Widget should render without issues with custom theme + expect(find.byType(ThemeToggleWidget), findsOneWidget); + }); + + testWidgets('handles rapid toggling correctly', (tester) async { + bool isDark = false; + int callbackCount = 0; + + await tester.pumpWidget( + MaterialApp( + theme: ThemeData.light(), + home: Scaffold( + body: ThemeToggleWidget( + isDark: isDark, + onChanged: (value) { + callbackCount++; + isDark = value; + }, + ), + ), + ), + ); + + // Tap switch multiple times + await tester.tap(find.byType(Switch)); + await tester.tap(find.byType(Switch)); + await tester.tap(find.byType(Switch)); + await tester.pump(); + + // Should have called callback 3 times + expect(callbackCount, 3); + }); + + testWidgets('maintains correct layout in different screen sizes', (tester) async { + await tester.pumpWidget( + MaterialApp( + theme: ThemeData.light(), + home: Scaffold( + body: Center( + child: ThemeToggleWidget( + isDark: false, + onChanged: (_) {}, + ), + ), + ), + ), + ); + + // Should maintain proper layout + final rowFinder = find.byType(Row); + final row = tester.widget(rowFinder); + expect(row.mainAxisSize, MainAxisSize.min); + expect(row.children.length, 3); // Sun icon, Switch, Moon icon + }); + }); +} diff --git a/tools/deploy/README-bump-version.md b/tools/deploy/README-bump-version.md index 7039600..669da1d 100644 --- a/tools/deploy/README-bump-version.md +++ b/tools/deploy/README-bump-version.md @@ -40,3 +40,4 @@ ### Интеграция в CI/CD: Скрипт автоматически запускается как pre-hook в GitHub Actions workflow перед каждым deploy'ем веб-приложения. +