diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..dfe0770 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +# Auto detect text files and perform LF normalization +* text=auto diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..682fbdb --- /dev/null +++ b/.gitignore @@ -0,0 +1,48 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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 +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# 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 + +lib/utils/keys.dart \ No newline at end of file diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..92f6487 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: b1395592de68cc8ac4522094ae59956dd21a91db + channel: stable + +project_type: app diff --git a/.netrc b/.netrc new file mode 100644 index 0000000..d6804e2 --- /dev/null +++ b/.netrc @@ -0,0 +1,3 @@ +machine api.mapbox.com +login mapbox +password sk.eyJ1Ijoic3ludGF4bHRkIiwiYSI6ImNrcjY2ZWZ0bTBiMGMyd2xwN2duajdodXQifQ.4JRUCSgvaTK2lssnMvRzRA diff --git a/README.md b/README.md new file mode 100644 index 0000000..3bdea63 --- /dev/null +++ b/README.md @@ -0,0 +1,113 @@ +# giraffe_spotter + +A new Flutter project. + +## 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://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. + +##Beware + +-Beware of 2 model classes after running this flutter command: + +```flutter + flutter pub build_runner +``` + +Files affected are item.g.dart and thumbnail.g.dart, so replace them with the code below :). + +##item.g should be: + +``` +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'Item.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +Item _$ItemFromJson(Map json) { + try{ + final data = Item( + title: Description.fromJson(json['title'] as Map), + link: Description.fromJson(json['link'] as Map), + comments: Description.fromJson(json['comments'] as Map), + creator: DecodedJson.fromJson(json['dc\u0024creator'] as Map), + pubDate: Description.fromJson(json['pubDate'] as Map), + category: DecodedJson.fromJson(json['category'] as Map), + guid: Description.fromJson(json['guid'] as Map), + description: DecodedJson.fromJson(json['description'] as Map), + encoded: DecodedJson.fromJson(json['content\u0024encoded'] as Map), + ); + return data; + } catch(_){ + final data = Item( + title: Description.fromJson(json['title'] as Map), + link: Description.fromJson(json['link'] as Map), + comments: Description.fromJson(json['comments'] as Map), + creator: DecodedJson.fromJson(json['dc\u0024creator'] as Map), + pubDate: Description.fromJson(json['pubDate'] as Map), + category: DecodedJson.fromJson(json['category'][0] as Map), + guid: Description.fromJson(json['guid'] as Map), + description: + DecodedJson.fromJson(json['description'] as Map), + encoded: DecodedJson.fromJson(json['content\u0024encoded'] as Map), + ); + return data; + } +} + +Map _$ItemToJson(Item instance) => { + 'title': instance.title, + 'link': instance.link, + 'comments': instance.comments, + 'dc\u0024creator': instance.creator, + 'pubDate': instance.pubDate, + 'category': instance.category, + 'guid': instance.guid, + 'description': instance.description, + 'content\u0024encoded': instance.encoded, +}; +``` + +##thumbnail.g.dart + +``` +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'ThumbNail.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** +ThumbNail _$ThumbNailFromJson(Map json) { + return ThumbNail( + json['title'] as String, + json['thumbnail_url'] as String, + ); +} + +Map _$ThumbNailToJson(ThumbNail instance) => { + 'title': instance.title, + 'thumbnail_url': instance.thumbnailUrl, +}; +``` + +#Addational files +Add this files in your vim .zshrc + +``` +machine api.mapbox.com +login mapbox +password sk.eyJ1Ijoic3ludGF4bHRkIiwiYSI6ImNrcjY2ZWZ0bTBiMGMyd2xwN2duajdodXQifQ.4JRUCSgvaTK2lssnMvRzRA +``` diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..0a741cb --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,11 @@ +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 diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..bebe150 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,74 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +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('app/key.properties') +if (keystorePropertiesFile.exists()) { + keystoreProperties.load(new FileInputStream(keystorePropertiesFile)) +} + +apply plugin: 'com.google.gms.google-services' +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 31 + ndkVersion "23.0.7530507" + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "ax.synt.giraffe_spotter" + minSdkVersion 24 + targetSdkVersion 31 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias keystoreProperties['keyAlias'] + keyPassword keystoreProperties['keyPassword'] + storeFile keystoreProperties['storeFile'] ? file(keystoreProperties['storeFile']) : null + storePassword keystoreProperties['storePassword'] + } + } + buildTypes { + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" + implementation "androidx.exifinterface:exifinterface:1.3.3" + implementation platform('com.google.firebase:firebase-bom:29.0.3') + implementation 'com.google.firebase:firebase-analytics' +} diff --git a/android/app/google-services.json b/android/app/google-services.json new file mode 100644 index 0000000..b1de141 --- /dev/null +++ b/android/app/google-services.json @@ -0,0 +1,55 @@ +{ + "project_info": { + "project_number": "568065724442", + "project_id": "giraffespotter-546fc", + "storage_bucket": "giraffespotter-546fc.appspot.com" + }, + "client": [ + { + "client_info": { + "mobilesdk_app_id": "1:568065724442:android:8bece7988616f6d31701a3", + "android_client_info": { + "package_name": "ax.synt.giraffe_spotter" + } + }, + "oauth_client": [ + { + "client_id": "568065724442-si5vk38ns434orsihe23r7b2qb1o27gd.apps.googleusercontent.com", + "client_type": 1, + "android_info": { + "package_name": "ax.synt.giraffe_spotter", + "certificate_hash": "27034b6919b8e7e4a1d633ed5bfc692ce42ddb12" + } + }, + { + "client_id": "568065724442-29knpcjidvotnn8bsbtbupcn2emme6ih.apps.googleusercontent.com", + "client_type": 3 + } + ], + "api_key": [ + { + "current_key": "AIzaSyAnX10VazrXJpqRgnCJDRBLSrCq_pFGEwE" + } + ], + "services": { + "appinvite_service": { + "other_platform_oauth_client": [ + { + "client_id": "568065724442-29knpcjidvotnn8bsbtbupcn2emme6ih.apps.googleusercontent.com", + "client_type": 3 + }, + { + "client_id": "568065724442-3v8e5kacef96e17r5i33itnputk9pbq4.apps.googleusercontent.com", + "client_type": 2, + "ios_info": { + "bundle_id": "ax.synt.giraffeSpotter", + "app_store_id": "1573260404" + } + } + ] + } + } + } + ], + "configuration_version": "1" +} \ No newline at end of file diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..dba7861 --- /dev/null +++ b/android/app/src/debug/AndroidManifest.xml @@ -0,0 +1,7 @@ + + + + diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..16ef6a0 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,51 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/ic_launcher-playstore.png b/android/app/src/main/ic_launcher-playstore.png new file mode 100644 index 0000000..9f36d26 Binary files /dev/null and b/android/app/src/main/ic_launcher-playstore.png differ diff --git a/android/app/src/main/kotlin/ax/synt/giraffe_spotter/MainActivity.kt b/android/app/src/main/kotlin/ax/synt/giraffe_spotter/MainActivity.kt new file mode 100644 index 0000000..f0d1815 --- /dev/null +++ b/android/app/src/main/kotlin/ax/synt/giraffe_spotter/MainActivity.kt @@ -0,0 +1,59 @@ +package ax.synt.giraffe_spotter + +import android.util.Log +import androidx.annotation.NonNull +import io.flutter.embedding.android.FlutterActivity +import io.flutter.embedding.engine.FlutterEngine +import io.flutter.plugin.common.MethodChannel +import java.io.File +import java.io.FileInputStream +import java.io.IOException +import androidx.exifinterface.media.ExifInterface + + +class MainActivity: FlutterActivity() { + private val channel = "ax.synt.giraffe_spotter/coordinates" + + override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) { + super.configureFlutterEngine(flutterEngine) + MethodChannel(flutterEngine.dartExecutor.binaryMessenger, channel).setMethodCallHandler { call, result -> + when (call.method) { + "getCoordsFilePath" -> getCoords(result, call.argument("path")) + else -> result.notImplemented() + } + } + } + + private fun getCoords(result: MethodChannel.Result, path: String?) { + var inputStream: FileInputStream? = null + var latLng: DoubleArray? = doubleArrayOf(0.0, 0.0) + if (path == null || path.isEmpty()) { + result.success(latLng) +// return + } + + try { + inputStream = FileInputStream(File(path)) + val exifInterface = ExifInterface(inputStream) + latLng = exifInterface.latLong + inputStream.close() + Log.d("Giraffe Spotter","Lat long picked: $latLng") + +// if(latLng) { +// result.success() +// listOf(latLng[0], latLng[1]) +// } else { +// listOf(1.0f, 1.0f) +// } + } catch (e: IOException) { + throw e + } finally { + if (inputStream != null) { + try { + inputStream.close() + } catch (ignored: IOException) { + } + } + } + } +} diff --git a/android/app/src/main/res/drawable-hdpi/splash.png b/android/app/src/main/res/drawable-hdpi/splash.png new file mode 100644 index 0000000..caf8cc7 Binary files /dev/null and b/android/app/src/main/res/drawable-hdpi/splash.png differ diff --git a/android/app/src/main/res/drawable-mdpi/splash.png b/android/app/src/main/res/drawable-mdpi/splash.png new file mode 100644 index 0000000..94f3260 Binary files /dev/null and b/android/app/src/main/res/drawable-mdpi/splash.png differ diff --git a/android/app/src/main/res/drawable-v21/background.png b/android/app/src/main/res/drawable-v21/background.png new file mode 100644 index 0000000..21b2005 Binary files /dev/null and b/android/app/src/main/res/drawable-v21/background.png differ diff --git a/android/app/src/main/res/drawable-v21/launch_background.xml b/android/app/src/main/res/drawable-v21/launch_background.xml new file mode 100644 index 0000000..3fe6b2e --- /dev/null +++ b/android/app/src/main/res/drawable-v21/launch_background.xml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/android/app/src/main/res/drawable-xhdpi/splash.png b/android/app/src/main/res/drawable-xhdpi/splash.png new file mode 100644 index 0000000..beec853 Binary files /dev/null and b/android/app/src/main/res/drawable-xhdpi/splash.png differ diff --git a/android/app/src/main/res/drawable-xxhdpi/splash.png b/android/app/src/main/res/drawable-xxhdpi/splash.png new file mode 100644 index 0000000..2b15f09 Binary files /dev/null and b/android/app/src/main/res/drawable-xxhdpi/splash.png differ diff --git a/android/app/src/main/res/drawable-xxxhdpi/splash.png b/android/app/src/main/res/drawable-xxxhdpi/splash.png new file mode 100644 index 0000000..2d09338 Binary files /dev/null and b/android/app/src/main/res/drawable-xxxhdpi/splash.png differ diff --git a/android/app/src/main/res/drawable/background.png b/android/app/src/main/res/drawable/background.png new file mode 100644 index 0000000..21b2005 Binary files /dev/null and b/android/app/src/main/res/drawable/background.png differ diff --git a/android/app/src/main/res/drawable/launch_background.xml b/android/app/src/main/res/drawable/launch_background.xml new file mode 100644 index 0000000..3fe6b2e --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml new file mode 100644 index 0000000..4ae7d12 --- /dev/null +++ b/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml new file mode 100644 index 0000000..4ae7d12 --- /dev/null +++ b/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/android/app/src/main/res/mipmap-hdpi/ic_launcher_background.png b/android/app/src/main/res/mipmap-hdpi/ic_launcher_background.png new file mode 100644 index 0000000..d314664 Binary files /dev/null and b/android/app/src/main/res/mipmap-hdpi/ic_launcher_background.png differ diff --git a/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png b/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png new file mode 100644 index 0000000..c625ebe Binary files /dev/null and b/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png differ diff --git a/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png b/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png new file mode 100644 index 0000000..7829f0e Binary files /dev/null and b/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png differ diff --git a/android/app/src/main/res/mipmap-mdpi/ic_launcher_background.png b/android/app/src/main/res/mipmap-mdpi/ic_launcher_background.png new file mode 100644 index 0000000..3f6eb01 Binary files /dev/null and b/android/app/src/main/res/mipmap-mdpi/ic_launcher_background.png differ diff --git a/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png b/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png new file mode 100644 index 0000000..2963916 Binary files /dev/null and b/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png differ diff --git a/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png b/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png new file mode 100644 index 0000000..db8e9d8 Binary files /dev/null and b/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png differ diff --git a/android/app/src/main/res/mipmap-xhdpi/ic_launcher_background.png b/android/app/src/main/res/mipmap-xhdpi/ic_launcher_background.png new file mode 100644 index 0000000..42b1c00 Binary files /dev/null and b/android/app/src/main/res/mipmap-xhdpi/ic_launcher_background.png differ diff --git a/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png b/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png new file mode 100644 index 0000000..13096a4 Binary files /dev/null and b/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png differ diff --git a/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png new file mode 100644 index 0000000..c659817 Binary files /dev/null and b/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png differ diff --git a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_background.png b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_background.png new file mode 100644 index 0000000..5eb9b4d Binary files /dev/null and b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_background.png differ diff --git a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png new file mode 100644 index 0000000..90724e7 Binary files /dev/null and b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png differ diff --git a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png new file mode 100644 index 0000000..b6ff7a4 Binary files /dev/null and b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png differ diff --git a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_background.png b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_background.png new file mode 100644 index 0000000..faa3932 Binary files /dev/null and b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_background.png differ diff --git a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png new file mode 100644 index 0000000..3f91d26 Binary files /dev/null and b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png differ diff --git a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png new file mode 100644 index 0000000..4a0e26e Binary files /dev/null and b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png differ diff --git a/android/app/src/main/res/values-night/styles.xml b/android/app/src/main/res/values-night/styles.xml new file mode 100644 index 0000000..7c806c6 --- /dev/null +++ b/android/app/src/main/res/values-night/styles.xml @@ -0,0 +1,19 @@ + + + + + + + \ No newline at end of file diff --git a/android/app/src/main/res/values/styles.xml b/android/app/src/main/res/values/styles.xml new file mode 100644 index 0000000..c8a5e60 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,19 @@ + + + + + + + \ No newline at end of file diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..e9a1757 --- /dev/null +++ b/android/app/src/profile/AndroidManifest.xml @@ -0,0 +1,8 @@ + + + + + diff --git a/android/build.gradle b/android/build.gradle new file mode 100644 index 0000000..f27b2a0 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,36 @@ +buildscript { + ext.kotlin_version = '1.5.30' + repositories { + google() + mavenCentral() + } + + dependencies { + classpath 'com.google.gms:google-services:4.3.10' + classpath 'com.android.tools.build:gradle:7.0.4' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + mavenCentral() + } + + tasks.withType(JavaCompile) { + options.compilerArgs << '-Xlint:-options' + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..47870cf --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.useAndroidX=true +android.enableJetifier=true +MAPBOX_DOWNLOADS_TOKEN=sk.eyJ1Ijoic3ludGF4bHRkIiwiYSI6ImNrcjY2ZWZ0bTBiMGMyd2xwN2duajdodXQifQ.4JRUCSgvaTK2lssnMvRzRA \ No newline at end of file diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..b8793d3 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-7.0.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..44e62bc --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,11 @@ +include ':app' + +def localPropertiesFile = new File(rootProject.projectDir, "local.properties") +def properties = new Properties() + +assert localPropertiesFile.exists() +localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) } + +def flutterSdkPath = properties.getProperty("flutter.sdk") +assert flutterSdkPath != null, "flutter.sdk not set in local.properties" +apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle" diff --git a/android/settings_aar.gradle b/android/settings_aar.gradle new file mode 100644 index 0000000..e7b4def --- /dev/null +++ b/android/settings_aar.gradle @@ -0,0 +1 @@ +include ':app' diff --git a/assets/3 User.svg b/assets/3 User.svg new file mode 100644 index 0000000..0c7e9d2 --- /dev/null +++ b/assets/3 User.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/Calendar.svg b/assets/Calendar.svg new file mode 100644 index 0000000..be5462e --- /dev/null +++ b/assets/Calendar.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/Delete.svg b/assets/Delete.svg new file mode 100644 index 0000000..e7e813e --- /dev/null +++ b/assets/Delete.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/Hide.png b/assets/Hide.png new file mode 100644 index 0000000..cf0d8e2 Binary files /dev/null and b/assets/Hide.png differ diff --git a/assets/Info Square.svg b/assets/Info Square.svg new file mode 100644 index 0000000..1ab75b9 --- /dev/null +++ b/assets/Info Square.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/Location.svg b/assets/Location.svg new file mode 100644 index 0000000..e946137 --- /dev/null +++ b/assets/Location.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/Logout.png b/assets/Logout.png new file mode 100644 index 0000000..66c7f9e Binary files /dev/null and b/assets/Logout.png differ diff --git a/assets/Logout.svg b/assets/Logout.svg new file mode 100644 index 0000000..d6468e4 --- /dev/null +++ b/assets/Logout.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/Time.svg b/assets/Time.svg new file mode 100644 index 0000000..b05dd2b --- /dev/null +++ b/assets/Time.svg @@ -0,0 +1,4 @@ + + + + diff --git a/assets/about_us.svg b/assets/about_us.svg new file mode 100644 index 0000000..b1bc331 --- /dev/null +++ b/assets/about_us.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/active_dot.svg b/assets/active_dot.svg new file mode 100644 index 0000000..b26ff1e --- /dev/null +++ b/assets/active_dot.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/add.svg b/assets/add.svg new file mode 100644 index 0000000..10bb3de --- /dev/null +++ b/assets/add.svg @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/assets/arrow_back.png b/assets/arrow_back.png new file mode 100644 index 0000000..b608ef9 Binary files /dev/null and b/assets/arrow_back.png differ diff --git a/assets/arrow_left.png b/assets/arrow_left.png new file mode 100644 index 0000000..b2062ab Binary files /dev/null and b/assets/arrow_left.png differ diff --git a/assets/arrow_right.png b/assets/arrow_right.png new file mode 100644 index 0000000..b506127 Binary files /dev/null and b/assets/arrow_right.png differ diff --git a/assets/bottomDesign.png b/assets/bottomDesign.png new file mode 100644 index 0000000..e0196ea Binary files /dev/null and b/assets/bottomDesign.png differ diff --git a/assets/calendar.png b/assets/calendar.png new file mode 100644 index 0000000..b16b406 Binary files /dev/null and b/assets/calendar.png differ diff --git a/assets/camera.png b/assets/camera.png new file mode 100644 index 0000000..af9f8d9 Binary files /dev/null and b/assets/camera.png differ diff --git a/assets/delete2.svg b/assets/delete2.svg new file mode 100644 index 0000000..e050710 --- /dev/null +++ b/assets/delete2.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/donate.svg b/assets/donate.svg new file mode 100644 index 0000000..8721152 --- /dev/null +++ b/assets/donate.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/assets/edit.svg b/assets/edit.svg new file mode 100644 index 0000000..08f68ec --- /dev/null +++ b/assets/edit.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/fonts/Poppins-Bold.ttf b/assets/fonts/Poppins-Bold.ttf new file mode 100644 index 0000000..b94d47f Binary files /dev/null and b/assets/fonts/Poppins-Bold.ttf differ diff --git a/assets/fonts/Poppins-ExtraBold.ttf b/assets/fonts/Poppins-ExtraBold.ttf new file mode 100644 index 0000000..8f008c3 Binary files /dev/null and b/assets/fonts/Poppins-ExtraBold.ttf differ diff --git a/assets/fonts/Poppins-ExtraLight.ttf b/assets/fonts/Poppins-ExtraLight.ttf new file mode 100644 index 0000000..ee62382 Binary files /dev/null and b/assets/fonts/Poppins-ExtraLight.ttf differ diff --git a/assets/fonts/Poppins-Light.ttf b/assets/fonts/Poppins-Light.ttf new file mode 100644 index 0000000..2ab0221 Binary files /dev/null and b/assets/fonts/Poppins-Light.ttf differ diff --git a/assets/fonts/Poppins-Medium.ttf b/assets/fonts/Poppins-Medium.ttf new file mode 100644 index 0000000..e90e87e Binary files /dev/null and b/assets/fonts/Poppins-Medium.ttf differ diff --git a/assets/fonts/Poppins-Regular.ttf b/assets/fonts/Poppins-Regular.ttf new file mode 100644 index 0000000..be06e7f Binary files /dev/null and b/assets/fonts/Poppins-Regular.ttf differ diff --git a/assets/fonts/Poppins-SemiBold.ttf b/assets/fonts/Poppins-SemiBold.ttf new file mode 100644 index 0000000..dabf7c2 Binary files /dev/null and b/assets/fonts/Poppins-SemiBold.ttf differ diff --git a/assets/fonts/Poppins-Thin.ttf b/assets/fonts/Poppins-Thin.ttf new file mode 100644 index 0000000..f5c0fdd Binary files /dev/null and b/assets/fonts/Poppins-Thin.ttf differ diff --git a/assets/giraffe_one.png b/assets/giraffe_one.png new file mode 100644 index 0000000..f11cd92 Binary files /dev/null and b/assets/giraffe_one.png differ diff --git a/assets/giraffe_two.png b/assets/giraffe_two.png new file mode 100644 index 0000000..6d84625 Binary files /dev/null and b/assets/giraffe_two.png differ diff --git a/assets/google_map.png b/assets/google_map.png new file mode 100644 index 0000000..ae5ad0d Binary files /dev/null and b/assets/google_map.png differ diff --git a/assets/home_heart.svg b/assets/home_heart.svg new file mode 100644 index 0000000..1a1bc14 --- /dev/null +++ b/assets/home_heart.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/images/AboutMap.png b/assets/images/AboutMap.png new file mode 100644 index 0000000..52a45ac Binary files /dev/null and b/assets/images/AboutMap.png differ diff --git a/assets/images/ActiveCamera.svg b/assets/images/ActiveCamera.svg new file mode 100644 index 0000000..e7c923d --- /dev/null +++ b/assets/images/ActiveCamera.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/images/ActiveHeart.svg b/assets/images/ActiveHeart.svg new file mode 100644 index 0000000..e67eb90 --- /dev/null +++ b/assets/images/ActiveHeart.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/images/ActiveLearn.svg b/assets/images/ActiveLearn.svg new file mode 100644 index 0000000..fee2638 --- /dev/null +++ b/assets/images/ActiveLearn.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/images/Anne.png b/assets/images/Anne.png new file mode 100644 index 0000000..365d088 Binary files /dev/null and b/assets/images/Anne.png differ diff --git a/assets/images/Authimage.png b/assets/images/Authimage.png new file mode 100644 index 0000000..5a0bd40 Binary files /dev/null and b/assets/images/Authimage.png differ diff --git a/assets/images/Capture.svg b/assets/images/Capture.svg new file mode 100644 index 0000000..512ae1d --- /dev/null +++ b/assets/images/Capture.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/images/Curve.png b/assets/images/Curve.png new file mode 100644 index 0000000..38b150e Binary files /dev/null and b/assets/images/Curve.png differ diff --git a/assets/images/Donation.svg b/assets/images/Donation.svg new file mode 100644 index 0000000..43db5f1 --- /dev/null +++ b/assets/images/Donation.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/images/Favorite.svg b/assets/images/Favorite.svg new file mode 100644 index 0000000..a46ce2b --- /dev/null +++ b/assets/images/Favorite.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/images/Flag3.png b/assets/images/Flag3.png new file mode 100644 index 0000000..7bcac40 Binary files /dev/null and b/assets/images/Flag3.png differ diff --git a/assets/images/Flag4.png b/assets/images/Flag4.png new file mode 100644 index 0000000..b719650 Binary files /dev/null and b/assets/images/Flag4.png differ diff --git a/assets/images/ForgiveAssets.png b/assets/images/ForgiveAssets.png new file mode 100644 index 0000000..ccdde62 Binary files /dev/null and b/assets/images/ForgiveAssets.png differ diff --git a/assets/images/GiraffeInfo.png b/assets/images/GiraffeInfo.png new file mode 100644 index 0000000..cb2829a Binary files /dev/null and b/assets/images/GiraffeInfo.png differ diff --git a/assets/images/GiraffeLogo.png b/assets/images/GiraffeLogo.png new file mode 100644 index 0000000..684047e Binary files /dev/null and b/assets/images/GiraffeLogo.png differ diff --git a/assets/images/GiraffeLogo.svg b/assets/images/GiraffeLogo.svg new file mode 100644 index 0000000..72d0f9d --- /dev/null +++ b/assets/images/GiraffeLogo.svg @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/assets/images/GiraffePic1.png b/assets/images/GiraffePic1.png new file mode 100644 index 0000000..d5dfdf5 Binary files /dev/null and b/assets/images/GiraffePic1.png differ diff --git a/assets/images/GiraffePic2.png b/assets/images/GiraffePic2.png new file mode 100644 index 0000000..fb72c9f Binary files /dev/null and b/assets/images/GiraffePic2.png differ diff --git a/assets/images/GiraffePic3.png b/assets/images/GiraffePic3.png new file mode 100644 index 0000000..e662a39 Binary files /dev/null and b/assets/images/GiraffePic3.png differ diff --git a/assets/images/GiraffePic4.png b/assets/images/GiraffePic4.png new file mode 100644 index 0000000..20f4e39 Binary files /dev/null and b/assets/images/GiraffePic4.png differ diff --git a/assets/images/Heart.svg b/assets/images/Heart.svg new file mode 100644 index 0000000..ba8f5bf --- /dev/null +++ b/assets/images/Heart.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/images/Home.svg b/assets/images/Home.svg new file mode 100644 index 0000000..431b02d --- /dev/null +++ b/assets/images/Home.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/images/InactiveHome.svg b/assets/images/InactiveHome.svg new file mode 100644 index 0000000..fb8344c --- /dev/null +++ b/assets/images/InactiveHome.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/images/Info.svg b/assets/images/Info.svg new file mode 100644 index 0000000..3923fab --- /dev/null +++ b/assets/images/Info.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/images/John.png b/assets/images/John.png new file mode 100644 index 0000000..780e4f4 Binary files /dev/null and b/assets/images/John.png differ diff --git a/assets/images/Kenya.png b/assets/images/Kenya.png new file mode 100644 index 0000000..1c894ee Binary files /dev/null and b/assets/images/Kenya.png differ diff --git a/assets/images/Libya.png b/assets/images/Libya.png new file mode 100644 index 0000000..37fefb3 Binary files /dev/null and b/assets/images/Libya.png differ diff --git a/assets/images/Location.svg b/assets/images/Location.svg new file mode 100644 index 0000000..0ad802d --- /dev/null +++ b/assets/images/Location.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/images/Map.png b/assets/images/Map.png new file mode 100644 index 0000000..bd3bb1b Binary files /dev/null and b/assets/images/Map.png differ diff --git a/assets/images/Marker.png b/assets/images/Marker.png new file mode 100644 index 0000000..2e12a37 Binary files /dev/null and b/assets/images/Marker.png differ diff --git a/assets/images/Menu.svg b/assets/images/Menu.svg new file mode 100644 index 0000000..1d1f23f --- /dev/null +++ b/assets/images/Menu.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/assets/images/Notifications.svg b/assets/images/Notifications.svg new file mode 100644 index 0000000..f1a66df --- /dev/null +++ b/assets/images/Notifications.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/images/Rejected.svg b/assets/images/Rejected.svg new file mode 100644 index 0000000..f70e82d --- /dev/null +++ b/assets/images/Rejected.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/assets/images/Resend.png b/assets/images/Resend.png new file mode 100644 index 0000000..0ba2b9f Binary files /dev/null and b/assets/images/Resend.png differ diff --git a/assets/images/Share.svg b/assets/images/Share.svg new file mode 100644 index 0000000..fa4338b --- /dev/null +++ b/assets/images/Share.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/images/SplashLogo.png b/assets/images/SplashLogo.png new file mode 100644 index 0000000..6635b13 Binary files /dev/null and b/assets/images/SplashLogo.png differ diff --git a/assets/images/Success.svg b/assets/images/Success.svg new file mode 100644 index 0000000..0c85b82 --- /dev/null +++ b/assets/images/Success.svg @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/images/Video.svg b/assets/images/Video.svg new file mode 100644 index 0000000..998da10 --- /dev/null +++ b/assets/images/Video.svg @@ -0,0 +1,4 @@ + + + + diff --git a/assets/images/camera.svg b/assets/images/camera.svg new file mode 100644 index 0000000..80008da --- /dev/null +++ b/assets/images/camera.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/images/dropDownIcon.png b/assets/images/dropDownIcon.png new file mode 100644 index 0000000..6dac552 Binary files /dev/null and b/assets/images/dropDownIcon.png differ diff --git a/assets/images/empty_favorites.svg b/assets/images/empty_favorites.svg new file mode 100644 index 0000000..717e577 --- /dev/null +++ b/assets/images/empty_favorites.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/images/facebook.svg b/assets/images/facebook.svg new file mode 100644 index 0000000..e3c90ff --- /dev/null +++ b/assets/images/facebook.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/assets/images/filter.png b/assets/images/filter.png new file mode 100644 index 0000000..eef212d Binary files /dev/null and b/assets/images/filter.png differ diff --git a/assets/images/forgot.svg b/assets/images/forgot.svg new file mode 100644 index 0000000..744b4df --- /dev/null +++ b/assets/images/forgot.svg @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/images/giraffe_logo.png b/assets/images/giraffe_logo.png new file mode 100644 index 0000000..5ef7d35 Binary files /dev/null and b/assets/images/giraffe_logo.png differ diff --git a/assets/images/giraffe_logo.svg b/assets/images/giraffe_logo.svg new file mode 100644 index 0000000..c42787b --- /dev/null +++ b/assets/images/giraffe_logo.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/assets/images/instagram.svg b/assets/images/instagram.svg new file mode 100644 index 0000000..657d6ff --- /dev/null +++ b/assets/images/instagram.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/assets/images/male.svg b/assets/images/male.svg new file mode 100644 index 0000000..f06d1f8 --- /dev/null +++ b/assets/images/male.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/images/reset_password.svg b/assets/images/reset_password.svg new file mode 100644 index 0000000..3245b5e --- /dev/null +++ b/assets/images/reset_password.svg @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/images/website.png b/assets/images/website.png new file mode 100644 index 0000000..7a2acb6 Binary files /dev/null and b/assets/images/website.png differ diff --git a/assets/images/youtube.svg b/assets/images/youtube.svg new file mode 100644 index 0000000..4338fa5 --- /dev/null +++ b/assets/images/youtube.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/assets/invite_friends.svg b/assets/invite_friends.svg new file mode 100644 index 0000000..60f7d84 --- /dev/null +++ b/assets/invite_friends.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/line.png b/assets/line.png new file mode 100644 index 0000000..60e373b Binary files /dev/null and b/assets/line.png differ diff --git a/assets/location.png b/assets/location.png new file mode 100644 index 0000000..5c9585b Binary files /dev/null and b/assets/location.png differ diff --git a/assets/lottie/comming_soon.json b/assets/lottie/comming_soon.json new file mode 100644 index 0000000..ef5ce5d --- /dev/null +++ b/assets/lottie/comming_soon.json @@ -0,0 +1 @@ +{"assets":[],"layers":[{"ddd":0,"ind":0,"ty":4,"nm":"形状图层 11","ks":{"o":{"k":100},"r":{"k":0},"p":{"k":[408,186,0]},"a":{"k":[0,0,0]},"s":{"k":[100,100,100]}},"ao":0,"shapes":[],"ip":0,"op":140,"st":0,"bm":0,"sr":1},{"ddd":0,"ind":1,"ty":4,"nm":"“o 6”轮廓","parent":3,"ks":{"o":{"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":46,"s":[0],"e":[100]},{"t":47}]},"r":{"k":0},"p":{"k":[24.814,-62.359,0]},"a":{"k":[22.808,-61.369,0]},"s":{"k":[98,102,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"k":{"i":[[-14.758,0],[0,19.476],[0,0],[14.758,0],[0,-19.355],[0,0]],"o":[[14.154,0],[0,0],[0,-19.476],[-14.033,0],[0,0],[0,19.476]],"v":[[30.968,-4.839],[56.13,-34.235],[56.13,-35.323],[30.968,-64.235],[5.928,-35.081],[5.928,-33.751]],"c":true}},"nm":"o","mn":"ADBE Vector Shape - Group"},{"ind":1,"ty":"sh","ks":{"k":{"i":[[12.944,0],[0,17.904],[0,0],[-12.823,0],[0,-18.508],[0,0]],"o":[[-12.944,0],[0,0],[0,-17.42],[12.944,0],[0,0],[0,17.783]],"v":[[30.968,-7.379],[8.831,-33.509],[8.831,-35.202],[30.968,-61.695],[53.227,-35.565],[53.227,-33.993]],"c":true}},"nm":"o","mn":"ADBE Vector Shape - Group"},{"ty":"mm","mm":1,"nm":"合并路径 1","mn":"ADBE Vector Filter - Merge"},{"ty":"fl","fillEnabled":true,"c":{"k":[0,0,0,1]},"o":{"k":100},"nm":"填充 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"k":[0,0],"ix":2},"a":{"k":[0,0],"ix":1},"s":{"k":[100,100],"ix":3},"r":{"k":0,"ix":6},"o":{"k":100,"ix":7},"sk":{"k":0,"ix":4},"sa":{"k":0,"ix":5},"nm":"变换"}],"nm":"o","np":5,"mn":"ADBE Vector Group"}],"ip":0,"op":140,"st":0,"bm":0,"sr":1},{"ddd":0,"ind":2,"ty":4,"nm":"“o 5”轮廓","parent":3,"ks":{"o":{"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":46,"s":[0],"e":[100]},{"t":47}]},"r":{"k":0},"p":{"k":[30.928,-60.228,0]},"a":{"k":[26.294,-61.781,0]},"s":{"k":[98,102,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"k":{"i":[[-14.758,0],[0,19.476],[0,0],[14.758,0],[0,-19.355],[0,0]],"o":[[14.154,0],[0,0],[0,-19.476],[-14.033,0],[0,0],[0,19.476]],"v":[[30.968,-4.839],[56.13,-34.235],[56.13,-35.323],[30.968,-64.235],[5.928,-35.081],[5.928,-33.751]],"c":true}},"nm":"o","mn":"ADBE Vector Shape - Group"},{"ind":1,"ty":"sh","ks":{"k":{"i":[[12.944,0],[0,17.904],[0,0],[-12.823,0],[0,-18.508],[0,0]],"o":[[-12.944,0],[0,0],[0,-17.42],[12.944,0],[0,0],[0,17.783]],"v":[[30.968,-7.379],[8.831,-33.509],[8.831,-35.202],[30.968,-61.695],[53.227,-35.565],[53.227,-33.993]],"c":true}},"nm":"o","mn":"ADBE Vector Shape - Group"},{"ty":"mm","mm":1,"nm":"合并路径 1","mn":"ADBE Vector Filter - Merge"},{"ty":"fl","fillEnabled":true,"c":{"k":[0,0,0,1]},"o":{"k":100},"nm":"填充 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"k":[0,0],"ix":2},"a":{"k":[0,0],"ix":1},"s":{"k":[100,100],"ix":3},"r":{"k":0,"ix":6},"o":{"k":100,"ix":7},"sk":{"k":0,"ix":4},"sa":{"k":0,"ix":5},"nm":"变换"}],"nm":"o","np":5,"mn":"ADBE Vector Group"}],"ip":0,"op":140,"st":0,"bm":0,"sr":1},{"ddd":0,"ind":3,"ty":4,"nm":"“o 4”轮廓","ks":{"o":{"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":46,"s":[0],"e":[100]},{"t":47}]},"r":{"k":0},"p":{"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":41,"s":[537.5,322,0],"e":[537.5,352,0],"to":[0,5,0],"ti":[0,-5,0]},{"t":47}]},"a":{"k":[24.006,-4.974,0]},"s":{"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,0.667]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0.333]},"n":["0p667_1_0p333_0","0p667_1_0p333_0","0p667_0p667_0p333_0p333"],"t":41,"s":[100,100,100],"e":[116,70,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,0.667]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0.333]},"n":["0p667_1_0p333_0","0p667_1_0p333_0","0p667_0p667_0p333_0p333"],"t":47,"s":[116,70,100],"e":[95,105,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,0.667]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0.333]},"n":["0p667_1_0p333_0","0p667_1_0p333_0","0p667_0p667_0p333_0p333"],"t":52,"s":[95,105,100],"e":[106,90,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,0.667]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0.333]},"n":["0p667_1_0p333_0","0p667_1_0p333_0","0p667_0p667_0p333_0p333"],"t":56,"s":[106,90,100],"e":[98,100,100]},{"t":60}]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"k":{"i":[[-14.758,0],[0,19.476],[0,0],[14.758,0],[0,-19.355],[0,0]],"o":[[14.154,0],[0,0],[0,-19.476],[-14.033,0],[0,0],[0,19.476]],"v":[[30.968,-4.839],[56.13,-34.235],[56.13,-35.323],[30.968,-64.235],[5.928,-35.081],[5.928,-33.751]],"c":true}},"nm":"o","mn":"ADBE Vector Shape - Group"},{"ind":1,"ty":"sh","ks":{"k":{"i":[[12.944,0],[0,17.904],[0,0],[-12.823,0],[0,-18.508],[0,0]],"o":[[-12.944,0],[0,0],[0,-17.42],[12.944,0],[0,0],[0,17.783]],"v":[[30.968,-7.379],[8.831,-33.509],[8.831,-35.202],[30.968,-61.695],[53.227,-35.565],[53.227,-33.993]],"c":true}},"nm":"o","mn":"ADBE Vector Shape - Group"},{"ty":"mm","mm":1,"nm":"合并路径 1","mn":"ADBE Vector Filter - Merge"},{"ty":"fl","fillEnabled":true,"c":{"k":[0,0,0,1]},"o":{"k":100},"nm":"填充 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"k":[0,0],"ix":2},"a":{"k":[0,0],"ix":1},"s":{"k":[100,100],"ix":3},"r":{"k":0,"ix":6},"o":{"k":100,"ix":7},"sk":{"k":0,"ix":4},"sa":{"k":0,"ix":5},"nm":"变换"}],"nm":"o","np":5,"mn":"ADBE Vector Group"}],"ip":0,"op":140,"st":0,"bm":0,"sr":1},{"ddd":0,"ind":4,"ty":4,"nm":"“o 3”轮廓","parent":6,"ks":{"o":{"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":46,"s":[100],"e":[0]},{"t":47}]},"r":{"k":0},"p":{"k":[24.08,-61.869,0]},"a":{"k":[22.808,-61.369,0]},"s":{"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"k":{"i":[[-14.758,0],[0,19.476],[0,0],[14.758,0],[0,-19.355],[0,0]],"o":[[14.154,0],[0,0],[0,-19.476],[-14.033,0],[0,0],[0,19.476]],"v":[[30.968,-4.839],[56.13,-34.235],[56.13,-35.323],[30.968,-64.235],[5.928,-35.081],[5.928,-33.751]],"c":true}},"nm":"o","mn":"ADBE Vector Shape - Group"},{"ind":1,"ty":"sh","ks":{"k":{"i":[[12.944,0],[0,17.904],[0,0],[-12.823,0],[0,-18.508],[0,0]],"o":[[-12.944,0],[0,0],[0,-17.42],[12.944,0],[0,0],[0,17.783]],"v":[[30.968,-7.379],[8.831,-33.509],[8.831,-35.202],[30.968,-61.695],[53.227,-35.565],[53.227,-33.993]],"c":true}},"nm":"o","mn":"ADBE Vector Shape - Group"},{"ty":"mm","mm":1,"nm":"合并路径 1","mn":"ADBE Vector Filter - Merge"},{"ty":"fl","fillEnabled":true,"c":{"k":[0,0,0,1]},"o":{"k":100},"nm":"填充 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"k":[0,0],"ix":2},"a":{"k":[0,0],"ix":1},"s":{"k":[100,100],"ix":3},"r":{"k":0,"ix":6},"o":{"k":100,"ix":7},"sk":{"k":0,"ix":4},"sa":{"k":0,"ix":5},"nm":"变换"}],"nm":"o","np":5,"mn":"ADBE Vector Group"}],"ip":0,"op":140,"st":0,"bm":0,"sr":1},{"ddd":0,"ind":5,"ty":4,"nm":"“o 2”轮廓","parent":6,"ks":{"o":{"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":46,"s":[100],"e":[0]},{"t":47}]},"r":{"k":0},"p":{"k":[23.38,-63.281,0]},"a":{"k":[26.294,-61.781,0]},"s":{"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"k":{"i":[[-14.758,0],[0,19.476],[0,0],[14.758,0],[0,-19.355],[0,0]],"o":[[14.154,0],[0,0],[0,-19.476],[-14.033,0],[0,0],[0,19.476]],"v":[[30.968,-4.839],[56.13,-34.235],[56.13,-35.323],[30.968,-64.235],[5.928,-35.081],[5.928,-33.751]],"c":true}},"nm":"o","mn":"ADBE Vector Shape - Group"},{"ind":1,"ty":"sh","ks":{"k":{"i":[[12.944,0],[0,17.904],[0,0],[-12.823,0],[0,-18.508],[0,0]],"o":[[-12.944,0],[0,0],[0,-17.42],[12.944,0],[0,0],[0,17.783]],"v":[[30.968,-7.379],[8.831,-33.509],[8.831,-35.202],[30.968,-61.695],[53.227,-35.565],[53.227,-33.993]],"c":true}},"nm":"o","mn":"ADBE Vector Shape - Group"},{"ty":"mm","mm":1,"nm":"合并路径 1","mn":"ADBE Vector Filter - Merge"},{"ty":"fl","fillEnabled":true,"c":{"k":[0,0,0,1]},"o":{"k":100},"nm":"填充 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"k":[0,0],"ix":2},"a":{"k":[0,0],"ix":1},"s":{"k":[100,100],"ix":3},"r":{"k":0,"ix":6},"o":{"k":100,"ix":7},"sk":{"k":0,"ix":4},"sa":{"k":0,"ix":5},"nm":"变换"}],"nm":"o","np":5,"mn":"ADBE Vector Group"}],"ip":0,"op":140,"st":0,"bm":0,"sr":1},{"ddd":0,"ind":6,"ty":4,"nm":"“o”轮廓","ks":{"o":{"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":46,"s":[100],"e":[0]},{"t":47}]},"r":{"k":[{"i":{"x":[0.072],"y":[1]},"o":{"x":[0.333],"y":[0]},"n":["0p072_1_0p333_0"],"t":18,"s":[0],"e":[-14]},{"i":{"x":[0.238],"y":[0.989]},"o":{"x":[0.333],"y":[0]},"n":["0p238_0p989_0p333_0"],"t":25,"s":[-14],"e":[13.704]},{"i":{"x":[0.213],"y":[1.025]},"o":{"x":[0.333],"y":[0]},"n":["0p213_1p025_0p333_0"],"t":30,"s":[13.704],"e":[-5.296]},{"i":{"x":[0.162],"y":[1]},"o":{"x":[0.333],"y":[0]},"n":["0p162_1_0p333_0"],"t":35,"s":[-5.296],"e":[11.704]},{"i":{"x":[0.162],"y":[1.006]},"o":{"x":[0.333],"y":[0]},"n":["0p162_1p006_0p333_0"],"t":39,"s":[11.704],"e":[-4.296]},{"i":{"x":[0.225],"y":[1]},"o":{"x":[0.333],"y":[0]},"n":["0p225_1_0p333_0"],"t":42,"s":[-4.296],"e":[0]},{"t":44}]},"p":{"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":1,"y":0.024},"n":"0p833_0p833_1_0p024","t":0,"s":[538,197,0],"e":[538,264,0],"to":[0,11.1666669845581,0],"ti":[0,-11.1666669845581,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":20,"s":[538,264,0],"e":[538,264,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.868,"y":0},"n":"0p833_0p833_0p868_0","t":41,"s":[538,264,0],"e":[538,294,0],"to":[0,5,0],"ti":[0,-5,0]},{"t":47}]},"a":{"k":[24.463,-62.974,0]},"s":{"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"k":{"i":[[-14.758,0],[0,19.476],[0,0],[14.758,0],[0,-19.355],[0,0]],"o":[[14.154,0],[0,0],[0,-19.476],[-14.033,0],[0,0],[0,19.476]],"v":[[30.968,-4.839],[56.13,-34.235],[56.13,-35.323],[30.968,-64.235],[5.928,-35.081],[5.928,-33.751]],"c":true}},"nm":"o","mn":"ADBE Vector Shape - Group"},{"ind":1,"ty":"sh","ks":{"k":{"i":[[12.944,0],[0,17.904],[0,0],[-12.823,0],[0,-18.508],[0,0]],"o":[[-12.944,0],[0,0],[0,-17.42],[12.944,0],[0,0],[0,17.783]],"v":[[30.968,-7.379],[8.831,-33.509],[8.831,-35.202],[30.968,-61.695],[53.227,-35.565],[53.227,-33.993]],"c":true}},"nm":"o","mn":"ADBE Vector Shape - Group"},{"ty":"mm","mm":1,"nm":"合并路径 1","mn":"ADBE Vector Filter - Merge"},{"ty":"fl","fillEnabled":true,"c":{"k":[0,0,0,1]},"o":{"k":100},"nm":"填充 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"k":[0,0],"ix":2},"a":{"k":[0,0],"ix":1},"s":{"k":[100,100],"ix":3},"r":{"k":0,"ix":6},"o":{"k":100,"ix":7},"sk":{"k":0,"ix":4},"sa":{"k":0,"ix":5},"nm":"变换"}],"nm":"o","np":5,"mn":"ADBE Vector Group"}],"ip":0,"op":140,"st":0,"bm":0,"sr":1},{"ddd":0,"ind":7,"ty":4,"nm":"“Coming so 3”轮廓","ks":{"o":{"k":100},"r":{"k":0},"p":{"k":[60.5,356,0]},"a":{"k":[0,0,0]},"s":{"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"k":{"i":[[-22.017,0],[-3.992,2.177],[0,0],[10.645,0],[0,24.315],[0,0],[-19.718,0],[-4.839,-2.54],[0,0],[9.315,0],[0,-26.13],[0,0]],"o":[[11.371,0],[0,0],[-4.718,2.661],[-20.565,0],[0,0],[0,-24.436],[8.71,0],[0,0],[-4.476,-2.54],[-21.654,0],[0,0],[0,25.888]],"v":[[39.315,-4.96],[60.606,-10.282],[60.606,-13.186],[39.557,-7.742],[9.799,-44.88],[9.799,-46.937],[40.888,-83.591],[60.122,-79.236],[60.122,-82.018],[40.888,-86.373],[6.653,-46.574],[6.653,-45.001]],"c":true}},"nm":"C","mn":"ADBE Vector Shape - Group"},{"ty":"fl","fillEnabled":true,"c":{"k":[0,0,0,1]},"o":{"k":100},"nm":"填充 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"k":[0,0],"ix":2},"a":{"k":[0,0],"ix":1},"s":{"k":[100,100],"ix":3},"r":{"k":0,"ix":6},"o":{"k":100,"ix":7},"sk":{"k":0,"ix":4},"sa":{"k":0,"ix":5},"nm":"变换"}],"nm":"C","np":3,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"k":{"i":[[-14.758,0],[0,19.476],[0,0],[14.758,0],[0,-19.355],[0,0]],"o":[[14.154,0],[0,0],[0,-19.476],[-14.033,0],[0,0],[0,19.476]],"v":[[93.07,-4.839],[118.232,-34.235],[118.232,-35.323],[93.07,-64.235],[68.029,-35.081],[68.029,-33.751]],"c":true}},"nm":"o","mn":"ADBE Vector Shape - Group"},{"ind":1,"ty":"sh","ks":{"k":{"i":[[12.944,0],[0,17.904],[0,0],[-12.823,0],[0,-18.508],[0,0]],"o":[[-12.944,0],[0,0],[0,-17.42],[12.944,0],[0,0],[0,17.783]],"v":[[93.07,-7.379],[70.932,-33.509],[70.932,-35.202],[93.07,-61.695],[115.328,-35.565],[115.328,-33.993]],"c":true}},"nm":"o","mn":"ADBE Vector Shape - Group"},{"ty":"mm","mm":1,"nm":"合并路径 1","mn":"ADBE Vector Filter - Merge"},{"ty":"fl","fillEnabled":true,"c":{"k":[0,0,0,1]},"o":{"k":100},"nm":"填充 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"k":[0,0],"ix":2},"a":{"k":[0,0],"ix":1},"s":{"k":[100,100],"ix":3},"r":{"k":0,"ix":6},"o":{"k":100,"ix":7},"sk":{"k":0,"ix":4},"sa":{"k":0,"ix":5},"nm":"变换"}],"nm":"o","np":5,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"k":{"i":[[0,0],[0,0],[0,0],[-6.532,0],[0,-9.557],[0,0],[0,0],[0,0],[0.484,1.694],[-5.807,0],[0,-9.557],[0,0],[0,0],[0,0],[9.436,0],[8.226,-5.202],[0,0],[6.774,0],[7.137,-4.355],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[7.016,-4.597],[8.468,0],[0,0],[0,0],[0,0],[0,-2.419],[7.742,-4.718],[8.589,0],[0,0],[0,0],[0,0],[0,-10.887],[-6.29,0],[0,0],[-2.419,-4.597],[-6.411,0],[0,0],[0,0],[0,0],[0,0]],"v":[[127.997,-5.686],[131.021,-5.686],[131.021,-54.921],[150.981,-61.574],[163.925,-48.63],[163.925,-5.686],[167.07,-5.686],[167.07,-49.114],[166.223,-55.042],[186.426,-61.574],[200.216,-48.63],[200.216,-5.686],[203.119,-5.686],[203.119,-49.114],[187.272,-64.235],[165.74,-57.34],[165.498,-57.34],[151.586,-64.235],[131.142,-57.703],[130.9,-57.703],[130.9,-63.389],[127.997,-63.389]],"c":true}},"nm":"m","mn":"ADBE Vector Shape - Group"},{"ty":"fl","fillEnabled":true,"c":{"k":[0,0,0,1]},"o":{"k":100},"nm":"填充 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"k":[0,0],"ix":2},"a":{"k":[0,0],"ix":1},"s":{"k":[100,100],"ix":3},"r":{"k":0,"ix":6},"o":{"k":100,"ix":7},"sk":{"k":0,"ix":4},"sa":{"k":0,"ix":5},"nm":"变换"}],"nm":"m","np":3,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[215.678,-5.928],[218.702,-5.928],[218.702,-63.509],[215.678,-63.509]],"c":true}},"nm":"i","mn":"ADBE Vector Shape - Group"},{"ind":1,"ty":"sh","ks":{"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[215.557,-76.816],[218.702,-76.816],[218.702,-81.292],[215.557,-81.292]],"c":true}},"nm":"i","mn":"ADBE Vector Shape - Group"},{"ty":"mm","mm":1,"nm":"合并路径 1","mn":"ADBE Vector Filter - Merge"},{"ty":"fl","fillEnabled":true,"c":{"k":[0,0,0,1]},"o":{"k":100},"nm":"填充 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"k":[0,0],"ix":2},"a":{"k":[0,0],"ix":1},"s":{"k":[100,100],"ix":3},"r":{"k":0,"ix":6},"o":{"k":100,"ix":7},"sk":{"k":0,"ix":4},"sa":{"k":0,"ix":5},"nm":"变换"}],"nm":"i","np":5,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"k":{"i":[[0,0],[0,0],[0,0],[-7.016,0],[0,-9.557],[0,0],[0,0],[0,0],[10.645,0],[7.137,-4.355],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[7.016,-4.476],[10.161,0],[0,0],[0,0],[0,0],[0,-10.887],[-7.258,0],[0,0],[0,0],[0,0],[0,0]],"v":[[231.776,-5.686],[234.8,-5.686],[234.8,-54.921],[256.333,-61.574],[271.091,-48.63],[271.091,-5.686],[274.115,-5.686],[274.115,-49.114],[257.421,-64.235],[234.921,-57.703],[234.679,-57.703],[234.679,-63.389],[231.776,-63.389]],"c":true}},"nm":"n","mn":"ADBE Vector Shape - Group"},{"ty":"fl","fillEnabled":true,"c":{"k":[0,0,0,1]},"o":{"k":100},"nm":"填充 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"k":[0,0],"ix":2},"a":{"k":[0,0],"ix":1},"s":{"k":[100,100],"ix":3},"r":{"k":0,"ix":6},"o":{"k":100,"ix":7},"sk":{"k":0,"ix":4},"sa":{"k":0,"ix":5},"nm":"变换"}],"nm":"n","np":3,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"k":{"i":[[-17.783,0],[0,9.557],[9.92,0],[0,0],[0,3.871],[-2.298,2.056],[-4.234,0],[0,11.492],[0,0],[4.96,2.661],[0,0],[0,0],[0,0],[2.54,0],[0,-11.008],[0,0],[-4.597,-2.782],[0,-3.508],[-3.145,-0.605],[0,0],[0,-7.621]],"o":[[19.113,0],[0,-10.766],[0,0],[-4.597,0],[0,-3.266],[3.266,1.694],[11.613,0],[0,0],[0,-6.653],[0,0],[0,0],[0,0],[-2.177,-0.484],[-11.855,0],[0,0],[0,6.29],[-3.145,2.903],[0,4.234],[0,0],[-6.653,2.54],[0,8.347]],"v":[[305.417,12.823],[332.03,-4.96],[314.732,-16.573],[297.433,-16.573],[290.175,-22.984],[294.529,-30.001],[305.78,-27.702],[325.861,-45.364],[325.861,-46.574],[317.998,-60.727],[331.667,-60.727],[331.667,-63.268],[312.917,-63.268],[305.901,-63.993],[285.457,-46.332],[285.457,-45.364],[292.715,-31.21],[287.15,-22.259],[293.32,-14.637],[293.32,-14.395],[281.102,-2.298]],"c":true}},"nm":"g","mn":"ADBE Vector Shape - Group"},{"ind":1,"ty":"sh","ks":{"k":{"i":[[17.299,0],[0,7.137],[-7.137,2.298],[0,0],[0,-9.073]],"o":[[-15.847,0],[0,-7.258],[0,0],[8.71,0],[0,8.105]],"v":[[305.296,10.162],[284.247,-2.54],[296.828,-13.67],[314.369,-13.67],[329.006,-4.597]],"c":true}},"nm":"g","mn":"ADBE Vector Shape - Group"},{"ind":2,"ty":"sh","ks":{"k":{"i":[[10.282,0],[0,9.799],[0,0],[-10.283,0],[0,-10.162],[0,0]],"o":[[-10.162,0],[0,0],[0,-9.557],[10.161,0],[0,0],[0,9.799]],"v":[[305.78,-30.122],[288.481,-45.243],[288.481,-46.574],[305.78,-61.574],[322.837,-46.574],[322.837,-45.243]],"c":true}},"nm":"g","mn":"ADBE Vector Shape - Group"},{"ty":"mm","mm":1,"nm":"合并路径 1","mn":"ADBE Vector Filter - Merge"},{"ty":"fl","fillEnabled":true,"c":{"k":[0,0,0,1]},"o":{"k":100},"nm":"填充 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"k":[0,0],"ix":2},"a":{"k":[0,0],"ix":1},"s":{"k":[100,100],"ix":3},"r":{"k":0,"ix":6},"o":{"k":100,"ix":7},"sk":{"k":0,"ix":4},"sa":{"k":0,"ix":5},"nm":"变换"}],"nm":"g","np":6,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"k":{"i":[[-7.984,0],[0,8.468],[9.678,2.903],[0,0],[0,7.016],[-9.92,0],[-3.992,-1.936],[0,0],[7.258,0],[0,-8.226],[-8.831,-2.419],[0,0],[0,-7.984],[12.218,0],[4.476,2.177],[0,0]],"o":[[13.791,0],[0,-9.678],[0,0],[-8.226,-2.54],[0,-6.653],[5.565,0],[0,0],[-3.145,-1.815],[-11.492,0],[0,8.71],[0,0],[9.073,2.54],[0,7.016],[-8.105,0],[0,0],[3.871,2.057]],"v":[[377.571,-4.839],[396.563,-20.202],[381.926,-36.049],[374.91,-38.106],[363.78,-50.566],[378.539,-61.574],[393.66,-58.187],[393.66,-60.727],[378.297,-64.235],[360.877,-50.445],[373.821,-35.565],[380.837,-33.388],[393.539,-20.081],[377.329,-7.5],[359.788,-11.613],[359.788,-8.952]],"c":true}},"nm":"s","mn":"ADBE Vector Shape - Group"},{"ty":"fl","fillEnabled":true,"c":{"k":[0,0,0,1]},"o":{"k":100},"nm":"填充 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"k":[0,0],"ix":2},"a":{"k":[0,0],"ix":1},"s":{"k":[100,100],"ix":3},"r":{"k":0,"ix":6},"o":{"k":100,"ix":7},"sk":{"k":0,"ix":4},"sa":{"k":0,"ix":5},"nm":"变换"}],"nm":"s","np":3,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"k":{"i":[[-14.758,0],[0,19.476],[0,0],[14.758,0],[0,-19.355],[0,0]],"o":[[14.154,0],[0,0],[0,-19.476],[-14.033,0],[0,0],[0,19.476]],"v":[[427.115,-4.839],[452.277,-34.235],[452.277,-35.323],[427.115,-64.235],[402.074,-35.081],[402.074,-33.751]],"c":true}},"nm":"o","mn":"ADBE Vector Shape - Group"},{"ind":1,"ty":"sh","ks":{"k":{"i":[[12.944,0],[0,17.904],[0,0],[-12.823,0],[0,-18.508],[0,0]],"o":[[-12.944,0],[0,0],[0,-17.42],[12.944,0],[0,0],[0,17.783]],"v":[[427.115,-7.379],[404.978,-33.509],[404.978,-35.202],[427.115,-61.695],[449.374,-35.565],[449.374,-33.993]],"c":true}},"nm":"o","mn":"ADBE Vector Shape - Group"},{"ty":"mm","mm":1,"nm":"合并路径 1","mn":"ADBE Vector Filter - Merge"},{"ty":"fl","fillEnabled":true,"c":{"k":[0,0,0,1]},"o":{"k":100},"nm":"填充 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"k":[0,0],"ix":2},"a":{"k":[0,0],"ix":1},"s":{"k":[100,100],"ix":3},"r":{"k":0,"ix":6},"o":{"k":100,"ix":7},"sk":{"k":0,"ix":4},"sa":{"k":0,"ix":5},"nm":"变换"}],"nm":"o","np":5,"mn":"ADBE Vector Group"}],"ip":0,"op":140,"st":0,"bm":0,"sr":1},{"ddd":0,"ind":8,"ty":4,"nm":"“Coming so 2”轮廓","ks":{"o":{"k":100},"r":{"k":0},"p":{"k":[57.5,358,0]},"a":{"k":[0,0,0]},"s":{"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"k":{"i":[[-22.017,0],[-3.992,2.177],[0,0],[10.645,0],[0,24.315],[0,0],[-19.718,0],[-4.839,-2.54],[0,0],[9.315,0],[0,-26.13],[0,0]],"o":[[11.371,0],[0,0],[-4.718,2.661],[-20.565,0],[0,0],[0,-24.436],[8.71,0],[0,0],[-4.476,-2.54],[-21.654,0],[0,0],[0,25.888]],"v":[[39.315,-4.96],[60.606,-10.282],[60.606,-13.186],[39.557,-7.742],[9.799,-44.88],[9.799,-46.937],[40.888,-83.591],[60.122,-79.236],[60.122,-82.018],[40.888,-86.373],[6.653,-46.574],[6.653,-45.001]],"c":true}},"nm":"C","mn":"ADBE Vector Shape - Group"},{"ty":"fl","fillEnabled":true,"c":{"k":[0,0,0,1]},"o":{"k":100},"nm":"填充 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"k":[0,0],"ix":2},"a":{"k":[0,0],"ix":1},"s":{"k":[100,100],"ix":3},"r":{"k":0,"ix":6},"o":{"k":100,"ix":7},"sk":{"k":0,"ix":4},"sa":{"k":0,"ix":5},"nm":"变换"}],"nm":"C","np":3,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"k":{"i":[[-14.758,0],[0,19.476],[0,0],[14.758,0],[0,-19.355],[0,0]],"o":[[14.154,0],[0,0],[0,-19.476],[-14.033,0],[0,0],[0,19.476]],"v":[[93.07,-4.839],[118.232,-34.235],[118.232,-35.323],[93.07,-64.235],[68.029,-35.081],[68.029,-33.751]],"c":true}},"nm":"o","mn":"ADBE Vector Shape - Group"},{"ind":1,"ty":"sh","ks":{"k":{"i":[[12.944,0],[0,17.904],[0,0],[-12.823,0],[0,-18.508],[0,0]],"o":[[-12.944,0],[0,0],[0,-17.42],[12.944,0],[0,0],[0,17.783]],"v":[[93.07,-7.379],[70.932,-33.509],[70.932,-35.202],[93.07,-61.695],[115.328,-35.565],[115.328,-33.993]],"c":true}},"nm":"o","mn":"ADBE Vector Shape - Group"},{"ty":"mm","mm":1,"nm":"合并路径 1","mn":"ADBE Vector Filter - Merge"},{"ty":"fl","fillEnabled":true,"c":{"k":[0,0,0,1]},"o":{"k":100},"nm":"填充 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"k":[0,0],"ix":2},"a":{"k":[0,0],"ix":1},"s":{"k":[100,100],"ix":3},"r":{"k":0,"ix":6},"o":{"k":100,"ix":7},"sk":{"k":0,"ix":4},"sa":{"k":0,"ix":5},"nm":"变换"}],"nm":"o","np":5,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"k":{"i":[[0,0],[0,0],[0,0],[-6.532,0],[0,-9.557],[0,0],[0,0],[0,0],[0.484,1.694],[-5.807,0],[0,-9.557],[0,0],[0,0],[0,0],[9.436,0],[8.226,-5.202],[0,0],[6.774,0],[7.137,-4.355],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[7.016,-4.597],[8.468,0],[0,0],[0,0],[0,0],[0,-2.419],[7.742,-4.718],[8.589,0],[0,0],[0,0],[0,0],[0,-10.887],[-6.29,0],[0,0],[-2.419,-4.597],[-6.411,0],[0,0],[0,0],[0,0],[0,0]],"v":[[127.997,-5.686],[131.021,-5.686],[131.021,-54.921],[150.981,-61.574],[163.925,-48.63],[163.925,-5.686],[167.07,-5.686],[167.07,-49.114],[166.223,-55.042],[186.426,-61.574],[200.216,-48.63],[200.216,-5.686],[203.119,-5.686],[203.119,-49.114],[187.272,-64.235],[165.74,-57.34],[165.498,-57.34],[151.586,-64.235],[131.142,-57.703],[130.9,-57.703],[130.9,-63.389],[127.997,-63.389]],"c":true}},"nm":"m","mn":"ADBE Vector Shape - Group"},{"ty":"fl","fillEnabled":true,"c":{"k":[0,0,0,1]},"o":{"k":100},"nm":"填充 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"k":[0,0],"ix":2},"a":{"k":[0,0],"ix":1},"s":{"k":[100,100],"ix":3},"r":{"k":0,"ix":6},"o":{"k":100,"ix":7},"sk":{"k":0,"ix":4},"sa":{"k":0,"ix":5},"nm":"变换"}],"nm":"m","np":3,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[215.678,-5.928],[218.702,-5.928],[218.702,-63.509],[215.678,-63.509]],"c":true}},"nm":"i","mn":"ADBE Vector Shape - Group"},{"ind":1,"ty":"sh","ks":{"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[215.557,-76.816],[218.702,-76.816],[218.702,-81.292],[215.557,-81.292]],"c":true}},"nm":"i","mn":"ADBE Vector Shape - Group"},{"ty":"mm","mm":1,"nm":"合并路径 1","mn":"ADBE Vector Filter - Merge"},{"ty":"fl","fillEnabled":true,"c":{"k":[0,0,0,1]},"o":{"k":100},"nm":"填充 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"k":[0,0],"ix":2},"a":{"k":[0,0],"ix":1},"s":{"k":[100,100],"ix":3},"r":{"k":0,"ix":6},"o":{"k":100,"ix":7},"sk":{"k":0,"ix":4},"sa":{"k":0,"ix":5},"nm":"变换"}],"nm":"i","np":5,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"k":{"i":[[0,0],[0,0],[0,0],[-7.016,0],[0,-9.557],[0,0],[0,0],[0,0],[10.645,0],[7.137,-4.355],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[7.016,-4.476],[10.161,0],[0,0],[0,0],[0,0],[0,-10.887],[-7.258,0],[0,0],[0,0],[0,0],[0,0]],"v":[[231.776,-5.686],[234.8,-5.686],[234.8,-54.921],[256.333,-61.574],[271.091,-48.63],[271.091,-5.686],[274.115,-5.686],[274.115,-49.114],[257.421,-64.235],[234.921,-57.703],[234.679,-57.703],[234.679,-63.389],[231.776,-63.389]],"c":true}},"nm":"n","mn":"ADBE Vector Shape - Group"},{"ty":"fl","fillEnabled":true,"c":{"k":[0,0,0,1]},"o":{"k":100},"nm":"填充 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"k":[0,0],"ix":2},"a":{"k":[0,0],"ix":1},"s":{"k":[100,100],"ix":3},"r":{"k":0,"ix":6},"o":{"k":100,"ix":7},"sk":{"k":0,"ix":4},"sa":{"k":0,"ix":5},"nm":"变换"}],"nm":"n","np":3,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"k":{"i":[[-17.783,0],[0,9.557],[9.92,0],[0,0],[0,3.871],[-2.298,2.056],[-4.234,0],[0,11.492],[0,0],[4.96,2.661],[0,0],[0,0],[0,0],[2.54,0],[0,-11.008],[0,0],[-4.597,-2.782],[0,-3.508],[-3.145,-0.605],[0,0],[0,-7.621]],"o":[[19.113,0],[0,-10.766],[0,0],[-4.597,0],[0,-3.266],[3.266,1.694],[11.613,0],[0,0],[0,-6.653],[0,0],[0,0],[0,0],[-2.177,-0.484],[-11.855,0],[0,0],[0,6.29],[-3.145,2.903],[0,4.234],[0,0],[-6.653,2.54],[0,8.347]],"v":[[305.417,12.823],[332.03,-4.96],[314.732,-16.573],[297.433,-16.573],[290.175,-22.984],[294.529,-30.001],[305.78,-27.702],[325.861,-45.364],[325.861,-46.574],[317.998,-60.727],[331.667,-60.727],[331.667,-63.268],[312.917,-63.268],[305.901,-63.993],[285.457,-46.332],[285.457,-45.364],[292.715,-31.21],[287.15,-22.259],[293.32,-14.637],[293.32,-14.395],[281.102,-2.298]],"c":true}},"nm":"g","mn":"ADBE Vector Shape - Group"},{"ind":1,"ty":"sh","ks":{"k":{"i":[[17.299,0],[0,7.137],[-7.137,2.298],[0,0],[0,-9.073]],"o":[[-15.847,0],[0,-7.258],[0,0],[8.71,0],[0,8.105]],"v":[[305.296,10.162],[284.247,-2.54],[296.828,-13.67],[314.369,-13.67],[329.006,-4.597]],"c":true}},"nm":"g","mn":"ADBE Vector Shape - Group"},{"ind":2,"ty":"sh","ks":{"k":{"i":[[10.282,0],[0,9.799],[0,0],[-10.283,0],[0,-10.162],[0,0]],"o":[[-10.162,0],[0,0],[0,-9.557],[10.161,0],[0,0],[0,9.799]],"v":[[305.78,-30.122],[288.481,-45.243],[288.481,-46.574],[305.78,-61.574],[322.837,-46.574],[322.837,-45.243]],"c":true}},"nm":"g","mn":"ADBE Vector Shape - Group"},{"ty":"mm","mm":1,"nm":"合并路径 1","mn":"ADBE Vector Filter - Merge"},{"ty":"fl","fillEnabled":true,"c":{"k":[0,0,0,1]},"o":{"k":100},"nm":"填充 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"k":[0,0],"ix":2},"a":{"k":[0,0],"ix":1},"s":{"k":[100,100],"ix":3},"r":{"k":0,"ix":6},"o":{"k":100,"ix":7},"sk":{"k":0,"ix":4},"sa":{"k":0,"ix":5},"nm":"变换"}],"nm":"g","np":6,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"k":{"i":[[-7.984,0],[0,8.468],[9.678,2.903],[0,0],[0,7.016],[-9.92,0],[-3.992,-1.936],[0,0],[7.258,0],[0,-8.226],[-8.831,-2.419],[0,0],[0,-7.984],[12.218,0],[4.476,2.177],[0,0]],"o":[[13.791,0],[0,-9.678],[0,0],[-8.226,-2.54],[0,-6.653],[5.565,0],[0,0],[-3.145,-1.815],[-11.492,0],[0,8.71],[0,0],[9.073,2.54],[0,7.016],[-8.105,0],[0,0],[3.871,2.057]],"v":[[377.571,-4.839],[396.563,-20.202],[381.926,-36.049],[374.91,-38.106],[363.78,-50.566],[378.539,-61.574],[393.66,-58.187],[393.66,-60.727],[378.297,-64.235],[360.877,-50.445],[373.821,-35.565],[380.837,-33.388],[393.539,-20.081],[377.329,-7.5],[359.788,-11.613],[359.788,-8.952]],"c":true}},"nm":"s","mn":"ADBE Vector Shape - Group"},{"ty":"fl","fillEnabled":true,"c":{"k":[0,0,0,1]},"o":{"k":100},"nm":"填充 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"k":[0,0],"ix":2},"a":{"k":[0,0],"ix":1},"s":{"k":[100,100],"ix":3},"r":{"k":0,"ix":6},"o":{"k":100,"ix":7},"sk":{"k":0,"ix":4},"sa":{"k":0,"ix":5},"nm":"变换"}],"nm":"s","np":3,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"k":{"i":[[-14.758,0],[0,19.476],[0,0],[14.758,0],[0,-19.355],[0,0]],"o":[[14.154,0],[0,0],[0,-19.476],[-14.033,0],[0,0],[0,19.476]],"v":[[427.115,-4.839],[452.277,-34.235],[452.277,-35.323],[427.115,-64.235],[402.074,-35.081],[402.074,-33.751]],"c":true}},"nm":"o","mn":"ADBE Vector Shape - Group"},{"ind":1,"ty":"sh","ks":{"k":{"i":[[12.944,0],[0,17.904],[0,0],[-12.823,0],[0,-18.508],[0,0]],"o":[[-12.944,0],[0,0],[0,-17.42],[12.944,0],[0,0],[0,17.783]],"v":[[427.115,-7.379],[404.978,-33.509],[404.978,-35.202],[427.115,-61.695],[449.374,-35.565],[449.374,-33.993]],"c":true}},"nm":"o","mn":"ADBE Vector Shape - Group"},{"ty":"mm","mm":1,"nm":"合并路径 1","mn":"ADBE Vector Filter - Merge"},{"ty":"fl","fillEnabled":true,"c":{"k":[0,0,0,1]},"o":{"k":100},"nm":"填充 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"k":[0,0],"ix":2},"a":{"k":[0,0],"ix":1},"s":{"k":[100,100],"ix":3},"r":{"k":0,"ix":6},"o":{"k":100,"ix":7},"sk":{"k":0,"ix":4},"sa":{"k":0,"ix":5},"nm":"变换"}],"nm":"o","np":5,"mn":"ADBE Vector Group"}],"ip":0,"op":140,"st":0,"bm":0,"sr":1},{"ddd":0,"ind":9,"ty":4,"nm":"“Coming so”轮廓","ks":{"o":{"k":100},"r":{"k":0},"p":{"k":[54.5,356,0]},"a":{"k":[0,0,0]},"s":{"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"k":{"i":[[-22.017,0],[-3.992,2.177],[0,0],[10.645,0],[0,24.315],[0,0],[-19.718,0],[-4.839,-2.54],[0,0],[9.315,0],[0,-26.13],[0,0]],"o":[[11.371,0],[0,0],[-4.718,2.661],[-20.565,0],[0,0],[0,-24.436],[8.71,0],[0,0],[-4.476,-2.54],[-21.654,0],[0,0],[0,25.888]],"v":[[39.315,-4.96],[60.606,-10.282],[60.606,-13.186],[39.557,-7.742],[9.799,-44.88],[9.799,-46.937],[40.888,-83.591],[60.122,-79.236],[60.122,-82.018],[40.888,-86.373],[6.653,-46.574],[6.653,-45.001]],"c":true}},"nm":"C","mn":"ADBE Vector Shape - Group"},{"ty":"fl","fillEnabled":true,"c":{"k":[0,0,0,1]},"o":{"k":100},"nm":"填充 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"k":[0,0],"ix":2},"a":{"k":[0,0],"ix":1},"s":{"k":[100,100],"ix":3},"r":{"k":0,"ix":6},"o":{"k":100,"ix":7},"sk":{"k":0,"ix":4},"sa":{"k":0,"ix":5},"nm":"变换"}],"nm":"C","np":3,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"k":{"i":[[-14.758,0],[0,19.476],[0,0],[14.758,0],[0,-19.355],[0,0]],"o":[[14.154,0],[0,0],[0,-19.476],[-14.033,0],[0,0],[0,19.476]],"v":[[93.07,-4.839],[118.232,-34.235],[118.232,-35.323],[93.07,-64.235],[68.029,-35.081],[68.029,-33.751]],"c":true}},"nm":"o","mn":"ADBE Vector Shape - Group"},{"ind":1,"ty":"sh","ks":{"k":{"i":[[12.944,0],[0,17.904],[0,0],[-12.823,0],[0,-18.508],[0,0]],"o":[[-12.944,0],[0,0],[0,-17.42],[12.944,0],[0,0],[0,17.783]],"v":[[93.07,-7.379],[70.932,-33.509],[70.932,-35.202],[93.07,-61.695],[115.328,-35.565],[115.328,-33.993]],"c":true}},"nm":"o","mn":"ADBE Vector Shape - Group"},{"ty":"mm","mm":1,"nm":"合并路径 1","mn":"ADBE Vector Filter - Merge"},{"ty":"fl","fillEnabled":true,"c":{"k":[0,0,0,1]},"o":{"k":100},"nm":"填充 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"k":[0,0],"ix":2},"a":{"k":[0,0],"ix":1},"s":{"k":[100,100],"ix":3},"r":{"k":0,"ix":6},"o":{"k":100,"ix":7},"sk":{"k":0,"ix":4},"sa":{"k":0,"ix":5},"nm":"变换"}],"nm":"o","np":5,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"k":{"i":[[0,0],[0,0],[0,0],[-6.532,0],[0,-9.557],[0,0],[0,0],[0,0],[0.484,1.694],[-5.807,0],[0,-9.557],[0,0],[0,0],[0,0],[9.436,0],[8.226,-5.202],[0,0],[6.774,0],[7.137,-4.355],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[7.016,-4.597],[8.468,0],[0,0],[0,0],[0,0],[0,-2.419],[7.742,-4.718],[8.589,0],[0,0],[0,0],[0,0],[0,-10.887],[-6.29,0],[0,0],[-2.419,-4.597],[-6.411,0],[0,0],[0,0],[0,0],[0,0]],"v":[[127.997,-5.686],[131.021,-5.686],[131.021,-54.921],[150.981,-61.574],[163.925,-48.63],[163.925,-5.686],[167.07,-5.686],[167.07,-49.114],[166.223,-55.042],[186.426,-61.574],[200.216,-48.63],[200.216,-5.686],[203.119,-5.686],[203.119,-49.114],[187.272,-64.235],[165.74,-57.34],[165.498,-57.34],[151.586,-64.235],[131.142,-57.703],[130.9,-57.703],[130.9,-63.389],[127.997,-63.389]],"c":true}},"nm":"m","mn":"ADBE Vector Shape - Group"},{"ty":"fl","fillEnabled":true,"c":{"k":[0,0,0,1]},"o":{"k":100},"nm":"填充 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"k":[0,0],"ix":2},"a":{"k":[0,0],"ix":1},"s":{"k":[100,100],"ix":3},"r":{"k":0,"ix":6},"o":{"k":100,"ix":7},"sk":{"k":0,"ix":4},"sa":{"k":0,"ix":5},"nm":"变换"}],"nm":"m","np":3,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[215.678,-5.928],[218.702,-5.928],[218.702,-63.509],[215.678,-63.509]],"c":true}},"nm":"i","mn":"ADBE Vector Shape - Group"},{"ind":1,"ty":"sh","ks":{"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[215.557,-76.816],[218.702,-76.816],[218.702,-81.292],[215.557,-81.292]],"c":true}},"nm":"i","mn":"ADBE Vector Shape - Group"},{"ty":"mm","mm":1,"nm":"合并路径 1","mn":"ADBE Vector Filter - Merge"},{"ty":"fl","fillEnabled":true,"c":{"k":[0,0,0,1]},"o":{"k":100},"nm":"填充 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"k":[0,0],"ix":2},"a":{"k":[0,0],"ix":1},"s":{"k":[100,100],"ix":3},"r":{"k":0,"ix":6},"o":{"k":100,"ix":7},"sk":{"k":0,"ix":4},"sa":{"k":0,"ix":5},"nm":"变换"}],"nm":"i","np":5,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"k":{"i":[[0,0],[0,0],[0,0],[-7.016,0],[0,-9.557],[0,0],[0,0],[0,0],[10.645,0],[7.137,-4.355],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[7.016,-4.476],[10.161,0],[0,0],[0,0],[0,0],[0,-10.887],[-7.258,0],[0,0],[0,0],[0,0],[0,0]],"v":[[231.776,-5.686],[234.8,-5.686],[234.8,-54.921],[256.333,-61.574],[271.091,-48.63],[271.091,-5.686],[274.115,-5.686],[274.115,-49.114],[257.421,-64.235],[234.921,-57.703],[234.679,-57.703],[234.679,-63.389],[231.776,-63.389]],"c":true}},"nm":"n","mn":"ADBE Vector Shape - Group"},{"ty":"fl","fillEnabled":true,"c":{"k":[0,0,0,1]},"o":{"k":100},"nm":"填充 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"k":[0,0],"ix":2},"a":{"k":[0,0],"ix":1},"s":{"k":[100,100],"ix":3},"r":{"k":0,"ix":6},"o":{"k":100,"ix":7},"sk":{"k":0,"ix":4},"sa":{"k":0,"ix":5},"nm":"变换"}],"nm":"n","np":3,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"k":{"i":[[-17.783,0],[0,9.557],[9.92,0],[0,0],[0,3.871],[-2.298,2.056],[-4.234,0],[0,11.492],[0,0],[4.96,2.661],[0,0],[0,0],[0,0],[2.54,0],[0,-11.008],[0,0],[-4.597,-2.782],[0,-3.508],[-3.145,-0.605],[0,0],[0,-7.621]],"o":[[19.113,0],[0,-10.766],[0,0],[-4.597,0],[0,-3.266],[3.266,1.694],[11.613,0],[0,0],[0,-6.653],[0,0],[0,0],[0,0],[-2.177,-0.484],[-11.855,0],[0,0],[0,6.29],[-3.145,2.903],[0,4.234],[0,0],[-6.653,2.54],[0,8.347]],"v":[[305.417,12.823],[332.03,-4.96],[314.732,-16.573],[297.433,-16.573],[290.175,-22.984],[294.529,-30.001],[305.78,-27.702],[325.861,-45.364],[325.861,-46.574],[317.998,-60.727],[331.667,-60.727],[331.667,-63.268],[312.917,-63.268],[305.901,-63.993],[285.457,-46.332],[285.457,-45.364],[292.715,-31.21],[287.15,-22.259],[293.32,-14.637],[293.32,-14.395],[281.102,-2.298]],"c":true}},"nm":"g","mn":"ADBE Vector Shape - Group"},{"ind":1,"ty":"sh","ks":{"k":{"i":[[17.299,0],[0,7.137],[-7.137,2.298],[0,0],[0,-9.073]],"o":[[-15.847,0],[0,-7.258],[0,0],[8.71,0],[0,8.105]],"v":[[305.296,10.162],[284.247,-2.54],[296.828,-13.67],[314.369,-13.67],[329.006,-4.597]],"c":true}},"nm":"g","mn":"ADBE Vector Shape - Group"},{"ind":2,"ty":"sh","ks":{"k":{"i":[[10.282,0],[0,9.799],[0,0],[-10.283,0],[0,-10.162],[0,0]],"o":[[-10.162,0],[0,0],[0,-9.557],[10.161,0],[0,0],[0,9.799]],"v":[[305.78,-30.122],[288.481,-45.243],[288.481,-46.574],[305.78,-61.574],[322.837,-46.574],[322.837,-45.243]],"c":true}},"nm":"g","mn":"ADBE Vector Shape - Group"},{"ty":"mm","mm":1,"nm":"合并路径 1","mn":"ADBE Vector Filter - Merge"},{"ty":"fl","fillEnabled":true,"c":{"k":[0,0,0,1]},"o":{"k":100},"nm":"填充 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"k":[0,0],"ix":2},"a":{"k":[0,0],"ix":1},"s":{"k":[100,100],"ix":3},"r":{"k":0,"ix":6},"o":{"k":100,"ix":7},"sk":{"k":0,"ix":4},"sa":{"k":0,"ix":5},"nm":"变换"}],"nm":"g","np":6,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"k":{"i":[[-7.984,0],[0,8.468],[9.678,2.903],[0,0],[0,7.016],[-9.92,0],[-3.992,-1.936],[0,0],[7.258,0],[0,-8.226],[-8.831,-2.419],[0,0],[0,-7.984],[12.218,0],[4.476,2.177],[0,0]],"o":[[13.791,0],[0,-9.678],[0,0],[-8.226,-2.54],[0,-6.653],[5.565,0],[0,0],[-3.145,-1.815],[-11.492,0],[0,8.71],[0,0],[9.073,2.54],[0,7.016],[-8.105,0],[0,0],[3.871,2.057]],"v":[[377.571,-4.839],[396.563,-20.202],[381.926,-36.049],[374.91,-38.106],[363.78,-50.566],[378.539,-61.574],[393.66,-58.187],[393.66,-60.727],[378.297,-64.235],[360.877,-50.445],[373.821,-35.565],[380.837,-33.388],[393.539,-20.081],[377.329,-7.5],[359.788,-11.613],[359.788,-8.952]],"c":true}},"nm":"s","mn":"ADBE Vector Shape - Group"},{"ty":"fl","fillEnabled":true,"c":{"k":[0,0,0,1]},"o":{"k":100},"nm":"填充 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"k":[0,0],"ix":2},"a":{"k":[0,0],"ix":1},"s":{"k":[100,100],"ix":3},"r":{"k":0,"ix":6},"o":{"k":100,"ix":7},"sk":{"k":0,"ix":4},"sa":{"k":0,"ix":5},"nm":"变换"}],"nm":"s","np":3,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"k":{"i":[[-14.758,0],[0,19.476],[0,0],[14.758,0],[0,-19.355],[0,0]],"o":[[14.154,0],[0,0],[0,-19.476],[-14.033,0],[0,0],[0,19.476]],"v":[[427.115,-4.839],[452.277,-34.235],[452.277,-35.323],[427.115,-64.235],[402.074,-35.081],[402.074,-33.751]],"c":true}},"nm":"o","mn":"ADBE Vector Shape - Group"},{"ind":1,"ty":"sh","ks":{"k":{"i":[[12.944,0],[0,17.904],[0,0],[-12.823,0],[0,-18.508],[0,0]],"o":[[-12.944,0],[0,0],[0,-17.42],[12.944,0],[0,0],[0,17.783]],"v":[[427.115,-7.379],[404.978,-33.509],[404.978,-35.202],[427.115,-61.695],[449.374,-35.565],[449.374,-33.993]],"c":true}},"nm":"o","mn":"ADBE Vector Shape - Group"},{"ty":"mm","mm":1,"nm":"合并路径 1","mn":"ADBE Vector Filter - Merge"},{"ty":"fl","fillEnabled":true,"c":{"k":[0,0,0,1]},"o":{"k":100},"nm":"填充 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"k":[0,0],"ix":2},"a":{"k":[0,0],"ix":1},"s":{"k":[100,100],"ix":3},"r":{"k":0,"ix":6},"o":{"k":100,"ix":7},"sk":{"k":0,"ix":4},"sa":{"k":0,"ix":5},"nm":"变换"}],"nm":"o","np":5,"mn":"ADBE Vector Group"}],"ip":0,"op":140,"st":0,"bm":0,"sr":1},{"ddd":0,"ind":10,"ty":4,"nm":"形状图层 10","ks":{"o":{"k":100},"r":{"k":0},"p":{"k":[408,186,0]},"a":{"k":[0,0,0]},"s":{"k":[100,100,100]}},"ao":0,"hasMask":true,"masksProperties":[{"inv":false,"mode":"f","pt":{"k":{"i":[[0,19.319],[0,0],[-13.919,0],[0,-19.318],[0,0],[14.04,0]],"o":[[0,0],[0,-19.199],[14.639,0],[0,0],[0,19.319],[-14.639,0]],"v":[[-101.437,3.5],[-101.437,2.18],[-76.598,-26.739],[-51.639,1.939],[-51.639,3.02],[-76.598,32.179]],"c":true}},"o":{"k":100},"x":{"k":0},"nm":"蒙版 1"},{"inv":false,"mode":"f","pt":{"k":{"i":[[0,17.64],[0,0],[12.839,0],[0,-17.279],[0,0],[-12.839,0]],"o":[[0,0],[0,-18.359],[-12.719,0],[0,0],[0,17.759],[12.839,0]],"v":[[-54.519,3.26],[-54.519,1.7],[-76.598,-24.219],[-98.557,2.06],[-98.557,3.74],[-76.598,29.659]],"c":true}},"o":{"k":100},"x":{"k":0},"nm":"蒙版 2"},{"inv":false,"mode":"f","pt":{"k":{"i":[[0,0],[0,0],[0,0],[0,0],[-6.36,0],[-2.399,-4.56],[0,0],[-6.24,0],[0,-10.8],[0,0],[0,0],[0,0],[8.52,0],[7.68,-4.68],[0,-2.4],[0,0],[0,0],[0,0],[8.4,0],[6.959,-4.56],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[7.08,-4.32],[6.72,0],[0,0],[8.16,-5.159],[9.359,0],[0,0],[0,0],[0,0],[0,-9.479],[-5.76,0],[0.48,1.68],[0,0],[0,0],[0,0],[0,-9.479],[-6.479,0],[0,0],[0,0],[0,0]],"v":[[-40.958,-25.898],[-38.079,-25.898],[-38.079,-20.259],[-37.838,-20.259],[-17.56,-26.739],[-3.76,-19.899],[-3.52,-19.899],[17.839,-26.739],[33.558,-11.739],[33.558,31.339],[30.678,31.339],[30.678,-11.26],[16.999,-24.099],[-3.04,-17.619],[-2.2,-11.739],[-2.2,31.339],[-5.32,31.339],[-5.32,-11.26],[-18.16,-24.099],[-37.958,-17.499],[-37.958,31.339],[-40.958,31.339]],"c":true}},"o":{"k":100},"x":{"k":0},"nm":"蒙版 3"},{"inv":false,"mode":"f","pt":{"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[47.12,-43.658],[50.24,-43.658],[50.24,-39.219],[47.12,-39.219]],"c":true}},"o":{"k":100},"x":{"k":0},"nm":"蒙版 4"},{"inv":false,"mode":"f","pt":{"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[47.24,-26.019],[50.24,-26.019],[50.24,31.099],[47.24,31.099]],"c":true}},"o":{"k":100},"x":{"k":0},"nm":"蒙版 5"},{"inv":false,"mode":"f","pt":{"k":{"i":[[0,0],[0,0],[0,0],[0,0],[-7.199,0],[0,-10.8],[0,0],[0,0],[0,0],[10.079,0],[6.959,-4.44],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[7.079,-4.32],[10.559,0],[0,0],[0,0],[0,0],[0,-9.479],[-6.96,0],[0,0],[0,0],[0,0]],"v":[[63.919,-25.898],[66.799,-25.898],[66.799,-20.259],[67.04,-20.259],[89.358,-26.739],[105.917,-11.739],[105.917,31.339],[102.917,31.339],[102.917,-11.26],[88.279,-24.099],[66.919,-17.499],[66.919,31.339],[63.919,31.339]],"c":true}},"o":{"k":100},"x":{"k":0},"nm":"蒙版 6"},{"inv":false,"mode":"f","pt":{"k":{"i":[[0,8.28],[-6.6,2.52],[0,0],[0,4.2],[-3.12,2.88],[0,6.239],[0,0],[-11.759,0],[-2.16,-0.479],[0,0],[0,0],[0,0],[0,-6.6],[0,0],[11.52,0],[3.24,1.68],[0,-3.24],[-4.56,0],[0,0],[0,-10.68],[18.959,0]],"o":[[0,-7.56],[0,0],[-3.119,-0.6],[0,-3.479],[-4.56,-2.76],[0,0],[0,-10.92],[2.521,0],[0,0],[0,0],[0,0],[4.92,2.64],[0,0],[0,11.399],[-4.2,0],[-2.279,2.04],[0,3.84],[0,0],[9.84,0],[0,9.479],[-17.64,0]],"v":[[113.838,34.698],[125.958,22.699],[125.958,22.459],[119.838,14.899],[125.358,6.02],[118.158,-8.019],[118.158,-8.979],[138.437,-26.499],[145.397,-25.779],[163.997,-25.779],[163.997,-23.259],[150.437,-23.259],[158.237,-9.22],[158.237,-8.019],[138.318,9.5],[127.158,7.22],[122.838,14.18],[130.038,20.539],[147.197,20.539],[164.356,32.059],[137.958,49.698]],"c":true}},"o":{"k":100},"x":{"k":0},"nm":"蒙版 7"},{"inv":false,"mode":"f","pt":{"k":{"i":[[0,8.039],[8.64,0],[0,0],[0,-7.2],[-15.72,0]],"o":[[0,-9],[0,0],[-7.08,2.28],[0,7.079],[17.159,0]],"v":[[161.357,32.419],[146.837,23.419],[129.438,23.419],[116.959,34.459],[137.837,47.059]],"c":true}},"o":{"k":100},"x":{"k":0},"nm":"蒙版 8"},{"inv":false,"mode":"f","pt":{"k":{"i":[[0,9.72],[0,0],[10.079,0],[0,-9.479],[0,0],[-10.08,0]],"o":[[0,0],[0,-10.079],[-10.2,0],[0,0],[0,9.72],[10.199,0]],"v":[[155.237,-7.899],[155.237,-9.22],[138.318,-24.099],[121.158,-9.22],[121.158,-7.899],[138.318,7.1]],"c":true}},"o":{"k":100},"x":{"k":0},"nm":"蒙版 9"}],"shapes":[{"ind":0,"ty":"sh","ks":{"k":{"i":[[0,25.68],[0,0],[-21.479,0],[-4.44,-2.521],[0,0],[8.64,0],[0,-24.238],[0,0],[-20.399,0],[-4.68,2.64],[0,0],[11.279,0]],"o":[[0,0],[0,-25.919],[9.239,0],[0,0],[-4.8,-2.52],[-19.56,0],[0,0],[0,24.119],[10.56,0],[0,0],[-3.96,2.159],[-21.839,0]],"v":[[-163.856,-8.16],[-163.856,-9.72],[-129.897,-49.198],[-110.818,-44.878],[-110.818,-42.118],[-129.897,-46.438],[-160.736,-10.08],[-160.736,-8.04],[-131.217,28.799],[-110.338,23.399],[-110.338,26.279],[-131.457,31.559]],"c":true}},"nm":"路径 1","mn":"ADBE Vector Shape - Group"}],"ip":0,"op":140,"st":0,"bm":0,"sr":1},{"ddd":0,"ind":11,"ty":4,"nm":"形状图层 3","ks":{"o":{"k":100},"r":{"k":0},"p":{"k":[393.5,225,0]},"a":{"k":[0,0,0]},"s":{"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"k":[2.757,15.836]},"p":{"k":[0,0]},"r":{"k":0},"nm":"矩形路径 1","mn":"ADBE Vector Shape - Rect"},{"ty":"fl","fillEnabled":true,"c":{"k":[0.42,0.42,0.42,1]},"o":{"k":100},"nm":"填充 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"k":[395.003,-82.082],"ix":2},"a":{"k":[0,0],"ix":1},"s":{"k":[100,100],"ix":3},"r":{"k":0,"ix":6},"o":{"k":100,"ix":7},"sk":{"k":0,"ix":4},"sa":{"k":0,"ix":5},"nm":"变换"}],"nm":"矩形 1","np":3,"mn":"ADBE Vector Group"}],"ip":0,"op":140,"st":0,"bm":0,"sr":1},{"ddd":0,"ind":12,"ty":4,"nm":"“图层 2”轮廓","ks":{"o":{"k":100},"r":{"k":0},"p":{"k":[371.5,221,0]},"a":{"k":[417.5,314,0]},"s":{"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"k":{"i":[[1.381,0],[0,-1.381],[-1.381,0],[0,1.381]],"o":[[-1.381,0],[0,1.381],[1.381,0],[0,-1.381]],"v":[[0,-2.5],[-2.5,0],[0,2.5],[2.5,0]],"c":true}},"nm":"路径 1","mn":"ADBE Vector Shape - Group"},{"ind":1,"ty":"sh","ks":{"k":{"i":[[-0.275,0],[0,-0.275],[0.275,0],[0,0.275]],"o":[[0.275,0],[0,0.275],[-0.275,0],[0,-0.275]],"v":[[0,-0.5],[0.5,0],[0,0.5],[-0.5,0]],"c":true}},"nm":"路径 2","mn":"ADBE Vector Shape - Group"},{"ty":"mm","mm":1,"nm":"合并路径 1","mn":"ADBE Vector Filter - Merge"},{"ty":"fl","fillEnabled":true,"c":{"k":[0.2,0.2,0.2,1]},"o":{"k":100},"nm":"填充 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"k":[680.5,341.5],"ix":2},"a":{"k":[0,0],"ix":1},"s":{"k":[100,100],"ix":3},"r":{"k":0,"ix":6},"o":{"k":100,"ix":7},"sk":{"k":0,"ix":4},"sa":{"k":0,"ix":5},"nm":"变换"}],"nm":"组 1","np":4,"mn":"ADBE Vector Group"}],"ip":0,"op":140,"st":0,"bm":0,"sr":1},{"ddd":0,"ind":13,"ty":4,"nm":"“图层 3”轮廓","ks":{"o":{"k":100},"r":{"k":0},"p":{"k":[371.5,221,0]},"a":{"k":[417.5,314,0]},"s":{"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"k":{"i":[[1.933,0],[0,-1.933],[-1.933,0],[0,1.933]],"o":[[-1.933,0],[0,1.933],[1.933,0],[0,-1.933]],"v":[[0,-3.5],[-3.5,0],[0,3.5],[3.5,0]],"c":true}},"nm":"路径 1","mn":"ADBE Vector Shape - Group"},{"ind":1,"ty":"sh","ks":{"k":{"i":[[-0.827,0],[0,-0.827],[0.827,0],[0,0.827]],"o":[[0.827,0],[0,0.827],[-0.827,0],[0,-0.827]],"v":[[0,-1.5],[1.5,0],[0,1.5],[-1.5,0]],"c":true}},"nm":"路径 2","mn":"ADBE Vector Shape - Group"},{"ty":"mm","mm":1,"nm":"合并路径 1","mn":"ADBE Vector Filter - Merge"},{"ty":"fl","fillEnabled":true,"c":{"k":[0.2,0.2,0.2,1]},"o":{"k":100},"nm":"填充 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"k":[610.5,278.5],"ix":2},"a":{"k":[0,0],"ix":1},"s":{"k":[100,100],"ix":3},"r":{"k":0,"ix":6},"o":{"k":100,"ix":7},"sk":{"k":0,"ix":4},"sa":{"k":0,"ix":5},"nm":"变换"}],"nm":"组 1","np":4,"mn":"ADBE Vector Group"}],"ip":0,"op":140,"st":0,"bm":0,"sr":1},{"ddd":0,"ind":14,"ty":4,"nm":"“图层 5”轮廓","ks":{"o":{"k":100},"r":{"k":0},"p":{"k":[371.5,221,0]},"a":{"k":[417.5,314,0]},"s":{"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"k":{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-92,17],[58,-18],[92,18]],"c":false}},"nm":"路径 1","mn":"ADBE Vector Shape - Group"},{"ty":"st","fillEnabled":true,"c":{"k":[0.42,0.42,0.42,1]},"o":{"k":100},"w":{"k":2},"lc":1,"lj":1,"ml":10,"nm":"描边 1","mn":"ADBE Vector Graphic - Stroke"},{"ty":"tr","p":{"k":[702,212],"ix":2},"a":{"k":[0,0],"ix":1},"s":{"k":[100,100],"ix":3},"r":{"k":0,"ix":6},"o":{"k":100,"ix":7},"sk":{"k":0,"ix":4},"sa":{"k":0,"ix":5},"nm":"变换"}],"nm":"组 1","np":2,"mn":"ADBE Vector Group"}],"ip":0,"op":140,"st":0,"bm":0,"sr":1},{"ddd":0,"ind":15,"ty":4,"nm":"“图层 6”轮廓","ks":{"o":{"k":100},"r":{"k":0},"p":{"k":[371.5,221,0]},"a":{"k":[417.5,314,0]},"s":{"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[5.363,-10],[-5.362,-10],[-5.362,0],[5.363,10]],"c":true}},"nm":"路径 1","mn":"ADBE Vector Shape - Group"},{"ind":1,"ty":"sh","ks":{"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[3.363,-8],[3.363,5.401],[-3.362,-0.87],[-3.362,-8]],"c":true}},"nm":"路径 2","mn":"ADBE Vector Shape - Group"},{"ty":"mm","mm":1,"nm":"合并路径 1","mn":"ADBE Vector Filter - Merge"},{"ty":"fl","fillEnabled":true,"c":{"k":[0.42,0.42,0.42,1]},"o":{"k":100},"nm":"填充 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"k":[734.637,259],"ix":2},"a":{"k":[0,0],"ix":1},"s":{"k":[100,100],"ix":3},"r":{"k":0,"ix":6},"o":{"k":100,"ix":7},"sk":{"k":0,"ix":4},"sa":{"k":0,"ix":5},"nm":"变换"}],"nm":"组 1","np":4,"mn":"ADBE Vector Group"}],"ip":0,"op":140,"st":0,"bm":0,"sr":1},{"ddd":0,"ind":16,"ty":4,"nm":"nn 2","ks":{"o":{"k":100},"r":{"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"n":["0p667_1_0p333_0"],"t":46,"s":[0],"e":[15]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"n":["0p667_1_0p333_0"],"t":49,"s":[15],"e":[0]},{"t":52}]},"p":{"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":46,"s":[620,351.375,0],"e":[638,351.375,0],"to":[3,0,0],"ti":[-3,0,0]},{"t":49}]},"a":{"k":[27.25,29.875,0]},"s":{"k":[{"i":{"x":[0.667,0.667,0.667],"y":[0.667,1,0.667]},"o":{"x":[0.333,0.333,0.333],"y":[0.333,0,0.333]},"n":["0p667_0p667_0p333_0p333","0p667_1_0p333_0","0p667_0p667_0p333_0p333"],"t":46,"s":[100,100,100],"e":[100,85,100]},{"i":{"x":[0.667,0.667,0.667],"y":[0.667,1,0.667]},"o":{"x":[0.333,0.333,0.333],"y":[0.333,0,0.333]},"n":["0p667_0p667_0p333_0p333","0p667_1_0p333_0","0p667_0p667_0p333_0p333"],"t":49,"s":[100,85,100],"e":[100,100,100]},{"t":52}]}},"ao":0,"shapes":[{"ind":0,"ty":"sh","ks":{"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"n":"0p667_1_0p333_0","t":46,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0.626,1.68],[6.339,0],[6.373,-3.627],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-6.283,0],[-0.483,-0.019],[-0.51,0],[0,-10.8],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[-2.212,-3.344],[-6.298,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[6.365,-3.293],[0.504,0],[0.517,-0.022],[10.559,0],[0,0],[0,0],[0,0],[0,0]],"v":[[27,30.392],[12,30.392],[12,27.392],[16.339,27.392],[16.37,0.375],[15.402,-21.076],[2.7,-25.752],[-16.659,-20.337],[-16.628,0.375],[-16.659,27.392],[-12,27.392],[-12,30.392],[-27,30.392],[-27,27.392],[-22.659,27.392],[-22.628,0.375],[-22.659,-29.552],[-19.779,-29.552],[-19.779,-27.552],[-19.659,-27.552],[-19.659,-29.552],[-16.779,-29.552],[-16.779,-25.42],[2.78,-30.392],[4.231,-30.335],[5.78,-30.392],[22.339,-15.393],[22.37,0.25],[22.339,27.392],[27,27.392]],"c":true}],"e":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,11.25],[0.626,1.68],[6.339,0],[6.373,-3.627],[0,-11.25],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,11.806],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-6.283,0],[-0.483,-0.019],[-0.51,0],[-2.661,-5.351],[0,-8.18],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,-11.25],[-2.212,-3.344],[-6.298,0],[0,0],[0,11.25],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,-11.806],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[6.365,-3.293],[0.504,0],[0.517,-0.022],[10.559,0],[2.661,5.351],[0,8.181],[0,0],[0,0]],"v":[[27,30.392],[12,30.392],[12,27.392],[16.339,27.392],[23.745,0.375],[17.402,-19.687],[2.7,-25.752],[-14.534,-20.198],[-9.253,0.375],[-16.659,27.392],[-12,27.392],[-12,30.392],[-27,30.392],[-27,27.392],[-22.659,27.392],[-15.253,0.375],[-22.659,-29.552],[-19.779,-29.552],[-19.779,-27.552],[-19.659,-27.552],[-19.659,-29.552],[-16.779,-29.552],[-16.779,-25.42],[2.78,-30.392],[4.231,-30.335],[5.78,-30.392],[23.839,-18.448],[29.745,0.25],[22.339,27.392],[27,27.392]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"n":"0p833_1_0p333_0","t":49,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,11.25],[0.626,1.68],[6.339,0],[6.373,-3.627],[0,-11.25],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,11.806],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-6.283,0],[-0.483,-0.019],[-0.51,0],[-2.661,-5.351],[0,-8.18],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,-11.25],[-2.212,-3.344],[-6.298,0],[0,0],[0,11.25],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,-11.806],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[6.365,-3.293],[0.504,0],[0.517,-0.022],[10.559,0],[2.661,5.351],[0,8.181],[0,0],[0,0]],"v":[[27,30.392],[12,30.392],[12,27.392],[16.339,27.392],[23.745,0.375],[17.402,-19.687],[2.7,-25.752],[-14.534,-20.198],[-9.253,0.375],[-16.659,27.392],[-12,27.392],[-12,30.392],[-27,30.392],[-27,27.392],[-22.659,27.392],[-15.253,0.375],[-22.659,-29.552],[-19.779,-29.552],[-19.779,-27.552],[-19.659,-27.552],[-19.659,-29.552],[-16.779,-29.552],[-16.779,-25.42],[2.78,-30.392],[4.231,-30.335],[5.78,-30.392],[23.839,-18.448],[29.745,0.25],[22.339,27.392],[27,27.392]],"c":true}],"e":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0.626,1.68],[6.339,0],[6.373,-3.627],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[-6.283,0],[-0.483,-0.019],[-0.51,0],[0,-10.8],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[-2.212,-3.344],[-6.298,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[6.365,-3.293],[0.504,0],[0.517,-0.022],[10.559,0],[0,0],[0,0],[0,0],[0,0]],"v":[[27,30.392],[12,30.392],[12,27.392],[16.339,27.392],[16.37,0.375],[15.402,-21.076],[2.7,-25.752],[-16.659,-20.337],[-16.628,0.375],[-16.659,27.392],[-12,27.392],[-12,30.392],[-27,30.392],[-27,27.392],[-22.659,27.392],[-22.628,0.375],[-22.659,-29.552],[-19.779,-29.552],[-19.779,-27.552],[-19.659,-27.552],[-19.659,-29.552],[-16.779,-29.552],[-16.779,-25.42],[2.78,-30.392],[4.231,-30.335],[5.78,-30.392],[22.339,-15.393],[22.37,0.25],[22.339,27.392],[27,27.392]],"c":true}]},{"t":52}]},"nm":"路径 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","fillEnabled":true,"c":{"k":[0,0,0,1]},"o":{"k":100},"nm":"填充 1","mn":"ADBE Vector Graphic - Fill"}],"ip":0,"op":140,"st":0,"bm":0,"sr":1},{"ddd":0,"ind":17,"ty":4,"nm":"形状图层 9","ks":{"o":{"k":100},"r":{"k":0},"p":{"k":[329.5,351.5,0]},"a":{"k":[0,0,0]},"s":{"k":[100,100,100]}},"ao":0,"shapes":[{"ind":0,"ty":"sh","ks":{"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-8,-1.5],[8,-1.5],[8,1.5],[-8,1.5]],"c":true}},"nm":"路径 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","fillEnabled":true,"c":{"k":[0,0,0,1]},"o":{"k":100},"nm":"填充 1","mn":"ADBE Vector Graphic - Fill"}],"ip":0,"op":140,"st":0,"bm":0,"sr":1},{"ddd":0,"ind":18,"ty":4,"nm":"形状图层 8","ks":{"o":{"k":100},"r":{"k":0},"p":{"k":[290,351.5,0]},"a":{"k":[0,0,0]},"s":{"k":[100,100,100]}},"ao":0,"shapes":[{"ind":0,"ty":"sh","ks":{"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-8,-1.5],[8,-1.5],[8,1.5],[-8,1.5]],"c":true}},"nm":"路径 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","fillEnabled":true,"c":{"k":[0,0,0,1]},"o":{"k":100},"nm":"填充 1","mn":"ADBE Vector Graphic - Fill"}],"ip":0,"op":140,"st":0,"bm":0,"sr":1},{"ddd":0,"ind":19,"ty":4,"nm":"形状图层 7","ks":{"o":{"k":100},"r":{"k":0},"p":{"k":[274,351.5,0]},"a":{"k":[0,0,0]},"s":{"k":[92,100,100]}},"ao":0,"shapes":[{"ind":0,"ty":"sh","ks":{"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-8,-1.5],[8,-1.5],[8,1.5],[-8,1.5]],"c":true}},"nm":"路径 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","fillEnabled":true,"c":{"k":[0,0,0,1]},"o":{"k":100},"nm":"填充 1","mn":"ADBE Vector Graphic - Fill"}],"ip":0,"op":140,"st":0,"bm":0,"sr":1},{"ddd":0,"ind":20,"ty":4,"nm":"形状图层 6","ks":{"o":{"k":100},"r":{"k":0},"p":{"k":[257.5,351.5,0]},"a":{"k":[0,0,0]},"s":{"k":[89,100,100]}},"ao":0,"shapes":[{"ind":0,"ty":"sh","ks":{"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-8,-1.5],[8,-1.5],[8,1.5],[-8,1.5]],"c":true}},"nm":"路径 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","fillEnabled":true,"c":{"k":[0,0,0,1]},"o":{"k":100},"nm":"填充 1","mn":"ADBE Vector Graphic - Fill"}],"ip":0,"op":140,"st":0,"bm":0,"sr":1},{"ddd":0,"ind":21,"ty":4,"nm":"形状图层 5","ks":{"o":{"k":100},"r":{"k":0},"p":{"k":[222.5,351.5,0]},"a":{"k":[0,0,0]},"s":{"k":[100,100,100]}},"ao":0,"shapes":[{"ind":0,"ty":"sh","ks":{"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-8,-1.5],[8,-1.5],[8,1.5],[-8,1.5]],"c":true}},"nm":"路径 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","fillEnabled":true,"c":{"k":[0,0,0,1]},"o":{"k":100},"nm":"填充 1","mn":"ADBE Vector Graphic - Fill"}],"ip":0,"op":140,"st":0,"bm":0,"sr":1},{"ddd":0,"ind":22,"ty":4,"nm":"形状图层 4","ks":{"o":{"k":100},"r":{"k":0},"p":{"k":[187.5,351.5,0]},"a":{"k":[0,0,0]},"s":{"k":[100,100,100]}},"ao":0,"shapes":[{"ind":0,"ty":"sh","ks":{"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-8,-1.5],[8,-1.5],[8,1.5],[-8,1.5]],"c":true}},"nm":"路径 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","fillEnabled":true,"c":{"k":[0,0,0,1]},"o":{"k":100},"nm":"填充 1","mn":"ADBE Vector Graphic - Fill"}],"ip":0,"op":140,"st":0,"bm":0,"sr":1},{"ddd":0,"ind":23,"ty":4,"nm":"“图层 7”轮廓","ks":{"o":{"k":100},"r":{"k":0},"p":{"k":[371.5,221,0]},"a":{"k":[417.5,314,0]},"s":{"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[11,20],[-11,0],[-11,-20],[11,-20]],"c":true}},"nm":"路径 1","mn":"ADBE Vector Shape - Group"},{"ty":"st","fillEnabled":true,"c":{"k":[0.42,0.42,0.42,1]},"o":{"k":100},"w":{"k":3},"lc":1,"lj":1,"ml":10,"nm":"描边 1","mn":"ADBE Vector Graphic - Stroke"},{"ty":"tr","p":{"k":[734.5,262.5],"ix":2},"a":{"k":[0,0],"ix":1},"s":{"k":[100,100],"ix":3},"r":{"k":0,"ix":6},"o":{"k":100,"ix":7},"sk":{"k":0,"ix":4},"sa":{"k":0,"ix":5},"nm":"变换"}],"nm":"组 1","np":2,"mn":"ADBE Vector Group"}],"ip":0,"op":140,"st":0,"bm":0,"sr":1},{"ddd":0,"ind":24,"ty":4,"nm":"“图层 8”轮廓","ks":{"o":{"k":100},"r":{"k":0},"p":{"k":[371.5,221,0]},"a":{"k":[417.5,314,0]},"s":{"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[13,-1],[-13,-1],[-13,1],[13,1]],"c":true}},"nm":"路径 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","fillEnabled":true,"c":{"k":[0.42,0.42,0.42,1]},"o":{"k":100},"nm":"填充 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"k":[760,374],"ix":2},"a":{"k":[0,0],"ix":1},"s":{"k":[100,100],"ix":3},"r":{"k":0,"ix":6},"o":{"k":100,"ix":7},"sk":{"k":0,"ix":4},"sa":{"k":0,"ix":5},"nm":"变换"}],"nm":"组 1","np":2,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[13,-1],[-13,-1],[-13,1],[13,1]],"c":true}},"nm":"路径 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","fillEnabled":true,"c":{"k":[0.42,0.42,0.42,1]},"o":{"k":100},"nm":"填充 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"k":[760,351],"ix":2},"a":{"k":[0,0],"ix":1},"s":{"k":[100,100],"ix":3},"r":{"k":0,"ix":6},"o":{"k":100,"ix":7},"sk":{"k":0,"ix":4},"sa":{"k":0,"ix":5},"nm":"变换"}],"nm":"组 2","np":2,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[13,-1],[-13,-1],[-13,1],[13,1]],"c":true}},"nm":"路径 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","fillEnabled":true,"c":{"k":[0.42,0.42,0.42,1]},"o":{"k":100},"nm":"填充 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"k":[760,330],"ix":2},"a":{"k":[0,0],"ix":1},"s":{"k":[100,100],"ix":3},"r":{"k":0,"ix":6},"o":{"k":100,"ix":7},"sk":{"k":0,"ix":4},"sa":{"k":0,"ix":5},"nm":"变换"}],"nm":"组 3","np":2,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[13,-1],[-13,-1],[-13,1],[13,1]],"c":true}},"nm":"路径 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","fillEnabled":true,"c":{"k":[0.42,0.42,0.42,1]},"o":{"k":100},"nm":"填充 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"k":[760,309],"ix":2},"a":{"k":[0,0],"ix":1},"s":{"k":[100,100],"ix":3},"r":{"k":0,"ix":6},"o":{"k":100,"ix":7},"sk":{"k":0,"ix":4},"sa":{"k":0,"ix":5},"nm":"变换"}],"nm":"组 4","np":2,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[13,-1],[-13,-1],[-13,1],[13,1]],"c":true}},"nm":"路径 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","fillEnabled":true,"c":{"k":[0.42,0.42,0.42,1]},"o":{"k":100},"nm":"填充 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"k":[760,286],"ix":2},"a":{"k":[0,0],"ix":1},"s":{"k":[100,100],"ix":3},"r":{"k":0,"ix":6},"o":{"k":100,"ix":7},"sk":{"k":0,"ix":4},"sa":{"k":0,"ix":5},"nm":"变换"}],"nm":"组 5","np":2,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[13,-1],[-13,-1],[-13,1],[13,1]],"c":true}},"nm":"路径 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","fillEnabled":true,"c":{"k":[0.42,0.42,0.42,1]},"o":{"k":100},"nm":"填充 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"k":[760,265],"ix":2},"a":{"k":[0,0],"ix":1},"s":{"k":[100,100],"ix":3},"r":{"k":0,"ix":6},"o":{"k":100,"ix":7},"sk":{"k":0,"ix":4},"sa":{"k":0,"ix":5},"nm":"变换"}],"nm":"组 6","np":2,"mn":"ADBE Vector Group"}],"ip":0,"op":140,"st":0,"bm":0,"sr":1},{"ddd":0,"ind":25,"ty":4,"nm":"“图层 9”轮廓","ks":{"o":{"k":100},"r":{"k":0},"p":{"k":[371.5,221,0]},"a":{"k":[417.5,314,0]},"s":{"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[16,-78],[-16,-78],[-16,78],[16,78]],"c":true}},"nm":"路径 1","mn":"ADBE Vector Shape - Group"},{"ind":1,"ty":"sh","ks":{"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[13,75],[-13,75],[-13,-75],[13,-75]],"c":true}},"nm":"路径 2","mn":"ADBE Vector Shape - Group"},{"ty":"mm","mm":1,"nm":"合并路径 1","mn":"ADBE Vector Filter - Merge"},{"ty":"fl","fillEnabled":true,"c":{"k":[0.42,0.42,0.42,1]},"o":{"k":100},"nm":"填充 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"k":[760,319],"ix":2},"a":{"k":[0,0],"ix":1},"s":{"k":[100,100],"ix":3},"r":{"k":0,"ix":6},"o":{"k":100,"ix":7},"sk":{"k":0,"ix":4},"sa":{"k":0,"ix":5},"nm":"变换"}],"nm":"组 1","np":4,"mn":"ADBE Vector Group"}],"ip":0,"op":140,"st":0,"bm":0,"sr":1},{"ddd":0,"ind":26,"ty":4,"nm":"“图层 10”轮廓","ks":{"o":{"k":100},"r":{"k":0},"p":{"k":[371.5,221,0]},"a":{"k":[417.5,314,0]},"s":{"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[13.75,-76.5],[-13.75,-55.5],[13.75,-32.5],[-13.75,-10.5],[13.75,10.5],[-13.75,32.5],[13.75,54.5],[-13.75,76.5]],"c":false}},"nm":"路径 1","mn":"ADBE Vector Shape - Group"},{"ty":"st","fillEnabled":true,"c":{"k":[0.42,0.42,0.42,1]},"o":{"k":100},"w":{"k":2},"lc":1,"lj":1,"ml":10,"nm":"描边 1","mn":"ADBE Vector Graphic - Stroke"},{"ty":"tr","p":{"k":[760.25,320],"ix":2},"a":{"k":[0,0],"ix":1},"s":{"k":[100,100],"ix":3},"r":{"k":0,"ix":6},"o":{"k":100,"ix":7},"sk":{"k":0,"ix":4},"sa":{"k":0,"ix":5},"nm":"变换"}],"nm":"组 1","np":2,"mn":"ADBE Vector Group"}],"ip":0,"op":140,"st":0,"bm":0,"sr":1},{"ddd":0,"ind":27,"ty":4,"nm":"“图层 11”轮廓","ks":{"o":{"k":100},"r":{"k":0},"p":{"k":[371.5,221,0]},"a":{"k":[417.5,314,0]},"s":{"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-13.75,-76.5],[13.75,-55.5],[-13.75,-32.5],[13.75,-10.5],[-13.75,10.5],[13.75,32.5],[-13.75,54.5],[13.75,76.5]],"c":false}},"nm":"路径 1","mn":"ADBE Vector Shape - Group"},{"ty":"st","fillEnabled":true,"c":{"k":[0.42,0.42,0.42,1]},"o":{"k":100},"w":{"k":2},"lc":1,"lj":1,"ml":10,"nm":"描边 1","mn":"ADBE Vector Graphic - Stroke"},{"ty":"tr","p":{"k":[759.25,319],"ix":2},"a":{"k":[0,0],"ix":1},"s":{"k":[100,100],"ix":3},"r":{"k":0,"ix":6},"o":{"k":100,"ix":7},"sk":{"k":0,"ix":4},"sa":{"k":0,"ix":5},"nm":"变换"}],"nm":"组 1","np":2,"mn":"ADBE Vector Group"}],"ip":0,"op":140,"st":0,"bm":0,"sr":1},{"ddd":0,"ind":28,"ty":4,"nm":"“图层 12”轮廓","ks":{"o":{"k":100},"r":{"k":0},"p":{"k":[371.5,221,0]},"a":{"k":[417.5,314,0]},"s":{"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-114,-8],[-114,8],[114,8],[114,5],[-111,5],[-111,-5],[114,-5],[114,-8]],"c":true}},"nm":"路径 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","fillEnabled":true,"c":{"k":[0.42,0.42,0.42,1]},"o":{"k":100},"nm":"填充 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"k":[721,236],"ix":2},"a":{"k":[0,0],"ix":1},"s":{"k":[100,100],"ix":3},"r":{"k":0,"ix":6},"o":{"k":100,"ix":7},"sk":{"k":0,"ix":4},"sa":{"k":0,"ix":5},"nm":"变换"}],"nm":"组 1","np":2,"mn":"ADBE Vector Group"}],"ip":0,"op":140,"st":0,"bm":0,"sr":1},{"ddd":0,"ind":29,"ty":4,"nm":"“图层 13”轮廓","ks":{"o":{"k":100},"r":{"k":0},"p":{"k":[371.5,221,0]},"a":{"k":[417.5,314,0]},"s":{"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-1,5.5],[1,5.5],[1,-5.5],[-1,-5.5]],"c":true}},"nm":"路径 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","fillEnabled":true,"c":{"k":[0.6,0.6,0.6,1]},"o":{"k":100},"nm":"填充 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"k":[813,235.5],"ix":2},"a":{"k":[0,0],"ix":1},"s":{"k":[100,100],"ix":3},"r":{"k":0,"ix":6},"o":{"k":100,"ix":7},"sk":{"k":0,"ix":4},"sa":{"k":0,"ix":5},"nm":"变换"}],"nm":"组 1","np":2,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-1,5.5],[1,5.5],[1,-5.5],[-1,-5.5]],"c":true}},"nm":"路径 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","fillEnabled":true,"c":{"k":[0.6,0.6,0.6,1]},"o":{"k":100},"nm":"填充 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"k":[791,235.5],"ix":2},"a":{"k":[0,0],"ix":1},"s":{"k":[100,100],"ix":3},"r":{"k":0,"ix":6},"o":{"k":100,"ix":7},"sk":{"k":0,"ix":4},"sa":{"k":0,"ix":5},"nm":"变换"}],"nm":"组 2","np":2,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-1,5.5],[1,5.5],[1,-5.5],[-1,-5.5]],"c":true}},"nm":"路径 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","fillEnabled":true,"c":{"k":[0.6,0.6,0.6,1]},"o":{"k":100},"nm":"填充 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"k":[770,235.5],"ix":2},"a":{"k":[0,0],"ix":1},"s":{"k":[100,100],"ix":3},"r":{"k":0,"ix":6},"o":{"k":100,"ix":7},"sk":{"k":0,"ix":4},"sa":{"k":0,"ix":5},"nm":"变换"}],"nm":"组 3","np":2,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-1,5.5],[1,5.5],[1,-5.5],[-1,-5.5]],"c":true}},"nm":"路径 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","fillEnabled":true,"c":{"k":[0.6,0.6,0.6,1]},"o":{"k":100},"nm":"填充 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"k":[747,235.5],"ix":2},"a":{"k":[0,0],"ix":1},"s":{"k":[100,100],"ix":3},"r":{"k":0,"ix":6},"o":{"k":100,"ix":7},"sk":{"k":0,"ix":4},"sa":{"k":0,"ix":5},"nm":"变换"}],"nm":"组 4","np":2,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-1,5.5],[1,5.5],[1,-5.5],[-1,-5.5]],"c":true}},"nm":"路径 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","fillEnabled":true,"c":{"k":[0.6,0.6,0.6,1]},"o":{"k":100},"nm":"填充 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"k":[724,235.5],"ix":2},"a":{"k":[0,0],"ix":1},"s":{"k":[100,100],"ix":3},"r":{"k":0,"ix":6},"o":{"k":100,"ix":7},"sk":{"k":0,"ix":4},"sa":{"k":0,"ix":5},"nm":"变换"}],"nm":"组 5","np":2,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-1,5.5],[1,5.5],[1,-5.5],[-1,-5.5]],"c":true}},"nm":"路径 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","fillEnabled":true,"c":{"k":[0.6,0.6,0.6,1]},"o":{"k":100},"nm":"填充 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"k":[700,235.5],"ix":2},"a":{"k":[0,0],"ix":1},"s":{"k":[100,100],"ix":3},"r":{"k":0,"ix":6},"o":{"k":100,"ix":7},"sk":{"k":0,"ix":4},"sa":{"k":0,"ix":5},"nm":"变换"}],"nm":"组 6","np":2,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-1,5.5],[1,5.5],[1,-5.5],[-1,-5.5]],"c":true}},"nm":"路径 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","fillEnabled":true,"c":{"k":[0.6,0.6,0.6,1]},"o":{"k":100},"nm":"填充 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"k":[675,235.5],"ix":2},"a":{"k":[0,0],"ix":1},"s":{"k":[100,100],"ix":3},"r":{"k":0,"ix":6},"o":{"k":100,"ix":7},"sk":{"k":0,"ix":4},"sa":{"k":0,"ix":5},"nm":"变换"}],"nm":"组 7","np":2,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-1,5.5],[1,5.5],[1,-5.5],[-1,-5.5]],"c":true}},"nm":"路径 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","fillEnabled":true,"c":{"k":[0.6,0.6,0.6,1]},"o":{"k":100},"nm":"填充 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"k":[654,235.5],"ix":2},"a":{"k":[0,0],"ix":1},"s":{"k":[100,100],"ix":3},"r":{"k":0,"ix":6},"o":{"k":100,"ix":7},"sk":{"k":0,"ix":4},"sa":{"k":0,"ix":5},"nm":"变换"}],"nm":"组 8","np":2,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-1,5.5],[1,5.5],[1,-5.5],[-1,-5.5]],"c":true}},"nm":"路径 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","fillEnabled":true,"c":{"k":[0.6,0.6,0.6,1]},"o":{"k":100},"nm":"填充 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"k":[631,235.5],"ix":2},"a":{"k":[0,0],"ix":1},"s":{"k":[100,100],"ix":3},"r":{"k":0,"ix":6},"o":{"k":100,"ix":7},"sk":{"k":0,"ix":4},"sa":{"k":0,"ix":5},"nm":"变换"}],"nm":"组 9","np":2,"mn":"ADBE Vector Group"}],"ip":0,"op":140,"st":0,"bm":0,"sr":1},{"ddd":0,"ind":30,"ty":4,"nm":"“图层 14”轮廓","ks":{"o":{"k":100},"r":{"k":0},"p":{"k":[371.5,221,0]},"a":{"k":[417.5,314,0]},"s":{"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[55,-11],[-55,-11],[-55,11],[55,11]],"c":true}},"nm":"路径 1","mn":"ADBE Vector Shape - Group"},{"ind":1,"ty":"sh","ks":{"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[52,8],[-52,8],[-52,-8],[52,-8]],"c":true}},"nm":"路径 2","mn":"ADBE Vector Shape - Group"},{"ty":"mm","mm":1,"nm":"合并路径 1","mn":"ADBE Vector Filter - Merge"},{"ty":"fl","fillEnabled":true,"c":{"k":[0.42,0.42,0.42,1]},"o":{"k":100},"nm":"填充 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"k":[759,437],"ix":2},"a":{"k":[0,0],"ix":1},"s":{"k":[100,100],"ix":3},"r":{"k":0,"ix":6},"o":{"k":100,"ix":7},"sk":{"k":0,"ix":4},"sa":{"k":0,"ix":5},"nm":"变换"}],"nm":"组 1","np":4,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-53.5,-9.5],[53.5,-9.5],[53.5,9.5],[-53.5,9.5]],"c":true}},"nm":"路径 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","fillEnabled":true,"c":{"k":[0.89,0.89,0.89,1]},"o":{"k":100},"nm":"填充 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"k":[759,437],"ix":2},"a":{"k":[0,0],"ix":1},"s":{"k":[100,100],"ix":3},"r":{"k":0,"ix":6},"o":{"k":100,"ix":7},"sk":{"k":0,"ix":4},"sa":{"k":0,"ix":5},"nm":"变换"}],"nm":"组 2","np":2,"mn":"ADBE Vector Group"}],"ip":0,"op":140,"st":0,"bm":0,"sr":1},{"ddd":0,"ind":31,"ty":4,"nm":"“图层 15”轮廓","ks":{"o":{"k":100},"r":{"k":0},"p":{"k":[371.5,221,0]},"a":{"k":[417.5,314,0]},"s":{"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[39,-7],[-39,-7],[-39,7],[39,7]],"c":true}},"nm":"路径 1","mn":"ADBE Vector Shape - Group"},{"ind":1,"ty":"sh","ks":{"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[36,4],[-36,4],[-36,-4],[36,-4]],"c":true}},"nm":"路径 2","mn":"ADBE Vector Shape - Group"},{"ty":"mm","mm":1,"nm":"合并路径 1","mn":"ADBE Vector Filter - Merge"},{"ty":"fl","fillEnabled":true,"c":{"k":[0.42,0.42,0.42,1]},"o":{"k":100},"nm":"填充 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"k":[760,423],"ix":2},"a":{"k":[0,0],"ix":1},"s":{"k":[100,100],"ix":3},"r":{"k":0,"ix":6},"o":{"k":100,"ix":7},"sk":{"k":0,"ix":4},"sa":{"k":0,"ix":5},"nm":"变换"}],"nm":"组 1","np":4,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-37.5,-5.5],[37.5,-5.5],[37.5,5.5],[-37.5,5.5]],"c":true}},"nm":"路径 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","fillEnabled":true,"c":{"k":[0.89,0.89,0.89,1]},"o":{"k":100},"nm":"填充 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"k":[760,423],"ix":2},"a":{"k":[0,0],"ix":1},"s":{"k":[100,100],"ix":3},"r":{"k":0,"ix":6},"o":{"k":100,"ix":7},"sk":{"k":0,"ix":4},"sa":{"k":0,"ix":5},"nm":"变换"}],"nm":"组 2","np":2,"mn":"ADBE Vector Group"}],"ip":0,"op":140,"st":0,"bm":0,"sr":1},{"ddd":0,"ind":32,"ty":4,"nm":"“图层 16”轮廓","ks":{"o":{"k":100},"r":{"k":0},"p":{"k":[371.5,221,0]},"a":{"k":[417.5,314,0]},"s":{"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[26,-12.5],[-26,-12.5],[-26,12.5],[26,12.5]],"c":true}},"nm":"路径 1","mn":"ADBE Vector Shape - Group"},{"ind":1,"ty":"sh","ks":{"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[23,9.5],[-23,9.5],[-23,-9.5],[23,-9.5]],"c":true}},"nm":"路径 2","mn":"ADBE Vector Shape - Group"},{"ty":"mm","mm":1,"nm":"合并路径 1","mn":"ADBE Vector Filter - Merge"},{"ty":"fl","fillEnabled":true,"c":{"k":[0.42,0.42,0.42,1]},"o":{"k":100},"nm":"填充 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"k":[760,406.5],"ix":2},"a":{"k":[0,0],"ix":1},"s":{"k":[100,100],"ix":3},"r":{"k":0,"ix":6},"o":{"k":100,"ix":7},"sk":{"k":0,"ix":4},"sa":{"k":0,"ix":5},"nm":"变换"}],"nm":"组 1","np":4,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-24.5,-11],[24.5,-11],[24.5,11],[-24.5,11]],"c":true}},"nm":"路径 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","fillEnabled":true,"c":{"k":[0.89,0.89,0.89,1]},"o":{"k":100},"nm":"填充 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"k":[760,406.5],"ix":2},"a":{"k":[0,0],"ix":1},"s":{"k":[100,100],"ix":3},"r":{"k":0,"ix":6},"o":{"k":100,"ix":7},"sk":{"k":0,"ix":4},"sa":{"k":0,"ix":5},"nm":"变换"}],"nm":"组 2","np":2,"mn":"ADBE Vector Group"}],"ip":0,"op":140,"st":0,"bm":0,"sr":1},{"ddd":0,"ind":33,"ty":4,"nm":"“图层 17”轮廓","ks":{"o":{"k":100},"r":{"k":0},"p":{"k":[371.5,221,0]},"a":{"k":[417.5,314,0]},"s":{"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-112.625,6.125],[-93.375,-6.125],[-68.375,5.875],[-48.375,-6.125],[-22.375,5.875],[0.625,-6.125],[23.625,5.875],[46.625,-6.125],[67.625,5.875],[90.625,-6.125],[112.625,5.875]],"c":false}},"nm":"路径 1","mn":"ADBE Vector Shape - Group"},{"ty":"st","fillEnabled":true,"c":{"k":[0.6,0.6,0.6,1]},"o":{"k":100},"w":{"k":2},"lc":1,"lj":1,"ml":10,"nm":"描边 1","mn":"ADBE Vector Graphic - Stroke"},{"ty":"tr","p":{"k":[722.875,236.375],"ix":2},"a":{"k":[0,0],"ix":1},"s":{"k":[100,100],"ix":3},"r":{"k":0,"ix":6},"o":{"k":100,"ix":7},"sk":{"k":0,"ix":4},"sa":{"k":0,"ix":5},"nm":"变换"}],"nm":"组 1","np":2,"mn":"ADBE Vector Group"}],"ip":0,"op":140,"st":0,"bm":0,"sr":1},{"ddd":0,"ind":34,"ty":4,"nm":"新沟子","ks":{"o":{"k":100},"r":{"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":18,"s":[0],"e":[-14]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":25,"s":[-14],"e":[9]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":30,"s":[9],"e":[-14]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":35,"s":[-14],"e":[4]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":39,"s":[4],"e":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":42,"s":[0],"e":[-99]},{"t":44}]},"p":{"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":1,"y":0.012},"n":"0p833_0p833_1_0p012","t":0,"s":[537.938,182.156,0],"e":[539.219,249.156,0],"to":[0.21354167163372,11.1666669845581,0],"ti":[-4.70428718202243e-9,-11.2008962631226,0]},{"i":{"x":1,"y":1},"o":{"x":0.167,"y":0},"n":"1_1_0p167_0","t":20,"s":[539.219,249.156,0],"e":[542.875,249.156,0],"to":[1.74996683810491e-11,0.04166666790843,0],"ti":[-0.875,0,0]},{"i":{"x":1,"y":1},"o":{"x":0.167,"y":0},"n":"1_1_0p167_0","t":25,"s":[542.875,249.156,0],"e":[535.188,249.656,0],"to":[0.875,0,0],"ti":[0,0,0]},{"i":{"x":1,"y":1},"o":{"x":0.167,"y":0},"n":"1_1_0p167_0","t":30,"s":[535.188,249.656,0],"e":[539.812,249.281,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":1,"y":1},"o":{"x":0.167,"y":0},"n":"1_1_0p167_0","t":35,"s":[539.812,249.281,0],"e":[536.812,249.281,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":1,"y":1},"o":{"x":0.167,"y":0},"n":"1_1_0p167_0","t":39,"s":[536.812,249.281,0],"e":[538.062,249.531,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":1,"y":1},"o":{"x":0.167,"y":0},"n":"1_1_0p167_0","t":42,"s":[538.062,249.531,0],"e":[538.125,250.875,0],"to":[0,0,0],"ti":[0,0,0]},{"t":44}]},"a":{"k":[0.031,-10.938,0]},"s":{"k":[100,100,100]}},"ao":0,"shapes":[{"ind":0,"ty":"sh","ks":{"k":{"i":[[6.075,0],[0.506,5.606],[0,0],[-4.632,0],[0,4.971],[4.971,0],[0,0],[0,-6.075]],"o":[[-5.737,0],[0,0],[0.498,4.499],[4.971,0],[0,-4.971],[0,0],[6.075,0],[0,6.075]],"v":[[-0.025,11],[-10.975,1],[-8.967,1],[-0.025,9],[8.975,0],[-0.025,-9],[-0.025,-11],[10.975,0]],"c":true}},"nm":"路径 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","fillEnabled":true,"c":{"k":[0.42,0.42,0.42,1]},"o":{"k":100},"nm":"填充 1","mn":"ADBE Vector Graphic - Fill"}],"ip":0,"op":140,"st":0,"bm":0,"sr":1},{"ddd":0,"ind":36,"ty":4,"nm":"绳子","ks":{"o":{"k":100},"r":{"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":18,"s":[0],"e":[-3]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":25,"s":[-3],"e":[2]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":30,"s":[2],"e":[-1]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":35,"s":[-1],"e":[1]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":39,"s":[1],"e":[0]},{"t":42}]},"p":{"k":[539.125,161.063,0]},"a":{"k":[585.125,253.698,0]},"s":{"k":[{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.363,1,0.333],"y":[0.363,0.011,0.333]},"n":["0p833_0p833_0p363_0p363","0p833_0p833_1_0p011","0p833_0p833_0p333_0p333"],"t":0,"s":[100,24,100],"e":[100,96,100]},{"t":20}]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[1,-46.5],[-1,-46.5],[-1,46.5],[1,46.5]],"c":true}},"nm":"路径 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","fillEnabled":true,"c":{"k":[0.42,0.42,0.42,1]},"o":{"k":100},"nm":"填充 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"k":[585,300.5],"ix":2},"a":{"k":[0,0],"ix":1},"s":{"k":[100,100],"ix":3},"r":{"k":0,"ix":6},"o":{"k":100,"ix":7},"sk":{"k":0,"ix":4},"sa":{"k":0,"ix":5},"nm":"变换"}],"nm":"组 1","np":2,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[1,46.5],[-1,46.5],[-1,-46.5],[1,-46.5]],"c":true}},"nm":"路径 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","fillEnabled":true,"c":{"k":[0.88,0.88,0.88,1]},"o":{"k":100},"nm":"填充 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"k":[585,300.5],"ix":2},"a":{"k":[0,0],"ix":1},"s":{"k":[100,100],"ix":3},"r":{"k":0,"ix":6},"o":{"k":100,"ix":7},"sk":{"k":0,"ix":4},"sa":{"k":0,"ix":5},"nm":"变换"}],"nm":"组 2","np":2,"mn":"ADBE Vector Group"}],"ip":0,"op":140,"st":0,"bm":0,"sr":1},{"ddd":0,"ind":37,"ty":4,"nm":"“图层 22”轮廓","ks":{"o":{"k":100},"r":{"k":0},"p":{"k":[371.5,221,0]},"a":{"k":[417.5,314,0]},"s":{"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-112.625,-6.125],[-93.375,6.125],[-68.375,-5.875],[-48.375,6.125],[-22.375,-5.875],[0.625,6.125],[23.625,-5.875],[46.625,6.125],[67.625,-5.875],[90.625,6.125],[112.625,-5.875]],"c":false}},"nm":"路径 1","mn":"ADBE Vector Shape - Group"},{"ty":"st","fillEnabled":true,"c":{"k":[0.6,0.6,0.6,1]},"o":{"k":100},"w":{"k":2},"lc":1,"lj":1,"ml":10,"nm":"描边 1","mn":"ADBE Vector Graphic - Stroke"},{"ty":"tr","p":{"k":[722.875,236.375],"ix":2},"a":{"k":[0,0],"ix":1},"s":{"k":[100,100],"ix":3},"r":{"k":0,"ix":6},"o":{"k":100,"ix":7},"sk":{"k":0,"ix":4},"sa":{"k":0,"ix":5},"nm":"变换"}],"nm":"组 1","np":2,"mn":"ADBE Vector Group"}],"ip":0,"op":140,"st":0,"bm":0,"sr":1},{"ddd":0,"ind":38,"ty":4,"nm":"“图层 23”轮廓","ks":{"o":{"k":100},"r":{"k":0},"p":{"k":[371.5,221,0]},"a":{"k":[417.5,314,0]},"s":{"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[25,-12.5],[-25,-12.5],[-25,12.5],[25,12.5]],"c":true}},"nm":"路径 1","mn":"ADBE Vector Shape - Group"},{"ind":1,"ty":"sh","ks":{"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[22,9.5],[-22,9.5],[-22,-9.5],[22,-9.5]],"c":true}},"nm":"路径 2","mn":"ADBE Vector Shape - Group"},{"ty":"mm","mm":1,"nm":"合并路径 1","mn":"ADBE Vector Filter - Merge"},{"ty":"fl","fillEnabled":true,"c":{"k":[0.42,0.42,0.42,1]},"o":{"k":100},"nm":"填充 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"k":[585,236.5],"ix":2},"a":{"k":[0,0],"ix":1},"s":{"k":[100,100],"ix":3},"r":{"k":0,"ix":6},"o":{"k":100,"ix":7},"sk":{"k":0,"ix":4},"sa":{"k":0,"ix":5},"nm":"变换"}],"nm":"组 1","np":4,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-23.5,-11],[23.5,-11],[23.5,11],[-23.5,11]],"c":true}},"nm":"路径 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","fillEnabled":true,"c":{"k":[0.88,0.88,0.88,1]},"o":{"k":100},"nm":"填充 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"k":[585,236.5],"ix":2},"a":{"k":[0,0],"ix":1},"s":{"k":[100,100],"ix":3},"r":{"k":0,"ix":6},"o":{"k":100,"ix":7},"sk":{"k":0,"ix":4},"sa":{"k":0,"ix":5},"nm":"变换"}],"nm":"组 2","np":2,"mn":"ADBE Vector Group"}],"ip":0,"op":140,"st":0,"bm":0,"sr":1},{"ddd":0,"ind":39,"ty":4,"nm":"“图层 24”轮廓","ks":{"o":{"k":100},"r":{"k":0},"p":{"k":[371.5,221,0]},"a":{"k":[417.5,314,0]},"s":{"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[8,-10],[-8,-10],[-8,10],[8,10]],"c":true}},"nm":"路径 1","mn":"ADBE Vector Shape - Group"},{"ind":1,"ty":"sh","ks":{"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[5,7],[-5,7],[-5,-7],[5,-7]],"c":true}},"nm":"路径 2","mn":"ADBE Vector Shape - Group"},{"ty":"mm","mm":1,"nm":"合并路径 1","mn":"ADBE Vector Filter - Merge"},{"ty":"fl","fillEnabled":true,"c":{"k":[0.42,0.42,0.42,1]},"o":{"k":100},"nm":"填充 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"k":[585,244],"ix":2},"a":{"k":[0,0],"ix":1},"s":{"k":[100,100],"ix":3},"r":{"k":0,"ix":6},"o":{"k":100,"ix":7},"sk":{"k":0,"ix":4},"sa":{"k":0,"ix":5},"nm":"变换"}],"nm":"组 1","np":4,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-6.5,-8.5],[6.5,-8.5],[6.5,8.5],[-6.5,8.5]],"c":true}},"nm":"路径 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","fillEnabled":true,"c":{"k":[0.88,0.88,0.88,1]},"o":{"k":100},"nm":"填充 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"k":[585,244],"ix":2},"a":{"k":[0,0],"ix":1},"s":{"k":[100,100],"ix":3},"r":{"k":0,"ix":6},"o":{"k":100,"ix":7},"sk":{"k":0,"ix":4},"sa":{"k":0,"ix":5},"nm":"变换"}],"nm":"组 2","np":2,"mn":"ADBE Vector Group"}],"ip":0,"op":140,"st":0,"bm":0,"sr":1},{"ddd":0,"ind":40,"ty":4,"nm":"云","ks":{"o":{"k":40},"r":{"k":0},"p":{"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":0,"s":[641,59,0],"e":[661,59,0],"to":[3.33333325386047,0,0],"ti":[-3.33333325386047,0,0]},{"t":75}]},"a":{"k":[685.5,156,0]},"s":{"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"k":{"i":[[6.84,-0.76],[4.18,0],[1.131,-2.51],[-0.76,-4.18],[-8.395,0],[-0.734,4.771]],"o":[[-1.258,-2.122],[-2.932,0],[-4.56,0],[0.864,4.749],[8.395,0],[0.76,-4.94]],"v":[[5.32,-4.94],[-1.14,-9.5],[-7.6,-4.18],[-15.2,2.28],[0,9.5],[15.2,2.28]],"c":true}},"nm":"路径 1","mn":"ADBE Vector Shape - Group"},{"ty":"st","fillEnabled":true,"c":{"k":[0.37,0.37,0.37,1]},"o":{"k":100},"w":{"k":2},"lc":1,"lj":1,"ml":10,"nm":"描边 1","mn":"ADBE Vector Graphic - Stroke"},{"ty":"fl","fillEnabled":true,"c":{"k":[1,1,1,1]},"o":{"k":100},"nm":"填充 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"k":[687.169,154.5],"ix":2},"a":{"k":[0,0],"ix":1},"s":{"k":[100,100],"ix":3},"r":{"k":0,"ix":6},"o":{"k":100,"ix":7},"sk":{"k":0,"ix":4},"sa":{"k":0,"ix":5},"nm":"变换"}],"nm":"组 1","np":3,"mn":"ADBE Vector Group"}],"ip":0,"op":140,"st":0,"bm":0,"sr":1},{"ddd":0,"ind":41,"ty":4,"nm":"云1","ks":{"o":{"k":53},"r":{"k":0},"p":{"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":0,"s":[190,160,0],"e":[220,160,0],"to":[5,0,0],"ti":[-5,0,0]},{"t":75}]},"a":{"k":[235.5,256,0]},"s":{"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ks":{"k":{"i":[[9,-1],[5.5,0],[1.488,-3.303],[-1,-5.5],[-11.046,0],[-0.966,6.277]],"o":[[-1.655,-2.792],[-3.858,0],[-6,0],[1.136,6.249],[11.046,0],[1,-6.5]],"v":[[7,-6.5],[-1.5,-12.5],[-10,-5.5],[-20,3],[0,12.5],[20,3]],"c":true}},"nm":"路径 1","mn":"ADBE Vector Shape - Group"},{"ty":"st","fillEnabled":true,"c":{"k":[0.37,0.37,0.37,1]},"o":{"k":100},"w":{"k":2},"lc":1,"lj":1,"ml":10,"nm":"描边 1","mn":"ADBE Vector Graphic - Stroke"},{"ty":"fl","fillEnabled":true,"c":{"k":[1,1,1,1]},"o":{"k":100},"nm":"填充 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"k":[236,254.5],"ix":2},"a":{"k":[0,0],"ix":1},"s":{"k":[100,100],"ix":3},"r":{"k":0,"ix":6},"o":{"k":100,"ix":7},"sk":{"k":0,"ix":4},"sa":{"k":0,"ix":5},"nm":"变换"}],"nm":"组 1","np":3,"mn":"ADBE Vector Group"}],"ip":0,"op":140,"st":0,"bm":0,"sr":1},{"ddd":0,"ind":42,"ty":4,"nm":"楼房","ks":{"o":{"k":100},"r":{"k":0},"p":{"k":[393.5,187,0]},"a":{"k":[0,0,0]},"s":{"k":[100,100,100]}},"ao":0,"shapes":[{"ind":0,"ty":"sh","ks":{"k":{"i":[[0,0],[204.069,0],[0,6.628],[-0.654,0.292],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,6.628],[-204.069,0],[0,-0.297],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[369,156],[-0.5,169],[-370,156],[-369,155.116],[-369,137.068],[-369,108.67],[-358.869,108.67],[-358.869,103.937],[-344.473,103.937],[-344.473,108.67],[-341.274,108.67],[-341.274,110.248],[-336.475,110.248],[-336.475,100.781],[-333.276,100.781],[-333.276,97.626],[-318.88,97.626],[-318.88,100.781],[-317.281,100.781],[-317.281,50.296],[-315.681,50.296],[-315.681,45.563],[-301.285,45.563],[-301.285,50.296],[-293.287,50.296],[-293.287,78.694],[-283.69,78.694],[-283.69,28.209],[-278.891,28.209],[-278.891,20.32],[-269.294,20.32],[-269.294,10.854],[-254.897,10.854],[-254.897,28.209],[-245.3,28.209],[-245.3,92.893],[-234.103,92.893],[-234.103,39.252],[-226.105,39.252],[-226.105,18.743],[-205.311,18.743],[-205.311,39.252],[-200.512,39.252],[-200.512,-39.631],[-194.114,-39.631],[-194.114,-49.097],[-192.514,-49.097],[-192.514,-69.607],[-189.315,-69.607],[-189.315,-74.34],[-187.716,-74.34],[-187.716,-110.626],[-182.917,-110.626],[-182.917,-74.34],[-181.317,-74.34],[-181.317,-69.607],[-178.118,-69.607],[-178.118,-49.097],[-176.519,-49.097],[-176.519,-39.631],[-170.121,-39.631],[-170.121,50.296],[-165.322,50.296],[-165.322,-115.359],[-146.127,-115.359],[-146.127,-126.403],[-130.131,-131.136],[-130.131,-137.447],[-115.735,-142.18],[-112.536,-142.18],[-112.536,-115.359],[-109.337,-115.359],[-109.337,20.32],[-102.939,20.32],[-102.939,-61.718],[-86.943,-61.718],[-86.943,-72.762],[-80.545,-72.762],[-80.545,-71.184],[-74.147,-71.184],[-74.147,-69.607],[-66.149,-69.607],[-66.149,48.719],[-53.352,48.719],[-53.352,-39.631],[-43.755,-39.631],[-43.755,-69.607],[-38.956,-69.607],[-38.956,-105.893],[-32.558,-105.893],[-32.558,-116.937],[-22.96,-116.937],[-22.96,-169],[-18.162,-169],[-18.162,-116.937],[-8.564,-116.937],[-8.564,-105.893],[-2.166,-105.893],[-2.166,-69.607],[2.633,-69.607],[2.633,-39.631],[10.631,-39.631],[10.631,64.495],[18.628,64.495],[18.628,7.699],[26.626,7.699],[26.626,-15.966],[42.622,-15.966],[42.622,-42.786],[58.618,-42.786],[58.618,7.699],[79.412,7.699],[79.412,66.073],[85.81,66.073],[85.81,-56.985],[114.602,-64.874],[114.602,-79.073],[138.596,-72.762],[138.596,34.519],[146.594,34.519],[146.594,-58.563],[170.587,-79.073],[194.581,-58.563],[194.581,72.383],[204.178,72.383],[204.178,34.519],[216.975,-55.408],[228.172,34.519],[228.172,50.296],[231.371,50.296],[231.371,20.32],[239.369,20.32],[239.369,-0.189],[252.165,-0.189],[252.165,12.432],[261.763,12.432],[261.763,50.296],[264.962,50.296],[264.962,92.893],[274.559,92.893],[274.559,64.495],[279.358,64.495],[279.358,55.029],[296.953,55.029],[296.953,64.495],[301.752,64.495],[301.752,97.626],[304.951,97.626],[304.951,89.738],[306.55,89.738],[306.55,85.005],[312.949,85.005],[312.949,81.85],[324.146,81.85],[324.146,89.738],[328.945,89.738],[328.945,94.471],[341.741,94.471],[341.741,100.781],[348.139,100.781],[348.139,85.005],[370,85.005],[370,156]],"c":true}},"nm":"路径 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","fillEnabled":true,"c":{"k":[0.94,0.94,0.94,1]},"o":{"k":100},"nm":"填充 1","mn":"ADBE Vector Graphic - Fill"}],"ip":0,"op":140,"st":0,"bm":0,"sr":1}],"v":"4.5.3","ddd":0,"ip":0,"op":75,"fr":25,"w":816,"h":372} \ No newline at end of file diff --git a/assets/map_location.png b/assets/map_location.png new file mode 100644 index 0000000..5f60ce1 Binary files /dev/null and b/assets/map_location.png differ diff --git a/assets/modalDelete.png b/assets/modalDelete.png new file mode 100644 index 0000000..174a91e Binary files /dev/null and b/assets/modalDelete.png differ diff --git a/assets/no_internet.svg b/assets/no_internet.svg new file mode 100644 index 0000000..ecc232b --- /dev/null +++ b/assets/no_internet.svg @@ -0,0 +1,303 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/not_active_dot.svg b/assets/not_active_dot.svg new file mode 100644 index 0000000..2852eb8 --- /dev/null +++ b/assets/not_active_dot.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/onboard1.svg b/assets/onboard1.svg new file mode 100644 index 0000000..858ed9a --- /dev/null +++ b/assets/onboard1.svg @@ -0,0 +1,336 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/onboard2.svg b/assets/onboard2.svg new file mode 100644 index 0000000..c2019fd --- /dev/null +++ b/assets/onboard2.svg @@ -0,0 +1,263 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/onboard3.svg b/assets/onboard3.svg new file mode 100644 index 0000000..2b9d62b --- /dev/null +++ b/assets/onboard3.svg @@ -0,0 +1,206 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/person.png b/assets/person.png new file mode 100644 index 0000000..994792f Binary files /dev/null and b/assets/person.png differ diff --git a/assets/remove.svg b/assets/remove.svg new file mode 100644 index 0000000..804c299 --- /dev/null +++ b/assets/remove.svg @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/assets/search.png b/assets/search.png new file mode 100644 index 0000000..3ae3e2a Binary files /dev/null and b/assets/search.png differ diff --git a/assets/search.svg b/assets/search.svg new file mode 100644 index 0000000..d3e53a1 --- /dev/null +++ b/assets/search.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/trash.svg b/assets/trash.svg new file mode 100644 index 0000000..b87e699 --- /dev/null +++ b/assets/trash.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/assets/upload.svg b/assets/upload.svg new file mode 100644 index 0000000..0c0e6a5 --- /dev/null +++ b/assets/upload.svg @@ -0,0 +1,55 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ios/.gitignore b/ios/.gitignore new file mode 100644 index 0000000..e96ef60 --- /dev/null +++ b/ios/.gitignore @@ -0,0 +1,32 @@ +*.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/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/ios/Flutter/AppFrameworkInfo.plist b/ios/Flutter/AppFrameworkInfo.plist new file mode 100644 index 0000000..8d4492f --- /dev/null +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 9.0 + + diff --git a/ios/Flutter/Debug.xcconfig b/ios/Flutter/Debug.xcconfig new file mode 100644 index 0000000..ec97fc6 --- /dev/null +++ b/ios/Flutter/Debug.xcconfig @@ -0,0 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" +#include "Generated.xcconfig" diff --git a/ios/Flutter/Release.xcconfig b/ios/Flutter/Release.xcconfig new file mode 100644 index 0000000..c4855bf --- /dev/null +++ b/ios/Flutter/Release.xcconfig @@ -0,0 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" +#include "Generated.xcconfig" diff --git a/ios/Podfile b/ios/Podfile new file mode 100644 index 0000000..403e1f1 --- /dev/null +++ b/ios/Podfile @@ -0,0 +1,52 @@ +# Uncomment this line to define a global platform for your project +# platform :ios, '9.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! + use_modular_headers! + + flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) +end + +post_install do |installer| + installer.pods_project.targets.each do |target| + flutter_additional_ios_build_settings(target) + end + installer.pods_project.build_configurations.each do |config| + config.build_settings["EXCLUDED_ARCHS[sdk=iphonesimulator*]"] = "arm64" + end +end + +# add the Firebase pod for Google Analytics +pod 'Firebase/Analytics' +# or pod 'Firebase/AnalyticsWithoutAdIdSupport' +# for Analytics without IDFA collection capability + +# add pods for any other desired Firebase products +# https://firebase.google.com/docs/ios/setup#available-podsappDel \ No newline at end of file diff --git a/ios/Podfile.lock b/ios/Podfile.lock new file mode 100644 index 0000000..6d7f49f --- /dev/null +++ b/ios/Podfile.lock @@ -0,0 +1,267 @@ +PODS: + - Firebase/Analytics (8.9.0): + - Firebase/Core + - Firebase/Core (8.9.0): + - Firebase/CoreOnly + - FirebaseAnalytics (~> 8.9.0) + - Firebase/CoreOnly (8.9.0): + - FirebaseCore (= 8.9.0) + - Firebase/DynamicLinks (8.9.0): + - Firebase/CoreOnly + - FirebaseDynamicLinks (~> 8.9.0) + - firebase_core (1.10.6): + - Firebase/CoreOnly (= 8.9.0) + - Flutter + - firebase_dynamic_links (2.0.11): + - Firebase/DynamicLinks (= 8.9.0) + - firebase_core + - Flutter + - FirebaseAnalytics (8.9.1): + - FirebaseAnalytics/AdIdSupport (= 8.9.1) + - FirebaseCore (~> 8.0) + - FirebaseInstallations (~> 8.0) + - GoogleUtilities/AppDelegateSwizzler (~> 7.6) + - GoogleUtilities/MethodSwizzler (~> 7.6) + - GoogleUtilities/Network (~> 7.6) + - "GoogleUtilities/NSData+zlib (~> 7.6)" + - nanopb (~> 2.30908.0) + - FirebaseAnalytics/AdIdSupport (8.9.1): + - FirebaseCore (~> 8.0) + - FirebaseInstallations (~> 8.0) + - GoogleAppMeasurement (= 8.9.1) + - GoogleUtilities/AppDelegateSwizzler (~> 7.6) + - GoogleUtilities/MethodSwizzler (~> 7.6) + - GoogleUtilities/Network (~> 7.6) + - "GoogleUtilities/NSData+zlib (~> 7.6)" + - nanopb (~> 2.30908.0) + - FirebaseCore (8.9.0): + - FirebaseCoreDiagnostics (~> 8.0) + - GoogleUtilities/Environment (~> 7.6) + - GoogleUtilities/Logger (~> 7.6) + - FirebaseCoreDiagnostics (8.10.0): + - GoogleDataTransport (~> 9.1) + - GoogleUtilities/Environment (~> 7.6) + - GoogleUtilities/Logger (~> 7.6) + - nanopb (~> 2.30908.0) + - FirebaseDynamicLinks (8.9.0): + - FirebaseCore (~> 8.0) + - FirebaseInstallations (8.10.0): + - FirebaseCore (~> 8.0) + - GoogleUtilities/Environment (~> 7.6) + - GoogleUtilities/UserDefaults (~> 7.6) + - PromisesObjC (< 3.0, >= 1.2) + - Flutter (1.0.0) + - flutter_fimber (0.0.1): + - Flutter + - flutter_inappwebview (0.0.1): + - Flutter + - flutter_inappwebview/Core (= 0.0.1) + - OrderedSet (~> 5.0) + - flutter_inappwebview/Core (0.0.1): + - Flutter + - OrderedSet (~> 5.0) + - flutter_smartlook (0.0.5): + - Flutter + - FMDB (2.7.5): + - FMDB/standard (= 2.7.5) + - FMDB/standard (2.7.5) + - geocoding (1.0.5): + - Flutter + - geolocator_apple (1.2.0): + - Flutter + - GoogleAppMeasurement (8.9.1): + - GoogleAppMeasurement/AdIdSupport (= 8.9.1) + - GoogleUtilities/AppDelegateSwizzler (~> 7.6) + - GoogleUtilities/MethodSwizzler (~> 7.6) + - GoogleUtilities/Network (~> 7.6) + - "GoogleUtilities/NSData+zlib (~> 7.6)" + - nanopb (~> 2.30908.0) + - GoogleAppMeasurement/AdIdSupport (8.9.1): + - GoogleAppMeasurement/WithoutAdIdSupport (= 8.9.1) + - GoogleUtilities/AppDelegateSwizzler (~> 7.6) + - GoogleUtilities/MethodSwizzler (~> 7.6) + - GoogleUtilities/Network (~> 7.6) + - "GoogleUtilities/NSData+zlib (~> 7.6)" + - nanopb (~> 2.30908.0) + - GoogleAppMeasurement/WithoutAdIdSupport (8.9.1): + - GoogleUtilities/AppDelegateSwizzler (~> 7.6) + - GoogleUtilities/MethodSwizzler (~> 7.6) + - GoogleUtilities/Network (~> 7.6) + - "GoogleUtilities/NSData+zlib (~> 7.6)" + - nanopb (~> 2.30908.0) + - GoogleDataTransport (9.1.2): + - GoogleUtilities/Environment (~> 7.2) + - nanopb (~> 2.30908.0) + - PromisesObjC (< 3.0, >= 1.2) + - GoogleUtilities/AppDelegateSwizzler (7.6.0): + - GoogleUtilities/Environment + - GoogleUtilities/Logger + - GoogleUtilities/Network + - GoogleUtilities/Environment (7.6.0): + - PromisesObjC (< 3.0, >= 1.2) + - GoogleUtilities/Logger (7.6.0): + - GoogleUtilities/Environment + - GoogleUtilities/MethodSwizzler (7.6.0): + - GoogleUtilities/Logger + - GoogleUtilities/Network (7.6.0): + - GoogleUtilities/Logger + - "GoogleUtilities/NSData+zlib" + - GoogleUtilities/Reachability + - "GoogleUtilities/NSData+zlib (7.6.0)" + - GoogleUtilities/Reachability (7.6.0): + - GoogleUtilities/Logger + - GoogleUtilities/UserDefaults (7.6.0): + - GoogleUtilities/Logger + - image_picker (0.0.1): + - Flutter + - location (0.0.1): + - Flutter + - Mapbox-iOS-SDK (6.4.1): + - MapboxMobileEvents (~> 0.10.12) + - mapbox_gl (0.0.1): + - Flutter + - Mapbox-iOS-SDK (~> 6.4.0) + - MapboxAnnotationExtension (~> 0.0.1-beta.1) + - MapboxAnnotationExtension (0.0.1-beta.2): + - Mapbox-iOS-SDK (~> 6.0) + - MapboxMobileEvents (0.10.13) + - nanopb (2.30908.0): + - nanopb/decode (= 2.30908.0) + - nanopb/encode (= 2.30908.0) + - nanopb/decode (2.30908.0) + - nanopb/encode (2.30908.0) + - open_mail_app (0.0.1): + - Flutter + - OrderedSet (5.0.0) + - path_provider_ios (0.0.1): + - Flutter + - PromisesObjC (2.0.0) + - share (0.0.1): + - Flutter + - shared_preferences_ios (0.0.1): + - Flutter + - sqflite (0.0.2): + - Flutter + - FMDB (>= 2.7.5) + - url_launcher_ios (0.0.1): + - Flutter + - webview_flutter_wkwebview (0.0.1): + - Flutter + +DEPENDENCIES: + - Firebase/Analytics + - firebase_core (from `.symlinks/plugins/firebase_core/ios`) + - firebase_dynamic_links (from `.symlinks/plugins/firebase_dynamic_links/ios`) + - Flutter (from `Flutter`) + - flutter_fimber (from `.symlinks/plugins/flutter_fimber/ios`) + - flutter_inappwebview (from `.symlinks/plugins/flutter_inappwebview/ios`) + - flutter_smartlook (from `.symlinks/plugins/flutter_smartlook/ios`) + - geocoding (from `.symlinks/plugins/geocoding/ios`) + - geolocator_apple (from `.symlinks/plugins/geolocator_apple/ios`) + - image_picker (from `.symlinks/plugins/image_picker/ios`) + - location (from `.symlinks/plugins/location/ios`) + - mapbox_gl (from `.symlinks/plugins/mapbox_gl/ios`) + - open_mail_app (from `.symlinks/plugins/open_mail_app/ios`) + - path_provider_ios (from `.symlinks/plugins/path_provider_ios/ios`) + - share (from `.symlinks/plugins/share/ios`) + - shared_preferences_ios (from `.symlinks/plugins/shared_preferences_ios/ios`) + - sqflite (from `.symlinks/plugins/sqflite/ios`) + - url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`) + - webview_flutter_wkwebview (from `.symlinks/plugins/webview_flutter_wkwebview/ios`) + +SPEC REPOS: + trunk: + - Firebase + - FirebaseAnalytics + - FirebaseCore + - FirebaseCoreDiagnostics + - FirebaseDynamicLinks + - FirebaseInstallations + - FMDB + - GoogleAppMeasurement + - GoogleDataTransport + - GoogleUtilities + - Mapbox-iOS-SDK + - MapboxAnnotationExtension + - MapboxMobileEvents + - nanopb + - OrderedSet + - PromisesObjC + +EXTERNAL SOURCES: + firebase_core: + :path: ".symlinks/plugins/firebase_core/ios" + firebase_dynamic_links: + :path: ".symlinks/plugins/firebase_dynamic_links/ios" + Flutter: + :path: Flutter + flutter_fimber: + :path: ".symlinks/plugins/flutter_fimber/ios" + flutter_inappwebview: + :path: ".symlinks/plugins/flutter_inappwebview/ios" + flutter_smartlook: + :path: ".symlinks/plugins/flutter_smartlook/ios" + geocoding: + :path: ".symlinks/plugins/geocoding/ios" + geolocator_apple: + :path: ".symlinks/plugins/geolocator_apple/ios" + image_picker: + :path: ".symlinks/plugins/image_picker/ios" + location: + :path: ".symlinks/plugins/location/ios" + mapbox_gl: + :path: ".symlinks/plugins/mapbox_gl/ios" + open_mail_app: + :path: ".symlinks/plugins/open_mail_app/ios" + path_provider_ios: + :path: ".symlinks/plugins/path_provider_ios/ios" + share: + :path: ".symlinks/plugins/share/ios" + shared_preferences_ios: + :path: ".symlinks/plugins/shared_preferences_ios/ios" + sqflite: + :path: ".symlinks/plugins/sqflite/ios" + url_launcher_ios: + :path: ".symlinks/plugins/url_launcher_ios/ios" + webview_flutter_wkwebview: + :path: ".symlinks/plugins/webview_flutter_wkwebview/ios" + +SPEC CHECKSUMS: + Firebase: 13d8d96499e2635428d5bf0ec675df21f95d9a95 + firebase_core: c263d7daf1dc92fcd9895e6abdc04872b0ee07ff + firebase_dynamic_links: 16a1987f9099cc9b283f654f7dad72d1b5209dde + FirebaseAnalytics: 4ab446ce08a3fe52e8a4303dd997cf26276bf968 + FirebaseCore: 599ee609343eaf4941bd188f85e3aa077ffe325b + FirebaseCoreDiagnostics: 56fb7216d87e0e6ec2feddefa9d8a392fe8b2c18 + FirebaseDynamicLinks: 50980cbe21d2bbe8374afcdccd94dc2db20dffca + FirebaseInstallations: 830327b45345ffc859eaa9c17bcd5ae893fd5425 + Flutter: 50d75fe2f02b26cc09d224853bb45737f8b3214a + flutter_fimber: 4a6b342666fecb329fca23143f4b72c46cdd8022 + flutter_inappwebview: bfd58618f49dc62f2676de690fc6dcda1d6c3721 + flutter_smartlook: 2aa304f6a38fc22b741ca750e0078606582525ae + FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a + geocoding: 32cfcdb16d38d907caaba65e2e42ad10d38bee58 + geolocator_apple: b741765c55dc21950e3e106e8b3584e55cf81ce5 + GoogleAppMeasurement: 837649ad3987936c232f6717c5680216f6243d24 + GoogleDataTransport: 629c20a4d363167143f30ea78320d5a7eb8bd940 + GoogleUtilities: 684ee790a24f73ebb2d1d966e9711c203f2a4237 + image_picker: 9aa50e1d8cdacdbed739e925b7eea16d014367e6 + location: 3a2eed4dd2fab25e7b7baf2a9efefe82b512d740 + Mapbox-iOS-SDK: f870f83cbdc7aa4a74afcee143aafb0dae390c82 + mapbox_gl: 33c5ab6306cbfa72289bb3606d2cd2e8baee9ff0 + MapboxAnnotationExtension: 4eee6c26349ef6d909f1a23a7eae2d0f7ca5fa7d + MapboxMobileEvents: e78db24b348f48e41e5895be7dc16e5b1bb43562 + nanopb: a0ba3315591a9ae0a16a309ee504766e90db0c96 + open_mail_app: 794172f6a22cd16319d3ddaf45e945b2f74952b0 + OrderedSet: aaeb196f7fef5a9edf55d89760da9176ad40b93c + path_provider_ios: 7d7ce634493af4477d156294792024ec3485acd5 + PromisesObjC: 68159ce6952d93e17b2dfe273b8c40907db5ba58 + share: 0b2c3e82132f5888bccca3351c504d0003b3b410 + shared_preferences_ios: aef470a42dc4675a1cdd50e3158b42e3d1232b32 + sqflite: 6d358c025f5b867b29ed92fc697fd34924e11904 + url_launcher_ios: 02f1989d4e14e998335b02b67a7590fa34f971af + webview_flutter_wkwebview: 005fbd90c888a42c5690919a1527ecc6649e1162 + +PODFILE CHECKSUM: 19e9e4fe539f84f372df394c1ac7782d5be37878 + +COCOAPODS: 1.11.2 diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj new file mode 100644 index 0000000..42aa519 --- /dev/null +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,585 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 51; + objects = { + +/* Begin PBXBuildFile section */ + 12102D50D39C34BD6A0A443B /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 66F3D99CFABF55D45D0DE940 /* Pods_Runner.framework */; }; + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; + 223905DE277247B50045F36C /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 223905DD277247B50045F36C /* GoogleService-Info.plist */; }; + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; + 404BC0ED277363B0002DE2DB /* AssetsLibrary.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 404BC0EC277363B0002DE2DB /* AssetsLibrary.framework */; }; + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; + 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 */; }; +/* End PBXBuildFile 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 */ + 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 = ""; }; + 19EA49D04E342002E8657FD4 /* 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 = ""; }; + 223905DD277247B50045F36C /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = ""; }; + 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; + 40456C5926B1BBD50070B4B7 /* Runner.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Runner.entitlements; sourceTree = ""; }; + 404BC0EC277363B0002DE2DB /* AssetsLibrary.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AssetsLibrary.framework; path = System/Library/Frameworks/AssetsLibrary.framework; sourceTree = SDKROOT; }; + 66F3D99CFABF55D45D0DE940 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 679E25D302417D89E64B7F00 /* 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 = ""; }; + 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 = ""; }; + 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 = ""; }; + 9E1F442C6C95DF38EACC9CC9 /* 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 = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 97C146EB1CF9000F007C117D /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 12102D50D39C34BD6A0A443B /* Pods_Runner.framework in Frameworks */, + 404BC0ED277363B0002DE2DB /* AssetsLibrary.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 427DE5F12306C9EAD6C3F879 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 404BC0EC277363B0002DE2DB /* AssetsLibrary.framework */, + 66F3D99CFABF55D45D0DE940 /* Pods_Runner.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 */, + B69F2C02E0F215F0D9FB506C /* Pods */, + 427DE5F12306C9EAD6C3F879 /* Frameworks */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 223905DD277247B50045F36C /* GoogleService-Info.plist */, + 40456C5926B1BBD50070B4B7 /* Runner.entitlements */, + 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 = ""; + }; + B69F2C02E0F215F0D9FB506C /* Pods */ = { + isa = PBXGroup; + children = ( + 679E25D302417D89E64B7F00 /* Pods-Runner.debug.xcconfig */, + 9E1F442C6C95DF38EACC9CC9 /* Pods-Runner.release.xcconfig */, + 19EA49D04E342002E8657FD4 /* Pods-Runner.profile.xcconfig */, + ); + path = Pods; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 97C146ED1CF9000F007C117D /* Runner */ = { + isa = PBXNativeTarget; + buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; + buildPhases = ( + A01C5BB8C843519C63952872 /* [CP] Check Pods Manifest.lock */, + 9740EEB61CF901F6004384FC /* Run Script */, + 97C146EA1CF9000F007C117D /* Sources */, + 97C146EB1CF9000F007C117D /* Frameworks */, + 97C146EC1CF9000F007C117D /* Resources */, + 9705A1C41CF9048500538489 /* Embed Frameworks */, + 3B06AD1E1E4923F5004D2608 /* Thin Binary */, + 49C2F3733557B33F523D5012 /* [CP] Embed Pods Frameworks */, + ); + 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 = { + LastUpgradeCheck = 1300; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 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 */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 223905DE277247B50045F36C /* GoogleService-Info.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 49C2F3733557B33F523D5012 /* [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; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + 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\n"; + }; + A01C5BB8C843519C63952872 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 12; + 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; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase 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_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"; + CODE_SIGN_STYLE = Automatic; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + EXCLUDED_ARCHS = ""; + "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64; + 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 = 10.0; + MTL_ENABLE_DEBUG_INFO = NO; + PROVISIONING_PROFILE_SPECIFIER = ""; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + VALIDATE_WORKSPACE = YES; + }; + name = Profile; + }; + 249021D4217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; + CURRENT_PROJECT_VERSION = 37; + DEVELOPMENT_TEAM = WU2RCT52GH; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + MARKETING_VERSION = 0.0.3; + ONLY_ACTIVE_ARCH = YES; + PRODUCT_BUNDLE_IDENTIFIER = ax.synt.giraffeSpotter; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + 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_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"; + CODE_SIGN_STYLE = Automatic; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + EXCLUDED_ARCHS = ""; + "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64; + 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 = 10.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + "OTHER_CODE_SIGN_FLAGS[sdk=*]" = ""; + PROVISIONING_PROFILE_SPECIFIER = ""; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_WORKSPACE = YES; + }; + 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_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"; + CODE_SIGN_STYLE = Automatic; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + EXCLUDED_ARCHS = ""; + "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64; + 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 = 10.0; + MTL_ENABLE_DEBUG_INFO = NO; + PROVISIONING_PROFILE_SPECIFIER = ""; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + VALIDATE_WORKSPACE = YES; + }; + name = Release; + }; + 97C147061CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; + CURRENT_PROJECT_VERSION = 37; + DEVELOPMENT_TEAM = WU2RCT52GH; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + MARKETING_VERSION = 0.0.3; + PRODUCT_BUNDLE_IDENTIFIER = ax.synt.giraffeSpotter; + 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; + CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; + CURRENT_PROJECT_VERSION = 37; + DEVELOPMENT_TEAM = WU2RCT52GH; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + MARKETING_VERSION = 0.0.3; + ONLY_ACTIVE_ARCH = YES; + PRODUCT_BUNDLE_IDENTIFIER = ax.synt.giraffeSpotter; + 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 */ + 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/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..919434a --- /dev/null +++ b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 0000000..f9b0d7c --- /dev/null +++ b/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + diff --git a/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme new file mode 100644 index 0000000..3db53b6 --- /dev/null +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ios/Runner.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..21a3cc1 --- /dev/null +++ b/ios/Runner.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/ios/Runner/AppDelegate.swift b/ios/Runner/AppDelegate.swift new file mode 100644 index 0000000..bdb6206 --- /dev/null +++ b/ios/Runner/AppDelegate.swift @@ -0,0 +1,66 @@ +import UIKit +import Flutter +import CoreLocation + +@UIApplicationMain +@objc class AppDelegate: FlutterAppDelegate { + override func application( + _ application: UIApplication, + didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? + ) -> Bool { + let controller : FlutterViewController = window?.rootViewController as! FlutterViewController + let channel = FlutterMethodChannel(name: "ax.synt.giraffe_spotter/coordinates", binaryMessenger: controller.binaryMessenger) + channel.setMethodCallHandler({ + [weak self] (call: FlutterMethodCall, result: @escaping FlutterResult) -> Void in + guard call.method == "getCoordsFilePath" else { + result(FlutterMethodNotImplemented) + return + } + self?.getCoordsFilePath(result: result, call: call) + }) + + GeneratedPluginRegistrant.register(with: self) + return super.application(application, didFinishLaunchingWithOptions: launchOptions) + } + + private func getCoordsFilePath(result: FlutterResult, call: FlutterMethodCall) { + var latPoints: [Any] = Array() + var longPoints: [Any] = Array() + if let args = call.arguments as? Dictionary { + if let path = args["path"] as? String { + let cfUrl = URL(fileURLWithPath: path) as CFURL + if let imageSource = CGImageSourceCreateWithURL(cfUrl, nil) { + let imageProperties = CGImageSourceCopyPropertiesAtIndex(imageSource, 0, nil) + if let dict = imageProperties as? [NSString: AnyObject] { + + if let gps = dict[kCGImagePropertyGPSDictionary] as? [NSString: AnyObject] { + var lat: Float = 0.0 + if let latitude = gps[kCGImagePropertyGPSLatitude] as? NSNumber { + lat = Float(CLLocationDegrees(latitude.floatValue)) + } + + var long: Float = 0.0 + if let longitude = gps[kCGImagePropertyGPSLongitude] as? NSNumber { + long = Float(CLLocationDegrees(longitude.floatValue)) + } + + var latRef: String = "" + if let latitudeRef = gps[kCGImagePropertyGPSLatitudeRef] as? NSString { + latRef = latitudeRef as String + } + + var longRef: String = "" + if let longitudeRef = gps[kCGImagePropertyGPSLongitudeRef] as? NSString { + longRef = longitudeRef as String + } + latPoints = [lat, latRef] + longPoints = [long, longRef] + + } + } + } + } + } + result([latPoints, longPoints]) + } +} diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Background-1024.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Background-1024.png new file mode 100644 index 0000000..10f9289 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Background-1024.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Background-20.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Background-20.png new file mode 100644 index 0000000..cfb1601 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Background-20.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Background-20@2x-1.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Background-20@2x-1.png new file mode 100644 index 0000000..1545964 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Background-20@2x-1.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Background-20@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Background-20@2x.png new file mode 100644 index 0000000..1545964 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Background-20@2x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Background-20@3x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Background-20@3x.png new file mode 100644 index 0000000..e2b0c57 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Background-20@3x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Background-29.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Background-29.png new file mode 100644 index 0000000..91d0758 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Background-29.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Background-29@2x-1.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Background-29@2x-1.png new file mode 100644 index 0000000..f2e6c30 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Background-29@2x-1.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Background-29@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Background-29@2x.png new file mode 100644 index 0000000..f2e6c30 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Background-29@2x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Background-29@3x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Background-29@3x.png new file mode 100644 index 0000000..b7b6bdc Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Background-29@3x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Background-40.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Background-40.png new file mode 100644 index 0000000..1545964 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Background-40.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Background-40@2x-1.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Background-40@2x-1.png new file mode 100644 index 0000000..41c45e9 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Background-40@2x-1.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Background-40@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Background-40@2x.png new file mode 100644 index 0000000..41c45e9 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Background-40@2x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Background-40@3x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Background-40@3x.png new file mode 100644 index 0000000..f921fd0 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Background-40@3x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Background-60@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Background-60@2x.png new file mode 100644 index 0000000..f921fd0 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Background-60@2x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Background-60@3x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Background-60@3x.png new file mode 100644 index 0000000..5e804c2 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Background-60@3x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Background-76.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Background-76.png new file mode 100644 index 0000000..a8820bc Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Background-76.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Background-76@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Background-76@2x.png new file mode 100644 index 0000000..4f2fd4b Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Background-76@2x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Background-83.5@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Background-83.5@2x.png new file mode 100644 index 0000000..87a724f Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Background-83.5@2x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..385fef2 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,116 @@ +{ + "images" : [ + { + "filename" : "Background-20@2x-1.png", + "idiom" : "iphone", + "scale" : "2x", + "size" : "20x20" + }, + { + "filename" : "Background-20@3x.png", + "idiom" : "iphone", + "scale" : "3x", + "size" : "20x20" + }, + { + "filename" : "Background-29@2x-1.png", + "idiom" : "iphone", + "scale" : "2x", + "size" : "29x29" + }, + { + "filename" : "Background-29@3x.png", + "idiom" : "iphone", + "scale" : "3x", + "size" : "29x29" + }, + { + "filename" : "Background-40@2x-1.png", + "idiom" : "iphone", + "scale" : "2x", + "size" : "40x40" + }, + { + "filename" : "Background-40@3x.png", + "idiom" : "iphone", + "scale" : "3x", + "size" : "40x40" + }, + { + "filename" : "Background-60@2x.png", + "idiom" : "iphone", + "scale" : "2x", + "size" : "60x60" + }, + { + "filename" : "Background-60@3x.png", + "idiom" : "iphone", + "scale" : "3x", + "size" : "60x60" + }, + { + "filename" : "Background-20.png", + "idiom" : "ipad", + "scale" : "1x", + "size" : "20x20" + }, + { + "filename" : "Background-20@2x.png", + "idiom" : "ipad", + "scale" : "2x", + "size" : "20x20" + }, + { + "filename" : "Background-29.png", + "idiom" : "ipad", + "scale" : "1x", + "size" : "29x29" + }, + { + "filename" : "Background-29@2x.png", + "idiom" : "ipad", + "scale" : "2x", + "size" : "29x29" + }, + { + "filename" : "Background-40.png", + "idiom" : "ipad", + "scale" : "1x", + "size" : "40x40" + }, + { + "filename" : "Background-40@2x.png", + "idiom" : "ipad", + "scale" : "2x", + "size" : "40x40" + }, + { + "filename" : "Background-76.png", + "idiom" : "ipad", + "scale" : "1x", + "size" : "76x76" + }, + { + "filename" : "Background-76@2x.png", + "idiom" : "ipad", + "scale" : "2x", + "size" : "76x76" + }, + { + "filename" : "Background-83.5@2x.png", + "idiom" : "ipad", + "scale" : "2x", + "size" : "83.5x83.5" + }, + { + "filename" : "Background-1024.png", + "idiom" : "ios-marketing", + "scale" : "1x", + "size" : "1024x1024" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/ios/Runner/Assets.xcassets/Contents.json b/ios/Runner/Assets.xcassets/Contents.json new file mode 100644 index 0000000..73c0059 --- /dev/null +++ b/ios/Runner/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/ios/Runner/Assets.xcassets/LaunchBackground.imageset/Contents.json b/ios/Runner/Assets.xcassets/LaunchBackground.imageset/Contents.json new file mode 100644 index 0000000..9f447e1 --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchBackground.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "background.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/ios/Runner/Assets.xcassets/LaunchBackground.imageset/background.png b/ios/Runner/Assets.xcassets/LaunchBackground.imageset/background.png new file mode 100644 index 0000000..21b2005 Binary files /dev/null and b/ios/Runner/Assets.xcassets/LaunchBackground.imageset/background.png differ diff --git a/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json b/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json new file mode 100644 index 0000000..00cabce --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "LaunchImage.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "LaunchImage@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "LaunchImage@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png new file mode 100644 index 0000000..94f3260 Binary files /dev/null and b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png differ diff --git a/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png new file mode 100644 index 0000000..beec853 Binary files /dev/null and b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png differ diff --git a/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png new file mode 100644 index 0000000..2b15f09 Binary files /dev/null and b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png differ diff --git a/ios/Runner/Base.lproj/LaunchScreen.storyboard b/ios/Runner/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 0000000..a8ad007 --- /dev/null +++ b/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ios/Runner/Base.lproj/Main.storyboard b/ios/Runner/Base.lproj/Main.storyboard new file mode 100644 index 0000000..f3c2851 --- /dev/null +++ b/ios/Runner/Base.lproj/Main.storyboard @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ios/Runner/GoogleService-Info.plist b/ios/Runner/GoogleService-Info.plist new file mode 100644 index 0000000..016ff7f --- /dev/null +++ b/ios/Runner/GoogleService-Info.plist @@ -0,0 +1,36 @@ + + + + + CLIENT_ID + 568065724442-3v8e5kacef96e17r5i33itnputk9pbq4.apps.googleusercontent.com + REVERSED_CLIENT_ID + com.googleusercontent.apps.568065724442-3v8e5kacef96e17r5i33itnputk9pbq4 + ANDROID_CLIENT_ID + 568065724442-si5vk38ns434orsihe23r7b2qb1o27gd.apps.googleusercontent.com + API_KEY + AIzaSyBPv-Oot7iADbqvmYo0DMyhMu71VaoumqI + GCM_SENDER_ID + 568065724442 + PLIST_VERSION + 1 + BUNDLE_ID + ax.synt.giraffeSpotter + PROJECT_ID + giraffespotter-546fc + STORAGE_BUCKET + giraffespotter-546fc.appspot.com + IS_ADS_ENABLED + + IS_ANALYTICS_ENABLED + + IS_APPINVITE_ENABLED + + IS_GCM_ENABLED + + IS_SIGNIN_ENABLED + + GOOGLE_APP_ID + 1:568065724442:ios:124ac9910a5bbdfd1701a3 + + \ No newline at end of file diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist new file mode 100644 index 0000000..56cbc54 --- /dev/null +++ b/ios/Runner/Info.plist @@ -0,0 +1,95 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + Giraffe Spotter + CFBundlePackageType + APPL + CFBundleShortVersionString + $(MARKETING_VERSION) + CFBundleSignature + ???? + CFBundleURLTypes + + + CFBundleTypeRole + Editor + CFBundleURLName + Bundle ID + CFBundleURLSchemes + + $(PRODUCT_BUNDLE_IDENTIFIER) + + + + CFBundleVersion + $(CURRENT_PROJECT_VERSION) + LSApplicationQueriesSchemes + + googlegmail + x-dispatch + readdle-spark + airmail + ms-outlook + ymail + fastmail + superhuman + + LSRequiresIPhoneOS + + MGLMapboxAccessToken + pk.eyJ1Ijoic3ludGF4bHRkIiwiYSI6ImNqeWgxanp6dzAwcmozbXBlejA0anBhOXoifQ.44mOLJDLY-oL45oicaZtuw + NSAppTransportSecurity + + NSAllowsArbitraryLoads + + + NSCameraUsageDescription + Camera usage for profile pictures + NSLocationAlwaysAndWhenInUseUsageDescription + This app needs access to location when open and in the background. + NSLocationAlwaysUsageDescription + This app needs access to location when in the background. + NSLocationWhenInUseUsageDescription + This app needs access to location in the background. + NSMicrophoneUsageDescription + Microphone usage for profile pictures + NSPhotoLibraryUsageDescription + Giraffe Spotter + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UIRequiresFullScreen + + UIStatusBarHidden + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + UIInterfaceOrientationPortraitUpsideDown + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UIViewControllerBasedStatusBarAppearance + + io.flutter.embedded_views_preview + YES + + diff --git a/ios/Runner/Runner-Bridging-Header.h b/ios/Runner/Runner-Bridging-Header.h new file mode 100644 index 0000000..308a2a5 --- /dev/null +++ b/ios/Runner/Runner-Bridging-Header.h @@ -0,0 +1 @@ +#import "GeneratedPluginRegistrant.h" diff --git a/ios/Runner/Runner.entitlements b/ios/Runner/Runner.entitlements new file mode 100644 index 0000000..04ec2e8 --- /dev/null +++ b/ios/Runner/Runner.entitlements @@ -0,0 +1,12 @@ + + + + + aps-environment + development + com.apple.developer.associated-domains + + applinks:gspotter.page.link + + + diff --git a/lib/App.dart b/lib/App.dart new file mode 100644 index 0000000..f170ecd --- /dev/null +++ b/lib/App.dart @@ -0,0 +1,50 @@ +import 'dart:async'; + +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:flutter_smartlook/flutter_smartlook.dart'; +import 'package:giraffe_spotter/blocs/dynamic_links/DynamicCubit.dart'; +import 'package:giraffe_spotter/pages/AppView.dart'; + +import 'config/Constants.dart'; + +class App extends StatefulWidget { + @override + _AppState createState() => _AppState(); +} + +class _AppState extends State with WidgetsBindingObserver { + @override + void initState() { + super.initState(); + // smartLookView(); + WidgetsBinding.instance!.addObserver(this); + } + + @override + void didChangeAppLifecycleState(AppLifecycleState state) { + if (state == AppLifecycleState.resumed) { + Timer(Duration(milliseconds: 1000), () { + BlocProvider.of(context).initDynamicLinks(); + }); + } + } + + @override + void dispose() { + super.dispose(); + Smartlook.stopRecording(); + } + + @override + Widget build(BuildContext context) { + return AppView(); + } + + smartLookView() { + SetupOptions options = (new SetupOptionsBuilder(Constants.SmartLookKey)).build(); + Smartlook.setupAndStartRecording(options); + Smartlook.enableCrashlytics(true); + Smartlook.startRecording(); + } +} diff --git a/lib/blocs/authentication/AuthenticationBloc.dart b/lib/blocs/authentication/AuthenticationBloc.dart new file mode 100644 index 0000000..656c764 --- /dev/null +++ b/lib/blocs/authentication/AuthenticationBloc.dart @@ -0,0 +1,59 @@ +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:giraffe_spotter/models/User.dart'; +import 'package:giraffe_spotter/network/NetworkExceptions.dart'; +import 'package:giraffe_spotter/repositories/AuthenticationRepository.dart'; +import 'package:pedantic/pedantic.dart'; + +import 'AuthenticationEvent.dart'; +import 'AuthenticationState.dart'; + +class AuthenticationBloc extends Bloc { + AuthenticationBloc({required AuthenticationRepository authRepository}) + : _authenticationRepository = authRepository, + super(const AuthenticationState.unknown()); + + final AuthenticationRepository _authenticationRepository; + @override + Stream mapEventToState(AuthenticationEvent event) async* { + if (event is AuthenticationStarted) { + yield* _mapAuthenticationStartedToState(); + } + else if (event is AuthenticationUserChanged) { + yield* _mapAuthenticationUserChangedToState(event); + } + else if (event is AuthenticationLogoutRequested) { + unawaited(_authenticationRepository.logout()); + yield const AuthenticationState.unauthenticated(); + } + } + + Stream _mapAuthenticationStartedToState() async* { + final isSignedIn = _authenticationRepository.isSignedIn; + if (isSignedIn) { + final result = await _authenticationRepository.user; + yield* result.when(success: (User? user) async* { + add(AuthenticationUserChanged(user!)); + }, failure: (NetworkExceptions? error) async* { + yield* error!.maybeWhen( + unauthenticatedRequest: () async* { + yield const AuthenticationState.unauthenticated(); + }, + noInternetConnection: () async* { + yield const AuthenticationState.noInternet(); + }, + orElse: () async* { + }); + }); + } else { + yield const AuthenticationState.unauthenticated(); + } + } + + Stream _mapAuthenticationUserChangedToState(AuthenticationUserChanged event) async* { + if (event.user != User.empty) { + yield AuthenticationState.authenticated(event.user); + } else { + yield const AuthenticationState.unauthenticated(); + } + } +} diff --git a/lib/blocs/authentication/AuthenticationEvent.dart b/lib/blocs/authentication/AuthenticationEvent.dart new file mode 100644 index 0000000..f444076 --- /dev/null +++ b/lib/blocs/authentication/AuthenticationEvent.dart @@ -0,0 +1,29 @@ +import 'package:equatable/equatable.dart'; +import 'package:giraffe_spotter/models/User.dart'; + +abstract class AuthenticationEvent extends Equatable { + const AuthenticationEvent(); + + @override + List get props => []; +} + +class AuthenticationUserChanged extends AuthenticationEvent { + const AuthenticationUserChanged(this.user); + + final User user; + + @override + List get props => [user]; +} + +class AuthenticationStarted extends AuthenticationEvent { + const AuthenticationStarted(); + + @override + List get props => []; +} + +class AuthenticationLogoutRequested extends AuthenticationEvent {} + +class NoConnectivityEvent extends AuthenticationEvent {} diff --git a/lib/blocs/authentication/AuthenticationState.dart b/lib/blocs/authentication/AuthenticationState.dart new file mode 100644 index 0000000..8df3151 --- /dev/null +++ b/lib/blocs/authentication/AuthenticationState.dart @@ -0,0 +1,26 @@ +import 'package:equatable/equatable.dart'; +import 'package:giraffe_spotter/models/User.dart'; + +enum AuthenticationStatus { authenticated, verified, completed, unauthenticated, unknown, no_internet } + +class AuthenticationState extends Equatable { + const AuthenticationState._({this.status = AuthenticationStatus.unknown, this.user = User.empty}); + + const AuthenticationState.unknown() : this._(); + + const AuthenticationState.authenticated(User user) : this._(status: AuthenticationStatus.authenticated, user: user); + + const AuthenticationState.verified(User user) : this._(status: AuthenticationStatus.verified, user: user); + + const AuthenticationState.completed(User user) : this._(status: AuthenticationStatus.completed, user: user); + + const AuthenticationState.unauthenticated() : this._(status: AuthenticationStatus.unauthenticated); + + const AuthenticationState.noInternet() : this._(status: AuthenticationStatus.no_internet); + + final AuthenticationStatus status; + final User user; + + @override + List get props => [status, user]; +} diff --git a/lib/blocs/authentication/PasswordCubit.dart b/lib/blocs/authentication/PasswordCubit.dart new file mode 100644 index 0000000..70db3f8 --- /dev/null +++ b/lib/blocs/authentication/PasswordCubit.dart @@ -0,0 +1,7 @@ +import 'package:bloc/bloc.dart'; + +class PasswordCubit extends Cubit { + PasswordCubit() : super(true); + + void toggleVisibility() => emit(!state); +} diff --git a/lib/blocs/authentication/forgot_password/ForgotCubit.dart b/lib/blocs/authentication/forgot_password/ForgotCubit.dart new file mode 100644 index 0000000..98f71e3 --- /dev/null +++ b/lib/blocs/authentication/forgot_password/ForgotCubit.dart @@ -0,0 +1,67 @@ +import 'package:bloc/bloc.dart'; +import 'package:equatable/equatable.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:formz/formz.dart'; +import 'package:giraffe_spotter/config/AppRoute.dart'; +import 'package:giraffe_spotter/config/Constants.dart'; +import 'package:giraffe_spotter/config/ServiceLocator.dart'; +import 'package:giraffe_spotter/inputs/authentication/Email.dart'; +import 'package:giraffe_spotter/network/ApiResult.dart'; +import 'package:giraffe_spotter/network/NetworkExceptions.dart'; +import 'package:giraffe_spotter/pages/authentication/Login.dart'; +import 'package:giraffe_spotter/repositories/AuthenticationRepository.dart'; +import 'package:giraffe_spotter/utils/SharedObjects.dart'; + + +part 'ForgotState.dart'; + +class ForgotCubit extends Cubit { + ForgotCubit(this._authenticationRepository) : super(const ForgotState()); + + final AuthenticationRepository _authenticationRepository; + String? errorMessage; + + void emailChange(String value) { + final email = Email.dirty(value); + emit(state.copyWith(email: email, status: Formz.validate([email]))); + } + + void validateEmail() { + final email = Email.dirty(state.email.value); + emit(state.copyWith(email: email)); + } + + void urlLink(Uri? link) { + emit(state.copyWith(link: link)); + } + + void changePage(bool page) { + emit(state.copyWith(page: page)); + } + + void sendMail(Uri? link,Email email,bool page) async { + validateEmail(); + emit(state.copyWith(status: Formz.validate([state.email]))); + if (!state.status.isValidated) return; + emit(state.copyWith(status: FormzStatus.submissionInProgress)); + ApiResult result = await _authenticationRepository.forgotPassword(email: state.email.value,link: link); + result.when(success: (_) async { + await SharedObjects.prefs!.setString(Constants.reset, _['token']); + await SharedObjects.prefs!.setString(Constants.userEmail, email.toString()); + emit(state.copyWith(status: FormzStatus.submissionSuccess, page: page)); + }, failure: (error) { + error!.maybeWhen(unProcessableEntity: (Map e) { + emit(state.copyWith( + status: FormzStatus.submissionFailure, + formErrors: (e['errors'] as Map).map((key, value) => MapEntry(key, (value as List).map((e) => e as String).toList())))); + }, unauthenticatedRequest: () { + emit(state.copyWith(status: FormzStatus.submissionFailure)); + locator!().navigateAndRemoveUntil(Login()); + }, orElse: () { + emit(state.copyWith(status: FormzStatus.submissionFailure)); + }); + var rawError = NetworkExceptions.getErrorMessage(error); + errorMessage = rawError; + }); + } +} diff --git a/lib/blocs/authentication/forgot_password/ForgotState.dart b/lib/blocs/authentication/forgot_password/ForgotState.dart new file mode 100644 index 0000000..1e4f3e3 --- /dev/null +++ b/lib/blocs/authentication/forgot_password/ForgotState.dart @@ -0,0 +1,25 @@ +part of 'ForgotCubit.dart'; + +class ForgotState extends Equatable { + + const ForgotState({ + this.email = const Email.pure(), + this.status = FormzStatus.pure, + this.formErrors, + this.page = false, + this.link, + }); + + final Email email; + final bool? page; + final FormzStatus status; + final Map>? formErrors; + final Uri? link; + + + @override + List get props => [email,status,formErrors,link,page]; + + ForgotState copyWith({Email? email,bool? page, FormzStatus? status,Map>? formErrors, Uri? link})=> + ForgotState(link: link,email: email?? this.email, page: page, formErrors: formErrors,status: status ?? this.status); +} diff --git a/lib/blocs/authentication/login/LoginCubit.dart b/lib/blocs/authentication/login/LoginCubit.dart new file mode 100644 index 0000000..91381c6 --- /dev/null +++ b/lib/blocs/authentication/login/LoginCubit.dart @@ -0,0 +1,64 @@ +import 'package:bloc/bloc.dart'; +import 'package:formz/formz.dart'; +import 'package:giraffe_spotter/blocs/authentication/login/LoginState.dart'; +import 'package:giraffe_spotter/config/Constants.dart'; +import 'package:giraffe_spotter/inputs/authentication/Email.dart'; +import 'package:giraffe_spotter/inputs/authentication/Password.dart'; +import 'package:giraffe_spotter/models/User.dart'; +import 'package:giraffe_spotter/network/ApiResult.dart'; +import 'package:giraffe_spotter/network/NetworkExceptions.dart'; +import 'package:giraffe_spotter/repositories/AuthenticationRepository.dart'; +import 'package:giraffe_spotter/utils/SharedObjects.dart'; + +class LoginCubit extends Cubit { + LoginCubit(this._authenticationRepository) : super(const LoginState()); + late NetworkExceptions? failureReason; + String? errorMessage; + final AuthenticationRepository _authenticationRepository; + + void emailChanged(String value) { + final email = Email.dirty(value); + emit(state.copyWith(email: email, status: Formz.validate([email, state.password]))); + } + + void passwordChanged(String value) { + final password = Password.dirty(value); + emit(state.copyWith(password: password, status: Formz.validate([state.email, password]))); + } + + void validateBeforeSubmit() { + final email = Email.dirty(state.email.value); + final password = Password.dirty(state.password.value); + + emit(state.copyWith(email: email, password: password)); + } + + Future signIn() async { + validateBeforeSubmit(); + emit(state.copyWith(status: Formz.validate([state.email, state.password]))); + if (!state.status.isValidated) return; + emit(state.copyWith(status: FormzStatus.submissionInProgress)); + ApiResult result = await _authenticationRepository.login(email: state.email.value, password: state.password.value); + result.when(success: (User? user) async { + print(user); + await SharedObjects.prefs!.setString(Constants.accessToken, user!.token.toString()); + await SharedObjects.prefs!.setString(Constants.userEmail, user.email.toString()); + await SharedObjects.prefs!.setString(Constants.userImage, user.profile_image.toString()); + await SharedObjects.prefs!.setString(Constants.name, user.name.toString()); + await SharedObjects.prefs!.setString(Constants.userid, user.uuid.toString()); + await SharedObjects.prefs!.setBool(Constants.logged, true); + emit(state.copyWith(status: FormzStatus.submissionSuccess, user: user)); + }, failure: (NetworkExceptions? error) { + var rawError = NetworkExceptions.getErrorMessage(error!); + errorMessage = rawError; + error.maybeWhen(unProcessableEntity: (Map e) { + emit(state.copyWith( + status: FormzStatus.submissionFailure, + formErrors: (e['errors'] as Map).map((key, value) => MapEntry(key, (value as List).map((e) => e as String).toList())))); + }, orElse: () { + errorMessage = 'Error occurred while submitting your request. Please try again.'; + emit(state.copyWith(status: FormzStatus.submissionFailure)); + }); + }); + } +} diff --git a/lib/blocs/authentication/login/LoginState.dart b/lib/blocs/authentication/login/LoginState.dart new file mode 100644 index 0000000..8d729fb --- /dev/null +++ b/lib/blocs/authentication/login/LoginState.dart @@ -0,0 +1,29 @@ +import 'package:equatable/equatable.dart'; +import 'package:formz/formz.dart'; +import 'package:giraffe_spotter/inputs/authentication/Password.dart'; +import 'package:giraffe_spotter/inputs/authentication/Email.dart'; +import 'package:giraffe_spotter/models/User.dart'; + +class LoginState extends Equatable { + const LoginState({ + this.email = const Email.pure(), + this.password = const Password.pure(), + this.status = FormzStatus.pure, + this.user = User.empty, + this.formErrors + }); + + final Email email; + final Password password; + final FormzStatus status; + final User user; + final Map>? formErrors; + + + @override + List get props => [email, password,formErrors, status, user]; + + LoginState copyWith({Email? email, Password? password, FormzStatus? status, User? user, Map>?formErrors}) => LoginState( + email: email ?? this.email, formErrors: formErrors, password: password ?? this.password, status: status ?? this.status, user: user ?? this.user); + +} diff --git a/lib/blocs/authentication/logout/LogoutCubit.dart b/lib/blocs/authentication/logout/LogoutCubit.dart new file mode 100644 index 0000000..d431fd3 --- /dev/null +++ b/lib/blocs/authentication/logout/LogoutCubit.dart @@ -0,0 +1,36 @@ +import 'package:bloc/bloc.dart'; +import 'package:equatable/equatable.dart'; +import 'package:formz/formz.dart'; +import 'package:giraffe_spotter/config/AppRoute.dart'; +import 'package:giraffe_spotter/config/ServiceLocator.dart'; +import 'package:giraffe_spotter/network/ApiResult.dart'; +import 'package:giraffe_spotter/pages/authentication/Login.dart'; +import 'package:giraffe_spotter/repositories/AuthenticationRepository.dart'; +import 'package:giraffe_spotter/utils/SharedObjects.dart'; + +part 'LogoutState.dart'; + +class LogoutCubit extends Cubit { + LogoutCubit(this._authenticationRepository) : super(LogoutState()); + + final AuthenticationRepository _authenticationRepository; + + Future logout() async{ + emit(state.copyWith(formzStatus: FormzStatus.submissionInProgress)); + ApiResult result = await _authenticationRepository.logout(); + result.when(success: (_){ + emit(state.copyWith(formzStatus: FormzStatus.submissionSuccess)); + SharedObjects.prefs!.clearSession(); + SharedObjects.prefs!.clearAll(); + }, failure: (error){ + error?.maybeWhen(unProcessableEntity: (Map e){ + emit(state.copyWith(formzStatus: FormzStatus.submissionFailure)); + },unauthenticatedRequest: (){ + emit(state.copyWith(formzStatus: FormzStatus.submissionFailure)); + locator!().navigateAndRemoveUntil(Login()); + },orElse: () { + emit(state.copyWith(formzStatus: FormzStatus.submissionFailure)); + }); + }); + } +} diff --git a/lib/blocs/authentication/logout/LogoutState.dart b/lib/blocs/authentication/logout/LogoutState.dart new file mode 100644 index 0000000..80fe896 --- /dev/null +++ b/lib/blocs/authentication/logout/LogoutState.dart @@ -0,0 +1,16 @@ +part of 'LogoutCubit.dart'; + + +class LogoutState extends Equatable { + + final FormzStatus formzStatus; + + const LogoutState ({this.formzStatus = FormzStatus.pure}); + + + + @override + List get props => [formzStatus]; + + LogoutState copyWith({FormzStatus? formzStatus}) => LogoutState(formzStatus: formzStatus ?? this.formzStatus); +} diff --git a/lib/blocs/authentication/resetPassword/ResetCubit.dart b/lib/blocs/authentication/resetPassword/ResetCubit.dart new file mode 100644 index 0000000..48cfc39 --- /dev/null +++ b/lib/blocs/authentication/resetPassword/ResetCubit.dart @@ -0,0 +1,69 @@ +import 'package:bloc/bloc.dart'; +import 'package:equatable/equatable.dart'; +import 'package:formz/formz.dart'; +import 'package:giraffe_spotter/config/AppRoute.dart'; +import 'package:giraffe_spotter/config/Constants.dart'; +import 'package:giraffe_spotter/config/ServiceLocator.dart'; +import 'package:giraffe_spotter/inputs/authentication/Email.dart'; +import 'package:giraffe_spotter/inputs/authentication/Password.dart'; +import 'package:giraffe_spotter/network/ApiResult.dart'; +import 'package:giraffe_spotter/pages/authentication/Login.dart'; +import 'package:giraffe_spotter/repositories/AuthenticationRepository.dart'; +import 'package:giraffe_spotter/utils/SharedObjects.dart'; + +part 'ResetState.dart'; + +class ResetCubit extends Cubit { + ResetCubit(this._authenticationRepository) : super(ResetState()); + + final AuthenticationRepository _authenticationRepository; + String? errorMessage; + + void passwordChanged(String value) { + final password = Password.dirty(value); + emit(state.copyWith(password: password, status: Formz.validate([state.password, password]))); + } + + void confirmPasswordChanged(String value) { + final password = Password.dirty(value); + emit(state.copyWith(confirmPassword: password, status: Formz.validate([state.confirmPassword, password]))); + } + + void emailChanged(value) { + print("this is the email :: "+ value.toString()); + final email = Email.dirty(value); + emit(state.copyWith(email: email, status: Formz.validate([state.email, email]))); + } + + void validateBeforeSubmit() { + final password = Password.dirty(state.password.value); + final confirmPassword = Password.dirty(state.confirmPassword.value); + + emit(state.copyWith(confirmPassword: confirmPassword, password: password)); + } + + Future reset() async { + validateBeforeSubmit(); + emit(state.copyWith(status: Formz.validate([state.confirmPassword, state.password]))); + if (!state.status.isValidated) return; + emit(state.copyWith(status: FormzStatus.submissionInProgress)); + ApiResult result = await _authenticationRepository.resetPassword(token: SharedObjects.prefs!.getString(Constants.reset), password: state.password.value, confirmPassword: state.confirmPassword.value, email: state.email.value); + result.when(success: (_) async{ + await SharedObjects.prefs!.setString(Constants.reset, ''); + emit(state.copyWith(status: FormzStatus.submissionSuccess)); + }, failure: (_) { + _?.maybeWhen(unProcessableEntity: (Map e) { + errorMessage = e['message']; + emit(state.copyWith( + status: FormzStatus.submissionFailure, + formErrors: (e['errors'] as Map).map((key, value) => MapEntry(key, (value as List).map((e) => e as String).toList())))); + }, unauthenticatedRequest: () { + emit(state.copyWith(status: FormzStatus.submissionFailure)); + locator!().navigateAndRemoveUntil(Login()); + }, orElse: () { + errorMessage = 'Error occurred while submitting your request. Please try again.'; + emit(state.copyWith(status: FormzStatus.submissionFailure)); + }); + }); + } +} diff --git a/lib/blocs/authentication/resetPassword/ResetState.dart b/lib/blocs/authentication/resetPassword/ResetState.dart new file mode 100644 index 0000000..1ae51d0 --- /dev/null +++ b/lib/blocs/authentication/resetPassword/ResetState.dart @@ -0,0 +1,24 @@ +part of 'ResetCubit.dart'; + +class ResetState extends Equatable { + + + final FormzStatus status; + final Password password; + final Password confirmPassword; + final Email email; + final Map>? formErrors; + + const ResetState({ + this.status = FormzStatus.pure, + this.password = const Password.pure(), + this.confirmPassword = const Password.pure(), + this.email = const Email.pure(), + this.formErrors + }); + + @override + List get props => [status,password,confirmPassword,formErrors,email]; + + ResetState copyWith({ Password? password, Password? confirmPassword,Email? email, FormzStatus? status, Map>?formErrors}) => ResetState(password: password?? this.password,email: email ?? this.email, confirmPassword: confirmPassword?? this.confirmPassword, formErrors: formErrors,status: status ?? this.status); +} diff --git a/lib/blocs/authentication/sign_up/Bloc.dart b/lib/blocs/authentication/sign_up/Bloc.dart new file mode 100644 index 0000000..07972d6 --- /dev/null +++ b/lib/blocs/authentication/sign_up/Bloc.dart @@ -0,0 +1,2 @@ +export 'SignUpCubit.dart'; +export 'SignUpState.dart'; diff --git a/lib/blocs/authentication/sign_up/SignUpCubit.dart b/lib/blocs/authentication/sign_up/SignUpCubit.dart new file mode 100644 index 0000000..67b475f --- /dev/null +++ b/lib/blocs/authentication/sign_up/SignUpCubit.dart @@ -0,0 +1,116 @@ +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:flutter_smartlook/flutter_smartlook.dart'; +import 'package:formz/formz.dart'; +import 'package:giraffe_spotter/config/AppRoute.dart'; +import 'package:giraffe_spotter/config/Constants.dart'; +import 'package:giraffe_spotter/config/ServiceLocator.dart'; +import 'package:giraffe_spotter/inputs/authentication/AcceptTerms.dart'; +import 'package:giraffe_spotter/inputs/authentication/Email.dart'; +import 'package:giraffe_spotter/inputs/authentication/Name.dart'; +import 'package:giraffe_spotter/inputs/authentication/Password.dart'; +import 'package:giraffe_spotter/models/User.dart'; +import 'package:giraffe_spotter/network/ApiResult.dart'; +import 'package:giraffe_spotter/network/NetworkExceptions.dart'; +import 'package:giraffe_spotter/pages/authentication/Login.dart'; +import 'package:giraffe_spotter/repositories/AuthenticationRepository.dart'; +import 'package:giraffe_spotter/utils/SharedObjects.dart'; + +import 'SignUpState.dart'; + +class SignUpCubit extends Cubit { + SignUpCubit(this._authRepository) + : emailError = null, + passwordError = null, + errorMessage = null, + fullNameError = null, + super(SignUpState()); + + final AuthenticationRepository _authRepository; + late String? errorMessage; + late String? emailError; + late String? passwordError; + late String? fullNameError; + late NetworkExceptions failureReason; + + void nameChanged(String value) { + final fullName = Name.dirty(value); + + emit(state.copyWith(fullName: fullName, status: Formz.validate([state.email, fullName, state.password, state.acceptTerms]))); + } + + void emailChanged(String value) { + final email = Email.dirty(value); + + emit(state.copyWith(email: email, status: Formz.validate([email, state.fullName, state.password, state.acceptTerms]))); + } + + void passwordChanged(String value) { + final password = Password.dirty(value); + + emit(state.copyWith(password: password, status: Formz.validate([state.email, password, state.fullName, state.acceptTerms]))); + } + + void acceptTermsChanged(bool? value) { + final acceptTerms = AcceptTerms.dirty(value ?? false); + emit(state.copyWith(acceptTerms: acceptTerms, status: Formz.validate([state.email, state.password, state.fullName, acceptTerms]))); + } + + void validateBeforeSignUp() { + final email = Email.dirty(state.email.value); + final password = Password.dirty(state.password.value); + final acceptTerms = AcceptTerms.dirty(state.acceptTerms.value); + final fullName = Name.dirty(state.fullName.value); + + emit(state.copyWith(email: email, password: password, acceptTerms: acceptTerms, fullName: fullName)); + } + + Future signUp() async { + validateBeforeSignUp(); + emit(state.copyWith(status: Formz.validate([state.fullName, state.email, state.password, state.acceptTerms]))); + if (!state.status.isValidated) return; + clearErrors(); + emit(state.copyWith(status: FormzStatus.submissionInProgress)); + ApiResult result = await _authRepository.signUp( + fullName: state.fullName.value, + email: state.email.value, + acceptTerms: state.acceptTerms.value, + password: state.password.value, + ); + + result.when(success: (User? user) async { + await SharedObjects.prefs!.setString(Constants.accessToken, user!.token.toString()); + await SharedObjects.prefs!.setString(Constants.userEmail, user.email.toString()); + await SharedObjects.prefs!.setString(Constants.userImage, user.profile_image.toString()); + await SharedObjects.prefs!.setString(Constants.name, user.name.toString()); + await SharedObjects.prefs!.setString(Constants.userid, user.uuid.toString()); + await SharedObjects.prefs!.setBool(Constants.logged, true); + Smartlook.setUserIdentifier(user.email.toString()); + emit(state.copyWith(status: FormzStatus.submissionSuccess, user: user)); + }, failure: (NetworkExceptions? error) { + failureReason = error!; + var rawError = NetworkExceptions.getErrorMessage(error); + errorMessage = rawError; + error.maybeWhen( + unProcessableEntity: (Map errors) { + emit(state.copyWith( + status: FormzStatus.submissionFailure, + error: error, + errors: (errors['errors'] as Map).map((key, value) => MapEntry(key, (value as List).map((e) => e).toList())))); + }, + unauthenticatedRequest: () { + emit(state.copyWith(status: FormzStatus.submissionFailure)); + locator!().navigateAndRemoveUntil(Login()); + }, + orElse: () { + errorMessage = 'Error occurred while submitting your request. Please try again.'; + emit(state.copyWith(status: FormzStatus.submissionFailure, error: error)); + }, + ); + }); + } + + void clearErrors() { + emailError = null; + passwordError = null; + } +} diff --git a/lib/blocs/authentication/sign_up/SignUpState.dart b/lib/blocs/authentication/sign_up/SignUpState.dart new file mode 100644 index 0000000..2007efb --- /dev/null +++ b/lib/blocs/authentication/sign_up/SignUpState.dart @@ -0,0 +1,50 @@ +import 'package:equatable/equatable.dart'; +import 'package:formz/formz.dart'; +import 'package:giraffe_spotter/inputs/authentication/AcceptTerms.dart'; +import 'package:giraffe_spotter/inputs/authentication/Email.dart'; +import 'package:giraffe_spotter/inputs/authentication/Name.dart'; +import 'package:giraffe_spotter/inputs/authentication/Password.dart'; +import 'package:giraffe_spotter/models/User.dart'; +import 'package:giraffe_spotter/network/NetworkExceptions.dart'; + +class SignUpState extends Equatable { + SignUpState({ + this.fullName = const Name.pure(), + this.email = const Email.pure(), + this.password = const Password.pure(), + this.acceptTerms = const AcceptTerms.pure(), + this.status = FormzStatus.pure, + this.user = User.empty, + this.error, + this.errors, + }); + final Email email; + final Password password; + final Name fullName; + final AcceptTerms acceptTerms; + final FormzStatus status; + final User user; + final NetworkExceptions? error; + final Map>? errors; + @override + List get props => [fullName, email, password, acceptTerms, status, user, errors]; + SignUpState copyWith( + {Name? fullName, + Email? email, + Password? password, + AcceptTerms? acceptTerms, + FormzStatus? status, + User? user, + NetworkExceptions? error, + Map>? errors}) => + SignUpState( + fullName: fullName ?? this.fullName, + email: email ?? this.email, + password: password ?? this.password, + acceptTerms: acceptTerms ?? this.acceptTerms, + status: status ?? this.status, + user: user ?? this.user, + error: error, + errors: errors, + ); +} diff --git a/lib/blocs/capture/CaptureCubit.dart b/lib/blocs/capture/CaptureCubit.dart new file mode 100644 index 0000000..2ac782a --- /dev/null +++ b/lib/blocs/capture/CaptureCubit.dart @@ -0,0 +1,69 @@ +import 'dart:io'; + +import 'package:bloc/bloc.dart'; +import 'package:equatable/equatable.dart'; +import 'package:flutter/material.dart'; +import 'package:formz/formz.dart'; +import 'package:giraffe_spotter/config/AppRoute.dart'; +import 'package:giraffe_spotter/config/ServiceLocator.dart'; +import 'package:giraffe_spotter/network/ApiResult.dart'; +import 'package:giraffe_spotter/pages/authentication/Login.dart'; +import 'package:giraffe_spotter/providers/CaptureProvider.dart'; + +part 'CaptureState.dart'; + +class CaptureCubit extends Cubit { + CaptureCubit(this._captureProvider) : super(CaptureState()); + final CaptureProvider _captureProvider; + String? errorMessage; + double? latitude; + double? longitude; + + void locationChanged(String? value, double? longitude, double? latitude) { + var parts = value!.split(','); + String? location = parts[0]; + String? country = parts.last; + emit(state.copyWith(location: location, longitude: longitude, latitude: latitude, country: country.isNotEmpty ? country : location)); + } + + void dateTimeChanged(DateTime? dateTime, TimeOfDay? timeOfDays) { + emit(state.copyWith(dateTime: DateTime(dateTime!.year, dateTime.month, dateTime.hour, timeOfDays!.hour, timeOfDays.minute).toString())); + } + + Future captureData(String? uuid, List images) async { + emit(state.copyWith(status: FormzStatus.submissionInProgress)); + ApiResult result = await _captureProvider.captureData( + dateTime: state.dateTime, + country: state.country, + location: state.location, + longitude: state.longitude, + latitude: state.latitude, + images: images); + result.when(success: (_) { + emit(state.copyWith(status: FormzStatus.submissionSuccess)); + }, failure: (error) { + error?.maybeWhen(unProcessableEntity: (Map e) { + errorMessage = e['message']; + emit(state.copyWith( + status: FormzStatus.submissionFailure, + formErrors: (e['errors'] as Map).map((key, value) => MapEntry(key, (value as List).map((e) => e as String).toList())))); + }, unauthenticatedRequest: () { + emit(state.copyWith(status: FormzStatus.submissionFailure)); + locator!().navigateAndRemoveUntil(Login()); + }, orElse: () { + errorMessage = 'Error occurred while submitting your request. Please try again.'; + emit(state.copyWith(status: FormzStatus.submissionFailure)); + }); + }); + } + + //Todo:: use this to send image to backend to fetch latlng + // Future checkLocation(File image) async { + // ApiResult result = await _captureProvider.checkLocation(image: image); + // result.when(success: (_) async { + // latitude = _!.latitude; + // longitude = _.longitude; + // }, failure: (error) { + // }); + // } +} diff --git a/lib/blocs/capture/CaptureState.dart b/lib/blocs/capture/CaptureState.dart new file mode 100644 index 0000000..61b0951 --- /dev/null +++ b/lib/blocs/capture/CaptureState.dart @@ -0,0 +1,41 @@ +part of 'CaptureCubit.dart'; + +class CaptureState extends Equatable { + final String dateTime; + final String location; + final double longitude; + final double latitude; + final String country; + final FormzStatus status; + final Map>? formErrors; + + const CaptureState({ + this.formErrors, + this.country = '', + this.longitude = 0.0, + this.latitude = 0.0, + this.dateTime = '', + this.location = '', + this.status = FormzStatus.pure, + }); + + @override + List get props => [formErrors, country, longitude, latitude, dateTime, location, status]; + + CaptureState copyWith( + {double? longitude, + double? latitude, + String? dateTime, + String? location, + FormzStatus? status, + Map>? formErrors, + String? country}) => + CaptureState( + latitude: latitude ?? this.latitude, + longitude: longitude ?? this.longitude, + dateTime: dateTime ?? this.dateTime, + location: location ?? this.location, + formErrors: formErrors, + status: status ?? this.status, + country: country ?? this.country); +} diff --git a/lib/blocs/capture/date_time/DateTimeCubit.dart b/lib/blocs/capture/date_time/DateTimeCubit.dart new file mode 100644 index 0000000..ad93967 --- /dev/null +++ b/lib/blocs/capture/date_time/DateTimeCubit.dart @@ -0,0 +1,37 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:giraffe_spotter/blocs/capture/date_time/DateTimeState.dart'; + +class DateAndTimeCubit extends Cubit { + + DateTime? copyWithTime; + TimeOfDay? timeOfDays; + DateAndTimeCubit() : super(DateAndTimeState()); + + void setDateTime(datetime) { + copyWithTime = datetime; + emit(DateAndTimeState(datetime: datetime)); + } + + void setTimeOfDay(timeOfDay) { + timeOfDays = timeOfDay; + emit(DateAndTimeState(timeOfDay: timeOfDay)); + } + + void reset(){ + copyWithTime = null; + timeOfDays = null; + } + + formatTime(TimeOfDay? input) { + var hour = input!.hour.toString(); + var minute = input.minute.toString(); + var period = input.period.toString() == 'DayPeriod.am' ? "am" : "pm"; + + var minutes = minute.length <= 1 ? "0"+ minute : minute; + if(int.parse(hour) > 11 ) { + return hour +":"+minutes; + } + return hour +":"+ minutes+" "+ period; + } +} diff --git a/lib/blocs/capture/date_time/DateTimeState.dart b/lib/blocs/capture/date_time/DateTimeState.dart new file mode 100644 index 0000000..28b8d43 --- /dev/null +++ b/lib/blocs/capture/date_time/DateTimeState.dart @@ -0,0 +1,10 @@ +import 'package:equatable/equatable.dart'; +import 'package:flutter/material.dart'; + +class DateAndTimeState extends Equatable { + DateAndTimeState({this.datetime, this.timeOfDay}); + final DateTime? datetime; + final TimeOfDay? timeOfDay; + @override + List get props => [datetime,timeOfDay]; +} diff --git a/lib/blocs/capture/imageCapture/ImageCaptureCubit.dart b/lib/blocs/capture/imageCapture/ImageCaptureCubit.dart new file mode 100644 index 0000000..e109efc --- /dev/null +++ b/lib/blocs/capture/imageCapture/ImageCaptureCubit.dart @@ -0,0 +1,61 @@ +import 'dart:io'; +import 'dart:math'; + +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:formz/formz.dart'; +import 'package:giraffe_spotter/models/ImageFile.dart'; + +class ImageCaptureCubit extends Cubit { + List assets = []; + List? numbers; + File? file; + List? profileAsset; + double? longitude; + double? latitude; + DateTime? dateTime; + + ImageCaptureCubit({required this.assets, this.file, this.profileAsset}) : super(ImageFile()); + + //parameter has assetEntity list ... + void imagePicker(asset) async { + emit(state.copyWith(file: file, status: FormzStatus.submissionInProgress, files: List.of(assets.toSet()))); + if (asset != null && assets.length < 10) { + assets.add(asset); + emit(state.copyWith(file: file, status: FormzStatus.submissionSuccess, files: List.of(assets.toSet()))); + } + } + + //remove the file from the List + void removePicked(int index) async { + emit(state.copyWith(file: file, status: FormzStatus.submissionInProgress, files: assets)); + assets.removeAt(index); + emit(state.copyWith(file: file, status: FormzStatus.submissionSuccess, files: assets)); + } + + imageRetrieve(int index) { + //number of assets --- index + File? image; + image = assets[index]; + return image; + } + + //to select profile image + void profileImage(File asset) async { + file = asset; + emit(state.copyWith(files: List.of(assets.toSet()), file: file, status: FormzStatus.submissionSuccess)); + } + + //clear the assets + void clearAll() { + if (assets.isNotEmpty) { + assets = []; + assets.clear(); + emit(state.copyWith(file: file, status: FormzStatus.submissionSuccess, files: List.of(assets.toSet()))); + } + } + + randomNumber(min, max) { + var rn = new Random(); + return min + rn.nextInt(max - min); + } +} diff --git a/lib/blocs/capture/map/location/LocationCubit.dart b/lib/blocs/capture/map/location/LocationCubit.dart new file mode 100644 index 0000000..f9edc5d --- /dev/null +++ b/lib/blocs/capture/map/location/LocationCubit.dart @@ -0,0 +1,33 @@ +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:geocoding/geocoding.dart'; +import 'package:giraffe_spotter/blocs/capture/map/location/LocationState.dart'; + +class LocationCubit extends Cubit { + LocationCubit({this.switched = false}) : super(InitialState()); + + bool switched; + + void changeCameraPosition(place) { + emit(PlaceState(place: place)); + } + + void initialState() { + emit(InitialState()); + } + + void imageLocator(placemark, latitude, longitude) async { + emit(ImageState(placemarks: placemark, latitude: latitude, longitude: longitude)); + } + + void markerPosition(latitude, longitude) async { + try { + List placemarks = await placemarkFromCoordinates(latitude!, longitude!); + emit(MarkerPosition(placemark: placemarks[0], latitude: latitude, longitude: longitude)); + } catch (e) {} + } + + void mapChange(bool value) { + switched = value; + value == true ? emit(MapSatellite()) : emit(MapStreet()); + } +} diff --git a/lib/blocs/capture/map/location/LocationState.dart b/lib/blocs/capture/map/location/LocationState.dart new file mode 100644 index 0000000..4f41546 --- /dev/null +++ b/lib/blocs/capture/map/location/LocationState.dart @@ -0,0 +1,52 @@ +import 'package:equatable/equatable.dart'; +import 'package:geocoding/geocoding.dart'; +import 'package:google_maps_webservice/places.dart'; + +abstract class LocationState extends Equatable {} + +class PlaceState extends LocationState { + PlaceState({required this.place}); + final PlacesSearchResult? place; + @override + List get props => [place]; +} + +class InitialState extends LocationState { + @override + List get props => []; +} + +class ImageState extends LocationState { + ImageState({required this.placemarks, required this.longitude, required this.latitude}); + + final Placemark? placemarks; + final double? latitude; + final double? longitude; + + @override + List get props => [placemarks, longitude, latitude]; +} + +class MarkerPosition extends LocationState { + MarkerPosition({required this.placemark, this.latitude, this.longitude}); + final Placemark? placemark; + final double? longitude; + final double? latitude; + + @override + List get props => [placemark, longitude, latitude]; +} + +class MapSatellite extends LocationState { + final String satellite = 'mapbox://styles/mapbox/satellite-streets-v11'; + + @override + List get props => [satellite]; +} + +class MapStreet extends LocationState { + final String satellite = 'mapbox://styles/mapbox/streets-v11'; + + @override + List get props => [satellite]; +} diff --git a/lib/blocs/capture/map/search/Bloc.dart b/lib/blocs/capture/map/search/Bloc.dart new file mode 100644 index 0000000..78a929a --- /dev/null +++ b/lib/blocs/capture/map/search/Bloc.dart @@ -0,0 +1,3 @@ +export 'MapSearchEvent.dart'; +export 'MapSearchState.dart'; +export 'MapSearchBloc.dart'; \ No newline at end of file diff --git a/lib/blocs/capture/map/search/MapSearchBloc.dart b/lib/blocs/capture/map/search/MapSearchBloc.dart new file mode 100644 index 0000000..e53f1b2 --- /dev/null +++ b/lib/blocs/capture/map/search/MapSearchBloc.dart @@ -0,0 +1,38 @@ +import 'dart:async'; + +import 'package:bloc/bloc.dart'; +import 'package:giraffe_spotter/blocs/capture/map/search/Bloc.dart'; +import 'package:giraffe_spotter/repositories/MapSearchRepository.dart'; +import 'package:google_maps_webservice/places.dart'; + +class MapSearchBloc extends Bloc { + MapSearchBloc(MapSearchRepository repository) + : _repository = repository, + super(MapSearchState.idle()); + final MapSearchRepository _repository; + @override + Stream mapEventToState(MapSearchEvent event) async* { + if (event is GetPlaces) { + yield* mapFetchPlacesEventToState(event.keyword); + } + if(event is Resettings) { + yield* mapResetPlaceEvent(); + } + } + + Stream mapResetPlaceEvent() async*{ + yield MapSearchState.idle(); + } + + Stream mapFetchPlacesEventToState(event) async* { + // call function for searching places + try { + yield MapSearchState.loading(); + List places = await _repository.getPlaces(event); + yield MapSearchState.getPlacesDone(places); + } catch (e) { + //TODO: remove the throw error; + throw e; + } + } +} diff --git a/lib/blocs/capture/map/search/MapSearchCubit.dart b/lib/blocs/capture/map/search/MapSearchCubit.dart new file mode 100644 index 0000000..55bccf8 --- /dev/null +++ b/lib/blocs/capture/map/search/MapSearchCubit.dart @@ -0,0 +1,23 @@ +import 'package:bloc/bloc.dart'; +import 'package:giraffe_spotter/config/Constants.dart'; +import 'package:mapbox_search/mapbox_search.dart'; + +class MapSearchCubit extends Cubit { + final String key = Constants.mapBoxToken; + final String keyword =''; + MapSearchCubit() : super(true); + + //Places Search + Future placesSearch(key,keyword) async { + var placesService = PlacesSearch( + apiKey: key, + limit: 5, + ); + + var places = await placesService.getPlaces( + key, + ); + + print(places); + } +} diff --git a/lib/blocs/capture/map/search/MapSearchEvent.dart b/lib/blocs/capture/map/search/MapSearchEvent.dart new file mode 100644 index 0000000..461594b --- /dev/null +++ b/lib/blocs/capture/map/search/MapSearchEvent.dart @@ -0,0 +1,10 @@ +import 'package:freezed_annotation/freezed_annotation.dart'; + +part 'MapSearchEvent.freezed.dart'; + +@freezed +abstract class MapSearchEvent with _$MapSearchEvent { + const factory MapSearchEvent.getPlaces(String keyword) = GetPlaces; + const factory MapSearchEvent.getExactPlaces(double latitude, double longitude) = GetExactPlaces; + const factory MapSearchEvent.reset() = Resettings; +} diff --git a/lib/blocs/capture/map/search/MapSearchEvent.freezed.dart b/lib/blocs/capture/map/search/MapSearchEvent.freezed.dart new file mode 100644 index 0000000..0a2dfc3 --- /dev/null +++ b/lib/blocs/capture/map/search/MapSearchEvent.freezed.dart @@ -0,0 +1,426 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides + +part of 'MapSearchEvent.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more informations: https://github.com/rrousselGit/freezed#custom-getters-and-methods'); + +/// @nodoc +class _$MapSearchEventTearOff { + const _$MapSearchEventTearOff(); + + GetPlaces getPlaces(String keyword) { + return GetPlaces( + keyword, + ); + } + + GetExactPlaces getExactPlaces(double latitude, double longitude) { + return GetExactPlaces( + latitude, + longitude, + ); + } + + Resettings reset() { + return const Resettings(); + } +} + +/// @nodoc +const $MapSearchEvent = _$MapSearchEventTearOff(); + +/// @nodoc +mixin _$MapSearchEvent { + @optionalTypeArgs + TResult when({ + required TResult Function(String keyword) getPlaces, + required TResult Function(double latitude, double longitude) getExactPlaces, + required TResult Function() reset, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult maybeWhen({ + TResult Function(String keyword)? getPlaces, + TResult Function(double latitude, double longitude)? getExactPlaces, + TResult Function()? reset, + required TResult orElse(), + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult map({ + required TResult Function(GetPlaces value) getPlaces, + required TResult Function(GetExactPlaces value) getExactPlaces, + required TResult Function(Resettings value) reset, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult maybeMap({ + TResult Function(GetPlaces value)? getPlaces, + TResult Function(GetExactPlaces value)? getExactPlaces, + TResult Function(Resettings value)? reset, + required TResult orElse(), + }) => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $MapSearchEventCopyWith<$Res> { + factory $MapSearchEventCopyWith( + MapSearchEvent value, $Res Function(MapSearchEvent) then) = + _$MapSearchEventCopyWithImpl<$Res>; +} + +/// @nodoc +class _$MapSearchEventCopyWithImpl<$Res> + implements $MapSearchEventCopyWith<$Res> { + _$MapSearchEventCopyWithImpl(this._value, this._then); + + final MapSearchEvent _value; + // ignore: unused_field + final $Res Function(MapSearchEvent) _then; +} + +/// @nodoc +abstract class $GetPlacesCopyWith<$Res> { + factory $GetPlacesCopyWith(GetPlaces value, $Res Function(GetPlaces) then) = + _$GetPlacesCopyWithImpl<$Res>; + $Res call({String keyword}); +} + +/// @nodoc +class _$GetPlacesCopyWithImpl<$Res> extends _$MapSearchEventCopyWithImpl<$Res> + implements $GetPlacesCopyWith<$Res> { + _$GetPlacesCopyWithImpl(GetPlaces _value, $Res Function(GetPlaces) _then) + : super(_value, (v) => _then(v as GetPlaces)); + + @override + GetPlaces get _value => super._value as GetPlaces; + + @override + $Res call({ + Object? keyword = freezed, + }) { + return _then(GetPlaces( + keyword == freezed + ? _value.keyword + : keyword // ignore: cast_nullable_to_non_nullable + as String, + )); + } +} + +/// @nodoc +class _$GetPlaces implements GetPlaces { + const _$GetPlaces(this.keyword); + + @override + final String keyword; + + @override + String toString() { + return 'MapSearchEvent.getPlaces(keyword: $keyword)'; + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || + (other is GetPlaces && + (identical(other.keyword, keyword) || + const DeepCollectionEquality().equals(other.keyword, keyword))); + } + + @override + int get hashCode => + runtimeType.hashCode ^ const DeepCollectionEquality().hash(keyword); + + @JsonKey(ignore: true) + @override + $GetPlacesCopyWith get copyWith => + _$GetPlacesCopyWithImpl(this, _$identity); + + @override + @optionalTypeArgs + TResult when({ + required TResult Function(String keyword) getPlaces, + required TResult Function(double latitude, double longitude) getExactPlaces, + required TResult Function() reset, + }) { + return getPlaces(keyword); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function(String keyword)? getPlaces, + TResult Function(double latitude, double longitude)? getExactPlaces, + TResult Function()? reset, + required TResult orElse(), + }) { + if (getPlaces != null) { + return getPlaces(keyword); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(GetPlaces value) getPlaces, + required TResult Function(GetExactPlaces value) getExactPlaces, + required TResult Function(Resettings value) reset, + }) { + return getPlaces(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(GetPlaces value)? getPlaces, + TResult Function(GetExactPlaces value)? getExactPlaces, + TResult Function(Resettings value)? reset, + required TResult orElse(), + }) { + if (getPlaces != null) { + return getPlaces(this); + } + return orElse(); + } +} + +abstract class GetPlaces implements MapSearchEvent { + const factory GetPlaces(String keyword) = _$GetPlaces; + + String get keyword => throw _privateConstructorUsedError; + @JsonKey(ignore: true) + $GetPlacesCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $GetExactPlacesCopyWith<$Res> { + factory $GetExactPlacesCopyWith( + GetExactPlaces value, $Res Function(GetExactPlaces) then) = + _$GetExactPlacesCopyWithImpl<$Res>; + $Res call({double latitude, double longitude}); +} + +/// @nodoc +class _$GetExactPlacesCopyWithImpl<$Res> + extends _$MapSearchEventCopyWithImpl<$Res> + implements $GetExactPlacesCopyWith<$Res> { + _$GetExactPlacesCopyWithImpl( + GetExactPlaces _value, $Res Function(GetExactPlaces) _then) + : super(_value, (v) => _then(v as GetExactPlaces)); + + @override + GetExactPlaces get _value => super._value as GetExactPlaces; + + @override + $Res call({ + Object? latitude = freezed, + Object? longitude = freezed, + }) { + return _then(GetExactPlaces( + latitude == freezed + ? _value.latitude + : latitude // ignore: cast_nullable_to_non_nullable + as double, + longitude == freezed + ? _value.longitude + : longitude // ignore: cast_nullable_to_non_nullable + as double, + )); + } +} + +/// @nodoc +class _$GetExactPlaces implements GetExactPlaces { + const _$GetExactPlaces(this.latitude, this.longitude); + + @override + final double latitude; + @override + final double longitude; + + @override + String toString() { + return 'MapSearchEvent.getExactPlaces(latitude: $latitude, longitude: $longitude)'; + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || + (other is GetExactPlaces && + (identical(other.latitude, latitude) || + const DeepCollectionEquality() + .equals(other.latitude, latitude)) && + (identical(other.longitude, longitude) || + const DeepCollectionEquality() + .equals(other.longitude, longitude))); + } + + @override + int get hashCode => + runtimeType.hashCode ^ + const DeepCollectionEquality().hash(latitude) ^ + const DeepCollectionEquality().hash(longitude); + + @JsonKey(ignore: true) + @override + $GetExactPlacesCopyWith get copyWith => + _$GetExactPlacesCopyWithImpl(this, _$identity); + + @override + @optionalTypeArgs + TResult when({ + required TResult Function(String keyword) getPlaces, + required TResult Function(double latitude, double longitude) getExactPlaces, + required TResult Function() reset, + }) { + return getExactPlaces(latitude, longitude); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function(String keyword)? getPlaces, + TResult Function(double latitude, double longitude)? getExactPlaces, + TResult Function()? reset, + required TResult orElse(), + }) { + if (getExactPlaces != null) { + return getExactPlaces(latitude, longitude); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(GetPlaces value) getPlaces, + required TResult Function(GetExactPlaces value) getExactPlaces, + required TResult Function(Resettings value) reset, + }) { + return getExactPlaces(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(GetPlaces value)? getPlaces, + TResult Function(GetExactPlaces value)? getExactPlaces, + TResult Function(Resettings value)? reset, + required TResult orElse(), + }) { + if (getExactPlaces != null) { + return getExactPlaces(this); + } + return orElse(); + } +} + +abstract class GetExactPlaces implements MapSearchEvent { + const factory GetExactPlaces(double latitude, double longitude) = + _$GetExactPlaces; + + double get latitude => throw _privateConstructorUsedError; + double get longitude => throw _privateConstructorUsedError; + @JsonKey(ignore: true) + $GetExactPlacesCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $ResettingsCopyWith<$Res> { + factory $ResettingsCopyWith( + Resettings value, $Res Function(Resettings) then) = + _$ResettingsCopyWithImpl<$Res>; +} + +/// @nodoc +class _$ResettingsCopyWithImpl<$Res> extends _$MapSearchEventCopyWithImpl<$Res> + implements $ResettingsCopyWith<$Res> { + _$ResettingsCopyWithImpl(Resettings _value, $Res Function(Resettings) _then) + : super(_value, (v) => _then(v as Resettings)); + + @override + Resettings get _value => super._value as Resettings; +} + +/// @nodoc +class _$Resettings implements Resettings { + const _$Resettings(); + + @override + String toString() { + return 'MapSearchEvent.reset()'; + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || (other is Resettings); + } + + @override + int get hashCode => runtimeType.hashCode; + + @override + @optionalTypeArgs + TResult when({ + required TResult Function(String keyword) getPlaces, + required TResult Function(double latitude, double longitude) getExactPlaces, + required TResult Function() reset, + }) { + return reset(); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function(String keyword)? getPlaces, + TResult Function(double latitude, double longitude)? getExactPlaces, + TResult Function()? reset, + required TResult orElse(), + }) { + if (reset != null) { + return reset(); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(GetPlaces value) getPlaces, + required TResult Function(GetExactPlaces value) getExactPlaces, + required TResult Function(Resettings value) reset, + }) { + return reset(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(GetPlaces value)? getPlaces, + TResult Function(GetExactPlaces value)? getExactPlaces, + TResult Function(Resettings value)? reset, + required TResult orElse(), + }) { + if (reset != null) { + return reset(this); + } + return orElse(); + } +} + +abstract class Resettings implements MapSearchEvent { + const factory Resettings() = _$Resettings; +} diff --git a/lib/blocs/capture/map/search/MapSearchState.dart b/lib/blocs/capture/map/search/MapSearchState.dart new file mode 100644 index 0000000..f47c76a --- /dev/null +++ b/lib/blocs/capture/map/search/MapSearchState.dart @@ -0,0 +1,20 @@ +import 'package:freezed_annotation/freezed_annotation.dart'; +import 'package:giraffe_spotter/network/NetworkExceptions.dart'; +import 'package:google_maps_webservice/places.dart'; +import 'package:mapbox_search/mapbox_search.dart'; + +part 'MapSearchState.freezed.dart'; + +@freezed +abstract class MapSearchState with _$MapSearchState { + const factory MapSearchState.idle() = Idle; + + const factory MapSearchState.loading() = Loading; + + const factory MapSearchState.getPlacesDone(List data) = GetPlacesDone; + + const factory MapSearchState.getExactPlacesDone(List? data) = GetExactPlacesDone; + + const factory MapSearchState.error(NetworkExceptions error) = Error; + +} diff --git a/lib/blocs/capture/map/search/MapSearchState.freezed.dart b/lib/blocs/capture/map/search/MapSearchState.freezed.dart new file mode 100644 index 0000000..095dcb5 --- /dev/null +++ b/lib/blocs/capture/map/search/MapSearchState.freezed.dart @@ -0,0 +1,681 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides + +part of 'MapSearchState.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more informations: https://github.com/rrousselGit/freezed#custom-getters-and-methods'); + +/// @nodoc +class _$MapSearchStateTearOff { + const _$MapSearchStateTearOff(); + + Idle idle() { + return const Idle(); + } + + Loading loading() { + return const Loading(); + } + + GetPlacesDone getPlacesDone(List data) { + return GetPlacesDone( + data, + ); + } + + GetExactPlacesDone getExactPlacesDone(List? data) { + return GetExactPlacesDone( + data, + ); + } + + Error error(NetworkExceptions error) { + return Error( + error, + ); + } +} + +/// @nodoc +const $MapSearchState = _$MapSearchStateTearOff(); + +/// @nodoc +mixin _$MapSearchState { + @optionalTypeArgs + TResult when({ + required TResult Function() idle, + required TResult Function() loading, + required TResult Function(List data) getPlacesDone, + required TResult Function(List? data) getExactPlacesDone, + required TResult Function(NetworkExceptions error) error, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? idle, + TResult Function()? loading, + TResult Function(List data)? getPlacesDone, + TResult Function(List? data)? getExactPlacesDone, + TResult Function(NetworkExceptions error)? error, + required TResult orElse(), + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult map({ + required TResult Function(Idle value) idle, + required TResult Function(Loading value) loading, + required TResult Function(GetPlacesDone value) getPlacesDone, + required TResult Function(GetExactPlacesDone value) getExactPlacesDone, + required TResult Function(Error value) error, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult maybeMap({ + TResult Function(Idle value)? idle, + TResult Function(Loading value)? loading, + TResult Function(GetPlacesDone value)? getPlacesDone, + TResult Function(GetExactPlacesDone value)? getExactPlacesDone, + TResult Function(Error value)? error, + required TResult orElse(), + }) => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $MapSearchStateCopyWith<$Res> { + factory $MapSearchStateCopyWith( + MapSearchState value, $Res Function(MapSearchState) then) = + _$MapSearchStateCopyWithImpl<$Res>; +} + +/// @nodoc +class _$MapSearchStateCopyWithImpl<$Res> + implements $MapSearchStateCopyWith<$Res> { + _$MapSearchStateCopyWithImpl(this._value, this._then); + + final MapSearchState _value; + // ignore: unused_field + final $Res Function(MapSearchState) _then; +} + +/// @nodoc +abstract class $IdleCopyWith<$Res> { + factory $IdleCopyWith(Idle value, $Res Function(Idle) then) = + _$IdleCopyWithImpl<$Res>; +} + +/// @nodoc +class _$IdleCopyWithImpl<$Res> extends _$MapSearchStateCopyWithImpl<$Res> + implements $IdleCopyWith<$Res> { + _$IdleCopyWithImpl(Idle _value, $Res Function(Idle) _then) + : super(_value, (v) => _then(v as Idle)); + + @override + Idle get _value => super._value as Idle; +} + +/// @nodoc +class _$Idle implements Idle { + const _$Idle(); + + @override + String toString() { + return 'MapSearchState.idle()'; + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || (other is Idle); + } + + @override + int get hashCode => runtimeType.hashCode; + + @override + @optionalTypeArgs + TResult when({ + required TResult Function() idle, + required TResult Function() loading, + required TResult Function(List data) getPlacesDone, + required TResult Function(List? data) getExactPlacesDone, + required TResult Function(NetworkExceptions error) error, + }) { + return idle(); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? idle, + TResult Function()? loading, + TResult Function(List data)? getPlacesDone, + TResult Function(List? data)? getExactPlacesDone, + TResult Function(NetworkExceptions error)? error, + required TResult orElse(), + }) { + if (idle != null) { + return idle(); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(Idle value) idle, + required TResult Function(Loading value) loading, + required TResult Function(GetPlacesDone value) getPlacesDone, + required TResult Function(GetExactPlacesDone value) getExactPlacesDone, + required TResult Function(Error value) error, + }) { + return idle(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(Idle value)? idle, + TResult Function(Loading value)? loading, + TResult Function(GetPlacesDone value)? getPlacesDone, + TResult Function(GetExactPlacesDone value)? getExactPlacesDone, + TResult Function(Error value)? error, + required TResult orElse(), + }) { + if (idle != null) { + return idle(this); + } + return orElse(); + } +} + +abstract class Idle implements MapSearchState { + const factory Idle() = _$Idle; +} + +/// @nodoc +abstract class $LoadingCopyWith<$Res> { + factory $LoadingCopyWith(Loading value, $Res Function(Loading) then) = + _$LoadingCopyWithImpl<$Res>; +} + +/// @nodoc +class _$LoadingCopyWithImpl<$Res> extends _$MapSearchStateCopyWithImpl<$Res> + implements $LoadingCopyWith<$Res> { + _$LoadingCopyWithImpl(Loading _value, $Res Function(Loading) _then) + : super(_value, (v) => _then(v as Loading)); + + @override + Loading get _value => super._value as Loading; +} + +/// @nodoc +class _$Loading implements Loading { + const _$Loading(); + + @override + String toString() { + return 'MapSearchState.loading()'; + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || (other is Loading); + } + + @override + int get hashCode => runtimeType.hashCode; + + @override + @optionalTypeArgs + TResult when({ + required TResult Function() idle, + required TResult Function() loading, + required TResult Function(List data) getPlacesDone, + required TResult Function(List? data) getExactPlacesDone, + required TResult Function(NetworkExceptions error) error, + }) { + return loading(); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? idle, + TResult Function()? loading, + TResult Function(List data)? getPlacesDone, + TResult Function(List? data)? getExactPlacesDone, + TResult Function(NetworkExceptions error)? error, + required TResult orElse(), + }) { + if (loading != null) { + return loading(); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(Idle value) idle, + required TResult Function(Loading value) loading, + required TResult Function(GetPlacesDone value) getPlacesDone, + required TResult Function(GetExactPlacesDone value) getExactPlacesDone, + required TResult Function(Error value) error, + }) { + return loading(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(Idle value)? idle, + TResult Function(Loading value)? loading, + TResult Function(GetPlacesDone value)? getPlacesDone, + TResult Function(GetExactPlacesDone value)? getExactPlacesDone, + TResult Function(Error value)? error, + required TResult orElse(), + }) { + if (loading != null) { + return loading(this); + } + return orElse(); + } +} + +abstract class Loading implements MapSearchState { + const factory Loading() = _$Loading; +} + +/// @nodoc +abstract class $GetPlacesDoneCopyWith<$Res> { + factory $GetPlacesDoneCopyWith( + GetPlacesDone value, $Res Function(GetPlacesDone) then) = + _$GetPlacesDoneCopyWithImpl<$Res>; + $Res call({List data}); +} + +/// @nodoc +class _$GetPlacesDoneCopyWithImpl<$Res> + extends _$MapSearchStateCopyWithImpl<$Res> + implements $GetPlacesDoneCopyWith<$Res> { + _$GetPlacesDoneCopyWithImpl( + GetPlacesDone _value, $Res Function(GetPlacesDone) _then) + : super(_value, (v) => _then(v as GetPlacesDone)); + + @override + GetPlacesDone get _value => super._value as GetPlacesDone; + + @override + $Res call({ + Object? data = freezed, + }) { + return _then(GetPlacesDone( + data == freezed + ? _value.data + : data // ignore: cast_nullable_to_non_nullable + as List, + )); + } +} + +/// @nodoc +class _$GetPlacesDone implements GetPlacesDone { + const _$GetPlacesDone(this.data); + + @override + final List data; + + @override + String toString() { + return 'MapSearchState.getPlacesDone(data: $data)'; + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || + (other is GetPlacesDone && + (identical(other.data, data) || + const DeepCollectionEquality().equals(other.data, data))); + } + + @override + int get hashCode => + runtimeType.hashCode ^ const DeepCollectionEquality().hash(data); + + @JsonKey(ignore: true) + @override + $GetPlacesDoneCopyWith get copyWith => + _$GetPlacesDoneCopyWithImpl(this, _$identity); + + @override + @optionalTypeArgs + TResult when({ + required TResult Function() idle, + required TResult Function() loading, + required TResult Function(List data) getPlacesDone, + required TResult Function(List? data) getExactPlacesDone, + required TResult Function(NetworkExceptions error) error, + }) { + return getPlacesDone(data); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? idle, + TResult Function()? loading, + TResult Function(List data)? getPlacesDone, + TResult Function(List? data)? getExactPlacesDone, + TResult Function(NetworkExceptions error)? error, + required TResult orElse(), + }) { + if (getPlacesDone != null) { + return getPlacesDone(data); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(Idle value) idle, + required TResult Function(Loading value) loading, + required TResult Function(GetPlacesDone value) getPlacesDone, + required TResult Function(GetExactPlacesDone value) getExactPlacesDone, + required TResult Function(Error value) error, + }) { + return getPlacesDone(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(Idle value)? idle, + TResult Function(Loading value)? loading, + TResult Function(GetPlacesDone value)? getPlacesDone, + TResult Function(GetExactPlacesDone value)? getExactPlacesDone, + TResult Function(Error value)? error, + required TResult orElse(), + }) { + if (getPlacesDone != null) { + return getPlacesDone(this); + } + return orElse(); + } +} + +abstract class GetPlacesDone implements MapSearchState { + const factory GetPlacesDone(List data) = _$GetPlacesDone; + + List get data => throw _privateConstructorUsedError; + @JsonKey(ignore: true) + $GetPlacesDoneCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $GetExactPlacesDoneCopyWith<$Res> { + factory $GetExactPlacesDoneCopyWith( + GetExactPlacesDone value, $Res Function(GetExactPlacesDone) then) = + _$GetExactPlacesDoneCopyWithImpl<$Res>; + $Res call({List? data}); +} + +/// @nodoc +class _$GetExactPlacesDoneCopyWithImpl<$Res> + extends _$MapSearchStateCopyWithImpl<$Res> + implements $GetExactPlacesDoneCopyWith<$Res> { + _$GetExactPlacesDoneCopyWithImpl( + GetExactPlacesDone _value, $Res Function(GetExactPlacesDone) _then) + : super(_value, (v) => _then(v as GetExactPlacesDone)); + + @override + GetExactPlacesDone get _value => super._value as GetExactPlacesDone; + + @override + $Res call({ + Object? data = freezed, + }) { + return _then(GetExactPlacesDone( + data == freezed + ? _value.data + : data // ignore: cast_nullable_to_non_nullable + as List?, + )); + } +} + +/// @nodoc +class _$GetExactPlacesDone implements GetExactPlacesDone { + const _$GetExactPlacesDone(this.data); + + @override + final List? data; + + @override + String toString() { + return 'MapSearchState.getExactPlacesDone(data: $data)'; + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || + (other is GetExactPlacesDone && + (identical(other.data, data) || + const DeepCollectionEquality().equals(other.data, data))); + } + + @override + int get hashCode => + runtimeType.hashCode ^ const DeepCollectionEquality().hash(data); + + @JsonKey(ignore: true) + @override + $GetExactPlacesDoneCopyWith get copyWith => + _$GetExactPlacesDoneCopyWithImpl(this, _$identity); + + @override + @optionalTypeArgs + TResult when({ + required TResult Function() idle, + required TResult Function() loading, + required TResult Function(List data) getPlacesDone, + required TResult Function(List? data) getExactPlacesDone, + required TResult Function(NetworkExceptions error) error, + }) { + return getExactPlacesDone(data); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? idle, + TResult Function()? loading, + TResult Function(List data)? getPlacesDone, + TResult Function(List? data)? getExactPlacesDone, + TResult Function(NetworkExceptions error)? error, + required TResult orElse(), + }) { + if (getExactPlacesDone != null) { + return getExactPlacesDone(data); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(Idle value) idle, + required TResult Function(Loading value) loading, + required TResult Function(GetPlacesDone value) getPlacesDone, + required TResult Function(GetExactPlacesDone value) getExactPlacesDone, + required TResult Function(Error value) error, + }) { + return getExactPlacesDone(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(Idle value)? idle, + TResult Function(Loading value)? loading, + TResult Function(GetPlacesDone value)? getPlacesDone, + TResult Function(GetExactPlacesDone value)? getExactPlacesDone, + TResult Function(Error value)? error, + required TResult orElse(), + }) { + if (getExactPlacesDone != null) { + return getExactPlacesDone(this); + } + return orElse(); + } +} + +abstract class GetExactPlacesDone implements MapSearchState { + const factory GetExactPlacesDone(List? data) = + _$GetExactPlacesDone; + + List? get data => throw _privateConstructorUsedError; + @JsonKey(ignore: true) + $GetExactPlacesDoneCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $ErrorCopyWith<$Res> { + factory $ErrorCopyWith(Error value, $Res Function(Error) then) = + _$ErrorCopyWithImpl<$Res>; + $Res call({NetworkExceptions error}); + + $NetworkExceptionsCopyWith<$Res> get error; +} + +/// @nodoc +class _$ErrorCopyWithImpl<$Res> extends _$MapSearchStateCopyWithImpl<$Res> + implements $ErrorCopyWith<$Res> { + _$ErrorCopyWithImpl(Error _value, $Res Function(Error) _then) + : super(_value, (v) => _then(v as Error)); + + @override + Error get _value => super._value as Error; + + @override + $Res call({ + Object? error = freezed, + }) { + return _then(Error( + error == freezed + ? _value.error + : error // ignore: cast_nullable_to_non_nullable + as NetworkExceptions, + )); + } + + @override + $NetworkExceptionsCopyWith<$Res> get error { + return $NetworkExceptionsCopyWith<$Res>(_value.error, (value) { + return _then(_value.copyWith(error: value)); + }); + } +} + +/// @nodoc +class _$Error implements Error { + const _$Error(this.error); + + @override + final NetworkExceptions error; + + @override + String toString() { + return 'MapSearchState.error(error: $error)'; + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || + (other is Error && + (identical(other.error, error) || + const DeepCollectionEquality().equals(other.error, error))); + } + + @override + int get hashCode => + runtimeType.hashCode ^ const DeepCollectionEquality().hash(error); + + @JsonKey(ignore: true) + @override + $ErrorCopyWith get copyWith => + _$ErrorCopyWithImpl(this, _$identity); + + @override + @optionalTypeArgs + TResult when({ + required TResult Function() idle, + required TResult Function() loading, + required TResult Function(List data) getPlacesDone, + required TResult Function(List? data) getExactPlacesDone, + required TResult Function(NetworkExceptions error) error, + }) { + return error(this.error); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? idle, + TResult Function()? loading, + TResult Function(List data)? getPlacesDone, + TResult Function(List? data)? getExactPlacesDone, + TResult Function(NetworkExceptions error)? error, + required TResult orElse(), + }) { + if (error != null) { + return error(this.error); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(Idle value) idle, + required TResult Function(Loading value) loading, + required TResult Function(GetPlacesDone value) getPlacesDone, + required TResult Function(GetExactPlacesDone value) getExactPlacesDone, + required TResult Function(Error value) error, + }) { + return error(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(Idle value)? idle, + TResult Function(Loading value)? loading, + TResult Function(GetPlacesDone value)? getPlacesDone, + TResult Function(GetExactPlacesDone value)? getExactPlacesDone, + TResult Function(Error value)? error, + required TResult orElse(), + }) { + if (error != null) { + return error(this); + } + return orElse(); + } +} + +abstract class Error implements MapSearchState { + const factory Error(NetworkExceptions error) = _$Error; + + NetworkExceptions get error => throw _privateConstructorUsedError; + @JsonKey(ignore: true) + $ErrorCopyWith get copyWith => throw _privateConstructorUsedError; +} diff --git a/lib/blocs/capture/pageCubit/CapturePageCubit.dart b/lib/blocs/capture/pageCubit/CapturePageCubit.dart new file mode 100644 index 0000000..32ba678 --- /dev/null +++ b/lib/blocs/capture/pageCubit/CapturePageCubit.dart @@ -0,0 +1,25 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; + +class CapturePageCubit extends Cubit { + PageController pageController = PageController(); + String title; + final initialPage; + final keepPage; + final viewportFraction; + + CapturePageCubit({this.title = 'Upload photos', this.initialPage = 0, this.keepPage = true, this.viewportFraction = 1.0}) : super(initialPage) { + pageController = PageController(initialPage: initialPage, keepPage: keepPage, viewportFraction: viewportFraction); + } + + void updatePageState(int index) { + if (state == index) return; + pageController.animateToPage(index, duration: Duration(milliseconds: 1), curve: Curves.easeInOutSine); + updateTitle(index); + emit(index); + } + + void updateTitle(int index) { + index == 0 ? title = 'Upload photos': title = 'Upload Details' ; + } +} diff --git a/lib/blocs/confirmDelete/DeleteCubit.dart b/lib/blocs/confirmDelete/DeleteCubit.dart new file mode 100644 index 0000000..afb99de --- /dev/null +++ b/lib/blocs/confirmDelete/DeleteCubit.dart @@ -0,0 +1,13 @@ +import 'package:flutter_bloc/flutter_bloc.dart'; + +class DeleteCubit extends Cubit { + + bool initialState; + DeleteCubit({this.initialState = false}) : super(initialState); + + void updatePageState(bool delete) { + if(delete == false)return; + initialState = delete; + emit(delete); + } +} diff --git a/lib/blocs/dynamic_links/DynamicCubit.dart b/lib/blocs/dynamic_links/DynamicCubit.dart new file mode 100644 index 0000000..e079252 --- /dev/null +++ b/lib/blocs/dynamic_links/DynamicCubit.dart @@ -0,0 +1,60 @@ +import 'package:bloc/bloc.dart'; +import 'package:equatable/equatable.dart'; +import 'package:firebase_dynamic_links/firebase_dynamic_links.dart'; +import 'package:formz/formz.dart'; + +part 'DynamicState.dart'; + +class DynamicCubit extends Cubit { + DynamicCubit() : super(DynamicState()); + + + void initDynamicLinks() async{ + + emit(state.copyWith(status: FormzStatus.submissionInProgress)); + final PendingDynamicLinkData? data = await FirebaseDynamicLinks.instance.getInitialLink(); + final Uri? deepLink = data?.link; + + if(deepLink != null){ + if(deepLink.queryParameters.containsKey('route')){ + emit(state.copyWith( route: deepLink.queryParameters['route'],data: deepLink.queryParameters.containsKey('email') ? deepLink.queryParameters['email'] : deepLink.queryParameters['id'], status: FormzStatus.submissionSuccess, home: false)); + } + } + + FirebaseDynamicLinks.instance.onLink( + onSuccess: (PendingDynamicLinkData? dynamicLink) async { + final Uri? deepLink = dynamicLink?.link; + if(deepLink != null){ + if(deepLink.queryParameters.containsKey('route')) { + emit(state.copyWith( route: deepLink.queryParameters['route'],data: deepLink.queryParameters.containsKey('email') ? deepLink.queryParameters['email'] : deepLink.queryParameters['id'], status: FormzStatus.submissionSuccess,home: false)); + } + } + }, + onError: (OnLinkErrorException e) async { + emit(state.copyWith( status: FormzStatus.submissionFailure)); + } + ); + } + + void createDynamicLink(String data, bool forgot) async { + emit(state.copyWith(status:FormzStatus.submissionInProgress)); + final DynamicLinkParameters parameters = DynamicLinkParameters( + uriPrefix: 'https://gspotter.page.link', + link: forgot == true ? Uri.parse('https://gspotter.page.link.com?route=ResetPassword&email=$data') + : Uri.parse('https://gspotter.page.link.com?route=GiraffeProfilePage&id=$data'), + androidParameters: AndroidParameters(packageName: 'ax.synt.giraffe_spotter'), + iosParameters: IosParameters(bundleId: 'ax.synt.giraffeSpotter') + ); + + final ShortDynamicLink shorty = await parameters.buildShortLink(); + + final Uri shortUrl = shorty.shortUrl; + + emit(state.copyWith(status: FormzStatus.submissionSuccess,shorturl: shortUrl, home: true)); + + } + + void stateChanger() async { + emit(state.copyWith(status: FormzStatus.submissionFailure)); + } +} diff --git a/lib/blocs/dynamic_links/DynamicState.dart b/lib/blocs/dynamic_links/DynamicState.dart new file mode 100644 index 0000000..ca45526 --- /dev/null +++ b/lib/blocs/dynamic_links/DynamicState.dart @@ -0,0 +1,24 @@ +part of 'DynamicCubit.dart'; + +class DynamicState extends Equatable{ + + final FormzStatus status; + final String? route; + final String? data; + final Uri? shorturl; + final bool? home; + + const DynamicState({ + this.status = FormzStatus.pure, + this.home = false, + this.route, + this.data, + this.shorturl, + }); + + @override + List get props => [ status,route,shorturl,data,home]; + + DynamicState copyWith({FormzStatus? status,bool? home, String? route,String? data, Uri? shorturl}) => DynamicState(data: data, status: status ?? this.status, route: route, shorturl: shorturl, home: home); + +} diff --git a/lib/blocs/edit_profile/PasswordCubit.dart b/lib/blocs/edit_profile/PasswordCubit.dart new file mode 100644 index 0000000..6c464b0 --- /dev/null +++ b/lib/blocs/edit_profile/PasswordCubit.dart @@ -0,0 +1,8 @@ +import 'package:flutter_bloc/flutter_bloc.dart'; + +class PasswordCubit extends Cubit { + + PasswordCubit(bool initialState) : super(initialState); + + void toggleVisibility()=> emit(!state); +} \ No newline at end of file diff --git a/lib/blocs/edit_profile/UpdateProfileCubit.dart b/lib/blocs/edit_profile/UpdateProfileCubit.dart new file mode 100644 index 0000000..a506604 --- /dev/null +++ b/lib/blocs/edit_profile/UpdateProfileCubit.dart @@ -0,0 +1,132 @@ +import 'dart:io'; + +import 'package:flutter/cupertino.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:flutter_smartlook/flutter_smartlook.dart'; +import 'package:formz/formz.dart'; +import 'package:giraffe_spotter/blocs/edit_profile/UpdateProfileState.dart'; +import 'package:giraffe_spotter/config/AppRoute.dart'; +import 'package:giraffe_spotter/config/Constants.dart'; +import 'package:giraffe_spotter/config/ServiceLocator.dart'; +import 'package:giraffe_spotter/inputs/authentication/Email.dart'; +import 'package:giraffe_spotter/inputs/authentication/Name.dart'; +import 'package:giraffe_spotter/models/User.dart'; +import 'package:giraffe_spotter/network/ApiResult.dart'; +import 'package:giraffe_spotter/network/NetworkExceptions.dart'; +import 'package:giraffe_spotter/pages/authentication/Login.dart'; +import 'package:giraffe_spotter/repositories/UpdateProfileRepository.dart'; +import 'package:giraffe_spotter/utils/SharedObjects.dart'; + +class UpdateProfileCubit extends Cubit { + UpdateProfileCubit(this.repository) : super(UpdateProfileState()); + final UpdateProfileRepository repository; + String? errorMessage; + late NetworkExceptions? failureReason; + + void nameChanged(String value, bool show) { + final name = Name.dirty(value); + emit(state.copyWith(fullName: name, show: show, status: Formz.validate([state.email, name]))); + } + + void emailChanged(String value, bool show) { + final email = Email.dirty(value); + emit(state.copyWith(email: email, show: show, status: Formz.validate([state.fullName, email]))); + } + + void validateBeforeUpdateProfile() { + final email = Email.dirty(state.email.value); + final name = Name.dirty(state.fullName.value); + emit(state.copyWith(email: email, fullName: name)); + } + + Future updateProfile() async { + emit(state.copyWith(status: Formz.validate([state.fullName, state.email]))); + if (!state.status.isValidated) return; + emit(state.copyWith(status: FormzStatus.submissionInProgress)); + ApiResult result = await repository.updateProfile( + fullName: state.fullName.value, + email: state.email.value, + ); + + result.when(success: (User? user) async { + await SharedObjects.prefs!.setString(Constants.userEmail, user!.email.toString()); + await SharedObjects.prefs!.setString(Constants.name, user.name.toString()); + emit(state.copyWith(status: FormzStatus.submissionSuccess, user: user)); + }, failure: (NetworkExceptions? error) { + failureReason = error!; + error.maybeWhen( + unProcessableEntity: (Map errors) { + errorMessage = errors['message']; + emit(state.copyWith( + status: FormzStatus.submissionFailure, + error: error, + errors: (errors['errors'] as Map).map((key, value) => MapEntry(key, (value as List).map((e) => e).toList())))); + }, + unauthenticatedRequest: () { + emit(state.copyWith(status: FormzStatus.submissionFailure)); + locator!().navigateAndRemoveUntil(Login()); + }, + orElse: () { + errorMessage = 'Error occurred while submitting your request. Please try again.'; + emit(state.copyWith(status: FormzStatus.submissionFailure, error: error)); + }, + ); + }); + } + + Future deleteProfile(String uuid) async { + emit(state.copyWith(status: FormzStatus.submissionInProgress)); + ApiResult result = await repository.deleteProfile(uuid: uuid); + result.when(success: (_) async { + emit(state.copyWith(status: FormzStatus.submissionSuccess)); + await SharedObjects.prefs!.clearAll(); + }, failure: (NetworkExceptions? e) { + e!.maybeWhen( + unProcessableEntity: (Map errors) { + errorMessage = errors['message']; + emit(state.copyWith( + status: FormzStatus.submissionFailure, + error: e, + errors: (errors['errors'] as Map).map((key, value) => MapEntry(key, (value as List).map((e) => e).toList())))); + }, + unauthenticatedRequest: () { + emit(state.copyWith(status: FormzStatus.submissionFailure)); + locator!().navigateAndRemoveUntil(Login()); + }, + orElse: () { + debugPrint(e.toString()); + errorMessage = 'Error occurred while submitting your request. Please try again.'; + emit(state.copyWith(status: FormzStatus.submissionFailure, error: e)); + }, + ); + }); + } + + Future updateImage(File image) async { + emit(state.copyWith(status: FormzStatus.submissionInProgress, image: true)); + ApiResult result = await repository.updateImage(image: image); + result.when(success: (user) async { + await SharedObjects.prefs!.setString(Constants.userEmail, user!.email.toString()); + await SharedObjects.prefs!.setString(Constants.name, user.name.toString()); + await SharedObjects.prefs!.setString(Constants.userImage, user.profile_image.toString()); + Smartlook.setUserIdentifier(user.email.toString()); + emit(state.copyWith(status: FormzStatus.submissionSuccess, user: user, image: false)); + }, failure: (error) { + error!.maybeWhen( + unProcessableEntity: (Map errors) { + errorMessage = errors['message']; + emit(state.copyWith( + status: FormzStatus.submissionFailure, + error: error, + image: false, + errors: (errors['errors'] as Map).map((key, value) => MapEntry(key, (value as List).map((e) => e).toList())))); + }, + orElse: () { + debugPrint(error.toString()); + errorMessage = 'Error occurred while submitting your request. Please try again.'; + emit(state.copyWith(status: FormzStatus.submissionFailure, error: error, image: false)); + }, + ); + }); + } +} diff --git a/lib/blocs/edit_profile/UpdateProfileState.dart b/lib/blocs/edit_profile/UpdateProfileState.dart new file mode 100644 index 0000000..6778210 --- /dev/null +++ b/lib/blocs/edit_profile/UpdateProfileState.dart @@ -0,0 +1,49 @@ +import 'package:equatable/equatable.dart'; +import 'package:formz/formz.dart'; +import 'package:giraffe_spotter/inputs/authentication/Email.dart'; +import 'package:giraffe_spotter/inputs/authentication/Name.dart'; +import 'package:giraffe_spotter/models/User.dart'; +import 'package:giraffe_spotter/network/NetworkExceptions.dart'; + +class UpdateProfileState extends Equatable { + UpdateProfileState({ + this.email = const Email.pure(), + this.fullName = const Name.pure(), + this.status = FormzStatus.pure, + this.user = User.empty, + this.show = false, + this.image = false, + this.error, + this.errors, + }); + final Email email; + final bool? show,image; + final Name fullName; + final FormzStatus status; + final User user; + final NetworkExceptions? error; + final Map>? errors; + + @override + List get props => [email, show,image, fullName, status, user, errors]; + UpdateProfileState copyWith({ + Name? fullName, + Email? email, + bool? image, + FormzStatus? status, + User? user, + bool? show, + NetworkExceptions? error, + Map>? errors, + }) => + UpdateProfileState( + fullName: fullName ?? this.fullName, + email: email ?? this.email, + status: status ?? this.status, + user: user ?? this.user, + error: error, + image: image, + show: show, + errors: errors, + ); +} diff --git a/lib/blocs/exceptions/ExceptionsBloc.dart b/lib/blocs/exceptions/ExceptionsBloc.dart new file mode 100644 index 0000000..00a8c0d --- /dev/null +++ b/lib/blocs/exceptions/ExceptionsBloc.dart @@ -0,0 +1,19 @@ +import 'package:flutter_bloc/flutter_bloc.dart'; + +import 'ExceptionsEvent.dart'; +import 'ExceptionsState.dart'; + +class ExceptionsBloc extends Bloc { + ExceptionsBloc() : super(ExceptionsState()); + + @override + Stream mapEventToState(ExceptionsEvent event) async* { + if (event is OnException) { + yield* event.error.maybeWhen( + unauthenticatedRequest: () async* { + yield UnAuthenticatedError(); + }, + orElse: () async* {}); + } + } +} diff --git a/lib/blocs/exceptions/ExceptionsEvent.dart b/lib/blocs/exceptions/ExceptionsEvent.dart new file mode 100644 index 0000000..ab50c50 --- /dev/null +++ b/lib/blocs/exceptions/ExceptionsEvent.dart @@ -0,0 +1,18 @@ +import 'package:equatable/equatable.dart'; +import 'package:giraffe_spotter/network/NetworkExceptions.dart'; + +class ExceptionsEvent extends Equatable { + const ExceptionsEvent(); + + @override + List get props => []; +} + +class OnException extends ExceptionsEvent { + final NetworkExceptions error; + + const OnException(this.error); + + @override + List get props => [error]; +} diff --git a/lib/blocs/exceptions/ExceptionsState.dart b/lib/blocs/exceptions/ExceptionsState.dart new file mode 100644 index 0000000..1b0294a --- /dev/null +++ b/lib/blocs/exceptions/ExceptionsState.dart @@ -0,0 +1,8 @@ +import 'package:equatable/equatable.dart'; + +class ExceptionsState extends Equatable { + @override + List get props => []; +} + +class UnAuthenticatedError extends ExceptionsState {} diff --git a/lib/blocs/filterGiraffes/FilterCubit.dart b/lib/blocs/filterGiraffes/FilterCubit.dart new file mode 100644 index 0000000..5bdbb24 --- /dev/null +++ b/lib/blocs/filterGiraffes/FilterCubit.dart @@ -0,0 +1,42 @@ +import 'package:bloc/bloc.dart'; +import 'package:formz/formz.dart'; +import 'package:giraffe_spotter/blocs/filterGiraffes/FilterState.dart'; +import 'package:giraffe_spotter/models/FilterFile.dart'; +import 'package:giraffe_spotter/models/Species.dart' as Spec; +import 'package:giraffe_spotter/network/ApiResult.dart'; +import 'package:giraffe_spotter/network/NetworkExceptions.dart'; +import 'package:giraffe_spotter/providers/FilterProvider.dart'; + + +class FilterCubit extends Cubit { + FilterCubit(this.filterProvider) : super(FilterState()); + + FilterProvider filterProvider = FilterProvider(); + + Future getFilterData() async{ + emit(state.copyWith(status: FormzStatus.submissionInProgress)); + ApiResult result = await filterProvider.getConfig(); + result.when(success: (_) { + retrieveData(_); + }, failure: (NetworkExceptions? error) { + emit(state.copyWith(status: FormzStatus.submissionFailure)); + }); + } + + retrieveData(FilterFile? filterFile) + { + List>? data = []; + data.add({true: Spec.Species(name: 'Select All', value: 'Select All')}); + filterFile!.locationID!.map((e) { + var name = e.name; + var id = e.id; + data.add({true: Spec.Species(name: name.toString(), value: id.toString())}); + if(e.locationID != null) { + e.locationID!.map((e) { + data.add({false : Spec.Species(name: e.name.toString(), value: e.id.toString())}); + }).toList(); + } + }).toList(); + emit(state.copyWith(status: FormzStatus.submissionSuccess, filterFile: data)); + } +} diff --git a/lib/blocs/filterGiraffes/FilterState.dart b/lib/blocs/filterGiraffes/FilterState.dart new file mode 100644 index 0000000..36c1bc5 --- /dev/null +++ b/lib/blocs/filterGiraffes/FilterState.dart @@ -0,0 +1,21 @@ +import 'package:equatable/equatable.dart'; +import 'package:formz/formz.dart'; +import 'package:giraffe_spotter/models/Species.dart'; + + +class FilterState extends Equatable{ + + FilterState({ + this.status = FormzStatus.pure, + this.filterFile + }); + + final FormzStatus status; + final List>? filterFile; + + @override + List get props => [status, filterFile]; + + FilterState copyWith({FormzStatus? status, List>? filterFile}) => + FilterState(status: status ?? this.status, filterFile: filterFile); +} diff --git a/lib/blocs/giraffe_profile/FilterGiraffesCubit.dart b/lib/blocs/giraffe_profile/FilterGiraffesCubit.dart new file mode 100644 index 0000000..84f6381 --- /dev/null +++ b/lib/blocs/giraffe_profile/FilterGiraffesCubit.dart @@ -0,0 +1,166 @@ +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:formz/formz.dart'; +import 'package:giraffe_spotter/config/Constants.dart'; +import 'package:giraffe_spotter/models/GiraffeData.dart'; +import 'package:giraffe_spotter/network/ApiResult.dart'; +import 'package:giraffe_spotter/network/NetworkExceptions.dart'; +import 'package:giraffe_spotter/repositories/GiraffeProfileRepository.dart'; +import 'package:giraffe_spotter/utils/SharedObjects.dart'; +import 'package:shared_preferences/shared_preferences.dart'; + +import 'FliterGiraffesState.dart'; + +class FilterGiraffesCubit extends Cubit { + FilterGiraffesCubit(this.repository) : super(FilterGiraffesState()); + final GiraffeProfileRepository repository; + String? errorMessage; + late NetworkExceptions? failureReason; + Map filterTempData = {}; + + void onAgeChanged(ageStart, ageEnd) { + emit(state.copyWith(ageEnd: ageEnd, ageStart: ageStart)); + } + + void onSpeciesChanged(String value) { + final species = value; + emit(state.copyWith(species: species)); + } + + void onLocationChanged(String value) { + final location = value.trim(); + + emit(state.copyWith(location: location)); + } + + void onSearchChanged(String value) { + final search = value; + emit(state.copyWith(search: search)); + } + + void onFemaleChanged(bool status) { + emit(state.copyWith( + gender: status ? 'f' : '', + femaleStatus: status, + maleStatus: false, + unknownStatus: false)); + } + + void onMaleChanged(bool status) { + emit(state.copyWith( + gender: status ? 'm' : '', + maleStatus: status, + femaleStatus: false, + unknownStatus: false)); + } + + void onUnknownChanged(bool status) { + emit(state.copyWith( + gender: status ? 'u' : '', + unknownStatus: status, + maleStatus: false, + femaleStatus: false)); + } + + Future filterGiraffes() async { + emit(state.copyWith(status: FormzStatus.submissionInProgress)); + tempStore( + state.ageStart.toInt(), + state.ageEnd.toInt(), + state.location == 'Select All' ? 'Select All' : state.location, + state.species == 'Select All' ? 'Select All' : state.species, + state.gender); + ApiResult> result = await repository.filteredGiraffes( + ageStart: state.ageStart.toInt().toString(), + ageEnd: state.ageEnd.toInt().toString(), + species: state.species == 'Select All' ? '' : state.species, + location: state.location == 'Select All' ? '' : state.location, + gender: state.gender); + result.when(success: (giraffes) { + emit(state.copyWith( + status: FormzStatus.submissionSuccess, filteredGiraffes: giraffes)); + }, failure: (NetworkExceptions? error) { + error?.maybeWhen( + unProcessableEntity: (Map errors) { + errorMessage = errors['message']; + emit( + state.copyWith( + status: FormzStatus.submissionFailure, + formErrors: (errors['errors'] as Map).map( + (key, value) => MapEntry( + key, + (value as List).map((e) => e as String).toList(), + ), + ), + ), + ); + }, + orElse: () { + errorMessage = + 'Error occurred while submitting your request. Please try again.'; + emit(state.copyWith(status: FormzStatus.submissionFailure)); + }, + ); + }); + } + + void filteredGiraffeResult(List? filteredResult) { + emit(state.copyWith( + status: FormzStatus.submissionSuccess, + filteredGiraffes: filteredResult)); + } + + void returnDefault() async { + clearStore(); + emit(state.copyWith( + ageStart: 1, + ageEnd: 100, + location: 'Select All', + species: 'Select All', + unknownStatus: false, + femaleStatus: false, + maleStatus: false)); + } + + void refresh() async { + emit(state.copyWith()); + } + + void tempStore(int ageStart, int ageEnd, String location, String species, + String gender) async { + await SharedObjects.prefs!.setInt(Constants.ageStart, ageStart); + await SharedObjects.prefs!.setInt(Constants.ageEnd, ageEnd); + await SharedObjects.prefs!.setString(Constants.location, location); + await SharedObjects.prefs!.setString(Constants.species, species); + await SharedObjects.prefs!.setString(Constants.gender, gender); + + filterTempData['ageStart'] = ageStart; + filterTempData['ageEnd'] = ageEnd; + filterTempData['location'] = location; + filterTempData['species'] = species; + filterTempData['gender'] = gender; + print(filterTempData.toString()); + } + + void clearStore() { + filterTempData.clear(); + print(filterTempData.toString()); + } + + void accesStore() async { + print(filterTempData.toString()); + final String? location; + final String? species; + final String? gender; + final int? ageStart; + final int? ageEnd; + + location = SharedObjects.prefs!.getString(Constants.location); + species = SharedObjects.prefs!.getString(Constants.species); + gender = SharedObjects.prefs!.getString(Constants.gender); + ageEnd = SharedObjects.prefs!.getInt(Constants.ageEnd); + ageStart = SharedObjects.prefs!.getInt(Constants.ageStart); + + print('location $location species $species gender $gender ageEnd $ageEnd ageStart $ageStart'); + emit(state.copyWith(gender: gender, species: species, location: location, ageEnd: ageEnd, ageStart: ageStart,maleStatus: gender == 'm'? true: false,femaleStatus: gender == 'f'? true: false,unknownStatus: gender == 'u'? true: false)); + } +} diff --git a/lib/blocs/giraffe_profile/FliterGiraffesState.dart b/lib/blocs/giraffe_profile/FliterGiraffesState.dart new file mode 100644 index 0000000..be5b485 --- /dev/null +++ b/lib/blocs/giraffe_profile/FliterGiraffesState.dart @@ -0,0 +1,61 @@ +import 'package:equatable/equatable.dart'; +import 'package:flutter/material.dart'; +import 'package:formz/formz.dart'; +import 'package:giraffe_spotter/models/GiraffeData.dart'; + +class FilterGiraffesState extends Equatable { + FilterGiraffesState( + {this.gender = '', + this.ageStart = 1, + this.ageEnd = 100, + this.location = 'Select All', + this.species = 'Select All', + this.search = '', + this.formErrors, + this.filteredGiraffes, + this.status = FormzStatus.pure, + this.femaleStatus = false, + this.unknownStatus = false, + this.maleStatus = false}); + + final String gender, location, species, search; + final int ageStart; + final int ageEnd; + final Map>? formErrors; + final List? filteredGiraffes; + final bool femaleStatus, maleStatus, unknownStatus; + final FormzStatus status; + + @override + List get props => + [gender, ageStart, ageEnd, formErrors, location, filteredGiraffes, femaleStatus, species, maleStatus, search, status, unknownStatus]; + + FilterGiraffesState copyWith({ + String? gender, + RangeValues? age, + int? ageStart, + int? ageEnd, + FormzStatus? status, + String? search, + Map>? formErrors, + String? species, + String? location, + List? filteredGiraffes, + bool? femaleStatus, + bool? maleStatus, + bool? unknownStatus, + }) => + FilterGiraffesState( + gender: gender ?? this.gender, + formErrors: formErrors, + species: species ?? this.species, + location: location ?? this.location, + search: search ?? this.search, + status: status ?? this.status, + filteredGiraffes: filteredGiraffes, + femaleStatus: femaleStatus ?? this.femaleStatus, + ageEnd: ageEnd ?? this.ageEnd, + ageStart: ageStart ?? this.ageStart, + unknownStatus: unknownStatus ?? this.unknownStatus, + maleStatus: maleStatus ?? this.maleStatus); +} diff --git a/lib/blocs/giraffe_profile/GiraffeProfileCubit.dart b/lib/blocs/giraffe_profile/GiraffeProfileCubit.dart new file mode 100644 index 0000000..0f78db6 --- /dev/null +++ b/lib/blocs/giraffe_profile/GiraffeProfileCubit.dart @@ -0,0 +1,116 @@ +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:giraffe_spotter/blocs/giraffe_profile/GiraffeProfileState.dart'; +import 'package:giraffe_spotter/config/AppRoute.dart'; +import 'package:giraffe_spotter/config/ServiceLocator.dart'; +import 'package:giraffe_spotter/models/GiraffeData.dart'; +import 'package:giraffe_spotter/network/ApiResult.dart'; +import 'package:giraffe_spotter/network/NetworkExceptions.dart'; +import 'package:giraffe_spotter/pages/authentication/Login.dart'; +import 'package:giraffe_spotter/repositories/GiraffeProfileRepository.dart'; + +class GiraffeProfileCubit extends Cubit { + GiraffeProfileCubit({required this.repository}) : super(GiraffeInitialState()) { + getGiraffes(true); + } + + final GiraffeProfileRepository repository; + String? errorMessage; + late NetworkExceptions? failureReason; + GiraffeData? singleData; + bool backing = false; + int page = 1; + + Future getGiraffes(bool home) async { + if (state is GiraffeLoadingState) return; + final currentState = state; + var oldPosts = []; + if (currentState is GiraffeLoadedState) { + oldPosts = currentState.giraffeProfiles!; + } + emit(GiraffeLoadingState(oldPosts, isFirstFetch: page == 1)); + ApiResult> result = await repository.getGiraffeProfiles(page: home == true ? 1 : page); + result.when(success: (newResult) async { + if (home == false) { + final giraffeData = (state as GiraffeLoadingState).oldGiraffeProfile; + giraffeData.addAll(newResult!); + page++; + emit(GiraffeLoadedState(giraffeProfiles: giraffeData)); + } else { + page++; + emit(GiraffeLoadedState(giraffeProfiles: newResult)); + } + }, failure: (NetworkExceptions? error) { + failureReason = error!; + error.maybeWhen( + unProcessableEntity: (Map errors) { + errorMessage = errors['message']; + emit(GiraffeErrorState( + errors: (errors['errors'] as Map).map( + (key, value) => MapEntry(key, (value as List).map((e) => e).toList()), + ))); + }, + unauthenticatedRequest: () { + GiraffeErrorState(error: error); + locator!().navigateAndRemoveUntil(Login()); + }, + orElse: () { + errorMessage = 'Error occurred while submitting your request. Please try again.'; + GiraffeErrorState(error: error); + }, + ); + }); + } + + Future updateGiraffes() async { + ApiResult> result = await repository.getGiraffeProfiles(page: page); + result.when(success: (newResult) { + final giraffeData = (state as GiraffeLoadedState).giraffeProfiles; + giraffeData!.addAll(newResult!); + print(giraffeData.length); + page++; + emit(GiraffeLoadedState(giraffeProfiles: giraffeData)); + }, failure: (NetworkExceptions? error) { + failureReason = error!; + error.maybeWhen( + unProcessableEntity: (Map errors) { + errorMessage = errors['message']; + emit(GiraffeErrorState( + errors: (errors['errors'] as Map).map( + (key, value) => MapEntry(key, (value as List).map((e) => e).toList()), + ))); + }, + orElse: () { + errorMessage = 'Error occurred while submitting your request. Please try again.'; + GiraffeErrorState(error: error); + }, + ); + }); + } + + Future setFilterData(List? data) async { + emit(GiraffeLoadedState(giraffeProfiles: data)); + } + + Future singleGiraffeData(String id) async { + ApiResult result = await repository.singleGiraffe(id: id); + result.when(success: (_){ + singleData = _; + emit(GiraffeLoadedState(singleData: _)); + }, failure:(error){ + failureReason = error!; + error.maybeWhen( + unProcessableEntity: (Map errors) { + errorMessage = errors['message']; + emit(GiraffeErrorState( + errors: (errors['errors'] as Map).map( + (key, value) => MapEntry(key, (value as List).map((e) => e).toList()), + ))); + }, + orElse: () { + errorMessage = 'Error occurred while submitting your request. Please try again.'; + GiraffeErrorState(error: error); + }, + ); + }); + } +} diff --git a/lib/blocs/giraffe_profile/GiraffeProfileState.dart b/lib/blocs/giraffe_profile/GiraffeProfileState.dart new file mode 100644 index 0000000..b954f89 --- /dev/null +++ b/lib/blocs/giraffe_profile/GiraffeProfileState.dart @@ -0,0 +1,41 @@ +import 'package:equatable/equatable.dart'; +import 'package:giraffe_spotter/models/GiraffeData.dart'; + +abstract class GiraffeProfileState extends Equatable {} + +class GiraffeInitialState extends GiraffeProfileState { + @override + List get props => []; +} + +class GiraffeLoadingState extends GiraffeProfileState { + final List oldGiraffeProfile; + final bool isFirstFetch; + + GiraffeLoadingState(this.oldGiraffeProfile, {this.isFirstFetch = false}); + + @override + List get props => []; +} + +// ignore: must_be_immutable +class GiraffeLoadedState extends GiraffeProfileState { + final List? giraffeProfiles; + final GiraffeData? singleData; + + GiraffeLoadedState({this.giraffeProfiles, this.singleData}); + + @override + List get props => [giraffeProfiles, singleData]; +} + +// ignore: must_be_immutable +class GiraffeErrorState extends GiraffeProfileState { + final error; + final errors; + + GiraffeErrorState({this.error, this.errors}); + + @override + get props => [errors, error]; +} diff --git a/lib/blocs/giraffe_profile/giraffe_fav/FavouriteCubit.dart b/lib/blocs/giraffe_profile/giraffe_fav/FavouriteCubit.dart new file mode 100644 index 0000000..30c6de3 --- /dev/null +++ b/lib/blocs/giraffe_profile/giraffe_fav/FavouriteCubit.dart @@ -0,0 +1,22 @@ +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:giraffe_spotter/blocs/giraffe_profile/giraffe_fav/FavouriteState.dart'; + +class FavouriteCubit extends Cubit { + FavouriteCubit({required this.data, required this.removed}) + : super(FavouriteState(giraffeDet: [])); + List data; + List removed = [342342432]; + + void addFav(int index) { + if(!data.contains(index)){ + data.add(index); + emit(state.copyWith(giraffeFav: data, giraffeDet: removed)); + } + } + + void remove(int index) { + data.remove(index); + removed.add(index); + emit(state.copyWith(giraffeFav: data,giraffeDet: removed)); + } +} \ No newline at end of file diff --git a/lib/blocs/giraffe_profile/giraffe_fav/FavouriteState.dart b/lib/blocs/giraffe_profile/giraffe_fav/FavouriteState.dart new file mode 100644 index 0000000..bf2d46e --- /dev/null +++ b/lib/blocs/giraffe_profile/giraffe_fav/FavouriteState.dart @@ -0,0 +1,14 @@ +import 'package:equatable/equatable.dart'; + +class FavouriteState extends Equatable { + + FavouriteState({this.giraffeFav, required this.giraffeDet}); + + final List? giraffeFav; + List giraffeDet = [2323]; + + FavouriteState copyWith({List? giraffeFav, List? giraffeDet}) => FavouriteState(giraffeFav: giraffeFav, giraffeDet: giraffeDet ?? this.giraffeDet); + + @override + List get props => [giraffeFav,giraffeDet]; +} \ No newline at end of file diff --git a/lib/blocs/giraffe_profile/giraffe_profile_search/GiraffeProfileSearchCubit.dart b/lib/blocs/giraffe_profile/giraffe_profile_search/GiraffeProfileSearchCubit.dart new file mode 100644 index 0000000..827facd --- /dev/null +++ b/lib/blocs/giraffe_profile/giraffe_profile_search/GiraffeProfileSearchCubit.dart @@ -0,0 +1,41 @@ +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:giraffe_spotter/network/NetworkExceptions.dart'; +import 'package:giraffe_spotter/repositories/GiraffeProfileRepository.dart'; + +import 'GiraffeProfileSearchState.dart'; + +class GiraffeProfileSearchCubit extends Cubit { + GiraffeProfileSearchCubit({this.keyword = '', this.dataItems}) : super(InitialSearchState()) { + searchGiraffeProfile(dataItems, keyword); + } + + List? dataItems, dataList; + String? keyword; + GiraffeProfileRepository? repository; + String? errorMessage; + late NetworkExceptions? failureReason; + + void searchGiraffeProfile(List? dataList, String? keyword) { + try { + if (dataList == null) { + print("step 1"); + emit(InitialSearchState()); + } else { + List finalList = []; + emit(LoadingSearchState()); + dataList.forEach((element) { + if (element['catalogNo'].toLowerCase().contains(keyword!.toLowerCase())) { + finalList.add(element); + } + }); + print("the list is hapa " + finalList.toString()); + emit(LoadedSearchState(dataItems: finalList)); + } + } catch (e) { + emit(ErrorSearchState(error: e)); + } + } + + // + +} diff --git a/lib/blocs/giraffe_profile/giraffe_profile_search/GiraffeProfileSearchState.dart b/lib/blocs/giraffe_profile/giraffe_profile_search/GiraffeProfileSearchState.dart new file mode 100644 index 0000000..560c87e --- /dev/null +++ b/lib/blocs/giraffe_profile/giraffe_profile_search/GiraffeProfileSearchState.dart @@ -0,0 +1,32 @@ +import 'package:equatable/equatable.dart'; + +abstract class GiraffeProfileSearchState extends Equatable { + const GiraffeProfileSearchState(); +} + +class InitialSearchState extends GiraffeProfileSearchState { + @override + List get props => []; +} + +class LoadingSearchState extends GiraffeProfileSearchState { + @override + List get props => []; +} + +class ErrorSearchState extends GiraffeProfileSearchState { + final error; + final errors; + + ErrorSearchState({this.error, this.errors}); + + @override + get props => [errors, error]; +} + +class LoadedSearchState extends GiraffeProfileSearchState { + final List dataItems; + LoadedSearchState({required this.dataItems}); + @override + List get props => [dataItems]; +} diff --git a/lib/blocs/home/BottomBarCubit.dart b/lib/blocs/home/BottomBarCubit.dart new file mode 100644 index 0000000..046bb4f --- /dev/null +++ b/lib/blocs/home/BottomBarCubit.dart @@ -0,0 +1,9 @@ +import 'package:flutter_bloc/flutter_bloc.dart'; + +class BottomBarCubit extends Cubit { + BottomBarCubit() : super(0); + + void updateIndex(int index) { + emit(index); + } +} diff --git a/lib/blocs/home/articles/ArticleBloc.dart b/lib/blocs/home/articles/ArticleBloc.dart new file mode 100644 index 0000000..b3734a3 --- /dev/null +++ b/lib/blocs/home/articles/ArticleBloc.dart @@ -0,0 +1,34 @@ +import 'dart:async'; + +import 'package:bloc/bloc.dart'; +import 'package:giraffe_spotter/models/WelcomeJson.dart'; +import 'package:giraffe_spotter/network/ApiResult.dart'; +import 'package:giraffe_spotter/repositories/FeedRepository.dart'; + +import 'Bloc.dart'; + +class ArticleBloc extends Bloc { + ArticleBloc(FeedRepository repository) + : _repository = repository, + super(ArticleState.idle()); + + final FeedRepository _repository; + + @override + Stream mapEventToState(ArticleEvent event) async* { + if (event is GetFeed) { + yield* mapFetchFeedEventToState(); + } + } + + Stream mapFetchFeedEventToState() async* { + yield ArticleState.loading(); + + ApiResult data = await _repository.getFeed(); + yield* data.when(success: (data) async* { + yield ArticleState.getFeedDone(data!); + }, failure: (error) async* { + yield ArticleState.error(error!); + }); + } +} diff --git a/lib/blocs/home/articles/ArticleEvent.dart b/lib/blocs/home/articles/ArticleEvent.dart new file mode 100644 index 0000000..e7d0a46 --- /dev/null +++ b/lib/blocs/home/articles/ArticleEvent.dart @@ -0,0 +1,10 @@ +import 'package:freezed_annotation/freezed_annotation.dart'; + +part 'ArticleEvent.freezed.dart'; + +@freezed +abstract class ArticleEvent with _$ArticleEvent{ + + const factory ArticleEvent.getFeed() = GetFeed; + +} diff --git a/lib/blocs/home/articles/ArticleEvent.freezed.dart b/lib/blocs/home/articles/ArticleEvent.freezed.dart new file mode 100644 index 0000000..c393843 --- /dev/null +++ b/lib/blocs/home/articles/ArticleEvent.freezed.dart @@ -0,0 +1,145 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides + +part of 'ArticleEvent.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more informations: https://github.com/rrousselGit/freezed#custom-getters-and-methods'); + +/// @nodoc +class _$ArticleEventTearOff { + const _$ArticleEventTearOff(); + + GetFeed getFeed() { + return const GetFeed(); + } +} + +/// @nodoc +const $ArticleEvent = _$ArticleEventTearOff(); + +/// @nodoc +mixin _$ArticleEvent { + @optionalTypeArgs + TResult when({ + required TResult Function() getFeed, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? getFeed, + required TResult orElse(), + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult map({ + required TResult Function(GetFeed value) getFeed, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult maybeMap({ + TResult Function(GetFeed value)? getFeed, + required TResult orElse(), + }) => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $ArticleEventCopyWith<$Res> { + factory $ArticleEventCopyWith( + ArticleEvent value, $Res Function(ArticleEvent) then) = + _$ArticleEventCopyWithImpl<$Res>; +} + +/// @nodoc +class _$ArticleEventCopyWithImpl<$Res> implements $ArticleEventCopyWith<$Res> { + _$ArticleEventCopyWithImpl(this._value, this._then); + + final ArticleEvent _value; + // ignore: unused_field + final $Res Function(ArticleEvent) _then; +} + +/// @nodoc +abstract class $GetFeedCopyWith<$Res> { + factory $GetFeedCopyWith(GetFeed value, $Res Function(GetFeed) then) = + _$GetFeedCopyWithImpl<$Res>; +} + +/// @nodoc +class _$GetFeedCopyWithImpl<$Res> extends _$ArticleEventCopyWithImpl<$Res> + implements $GetFeedCopyWith<$Res> { + _$GetFeedCopyWithImpl(GetFeed _value, $Res Function(GetFeed) _then) + : super(_value, (v) => _then(v as GetFeed)); + + @override + GetFeed get _value => super._value as GetFeed; +} + +/// @nodoc +class _$GetFeed implements GetFeed { + const _$GetFeed(); + + @override + String toString() { + return 'ArticleEvent.getFeed()'; + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || (other is GetFeed); + } + + @override + int get hashCode => runtimeType.hashCode; + + @override + @optionalTypeArgs + TResult when({ + required TResult Function() getFeed, + }) { + return getFeed(); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? getFeed, + required TResult orElse(), + }) { + if (getFeed != null) { + return getFeed(); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(GetFeed value) getFeed, + }) { + return getFeed(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(GetFeed value)? getFeed, + required TResult orElse(), + }) { + if (getFeed != null) { + return getFeed(this); + } + return orElse(); + } +} + +abstract class GetFeed implements ArticleEvent { + const factory GetFeed() = _$GetFeed; +} diff --git a/lib/blocs/home/articles/ArticleState.dart b/lib/blocs/home/articles/ArticleState.dart new file mode 100644 index 0000000..99dc561 --- /dev/null +++ b/lib/blocs/home/articles/ArticleState.dart @@ -0,0 +1,18 @@ +import 'package:freezed_annotation/freezed_annotation.dart'; +import 'package:giraffe_spotter/models/WelcomeJson.dart'; +import 'package:giraffe_spotter/network/NetworkExceptions.dart'; + +part 'ArticleState.freezed.dart'; + + +@freezed +abstract class ArticleState with _$ArticleState { + + const factory ArticleState.idle() = Idle; + + const factory ArticleState.loading() = Loading; + + const factory ArticleState.getFeedDone(WelcomeJson data) = GetFeedDone; + + const factory ArticleState.error(NetworkExceptions error) = Error; +} diff --git a/lib/blocs/home/articles/ArticleState.freezed.dart b/lib/blocs/home/articles/ArticleState.freezed.dart new file mode 100644 index 0000000..0682e65 --- /dev/null +++ b/lib/blocs/home/articles/ArticleState.freezed.dart @@ -0,0 +1,525 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides + +part of 'ArticleState.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more informations: https://github.com/rrousselGit/freezed#custom-getters-and-methods'); + +/// @nodoc +class _$ArticleStateTearOff { + const _$ArticleStateTearOff(); + + Idle idle() { + return const Idle(); + } + + Loading loading() { + return const Loading(); + } + + GetFeedDone getFeedDone(WelcomeJson data) { + return GetFeedDone( + data, + ); + } + + Error error(NetworkExceptions error) { + return Error( + error, + ); + } +} + +/// @nodoc +const $ArticleState = _$ArticleStateTearOff(); + +/// @nodoc +mixin _$ArticleState { + @optionalTypeArgs + TResult when({ + required TResult Function() idle, + required TResult Function() loading, + required TResult Function(WelcomeJson data) getFeedDone, + required TResult Function(NetworkExceptions error) error, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? idle, + TResult Function()? loading, + TResult Function(WelcomeJson data)? getFeedDone, + TResult Function(NetworkExceptions error)? error, + required TResult orElse(), + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult map({ + required TResult Function(Idle value) idle, + required TResult Function(Loading value) loading, + required TResult Function(GetFeedDone value) getFeedDone, + required TResult Function(Error value) error, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult maybeMap({ + TResult Function(Idle value)? idle, + TResult Function(Loading value)? loading, + TResult Function(GetFeedDone value)? getFeedDone, + TResult Function(Error value)? error, + required TResult orElse(), + }) => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $ArticleStateCopyWith<$Res> { + factory $ArticleStateCopyWith( + ArticleState value, $Res Function(ArticleState) then) = + _$ArticleStateCopyWithImpl<$Res>; +} + +/// @nodoc +class _$ArticleStateCopyWithImpl<$Res> implements $ArticleStateCopyWith<$Res> { + _$ArticleStateCopyWithImpl(this._value, this._then); + + final ArticleState _value; + // ignore: unused_field + final $Res Function(ArticleState) _then; +} + +/// @nodoc +abstract class $IdleCopyWith<$Res> { + factory $IdleCopyWith(Idle value, $Res Function(Idle) then) = + _$IdleCopyWithImpl<$Res>; +} + +/// @nodoc +class _$IdleCopyWithImpl<$Res> extends _$ArticleStateCopyWithImpl<$Res> + implements $IdleCopyWith<$Res> { + _$IdleCopyWithImpl(Idle _value, $Res Function(Idle) _then) + : super(_value, (v) => _then(v as Idle)); + + @override + Idle get _value => super._value as Idle; +} + +/// @nodoc +class _$Idle implements Idle { + const _$Idle(); + + @override + String toString() { + return 'ArticleState.idle()'; + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || (other is Idle); + } + + @override + int get hashCode => runtimeType.hashCode; + + @override + @optionalTypeArgs + TResult when({ + required TResult Function() idle, + required TResult Function() loading, + required TResult Function(WelcomeJson data) getFeedDone, + required TResult Function(NetworkExceptions error) error, + }) { + return idle(); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? idle, + TResult Function()? loading, + TResult Function(WelcomeJson data)? getFeedDone, + TResult Function(NetworkExceptions error)? error, + required TResult orElse(), + }) { + if (idle != null) { + return idle(); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(Idle value) idle, + required TResult Function(Loading value) loading, + required TResult Function(GetFeedDone value) getFeedDone, + required TResult Function(Error value) error, + }) { + return idle(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(Idle value)? idle, + TResult Function(Loading value)? loading, + TResult Function(GetFeedDone value)? getFeedDone, + TResult Function(Error value)? error, + required TResult orElse(), + }) { + if (idle != null) { + return idle(this); + } + return orElse(); + } +} + +abstract class Idle implements ArticleState { + const factory Idle() = _$Idle; +} + +/// @nodoc +abstract class $LoadingCopyWith<$Res> { + factory $LoadingCopyWith(Loading value, $Res Function(Loading) then) = + _$LoadingCopyWithImpl<$Res>; +} + +/// @nodoc +class _$LoadingCopyWithImpl<$Res> extends _$ArticleStateCopyWithImpl<$Res> + implements $LoadingCopyWith<$Res> { + _$LoadingCopyWithImpl(Loading _value, $Res Function(Loading) _then) + : super(_value, (v) => _then(v as Loading)); + + @override + Loading get _value => super._value as Loading; +} + +/// @nodoc +class _$Loading implements Loading { + const _$Loading(); + + @override + String toString() { + return 'ArticleState.loading()'; + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || (other is Loading); + } + + @override + int get hashCode => runtimeType.hashCode; + + @override + @optionalTypeArgs + TResult when({ + required TResult Function() idle, + required TResult Function() loading, + required TResult Function(WelcomeJson data) getFeedDone, + required TResult Function(NetworkExceptions error) error, + }) { + return loading(); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? idle, + TResult Function()? loading, + TResult Function(WelcomeJson data)? getFeedDone, + TResult Function(NetworkExceptions error)? error, + required TResult orElse(), + }) { + if (loading != null) { + return loading(); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(Idle value) idle, + required TResult Function(Loading value) loading, + required TResult Function(GetFeedDone value) getFeedDone, + required TResult Function(Error value) error, + }) { + return loading(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(Idle value)? idle, + TResult Function(Loading value)? loading, + TResult Function(GetFeedDone value)? getFeedDone, + TResult Function(Error value)? error, + required TResult orElse(), + }) { + if (loading != null) { + return loading(this); + } + return orElse(); + } +} + +abstract class Loading implements ArticleState { + const factory Loading() = _$Loading; +} + +/// @nodoc +abstract class $GetFeedDoneCopyWith<$Res> { + factory $GetFeedDoneCopyWith( + GetFeedDone value, $Res Function(GetFeedDone) then) = + _$GetFeedDoneCopyWithImpl<$Res>; + $Res call({WelcomeJson data}); +} + +/// @nodoc +class _$GetFeedDoneCopyWithImpl<$Res> extends _$ArticleStateCopyWithImpl<$Res> + implements $GetFeedDoneCopyWith<$Res> { + _$GetFeedDoneCopyWithImpl( + GetFeedDone _value, $Res Function(GetFeedDone) _then) + : super(_value, (v) => _then(v as GetFeedDone)); + + @override + GetFeedDone get _value => super._value as GetFeedDone; + + @override + $Res call({ + Object? data = freezed, + }) { + return _then(GetFeedDone( + data == freezed + ? _value.data + : data // ignore: cast_nullable_to_non_nullable + as WelcomeJson, + )); + } +} + +/// @nodoc +class _$GetFeedDone implements GetFeedDone { + const _$GetFeedDone(this.data); + + @override + final WelcomeJson data; + + @override + String toString() { + return 'ArticleState.getFeedDone(data: $data)'; + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || + (other is GetFeedDone && + (identical(other.data, data) || + const DeepCollectionEquality().equals(other.data, data))); + } + + @override + int get hashCode => + runtimeType.hashCode ^ const DeepCollectionEquality().hash(data); + + @JsonKey(ignore: true) + @override + $GetFeedDoneCopyWith get copyWith => + _$GetFeedDoneCopyWithImpl(this, _$identity); + + @override + @optionalTypeArgs + TResult when({ + required TResult Function() idle, + required TResult Function() loading, + required TResult Function(WelcomeJson data) getFeedDone, + required TResult Function(NetworkExceptions error) error, + }) { + return getFeedDone(data); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? idle, + TResult Function()? loading, + TResult Function(WelcomeJson data)? getFeedDone, + TResult Function(NetworkExceptions error)? error, + required TResult orElse(), + }) { + if (getFeedDone != null) { + return getFeedDone(data); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(Idle value) idle, + required TResult Function(Loading value) loading, + required TResult Function(GetFeedDone value) getFeedDone, + required TResult Function(Error value) error, + }) { + return getFeedDone(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(Idle value)? idle, + TResult Function(Loading value)? loading, + TResult Function(GetFeedDone value)? getFeedDone, + TResult Function(Error value)? error, + required TResult orElse(), + }) { + if (getFeedDone != null) { + return getFeedDone(this); + } + return orElse(); + } +} + +abstract class GetFeedDone implements ArticleState { + const factory GetFeedDone(WelcomeJson data) = _$GetFeedDone; + + WelcomeJson get data => throw _privateConstructorUsedError; + @JsonKey(ignore: true) + $GetFeedDoneCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $ErrorCopyWith<$Res> { + factory $ErrorCopyWith(Error value, $Res Function(Error) then) = + _$ErrorCopyWithImpl<$Res>; + $Res call({NetworkExceptions error}); + + $NetworkExceptionsCopyWith<$Res> get error; +} + +/// @nodoc +class _$ErrorCopyWithImpl<$Res> extends _$ArticleStateCopyWithImpl<$Res> + implements $ErrorCopyWith<$Res> { + _$ErrorCopyWithImpl(Error _value, $Res Function(Error) _then) + : super(_value, (v) => _then(v as Error)); + + @override + Error get _value => super._value as Error; + + @override + $Res call({ + Object? error = freezed, + }) { + return _then(Error( + error == freezed + ? _value.error + : error // ignore: cast_nullable_to_non_nullable + as NetworkExceptions, + )); + } + + @override + $NetworkExceptionsCopyWith<$Res> get error { + return $NetworkExceptionsCopyWith<$Res>(_value.error, (value) { + return _then(_value.copyWith(error: value)); + }); + } +} + +/// @nodoc +class _$Error implements Error { + const _$Error(this.error); + + @override + final NetworkExceptions error; + + @override + String toString() { + return 'ArticleState.error(error: $error)'; + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || + (other is Error && + (identical(other.error, error) || + const DeepCollectionEquality().equals(other.error, error))); + } + + @override + int get hashCode => + runtimeType.hashCode ^ const DeepCollectionEquality().hash(error); + + @JsonKey(ignore: true) + @override + $ErrorCopyWith get copyWith => + _$ErrorCopyWithImpl(this, _$identity); + + @override + @optionalTypeArgs + TResult when({ + required TResult Function() idle, + required TResult Function() loading, + required TResult Function(WelcomeJson data) getFeedDone, + required TResult Function(NetworkExceptions error) error, + }) { + return error(this.error); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? idle, + TResult Function()? loading, + TResult Function(WelcomeJson data)? getFeedDone, + TResult Function(NetworkExceptions error)? error, + required TResult orElse(), + }) { + if (error != null) { + return error(this.error); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(Idle value) idle, + required TResult Function(Loading value) loading, + required TResult Function(GetFeedDone value) getFeedDone, + required TResult Function(Error value) error, + }) { + return error(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(Idle value)? idle, + TResult Function(Loading value)? loading, + TResult Function(GetFeedDone value)? getFeedDone, + TResult Function(Error value)? error, + required TResult orElse(), + }) { + if (error != null) { + return error(this); + } + return orElse(); + } +} + +abstract class Error implements ArticleState { + const factory Error(NetworkExceptions error) = _$Error; + + NetworkExceptions get error => throw _privateConstructorUsedError; + @JsonKey(ignore: true) + $ErrorCopyWith get copyWith => throw _privateConstructorUsedError; +} diff --git a/lib/blocs/home/articles/Bloc.dart b/lib/blocs/home/articles/Bloc.dart new file mode 100644 index 0000000..16b7100 --- /dev/null +++ b/lib/blocs/home/articles/Bloc.dart @@ -0,0 +1,3 @@ +export 'ArticleBloc.dart'; +export 'ArticleState.dart'; +export 'ArticleEvent.dart'; diff --git a/lib/blocs/home/articles/ThumbNail/Bloc.dart b/lib/blocs/home/articles/ThumbNail/Bloc.dart new file mode 100644 index 0000000..9f54ea6 --- /dev/null +++ b/lib/blocs/home/articles/ThumbNail/Bloc.dart @@ -0,0 +1,3 @@ +export 'ThumbNailBloc.dart'; +export 'ThumbNailEvent.dart'; +export 'ThumbNailState.dart'; \ No newline at end of file diff --git a/lib/blocs/home/articles/ThumbNail/ThumbNailBloc.dart b/lib/blocs/home/articles/ThumbNail/ThumbNailBloc.dart new file mode 100644 index 0000000..40175ea --- /dev/null +++ b/lib/blocs/home/articles/ThumbNail/ThumbNailBloc.dart @@ -0,0 +1,40 @@ +import 'dart:async'; + +import 'package:bloc/bloc.dart'; +import 'package:giraffe_spotter/network/ApiResult.dart'; +import 'package:giraffe_spotter/repositories/ThumbNailRepository.dart'; + +import 'Bloc.dart'; + + +class ThumbNailBloc extends Bloc { + ThumbNailBloc(ThumbNailRepository thumbNailRepository) : + _thumbNailRepository = thumbNailRepository, + super(ThumbNailState.idle()); + + final ThumbNailRepository _thumbNailRepository; + + @override + Stream mapEventToState(ThumbNailEvent event) async* { + if(event is GetThumb){ + yield* mapYoutubeThumbNail(event); + } + } + + + + Stream mapYoutubeThumbNail(ThumbNailEvent event) async*{ + yield ThumbNailState.loading(); + ApiResult data = await _thumbNailRepository.getThumbNail(event.youtubeUrl); + yield* data.when( + success: (data) async*{ + yield ThumbNailState.getThumbNail( data!); + }, + failure: ( error) async* { + yield ThumbNailState.error(error!); + } + ); + } + + +} diff --git a/lib/blocs/home/articles/ThumbNail/ThumbNailEvent.dart b/lib/blocs/home/articles/ThumbNail/ThumbNailEvent.dart new file mode 100644 index 0000000..a0db40a --- /dev/null +++ b/lib/blocs/home/articles/ThumbNail/ThumbNailEvent.dart @@ -0,0 +1,10 @@ +import 'package:freezed_annotation/freezed_annotation.dart'; + +part 'ThumbNailEvent.freezed.dart'; + +@freezed +abstract class ThumbNailEvent with _$ThumbNailEvent { + + const factory ThumbNailEvent.getThumbNail(String youtubeUrl) = GetThumb; +} + diff --git a/lib/blocs/home/articles/ThumbNail/ThumbNailEvent.freezed.dart b/lib/blocs/home/articles/ThumbNail/ThumbNailEvent.freezed.dart new file mode 100644 index 0000000..38b5317 --- /dev/null +++ b/lib/blocs/home/articles/ThumbNail/ThumbNailEvent.freezed.dart @@ -0,0 +1,202 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides + +part of 'ThumbNailEvent.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more informations: https://github.com/rrousselGit/freezed#custom-getters-and-methods'); + +/// @nodoc +class _$ThumbNailEventTearOff { + const _$ThumbNailEventTearOff(); + + GetThumb getThumbNail(String youtubeUrl) { + return GetThumb( + youtubeUrl, + ); + } +} + +/// @nodoc +const $ThumbNailEvent = _$ThumbNailEventTearOff(); + +/// @nodoc +mixin _$ThumbNailEvent { + String get youtubeUrl => throw _privateConstructorUsedError; + + @optionalTypeArgs + TResult when({ + required TResult Function(String youtubeUrl) getThumbNail, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult maybeWhen({ + TResult Function(String youtubeUrl)? getThumbNail, + required TResult orElse(), + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult map({ + required TResult Function(GetThumb value) getThumbNail, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult maybeMap({ + TResult Function(GetThumb value)? getThumbNail, + required TResult orElse(), + }) => + throw _privateConstructorUsedError; + + @JsonKey(ignore: true) + $ThumbNailEventCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $ThumbNailEventCopyWith<$Res> { + factory $ThumbNailEventCopyWith( + ThumbNailEvent value, $Res Function(ThumbNailEvent) then) = + _$ThumbNailEventCopyWithImpl<$Res>; + $Res call({String youtubeUrl}); +} + +/// @nodoc +class _$ThumbNailEventCopyWithImpl<$Res> + implements $ThumbNailEventCopyWith<$Res> { + _$ThumbNailEventCopyWithImpl(this._value, this._then); + + final ThumbNailEvent _value; + // ignore: unused_field + final $Res Function(ThumbNailEvent) _then; + + @override + $Res call({ + Object? youtubeUrl = freezed, + }) { + return _then(_value.copyWith( + youtubeUrl: youtubeUrl == freezed + ? _value.youtubeUrl + : youtubeUrl // ignore: cast_nullable_to_non_nullable + as String, + )); + } +} + +/// @nodoc +abstract class $GetThumbCopyWith<$Res> + implements $ThumbNailEventCopyWith<$Res> { + factory $GetThumbCopyWith(GetThumb value, $Res Function(GetThumb) then) = + _$GetThumbCopyWithImpl<$Res>; + @override + $Res call({String youtubeUrl}); +} + +/// @nodoc +class _$GetThumbCopyWithImpl<$Res> extends _$ThumbNailEventCopyWithImpl<$Res> + implements $GetThumbCopyWith<$Res> { + _$GetThumbCopyWithImpl(GetThumb _value, $Res Function(GetThumb) _then) + : super(_value, (v) => _then(v as GetThumb)); + + @override + GetThumb get _value => super._value as GetThumb; + + @override + $Res call({ + Object? youtubeUrl = freezed, + }) { + return _then(GetThumb( + youtubeUrl == freezed + ? _value.youtubeUrl + : youtubeUrl // ignore: cast_nullable_to_non_nullable + as String, + )); + } +} + +/// @nodoc +class _$GetThumb implements GetThumb { + const _$GetThumb(this.youtubeUrl); + + @override + final String youtubeUrl; + + @override + String toString() { + return 'ThumbNailEvent.getThumbNail(youtubeUrl: $youtubeUrl)'; + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || + (other is GetThumb && + (identical(other.youtubeUrl, youtubeUrl) || + const DeepCollectionEquality() + .equals(other.youtubeUrl, youtubeUrl))); + } + + @override + int get hashCode => + runtimeType.hashCode ^ const DeepCollectionEquality().hash(youtubeUrl); + + @JsonKey(ignore: true) + @override + $GetThumbCopyWith get copyWith => + _$GetThumbCopyWithImpl(this, _$identity); + + @override + @optionalTypeArgs + TResult when({ + required TResult Function(String youtubeUrl) getThumbNail, + }) { + return getThumbNail(youtubeUrl); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function(String youtubeUrl)? getThumbNail, + required TResult orElse(), + }) { + if (getThumbNail != null) { + return getThumbNail(youtubeUrl); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(GetThumb value) getThumbNail, + }) { + return getThumbNail(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(GetThumb value)? getThumbNail, + required TResult orElse(), + }) { + if (getThumbNail != null) { + return getThumbNail(this); + } + return orElse(); + } +} + +abstract class GetThumb implements ThumbNailEvent { + const factory GetThumb(String youtubeUrl) = _$GetThumb; + + @override + String get youtubeUrl => throw _privateConstructorUsedError; + @override + @JsonKey(ignore: true) + $GetThumbCopyWith get copyWith => + throw _privateConstructorUsedError; +} diff --git a/lib/blocs/home/articles/ThumbNail/ThumbNailState.dart b/lib/blocs/home/articles/ThumbNail/ThumbNailState.dart new file mode 100644 index 0000000..fd07fc6 --- /dev/null +++ b/lib/blocs/home/articles/ThumbNail/ThumbNailState.dart @@ -0,0 +1,19 @@ +import 'package:freezed_annotation/freezed_annotation.dart'; +import 'package:giraffe_spotter/models/ThumbNail.dart'; +import 'package:giraffe_spotter/network/NetworkExceptions.dart'; + + +part 'ThumbNailState.freezed.dart'; + + +@freezed +abstract class ThumbNailState with _$ThumbNailState { + + const factory ThumbNailState.idle() = Idle; + + const factory ThumbNailState.loading() = Loading; + + const factory ThumbNailState.getThumbNail(ThumbNail data) = GetFeedDone; + + const factory ThumbNailState.error(NetworkExceptions error) = Error; +} \ No newline at end of file diff --git a/lib/blocs/home/articles/ThumbNail/ThumbNailState.freezed.dart b/lib/blocs/home/articles/ThumbNail/ThumbNailState.freezed.dart new file mode 100644 index 0000000..f0c3f12 --- /dev/null +++ b/lib/blocs/home/articles/ThumbNail/ThumbNailState.freezed.dart @@ -0,0 +1,526 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides + +part of 'ThumbNailState.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more informations: https://github.com/rrousselGit/freezed#custom-getters-and-methods'); + +/// @nodoc +class _$ThumbNailStateTearOff { + const _$ThumbNailStateTearOff(); + + Idle idle() { + return const Idle(); + } + + Loading loading() { + return const Loading(); + } + + GetFeedDone getThumbNail(ThumbNail data) { + return GetFeedDone( + data, + ); + } + + Error error(NetworkExceptions error) { + return Error( + error, + ); + } +} + +/// @nodoc +const $ThumbNailState = _$ThumbNailStateTearOff(); + +/// @nodoc +mixin _$ThumbNailState { + @optionalTypeArgs + TResult when({ + required TResult Function() idle, + required TResult Function() loading, + required TResult Function(ThumbNail data) getThumbNail, + required TResult Function(NetworkExceptions error) error, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? idle, + TResult Function()? loading, + TResult Function(ThumbNail data)? getThumbNail, + TResult Function(NetworkExceptions error)? error, + required TResult orElse(), + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult map({ + required TResult Function(Idle value) idle, + required TResult Function(Loading value) loading, + required TResult Function(GetFeedDone value) getThumbNail, + required TResult Function(Error value) error, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult maybeMap({ + TResult Function(Idle value)? idle, + TResult Function(Loading value)? loading, + TResult Function(GetFeedDone value)? getThumbNail, + TResult Function(Error value)? error, + required TResult orElse(), + }) => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $ThumbNailStateCopyWith<$Res> { + factory $ThumbNailStateCopyWith( + ThumbNailState value, $Res Function(ThumbNailState) then) = + _$ThumbNailStateCopyWithImpl<$Res>; +} + +/// @nodoc +class _$ThumbNailStateCopyWithImpl<$Res> + implements $ThumbNailStateCopyWith<$Res> { + _$ThumbNailStateCopyWithImpl(this._value, this._then); + + final ThumbNailState _value; + // ignore: unused_field + final $Res Function(ThumbNailState) _then; +} + +/// @nodoc +abstract class $IdleCopyWith<$Res> { + factory $IdleCopyWith(Idle value, $Res Function(Idle) then) = + _$IdleCopyWithImpl<$Res>; +} + +/// @nodoc +class _$IdleCopyWithImpl<$Res> extends _$ThumbNailStateCopyWithImpl<$Res> + implements $IdleCopyWith<$Res> { + _$IdleCopyWithImpl(Idle _value, $Res Function(Idle) _then) + : super(_value, (v) => _then(v as Idle)); + + @override + Idle get _value => super._value as Idle; +} + +/// @nodoc +class _$Idle implements Idle { + const _$Idle(); + + @override + String toString() { + return 'ThumbNailState.idle()'; + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || (other is Idle); + } + + @override + int get hashCode => runtimeType.hashCode; + + @override + @optionalTypeArgs + TResult when({ + required TResult Function() idle, + required TResult Function() loading, + required TResult Function(ThumbNail data) getThumbNail, + required TResult Function(NetworkExceptions error) error, + }) { + return idle(); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? idle, + TResult Function()? loading, + TResult Function(ThumbNail data)? getThumbNail, + TResult Function(NetworkExceptions error)? error, + required TResult orElse(), + }) { + if (idle != null) { + return idle(); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(Idle value) idle, + required TResult Function(Loading value) loading, + required TResult Function(GetFeedDone value) getThumbNail, + required TResult Function(Error value) error, + }) { + return idle(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(Idle value)? idle, + TResult Function(Loading value)? loading, + TResult Function(GetFeedDone value)? getThumbNail, + TResult Function(Error value)? error, + required TResult orElse(), + }) { + if (idle != null) { + return idle(this); + } + return orElse(); + } +} + +abstract class Idle implements ThumbNailState { + const factory Idle() = _$Idle; +} + +/// @nodoc +abstract class $LoadingCopyWith<$Res> { + factory $LoadingCopyWith(Loading value, $Res Function(Loading) then) = + _$LoadingCopyWithImpl<$Res>; +} + +/// @nodoc +class _$LoadingCopyWithImpl<$Res> extends _$ThumbNailStateCopyWithImpl<$Res> + implements $LoadingCopyWith<$Res> { + _$LoadingCopyWithImpl(Loading _value, $Res Function(Loading) _then) + : super(_value, (v) => _then(v as Loading)); + + @override + Loading get _value => super._value as Loading; +} + +/// @nodoc +class _$Loading implements Loading { + const _$Loading(); + + @override + String toString() { + return 'ThumbNailState.loading()'; + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || (other is Loading); + } + + @override + int get hashCode => runtimeType.hashCode; + + @override + @optionalTypeArgs + TResult when({ + required TResult Function() idle, + required TResult Function() loading, + required TResult Function(ThumbNail data) getThumbNail, + required TResult Function(NetworkExceptions error) error, + }) { + return loading(); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? idle, + TResult Function()? loading, + TResult Function(ThumbNail data)? getThumbNail, + TResult Function(NetworkExceptions error)? error, + required TResult orElse(), + }) { + if (loading != null) { + return loading(); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(Idle value) idle, + required TResult Function(Loading value) loading, + required TResult Function(GetFeedDone value) getThumbNail, + required TResult Function(Error value) error, + }) { + return loading(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(Idle value)? idle, + TResult Function(Loading value)? loading, + TResult Function(GetFeedDone value)? getThumbNail, + TResult Function(Error value)? error, + required TResult orElse(), + }) { + if (loading != null) { + return loading(this); + } + return orElse(); + } +} + +abstract class Loading implements ThumbNailState { + const factory Loading() = _$Loading; +} + +/// @nodoc +abstract class $GetFeedDoneCopyWith<$Res> { + factory $GetFeedDoneCopyWith( + GetFeedDone value, $Res Function(GetFeedDone) then) = + _$GetFeedDoneCopyWithImpl<$Res>; + $Res call({ThumbNail data}); +} + +/// @nodoc +class _$GetFeedDoneCopyWithImpl<$Res> extends _$ThumbNailStateCopyWithImpl<$Res> + implements $GetFeedDoneCopyWith<$Res> { + _$GetFeedDoneCopyWithImpl( + GetFeedDone _value, $Res Function(GetFeedDone) _then) + : super(_value, (v) => _then(v as GetFeedDone)); + + @override + GetFeedDone get _value => super._value as GetFeedDone; + + @override + $Res call({ + Object? data = freezed, + }) { + return _then(GetFeedDone( + data == freezed + ? _value.data + : data // ignore: cast_nullable_to_non_nullable + as ThumbNail, + )); + } +} + +/// @nodoc +class _$GetFeedDone implements GetFeedDone { + const _$GetFeedDone(this.data); + + @override + final ThumbNail data; + + @override + String toString() { + return 'ThumbNailState.getThumbNail(data: $data)'; + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || + (other is GetFeedDone && + (identical(other.data, data) || + const DeepCollectionEquality().equals(other.data, data))); + } + + @override + int get hashCode => + runtimeType.hashCode ^ const DeepCollectionEquality().hash(data); + + @JsonKey(ignore: true) + @override + $GetFeedDoneCopyWith get copyWith => + _$GetFeedDoneCopyWithImpl(this, _$identity); + + @override + @optionalTypeArgs + TResult when({ + required TResult Function() idle, + required TResult Function() loading, + required TResult Function(ThumbNail data) getThumbNail, + required TResult Function(NetworkExceptions error) error, + }) { + return getThumbNail(data); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? idle, + TResult Function()? loading, + TResult Function(ThumbNail data)? getThumbNail, + TResult Function(NetworkExceptions error)? error, + required TResult orElse(), + }) { + if (getThumbNail != null) { + return getThumbNail(data); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(Idle value) idle, + required TResult Function(Loading value) loading, + required TResult Function(GetFeedDone value) getThumbNail, + required TResult Function(Error value) error, + }) { + return getThumbNail(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(Idle value)? idle, + TResult Function(Loading value)? loading, + TResult Function(GetFeedDone value)? getThumbNail, + TResult Function(Error value)? error, + required TResult orElse(), + }) { + if (getThumbNail != null) { + return getThumbNail(this); + } + return orElse(); + } +} + +abstract class GetFeedDone implements ThumbNailState { + const factory GetFeedDone(ThumbNail data) = _$GetFeedDone; + + ThumbNail get data => throw _privateConstructorUsedError; + @JsonKey(ignore: true) + $GetFeedDoneCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $ErrorCopyWith<$Res> { + factory $ErrorCopyWith(Error value, $Res Function(Error) then) = + _$ErrorCopyWithImpl<$Res>; + $Res call({NetworkExceptions error}); + + $NetworkExceptionsCopyWith<$Res> get error; +} + +/// @nodoc +class _$ErrorCopyWithImpl<$Res> extends _$ThumbNailStateCopyWithImpl<$Res> + implements $ErrorCopyWith<$Res> { + _$ErrorCopyWithImpl(Error _value, $Res Function(Error) _then) + : super(_value, (v) => _then(v as Error)); + + @override + Error get _value => super._value as Error; + + @override + $Res call({ + Object? error = freezed, + }) { + return _then(Error( + error == freezed + ? _value.error + : error // ignore: cast_nullable_to_non_nullable + as NetworkExceptions, + )); + } + + @override + $NetworkExceptionsCopyWith<$Res> get error { + return $NetworkExceptionsCopyWith<$Res>(_value.error, (value) { + return _then(_value.copyWith(error: value)); + }); + } +} + +/// @nodoc +class _$Error implements Error { + const _$Error(this.error); + + @override + final NetworkExceptions error; + + @override + String toString() { + return 'ThumbNailState.error(error: $error)'; + } + + @override + bool operator ==(dynamic other) { + return identical(this, other) || + (other is Error && + (identical(other.error, error) || + const DeepCollectionEquality().equals(other.error, error))); + } + + @override + int get hashCode => + runtimeType.hashCode ^ const DeepCollectionEquality().hash(error); + + @JsonKey(ignore: true) + @override + $ErrorCopyWith get copyWith => + _$ErrorCopyWithImpl(this, _$identity); + + @override + @optionalTypeArgs + TResult when({ + required TResult Function() idle, + required TResult Function() loading, + required TResult Function(ThumbNail data) getThumbNail, + required TResult Function(NetworkExceptions error) error, + }) { + return error(this.error); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function()? idle, + TResult Function()? loading, + TResult Function(ThumbNail data)? getThumbNail, + TResult Function(NetworkExceptions error)? error, + required TResult orElse(), + }) { + if (error != null) { + return error(this.error); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(Idle value) idle, + required TResult Function(Loading value) loading, + required TResult Function(GetFeedDone value) getThumbNail, + required TResult Function(Error value) error, + }) { + return error(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(Idle value)? idle, + TResult Function(Loading value)? loading, + TResult Function(GetFeedDone value)? getThumbNail, + TResult Function(Error value)? error, + required TResult orElse(), + }) { + if (error != null) { + return error(this); + } + return orElse(); + } +} + +abstract class Error implements ThumbNailState { + const factory Error(NetworkExceptions error) = _$Error; + + NetworkExceptions get error => throw _privateConstructorUsedError; + @JsonKey(ignore: true) + $ErrorCopyWith get copyWith => throw _privateConstructorUsedError; +} diff --git a/lib/blocs/home/articlesSearch/ArticleSearchCubit.dart b/lib/blocs/home/articlesSearch/ArticleSearchCubit.dart new file mode 100644 index 0000000..89a6fb7 --- /dev/null +++ b/lib/blocs/home/articlesSearch/ArticleSearchCubit.dart @@ -0,0 +1,42 @@ +import 'package:bloc/bloc.dart'; +import 'package:equatable/equatable.dart'; +import 'package:giraffe_spotter/models/Item.dart'; + +part 'ArticleSearchState.dart'; + +class ArticleSearchCubit extends Cubit { + List dataItems ; + String searchText; + + ArticleSearchCubit({ required this.dataItems ,this.searchText = ''}) : super(InitialSearchState()){ + retrieveTitle(dataItems, searchText); + } + + //method to check letter || word in item.title + void retrieveTitle(List? dataItems, String? searchText) { + try { + // Loading state ===> searching ... + emit(LoadingSearchState()); + // empty list to add the Item data + List finalList = []; + if(dataItems !=null ){ + if(searchText == null){ + emit(InitialSearchState());} + else{ + //check each title if it contains the letter || word + dataItems.forEach((element) { + //turned to lowercase to find all + if (element.title.t!.toLowerCase().contains(searchText.toLowerCase())){ + finalList.add(element); + }}); + emit(LoadedSearchState(finalList)); + } + }else if(searchText == null){ + emit(InitialSearchState()); + } + } catch (e) { + emit(ErrorSearchState()); + } + } + +} diff --git a/lib/blocs/home/articlesSearch/ArticleSearchState.dart b/lib/blocs/home/articlesSearch/ArticleSearchState.dart new file mode 100644 index 0000000..948ea8e --- /dev/null +++ b/lib/blocs/home/articlesSearch/ArticleSearchState.dart @@ -0,0 +1,30 @@ +part of 'ArticleSearchCubit.dart'; + +abstract class ArticleSearchState extends Equatable { + const ArticleSearchState(); +} + +class InitialSearchState extends ArticleSearchState { + @override + List get props => []; +} + +class LoadingSearchState extends ArticleSearchState{ + @override + List get props => []; +} + +class ErrorSearchState extends ArticleSearchState{ + @override + List get props => []; +} + +class LoadedSearchState extends ArticleSearchState{ + final List dataItems; + //passing the item model data to the UI endpoint + LoadedSearchState(this.dataItems); + + @override + List get props => [dataItems]; +} + diff --git a/lib/blocs/home/profile/GiraffeFavCubit.dart b/lib/blocs/home/profile/GiraffeFavCubit.dart new file mode 100644 index 0000000..e7c937b --- /dev/null +++ b/lib/blocs/home/profile/GiraffeFavCubit.dart @@ -0,0 +1,99 @@ +import 'package:bloc/bloc.dart'; +import 'package:formz/formz.dart'; +import 'package:giraffe_spotter/blocs/home/profile/GiraffeFavState.dart'; +import 'package:giraffe_spotter/config/AppRoute.dart'; +import 'package:giraffe_spotter/config/ServiceLocator.dart'; +import 'package:giraffe_spotter/models/GiraffeData.dart'; +import 'package:giraffe_spotter/network/ApiResult.dart'; +import 'package:giraffe_spotter/pages/authentication/Login.dart'; +import 'package:giraffe_spotter/providers/FavouriteProvider.dart'; + +class GiraffeFavCubit extends Cubit { + final int initialValue; + final FavouriteProvider favouriteProvider; + bool backRefresh; + String? errorMessage; + GiraffeFavCubit({required this.initialValue,this.backRefresh = false,required this.favouriteProvider}) : super(GiraffeFavState(initialValue: initialValue)); + + void addFavourite(String id) async + { + emit(state.copyWith(status: FormzStatus.submissionInProgress)); + ApiResult results = await favouriteProvider.addFavourite(id); + results.when( + success: (_){ + backRefresh = true; + emit(state.copyWith(status: FormzStatus.submissionSuccess,initialValue: 1)); + }, + failure: (error){ + error?.maybeWhen(unProcessableEntity: (Map e){ + errorMessage = e['message']; + emit(state.copyWith( + status: FormzStatus.submissionFailure, + formErrors: (e['errors'] as Map).map((key, value) => MapEntry(key, (value as List).map((e) => e as String).toList())))); + },unauthenticatedRequest: () { + emit(state.copyWith(status: FormzStatus.submissionFailure)); + locator!().navigateAndRemoveUntil(Login()); + },orElse: () { + errorMessage = 'Error occurred while submitting your request. Please try again.'; + emit(state.copyWith(status: FormzStatus.submissionFailure)); + }); + }); + } + + void unFavourite(String id) async + { + emit(state.copyWith(status: FormzStatus.submissionInProgress)); + ApiResult results = await favouriteProvider.unFavourite(id); + results.when( + success: (_){ + backRefresh = true; + emit(state.copyWith(status: FormzStatus.submissionSuccess,initialValue: 0)); + }, + failure: (error){ + error?.maybeWhen(unProcessableEntity: (Map e){ + errorMessage = e['message']; + emit(state.copyWith( + status: FormzStatus.submissionFailure, + formErrors: (e['errors'] as Map).map((key, value) => MapEntry(key, (value as List).map((e) => e as String).toList())))); + },unauthenticatedRequest: (){ + emit(state.copyWith(status: FormzStatus.submissionFailure)); + locator!().navigateAndRemoveUntil(Login()); + },orElse: () { + errorMessage = 'Error occurred while submitting your request. Please try again.'; + emit(state.copyWith(status: FormzStatus.submissionFailure)); + }); + }); + } + + favourites() async + { + emit(state.copyWith(status: FormzStatus.submissionInProgress)); + ApiResult> results = await favouriteProvider.favourites(); + results.when( + success: (_) { + List newData = []; + _!.forEach((element) { + if(newData.contains(element) == false) { + newData.add(element); + } + }); + emit(state.copyWith(status: FormzStatus.submissionSuccess,initialValue: 1, favouritesGiraffes: newData)); + }, + failure: (error){ + error?.maybeWhen(unProcessableEntity: (Map e){ + errorMessage = e['message']; + emit(state.copyWith( + status: FormzStatus.submissionFailure, + formErrors: (e['errors'] as Map).map((key, value) => MapEntry(key, (value as List).map((e) => e as String).toList())))); + }, unauthenticatedRequest: () { + emit(state.copyWith(status: FormzStatus.submissionFailure)); + locator!().navigateAndRemoveUntil(Login()); + }, orElse: () { + errorMessage = 'Error occurred while submitting your request. Please try again.'; + emit(state.copyWith(status: FormzStatus.submissionFailure)); + }); + }); + } +} + + diff --git a/lib/blocs/home/profile/GiraffeFavState.dart b/lib/blocs/home/profile/GiraffeFavState.dart new file mode 100644 index 0000000..15a1216 --- /dev/null +++ b/lib/blocs/home/profile/GiraffeFavState.dart @@ -0,0 +1,29 @@ +import 'package:equatable/equatable.dart'; +import 'package:formz/formz.dart'; +import 'package:giraffe_spotter/models/GiraffeData.dart'; +import 'package:giraffe_spotter/models/GiraffeProfile.dart'; + +class GiraffeFavState extends Equatable{ + + + final int? initialValue; + final FormzStatus status; + bool favRefresh; + final List? favouritesGiraffes; + final Map>? formErrors; + + GiraffeFavState({ + this.formErrors, + this.favRefresh = false, + this.favouritesGiraffes, + this.initialValue, + this.status = FormzStatus.pure, + }); + + @override + List get props => [formErrors,favouritesGiraffes,initialValue,status]; + + GiraffeFavState copyWith({List? favouritesGiraffes, int? initialValue,FormzStatus? status,Map>? formErrors, bool? favRefresh }) => GiraffeFavState + (initialValue: initialValue , status: status?? this.status,formErrors: formErrors, favRefresh: favRefresh ?? this.favRefresh, favouritesGiraffes :favouritesGiraffes); + +} \ No newline at end of file diff --git a/lib/blocs/home/profile/GiraffeProfileStringCubit.dart b/lib/blocs/home/profile/GiraffeProfileStringCubit.dart new file mode 100644 index 0000000..0aa319c --- /dev/null +++ b/lib/blocs/home/profile/GiraffeProfileStringCubit.dart @@ -0,0 +1,19 @@ +import 'package:collection/collection.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:giraffe_spotter/models/GiraffeData.dart'; + +class GiraffeProfileStringCubit extends Cubit { + GiraffeProfileStringCubit() : super('assets/images/Anne.png'); + + List images = []; + + void captureDataItems(GiraffeData data) { + data.encounters.map((e) => e.annotations).forEach((element) => + element.map((e) => e).forEach((element) => element.media.map((e) => e).forEach((element) => images.add(element.image_url)))); + emit(images.firstOrNull); + } + + void setImage(String? image) { + emit(image!); + } +} diff --git a/lib/blocs/network/CheckConnectionBloc.dart b/lib/blocs/network/CheckConnectionBloc.dart new file mode 100644 index 0000000..387fd70 --- /dev/null +++ b/lib/blocs/network/CheckConnectionBloc.dart @@ -0,0 +1,36 @@ +import 'dart:async'; + +import 'package:data_connection_checker/data_connection_checker.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:giraffe_spotter/blocs/network/CheckConnectionEvent.dart'; +import 'package:giraffe_spotter/blocs/network/CheckConnectionState.dart'; + +class CheckNetworkConnectionBloc extends Bloc { + CheckNetworkConnectionBloc() : super(ConnectionInitial()); + StreamSubscription? _streamSubscription; + bool intialState = false; + + @override + Stream mapEventToState(CheckNetworkConnectionEvent event) async* { + if (event is ListenConnection) { + _streamSubscription = DataConnectionChecker().onStatusChange.listen((status) { + add(ConnectionChanged( + status == DataConnectionStatus.disconnected ? ConnectionFailure() : ConnectionSuccess(), + )); + }); + } + if (event is ConnectionChanged) yield event.connection; + } + + @override + Future close() { + _streamSubscription?.cancel(); + return super.close(); + } + + changeBool(bool checker) { + intialState = true; + print("this is the bool ::: " + intialState.toString()); + // emit(intialState); + } +} diff --git a/lib/blocs/network/CheckConnectionEvent.dart b/lib/blocs/network/CheckConnectionEvent.dart new file mode 100644 index 0000000..60e759f --- /dev/null +++ b/lib/blocs/network/CheckConnectionEvent.dart @@ -0,0 +1,10 @@ +import 'CheckConnectionState.dart'; + +abstract class CheckNetworkConnectionEvent {} + +class ListenConnection extends CheckNetworkConnectionEvent {} + +class ConnectionChanged extends CheckNetworkConnectionEvent { + CheckNetworkConnectionState connection; + ConnectionChanged(this.connection); +} diff --git a/lib/blocs/network/CheckConnectionState.dart b/lib/blocs/network/CheckConnectionState.dart new file mode 100644 index 0000000..5da34a4 --- /dev/null +++ b/lib/blocs/network/CheckConnectionState.dart @@ -0,0 +1,8 @@ +abstract class CheckNetworkConnectionState {} + +class ConnectionInitial extends CheckNetworkConnectionState {} + +class ConnectionSuccess extends CheckNetworkConnectionState {} + +class ConnectionFailure extends CheckNetworkConnectionState {} + diff --git a/lib/blocs/notification/notification_cubit.dart b/lib/blocs/notification/notification_cubit.dart new file mode 100644 index 0000000..855450a --- /dev/null +++ b/lib/blocs/notification/notification_cubit.dart @@ -0,0 +1,13 @@ +import 'package:bloc/bloc.dart'; + + +class NotificationCubit extends Cubit { + bool notifications; + + NotificationCubit({required this.notifications}) : super(notifications); + + changeBool(bool changer){ + notifications = changer; + emit(changer); + } +} diff --git a/lib/blocs/on_boarding/PageCubit.dart b/lib/blocs/on_boarding/PageCubit.dart new file mode 100644 index 0000000..31875a1 --- /dev/null +++ b/lib/blocs/on_boarding/PageCubit.dart @@ -0,0 +1,24 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; + +class PageCubit extends Cubit { + PageController pageController = PageController(); + final initialPage; + final keepPage; + final viewportFraction; + PageCubit({this.initialPage = 0, this.keepPage = true, this.viewportFraction = 1.0}): super(initialPage) { + pageController = PageController(initialPage: initialPage, keepPage: keepPage, viewportFraction: viewportFraction); + } + + void updatePageState(int index) { + if (state == index) return; + + pageController.animateToPage(index, duration: Duration(milliseconds: 300), curve: Curves.easeInOutSine); + emit(index); + } + + void jumpToLast() { + {pageController.animateToPage(2, duration: Duration(milliseconds: 1), curve: Curves.easeInOutSine);} + emit(2); + } +} diff --git a/lib/blocs/pageWrappers/PageWrap.dart b/lib/blocs/pageWrappers/PageWrap.dart new file mode 100644 index 0000000..c00eb87 --- /dev/null +++ b/lib/blocs/pageWrappers/PageWrap.dart @@ -0,0 +1,14 @@ +import 'package:bloc/bloc.dart'; +import 'package:flutter/material.dart'; + +class PageWrapCubit extends Cubit { + ScrollController controller = ScrollController(); + PageWrapCubit() : super(0){ + controller = ScrollController(initialScrollOffset: 0.0,keepScrollOffset: false); + } + + void restoreScroll(){ + controller.jumpTo(0.0); + } + +} diff --git a/lib/blocs/share_button/ShareButtonCubit.dart b/lib/blocs/share_button/ShareButtonCubit.dart new file mode 100644 index 0000000..2f18b5f --- /dev/null +++ b/lib/blocs/share_button/ShareButtonCubit.dart @@ -0,0 +1,9 @@ +import 'package:flutter_bloc/flutter_bloc.dart'; + +class ShareButtonCubit extends Cubit { + ShareButtonCubit() : super(false); + + void getLink(bool disabled) { + emit(disabled); + } +} diff --git a/lib/blocs/videos/VideoCubit.dart b/lib/blocs/videos/VideoCubit.dart new file mode 100644 index 0000000..4375a4c --- /dev/null +++ b/lib/blocs/videos/VideoCubit.dart @@ -0,0 +1,25 @@ +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:giraffe_spotter/blocs/videos/VideoState.dart'; +import 'package:giraffe_spotter/network/NetworkExceptions.dart'; +import 'package:giraffe_spotter/repositories/YoutubeRepository.dart'; + +class VideoCubit extends Cubit { + VideoCubit() : super(InitialState()) { + getYoutubeVideos(); + } + + void getYoutubeVideos() async { + try { + emit(LoadingState()); + final youtubeVideos = await YoutubeVideosRepository().youtubeVideos; + + emit(LoadedState(videos: youtubeVideos)); + } catch (e) { + emit( + ErrorState( + error: NetworkExceptions.getDioException(e), + ), + ); + } + } +} diff --git a/lib/blocs/videos/VideoState.dart b/lib/blocs/videos/VideoState.dart new file mode 100644 index 0000000..10b0a4c --- /dev/null +++ b/lib/blocs/videos/VideoState.dart @@ -0,0 +1,31 @@ +import 'package:equatable/equatable.dart'; +import 'package:giraffe_spotter/models/YoutubeVideo.dart'; +import 'package:giraffe_spotter/network/NetworkExceptions.dart'; + +abstract class VideoState extends Equatable {} + +class InitialState extends VideoState { + @override + List get props => []; +} + +class LoadingState extends VideoState { + @override + List get props => []; +} + +// ignore: must_be_immutable +class LoadedState extends VideoState { + final List