Showing
100 changed files
with
4291 additions
and
0 deletions
Too many changes to show.
To preserve performance only 100 of 100+ files are displayed.
.gitignore
0 → 100644
| 1 | +# Miscellaneous | ||
| 2 | +*.class | ||
| 3 | +*.log | ||
| 4 | +*.pyc | ||
| 5 | +*.swp | ||
| 6 | +.DS_Store | ||
| 7 | +.atom/ | ||
| 8 | +.build/ | ||
| 9 | +.buildlog/ | ||
| 10 | +.history | ||
| 11 | +.svn/ | ||
| 12 | +.swiftpm/ | ||
| 13 | +migrate_working_dir/ | ||
| 14 | + | ||
| 15 | +# IntelliJ related | ||
| 16 | +*.iml | ||
| 17 | +*.ipr | ||
| 18 | +*.iws | ||
| 19 | +.idea/ | ||
| 20 | + | ||
| 21 | +# The .vscode folder contains launch configuration and tasks you configure in | ||
| 22 | +# VS Code which you may wish to be included in version control, so this line | ||
| 23 | +# is commented out by default. | ||
| 24 | +#.vscode/ | ||
| 25 | + | ||
| 26 | +# Flutter/Dart/Pub related | ||
| 27 | +**/doc/api/ | ||
| 28 | +**/ios/Flutter/.last_build_id | ||
| 29 | +.dart_tool/ | ||
| 30 | +.flutter-plugins | ||
| 31 | +.flutter-plugins-dependencies | ||
| 32 | +.pub-cache/ | ||
| 33 | +.pub/ | ||
| 34 | +/build/ | ||
| 35 | + | ||
| 36 | +# Symbolication related | ||
| 37 | +app.*.symbols | ||
| 38 | + | ||
| 39 | +# Obfuscation related | ||
| 40 | +app.*.map.json | ||
| 41 | + | ||
| 42 | +# Android Studio will place build artifacts here | ||
| 43 | +/android/app/debug | ||
| 44 | +/android/app/profile | ||
| 45 | +/android/app/release |
.metadata
0 → 100644
| 1 | +# This file tracks properties of this Flutter project. | ||
| 2 | +# Used by Flutter tool to assess capabilities and perform upgrades etc. | ||
| 3 | +# | ||
| 4 | +# This file should be version controlled and should not be manually edited. | ||
| 5 | + | ||
| 6 | +version: | ||
| 7 | + revision: "50e8dd668fbc8a752eb904e9c1b4f3a995498d13" | ||
| 8 | + channel: "[user-branch]" | ||
| 9 | + | ||
| 10 | +project_type: app | ||
| 11 | + | ||
| 12 | +# Tracks metadata for the flutter migrate command | ||
| 13 | +migration: | ||
| 14 | + platforms: | ||
| 15 | + - platform: root | ||
| 16 | + create_revision: 50e8dd668fbc8a752eb904e9c1b4f3a995498d13 | ||
| 17 | + base_revision: 50e8dd668fbc8a752eb904e9c1b4f3a995498d13 | ||
| 18 | + - platform: android | ||
| 19 | + create_revision: 50e8dd668fbc8a752eb904e9c1b4f3a995498d13 | ||
| 20 | + base_revision: 50e8dd668fbc8a752eb904e9c1b4f3a995498d13 | ||
| 21 | + - platform: ios | ||
| 22 | + create_revision: 50e8dd668fbc8a752eb904e9c1b4f3a995498d13 | ||
| 23 | + base_revision: 50e8dd668fbc8a752eb904e9c1b4f3a995498d13 | ||
| 24 | + - platform: ohos | ||
| 25 | + create_revision: 50e8dd668fbc8a752eb904e9c1b4f3a995498d13 | ||
| 26 | + base_revision: 50e8dd668fbc8a752eb904e9c1b4f3a995498d13 | ||
| 27 | + | ||
| 28 | + # User provided section | ||
| 29 | + | ||
| 30 | + # List of Local paths (relative to this file) that should be | ||
| 31 | + # ignored by the migrate tool. | ||
| 32 | + # | ||
| 33 | + # Files that are not part of the templates will be ignored by default. | ||
| 34 | + unmanaged_files: | ||
| 35 | + - 'lib/main.dart' | ||
| 36 | + - 'ios/Runner.xcodeproj/project.pbxproj' |
README.md
0 → 100644
| 1 | +# doublefeel_flutter | ||
| 2 | + | ||
| 3 | +A new Flutter project. | ||
| 4 | + | ||
| 5 | +## Getting Started | ||
| 6 | + | ||
| 7 | +This project is a starting point for a Flutter application. | ||
| 8 | + | ||
| 9 | +A few resources to get you started if this is your first Flutter project: | ||
| 10 | + | ||
| 11 | +- [Lab: Write your first Flutter app](https://docs.flutter.dev/get-started/codelab) | ||
| 12 | +- [Cookbook: Useful Flutter samples](https://docs.flutter.dev/cookbook) | ||
| 13 | + | ||
| 14 | +For help getting started with Flutter development, view the | ||
| 15 | +[online documentation](https://docs.flutter.dev/), which offers tutorials, | ||
| 16 | +samples, guidance on mobile development, and a full API reference. |
analysis_options.yaml
0 → 100644
| 1 | +# This file configures the analyzer, which statically analyzes Dart code to | ||
| 2 | +# check for errors, warnings, and lints. | ||
| 3 | +# | ||
| 4 | +# The issues identified by the analyzer are surfaced in the UI of Dart-enabled | ||
| 5 | +# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be | ||
| 6 | +# invoked from the command line by running `flutter analyze`. | ||
| 7 | + | ||
| 8 | +# The following line activates a set of recommended lints for Flutter apps, | ||
| 9 | +# packages, and plugins designed to encourage good coding practices. | ||
| 10 | +include: package:flutter_lints/flutter.yaml | ||
| 11 | + | ||
| 12 | +analyzer: | ||
| 13 | + exclude: | ||
| 14 | + - lib/**/*.g.dart | ||
| 15 | + - lib/app/routes/app_routes.dart | ||
| 16 | + | ||
| 17 | +linter: | ||
| 18 | + # The lint rules applied to this project can be customized in the | ||
| 19 | + # section below to disable rules from the `package:flutter_lints/flutter.yaml` | ||
| 20 | + # included above or to enable additional rules. A list of all available lints | ||
| 21 | + # and their documentation is published at https://dart.dev/lints. | ||
| 22 | + # | ||
| 23 | + # Instead of disabling a lint rule for the entire project in the | ||
| 24 | + # section below, it can also be suppressed for a single line of code | ||
| 25 | + # or a specific dart file by using the `// ignore: name_of_lint` and | ||
| 26 | + # `// ignore_for_file: name_of_lint` syntax on the line or in the file | ||
| 27 | + # producing the lint. | ||
| 28 | + rules: | ||
| 29 | + # avoid_print: false # Uncomment to disable the `avoid_print` rule | ||
| 30 | + # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule | ||
| 31 | + | ||
| 32 | +# Additional information about this file can be found at | ||
| 33 | +# https://dart.dev/guides/language/analysis-options |
android/.gitignore
0 → 100644
android/app/agconnect-services.json
0 → 100644
| 1 | +{"agcgw_all":{"SG":"connect-dra.dbankcloud.cn","SG_back":"connect-dra.hispace.hicloud.com","CN":"connect-drcn.dbankcloud.cn","CN_back":"connect-drcn.hispace.hicloud.com","RU":"connect-drru.hispace.dbankcloud.ru","RU_back":"connect-drru.hispace.dbankcloud.cn","DE":"connect-dre.dbankcloud.cn","DE_back":"connect-dre.hispace.hicloud.com"},"websocketgw_all":{"SG":"connect-ws-dra.hispace.dbankcloud.cn","SG_back":"connect-ws-dra.hispace.dbankcloud.com","CN":"connect-ws-drcn.hispace.dbankcloud.cn","CN_back":"connect-ws-drcn.hispace.dbankcloud.com","RU":"connect-ws-drru.hispace.dbankcloud.ru","RU_back":"connect-ws-drru.hispace.dbankcloud.cn","DE":"connect-ws-dre.hispace.dbankcloud.cn","DE_back":"connect-ws-dre.hispace.dbankcloud.com"},"client":{"cp_id":"900086000022307512","product_id":"461323198430851343","client_id":"1811673616249541056","client_secret":"88747662DC6FB467CDAE57C91D183E6E242AC40ACA10252310F0546CC136DB3C","project_id":"461323198430851343","app_id":"115627281","api_key":"DgEDAGFcIuuhc7kxg5R79OsFU2qRQ9nEQ+1EK8ENbMlStWgsruPnPHo6ix7N/TWt1RkdpOHHtjZKxFNAR97f9DiXK3gUeSjq5WTeog==","package_name":"com.doublefeel.app"},"oauth_client":{"client_id":"115627281","client_type":1},"app_info":{"app_id":"115627281","package_name":"com.doublefeel.app"},"configuration_version":"3.0","appInfos":[{"package_name":"com.doublefeel.app","client":{"app_id":"115627281"},"app_info":{"package_name":"com.doublefeel.app","app_id":"115627281"},"oauth_client":{"client_type":1,"client_id":"115627281"}}]} |
android/app/build.gradle
0 → 100644
| 1 | +plugins { | ||
| 2 | + id "com.android.application" | ||
| 3 | + id "kotlin-android" | ||
| 4 | + id "dev.flutter.flutter-gradle-plugin" | ||
| 5 | +} | ||
| 6 | + | ||
| 7 | +android { | ||
| 8 | + namespace = "com.doublefeel.app" | ||
| 9 | + compileSdk = flutter.compileSdkVersion | ||
| 10 | + ndkVersion = flutter.ndkVersion | ||
| 11 | + | ||
| 12 | + compileOptions { | ||
| 13 | + sourceCompatibility = JavaVersion.VERSION_1_8 | ||
| 14 | + targetCompatibility = JavaVersion.VERSION_1_8 | ||
| 15 | + } | ||
| 16 | + | ||
| 17 | + kotlinOptions { | ||
| 18 | + jvmTarget = JavaVersion.VERSION_1_8 | ||
| 19 | + } | ||
| 20 | + | ||
| 21 | + defaultConfig { | ||
| 22 | + applicationId = "com.doublefeel.app" | ||
| 23 | + minSdk = 29 | ||
| 24 | + targetSdk = flutter.targetSdkVersion | ||
| 25 | + versionCode = flutter.versionCode | ||
| 26 | + versionName = flutter.versionName | ||
| 27 | + } | ||
| 28 | + | ||
| 29 | + buildTypes { | ||
| 30 | + release { | ||
| 31 | + signingConfig = signingConfigs.debug | ||
| 32 | + } | ||
| 33 | + } | ||
| 34 | +} | ||
| 35 | + | ||
| 36 | +flutter { | ||
| 37 | + source = "../.." | ||
| 38 | +} | ||
| 39 | + | ||
| 40 | +dependencies { | ||
| 41 | + implementation "androidx.activity:activity-ktx:1.8.2" | ||
| 42 | + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.22" | ||
| 43 | + implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3" | ||
| 44 | + implementation "com.alipay.sdk:alipaysdk-android:15.8.38" | ||
| 45 | + implementation "com.huawei.hms:health:6.15.0.300" | ||
| 46 | + implementation "com.huawei.hms:wearengine:5.0.3.304" | ||
| 47 | + implementation "com.huawei.hihealth:hihealthkit:6.7.0.300" | ||
| 48 | +} |
android/app/src/main/AndroidManifest.xml
0 → 100644
| 1 | +<manifest xmlns:android="http://schemas.android.com/apk/res/android"> | ||
| 2 | + <uses-permission android:name="android.permission.INTERNET" /> | ||
| 3 | + <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> | ||
| 4 | + <uses-permission android:name="android.permission.POST_NOTIFICATIONS" /> | ||
| 5 | + | ||
| 6 | + <queries> | ||
| 7 | + <package android:name="com.huawei.health" /> | ||
| 8 | + </queries> | ||
| 9 | + | ||
| 10 | + <application | ||
| 11 | + android:label="DoubleFeel" | ||
| 12 | + android:name="${applicationName}" | ||
| 13 | + android:icon="@mipmap/ic_launcher"> | ||
| 14 | + <activity | ||
| 15 | + android:name=".MainActivity" | ||
| 16 | + android:exported="true" | ||
| 17 | + android:launchMode="singleTop" | ||
| 18 | + android:taskAffinity="" | ||
| 19 | + android:theme="@style/LaunchTheme" | ||
| 20 | + android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode" | ||
| 21 | + android:hardwareAccelerated="true" | ||
| 22 | + android:windowSoftInputMode="adjustResize"> | ||
| 23 | + <!-- Specifies an Android theme to apply to this Activity as soon as | ||
| 24 | + the Android process has started. This theme is visible to the user | ||
| 25 | + while the Flutter UI initializes. After that, this theme continues | ||
| 26 | + to determine the Window background behind the Flutter UI. --> | ||
| 27 | + <meta-data | ||
| 28 | + android:name="io.flutter.embedding.android.NormalTheme" | ||
| 29 | + android:resource="@style/NormalTheme" | ||
| 30 | + /> | ||
| 31 | + <intent-filter> | ||
| 32 | + <action android:name="android.intent.action.MAIN"/> | ||
| 33 | + <category android:name="android.intent.category.LAUNCHER"/> | ||
| 34 | + </intent-filter> | ||
| 35 | + </activity> | ||
| 36 | + <!-- Don't delete the meta-data below. | ||
| 37 | + This is used by the Flutter tool to generate GeneratedPluginRegistrant.java --> | ||
| 38 | + <meta-data | ||
| 39 | + android:name="flutterEmbedding" | ||
| 40 | + android:value="2" /> | ||
| 41 | + <meta-data | ||
| 42 | + android:name="com.huawei.hms.client.appid" | ||
| 43 | + android:value="115627281" /> | ||
| 44 | + </application> | ||
| 45 | + <!-- Required to query activities that can process text, see: | ||
| 46 | + https://developer.android.com/training/package-visibility and | ||
| 47 | + https://developer.android.com/reference/android/content/Intent#ACTION_PROCESS_TEXT. | ||
| 48 | + | ||
| 49 | + In particular, this is used by the Flutter engine in io.flutter.plugin.text.ProcessTextPlugin. --> | ||
| 50 | + <queries> | ||
| 51 | + <intent> | ||
| 52 | + <action android:name="android.intent.action.PROCESS_TEXT"/> | ||
| 53 | + <data android:mimeType="text/plain"/> | ||
| 54 | + </intent> | ||
| 55 | + </queries> | ||
| 56 | +</manifest> |
| 1 | +package com.doublefeel.app | ||
| 2 | + | ||
| 3 | +import android.content.Intent | ||
| 4 | +import androidx.activity.result.contract.ActivityResultContracts | ||
| 5 | +import com.doublefeel.app.native.AlipayHostApiImpl | ||
| 6 | +import com.doublefeel.app.native.HealthKitHostApiImpl | ||
| 7 | +import com.doublefeel.app.native.WearEngineHostApiImpl | ||
| 8 | +import com.doublefeel.app.pigeon.HealthKitHostApi | ||
| 9 | +import com.doublefeel.app.pigeon.alipay.AlipayHostApi | ||
| 10 | +import com.doublefeel.app.pigeon.wear.WearEngineHostApi | ||
| 11 | +import io.flutter.embedding.android.FlutterFragmentActivity | ||
| 12 | +import io.flutter.embedding.engine.FlutterEngine | ||
| 13 | +import java.util.concurrent.CountDownLatch | ||
| 14 | +import java.util.concurrent.TimeUnit | ||
| 15 | +import java.util.concurrent.atomic.AtomicBoolean | ||
| 16 | + | ||
| 17 | +class MainActivity : FlutterFragmentActivity() { | ||
| 18 | + | ||
| 19 | + private var healthAuthLatch: CountDownLatch? = null | ||
| 20 | + private val healthAuthGranted = AtomicBoolean(false) | ||
| 21 | + | ||
| 22 | + private val healthClientAuthLauncher = registerForActivityResult( | ||
| 23 | + ActivityResultContracts.StartActivityForResult(), | ||
| 24 | + ) { result -> | ||
| 25 | + healthAuthGranted.set(result.resultCode == RESULT_OK) | ||
| 26 | + healthAuthLatch?.countDown() | ||
| 27 | + } | ||
| 28 | + | ||
| 29 | + override fun configureFlutterEngine(flutterEngine: FlutterEngine) { | ||
| 30 | + super.configureFlutterEngine(flutterEngine) | ||
| 31 | + MainActivityHolder.activity = this | ||
| 32 | + val messenger = flutterEngine.dartExecutor.binaryMessenger | ||
| 33 | + HealthKitHostApi.setUp(messenger, HealthKitHostApiImpl(this)) | ||
| 34 | + WearEngineHostApi.setUp(messenger, WearEngineHostApiImpl(applicationContext)) | ||
| 35 | + AlipayHostApi.setUp(messenger, AlipayHostApiImpl(this)) | ||
| 36 | + } | ||
| 37 | + | ||
| 38 | + override fun onDestroy() { | ||
| 39 | + if (MainActivityHolder.activity === this) { | ||
| 40 | + MainActivityHolder.activity = null | ||
| 41 | + } | ||
| 42 | + super.onDestroy() | ||
| 43 | + } | ||
| 44 | + | ||
| 45 | + fun launchHealthClientAuth(intent: Intent): Boolean { | ||
| 46 | + healthAuthGranted.set(false) | ||
| 47 | + healthAuthLatch = CountDownLatch(1) | ||
| 48 | + healthClientAuthLauncher.launch(intent) | ||
| 49 | + return healthAuthLatch?.await(120, TimeUnit.SECONDS) == true && healthAuthGranted.get() | ||
| 50 | + } | ||
| 51 | +} | ||
| 52 | + | ||
| 53 | +object MainActivityHolder { | ||
| 54 | + var activity: MainActivity? = null | ||
| 55 | +} |
| 1 | +package com.doublefeel.app.native | ||
| 2 | + | ||
| 3 | +import com.alipay.sdk.app.PayTask | ||
| 4 | +import com.doublefeel.app.MainActivity | ||
| 5 | +import com.doublefeel.app.pigeon.alipay.AliPayResultCode | ||
| 6 | +import com.doublefeel.app.pigeon.alipay.AlipayHostApi | ||
| 7 | +import kotlinx.coroutines.runBlocking | ||
| 8 | +import kotlinx.coroutines.Dispatchers | ||
| 9 | +import kotlinx.coroutines.withContext | ||
| 10 | + | ||
| 11 | +/** Alipay SDK host implementation for Pigeon. */ | ||
| 12 | +class AlipayHostApiImpl( | ||
| 13 | + private val activity: MainActivity, | ||
| 14 | +) : AlipayHostApi { | ||
| 15 | + | ||
| 16 | + override fun launchAliPay(prepayData: String): AliPayResultCode { | ||
| 17 | + return runBlocking { | ||
| 18 | + withContext(Dispatchers.IO) { | ||
| 19 | + runCatching { | ||
| 20 | + val payTask = PayTask(activity) | ||
| 21 | + val result = payTask.payV2(prepayData, true) | ||
| 22 | + when (result["resultStatus"]) { | ||
| 23 | + "9000" -> AliPayResultCode.SUCCESS | ||
| 24 | + "6001" -> AliPayResultCode.CANCEL | ||
| 25 | + else -> AliPayResultCode.ERROR | ||
| 26 | + } | ||
| 27 | + }.getOrElse { AliPayResultCode.ERROR } | ||
| 28 | + } | ||
| 29 | + } | ||
| 30 | + } | ||
| 31 | +} |
| 1 | +package com.doublefeel.app.native | ||
| 2 | + | ||
| 3 | +import com.doublefeel.app.MainActivity | ||
| 4 | +import com.doublefeel.app.pigeon.HealthKitHostApi | ||
| 5 | +import com.doublefeel.app.pigeon.HealthUploadResult | ||
| 6 | + | ||
| 7 | +class HealthKitHostApiImpl( | ||
| 8 | + private val activity: MainActivity, | ||
| 9 | +) : HealthKitHostApi { | ||
| 10 | + | ||
| 11 | + override fun checkHealthAppAuthorization(): Boolean { | ||
| 12 | + return HuaweiHealthBridge.checkHealthAppAuthorization(activity.applicationContext) | ||
| 13 | + } | ||
| 14 | + | ||
| 15 | + override fun getHealthServerAuthUrl(): String { | ||
| 16 | + return HuaweiHealthBridge.getHealthServerAuthUrl() | ||
| 17 | + } | ||
| 18 | + | ||
| 19 | + override fun requestHealthClientAuthorization(): Boolean { | ||
| 20 | + return HuaweiHealthBridge.requestClientAuthorization(activity) | ||
| 21 | + } | ||
| 22 | + | ||
| 23 | + override fun cancelHealthAppAuthorization(): Boolean { | ||
| 24 | + return HuaweiHealthBridge.cancelHealthAppAuthorization(activity) | ||
| 25 | + } | ||
| 26 | + | ||
| 27 | + override fun performHealthUpload(): HealthUploadResult { | ||
| 28 | + return HealthUploadResult( | ||
| 29 | + commonUploadSuccess = false, | ||
| 30 | + sleepUploadSuccess = false, | ||
| 31 | + errorMessage = "Native bulk upload runs via Dart HealthKitUploadService; HMS read bridge pending", | ||
| 32 | + ) | ||
| 33 | + } | ||
| 34 | +} |
| 1 | +package com.doublefeel.app.native | ||
| 2 | + | ||
| 3 | +import android.app.Activity | ||
| 4 | +import android.content.Context | ||
| 5 | +import android.content.Intent | ||
| 6 | +import android.net.Uri | ||
| 7 | +import androidx.core.net.toUri | ||
| 8 | +import com.doublefeel.app.MainActivity | ||
| 9 | +import com.huawei.hihealthkit.data.store.HiHealthDataStore | ||
| 10 | +import com.huawei.hms.hihealth.HuaweiHiHealth | ||
| 11 | +import com.huawei.hms.hihealth.SettingController | ||
| 12 | +import com.huawei.hms.hihealth.data.Scopes | ||
| 13 | +import com.huawei.hihealthkit.data.HiHealthExtendScope | ||
| 14 | +import java.util.UUID | ||
| 15 | +import java.util.concurrent.CountDownLatch | ||
| 16 | +import java.util.concurrent.TimeUnit | ||
| 17 | +import kotlin.coroutines.resume | ||
| 18 | +import kotlin.coroutines.suspendCoroutine | ||
| 19 | +import kotlinx.coroutines.runBlocking | ||
| 20 | + | ||
| 21 | +/** Huawei Health Kit authorization and data bridge. */ | ||
| 22 | +object HuaweiHealthBridge { | ||
| 23 | + | ||
| 24 | + private const val APP_ID_HUAWEI = "115627281" | ||
| 25 | + private const val CALLBACK_URL_HUAWEI = | ||
| 26 | + "https://h5hosting.dbankcdn.com/cch5/healthkit/oauth-h5/oauth-callback.html" | ||
| 27 | + | ||
| 28 | + private val scopes = arrayOf( | ||
| 29 | + Scopes.HEALTHKIT_HEARTRATE_READ, | ||
| 30 | + Scopes.HEALTHKIT_CALORIES_READ, | ||
| 31 | + Scopes.HEALTHKIT_STEP_READ, | ||
| 32 | + Scopes.HEALTHKIT_SLEEP_READ, | ||
| 33 | + Scopes.HEALTHKIT_OXYGEN_SATURATION_READ, | ||
| 34 | + Scopes.HEALTHKIT_STRENGTH_READ, | ||
| 35 | + Scopes.HEALTHKIT_HISTORYDATA_OPEN_MONTH, | ||
| 36 | + "https://www.huawei.com/healthkit/activehours.read", | ||
| 37 | + HiHealthExtendScope.HEALTHKIT_EXTEND_REALTIME_HEART_READ, | ||
| 38 | + ) | ||
| 39 | + | ||
| 40 | + private val fullScopes = scopes + arrayOf("openid", "profile") | ||
| 41 | + | ||
| 42 | + fun getHealthServerAuthUrl(): String { | ||
| 43 | + val uri = "https://oauth-login.cloud.huawei.com/oauth2/v3/authorize".toUri() | ||
| 44 | + return uri.buildUpon() | ||
| 45 | + .appendQueryParameter("client_id", APP_ID_HUAWEI) | ||
| 46 | + .appendQueryParameter("response_type", "code") | ||
| 47 | + .appendQueryParameter("redirect_uri", CALLBACK_URL_HUAWEI) | ||
| 48 | + .appendQueryParameter("scope", fullScopes.joinToString(" ")) | ||
| 49 | + .appendQueryParameter("state", UUID.randomUUID().toString()) | ||
| 50 | + .appendQueryParameter("display", "touch") | ||
| 51 | + .appendQueryParameter("access_type", "offline") | ||
| 52 | + .build() | ||
| 53 | + .toString() | ||
| 54 | + } | ||
| 55 | + | ||
| 56 | + fun createClientAuthIntent(context: Context): Intent? { | ||
| 57 | + return runCatching { | ||
| 58 | + val settingController = HuaweiHiHealth.getSettingController(context) | ||
| 59 | + settingController.requestAuthorizationIntent(fullScopes, true) | ||
| 60 | + }.getOrNull() | ||
| 61 | + } | ||
| 62 | + | ||
| 63 | + fun checkHealthAppAuthorization(context: Context): Boolean { | ||
| 64 | + return runBlocking { | ||
| 65 | + suspendCoroutine { continuation -> | ||
| 66 | + try { | ||
| 67 | + val settingController = HuaweiHiHealth.getSettingController(context) | ||
| 68 | + settingController.healthAppAuthorization | ||
| 69 | + .addOnSuccessListener { result -> continuation.resume(result) } | ||
| 70 | + .addOnFailureListener { continuation.resume(false) } | ||
| 71 | + } catch (_: Throwable) { | ||
| 72 | + continuation.resume(false) | ||
| 73 | + } | ||
| 74 | + } | ||
| 75 | + } | ||
| 76 | + } | ||
| 77 | + | ||
| 78 | + fun requestClientAuthorization(activity: MainActivity): Boolean { | ||
| 79 | + val intent = createClientAuthIntent(activity) ?: return false | ||
| 80 | + return activity.launchHealthClientAuth(intent) | ||
| 81 | + } | ||
| 82 | + | ||
| 83 | + fun cancelHealthAppAuthorization(activity: Activity): Boolean { | ||
| 84 | + return runBlocking { | ||
| 85 | + suspendCoroutine { continuation -> | ||
| 86 | + try { | ||
| 87 | + val consentsController = HuaweiHiHealth.getConsentsController(activity) | ||
| 88 | + consentsController.cancelAuthorization(false) | ||
| 89 | + .addOnSuccessListener { continuation.resume(true) } | ||
| 90 | + .addOnFailureListener { continuation.resume(false) } | ||
| 91 | + } catch (_: Throwable) { | ||
| 92 | + continuation.resume(false) | ||
| 93 | + } | ||
| 94 | + } | ||
| 95 | + } | ||
| 96 | + } | ||
| 97 | +} |
| 1 | +package com.doublefeel.app.native | ||
| 2 | + | ||
| 3 | +import android.content.Context | ||
| 4 | +import com.huawei.wearengine.HiWear | ||
| 5 | +import com.huawei.wearengine.device.Device | ||
| 6 | +import com.huawei.wearengine.p2p.Message | ||
| 7 | +import com.huawei.wearengine.p2p.P2pClient | ||
| 8 | +import com.huawei.wearengine.p2p.SendCallback | ||
| 9 | +import java.nio.charset.StandardCharsets | ||
| 10 | +import kotlin.coroutines.resume | ||
| 11 | +import kotlin.coroutines.suspendCoroutine | ||
| 12 | +import kotlinx.coroutines.runBlocking | ||
| 13 | + | ||
| 14 | +/** Huawei Wear Engine P2P bridge. */ | ||
| 15 | +object HuaweiWearBridge { | ||
| 16 | + | ||
| 17 | + private const val WATCH_APP_PACKAGE = "com.doublefeel.watchapp" | ||
| 18 | + private const val WATCH_APP_FINGER_PRINT = | ||
| 19 | + "${WATCH_APP_PACKAGE}_BETLDdeS3sjRDIkykOBVVAAyTWNBAdgYY0Y5lSEnZl2oH1xo1aHKtSolvrcbUWbu1vbD3JknBBRLJHgYhqI6lXo=" | ||
| 20 | + | ||
| 21 | + fun hasAvailableDevices(context: Context): Boolean { | ||
| 22 | + return runBlocking { | ||
| 23 | + suspendCoroutine { continuation -> | ||
| 24 | + runCatching { | ||
| 25 | + HiWear.getDeviceClient(context) | ||
| 26 | + .hasAvailableDevices() | ||
| 27 | + .addOnSuccessListener { continuation.resume(it) } | ||
| 28 | + .addOnFailureListener { continuation.resume(false) } | ||
| 29 | + }.onFailure { continuation.resume(false) } | ||
| 30 | + } | ||
| 31 | + } | ||
| 32 | + } | ||
| 33 | + | ||
| 34 | + fun getConnectedDevice(context: Context): Device? { | ||
| 35 | + return runBlocking { | ||
| 36 | + suspendCoroutine { continuation -> | ||
| 37 | + runCatching { | ||
| 38 | + HiWear.getDeviceClient(context) | ||
| 39 | + .bondedDevices | ||
| 40 | + .addOnSuccessListener { devices -> | ||
| 41 | + continuation.resume(devices?.firstOrNull { it.isConnected }) | ||
| 42 | + } | ||
| 43 | + .addOnFailureListener { continuation.resume(null) } | ||
| 44 | + }.onFailure { continuation.resume(null) } | ||
| 45 | + } | ||
| 46 | + } | ||
| 47 | + } | ||
| 48 | + | ||
| 49 | + fun registerMessageReceiver(context: Context, device: Device): Boolean { | ||
| 50 | + return runBlocking { | ||
| 51 | + suspendCoroutine { continuation -> | ||
| 52 | + runCatching { | ||
| 53 | + val p2pClient = HiWear.getP2pClient(context).apply { | ||
| 54 | + setPeerPkgName(WATCH_APP_PACKAGE) | ||
| 55 | + setPeerFingerPrint(WATCH_APP_FINGER_PRINT) | ||
| 56 | + } | ||
| 57 | + p2pClient.registerReceiver(device) { _ -> } | ||
| 58 | + .addOnSuccessListener { continuation.resume(true) } | ||
| 59 | + .addOnFailureListener { continuation.resume(false) } | ||
| 60 | + }.onFailure { continuation.resume(false) } | ||
| 61 | + } | ||
| 62 | + } | ||
| 63 | + } | ||
| 64 | + | ||
| 65 | + fun sendTextMessage(context: Context, device: Device, text: String): Boolean { | ||
| 66 | + return runBlocking { | ||
| 67 | + suspendCoroutine { continuation -> | ||
| 68 | + runCatching { | ||
| 69 | + val p2pClient = HiWear.getP2pClient(context).apply { | ||
| 70 | + setPeerPkgName(WATCH_APP_PACKAGE) | ||
| 71 | + setPeerFingerPrint(WATCH_APP_FINGER_PRINT) | ||
| 72 | + } | ||
| 73 | + val message = Message.Builder() | ||
| 74 | + .setPayload(text.toByteArray(StandardCharsets.UTF_8)) | ||
| 75 | + .build() | ||
| 76 | + p2pClient.send(device, message, object : SendCallback { | ||
| 77 | + override fun onSendResult(resultCode: Int) { | ||
| 78 | + continuation.resume(resultCode == 200 || resultCode == 202) | ||
| 79 | + } | ||
| 80 | + | ||
| 81 | + override fun onSendProgress(progress: Long) {} | ||
| 82 | + }).addOnFailureListener { continuation.resume(false) } | ||
| 83 | + }.onFailure { continuation.resume(false) } | ||
| 84 | + } | ||
| 85 | + } | ||
| 86 | + } | ||
| 87 | + | ||
| 88 | + fun isWatchAppInstalled(context: Context, device: Device): Boolean { | ||
| 89 | + return runBlocking { | ||
| 90 | + suspendCoroutine { continuation -> | ||
| 91 | + runCatching { | ||
| 92 | + HiWear.getP2pClient(context) | ||
| 93 | + .isAppInstalled(device, WATCH_APP_PACKAGE) | ||
| 94 | + .addOnSuccessListener { continuation.resume(it) } | ||
| 95 | + .addOnFailureListener { continuation.resume(false) } | ||
| 96 | + }.onFailure { continuation.resume(false) } | ||
| 97 | + } | ||
| 98 | + } | ||
| 99 | + } | ||
| 100 | +} |
| 1 | +package com.doublefeel.app.native | ||
| 2 | + | ||
| 3 | +import android.content.Context | ||
| 4 | +import com.doublefeel.app.pigeon.wear.WearDeviceInfo | ||
| 5 | +import com.doublefeel.app.pigeon.wear.WearEngineHostApi | ||
| 6 | +import com.huawei.wearengine.device.Device | ||
| 7 | + | ||
| 8 | +class WearEngineHostApiImpl( | ||
| 9 | + private val context: Context, | ||
| 10 | +) : WearEngineHostApi { | ||
| 11 | + | ||
| 12 | + private var connectedDevice: Device? = null | ||
| 13 | + | ||
| 14 | + override fun hasAvailableDevices(): Boolean { | ||
| 15 | + return HuaweiWearBridge.hasAvailableDevices(context) | ||
| 16 | + } | ||
| 17 | + | ||
| 18 | + override fun checkConnectedDevice(): WearDeviceInfo? { | ||
| 19 | + val device = HuaweiWearBridge.getConnectedDevice(context) | ||
| 20 | + if (device == null) { | ||
| 21 | + connectedDevice = null | ||
| 22 | + return null | ||
| 23 | + } | ||
| 24 | + if (HuaweiWearBridge.isWatchAppInstalled(context, device)) { | ||
| 25 | + connectedDevice = device | ||
| 26 | + return WearDeviceInfo( | ||
| 27 | + deviceId = device.uuid, | ||
| 28 | + deviceName = device.name, | ||
| 29 | + isConnected = device.isConnected, | ||
| 30 | + ) | ||
| 31 | + } | ||
| 32 | + connectedDevice = null | ||
| 33 | + return null | ||
| 34 | + } | ||
| 35 | + | ||
| 36 | + override fun registerMessageReceiver(): Boolean { | ||
| 37 | + val device = connectedDevice ?: HuaweiWearBridge.getConnectedDevice(context) | ||
| 38 | + if (device == null) { | ||
| 39 | + return false | ||
| 40 | + } | ||
| 41 | + connectedDevice = device | ||
| 42 | + return HuaweiWearBridge.registerMessageReceiver(context, device) | ||
| 43 | + } | ||
| 44 | + | ||
| 45 | + override fun sendTextMessage(message: String): Boolean { | ||
| 46 | + val device = connectedDevice ?: return false | ||
| 47 | + return HuaweiWearBridge.sendTextMessage(context, device, message) | ||
| 48 | + } | ||
| 49 | + | ||
| 50 | + override fun sendWatchSyncPayload(jsonPayload: String): Boolean { | ||
| 51 | + return sendTextMessage(jsonPayload) | ||
| 52 | + } | ||
| 53 | +} |
| 1 | +// // Copyright 2013 The Flutter Authors. All rights reserved. | ||
| 2 | +// Autogenerated from Pigeon (v25.5.0), do not edit directly. | ||
| 3 | +// See also: https://pub.dev/packages/pigeon | ||
| 4 | +@file:Suppress("UNCHECKED_CAST", "ArrayInDataClass") | ||
| 5 | + | ||
| 6 | +package com.doublefeel.app.pigeon.alipay | ||
| 7 | + | ||
| 8 | +import android.util.Log | ||
| 9 | +import io.flutter.plugin.common.BasicMessageChannel | ||
| 10 | +import io.flutter.plugin.common.BinaryMessenger | ||
| 11 | +import io.flutter.plugin.common.EventChannel | ||
| 12 | +import io.flutter.plugin.common.MessageCodec | ||
| 13 | +import io.flutter.plugin.common.StandardMethodCodec | ||
| 14 | +import io.flutter.plugin.common.StandardMessageCodec | ||
| 15 | +import java.io.ByteArrayOutputStream | ||
| 16 | +import java.nio.ByteBuffer | ||
| 17 | +private object AlipayApiPigeonUtils { | ||
| 18 | + | ||
| 19 | + fun wrapResult(result: Any?): List<Any?> { | ||
| 20 | + return listOf(result) | ||
| 21 | + } | ||
| 22 | + | ||
| 23 | + fun wrapError(exception: Throwable): List<Any?> { | ||
| 24 | + return if (exception is FlutterError) { | ||
| 25 | + listOf( | ||
| 26 | + exception.code, | ||
| 27 | + exception.message, | ||
| 28 | + exception.details | ||
| 29 | + ) | ||
| 30 | + } else { | ||
| 31 | + listOf( | ||
| 32 | + exception.javaClass.simpleName, | ||
| 33 | + exception.toString(), | ||
| 34 | + "Cause: " + exception.cause + ", Stacktrace: " + Log.getStackTraceString(exception) | ||
| 35 | + ) | ||
| 36 | + } | ||
| 37 | + } | ||
| 38 | +} | ||
| 39 | + | ||
| 40 | +/** | ||
| 41 | + * Error class for passing custom error details to Flutter via a thrown PlatformException. | ||
| 42 | + * @property code The error code. | ||
| 43 | + * @property message The error message. | ||
| 44 | + * @property details The error details. Must be a datatype supported by the api codec. | ||
| 45 | + */ | ||
| 46 | +class FlutterError ( | ||
| 47 | + val code: String, | ||
| 48 | + override val message: String? = null, | ||
| 49 | + val details: Any? = null | ||
| 50 | +) : Throwable() | ||
| 51 | + | ||
| 52 | +/** Alipay payment result codes. */ | ||
| 53 | +enum class AliPayResultCode(val raw: Int) { | ||
| 54 | + SUCCESS(0), | ||
| 55 | + CANCEL(1), | ||
| 56 | + ERROR(2), | ||
| 57 | + UNSUPPORTED(3); | ||
| 58 | + | ||
| 59 | + companion object { | ||
| 60 | + fun ofRaw(raw: Int): AliPayResultCode? { | ||
| 61 | + return values().firstOrNull { it.raw == raw } | ||
| 62 | + } | ||
| 63 | + } | ||
| 64 | +} | ||
| 65 | +private open class AlipayApiPigeonCodec : StandardMessageCodec() { | ||
| 66 | + override fun readValueOfType(type: Byte, buffer: ByteBuffer): Any? { | ||
| 67 | + return when (type) { | ||
| 68 | + 129.toByte() -> { | ||
| 69 | + return (readValue(buffer) as Long?)?.let { | ||
| 70 | + AliPayResultCode.ofRaw(it.toInt()) | ||
| 71 | + } | ||
| 72 | + } | ||
| 73 | + else -> super.readValueOfType(type, buffer) | ||
| 74 | + } | ||
| 75 | + } | ||
| 76 | + override fun writeValue(stream: ByteArrayOutputStream, value: Any?) { | ||
| 77 | + when (value) { | ||
| 78 | + is AliPayResultCode -> { | ||
| 79 | + stream.write(129) | ||
| 80 | + writeValue(stream, value.raw) | ||
| 81 | + } | ||
| 82 | + else -> super.writeValue(stream, value) | ||
| 83 | + } | ||
| 84 | + } | ||
| 85 | +} | ||
| 86 | + | ||
| 87 | +/** Generated interface from Pigeon that represents a handler of messages from Flutter. */ | ||
| 88 | +interface AlipayHostApi { | ||
| 89 | + fun launchAliPay(prepayData: String): AliPayResultCode | ||
| 90 | + | ||
| 91 | + companion object { | ||
| 92 | + /** The codec used by AlipayHostApi. */ | ||
| 93 | + val codec: MessageCodec<Any?> by lazy { | ||
| 94 | + AlipayApiPigeonCodec() | ||
| 95 | + } | ||
| 96 | + /** Sets up an instance of `AlipayHostApi` to handle messages through the `binaryMessenger`. */ | ||
| 97 | + @JvmOverloads | ||
| 98 | + fun setUp(binaryMessenger: BinaryMessenger, api: AlipayHostApi?, messageChannelSuffix: String = "") { | ||
| 99 | + val separatedMessageChannelSuffix = if (messageChannelSuffix.isNotEmpty()) ".$messageChannelSuffix" else "" | ||
| 100 | + run { | ||
| 101 | + val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.doublefeel_flutter.AlipayHostApi.launchAliPay$separatedMessageChannelSuffix", codec) | ||
| 102 | + if (api != null) { | ||
| 103 | + channel.setMessageHandler { message, reply -> | ||
| 104 | + val args = message as List<Any?> | ||
| 105 | + val prepayDataArg = args[0] as String | ||
| 106 | + val wrapped: List<Any?> = try { | ||
| 107 | + listOf(api.launchAliPay(prepayDataArg)) | ||
| 108 | + } catch (exception: Throwable) { | ||
| 109 | + AlipayApiPigeonUtils.wrapError(exception) | ||
| 110 | + } | ||
| 111 | + reply.reply(wrapped) | ||
| 112 | + } | ||
| 113 | + } else { | ||
| 114 | + channel.setMessageHandler(null) | ||
| 115 | + } | ||
| 116 | + } | ||
| 117 | + } | ||
| 118 | + } | ||
| 119 | +} |
| 1 | +// // Copyright 2013 The Flutter Authors. All rights reserved. | ||
| 2 | +// Autogenerated from Pigeon (v25.5.0), do not edit directly. | ||
| 3 | +// See also: https://pub.dev/packages/pigeon | ||
| 4 | +@file:Suppress("UNCHECKED_CAST", "ArrayInDataClass") | ||
| 5 | + | ||
| 6 | +package com.doublefeel.app.pigeon | ||
| 7 | + | ||
| 8 | +import android.util.Log | ||
| 9 | +import io.flutter.plugin.common.BasicMessageChannel | ||
| 10 | +import io.flutter.plugin.common.BinaryMessenger | ||
| 11 | +import io.flutter.plugin.common.EventChannel | ||
| 12 | +import io.flutter.plugin.common.MessageCodec | ||
| 13 | +import io.flutter.plugin.common.StandardMethodCodec | ||
| 14 | +import io.flutter.plugin.common.StandardMessageCodec | ||
| 15 | +import java.io.ByteArrayOutputStream | ||
| 16 | +import java.nio.ByteBuffer | ||
| 17 | +private object HealthKitApiPigeonUtils { | ||
| 18 | + | ||
| 19 | + fun wrapResult(result: Any?): List<Any?> { | ||
| 20 | + return listOf(result) | ||
| 21 | + } | ||
| 22 | + | ||
| 23 | + fun wrapError(exception: Throwable): List<Any?> { | ||
| 24 | + return if (exception is FlutterError) { | ||
| 25 | + listOf( | ||
| 26 | + exception.code, | ||
| 27 | + exception.message, | ||
| 28 | + exception.details | ||
| 29 | + ) | ||
| 30 | + } else { | ||
| 31 | + listOf( | ||
| 32 | + exception.javaClass.simpleName, | ||
| 33 | + exception.toString(), | ||
| 34 | + "Cause: " + exception.cause + ", Stacktrace: " + Log.getStackTraceString(exception) | ||
| 35 | + ) | ||
| 36 | + } | ||
| 37 | + } | ||
| 38 | + fun deepEquals(a: Any?, b: Any?): Boolean { | ||
| 39 | + if (a is ByteArray && b is ByteArray) { | ||
| 40 | + return a.contentEquals(b) | ||
| 41 | + } | ||
| 42 | + if (a is IntArray && b is IntArray) { | ||
| 43 | + return a.contentEquals(b) | ||
| 44 | + } | ||
| 45 | + if (a is LongArray && b is LongArray) { | ||
| 46 | + return a.contentEquals(b) | ||
| 47 | + } | ||
| 48 | + if (a is DoubleArray && b is DoubleArray) { | ||
| 49 | + return a.contentEquals(b) | ||
| 50 | + } | ||
| 51 | + if (a is Array<*> && b is Array<*>) { | ||
| 52 | + return a.size == b.size && | ||
| 53 | + a.indices.all{ deepEquals(a[it], b[it]) } | ||
| 54 | + } | ||
| 55 | + if (a is List<*> && b is List<*>) { | ||
| 56 | + return a.size == b.size && | ||
| 57 | + a.indices.all{ deepEquals(a[it], b[it]) } | ||
| 58 | + } | ||
| 59 | + if (a is Map<*, *> && b is Map<*, *>) { | ||
| 60 | + return a.size == b.size && a.all { | ||
| 61 | + (b as Map<Any?, Any?>).containsKey(it.key) && | ||
| 62 | + deepEquals(it.value, b[it.key]) | ||
| 63 | + } | ||
| 64 | + } | ||
| 65 | + return a == b | ||
| 66 | + } | ||
| 67 | + | ||
| 68 | +} | ||
| 69 | + | ||
| 70 | +/** | ||
| 71 | + * Error class for passing custom error details to Flutter via a thrown PlatformException. | ||
| 72 | + * @property code The error code. | ||
| 73 | + * @property message The error message. | ||
| 74 | + * @property details The error details. Must be a datatype supported by the api codec. | ||
| 75 | + */ | ||
| 76 | +class FlutterError ( | ||
| 77 | + val code: String, | ||
| 78 | + override val message: String? = null, | ||
| 79 | + val details: Any? = null | ||
| 80 | +) : Throwable() | ||
| 81 | + | ||
| 82 | +/** Generated class from Pigeon that represents data sent in messages. */ | ||
| 83 | +data class HealthUploadResult ( | ||
| 84 | + val commonUploadSuccess: Boolean, | ||
| 85 | + val sleepUploadSuccess: Boolean, | ||
| 86 | + val errorMessage: String? = null | ||
| 87 | +) | ||
| 88 | + { | ||
| 89 | + companion object { | ||
| 90 | + fun fromList(pigeonVar_list: List<Any?>): HealthUploadResult { | ||
| 91 | + val commonUploadSuccess = pigeonVar_list[0] as Boolean | ||
| 92 | + val sleepUploadSuccess = pigeonVar_list[1] as Boolean | ||
| 93 | + val errorMessage = pigeonVar_list[2] as String? | ||
| 94 | + return HealthUploadResult(commonUploadSuccess, sleepUploadSuccess, errorMessage) | ||
| 95 | + } | ||
| 96 | + } | ||
| 97 | + fun toList(): List<Any?> { | ||
| 98 | + return listOf( | ||
| 99 | + commonUploadSuccess, | ||
| 100 | + sleepUploadSuccess, | ||
| 101 | + errorMessage, | ||
| 102 | + ) | ||
| 103 | + } | ||
| 104 | + override fun equals(other: Any?): Boolean { | ||
| 105 | + if (other !is HealthUploadResult) { | ||
| 106 | + return false | ||
| 107 | + } | ||
| 108 | + if (this === other) { | ||
| 109 | + return true | ||
| 110 | + } | ||
| 111 | + return HealthKitApiPigeonUtils.deepEquals(toList(), other.toList()) } | ||
| 112 | + | ||
| 113 | + override fun hashCode(): Int = toList().hashCode() | ||
| 114 | +} | ||
| 115 | +private open class HealthKitApiPigeonCodec : StandardMessageCodec() { | ||
| 116 | + override fun readValueOfType(type: Byte, buffer: ByteBuffer): Any? { | ||
| 117 | + return when (type) { | ||
| 118 | + 129.toByte() -> { | ||
| 119 | + return (readValue(buffer) as? List<Any?>)?.let { | ||
| 120 | + HealthUploadResult.fromList(it) | ||
| 121 | + } | ||
| 122 | + } | ||
| 123 | + else -> super.readValueOfType(type, buffer) | ||
| 124 | + } | ||
| 125 | + } | ||
| 126 | + override fun writeValue(stream: ByteArrayOutputStream, value: Any?) { | ||
| 127 | + when (value) { | ||
| 128 | + is HealthUploadResult -> { | ||
| 129 | + stream.write(129) | ||
| 130 | + writeValue(stream, value.toList()) | ||
| 131 | + } | ||
| 132 | + else -> super.writeValue(stream, value) | ||
| 133 | + } | ||
| 134 | + } | ||
| 135 | +} | ||
| 136 | + | ||
| 137 | +/** Generated interface from Pigeon that represents a handler of messages from Flutter. */ | ||
| 138 | +interface HealthKitHostApi { | ||
| 139 | + fun checkHealthAppAuthorization(): Boolean | ||
| 140 | + fun getHealthServerAuthUrl(): String | ||
| 141 | + /** Opens Huawei Health client authorization UI. Returns whether user granted. */ | ||
| 142 | + fun requestHealthClientAuthorization(): Boolean | ||
| 143 | + fun cancelHealthAppAuthorization(): Boolean | ||
| 144 | + /** Runs native health read and server upload pipeline. */ | ||
| 145 | + fun performHealthUpload(): HealthUploadResult | ||
| 146 | + | ||
| 147 | + companion object { | ||
| 148 | + /** The codec used by HealthKitHostApi. */ | ||
| 149 | + val codec: MessageCodec<Any?> by lazy { | ||
| 150 | + HealthKitApiPigeonCodec() | ||
| 151 | + } | ||
| 152 | + /** Sets up an instance of `HealthKitHostApi` to handle messages through the `binaryMessenger`. */ | ||
| 153 | + @JvmOverloads | ||
| 154 | + fun setUp(binaryMessenger: BinaryMessenger, api: HealthKitHostApi?, messageChannelSuffix: String = "") { | ||
| 155 | + val separatedMessageChannelSuffix = if (messageChannelSuffix.isNotEmpty()) ".$messageChannelSuffix" else "" | ||
| 156 | + run { | ||
| 157 | + val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.doublefeel_flutter.HealthKitHostApi.checkHealthAppAuthorization$separatedMessageChannelSuffix", codec) | ||
| 158 | + if (api != null) { | ||
| 159 | + channel.setMessageHandler { _, reply -> | ||
| 160 | + val wrapped: List<Any?> = try { | ||
| 161 | + listOf(api.checkHealthAppAuthorization()) | ||
| 162 | + } catch (exception: Throwable) { | ||
| 163 | + HealthKitApiPigeonUtils.wrapError(exception) | ||
| 164 | + } | ||
| 165 | + reply.reply(wrapped) | ||
| 166 | + } | ||
| 167 | + } else { | ||
| 168 | + channel.setMessageHandler(null) | ||
| 169 | + } | ||
| 170 | + } | ||
| 171 | + run { | ||
| 172 | + val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.doublefeel_flutter.HealthKitHostApi.getHealthServerAuthUrl$separatedMessageChannelSuffix", codec) | ||
| 173 | + if (api != null) { | ||
| 174 | + channel.setMessageHandler { _, reply -> | ||
| 175 | + val wrapped: List<Any?> = try { | ||
| 176 | + listOf(api.getHealthServerAuthUrl()) | ||
| 177 | + } catch (exception: Throwable) { | ||
| 178 | + HealthKitApiPigeonUtils.wrapError(exception) | ||
| 179 | + } | ||
| 180 | + reply.reply(wrapped) | ||
| 181 | + } | ||
| 182 | + } else { | ||
| 183 | + channel.setMessageHandler(null) | ||
| 184 | + } | ||
| 185 | + } | ||
| 186 | + run { | ||
| 187 | + val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.doublefeel_flutter.HealthKitHostApi.requestHealthClientAuthorization$separatedMessageChannelSuffix", codec) | ||
| 188 | + if (api != null) { | ||
| 189 | + channel.setMessageHandler { _, reply -> | ||
| 190 | + val wrapped: List<Any?> = try { | ||
| 191 | + listOf(api.requestHealthClientAuthorization()) | ||
| 192 | + } catch (exception: Throwable) { | ||
| 193 | + HealthKitApiPigeonUtils.wrapError(exception) | ||
| 194 | + } | ||
| 195 | + reply.reply(wrapped) | ||
| 196 | + } | ||
| 197 | + } else { | ||
| 198 | + channel.setMessageHandler(null) | ||
| 199 | + } | ||
| 200 | + } | ||
| 201 | + run { | ||
| 202 | + val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.doublefeel_flutter.HealthKitHostApi.cancelHealthAppAuthorization$separatedMessageChannelSuffix", codec) | ||
| 203 | + if (api != null) { | ||
| 204 | + channel.setMessageHandler { _, reply -> | ||
| 205 | + val wrapped: List<Any?> = try { | ||
| 206 | + listOf(api.cancelHealthAppAuthorization()) | ||
| 207 | + } catch (exception: Throwable) { | ||
| 208 | + HealthKitApiPigeonUtils.wrapError(exception) | ||
| 209 | + } | ||
| 210 | + reply.reply(wrapped) | ||
| 211 | + } | ||
| 212 | + } else { | ||
| 213 | + channel.setMessageHandler(null) | ||
| 214 | + } | ||
| 215 | + } | ||
| 216 | + run { | ||
| 217 | + val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.doublefeel_flutter.HealthKitHostApi.performHealthUpload$separatedMessageChannelSuffix", codec) | ||
| 218 | + if (api != null) { | ||
| 219 | + channel.setMessageHandler { _, reply -> | ||
| 220 | + val wrapped: List<Any?> = try { | ||
| 221 | + listOf(api.performHealthUpload()) | ||
| 222 | + } catch (exception: Throwable) { | ||
| 223 | + HealthKitApiPigeonUtils.wrapError(exception) | ||
| 224 | + } | ||
| 225 | + reply.reply(wrapped) | ||
| 226 | + } | ||
| 227 | + } else { | ||
| 228 | + channel.setMessageHandler(null) | ||
| 229 | + } | ||
| 230 | + } | ||
| 231 | + } | ||
| 232 | + } | ||
| 233 | +} |
| 1 | +// // Copyright 2013 The Flutter Authors. All rights reserved. | ||
| 2 | +// Autogenerated from Pigeon (v25.5.0), do not edit directly. | ||
| 3 | +// See also: https://pub.dev/packages/pigeon | ||
| 4 | +@file:Suppress("UNCHECKED_CAST", "ArrayInDataClass") | ||
| 5 | + | ||
| 6 | +package com.doublefeel.app.pigeon.wear | ||
| 7 | + | ||
| 8 | +import android.util.Log | ||
| 9 | +import io.flutter.plugin.common.BasicMessageChannel | ||
| 10 | +import io.flutter.plugin.common.BinaryMessenger | ||
| 11 | +import io.flutter.plugin.common.EventChannel | ||
| 12 | +import io.flutter.plugin.common.MessageCodec | ||
| 13 | +import io.flutter.plugin.common.StandardMethodCodec | ||
| 14 | +import io.flutter.plugin.common.StandardMessageCodec | ||
| 15 | +import java.io.ByteArrayOutputStream | ||
| 16 | +import java.nio.ByteBuffer | ||
| 17 | +private object WearEngineApiPigeonUtils { | ||
| 18 | + | ||
| 19 | + fun wrapResult(result: Any?): List<Any?> { | ||
| 20 | + return listOf(result) | ||
| 21 | + } | ||
| 22 | + | ||
| 23 | + fun wrapError(exception: Throwable): List<Any?> { | ||
| 24 | + return if (exception is FlutterError) { | ||
| 25 | + listOf( | ||
| 26 | + exception.code, | ||
| 27 | + exception.message, | ||
| 28 | + exception.details | ||
| 29 | + ) | ||
| 30 | + } else { | ||
| 31 | + listOf( | ||
| 32 | + exception.javaClass.simpleName, | ||
| 33 | + exception.toString(), | ||
| 34 | + "Cause: " + exception.cause + ", Stacktrace: " + Log.getStackTraceString(exception) | ||
| 35 | + ) | ||
| 36 | + } | ||
| 37 | + } | ||
| 38 | + fun deepEquals(a: Any?, b: Any?): Boolean { | ||
| 39 | + if (a is ByteArray && b is ByteArray) { | ||
| 40 | + return a.contentEquals(b) | ||
| 41 | + } | ||
| 42 | + if (a is IntArray && b is IntArray) { | ||
| 43 | + return a.contentEquals(b) | ||
| 44 | + } | ||
| 45 | + if (a is LongArray && b is LongArray) { | ||
| 46 | + return a.contentEquals(b) | ||
| 47 | + } | ||
| 48 | + if (a is DoubleArray && b is DoubleArray) { | ||
| 49 | + return a.contentEquals(b) | ||
| 50 | + } | ||
| 51 | + if (a is Array<*> && b is Array<*>) { | ||
| 52 | + return a.size == b.size && | ||
| 53 | + a.indices.all{ deepEquals(a[it], b[it]) } | ||
| 54 | + } | ||
| 55 | + if (a is List<*> && b is List<*>) { | ||
| 56 | + return a.size == b.size && | ||
| 57 | + a.indices.all{ deepEquals(a[it], b[it]) } | ||
| 58 | + } | ||
| 59 | + if (a is Map<*, *> && b is Map<*, *>) { | ||
| 60 | + return a.size == b.size && a.all { | ||
| 61 | + (b as Map<Any?, Any?>).containsKey(it.key) && | ||
| 62 | + deepEquals(it.value, b[it.key]) | ||
| 63 | + } | ||
| 64 | + } | ||
| 65 | + return a == b | ||
| 66 | + } | ||
| 67 | + | ||
| 68 | +} | ||
| 69 | + | ||
| 70 | +/** | ||
| 71 | + * Error class for passing custom error details to Flutter via a thrown PlatformException. | ||
| 72 | + * @property code The error code. | ||
| 73 | + * @property message The error message. | ||
| 74 | + * @property details The error details. Must be a datatype supported by the api codec. | ||
| 75 | + */ | ||
| 76 | +class FlutterError ( | ||
| 77 | + val code: String, | ||
| 78 | + override val message: String? = null, | ||
| 79 | + val details: Any? = null | ||
| 80 | +) : Throwable() | ||
| 81 | + | ||
| 82 | +/** Generated class from Pigeon that represents data sent in messages. */ | ||
| 83 | +data class WearDeviceInfo ( | ||
| 84 | + val deviceId: String? = null, | ||
| 85 | + val deviceName: String? = null, | ||
| 86 | + val isConnected: Boolean? = null | ||
| 87 | +) | ||
| 88 | + { | ||
| 89 | + companion object { | ||
| 90 | + fun fromList(pigeonVar_list: List<Any?>): WearDeviceInfo { | ||
| 91 | + val deviceId = pigeonVar_list[0] as String? | ||
| 92 | + val deviceName = pigeonVar_list[1] as String? | ||
| 93 | + val isConnected = pigeonVar_list[2] as Boolean? | ||
| 94 | + return WearDeviceInfo(deviceId, deviceName, isConnected) | ||
| 95 | + } | ||
| 96 | + } | ||
| 97 | + fun toList(): List<Any?> { | ||
| 98 | + return listOf( | ||
| 99 | + deviceId, | ||
| 100 | + deviceName, | ||
| 101 | + isConnected, | ||
| 102 | + ) | ||
| 103 | + } | ||
| 104 | + override fun equals(other: Any?): Boolean { | ||
| 105 | + if (other !is WearDeviceInfo) { | ||
| 106 | + return false | ||
| 107 | + } | ||
| 108 | + if (this === other) { | ||
| 109 | + return true | ||
| 110 | + } | ||
| 111 | + return WearEngineApiPigeonUtils.deepEquals(toList(), other.toList()) } | ||
| 112 | + | ||
| 113 | + override fun hashCode(): Int = toList().hashCode() | ||
| 114 | +} | ||
| 115 | +private open class WearEngineApiPigeonCodec : StandardMessageCodec() { | ||
| 116 | + override fun readValueOfType(type: Byte, buffer: ByteBuffer): Any? { | ||
| 117 | + return when (type) { | ||
| 118 | + 129.toByte() -> { | ||
| 119 | + return (readValue(buffer) as? List<Any?>)?.let { | ||
| 120 | + WearDeviceInfo.fromList(it) | ||
| 121 | + } | ||
| 122 | + } | ||
| 123 | + else -> super.readValueOfType(type, buffer) | ||
| 124 | + } | ||
| 125 | + } | ||
| 126 | + override fun writeValue(stream: ByteArrayOutputStream, value: Any?) { | ||
| 127 | + when (value) { | ||
| 128 | + is WearDeviceInfo -> { | ||
| 129 | + stream.write(129) | ||
| 130 | + writeValue(stream, value.toList()) | ||
| 131 | + } | ||
| 132 | + else -> super.writeValue(stream, value) | ||
| 133 | + } | ||
| 134 | + } | ||
| 135 | +} | ||
| 136 | + | ||
| 137 | +/** Generated interface from Pigeon that represents a handler of messages from Flutter. */ | ||
| 138 | +interface WearEngineHostApi { | ||
| 139 | + fun hasAvailableDevices(): Boolean | ||
| 140 | + fun checkConnectedDevice(): WearDeviceInfo? | ||
| 141 | + fun registerMessageReceiver(): Boolean | ||
| 142 | + fun sendTextMessage(message: String): Boolean | ||
| 143 | + fun sendWatchSyncPayload(jsonPayload: String): Boolean | ||
| 144 | + | ||
| 145 | + companion object { | ||
| 146 | + /** The codec used by WearEngineHostApi. */ | ||
| 147 | + val codec: MessageCodec<Any?> by lazy { | ||
| 148 | + WearEngineApiPigeonCodec() | ||
| 149 | + } | ||
| 150 | + /** Sets up an instance of `WearEngineHostApi` to handle messages through the `binaryMessenger`. */ | ||
| 151 | + @JvmOverloads | ||
| 152 | + fun setUp(binaryMessenger: BinaryMessenger, api: WearEngineHostApi?, messageChannelSuffix: String = "") { | ||
| 153 | + val separatedMessageChannelSuffix = if (messageChannelSuffix.isNotEmpty()) ".$messageChannelSuffix" else "" | ||
| 154 | + run { | ||
| 155 | + val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.doublefeel_flutter.WearEngineHostApi.hasAvailableDevices$separatedMessageChannelSuffix", codec) | ||
| 156 | + if (api != null) { | ||
| 157 | + channel.setMessageHandler { _, reply -> | ||
| 158 | + val wrapped: List<Any?> = try { | ||
| 159 | + listOf(api.hasAvailableDevices()) | ||
| 160 | + } catch (exception: Throwable) { | ||
| 161 | + WearEngineApiPigeonUtils.wrapError(exception) | ||
| 162 | + } | ||
| 163 | + reply.reply(wrapped) | ||
| 164 | + } | ||
| 165 | + } else { | ||
| 166 | + channel.setMessageHandler(null) | ||
| 167 | + } | ||
| 168 | + } | ||
| 169 | + run { | ||
| 170 | + val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.doublefeel_flutter.WearEngineHostApi.checkConnectedDevice$separatedMessageChannelSuffix", codec) | ||
| 171 | + if (api != null) { | ||
| 172 | + channel.setMessageHandler { _, reply -> | ||
| 173 | + val wrapped: List<Any?> = try { | ||
| 174 | + listOf(api.checkConnectedDevice()) | ||
| 175 | + } catch (exception: Throwable) { | ||
| 176 | + WearEngineApiPigeonUtils.wrapError(exception) | ||
| 177 | + } | ||
| 178 | + reply.reply(wrapped) | ||
| 179 | + } | ||
| 180 | + } else { | ||
| 181 | + channel.setMessageHandler(null) | ||
| 182 | + } | ||
| 183 | + } | ||
| 184 | + run { | ||
| 185 | + val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.doublefeel_flutter.WearEngineHostApi.registerMessageReceiver$separatedMessageChannelSuffix", codec) | ||
| 186 | + if (api != null) { | ||
| 187 | + channel.setMessageHandler { _, reply -> | ||
| 188 | + val wrapped: List<Any?> = try { | ||
| 189 | + listOf(api.registerMessageReceiver()) | ||
| 190 | + } catch (exception: Throwable) { | ||
| 191 | + WearEngineApiPigeonUtils.wrapError(exception) | ||
| 192 | + } | ||
| 193 | + reply.reply(wrapped) | ||
| 194 | + } | ||
| 195 | + } else { | ||
| 196 | + channel.setMessageHandler(null) | ||
| 197 | + } | ||
| 198 | + } | ||
| 199 | + run { | ||
| 200 | + val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.doublefeel_flutter.WearEngineHostApi.sendTextMessage$separatedMessageChannelSuffix", codec) | ||
| 201 | + if (api != null) { | ||
| 202 | + channel.setMessageHandler { message, reply -> | ||
| 203 | + val args = message as List<Any?> | ||
| 204 | + val messageArg = args[0] as String | ||
| 205 | + val wrapped: List<Any?> = try { | ||
| 206 | + listOf(api.sendTextMessage(messageArg)) | ||
| 207 | + } catch (exception: Throwable) { | ||
| 208 | + WearEngineApiPigeonUtils.wrapError(exception) | ||
| 209 | + } | ||
| 210 | + reply.reply(wrapped) | ||
| 211 | + } | ||
| 212 | + } else { | ||
| 213 | + channel.setMessageHandler(null) | ||
| 214 | + } | ||
| 215 | + } | ||
| 216 | + run { | ||
| 217 | + val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.doublefeel_flutter.WearEngineHostApi.sendWatchSyncPayload$separatedMessageChannelSuffix", codec) | ||
| 218 | + if (api != null) { | ||
| 219 | + channel.setMessageHandler { message, reply -> | ||
| 220 | + val args = message as List<Any?> | ||
| 221 | + val jsonPayloadArg = args[0] as String | ||
| 222 | + val wrapped: List<Any?> = try { | ||
| 223 | + listOf(api.sendWatchSyncPayload(jsonPayloadArg)) | ||
| 224 | + } catch (exception: Throwable) { | ||
| 225 | + WearEngineApiPigeonUtils.wrapError(exception) | ||
| 226 | + } | ||
| 227 | + reply.reply(wrapped) | ||
| 228 | + } | ||
| 229 | + } else { | ||
| 230 | + channel.setMessageHandler(null) | ||
| 231 | + } | ||
| 232 | + } | ||
| 233 | + } | ||
| 234 | + } | ||
| 235 | +} |
| 1 | +<?xml version="1.0" encoding="utf-8"?> | ||
| 2 | +<!-- Modify this file to customize your launch splash screen --> | ||
| 3 | +<layer-list xmlns:android="http://schemas.android.com/apk/res/android"> | ||
| 4 | + <item android:drawable="?android:colorBackground" /> | ||
| 5 | + | ||
| 6 | + <!-- You can insert your own image assets here --> | ||
| 7 | + <!-- <item> | ||
| 8 | + <bitmap | ||
| 9 | + android:gravity="center" | ||
| 10 | + android:src="@mipmap/launch_image" /> | ||
| 11 | + </item> --> | ||
| 12 | +</layer-list> |
| 1 | +<?xml version="1.0" encoding="utf-8"?> | ||
| 2 | +<!-- Modify this file to customize your launch splash screen --> | ||
| 3 | +<layer-list xmlns:android="http://schemas.android.com/apk/res/android"> | ||
| 4 | + <item android:drawable="@android:color/white" /> | ||
| 5 | + | ||
| 6 | + <!-- You can insert your own image assets here --> | ||
| 7 | + <!-- <item> | ||
| 8 | + <bitmap | ||
| 9 | + android:gravity="center" | ||
| 10 | + android:src="@mipmap/launch_image" /> | ||
| 11 | + </item> --> | ||
| 12 | +</layer-list> |
544 Bytes
442 Bytes
721 Bytes
1.01 KB
1.41 KB
| 1 | +<?xml version="1.0" encoding="utf-8"?> | ||
| 2 | +<resources> | ||
| 3 | + <!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is on --> | ||
| 4 | + <style name="LaunchTheme" parent="@android:style/Theme.Black.NoTitleBar"> | ||
| 5 | + <!-- Show a splash screen on the activity. Automatically removed when | ||
| 6 | + the Flutter engine draws its first frame --> | ||
| 7 | + <item name="android:windowBackground">@drawable/launch_background</item> | ||
| 8 | + </style> | ||
| 9 | + <!-- Theme applied to the Android Window as soon as the process has started. | ||
| 10 | + This theme determines the color of the Android Window while your | ||
| 11 | + Flutter UI initializes, as well as behind your Flutter UI while its | ||
| 12 | + running. | ||
| 13 | + | ||
| 14 | + This Theme is only used starting with V2 of Flutter's Android embedding. --> | ||
| 15 | + <style name="NormalTheme" parent="@android:style/Theme.Black.NoTitleBar"> | ||
| 16 | + <item name="android:windowBackground">?android:colorBackground</item> | ||
| 17 | + </style> | ||
| 18 | +</resources> |
android/app/src/main/res/values/styles.xml
0 → 100644
| 1 | +<?xml version="1.0" encoding="utf-8"?> | ||
| 2 | +<resources> | ||
| 3 | + <!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is off --> | ||
| 4 | + <style name="LaunchTheme" parent="@android:style/Theme.Light.NoTitleBar"> | ||
| 5 | + <!-- Show a splash screen on the activity. Automatically removed when | ||
| 6 | + the Flutter engine draws its first frame --> | ||
| 7 | + <item name="android:windowBackground">@drawable/launch_background</item> | ||
| 8 | + </style> | ||
| 9 | + <!-- Theme applied to the Android Window as soon as the process has started. | ||
| 10 | + This theme determines the color of the Android Window while your | ||
| 11 | + Flutter UI initializes, as well as behind your Flutter UI while its | ||
| 12 | + running. | ||
| 13 | + | ||
| 14 | + This Theme is only used starting with V2 of Flutter's Android embedding. --> | ||
| 15 | + <style name="NormalTheme" parent="@android:style/Theme.Light.NoTitleBar"> | ||
| 16 | + <item name="android:windowBackground">?android:colorBackground</item> | ||
| 17 | + </style> | ||
| 18 | +</resources> |
android/build.gradle
0 → 100644
| 1 | +allprojects { | ||
| 2 | + repositories { | ||
| 3 | + google() | ||
| 4 | + mavenCentral() | ||
| 5 | + maven { url "https://developer.huawei.com/repo/" } | ||
| 6 | + maven { url "https://mirrors.huaweicloud.com/repository/maven/" } | ||
| 7 | + maven { url "https://jitpack.io" } | ||
| 8 | + } | ||
| 9 | +} | ||
| 10 | + | ||
| 11 | +rootProject.buildDir = "../build" | ||
| 12 | +subprojects { | ||
| 13 | + project.buildDir = "${rootProject.buildDir}/${project.name}" | ||
| 14 | +} | ||
| 15 | +subprojects { | ||
| 16 | + project.evaluationDependsOn(":app") | ||
| 17 | +} | ||
| 18 | + | ||
| 19 | +tasks.register("clean", Delete) { | ||
| 20 | + delete rootProject.buildDir | ||
| 21 | +} |
android/gradle.properties
0 → 100644
android/settings.gradle
0 → 100644
| 1 | +pluginManagement { | ||
| 2 | + def flutterSdkPath = { | ||
| 3 | + def properties = new Properties() | ||
| 4 | + file("local.properties").withInputStream { properties.load(it) } | ||
| 5 | + def flutterSdkPath = properties.getProperty("flutter.sdk") | ||
| 6 | + assert flutterSdkPath != null, "flutter.sdk not set in local.properties" | ||
| 7 | + return flutterSdkPath | ||
| 8 | + }() | ||
| 9 | + | ||
| 10 | + includeBuild("$flutterSdkPath/packages/flutter_tools/gradle") | ||
| 11 | + | ||
| 12 | + repositories { | ||
| 13 | + google() | ||
| 14 | + mavenCentral() | ||
| 15 | + gradlePluginPortal() | ||
| 16 | + maven { url "https://developer.huawei.com/repo/" } | ||
| 17 | + } | ||
| 18 | +} | ||
| 19 | + | ||
| 20 | +plugins { | ||
| 21 | + id "dev.flutter.flutter-plugin-loader" version "1.0.0" | ||
| 22 | + id "com.android.application" version "8.3.2" apply false | ||
| 23 | + id "org.jetbrains.kotlin.android" version "1.8.22" apply false | ||
| 24 | +} | ||
| 25 | + | ||
| 26 | +include ":app" |
assets/images/common/ic_arrow_green_up.png
0 → 100644
230 Bytes
assets/images/common/ic_arrow_red_down.png
0 → 100644
224 Bytes
assets/images/common/ic_nav_back.webp
0 → 100644
No preview for this file type
assets/images/tabbar/icon_friends.png
0 → 100644
985 Bytes
assets/images/tabbar/icon_my.png
0 → 100644
779 Bytes
assets/images/tabbar/icon_today.png
0 → 100644
842 Bytes
assets/images/tabbar/icon_trend.png
0 → 100644
392 Bytes
assets/images/today/premium_chevron.png
0 → 100644
293 Bytes
| 1 | +<svg preserveAspectRatio="none" width="100%" height="100%" overflow="visible" style="display: block;" viewBox="0 0 76.3555 45.7217" fill="none" xmlns="http://www.w3.org/2000/svg"> | ||
| 2 | +<path id="Subtract" d="M57.6094 0C57.6094 2.52513 59.6565 4.57227 62.1816 4.57227C64.6278 4.57216 66.6256 2.65105 66.748 0.235352L66.7539 0H70.8682C73.8982 0 76.3553 2.45629 76.3555 5.48633V40.2354C76.3553 43.2654 73.8982 45.7217 70.8682 45.7217H66.7539C66.7538 43.1967 64.7066 41.1495 62.1816 41.1494C59.6565 41.1494 57.6094 43.1966 57.6094 45.7217H5.48633C2.45638 45.7215 0.000155327 43.2653 0 40.2354V5.48633C0.000145425 2.45638 2.45638 0.000147154 5.48633 0H57.6094Z" fill="var(--fill-0, #916DF7)"/> | ||
| 3 | +</svg> |
2.98 KB
build.yaml
0 → 100644
ios/.gitignore
0 → 100644
| 1 | +**/dgph | ||
| 2 | +*.mode1v3 | ||
| 3 | +*.mode2v3 | ||
| 4 | +*.moved-aside | ||
| 5 | +*.pbxuser | ||
| 6 | +*.perspectivev3 | ||
| 7 | +**/*sync/ | ||
| 8 | +.sconsign.dblite | ||
| 9 | +.tags* | ||
| 10 | +**/.vagrant/ | ||
| 11 | +**/DerivedData/ | ||
| 12 | +Icon? | ||
| 13 | +**/Pods/ | ||
| 14 | +**/.symlinks/ | ||
| 15 | +profile | ||
| 16 | +xcuserdata | ||
| 17 | +**/.generated/ | ||
| 18 | +Flutter/App.framework | ||
| 19 | +Flutter/Flutter.framework | ||
| 20 | +Flutter/Flutter.podspec | ||
| 21 | +Flutter/Generated.xcconfig | ||
| 22 | +Flutter/ephemeral/ | ||
| 23 | +Flutter/app.flx | ||
| 24 | +Flutter/app.zip | ||
| 25 | +Flutter/flutter_assets/ | ||
| 26 | +Flutter/flutter_export_environment.sh | ||
| 27 | +ServiceDefinitions.json | ||
| 28 | +Runner/GeneratedPluginRegistrant.* | ||
| 29 | + | ||
| 30 | +# Exceptions to above rules. | ||
| 31 | +!default.mode1v3 | ||
| 32 | +!default.mode2v3 | ||
| 33 | +!default.pbxuser | ||
| 34 | +!default.perspectivev3 |
ios/Flutter/AppFrameworkInfo.plist
0 → 100644
| 1 | +<?xml version="1.0" encoding="UTF-8"?> | ||
| 2 | +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> | ||
| 3 | +<plist version="1.0"> | ||
| 4 | +<dict> | ||
| 5 | + <key>CFBundleDevelopmentRegion</key> | ||
| 6 | + <string>en</string> | ||
| 7 | + <key>CFBundleExecutable</key> | ||
| 8 | + <string>App</string> | ||
| 9 | + <key>CFBundleIdentifier</key> | ||
| 10 | + <string>io.flutter.flutter.app</string> | ||
| 11 | + <key>CFBundleInfoDictionaryVersion</key> | ||
| 12 | + <string>6.0</string> | ||
| 13 | + <key>CFBundleName</key> | ||
| 14 | + <string>App</string> | ||
| 15 | + <key>CFBundlePackageType</key> | ||
| 16 | + <string>FMWK</string> | ||
| 17 | + <key>CFBundleShortVersionString</key> | ||
| 18 | + <string>1.0</string> | ||
| 19 | + <key>CFBundleSignature</key> | ||
| 20 | + <string>????</string> | ||
| 21 | + <key>CFBundleVersion</key> | ||
| 22 | + <string>1.0</string> | ||
| 23 | + <key>MinimumOSVersion</key> | ||
| 24 | + <string>13.0</string> | ||
| 25 | +</dict> | ||
| 26 | +</plist> |
ios/Flutter/Debug.xcconfig
0 → 100644
ios/Flutter/Release.xcconfig
0 → 100644
ios/Podfile
0 → 100644
| 1 | +platform :ios, '13.0' | ||
| 2 | + | ||
| 3 | +# CocoaPods analytics sends network stats synchronously affecting flutter build latency. | ||
| 4 | +ENV['COCOAPODS_DISABLE_STATS'] = 'true' | ||
| 5 | + | ||
| 6 | +project 'Runner', { | ||
| 7 | + 'Debug' => :debug, | ||
| 8 | + 'Profile' => :release, | ||
| 9 | + 'Release' => :release, | ||
| 10 | +} | ||
| 11 | + | ||
| 12 | +def flutter_root | ||
| 13 | + generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) | ||
| 14 | + unless File.exist?(generated_xcode_build_settings_path) | ||
| 15 | + raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" | ||
| 16 | + end | ||
| 17 | + | ||
| 18 | + File.foreach(generated_xcode_build_settings_path) do |line| | ||
| 19 | + matches = line.match(/FLUTTER_ROOT\=(.*)/) | ||
| 20 | + return matches[1].strip if matches | ||
| 21 | + end | ||
| 22 | + raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" | ||
| 23 | +end | ||
| 24 | + | ||
| 25 | +require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) | ||
| 26 | + | ||
| 27 | +flutter_ios_podfile_setup | ||
| 28 | + | ||
| 29 | +target 'Runner' do | ||
| 30 | + use_frameworks! | ||
| 31 | + use_modular_headers! | ||
| 32 | + | ||
| 33 | + flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) | ||
| 34 | + target 'RunnerTests' do | ||
| 35 | + inherit! :search_paths | ||
| 36 | + end | ||
| 37 | +end | ||
| 38 | + | ||
| 39 | +post_install do |installer| | ||
| 40 | + installer.pods_project.targets.each do |target| | ||
| 41 | + flutter_additional_ios_build_settings(target) | ||
| 42 | + end | ||
| 43 | +end |
ios/Podfile.lock
0 → 100644
| 1 | +PODS: | ||
| 2 | + - Flutter (1.0.0) | ||
| 3 | + - image_cropper (0.0.4): | ||
| 4 | + - Flutter | ||
| 5 | + - TOCropViewController (~> 2.7.4) | ||
| 6 | + - image_picker_ios (0.0.1): | ||
| 7 | + - Flutter | ||
| 8 | + - path_provider_foundation (0.0.1): | ||
| 9 | + - Flutter | ||
| 10 | + - FlutterMacOS | ||
| 11 | + - permission_handler_apple (9.3.0): | ||
| 12 | + - Flutter | ||
| 13 | + - shared_preferences_foundation (0.0.1): | ||
| 14 | + - Flutter | ||
| 15 | + - FlutterMacOS | ||
| 16 | + - sqflite_darwin (0.0.4): | ||
| 17 | + - Flutter | ||
| 18 | + - FlutterMacOS | ||
| 19 | + - TOCropViewController (2.7.4) | ||
| 20 | + - webview_flutter_wkwebview (0.0.1): | ||
| 21 | + - Flutter | ||
| 22 | + - FlutterMacOS | ||
| 23 | + | ||
| 24 | +DEPENDENCIES: | ||
| 25 | + - Flutter (from `Flutter`) | ||
| 26 | + - image_cropper (from `.symlinks/plugins/image_cropper/ios`) | ||
| 27 | + - image_picker_ios (from `.symlinks/plugins/image_picker_ios/ios`) | ||
| 28 | + - path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`) | ||
| 29 | + - permission_handler_apple (from `.symlinks/plugins/permission_handler_apple/ios`) | ||
| 30 | + - shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`) | ||
| 31 | + - sqflite_darwin (from `.symlinks/plugins/sqflite_darwin/darwin`) | ||
| 32 | + - webview_flutter_wkwebview (from `.symlinks/plugins/webview_flutter_wkwebview/darwin`) | ||
| 33 | + | ||
| 34 | +SPEC REPOS: | ||
| 35 | + trunk: | ||
| 36 | + - TOCropViewController | ||
| 37 | + | ||
| 38 | +EXTERNAL SOURCES: | ||
| 39 | + Flutter: | ||
| 40 | + :path: Flutter | ||
| 41 | + image_cropper: | ||
| 42 | + :path: ".symlinks/plugins/image_cropper/ios" | ||
| 43 | + image_picker_ios: | ||
| 44 | + :path: ".symlinks/plugins/image_picker_ios/ios" | ||
| 45 | + path_provider_foundation: | ||
| 46 | + :path: ".symlinks/plugins/path_provider_foundation/darwin" | ||
| 47 | + permission_handler_apple: | ||
| 48 | + :path: ".symlinks/plugins/permission_handler_apple/ios" | ||
| 49 | + shared_preferences_foundation: | ||
| 50 | + :path: ".symlinks/plugins/shared_preferences_foundation/darwin" | ||
| 51 | + sqflite_darwin: | ||
| 52 | + :path: ".symlinks/plugins/sqflite_darwin/darwin" | ||
| 53 | + webview_flutter_wkwebview: | ||
| 54 | + :path: ".symlinks/plugins/webview_flutter_wkwebview/darwin" | ||
| 55 | + | ||
| 56 | +SPEC CHECKSUMS: | ||
| 57 | + Flutter: cabc95a1d2626b1b06e7179b784ebcf0c0cde467 | ||
| 58 | + image_cropper: c4326ea50132b1e1564499e5d32a84f01fb03537 | ||
| 59 | + image_picker_ios: 7fe1ff8e34c1790d6fff70a32484959f563a928a | ||
| 60 | + path_provider_foundation: 080d55be775b7414fd5a5ef3ac137b97b097e564 | ||
| 61 | + permission_handler_apple: 4ed2196e43d0651e8ff7ca3483a069d469701f2d | ||
| 62 | + shared_preferences_foundation: 9e1978ff2562383bd5676f64ec4e9aa8fa06a6f7 | ||
| 63 | + sqflite_darwin: 20b2a3a3b70e43edae938624ce550a3cbf66a3d0 | ||
| 64 | + TOCropViewController: 80b8985ad794298fb69d3341de183f33d1853654 | ||
| 65 | + webview_flutter_wkwebview: 1821ceac936eba6f7984d89a9f3bcb4dea99ebb2 | ||
| 66 | + | ||
| 67 | +PODFILE CHECKSUM: ade96bceabe3919b69c16573938e4268fe3a6c9d | ||
| 68 | + | ||
| 69 | +COCOAPODS: 1.16.2 |
ios/Runner.xcodeproj/project.pbxproj
0 → 100644
| 1 | +// !$*UTF8*$! | ||
| 2 | +{ | ||
| 3 | + archiveVersion = 1; | ||
| 4 | + classes = { | ||
| 5 | + }; | ||
| 6 | + objectVersion = 54; | ||
| 7 | + objects = { | ||
| 8 | + | ||
| 9 | +/* Begin PBXBuildFile section */ | ||
| 10 | + 0D37801EADFB01D2BF214330 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D813EFE9B8AFD28D707C26F9 /* Pods_Runner.framework */; }; | ||
| 11 | + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; | ||
| 12 | + 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; }; | ||
| 13 | + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; | ||
| 14 | + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; | ||
| 15 | + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; | ||
| 16 | + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; | ||
| 17 | + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; | ||
| 18 | + DF01A2B41CF9000F007C001 /* HealthKitApi.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF01A2B31CF9000F007C001 /* HealthKitApi.swift */; }; | ||
| 19 | + DF01A2B41CF9000F007C002 /* WearEngineApi.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF01A2B31CF9000F007C002 /* WearEngineApi.swift */; }; | ||
| 20 | + DF01A2B41CF9000F007C003 /* AlipayApi.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF01A2B31CF9000F007C003 /* AlipayApi.swift */; }; | ||
| 21 | + DF01A2B41CF9000F007C004 /* NativeHostApiStubs.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF01A2B31CF9000F007C004 /* NativeHostApiStubs.swift */; }; | ||
| 22 | + DF01A2B41CF9000F007C005 /* PigeonShared.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF01A2B31CF9000F007C005 /* PigeonShared.swift */; }; | ||
| 23 | + EA47CAD80DF77F162CC86851 /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FD2FC62391A106A0C6E9CF39 /* Pods_RunnerTests.framework */; }; | ||
| 24 | +/* End PBXBuildFile section */ | ||
| 25 | + | ||
| 26 | +/* Begin PBXContainerItemProxy section */ | ||
| 27 | + 331C8085294A63A400263BE5 /* PBXContainerItemProxy */ = { | ||
| 28 | + isa = PBXContainerItemProxy; | ||
| 29 | + containerPortal = 97C146E61CF9000F007C117D /* Project object */; | ||
| 30 | + proxyType = 1; | ||
| 31 | + remoteGlobalIDString = 97C146ED1CF9000F007C117D; | ||
| 32 | + remoteInfo = Runner; | ||
| 33 | + }; | ||
| 34 | +/* End PBXContainerItemProxy section */ | ||
| 35 | + | ||
| 36 | +/* Begin PBXCopyFilesBuildPhase section */ | ||
| 37 | + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { | ||
| 38 | + isa = PBXCopyFilesBuildPhase; | ||
| 39 | + buildActionMask = 2147483647; | ||
| 40 | + dstPath = ""; | ||
| 41 | + dstSubfolderSpec = 10; | ||
| 42 | + files = ( | ||
| 43 | + ); | ||
| 44 | + name = "Embed Frameworks"; | ||
| 45 | + runOnlyForDeploymentPostprocessing = 0; | ||
| 46 | + }; | ||
| 47 | +/* End PBXCopyFilesBuildPhase section */ | ||
| 48 | + | ||
| 49 | +/* Begin PBXFileReference section */ | ||
| 50 | + 0D1CEDE9C3295903C8FCF702 /* 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 = "<group>"; }; | ||
| 51 | + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; }; | ||
| 52 | + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; }; | ||
| 53 | + 2ECF3C9772810B1582D524F4 /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = "<group>"; }; | ||
| 54 | + 331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = "<group>"; }; | ||
| 55 | + 331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; | ||
| 56 | + 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; }; | ||
| 57 | + 5620C49637B3BA24A7B2A069 /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = "<group>"; }; | ||
| 58 | + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = "<group>"; }; | ||
| 59 | + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; }; | ||
| 60 | + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; }; | ||
| 61 | + 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = "<group>"; }; | ||
| 62 | + 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = "<group>"; }; | ||
| 63 | + 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; | ||
| 64 | + 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; }; | ||
| 65 | + 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; }; | ||
| 66 | + 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; }; | ||
| 67 | + 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; }; | ||
| 68 | + 98740F53C55D411DD8809A3F /* 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 = "<group>"; }; | ||
| 69 | + 9D26AF01D43E742248474B60 /* 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 = "<group>"; }; | ||
| 70 | + D0BB543595814545A916196E /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = "<group>"; }; | ||
| 71 | + D813EFE9B8AFD28D707C26F9 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; | ||
| 72 | + DF01A2B31CF9000F007C001 /* HealthKitApi.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HealthKitApi.swift; sourceTree = "<group>"; }; | ||
| 73 | + DF01A2B31CF9000F007C002 /* WearEngineApi.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WearEngineApi.swift; sourceTree = "<group>"; }; | ||
| 74 | + DF01A2B31CF9000F007C003 /* AlipayApi.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlipayApi.swift; sourceTree = "<group>"; }; | ||
| 75 | + DF01A2B31CF9000F007C004 /* NativeHostApiStubs.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NativeHostApiStubs.swift; sourceTree = "<group>"; }; | ||
| 76 | + DF01A2B31CF9000F007C005 /* PigeonShared.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PigeonShared.swift; sourceTree = "<group>"; }; | ||
| 77 | + FD2FC62391A106A0C6E9CF39 /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; | ||
| 78 | +/* End PBXFileReference section */ | ||
| 79 | + | ||
| 80 | +/* Begin PBXFrameworksBuildPhase section */ | ||
| 81 | + 71910C375FB994D0ECBC6E88 /* Frameworks */ = { | ||
| 82 | + isa = PBXFrameworksBuildPhase; | ||
| 83 | + buildActionMask = 2147483647; | ||
| 84 | + files = ( | ||
| 85 | + EA47CAD80DF77F162CC86851 /* Pods_RunnerTests.framework in Frameworks */, | ||
| 86 | + ); | ||
| 87 | + runOnlyForDeploymentPostprocessing = 0; | ||
| 88 | + }; | ||
| 89 | + 97C146EB1CF9000F007C117D /* Frameworks */ = { | ||
| 90 | + isa = PBXFrameworksBuildPhase; | ||
| 91 | + buildActionMask = 2147483647; | ||
| 92 | + files = ( | ||
| 93 | + 0D37801EADFB01D2BF214330 /* Pods_Runner.framework in Frameworks */, | ||
| 94 | + ); | ||
| 95 | + runOnlyForDeploymentPostprocessing = 0; | ||
| 96 | + }; | ||
| 97 | +/* End PBXFrameworksBuildPhase section */ | ||
| 98 | + | ||
| 99 | +/* Begin PBXGroup section */ | ||
| 100 | + 331C8082294A63A400263BE5 /* RunnerTests */ = { | ||
| 101 | + isa = PBXGroup; | ||
| 102 | + children = ( | ||
| 103 | + 331C807B294A618700263BE5 /* RunnerTests.swift */, | ||
| 104 | + ); | ||
| 105 | + path = RunnerTests; | ||
| 106 | + sourceTree = "<group>"; | ||
| 107 | + }; | ||
| 108 | + 9740EEB11CF90186004384FC /* Flutter */ = { | ||
| 109 | + isa = PBXGroup; | ||
| 110 | + children = ( | ||
| 111 | + 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, | ||
| 112 | + 9740EEB21CF90195004384FC /* Debug.xcconfig */, | ||
| 113 | + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, | ||
| 114 | + 9740EEB31CF90195004384FC /* Generated.xcconfig */, | ||
| 115 | + ); | ||
| 116 | + name = Flutter; | ||
| 117 | + sourceTree = "<group>"; | ||
| 118 | + }; | ||
| 119 | + 97C146E51CF9000F007C117D = { | ||
| 120 | + isa = PBXGroup; | ||
| 121 | + children = ( | ||
| 122 | + 9740EEB11CF90186004384FC /* Flutter */, | ||
| 123 | + 97C146F01CF9000F007C117D /* Runner */, | ||
| 124 | + 97C146EF1CF9000F007C117D /* Products */, | ||
| 125 | + 331C8082294A63A400263BE5 /* RunnerTests */, | ||
| 126 | + A46DE786AD5506CE018A4A59 /* Pods */, | ||
| 127 | + 97D312C4F82913758AF2C32D /* Frameworks */, | ||
| 128 | + ); | ||
| 129 | + sourceTree = "<group>"; | ||
| 130 | + }; | ||
| 131 | + 97C146EF1CF9000F007C117D /* Products */ = { | ||
| 132 | + isa = PBXGroup; | ||
| 133 | + children = ( | ||
| 134 | + 97C146EE1CF9000F007C117D /* Runner.app */, | ||
| 135 | + 331C8081294A63A400263BE5 /* RunnerTests.xctest */, | ||
| 136 | + ); | ||
| 137 | + name = Products; | ||
| 138 | + sourceTree = "<group>"; | ||
| 139 | + }; | ||
| 140 | + 97C146F01CF9000F007C117D /* Runner */ = { | ||
| 141 | + isa = PBXGroup; | ||
| 142 | + children = ( | ||
| 143 | + 97C146FA1CF9000F007C117D /* Main.storyboard */, | ||
| 144 | + 97C146FD1CF9000F007C117D /* Assets.xcassets */, | ||
| 145 | + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, | ||
| 146 | + 97C147021CF9000F007C117D /* Info.plist */, | ||
| 147 | + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, | ||
| 148 | + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, | ||
| 149 | + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, | ||
| 150 | + DF01A2B51CF9000F007C001 /* Pigeon */, | ||
| 151 | + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, | ||
| 152 | + ); | ||
| 153 | + path = Runner; | ||
| 154 | + sourceTree = "<group>"; | ||
| 155 | + }; | ||
| 156 | + 97D312C4F82913758AF2C32D /* Frameworks */ = { | ||
| 157 | + isa = PBXGroup; | ||
| 158 | + children = ( | ||
| 159 | + D813EFE9B8AFD28D707C26F9 /* Pods_Runner.framework */, | ||
| 160 | + FD2FC62391A106A0C6E9CF39 /* Pods_RunnerTests.framework */, | ||
| 161 | + ); | ||
| 162 | + name = Frameworks; | ||
| 163 | + sourceTree = "<group>"; | ||
| 164 | + }; | ||
| 165 | + A46DE786AD5506CE018A4A59 /* Pods */ = { | ||
| 166 | + isa = PBXGroup; | ||
| 167 | + children = ( | ||
| 168 | + 0D1CEDE9C3295903C8FCF702 /* Pods-Runner.debug.xcconfig */, | ||
| 169 | + 9D26AF01D43E742248474B60 /* Pods-Runner.release.xcconfig */, | ||
| 170 | + 98740F53C55D411DD8809A3F /* Pods-Runner.profile.xcconfig */, | ||
| 171 | + D0BB543595814545A916196E /* Pods-RunnerTests.debug.xcconfig */, | ||
| 172 | + 2ECF3C9772810B1582D524F4 /* Pods-RunnerTests.release.xcconfig */, | ||
| 173 | + 5620C49637B3BA24A7B2A069 /* Pods-RunnerTests.profile.xcconfig */, | ||
| 174 | + ); | ||
| 175 | + name = Pods; | ||
| 176 | + path = Pods; | ||
| 177 | + sourceTree = "<group>"; | ||
| 178 | + }; | ||
| 179 | + DF01A2B51CF9000F007C001 /* Pigeon */ = { | ||
| 180 | + isa = PBXGroup; | ||
| 181 | + children = ( | ||
| 182 | + DF01A2B31CF9000F007C005 /* PigeonShared.swift */, | ||
| 183 | + DF01A2B31CF9000F007C001 /* HealthKitApi.swift */, | ||
| 184 | + DF01A2B31CF9000F007C002 /* WearEngineApi.swift */, | ||
| 185 | + DF01A2B31CF9000F007C003 /* AlipayApi.swift */, | ||
| 186 | + DF01A2B31CF9000F007C004 /* NativeHostApiStubs.swift */, | ||
| 187 | + ); | ||
| 188 | + path = Pigeon; | ||
| 189 | + sourceTree = "<group>"; | ||
| 190 | + }; | ||
| 191 | +/* End PBXGroup section */ | ||
| 192 | + | ||
| 193 | +/* Begin PBXNativeTarget section */ | ||
| 194 | + 331C8080294A63A400263BE5 /* RunnerTests */ = { | ||
| 195 | + isa = PBXNativeTarget; | ||
| 196 | + buildConfigurationList = 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; | ||
| 197 | + buildPhases = ( | ||
| 198 | + FA6A63AA7E44E76FF1168BF2 /* [CP] Check Pods Manifest.lock */, | ||
| 199 | + 331C807D294A63A400263BE5 /* Sources */, | ||
| 200 | + 331C807F294A63A400263BE5 /* Resources */, | ||
| 201 | + 71910C375FB994D0ECBC6E88 /* Frameworks */, | ||
| 202 | + ); | ||
| 203 | + buildRules = ( | ||
| 204 | + ); | ||
| 205 | + dependencies = ( | ||
| 206 | + 331C8086294A63A400263BE5 /* PBXTargetDependency */, | ||
| 207 | + ); | ||
| 208 | + name = RunnerTests; | ||
| 209 | + productName = RunnerTests; | ||
| 210 | + productReference = 331C8081294A63A400263BE5 /* RunnerTests.xctest */; | ||
| 211 | + productType = "com.apple.product-type.bundle.unit-test"; | ||
| 212 | + }; | ||
| 213 | + 97C146ED1CF9000F007C117D /* Runner */ = { | ||
| 214 | + isa = PBXNativeTarget; | ||
| 215 | + buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; | ||
| 216 | + buildPhases = ( | ||
| 217 | + 30EE1EAEF04FCF17330C508E /* [CP] Check Pods Manifest.lock */, | ||
| 218 | + 9740EEB61CF901F6004384FC /* Run Script */, | ||
| 219 | + 97C146EA1CF9000F007C117D /* Sources */, | ||
| 220 | + 97C146EB1CF9000F007C117D /* Frameworks */, | ||
| 221 | + 97C146EC1CF9000F007C117D /* Resources */, | ||
| 222 | + 9705A1C41CF9048500538489 /* Embed Frameworks */, | ||
| 223 | + 3B06AD1E1E4923F5004D2608 /* Thin Binary */, | ||
| 224 | + 2CBFB5724AAC059A33245577 /* [CP] Embed Pods Frameworks */, | ||
| 225 | + 91949B6425377114094461C0 /* [CP] Copy Pods Resources */, | ||
| 226 | + ); | ||
| 227 | + buildRules = ( | ||
| 228 | + ); | ||
| 229 | + dependencies = ( | ||
| 230 | + ); | ||
| 231 | + name = Runner; | ||
| 232 | + productName = Runner; | ||
| 233 | + productReference = 97C146EE1CF9000F007C117D /* Runner.app */; | ||
| 234 | + productType = "com.apple.product-type.application"; | ||
| 235 | + }; | ||
| 236 | +/* End PBXNativeTarget section */ | ||
| 237 | + | ||
| 238 | +/* Begin PBXProject section */ | ||
| 239 | + 97C146E61CF9000F007C117D /* Project object */ = { | ||
| 240 | + isa = PBXProject; | ||
| 241 | + attributes = { | ||
| 242 | + BuildIndependentTargetsInParallel = YES; | ||
| 243 | + LastUpgradeCheck = 1510; | ||
| 244 | + ORGANIZATIONNAME = ""; | ||
| 245 | + TargetAttributes = { | ||
| 246 | + 331C8080294A63A400263BE5 = { | ||
| 247 | + CreatedOnToolsVersion = 14.0; | ||
| 248 | + TestTargetID = 97C146ED1CF9000F007C117D; | ||
| 249 | + }; | ||
| 250 | + 97C146ED1CF9000F007C117D = { | ||
| 251 | + CreatedOnToolsVersion = 7.3.1; | ||
| 252 | + LastSwiftMigration = 1100; | ||
| 253 | + }; | ||
| 254 | + }; | ||
| 255 | + }; | ||
| 256 | + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; | ||
| 257 | + compatibilityVersion = "Xcode 9.3"; | ||
| 258 | + developmentRegion = en; | ||
| 259 | + hasScannedForEncodings = 0; | ||
| 260 | + knownRegions = ( | ||
| 261 | + en, | ||
| 262 | + Base, | ||
| 263 | + ); | ||
| 264 | + mainGroup = 97C146E51CF9000F007C117D; | ||
| 265 | + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; | ||
| 266 | + projectDirPath = ""; | ||
| 267 | + projectRoot = ""; | ||
| 268 | + targets = ( | ||
| 269 | + 97C146ED1CF9000F007C117D /* Runner */, | ||
| 270 | + 331C8080294A63A400263BE5 /* RunnerTests */, | ||
| 271 | + ); | ||
| 272 | + }; | ||
| 273 | +/* End PBXProject section */ | ||
| 274 | + | ||
| 275 | +/* Begin PBXResourcesBuildPhase section */ | ||
| 276 | + 331C807F294A63A400263BE5 /* Resources */ = { | ||
| 277 | + isa = PBXResourcesBuildPhase; | ||
| 278 | + buildActionMask = 2147483647; | ||
| 279 | + files = ( | ||
| 280 | + ); | ||
| 281 | + runOnlyForDeploymentPostprocessing = 0; | ||
| 282 | + }; | ||
| 283 | + 97C146EC1CF9000F007C117D /* Resources */ = { | ||
| 284 | + isa = PBXResourcesBuildPhase; | ||
| 285 | + buildActionMask = 2147483647; | ||
| 286 | + files = ( | ||
| 287 | + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, | ||
| 288 | + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, | ||
| 289 | + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, | ||
| 290 | + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, | ||
| 291 | + ); | ||
| 292 | + runOnlyForDeploymentPostprocessing = 0; | ||
| 293 | + }; | ||
| 294 | +/* End PBXResourcesBuildPhase section */ | ||
| 295 | + | ||
| 296 | +/* Begin PBXShellScriptBuildPhase section */ | ||
| 297 | + 2CBFB5724AAC059A33245577 /* [CP] Embed Pods Frameworks */ = { | ||
| 298 | + isa = PBXShellScriptBuildPhase; | ||
| 299 | + buildActionMask = 2147483647; | ||
| 300 | + files = ( | ||
| 301 | + ); | ||
| 302 | + inputFileListPaths = ( | ||
| 303 | + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", | ||
| 304 | + ); | ||
| 305 | + name = "[CP] Embed Pods Frameworks"; | ||
| 306 | + outputFileListPaths = ( | ||
| 307 | + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", | ||
| 308 | + ); | ||
| 309 | + runOnlyForDeploymentPostprocessing = 0; | ||
| 310 | + shellPath = /bin/sh; | ||
| 311 | + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; | ||
| 312 | + showEnvVarsInLog = 0; | ||
| 313 | + }; | ||
| 314 | + 30EE1EAEF04FCF17330C508E /* [CP] Check Pods Manifest.lock */ = { | ||
| 315 | + isa = PBXShellScriptBuildPhase; | ||
| 316 | + buildActionMask = 2147483647; | ||
| 317 | + files = ( | ||
| 318 | + ); | ||
| 319 | + inputFileListPaths = ( | ||
| 320 | + ); | ||
| 321 | + inputPaths = ( | ||
| 322 | + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", | ||
| 323 | + "${PODS_ROOT}/Manifest.lock", | ||
| 324 | + ); | ||
| 325 | + name = "[CP] Check Pods Manifest.lock"; | ||
| 326 | + outputFileListPaths = ( | ||
| 327 | + ); | ||
| 328 | + outputPaths = ( | ||
| 329 | + "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", | ||
| 330 | + ); | ||
| 331 | + runOnlyForDeploymentPostprocessing = 0; | ||
| 332 | + shellPath = /bin/sh; | ||
| 333 | + 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"; | ||
| 334 | + showEnvVarsInLog = 0; | ||
| 335 | + }; | ||
| 336 | + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { | ||
| 337 | + isa = PBXShellScriptBuildPhase; | ||
| 338 | + alwaysOutOfDate = 1; | ||
| 339 | + buildActionMask = 2147483647; | ||
| 340 | + files = ( | ||
| 341 | + ); | ||
| 342 | + inputPaths = ( | ||
| 343 | + "${TARGET_BUILD_DIR}/${INFOPLIST_PATH}", | ||
| 344 | + ); | ||
| 345 | + name = "Thin Binary"; | ||
| 346 | + outputPaths = ( | ||
| 347 | + ); | ||
| 348 | + runOnlyForDeploymentPostprocessing = 0; | ||
| 349 | + shellPath = /bin/sh; | ||
| 350 | + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; | ||
| 351 | + }; | ||
| 352 | + 91949B6425377114094461C0 /* [CP] Copy Pods Resources */ = { | ||
| 353 | + isa = PBXShellScriptBuildPhase; | ||
| 354 | + buildActionMask = 2147483647; | ||
| 355 | + files = ( | ||
| 356 | + ); | ||
| 357 | + inputFileListPaths = ( | ||
| 358 | + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-input-files.xcfilelist", | ||
| 359 | + ); | ||
| 360 | + name = "[CP] Copy Pods Resources"; | ||
| 361 | + outputFileListPaths = ( | ||
| 362 | + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-output-files.xcfilelist", | ||
| 363 | + ); | ||
| 364 | + runOnlyForDeploymentPostprocessing = 0; | ||
| 365 | + shellPath = /bin/sh; | ||
| 366 | + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n"; | ||
| 367 | + showEnvVarsInLog = 0; | ||
| 368 | + }; | ||
| 369 | + 9740EEB61CF901F6004384FC /* Run Script */ = { | ||
| 370 | + isa = PBXShellScriptBuildPhase; | ||
| 371 | + alwaysOutOfDate = 1; | ||
| 372 | + buildActionMask = 2147483647; | ||
| 373 | + files = ( | ||
| 374 | + ); | ||
| 375 | + inputPaths = ( | ||
| 376 | + ); | ||
| 377 | + name = "Run Script"; | ||
| 378 | + outputPaths = ( | ||
| 379 | + ); | ||
| 380 | + runOnlyForDeploymentPostprocessing = 0; | ||
| 381 | + shellPath = /bin/sh; | ||
| 382 | + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; | ||
| 383 | + }; | ||
| 384 | + FA6A63AA7E44E76FF1168BF2 /* [CP] Check Pods Manifest.lock */ = { | ||
| 385 | + isa = PBXShellScriptBuildPhase; | ||
| 386 | + buildActionMask = 2147483647; | ||
| 387 | + files = ( | ||
| 388 | + ); | ||
| 389 | + inputFileListPaths = ( | ||
| 390 | + ); | ||
| 391 | + inputPaths = ( | ||
| 392 | + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", | ||
| 393 | + "${PODS_ROOT}/Manifest.lock", | ||
| 394 | + ); | ||
| 395 | + name = "[CP] Check Pods Manifest.lock"; | ||
| 396 | + outputFileListPaths = ( | ||
| 397 | + ); | ||
| 398 | + outputPaths = ( | ||
| 399 | + "$(DERIVED_FILE_DIR)/Pods-RunnerTests-checkManifestLockResult.txt", | ||
| 400 | + ); | ||
| 401 | + runOnlyForDeploymentPostprocessing = 0; | ||
| 402 | + shellPath = /bin/sh; | ||
| 403 | + 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"; | ||
| 404 | + showEnvVarsInLog = 0; | ||
| 405 | + }; | ||
| 406 | +/* End PBXShellScriptBuildPhase section */ | ||
| 407 | + | ||
| 408 | +/* Begin PBXSourcesBuildPhase section */ | ||
| 409 | + 331C807D294A63A400263BE5 /* Sources */ = { | ||
| 410 | + isa = PBXSourcesBuildPhase; | ||
| 411 | + buildActionMask = 2147483647; | ||
| 412 | + files = ( | ||
| 413 | + 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */, | ||
| 414 | + ); | ||
| 415 | + runOnlyForDeploymentPostprocessing = 0; | ||
| 416 | + }; | ||
| 417 | + 97C146EA1CF9000F007C117D /* Sources */ = { | ||
| 418 | + isa = PBXSourcesBuildPhase; | ||
| 419 | + buildActionMask = 2147483647; | ||
| 420 | + files = ( | ||
| 421 | + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, | ||
| 422 | + DF01A2B41CF9000F007C005 /* PigeonShared.swift in Sources */, | ||
| 423 | + DF01A2B41CF9000F007C001 /* HealthKitApi.swift in Sources */, | ||
| 424 | + DF01A2B41CF9000F007C002 /* WearEngineApi.swift in Sources */, | ||
| 425 | + DF01A2B41CF9000F007C003 /* AlipayApi.swift in Sources */, | ||
| 426 | + DF01A2B41CF9000F007C004 /* NativeHostApiStubs.swift in Sources */, | ||
| 427 | + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, | ||
| 428 | + ); | ||
| 429 | + runOnlyForDeploymentPostprocessing = 0; | ||
| 430 | + }; | ||
| 431 | +/* End PBXSourcesBuildPhase section */ | ||
| 432 | + | ||
| 433 | +/* Begin PBXTargetDependency section */ | ||
| 434 | + 331C8086294A63A400263BE5 /* PBXTargetDependency */ = { | ||
| 435 | + isa = PBXTargetDependency; | ||
| 436 | + target = 97C146ED1CF9000F007C117D /* Runner */; | ||
| 437 | + targetProxy = 331C8085294A63A400263BE5 /* PBXContainerItemProxy */; | ||
| 438 | + }; | ||
| 439 | +/* End PBXTargetDependency section */ | ||
| 440 | + | ||
| 441 | +/* Begin PBXVariantGroup section */ | ||
| 442 | + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { | ||
| 443 | + isa = PBXVariantGroup; | ||
| 444 | + children = ( | ||
| 445 | + 97C146FB1CF9000F007C117D /* Base */, | ||
| 446 | + ); | ||
| 447 | + name = Main.storyboard; | ||
| 448 | + sourceTree = "<group>"; | ||
| 449 | + }; | ||
| 450 | + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { | ||
| 451 | + isa = PBXVariantGroup; | ||
| 452 | + children = ( | ||
| 453 | + 97C147001CF9000F007C117D /* Base */, | ||
| 454 | + ); | ||
| 455 | + name = LaunchScreen.storyboard; | ||
| 456 | + sourceTree = "<group>"; | ||
| 457 | + }; | ||
| 458 | +/* End PBXVariantGroup section */ | ||
| 459 | + | ||
| 460 | +/* Begin XCBuildConfiguration section */ | ||
| 461 | + 249021D3217E4FDB00AE95B9 /* Profile */ = { | ||
| 462 | + isa = XCBuildConfiguration; | ||
| 463 | + buildSettings = { | ||
| 464 | + ALWAYS_SEARCH_USER_PATHS = NO; | ||
| 465 | + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; | ||
| 466 | + CLANG_ANALYZER_NONNULL = YES; | ||
| 467 | + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; | ||
| 468 | + CLANG_CXX_LIBRARY = "libc++"; | ||
| 469 | + CLANG_ENABLE_MODULES = YES; | ||
| 470 | + CLANG_ENABLE_OBJC_ARC = YES; | ||
| 471 | + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; | ||
| 472 | + CLANG_WARN_BOOL_CONVERSION = YES; | ||
| 473 | + CLANG_WARN_COMMA = YES; | ||
| 474 | + CLANG_WARN_CONSTANT_CONVERSION = YES; | ||
| 475 | + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; | ||
| 476 | + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; | ||
| 477 | + CLANG_WARN_EMPTY_BODY = YES; | ||
| 478 | + CLANG_WARN_ENUM_CONVERSION = YES; | ||
| 479 | + CLANG_WARN_INFINITE_RECURSION = YES; | ||
| 480 | + CLANG_WARN_INT_CONVERSION = YES; | ||
| 481 | + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; | ||
| 482 | + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; | ||
| 483 | + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; | ||
| 484 | + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; | ||
| 485 | + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; | ||
| 486 | + CLANG_WARN_STRICT_PROTOTYPES = YES; | ||
| 487 | + CLANG_WARN_SUSPICIOUS_MOVE = YES; | ||
| 488 | + CLANG_WARN_UNREACHABLE_CODE = YES; | ||
| 489 | + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; | ||
| 490 | + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; | ||
| 491 | + COPY_PHASE_STRIP = NO; | ||
| 492 | + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; | ||
| 493 | + ENABLE_NS_ASSERTIONS = NO; | ||
| 494 | + ENABLE_STRICT_OBJC_MSGSEND = YES; | ||
| 495 | + ENABLE_USER_SCRIPT_SANDBOXING = NO; | ||
| 496 | + GCC_C_LANGUAGE_STANDARD = gnu99; | ||
| 497 | + GCC_NO_COMMON_BLOCKS = YES; | ||
| 498 | + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; | ||
| 499 | + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; | ||
| 500 | + GCC_WARN_UNDECLARED_SELECTOR = YES; | ||
| 501 | + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; | ||
| 502 | + GCC_WARN_UNUSED_FUNCTION = YES; | ||
| 503 | + GCC_WARN_UNUSED_VARIABLE = YES; | ||
| 504 | + IPHONEOS_DEPLOYMENT_TARGET = 13.0; | ||
| 505 | + MTL_ENABLE_DEBUG_INFO = NO; | ||
| 506 | + SDKROOT = iphoneos; | ||
| 507 | + SUPPORTED_PLATFORMS = iphoneos; | ||
| 508 | + TARGETED_DEVICE_FAMILY = "1,2"; | ||
| 509 | + VALIDATE_PRODUCT = YES; | ||
| 510 | + }; | ||
| 511 | + name = Profile; | ||
| 512 | + }; | ||
| 513 | + 249021D4217E4FDB00AE95B9 /* Profile */ = { | ||
| 514 | + isa = XCBuildConfiguration; | ||
| 515 | + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; | ||
| 516 | + buildSettings = { | ||
| 517 | + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; | ||
| 518 | + CLANG_ENABLE_MODULES = YES; | ||
| 519 | + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; | ||
| 520 | + DEVELOPMENT_TEAM = ZRPLMC329K; | ||
| 521 | + ENABLE_BITCODE = NO; | ||
| 522 | + INFOPLIST_FILE = Runner/Info.plist; | ||
| 523 | + LD_RUNPATH_SEARCH_PATHS = ( | ||
| 524 | + "$(inherited)", | ||
| 525 | + "@executable_path/Frameworks", | ||
| 526 | + ); | ||
| 527 | + PRODUCT_BUNDLE_IDENTIFIER = com.luiz.doublefeel; | ||
| 528 | + PRODUCT_NAME = "$(TARGET_NAME)"; | ||
| 529 | + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; | ||
| 530 | + SWIFT_VERSION = 5.0; | ||
| 531 | + VERSIONING_SYSTEM = "apple-generic"; | ||
| 532 | + }; | ||
| 533 | + name = Profile; | ||
| 534 | + }; | ||
| 535 | + 331C8088294A63A400263BE5 /* Debug */ = { | ||
| 536 | + isa = XCBuildConfiguration; | ||
| 537 | + baseConfigurationReference = D0BB543595814545A916196E /* Pods-RunnerTests.debug.xcconfig */; | ||
| 538 | + buildSettings = { | ||
| 539 | + BUNDLE_LOADER = "$(TEST_HOST)"; | ||
| 540 | + CODE_SIGN_STYLE = Automatic; | ||
| 541 | + CURRENT_PROJECT_VERSION = 1; | ||
| 542 | + GENERATE_INFOPLIST_FILE = YES; | ||
| 543 | + MARKETING_VERSION = 1.0; | ||
| 544 | + PRODUCT_BUNDLE_IDENTIFIER = com.luiz.doublefeel.RunnerTests; | ||
| 545 | + PRODUCT_NAME = "$(TARGET_NAME)"; | ||
| 546 | + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; | ||
| 547 | + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; | ||
| 548 | + SWIFT_VERSION = 5.0; | ||
| 549 | + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; | ||
| 550 | + }; | ||
| 551 | + name = Debug; | ||
| 552 | + }; | ||
| 553 | + 331C8089294A63A400263BE5 /* Release */ = { | ||
| 554 | + isa = XCBuildConfiguration; | ||
| 555 | + baseConfigurationReference = 2ECF3C9772810B1582D524F4 /* Pods-RunnerTests.release.xcconfig */; | ||
| 556 | + buildSettings = { | ||
| 557 | + BUNDLE_LOADER = "$(TEST_HOST)"; | ||
| 558 | + CODE_SIGN_STYLE = Automatic; | ||
| 559 | + CURRENT_PROJECT_VERSION = 1; | ||
| 560 | + GENERATE_INFOPLIST_FILE = YES; | ||
| 561 | + MARKETING_VERSION = 1.0; | ||
| 562 | + PRODUCT_BUNDLE_IDENTIFIER = com.luiz.doublefeel.RunnerTests; | ||
| 563 | + PRODUCT_NAME = "$(TARGET_NAME)"; | ||
| 564 | + SWIFT_VERSION = 5.0; | ||
| 565 | + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; | ||
| 566 | + }; | ||
| 567 | + name = Release; | ||
| 568 | + }; | ||
| 569 | + 331C808A294A63A400263BE5 /* Profile */ = { | ||
| 570 | + isa = XCBuildConfiguration; | ||
| 571 | + baseConfigurationReference = 5620C49637B3BA24A7B2A069 /* Pods-RunnerTests.profile.xcconfig */; | ||
| 572 | + buildSettings = { | ||
| 573 | + BUNDLE_LOADER = "$(TEST_HOST)"; | ||
| 574 | + CODE_SIGN_STYLE = Automatic; | ||
| 575 | + CURRENT_PROJECT_VERSION = 1; | ||
| 576 | + GENERATE_INFOPLIST_FILE = YES; | ||
| 577 | + MARKETING_VERSION = 1.0; | ||
| 578 | + PRODUCT_BUNDLE_IDENTIFIER = com.luiz.doublefeel.RunnerTests; | ||
| 579 | + PRODUCT_NAME = "$(TARGET_NAME)"; | ||
| 580 | + SWIFT_VERSION = 5.0; | ||
| 581 | + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; | ||
| 582 | + }; | ||
| 583 | + name = Profile; | ||
| 584 | + }; | ||
| 585 | + 97C147031CF9000F007C117D /* Debug */ = { | ||
| 586 | + isa = XCBuildConfiguration; | ||
| 587 | + buildSettings = { | ||
| 588 | + ALWAYS_SEARCH_USER_PATHS = NO; | ||
| 589 | + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; | ||
| 590 | + CLANG_ANALYZER_NONNULL = YES; | ||
| 591 | + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; | ||
| 592 | + CLANG_CXX_LIBRARY = "libc++"; | ||
| 593 | + CLANG_ENABLE_MODULES = YES; | ||
| 594 | + CLANG_ENABLE_OBJC_ARC = YES; | ||
| 595 | + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; | ||
| 596 | + CLANG_WARN_BOOL_CONVERSION = YES; | ||
| 597 | + CLANG_WARN_COMMA = YES; | ||
| 598 | + CLANG_WARN_CONSTANT_CONVERSION = YES; | ||
| 599 | + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; | ||
| 600 | + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; | ||
| 601 | + CLANG_WARN_EMPTY_BODY = YES; | ||
| 602 | + CLANG_WARN_ENUM_CONVERSION = YES; | ||
| 603 | + CLANG_WARN_INFINITE_RECURSION = YES; | ||
| 604 | + CLANG_WARN_INT_CONVERSION = YES; | ||
| 605 | + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; | ||
| 606 | + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; | ||
| 607 | + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; | ||
| 608 | + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; | ||
| 609 | + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; | ||
| 610 | + CLANG_WARN_STRICT_PROTOTYPES = YES; | ||
| 611 | + CLANG_WARN_SUSPICIOUS_MOVE = YES; | ||
| 612 | + CLANG_WARN_UNREACHABLE_CODE = YES; | ||
| 613 | + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; | ||
| 614 | + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; | ||
| 615 | + COPY_PHASE_STRIP = NO; | ||
| 616 | + DEBUG_INFORMATION_FORMAT = dwarf; | ||
| 617 | + ENABLE_STRICT_OBJC_MSGSEND = YES; | ||
| 618 | + ENABLE_TESTABILITY = YES; | ||
| 619 | + ENABLE_USER_SCRIPT_SANDBOXING = NO; | ||
| 620 | + GCC_C_LANGUAGE_STANDARD = gnu99; | ||
| 621 | + GCC_DYNAMIC_NO_PIC = NO; | ||
| 622 | + GCC_NO_COMMON_BLOCKS = YES; | ||
| 623 | + GCC_OPTIMIZATION_LEVEL = 0; | ||
| 624 | + GCC_PREPROCESSOR_DEFINITIONS = ( | ||
| 625 | + "DEBUG=1", | ||
| 626 | + "$(inherited)", | ||
| 627 | + ); | ||
| 628 | + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; | ||
| 629 | + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; | ||
| 630 | + GCC_WARN_UNDECLARED_SELECTOR = YES; | ||
| 631 | + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; | ||
| 632 | + GCC_WARN_UNUSED_FUNCTION = YES; | ||
| 633 | + GCC_WARN_UNUSED_VARIABLE = YES; | ||
| 634 | + IPHONEOS_DEPLOYMENT_TARGET = 13.0; | ||
| 635 | + MTL_ENABLE_DEBUG_INFO = YES; | ||
| 636 | + ONLY_ACTIVE_ARCH = YES; | ||
| 637 | + SDKROOT = iphoneos; | ||
| 638 | + TARGETED_DEVICE_FAMILY = "1,2"; | ||
| 639 | + }; | ||
| 640 | + name = Debug; | ||
| 641 | + }; | ||
| 642 | + 97C147041CF9000F007C117D /* Release */ = { | ||
| 643 | + isa = XCBuildConfiguration; | ||
| 644 | + buildSettings = { | ||
| 645 | + ALWAYS_SEARCH_USER_PATHS = NO; | ||
| 646 | + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; | ||
| 647 | + CLANG_ANALYZER_NONNULL = YES; | ||
| 648 | + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; | ||
| 649 | + CLANG_CXX_LIBRARY = "libc++"; | ||
| 650 | + CLANG_ENABLE_MODULES = YES; | ||
| 651 | + CLANG_ENABLE_OBJC_ARC = YES; | ||
| 652 | + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; | ||
| 653 | + CLANG_WARN_BOOL_CONVERSION = YES; | ||
| 654 | + CLANG_WARN_COMMA = YES; | ||
| 655 | + CLANG_WARN_CONSTANT_CONVERSION = YES; | ||
| 656 | + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; | ||
| 657 | + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; | ||
| 658 | + CLANG_WARN_EMPTY_BODY = YES; | ||
| 659 | + CLANG_WARN_ENUM_CONVERSION = YES; | ||
| 660 | + CLANG_WARN_INFINITE_RECURSION = YES; | ||
| 661 | + CLANG_WARN_INT_CONVERSION = YES; | ||
| 662 | + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; | ||
| 663 | + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; | ||
| 664 | + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; | ||
| 665 | + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; | ||
| 666 | + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; | ||
| 667 | + CLANG_WARN_STRICT_PROTOTYPES = YES; | ||
| 668 | + CLANG_WARN_SUSPICIOUS_MOVE = YES; | ||
| 669 | + CLANG_WARN_UNREACHABLE_CODE = YES; | ||
| 670 | + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; | ||
| 671 | + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; | ||
| 672 | + COPY_PHASE_STRIP = NO; | ||
| 673 | + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; | ||
| 674 | + ENABLE_NS_ASSERTIONS = NO; | ||
| 675 | + ENABLE_STRICT_OBJC_MSGSEND = YES; | ||
| 676 | + ENABLE_USER_SCRIPT_SANDBOXING = NO; | ||
| 677 | + GCC_C_LANGUAGE_STANDARD = gnu99; | ||
| 678 | + GCC_NO_COMMON_BLOCKS = YES; | ||
| 679 | + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; | ||
| 680 | + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; | ||
| 681 | + GCC_WARN_UNDECLARED_SELECTOR = YES; | ||
| 682 | + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; | ||
| 683 | + GCC_WARN_UNUSED_FUNCTION = YES; | ||
| 684 | + GCC_WARN_UNUSED_VARIABLE = YES; | ||
| 685 | + IPHONEOS_DEPLOYMENT_TARGET = 13.0; | ||
| 686 | + MTL_ENABLE_DEBUG_INFO = NO; | ||
| 687 | + SDKROOT = iphoneos; | ||
| 688 | + SUPPORTED_PLATFORMS = iphoneos; | ||
| 689 | + SWIFT_COMPILATION_MODE = wholemodule; | ||
| 690 | + SWIFT_OPTIMIZATION_LEVEL = "-O"; | ||
| 691 | + TARGETED_DEVICE_FAMILY = "1,2"; | ||
| 692 | + VALIDATE_PRODUCT = YES; | ||
| 693 | + }; | ||
| 694 | + name = Release; | ||
| 695 | + }; | ||
| 696 | + 97C147061CF9000F007C117D /* Debug */ = { | ||
| 697 | + isa = XCBuildConfiguration; | ||
| 698 | + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; | ||
| 699 | + buildSettings = { | ||
| 700 | + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; | ||
| 701 | + CLANG_ENABLE_MODULES = YES; | ||
| 702 | + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; | ||
| 703 | + DEVELOPMENT_TEAM = ZRPLMC329K; | ||
| 704 | + ENABLE_BITCODE = NO; | ||
| 705 | + INFOPLIST_FILE = Runner/Info.plist; | ||
| 706 | + LD_RUNPATH_SEARCH_PATHS = ( | ||
| 707 | + "$(inherited)", | ||
| 708 | + "@executable_path/Frameworks", | ||
| 709 | + ); | ||
| 710 | + PRODUCT_BUNDLE_IDENTIFIER = com.luiz.doublefeel; | ||
| 711 | + PRODUCT_NAME = "$(TARGET_NAME)"; | ||
| 712 | + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; | ||
| 713 | + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; | ||
| 714 | + SWIFT_VERSION = 5.0; | ||
| 715 | + VERSIONING_SYSTEM = "apple-generic"; | ||
| 716 | + }; | ||
| 717 | + name = Debug; | ||
| 718 | + }; | ||
| 719 | + 97C147071CF9000F007C117D /* Release */ = { | ||
| 720 | + isa = XCBuildConfiguration; | ||
| 721 | + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; | ||
| 722 | + buildSettings = { | ||
| 723 | + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; | ||
| 724 | + CLANG_ENABLE_MODULES = YES; | ||
| 725 | + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; | ||
| 726 | + DEVELOPMENT_TEAM = ZRPLMC329K; | ||
| 727 | + ENABLE_BITCODE = NO; | ||
| 728 | + INFOPLIST_FILE = Runner/Info.plist; | ||
| 729 | + LD_RUNPATH_SEARCH_PATHS = ( | ||
| 730 | + "$(inherited)", | ||
| 731 | + "@executable_path/Frameworks", | ||
| 732 | + ); | ||
| 733 | + PRODUCT_BUNDLE_IDENTIFIER = com.luiz.doublefeel; | ||
| 734 | + PRODUCT_NAME = "$(TARGET_NAME)"; | ||
| 735 | + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; | ||
| 736 | + SWIFT_VERSION = 5.0; | ||
| 737 | + VERSIONING_SYSTEM = "apple-generic"; | ||
| 738 | + }; | ||
| 739 | + name = Release; | ||
| 740 | + }; | ||
| 741 | +/* End XCBuildConfiguration section */ | ||
| 742 | + | ||
| 743 | +/* Begin XCConfigurationList section */ | ||
| 744 | + 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = { | ||
| 745 | + isa = XCConfigurationList; | ||
| 746 | + buildConfigurations = ( | ||
| 747 | + 331C8088294A63A400263BE5 /* Debug */, | ||
| 748 | + 331C8089294A63A400263BE5 /* Release */, | ||
| 749 | + 331C808A294A63A400263BE5 /* Profile */, | ||
| 750 | + ); | ||
| 751 | + defaultConfigurationIsVisible = 0; | ||
| 752 | + defaultConfigurationName = Release; | ||
| 753 | + }; | ||
| 754 | + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { | ||
| 755 | + isa = XCConfigurationList; | ||
| 756 | + buildConfigurations = ( | ||
| 757 | + 97C147031CF9000F007C117D /* Debug */, | ||
| 758 | + 97C147041CF9000F007C117D /* Release */, | ||
| 759 | + 249021D3217E4FDB00AE95B9 /* Profile */, | ||
| 760 | + ); | ||
| 761 | + defaultConfigurationIsVisible = 0; | ||
| 762 | + defaultConfigurationName = Release; | ||
| 763 | + }; | ||
| 764 | + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { | ||
| 765 | + isa = XCConfigurationList; | ||
| 766 | + buildConfigurations = ( | ||
| 767 | + 97C147061CF9000F007C117D /* Debug */, | ||
| 768 | + 97C147071CF9000F007C117D /* Release */, | ||
| 769 | + 249021D4217E4FDB00AE95B9 /* Profile */, | ||
| 770 | + ); | ||
| 771 | + defaultConfigurationIsVisible = 0; | ||
| 772 | + defaultConfigurationName = Release; | ||
| 773 | + }; | ||
| 774 | +/* End XCConfigurationList section */ | ||
| 775 | + }; | ||
| 776 | + rootObject = 97C146E61CF9000F007C117D /* Project object */; | ||
| 777 | +} |
| 1 | +<?xml version="1.0" encoding="UTF-8"?> | ||
| 2 | +<Scheme | ||
| 3 | + LastUpgradeVersion = "1510" | ||
| 4 | + version = "1.3"> | ||
| 5 | + <BuildAction | ||
| 6 | + parallelizeBuildables = "YES" | ||
| 7 | + buildImplicitDependencies = "YES"> | ||
| 8 | + <BuildActionEntries> | ||
| 9 | + <BuildActionEntry | ||
| 10 | + buildForTesting = "YES" | ||
| 11 | + buildForRunning = "YES" | ||
| 12 | + buildForProfiling = "YES" | ||
| 13 | + buildForArchiving = "YES" | ||
| 14 | + buildForAnalyzing = "YES"> | ||
| 15 | + <BuildableReference | ||
| 16 | + BuildableIdentifier = "primary" | ||
| 17 | + BlueprintIdentifier = "97C146ED1CF9000F007C117D" | ||
| 18 | + BuildableName = "Runner.app" | ||
| 19 | + BlueprintName = "Runner" | ||
| 20 | + ReferencedContainer = "container:Runner.xcodeproj"> | ||
| 21 | + </BuildableReference> | ||
| 22 | + </BuildActionEntry> | ||
| 23 | + </BuildActionEntries> | ||
| 24 | + </BuildAction> | ||
| 25 | + <TestAction | ||
| 26 | + buildConfiguration = "Debug" | ||
| 27 | + selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" | ||
| 28 | + selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" | ||
| 29 | + customLLDBInitFile = "$(SRCROOT)/Flutter/ephemeral/flutter_lldbinit" | ||
| 30 | + shouldUseLaunchSchemeArgsEnv = "YES"> | ||
| 31 | + <MacroExpansion> | ||
| 32 | + <BuildableReference | ||
| 33 | + BuildableIdentifier = "primary" | ||
| 34 | + BlueprintIdentifier = "97C146ED1CF9000F007C117D" | ||
| 35 | + BuildableName = "Runner.app" | ||
| 36 | + BlueprintName = "Runner" | ||
| 37 | + ReferencedContainer = "container:Runner.xcodeproj"> | ||
| 38 | + </BuildableReference> | ||
| 39 | + </MacroExpansion> | ||
| 40 | + <Testables> | ||
| 41 | + <TestableReference | ||
| 42 | + skipped = "NO" | ||
| 43 | + parallelizable = "YES"> | ||
| 44 | + <BuildableReference | ||
| 45 | + BuildableIdentifier = "primary" | ||
| 46 | + BlueprintIdentifier = "331C8080294A63A400263BE5" | ||
| 47 | + BuildableName = "RunnerTests.xctest" | ||
| 48 | + BlueprintName = "RunnerTests" | ||
| 49 | + ReferencedContainer = "container:Runner.xcodeproj"> | ||
| 50 | + </BuildableReference> | ||
| 51 | + </TestableReference> | ||
| 52 | + </Testables> | ||
| 53 | + </TestAction> | ||
| 54 | + <LaunchAction | ||
| 55 | + buildConfiguration = "Debug" | ||
| 56 | + selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" | ||
| 57 | + selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" | ||
| 58 | + customLLDBInitFile = "$(SRCROOT)/Flutter/ephemeral/flutter_lldbinit" | ||
| 59 | + launchStyle = "0" | ||
| 60 | + useCustomWorkingDirectory = "NO" | ||
| 61 | + ignoresPersistentStateOnLaunch = "NO" | ||
| 62 | + debugDocumentVersioning = "YES" | ||
| 63 | + debugServiceExtension = "internal" | ||
| 64 | + enableGPUValidationMode = "1" | ||
| 65 | + allowLocationSimulation = "YES"> | ||
| 66 | + <BuildableProductRunnable | ||
| 67 | + runnableDebuggingMode = "0"> | ||
| 68 | + <BuildableReference | ||
| 69 | + BuildableIdentifier = "primary" | ||
| 70 | + BlueprintIdentifier = "97C146ED1CF9000F007C117D" | ||
| 71 | + BuildableName = "Runner.app" | ||
| 72 | + BlueprintName = "Runner" | ||
| 73 | + ReferencedContainer = "container:Runner.xcodeproj"> | ||
| 74 | + </BuildableReference> | ||
| 75 | + </BuildableProductRunnable> | ||
| 76 | + </LaunchAction> | ||
| 77 | + <ProfileAction | ||
| 78 | + buildConfiguration = "Profile" | ||
| 79 | + shouldUseLaunchSchemeArgsEnv = "YES" | ||
| 80 | + savedToolIdentifier = "" | ||
| 81 | + useCustomWorkingDirectory = "NO" | ||
| 82 | + debugDocumentVersioning = "YES"> | ||
| 83 | + <BuildableProductRunnable | ||
| 84 | + runnableDebuggingMode = "0"> | ||
| 85 | + <BuildableReference | ||
| 86 | + BuildableIdentifier = "primary" | ||
| 87 | + BlueprintIdentifier = "97C146ED1CF9000F007C117D" | ||
| 88 | + BuildableName = "Runner.app" | ||
| 89 | + BlueprintName = "Runner" | ||
| 90 | + ReferencedContainer = "container:Runner.xcodeproj"> | ||
| 91 | + </BuildableReference> | ||
| 92 | + </BuildableProductRunnable> | ||
| 93 | + </ProfileAction> | ||
| 94 | + <AnalyzeAction | ||
| 95 | + buildConfiguration = "Debug"> | ||
| 96 | + </AnalyzeAction> | ||
| 97 | + <ArchiveAction | ||
| 98 | + buildConfiguration = "Release" | ||
| 99 | + revealArchiveInOrganizer = "YES"> | ||
| 100 | + </ArchiveAction> | ||
| 101 | +</Scheme> |
ios/Runner/AppDelegate.swift
0 → 100644
| 1 | +import Flutter | ||
| 2 | +import UIKit | ||
| 3 | + | ||
| 4 | +@main | ||
| 5 | +@objc class AppDelegate: FlutterAppDelegate { | ||
| 6 | + override func application( | ||
| 7 | + _ application: UIApplication, | ||
| 8 | + didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? | ||
| 9 | + ) -> Bool { | ||
| 10 | + GeneratedPluginRegistrant.register(with: self) | ||
| 11 | + if let controller = window?.rootViewController as? FlutterViewController { | ||
| 12 | + NativePigeonRegistrar.register(binaryMessenger: controller.binaryMessenger) | ||
| 13 | + } | ||
| 14 | + return super.application(application, didFinishLaunchingWithOptions: launchOptions) | ||
| 15 | + } | ||
| 16 | +} |
| 1 | +{ | ||
| 2 | + "images" : [ | ||
| 3 | + { | ||
| 4 | + "size" : "20x20", | ||
| 5 | + "idiom" : "iphone", | ||
| 6 | + "filename" : "Icon-App-20x20@2x.png", | ||
| 7 | + "scale" : "2x" | ||
| 8 | + }, | ||
| 9 | + { | ||
| 10 | + "size" : "20x20", | ||
| 11 | + "idiom" : "iphone", | ||
| 12 | + "filename" : "Icon-App-20x20@3x.png", | ||
| 13 | + "scale" : "3x" | ||
| 14 | + }, | ||
| 15 | + { | ||
| 16 | + "size" : "29x29", | ||
| 17 | + "idiom" : "iphone", | ||
| 18 | + "filename" : "Icon-App-29x29@1x.png", | ||
| 19 | + "scale" : "1x" | ||
| 20 | + }, | ||
| 21 | + { | ||
| 22 | + "size" : "29x29", | ||
| 23 | + "idiom" : "iphone", | ||
| 24 | + "filename" : "Icon-App-29x29@2x.png", | ||
| 25 | + "scale" : "2x" | ||
| 26 | + }, | ||
| 27 | + { | ||
| 28 | + "size" : "29x29", | ||
| 29 | + "idiom" : "iphone", | ||
| 30 | + "filename" : "Icon-App-29x29@3x.png", | ||
| 31 | + "scale" : "3x" | ||
| 32 | + }, | ||
| 33 | + { | ||
| 34 | + "size" : "40x40", | ||
| 35 | + "idiom" : "iphone", | ||
| 36 | + "filename" : "Icon-App-40x40@2x.png", | ||
| 37 | + "scale" : "2x" | ||
| 38 | + }, | ||
| 39 | + { | ||
| 40 | + "size" : "40x40", | ||
| 41 | + "idiom" : "iphone", | ||
| 42 | + "filename" : "Icon-App-40x40@3x.png", | ||
| 43 | + "scale" : "3x" | ||
| 44 | + }, | ||
| 45 | + { | ||
| 46 | + "size" : "60x60", | ||
| 47 | + "idiom" : "iphone", | ||
| 48 | + "filename" : "Icon-App-60x60@2x.png", | ||
| 49 | + "scale" : "2x" | ||
| 50 | + }, | ||
| 51 | + { | ||
| 52 | + "size" : "60x60", | ||
| 53 | + "idiom" : "iphone", | ||
| 54 | + "filename" : "Icon-App-60x60@3x.png", | ||
| 55 | + "scale" : "3x" | ||
| 56 | + }, | ||
| 57 | + { | ||
| 58 | + "size" : "20x20", | ||
| 59 | + "idiom" : "ipad", | ||
| 60 | + "filename" : "Icon-App-20x20@1x.png", | ||
| 61 | + "scale" : "1x" | ||
| 62 | + }, | ||
| 63 | + { | ||
| 64 | + "size" : "20x20", | ||
| 65 | + "idiom" : "ipad", | ||
| 66 | + "filename" : "Icon-App-20x20@2x.png", | ||
| 67 | + "scale" : "2x" | ||
| 68 | + }, | ||
| 69 | + { | ||
| 70 | + "size" : "29x29", | ||
| 71 | + "idiom" : "ipad", | ||
| 72 | + "filename" : "Icon-App-29x29@1x.png", | ||
| 73 | + "scale" : "1x" | ||
| 74 | + }, | ||
| 75 | + { | ||
| 76 | + "size" : "29x29", | ||
| 77 | + "idiom" : "ipad", | ||
| 78 | + "filename" : "Icon-App-29x29@2x.png", | ||
| 79 | + "scale" : "2x" | ||
| 80 | + }, | ||
| 81 | + { | ||
| 82 | + "size" : "40x40", | ||
| 83 | + "idiom" : "ipad", | ||
| 84 | + "filename" : "Icon-App-40x40@1x.png", | ||
| 85 | + "scale" : "1x" | ||
| 86 | + }, | ||
| 87 | + { | ||
| 88 | + "size" : "40x40", | ||
| 89 | + "idiom" : "ipad", | ||
| 90 | + "filename" : "Icon-App-40x40@2x.png", | ||
| 91 | + "scale" : "2x" | ||
| 92 | + }, | ||
| 93 | + { | ||
| 94 | + "size" : "76x76", | ||
| 95 | + "idiom" : "ipad", | ||
| 96 | + "filename" : "Icon-App-76x76@1x.png", | ||
| 97 | + "scale" : "1x" | ||
| 98 | + }, | ||
| 99 | + { | ||
| 100 | + "size" : "76x76", | ||
| 101 | + "idiom" : "ipad", | ||
| 102 | + "filename" : "Icon-App-76x76@2x.png", | ||
| 103 | + "scale" : "2x" | ||
| 104 | + }, | ||
| 105 | + { | ||
| 106 | + "size" : "83.5x83.5", | ||
| 107 | + "idiom" : "ipad", | ||
| 108 | + "filename" : "Icon-App-83.5x83.5@2x.png", | ||
| 109 | + "scale" : "2x" | ||
| 110 | + }, | ||
| 111 | + { | ||
| 112 | + "size" : "1024x1024", | ||
| 113 | + "idiom" : "ios-marketing", | ||
| 114 | + "filename" : "Icon-App-1024x1024@1x.png", | ||
| 115 | + "scale" : "1x" | ||
| 116 | + } | ||
| 117 | + ], | ||
| 118 | + "info" : { | ||
| 119 | + "version" : 1, | ||
| 120 | + "author" : "xcode" | ||
| 121 | + } | ||
| 122 | +} |
10.7 KB
295 Bytes
406 Bytes
450 Bytes
282 Bytes
462 Bytes
704 Bytes
406 Bytes
586 Bytes
862 Bytes
862 Bytes
1.63 KB
762 Bytes
1.2 KB
1.38 KB
| 1 | +{ | ||
| 2 | + "images" : [ | ||
| 3 | + { | ||
| 4 | + "idiom" : "universal", | ||
| 5 | + "filename" : "LaunchImage.png", | ||
| 6 | + "scale" : "1x" | ||
| 7 | + }, | ||
| 8 | + { | ||
| 9 | + "idiom" : "universal", | ||
| 10 | + "filename" : "LaunchImage@2x.png", | ||
| 11 | + "scale" : "2x" | ||
| 12 | + }, | ||
| 13 | + { | ||
| 14 | + "idiom" : "universal", | ||
| 15 | + "filename" : "LaunchImage@3x.png", | ||
| 16 | + "scale" : "3x" | ||
| 17 | + } | ||
| 18 | + ], | ||
| 19 | + "info" : { | ||
| 20 | + "version" : 1, | ||
| 21 | + "author" : "xcode" | ||
| 22 | + } | ||
| 23 | +} |
68 Bytes
68 Bytes
68 Bytes
| 1 | +# Launch Screen Assets | ||
| 2 | + | ||
| 3 | +You can customize the launch screen with your own desired assets by replacing the image files in this directory. | ||
| 4 | + | ||
| 5 | +You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. |
| 1 | +<?xml version="1.0" encoding="UTF-8" standalone="no"?> | ||
| 2 | +<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="12121" systemVersion="16G29" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" colorMatched="YES" initialViewController="01J-lp-oVM"> | ||
| 3 | + <dependencies> | ||
| 4 | + <deployment identifier="iOS"/> | ||
| 5 | + <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="12089"/> | ||
| 6 | + </dependencies> | ||
| 7 | + <scenes> | ||
| 8 | + <!--View Controller--> | ||
| 9 | + <scene sceneID="EHf-IW-A2E"> | ||
| 10 | + <objects> | ||
| 11 | + <viewController id="01J-lp-oVM" sceneMemberID="viewController"> | ||
| 12 | + <layoutGuides> | ||
| 13 | + <viewControllerLayoutGuide type="top" id="Ydg-fD-yQy"/> | ||
| 14 | + <viewControllerLayoutGuide type="bottom" id="xbc-2k-c8Z"/> | ||
| 15 | + </layoutGuides> | ||
| 16 | + <view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3"> | ||
| 17 | + <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> | ||
| 18 | + <subviews> | ||
| 19 | + <imageView opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" image="LaunchImage" translatesAutoresizingMaskIntoConstraints="NO" id="YRO-k0-Ey4"> | ||
| 20 | + </imageView> | ||
| 21 | + </subviews> | ||
| 22 | + <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> | ||
| 23 | + <constraints> | ||
| 24 | + <constraint firstItem="YRO-k0-Ey4" firstAttribute="centerX" secondItem="Ze5-6b-2t3" secondAttribute="centerX" id="1a2-6s-vTC"/> | ||
| 25 | + <constraint firstItem="YRO-k0-Ey4" firstAttribute="centerY" secondItem="Ze5-6b-2t3" secondAttribute="centerY" id="4X2-HB-R7a"/> | ||
| 26 | + </constraints> | ||
| 27 | + </view> | ||
| 28 | + </viewController> | ||
| 29 | + <placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/> | ||
| 30 | + </objects> | ||
| 31 | + <point key="canvasLocation" x="53" y="375"/> | ||
| 32 | + </scene> | ||
| 33 | + </scenes> | ||
| 34 | + <resources> | ||
| 35 | + <image name="LaunchImage" width="168" height="185"/> | ||
| 36 | + </resources> | ||
| 37 | +</document> |
ios/Runner/Base.lproj/Main.storyboard
0 → 100644
| 1 | +<?xml version="1.0" encoding="UTF-8" standalone="no"?> | ||
| 2 | +<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="10117" systemVersion="15F34" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="BYZ-38-t0r"> | ||
| 3 | + <dependencies> | ||
| 4 | + <deployment identifier="iOS"/> | ||
| 5 | + <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="10085"/> | ||
| 6 | + </dependencies> | ||
| 7 | + <scenes> | ||
| 8 | + <!--Flutter View Controller--> | ||
| 9 | + <scene sceneID="tne-QT-ifu"> | ||
| 10 | + <objects> | ||
| 11 | + <viewController id="BYZ-38-t0r" customClass="FlutterViewController" sceneMemberID="viewController"> | ||
| 12 | + <layoutGuides> | ||
| 13 | + <viewControllerLayoutGuide type="top" id="y3c-jy-aDJ"/> | ||
| 14 | + <viewControllerLayoutGuide type="bottom" id="wfy-db-euE"/> | ||
| 15 | + </layoutGuides> | ||
| 16 | + <view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC"> | ||
| 17 | + <rect key="frame" x="0.0" y="0.0" width="600" height="600"/> | ||
| 18 | + <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> | ||
| 19 | + <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/> | ||
| 20 | + </view> | ||
| 21 | + </viewController> | ||
| 22 | + <placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/> | ||
| 23 | + </objects> | ||
| 24 | + </scene> | ||
| 25 | + </scenes> | ||
| 26 | +</document> |
ios/Runner/Info.plist
0 → 100644
| 1 | +<?xml version="1.0" encoding="UTF-8"?> | ||
| 2 | +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> | ||
| 3 | +<plist version="1.0"> | ||
| 4 | +<dict> | ||
| 5 | + <key>CFBundleDevelopmentRegion</key> | ||
| 6 | + <string>$(DEVELOPMENT_LANGUAGE)</string> | ||
| 7 | + <key>CFBundleDisplayName</key> | ||
| 8 | + <string>Doublefeel Flutter</string> | ||
| 9 | + <key>CFBundleExecutable</key> | ||
| 10 | + <string>$(EXECUTABLE_NAME)</string> | ||
| 11 | + <key>CFBundleIdentifier</key> | ||
| 12 | + <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string> | ||
| 13 | + <key>CFBundleInfoDictionaryVersion</key> | ||
| 14 | + <string>6.0</string> | ||
| 15 | + <key>CFBundleName</key> | ||
| 16 | + <string>doublefeel_flutter</string> | ||
| 17 | + <key>CFBundlePackageType</key> | ||
| 18 | + <string>APPL</string> | ||
| 19 | + <key>CFBundleShortVersionString</key> | ||
| 20 | + <string>$(FLUTTER_BUILD_NAME)</string> | ||
| 21 | + <key>CFBundleSignature</key> | ||
| 22 | + <string>????</string> | ||
| 23 | + <key>CFBundleVersion</key> | ||
| 24 | + <string>$(FLUTTER_BUILD_NUMBER)</string> | ||
| 25 | + <key>LSRequiresIPhoneOS</key> | ||
| 26 | + <true/> | ||
| 27 | + <key>UILaunchStoryboardName</key> | ||
| 28 | + <string>LaunchScreen</string> | ||
| 29 | + <key>UIMainStoryboardFile</key> | ||
| 30 | + <string>Main</string> | ||
| 31 | + <key>UISupportedInterfaceOrientations</key> | ||
| 32 | + <array> | ||
| 33 | + <string>UIInterfaceOrientationPortrait</string> | ||
| 34 | + <string>UIInterfaceOrientationLandscapeLeft</string> | ||
| 35 | + <string>UIInterfaceOrientationLandscapeRight</string> | ||
| 36 | + </array> | ||
| 37 | + <key>UISupportedInterfaceOrientations~ipad</key> | ||
| 38 | + <array> | ||
| 39 | + <string>UIInterfaceOrientationPortrait</string> | ||
| 40 | + <string>UIInterfaceOrientationPortraitUpsideDown</string> | ||
| 41 | + <string>UIInterfaceOrientationLandscapeLeft</string> | ||
| 42 | + <string>UIInterfaceOrientationLandscapeRight</string> | ||
| 43 | + </array> | ||
| 44 | + <key>CADisableMinimumFrameDurationOnPhone</key> | ||
| 45 | + <true/> | ||
| 46 | + <key>UIApplicationSupportsIndirectInputEvents</key> | ||
| 47 | + <true/> | ||
| 48 | +</dict> | ||
| 49 | +</plist> |
ios/Runner/Pigeon/AlipayApi.swift
0 → 100644
| 1 | +// // Copyright 2013 The Flutter Authors. All rights reserved. | ||
| 2 | +// Autogenerated from Pigeon (v25.5.0), do not edit directly. | ||
| 3 | +// See also: https://pub.dev/packages/pigeon | ||
| 4 | + | ||
| 5 | +import Foundation | ||
| 6 | + | ||
| 7 | +#if os(iOS) | ||
| 8 | + import Flutter | ||
| 9 | +#elseif os(macOS) | ||
| 10 | + import FlutterMacOS | ||
| 11 | +#else | ||
| 12 | + #error("Unsupported platform.") | ||
| 13 | +#endif | ||
| 14 | + | ||
| 15 | + | ||
| 16 | +private func wrapResult(_ result: Any?) -> [Any?] { | ||
| 17 | + return [result] | ||
| 18 | + | ||
| 19 | +} | ||
| 20 | + | ||
| 21 | +private func wrapError(_ error: Any) -> [Any?] { | ||
| 22 | + if let pigeonError = error as? PigeonError { | ||
| 23 | + return [ | ||
| 24 | + pigeonError.code, | ||
| 25 | + pigeonError.message, | ||
| 26 | + pigeonError.details, | ||
| 27 | + ] | ||
| 28 | + } | ||
| 29 | + if let flutterError = error as? FlutterError { | ||
| 30 | + return [ | ||
| 31 | + flutterError.code, | ||
| 32 | + flutterError.message, | ||
| 33 | + flutterError.details, | ||
| 34 | + ] | ||
| 35 | + } | ||
| 36 | + return [ | ||
| 37 | + "\(error)", | ||
| 38 | + "\(type(of: error))", | ||
| 39 | + "Stacktrace: \(Thread.callStackSymbols)", | ||
| 40 | + ] | ||
| 41 | +} | ||
| 42 | + | ||
| 43 | +private func isNullish(_ value: Any?) -> Bool { | ||
| 44 | + return value is NSNull || value == nil | ||
| 45 | +} | ||
| 46 | + | ||
| 47 | +private func nilOrValue<T>(_ value: Any?) -> T? { | ||
| 48 | + if value is NSNull { return nil } | ||
| 49 | + return value as! T? | ||
| 50 | +} | ||
| 51 | + | ||
| 52 | + | ||
| 53 | +/// Alipay payment result codes. | ||
| 54 | +enum AliPayResultCode: Int { | ||
| 55 | + case success = 0 | ||
| 56 | + case cancel = 1 | ||
| 57 | + case error = 2 | ||
| 58 | + case unsupported = 3 | ||
| 59 | +} | ||
| 60 | + | ||
| 61 | +private class AlipayApiPigeonCodecReader: FlutterStandardReader { | ||
| 62 | + override func readValue(ofType type: UInt8) -> Any? { | ||
| 63 | + switch type { | ||
| 64 | + case 129: | ||
| 65 | + let enumResultAsInt: Int? = nilOrValue(self.readValue() as! Int?) | ||
| 66 | + if let enumResultAsInt = enumResultAsInt { | ||
| 67 | + return AliPayResultCode(rawValue: enumResultAsInt) | ||
| 68 | + } | ||
| 69 | + return nil | ||
| 70 | + default: | ||
| 71 | + return super.readValue(ofType: type) | ||
| 72 | + } | ||
| 73 | + } | ||
| 74 | +} | ||
| 75 | + | ||
| 76 | +private class AlipayApiPigeonCodecWriter: FlutterStandardWriter { | ||
| 77 | + override func writeValue(_ value: Any) { | ||
| 78 | + if let value = value as? AliPayResultCode { | ||
| 79 | + super.writeByte(129) | ||
| 80 | + super.writeValue(value.rawValue) | ||
| 81 | + } else { | ||
| 82 | + super.writeValue(value) | ||
| 83 | + } | ||
| 84 | + } | ||
| 85 | +} | ||
| 86 | + | ||
| 87 | +private class AlipayApiPigeonCodecReaderWriter: FlutterStandardReaderWriter { | ||
| 88 | + override func reader(with data: Data) -> FlutterStandardReader { | ||
| 89 | + return AlipayApiPigeonCodecReader(data: data) | ||
| 90 | + } | ||
| 91 | + | ||
| 92 | + override func writer(with data: NSMutableData) -> FlutterStandardWriter { | ||
| 93 | + return AlipayApiPigeonCodecWriter(data: data) | ||
| 94 | + } | ||
| 95 | +} | ||
| 96 | + | ||
| 97 | +class AlipayApiPigeonCodec: FlutterStandardMessageCodec, @unchecked Sendable { | ||
| 98 | + static let shared = AlipayApiPigeonCodec(readerWriter: AlipayApiPigeonCodecReaderWriter()) | ||
| 99 | +} | ||
| 100 | + | ||
| 101 | +/// Generated protocol from Pigeon that represents a handler of messages from Flutter. | ||
| 102 | +protocol AlipayHostApi { | ||
| 103 | + func launchAliPay(prepayData: String) throws -> AliPayResultCode | ||
| 104 | +} | ||
| 105 | + | ||
| 106 | +/// Generated setup class from Pigeon to handle messages through the `binaryMessenger`. | ||
| 107 | +class AlipayHostApiSetup { | ||
| 108 | + static var codec: FlutterStandardMessageCodec { AlipayApiPigeonCodec.shared } | ||
| 109 | + /// Sets up an instance of `AlipayHostApi` to handle messages through the `binaryMessenger`. | ||
| 110 | + static func setUp(binaryMessenger: FlutterBinaryMessenger, api: AlipayHostApi?, messageChannelSuffix: String = "") { | ||
| 111 | + let channelSuffix = messageChannelSuffix.count > 0 ? ".\(messageChannelSuffix)" : "" | ||
| 112 | + let launchAliPayChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.doublefeel_flutter.AlipayHostApi.launchAliPay\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) | ||
| 113 | + if let api = api { | ||
| 114 | + launchAliPayChannel.setMessageHandler { message, reply in | ||
| 115 | + let args = message as! [Any?] | ||
| 116 | + let prepayDataArg = args[0] as! String | ||
| 117 | + do { | ||
| 118 | + let result = try api.launchAliPay(prepayData: prepayDataArg) | ||
| 119 | + reply(wrapResult(result)) | ||
| 120 | + } catch { | ||
| 121 | + reply(wrapError(error)) | ||
| 122 | + } | ||
| 123 | + } | ||
| 124 | + } else { | ||
| 125 | + launchAliPayChannel.setMessageHandler(nil) | ||
| 126 | + } | ||
| 127 | + } | ||
| 128 | +} |
ios/Runner/Pigeon/HealthKitApi.swift
0 → 100644
| 1 | +// // Copyright 2013 The Flutter Authors. All rights reserved. | ||
| 2 | +// Autogenerated from Pigeon (v25.5.0), do not edit directly. | ||
| 3 | +// See also: https://pub.dev/packages/pigeon | ||
| 4 | + | ||
| 5 | +import Foundation | ||
| 6 | + | ||
| 7 | +#if os(iOS) | ||
| 8 | + import Flutter | ||
| 9 | +#elseif os(macOS) | ||
| 10 | + import FlutterMacOS | ||
| 11 | +#else | ||
| 12 | + #error("Unsupported platform.") | ||
| 13 | +#endif | ||
| 14 | + | ||
| 15 | + | ||
| 16 | +private func wrapResult(_ result: Any?) -> [Any?] { | ||
| 17 | + return [result] | ||
| 18 | +} | ||
| 19 | + | ||
| 20 | +private func wrapError(_ error: Any) -> [Any?] { | ||
| 21 | + if let pigeonError = error as? PigeonError { | ||
| 22 | + return [ | ||
| 23 | + pigeonError.code, | ||
| 24 | + pigeonError.message, | ||
| 25 | + pigeonError.details, | ||
| 26 | + ] | ||
| 27 | + } | ||
| 28 | + if let flutterError = error as? FlutterError { | ||
| 29 | + return [ | ||
| 30 | + flutterError.code, | ||
| 31 | + flutterError.message, | ||
| 32 | + flutterError.details, | ||
| 33 | + ] | ||
| 34 | + } | ||
| 35 | + return [ | ||
| 36 | + "\(error)", | ||
| 37 | + "\(type(of: error))", | ||
| 38 | + "Stacktrace: \(Thread.callStackSymbols)", | ||
| 39 | + ] | ||
| 40 | +} | ||
| 41 | + | ||
| 42 | +private func isNullish(_ value: Any?) -> Bool { | ||
| 43 | + return value is NSNull || value == nil | ||
| 44 | +} | ||
| 45 | + | ||
| 46 | +private func nilOrValue<T>(_ value: Any?) -> T? { | ||
| 47 | + if value is NSNull { return nil } | ||
| 48 | + return value as! T? | ||
| 49 | +} | ||
| 50 | + | ||
| 51 | +func deepEqualsHealthKitApi(_ lhs: Any?, _ rhs: Any?) -> Bool { | ||
| 52 | + let cleanLhs = nilOrValue(lhs) as Any? | ||
| 53 | + let cleanRhs = nilOrValue(rhs) as Any? | ||
| 54 | + switch (cleanLhs, cleanRhs) { | ||
| 55 | + case (nil, nil): | ||
| 56 | + return true | ||
| 57 | + | ||
| 58 | + case (nil, _), (_, nil): | ||
| 59 | + return false | ||
| 60 | + | ||
| 61 | + case is (Void, Void): | ||
| 62 | + return true | ||
| 63 | + | ||
| 64 | + case let (cleanLhsHashable, cleanRhsHashable) as (AnyHashable, AnyHashable): | ||
| 65 | + return cleanLhsHashable == cleanRhsHashable | ||
| 66 | + | ||
| 67 | + case let (cleanLhsArray, cleanRhsArray) as ([Any?], [Any?]): | ||
| 68 | + guard cleanLhsArray.count == cleanRhsArray.count else { return false } | ||
| 69 | + for (index, element) in cleanLhsArray.enumerated() { | ||
| 70 | + if !deepEqualsHealthKitApi(element, cleanRhsArray[index]) { | ||
| 71 | + return false | ||
| 72 | + } | ||
| 73 | + } | ||
| 74 | + return true | ||
| 75 | + | ||
| 76 | + case let (cleanLhsDictionary, cleanRhsDictionary) as ([AnyHashable: Any?], [AnyHashable: Any?]): | ||
| 77 | + guard cleanLhsDictionary.count == cleanRhsDictionary.count else { return false } | ||
| 78 | + for (key, cleanLhsValue) in cleanLhsDictionary { | ||
| 79 | + guard cleanRhsDictionary.index(forKey: key) != nil else { return false } | ||
| 80 | + if !deepEqualsHealthKitApi(cleanLhsValue, cleanRhsDictionary[key]!) { | ||
| 81 | + return false | ||
| 82 | + } | ||
| 83 | + } | ||
| 84 | + return true | ||
| 85 | + | ||
| 86 | + default: | ||
| 87 | + // Any other type shouldn't be able to be used with pigeon. File an issue if you find this to be untrue. | ||
| 88 | + return false | ||
| 89 | + } | ||
| 90 | +} | ||
| 91 | + | ||
| 92 | +func deepHashHealthKitApi(value: Any?, hasher: inout Hasher) { | ||
| 93 | + if let valueList = value as? [AnyHashable] { | ||
| 94 | + for item in valueList { deepHashHealthKitApi(value: item, hasher: &hasher) } | ||
| 95 | + return | ||
| 96 | + } | ||
| 97 | + | ||
| 98 | + if let valueDict = value as? [AnyHashable: AnyHashable] { | ||
| 99 | + for key in valueDict.keys { | ||
| 100 | + hasher.combine(key) | ||
| 101 | + deepHashHealthKitApi(value: valueDict[key]!, hasher: &hasher) | ||
| 102 | + } | ||
| 103 | + return | ||
| 104 | + } | ||
| 105 | + | ||
| 106 | + if let hashableValue = value as? AnyHashable { | ||
| 107 | + hasher.combine(hashableValue.hashValue) | ||
| 108 | + } | ||
| 109 | + | ||
| 110 | + return hasher.combine(String(describing: value)) | ||
| 111 | +} | ||
| 112 | + | ||
| 113 | + | ||
| 114 | + | ||
| 115 | +/// Generated class from Pigeon that represents data sent in messages. | ||
| 116 | +struct HealthUploadResult: Hashable { | ||
| 117 | + var commonUploadSuccess: Bool | ||
| 118 | + var sleepUploadSuccess: Bool | ||
| 119 | + var errorMessage: String? = nil | ||
| 120 | + | ||
| 121 | + | ||
| 122 | + // swift-format-ignore: AlwaysUseLowerCamelCase | ||
| 123 | + static func fromList(_ pigeonVar_list: [Any?]) -> HealthUploadResult? { | ||
| 124 | + let commonUploadSuccess = pigeonVar_list[0] as! Bool | ||
| 125 | + let sleepUploadSuccess = pigeonVar_list[1] as! Bool | ||
| 126 | + let errorMessage: String? = nilOrValue(pigeonVar_list[2]) | ||
| 127 | + | ||
| 128 | + return HealthUploadResult( | ||
| 129 | + commonUploadSuccess: commonUploadSuccess, | ||
| 130 | + sleepUploadSuccess: sleepUploadSuccess, | ||
| 131 | + errorMessage: errorMessage | ||
| 132 | + ) | ||
| 133 | + } | ||
| 134 | + func toList() -> [Any?] { | ||
| 135 | + return [ | ||
| 136 | + commonUploadSuccess, | ||
| 137 | + sleepUploadSuccess, | ||
| 138 | + errorMessage, | ||
| 139 | + ] | ||
| 140 | + } | ||
| 141 | + static func == (lhs: HealthUploadResult, rhs: HealthUploadResult) -> Bool { | ||
| 142 | + return deepEqualsHealthKitApi(lhs.toList(), rhs.toList()) } | ||
| 143 | + func hash(into hasher: inout Hasher) { | ||
| 144 | + deepHashHealthKitApi(value: toList(), hasher: &hasher) | ||
| 145 | + } | ||
| 146 | +} | ||
| 147 | + | ||
| 148 | +private class HealthKitApiPigeonCodecReader: FlutterStandardReader { | ||
| 149 | + override func readValue(ofType type: UInt8) -> Any? { | ||
| 150 | + switch type { | ||
| 151 | + case 129: | ||
| 152 | + return HealthUploadResult.fromList(self.readValue() as! [Any?]) | ||
| 153 | + default: | ||
| 154 | + return super.readValue(ofType: type) | ||
| 155 | + } | ||
| 156 | + } | ||
| 157 | +} | ||
| 158 | + | ||
| 159 | +private class HealthKitApiPigeonCodecWriter: FlutterStandardWriter { | ||
| 160 | + override func writeValue(_ value: Any) { | ||
| 161 | + if let value = value as? HealthUploadResult { | ||
| 162 | + super.writeByte(129) | ||
| 163 | + super.writeValue(value.toList()) | ||
| 164 | + } else { | ||
| 165 | + super.writeValue(value) | ||
| 166 | + } | ||
| 167 | + } | ||
| 168 | +} | ||
| 169 | + | ||
| 170 | +private class HealthKitApiPigeonCodecReaderWriter: FlutterStandardReaderWriter { | ||
| 171 | + override func reader(with data: Data) -> FlutterStandardReader { | ||
| 172 | + return HealthKitApiPigeonCodecReader(data: data) | ||
| 173 | + } | ||
| 174 | + | ||
| 175 | + override func writer(with data: NSMutableData) -> FlutterStandardWriter { | ||
| 176 | + return HealthKitApiPigeonCodecWriter(data: data) | ||
| 177 | + } | ||
| 178 | +} | ||
| 179 | + | ||
| 180 | +class HealthKitApiPigeonCodec: FlutterStandardMessageCodec, @unchecked Sendable { | ||
| 181 | + static let shared = HealthKitApiPigeonCodec(readerWriter: HealthKitApiPigeonCodecReaderWriter()) | ||
| 182 | +} | ||
| 183 | + | ||
| 184 | +/// Generated protocol from Pigeon that represents a handler of messages from Flutter. | ||
| 185 | +protocol HealthKitHostApi { | ||
| 186 | + func checkHealthAppAuthorization() throws -> Bool | ||
| 187 | + func getHealthServerAuthUrl() throws -> String | ||
| 188 | + /// Opens Huawei Health client authorization UI. Returns whether user granted. | ||
| 189 | + func requestHealthClientAuthorization() throws -> Bool | ||
| 190 | + func cancelHealthAppAuthorization() throws -> Bool | ||
| 191 | + /// Runs native health read and server upload pipeline. | ||
| 192 | + func performHealthUpload() throws -> HealthUploadResult | ||
| 193 | +} | ||
| 194 | + | ||
| 195 | +/// Generated setup class from Pigeon to handle messages through the `binaryMessenger`. | ||
| 196 | +class HealthKitHostApiSetup { | ||
| 197 | + static var codec: FlutterStandardMessageCodec { HealthKitApiPigeonCodec.shared } | ||
| 198 | + /// Sets up an instance of `HealthKitHostApi` to handle messages through the `binaryMessenger`. | ||
| 199 | + static func setUp(binaryMessenger: FlutterBinaryMessenger, api: HealthKitHostApi?, messageChannelSuffix: String = "") { | ||
| 200 | + let channelSuffix = messageChannelSuffix.count > 0 ? ".\(messageChannelSuffix)" : "" | ||
| 201 | + let checkHealthAppAuthorizationChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.doublefeel_flutter.HealthKitHostApi.checkHealthAppAuthorization\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) | ||
| 202 | + if let api = api { | ||
| 203 | + checkHealthAppAuthorizationChannel.setMessageHandler { _, reply in | ||
| 204 | + do { | ||
| 205 | + let result = try api.checkHealthAppAuthorization() | ||
| 206 | + reply(wrapResult(result)) | ||
| 207 | + } catch { | ||
| 208 | + reply(wrapError(error)) | ||
| 209 | + } | ||
| 210 | + } | ||
| 211 | + } else { | ||
| 212 | + checkHealthAppAuthorizationChannel.setMessageHandler(nil) | ||
| 213 | + } | ||
| 214 | + let getHealthServerAuthUrlChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.doublefeel_flutter.HealthKitHostApi.getHealthServerAuthUrl\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) | ||
| 215 | + if let api = api { | ||
| 216 | + getHealthServerAuthUrlChannel.setMessageHandler { _, reply in | ||
| 217 | + do { | ||
| 218 | + let result = try api.getHealthServerAuthUrl() | ||
| 219 | + reply(wrapResult(result)) | ||
| 220 | + } catch { | ||
| 221 | + reply(wrapError(error)) | ||
| 222 | + } | ||
| 223 | + } | ||
| 224 | + } else { | ||
| 225 | + getHealthServerAuthUrlChannel.setMessageHandler(nil) | ||
| 226 | + } | ||
| 227 | + /// Opens Huawei Health client authorization UI. Returns whether user granted. | ||
| 228 | + let requestHealthClientAuthorizationChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.doublefeel_flutter.HealthKitHostApi.requestHealthClientAuthorization\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) | ||
| 229 | + if let api = api { | ||
| 230 | + requestHealthClientAuthorizationChannel.setMessageHandler { _, reply in | ||
| 231 | + do { | ||
| 232 | + let result = try api.requestHealthClientAuthorization() | ||
| 233 | + reply(wrapResult(result)) | ||
| 234 | + } catch { | ||
| 235 | + reply(wrapError(error)) | ||
| 236 | + } | ||
| 237 | + } | ||
| 238 | + } else { | ||
| 239 | + requestHealthClientAuthorizationChannel.setMessageHandler(nil) | ||
| 240 | + } | ||
| 241 | + let cancelHealthAppAuthorizationChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.doublefeel_flutter.HealthKitHostApi.cancelHealthAppAuthorization\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) | ||
| 242 | + if let api = api { | ||
| 243 | + cancelHealthAppAuthorizationChannel.setMessageHandler { _, reply in | ||
| 244 | + do { | ||
| 245 | + let result = try api.cancelHealthAppAuthorization() | ||
| 246 | + reply(wrapResult(result)) | ||
| 247 | + } catch { | ||
| 248 | + reply(wrapError(error)) | ||
| 249 | + } | ||
| 250 | + } | ||
| 251 | + } else { | ||
| 252 | + cancelHealthAppAuthorizationChannel.setMessageHandler(nil) | ||
| 253 | + } | ||
| 254 | + /// Runs native health read and server upload pipeline. | ||
| 255 | + let performHealthUploadChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.doublefeel_flutter.HealthKitHostApi.performHealthUpload\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) | ||
| 256 | + if let api = api { | ||
| 257 | + performHealthUploadChannel.setMessageHandler { _, reply in | ||
| 258 | + do { | ||
| 259 | + let result = try api.performHealthUpload() | ||
| 260 | + reply(wrapResult(result)) | ||
| 261 | + } catch { | ||
| 262 | + reply(wrapError(error)) | ||
| 263 | + } | ||
| 264 | + } | ||
| 265 | + } else { | ||
| 266 | + performHealthUploadChannel.setMessageHandler(nil) | ||
| 267 | + } | ||
| 268 | + } | ||
| 269 | +} |
ios/Runner/Pigeon/NativeHostApiStubs.swift
0 → 100644
| 1 | +import Foundation | ||
| 2 | +import Flutter | ||
| 3 | + | ||
| 4 | +private let unsupported = "HealthKit / WearEngine / Alipay are not supported on iOS in this build." | ||
| 5 | + | ||
| 6 | +final class HealthKitHostApiStub: HealthKitHostApi { | ||
| 7 | + func checkHealthAppAuthorization() throws -> Bool { false } | ||
| 8 | + func getHealthServerAuthUrl() throws -> String { "" } | ||
| 9 | + func requestHealthClientAuthorization() throws -> Bool { false } | ||
| 10 | + func cancelHealthAppAuthorization() throws -> Bool { false } | ||
| 11 | + func performHealthUpload() throws -> HealthUploadResult { | ||
| 12 | + HealthUploadResult(commonUploadSuccess: false, sleepUploadSuccess: false, errorMessage: unsupported) | ||
| 13 | + } | ||
| 14 | +} | ||
| 15 | + | ||
| 16 | +final class WearEngineHostApiStub: WearEngineHostApi { | ||
| 17 | + func hasAvailableDevices() throws -> Bool { false } | ||
| 18 | + func checkConnectedDevice() throws -> WearDeviceInfo? { nil } | ||
| 19 | + func registerMessageReceiver() throws -> Bool { false } | ||
| 20 | + func sendTextMessage(message: String) throws -> Bool { false } | ||
| 21 | + func sendWatchSyncPayload(jsonPayload: String) throws -> Bool { false } | ||
| 22 | +} | ||
| 23 | + | ||
| 24 | +final class AlipayHostApiStub: AlipayHostApi { | ||
| 25 | + func launchAliPay(prepayData: String) throws -> AliPayResultCode { .unsupported } | ||
| 26 | +} | ||
| 27 | + | ||
| 28 | +enum NativePigeonRegistrar { | ||
| 29 | + static func register(binaryMessenger: FlutterBinaryMessenger) { | ||
| 30 | + HealthKitHostApiSetup.setUp(binaryMessenger: binaryMessenger, api: HealthKitHostApiStub()) | ||
| 31 | + WearEngineHostApiSetup.setUp(binaryMessenger: binaryMessenger, api: WearEngineHostApiStub()) | ||
| 32 | + AlipayHostApiSetup.setUp(binaryMessenger: binaryMessenger, api: AlipayHostApiStub()) | ||
| 33 | + } | ||
| 34 | +} |
ios/Runner/Pigeon/PigeonShared.swift
0 → 100644
| 1 | +// Shared Pigeon types for all generated API files in this target. | ||
| 2 | +// Pigeon emits PigeonError in every swiftOut file; only one definition is allowed per module. | ||
| 3 | + | ||
| 4 | +import Foundation | ||
| 5 | + | ||
| 6 | +/// Error class for passing custom error details to Dart side. | ||
| 7 | +final class PigeonError: Error { | ||
| 8 | + let code: String | ||
| 9 | + let message: String? | ||
| 10 | + let details: Sendable? | ||
| 11 | + | ||
| 12 | + init(code: String, message: String?, details: Sendable?) { | ||
| 13 | + self.code = code | ||
| 14 | + self.message = message | ||
| 15 | + self.details = details | ||
| 16 | + } | ||
| 17 | + | ||
| 18 | + var localizedDescription: String { | ||
| 19 | + return | ||
| 20 | + "PigeonError(code: \(code), message: \(message ?? "<nil>"), details: \(details ?? "<nil>")" | ||
| 21 | + } | ||
| 22 | +} |
ios/Runner/Pigeon/WearEngineApi.swift
0 → 100644
| 1 | +// // Copyright 2013 The Flutter Authors. All rights reserved. | ||
| 2 | +// Autogenerated from Pigeon (v25.5.0), do not edit directly. | ||
| 3 | +// See also: https://pub.dev/packages/pigeon | ||
| 4 | + | ||
| 5 | +import Foundation | ||
| 6 | + | ||
| 7 | +#if os(iOS) | ||
| 8 | + import Flutter | ||
| 9 | +#elseif os(macOS) | ||
| 10 | + import FlutterMacOS | ||
| 11 | +#else | ||
| 12 | + #error("Unsupported platform.") | ||
| 13 | +#endif | ||
| 14 | + | ||
| 15 | + | ||
| 16 | +private func wrapResult(_ result: Any?) -> [Any?] { | ||
| 17 | + return [result] | ||
| 18 | +} | ||
| 19 | + | ||
| 20 | +private func wrapError(_ error: Any) -> [Any?] { | ||
| 21 | + if let pigeonError = error as? PigeonError { | ||
| 22 | + return [ | ||
| 23 | + pigeonError.code, | ||
| 24 | + pigeonError.message, | ||
| 25 | + pigeonError.details, | ||
| 26 | + ] | ||
| 27 | + } | ||
| 28 | + if let flutterError = error as? FlutterError { | ||
| 29 | + return [ | ||
| 30 | + flutterError.code, | ||
| 31 | + flutterError.message, | ||
| 32 | + flutterError.details, | ||
| 33 | + ] | ||
| 34 | + } | ||
| 35 | + return [ | ||
| 36 | + "\(error)", | ||
| 37 | + "\(type(of: error))", | ||
| 38 | + "Stacktrace: \(Thread.callStackSymbols)", | ||
| 39 | + ] | ||
| 40 | +} | ||
| 41 | + | ||
| 42 | +private func isNullish(_ value: Any?) -> Bool { | ||
| 43 | + return value is NSNull || value == nil | ||
| 44 | +} | ||
| 45 | + | ||
| 46 | +private func nilOrValue<T>(_ value: Any?) -> T? { | ||
| 47 | + if value is NSNull { return nil } | ||
| 48 | + return value as! T? | ||
| 49 | +} | ||
| 50 | + | ||
| 51 | +func deepEqualsWearEngineApi(_ lhs: Any?, _ rhs: Any?) -> Bool { | ||
| 52 | + let cleanLhs = nilOrValue(lhs) as Any? | ||
| 53 | + let cleanRhs = nilOrValue(rhs) as Any? | ||
| 54 | + switch (cleanLhs, cleanRhs) { | ||
| 55 | + case (nil, nil): | ||
| 56 | + return true | ||
| 57 | + | ||
| 58 | + case (nil, _), (_, nil): | ||
| 59 | + return false | ||
| 60 | + | ||
| 61 | + case is (Void, Void): | ||
| 62 | + return true | ||
| 63 | + | ||
| 64 | + case let (cleanLhsHashable, cleanRhsHashable) as (AnyHashable, AnyHashable): | ||
| 65 | + return cleanLhsHashable == cleanRhsHashable | ||
| 66 | + | ||
| 67 | + case let (cleanLhsArray, cleanRhsArray) as ([Any?], [Any?]): | ||
| 68 | + guard cleanLhsArray.count == cleanRhsArray.count else { return false } | ||
| 69 | + for (index, element) in cleanLhsArray.enumerated() { | ||
| 70 | + if !deepEqualsWearEngineApi(element, cleanRhsArray[index]) { | ||
| 71 | + return false | ||
| 72 | + } | ||
| 73 | + } | ||
| 74 | + return true | ||
| 75 | + | ||
| 76 | + case let (cleanLhsDictionary, cleanRhsDictionary) as ([AnyHashable: Any?], [AnyHashable: Any?]): | ||
| 77 | + guard cleanLhsDictionary.count == cleanRhsDictionary.count else { return false } | ||
| 78 | + for (key, cleanLhsValue) in cleanLhsDictionary { | ||
| 79 | + guard cleanRhsDictionary.index(forKey: key) != nil else { return false } | ||
| 80 | + if !deepEqualsWearEngineApi(cleanLhsValue, cleanRhsDictionary[key]!) { | ||
| 81 | + return false | ||
| 82 | + } | ||
| 83 | + } | ||
| 84 | + return true | ||
| 85 | + | ||
| 86 | + default: | ||
| 87 | + // Any other type shouldn't be able to be used with pigeon. File an issue if you find this to be untrue. | ||
| 88 | + return false | ||
| 89 | + } | ||
| 90 | +} | ||
| 91 | + | ||
| 92 | +func deepHashWearEngineApi(value: Any?, hasher: inout Hasher) { | ||
| 93 | + if let valueList = value as? [AnyHashable] { | ||
| 94 | + for item in valueList { deepHashWearEngineApi(value: item, hasher: &hasher) } | ||
| 95 | + return | ||
| 96 | + } | ||
| 97 | + | ||
| 98 | + if let valueDict = value as? [AnyHashable: AnyHashable] { | ||
| 99 | + for key in valueDict.keys { | ||
| 100 | + hasher.combine(key) | ||
| 101 | + deepHashWearEngineApi(value: valueDict[key]!, hasher: &hasher) | ||
| 102 | + } | ||
| 103 | + return | ||
| 104 | + } | ||
| 105 | + | ||
| 106 | + if let hashableValue = value as? AnyHashable { | ||
| 107 | + hasher.combine(hashableValue.hashValue) | ||
| 108 | + } | ||
| 109 | + | ||
| 110 | + return hasher.combine(String(describing: value)) | ||
| 111 | +} | ||
| 112 | + | ||
| 113 | + | ||
| 114 | + | ||
| 115 | +/// Generated class from Pigeon that represents data sent in messages. | ||
| 116 | +struct WearDeviceInfo: Hashable { | ||
| 117 | + var deviceId: String? = nil | ||
| 118 | + var deviceName: String? = nil | ||
| 119 | + var isConnected: Bool? = nil | ||
| 120 | + | ||
| 121 | + | ||
| 122 | + // swift-format-ignore: AlwaysUseLowerCamelCase | ||
| 123 | + static func fromList(_ pigeonVar_list: [Any?]) -> WearDeviceInfo? { | ||
| 124 | + let deviceId: String? = nilOrValue(pigeonVar_list[0]) | ||
| 125 | + let deviceName: String? = nilOrValue(pigeonVar_list[1]) | ||
| 126 | + let isConnected: Bool? = nilOrValue(pigeonVar_list[2]) | ||
| 127 | + | ||
| 128 | + return WearDeviceInfo( | ||
| 129 | + deviceId: deviceId, | ||
| 130 | + deviceName: deviceName, | ||
| 131 | + isConnected: isConnected | ||
| 132 | + ) | ||
| 133 | + } | ||
| 134 | + func toList() -> [Any?] { | ||
| 135 | + return [ | ||
| 136 | + deviceId, | ||
| 137 | + deviceName, | ||
| 138 | + isConnected, | ||
| 139 | + ] | ||
| 140 | + } | ||
| 141 | + static func == (lhs: WearDeviceInfo, rhs: WearDeviceInfo) -> Bool { | ||
| 142 | + return deepEqualsWearEngineApi(lhs.toList(), rhs.toList()) } | ||
| 143 | + func hash(into hasher: inout Hasher) { | ||
| 144 | + deepHashWearEngineApi(value: toList(), hasher: &hasher) | ||
| 145 | + } | ||
| 146 | +} | ||
| 147 | + | ||
| 148 | +private class WearEngineApiPigeonCodecReader: FlutterStandardReader { | ||
| 149 | + override func readValue(ofType type: UInt8) -> Any? { | ||
| 150 | + switch type { | ||
| 151 | + case 129: | ||
| 152 | + return WearDeviceInfo.fromList(self.readValue() as! [Any?]) | ||
| 153 | + default: | ||
| 154 | + return super.readValue(ofType: type) | ||
| 155 | + } | ||
| 156 | + } | ||
| 157 | +} | ||
| 158 | + | ||
| 159 | +private class WearEngineApiPigeonCodecWriter: FlutterStandardWriter { | ||
| 160 | + override func writeValue(_ value: Any) { | ||
| 161 | + if let value = value as? WearDeviceInfo { | ||
| 162 | + super.writeByte(129) | ||
| 163 | + super.writeValue(value.toList()) | ||
| 164 | + } else { | ||
| 165 | + super.writeValue(value) | ||
| 166 | + } | ||
| 167 | + } | ||
| 168 | +} | ||
| 169 | + | ||
| 170 | +private class WearEngineApiPigeonCodecReaderWriter: FlutterStandardReaderWriter { | ||
| 171 | + override func reader(with data: Data) -> FlutterStandardReader { | ||
| 172 | + return WearEngineApiPigeonCodecReader(data: data) | ||
| 173 | + } | ||
| 174 | + | ||
| 175 | + override func writer(with data: NSMutableData) -> FlutterStandardWriter { | ||
| 176 | + return WearEngineApiPigeonCodecWriter(data: data) | ||
| 177 | + } | ||
| 178 | +} | ||
| 179 | + | ||
| 180 | +class WearEngineApiPigeonCodec: FlutterStandardMessageCodec, @unchecked Sendable { | ||
| 181 | + static let shared = WearEngineApiPigeonCodec(readerWriter: WearEngineApiPigeonCodecReaderWriter()) | ||
| 182 | +} | ||
| 183 | + | ||
| 184 | +/// Generated protocol from Pigeon that represents a handler of messages from Flutter. | ||
| 185 | +protocol WearEngineHostApi { | ||
| 186 | + func hasAvailableDevices() throws -> Bool | ||
| 187 | + func checkConnectedDevice() throws -> WearDeviceInfo? | ||
| 188 | + func registerMessageReceiver() throws -> Bool | ||
| 189 | + func sendTextMessage(message: String) throws -> Bool | ||
| 190 | + func sendWatchSyncPayload(jsonPayload: String) throws -> Bool | ||
| 191 | +} | ||
| 192 | + | ||
| 193 | +/// Generated setup class from Pigeon to handle messages through the `binaryMessenger`. | ||
| 194 | +class WearEngineHostApiSetup { | ||
| 195 | + static var codec: FlutterStandardMessageCodec { WearEngineApiPigeonCodec.shared } | ||
| 196 | + /// Sets up an instance of `WearEngineHostApi` to handle messages through the `binaryMessenger`. | ||
| 197 | + static func setUp(binaryMessenger: FlutterBinaryMessenger, api: WearEngineHostApi?, messageChannelSuffix: String = "") { | ||
| 198 | + let channelSuffix = messageChannelSuffix.count > 0 ? ".\(messageChannelSuffix)" : "" | ||
| 199 | + let hasAvailableDevicesChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.doublefeel_flutter.WearEngineHostApi.hasAvailableDevices\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) | ||
| 200 | + if let api = api { | ||
| 201 | + hasAvailableDevicesChannel.setMessageHandler { _, reply in | ||
| 202 | + do { | ||
| 203 | + let result = try api.hasAvailableDevices() | ||
| 204 | + reply(wrapResult(result)) | ||
| 205 | + } catch { | ||
| 206 | + reply(wrapError(error)) | ||
| 207 | + } | ||
| 208 | + } | ||
| 209 | + } else { | ||
| 210 | + hasAvailableDevicesChannel.setMessageHandler(nil) | ||
| 211 | + } | ||
| 212 | + let checkConnectedDeviceChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.doublefeel_flutter.WearEngineHostApi.checkConnectedDevice\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) | ||
| 213 | + if let api = api { | ||
| 214 | + checkConnectedDeviceChannel.setMessageHandler { _, reply in | ||
| 215 | + do { | ||
| 216 | + let result = try api.checkConnectedDevice() | ||
| 217 | + reply(wrapResult(result)) | ||
| 218 | + } catch { | ||
| 219 | + reply(wrapError(error)) | ||
| 220 | + } | ||
| 221 | + } | ||
| 222 | + } else { | ||
| 223 | + checkConnectedDeviceChannel.setMessageHandler(nil) | ||
| 224 | + } | ||
| 225 | + let registerMessageReceiverChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.doublefeel_flutter.WearEngineHostApi.registerMessageReceiver\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) | ||
| 226 | + if let api = api { | ||
| 227 | + registerMessageReceiverChannel.setMessageHandler { _, reply in | ||
| 228 | + do { | ||
| 229 | + let result = try api.registerMessageReceiver() | ||
| 230 | + reply(wrapResult(result)) | ||
| 231 | + } catch { | ||
| 232 | + reply(wrapError(error)) | ||
| 233 | + } | ||
| 234 | + } | ||
| 235 | + } else { | ||
| 236 | + registerMessageReceiverChannel.setMessageHandler(nil) | ||
| 237 | + } | ||
| 238 | + let sendTextMessageChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.doublefeel_flutter.WearEngineHostApi.sendTextMessage\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) | ||
| 239 | + if let api = api { | ||
| 240 | + sendTextMessageChannel.setMessageHandler { message, reply in | ||
| 241 | + let args = message as! [Any?] | ||
| 242 | + let messageArg = args[0] as! String | ||
| 243 | + do { | ||
| 244 | + let result = try api.sendTextMessage(message: messageArg) | ||
| 245 | + reply(wrapResult(result)) | ||
| 246 | + } catch { | ||
| 247 | + reply(wrapError(error)) | ||
| 248 | + } | ||
| 249 | + } | ||
| 250 | + } else { | ||
| 251 | + sendTextMessageChannel.setMessageHandler(nil) | ||
| 252 | + } | ||
| 253 | + let sendWatchSyncPayloadChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.doublefeel_flutter.WearEngineHostApi.sendWatchSyncPayload\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) | ||
| 254 | + if let api = api { | ||
| 255 | + sendWatchSyncPayloadChannel.setMessageHandler { message, reply in | ||
| 256 | + let args = message as! [Any?] | ||
| 257 | + let jsonPayloadArg = args[0] as! String | ||
| 258 | + do { | ||
| 259 | + let result = try api.sendWatchSyncPayload(jsonPayload: jsonPayloadArg) | ||
| 260 | + reply(wrapResult(result)) | ||
| 261 | + } catch { | ||
| 262 | + reply(wrapError(error)) | ||
| 263 | + } | ||
| 264 | + } | ||
| 265 | + } else { | ||
| 266 | + sendWatchSyncPayloadChannel.setMessageHandler(nil) | ||
| 267 | + } | ||
| 268 | + } | ||
| 269 | +} |
ios/Runner/Runner-Bridging-Header.h
0 → 100644
| 1 | +#import "GeneratedPluginRegistrant.h" |
ios/RunnerTests/RunnerTests.swift
0 → 100644
| 1 | +import Flutter | ||
| 2 | +import UIKit | ||
| 3 | +import XCTest | ||
| 4 | + | ||
| 5 | +class RunnerTests: XCTestCase { | ||
| 6 | + | ||
| 7 | + func testExample() { | ||
| 8 | + // If you add code to the Runner application, consider adding tests here. | ||
| 9 | + // See https://developer.apple.com/documentation/xctest for more information about using XCTest. | ||
| 10 | + } | ||
| 11 | + | ||
| 12 | +} |
l10n.yaml
0 → 100644
lib/app/bindings/dependency_registrars.dart
0 → 100644
| 1 | +import 'package:get/get.dart'; | ||
| 2 | + | ||
| 3 | +import '../../core/config/app_environment_config.dart'; | ||
| 4 | +import '../../core/error/app_error_handler.dart'; | ||
| 5 | +import '../../core/network/api/config_api.dart'; | ||
| 6 | +import '../../core/network/api/health_api.dart'; | ||
| 7 | +import '../../core/network/api/interaction_api.dart'; | ||
| 8 | +import '../../core/network/api/obs_api.dart'; | ||
| 9 | +import '../../core/network/api/pay_api.dart'; | ||
| 10 | +import '../../core/network/api/user_api.dart'; | ||
| 11 | +import '../../core/network/api/vip_api.dart'; | ||
| 12 | +import '../../core/network/dio_client.dart'; | ||
| 13 | +import '../../core/services/health_kit_upload_service.dart'; | ||
| 14 | +import '../../core/services/im_service.dart'; | ||
| 15 | +import '../../core/services/obs_upload_service.dart'; | ||
| 16 | +import '../../core/services/push_service.dart'; | ||
| 17 | +import '../../core/services/thinking_data_service.dart'; | ||
| 18 | +import '../../core/services/user_state_service.dart'; | ||
| 19 | +import '../../core/services/wear_engine_service.dart'; | ||
| 20 | +import '../../data/local/user_preferences_storage.dart'; | ||
| 21 | + | ||
| 22 | +/// App-wide infrastructure (error handling, config, network client). | ||
| 23 | +void registerCoreDeps({ | ||
| 24 | + required AppEnvironmentConfig environmentConfig, | ||
| 25 | + required UserPreferencesStorage userPreferencesStorage, | ||
| 26 | +}) { | ||
| 27 | + Get.put(AppErrorHandler(), permanent: true); | ||
| 28 | + Get.put(environmentConfig, permanent: true); | ||
| 29 | + Get.put(userPreferencesStorage, permanent: true); | ||
| 30 | + Get.put( | ||
| 31 | + DioClient( | ||
| 32 | + Get.find<AppEnvironmentConfig>(), | ||
| 33 | + Get.find<UserPreferencesStorage>(), | ||
| 34 | + ), | ||
| 35 | + permanent: true, | ||
| 36 | + ); | ||
| 37 | +} | ||
| 38 | + | ||
| 39 | +/// User session, auth APIs, and login-side SDK wiring. | ||
| 40 | +void registerUserSessionDeps() { | ||
| 41 | + final dioClient = Get.find<DioClient>(); | ||
| 42 | + final userPrefs = Get.find<UserPreferencesStorage>(); | ||
| 43 | + | ||
| 44 | + Get.put(UserApi(dioClient), permanent: true); | ||
| 45 | + Get.put(VipApi(dioClient), permanent: true); | ||
| 46 | + Get.put<ImService>(ImServiceStub(), permanent: true); | ||
| 47 | + Get.put( | ||
| 48 | + ThinkingDataService(Get.find<AppEnvironmentConfig>()), | ||
| 49 | + permanent: true, | ||
| 50 | + ); | ||
| 51 | + Get.put(PushService(Get.find<UserApi>()), permanent: true); | ||
| 52 | + Get.put( | ||
| 53 | + UserStateService( | ||
| 54 | + userPrefs, | ||
| 55 | + Get.find<UserApi>(), | ||
| 56 | + Get.find<ImService>(), | ||
| 57 | + Get.find<PushService>(), | ||
| 58 | + Get.find<ThinkingDataService>(), | ||
| 59 | + ), | ||
| 60 | + permanent: true, | ||
| 61 | + ); | ||
| 62 | +} | ||
| 63 | + | ||
| 64 | +/// Health data API and upload pipeline (lazy, recreated after dispose). | ||
| 65 | +void registerHealthDeps(DioClient dioClient) { | ||
| 66 | + Get.lazyPut(() => HealthApi(dioClient), fenix: true); | ||
| 67 | + Get.lazyPut( | ||
| 68 | + () => HealthKitUploadService(Get.find<HealthApi>()), | ||
| 69 | + fenix: true, | ||
| 70 | + ); | ||
| 71 | +} | ||
| 72 | + | ||
| 73 | +/// Payment API. | ||
| 74 | +void registerPayDeps(DioClient dioClient) { | ||
| 75 | + Get.lazyPut(() => PayApi(dioClient), fenix: true); | ||
| 76 | +} | ||
| 77 | + | ||
| 78 | +/// Remote config API. | ||
| 79 | +void registerConfigDeps(DioClient dioClient) { | ||
| 80 | + Get.lazyPut(() => ConfigApi(dioClient), fenix: true); | ||
| 81 | +} | ||
| 82 | + | ||
| 83 | +/// Partner interaction API and wear engine. | ||
| 84 | +void registerInteractionDeps( | ||
| 85 | + DioClient dioClient, | ||
| 86 | + UserPreferencesStorage userPrefs, | ||
| 87 | +) { | ||
| 88 | + Get.lazyPut(() => InteractionApi(dioClient), fenix: true); | ||
| 89 | + Get.lazyPut( | ||
| 90 | + () => WearEngineService( | ||
| 91 | + userPrefs, | ||
| 92 | + Get.find<HealthApi>(), | ||
| 93 | + Get.find<InteractionApi>(), | ||
| 94 | + ), | ||
| 95 | + fenix: true, | ||
| 96 | + ); | ||
| 97 | +} | ||
| 98 | + | ||
| 99 | +/// Object storage upload API and service. | ||
| 100 | +void registerObsDeps(DioClient dioClient) { | ||
| 101 | + Get.lazyPut(() => ObsApi(dioClient), fenix: true); | ||
| 102 | + Get.lazyPut(() => ObsUploadService(Get.find<ObsApi>()), fenix: true); | ||
| 103 | +} |
lib/app/bindings/initial_binding.dart
0 → 100644
| 1 | +import 'package:get/get.dart'; | ||
| 2 | + | ||
| 3 | +import '../../core/config/app_environment_config.dart'; | ||
| 4 | +import '../../core/network/dio_client.dart'; | ||
| 5 | +import '../../data/local/user_preferences_storage.dart'; | ||
| 6 | +import 'dependency_registrars.dart'; | ||
| 7 | + | ||
| 8 | +/// Core dependencies required at cold start (splash + session). | ||
| 9 | +class InitialBinding extends Bindings { | ||
| 10 | + InitialBinding({ | ||
| 11 | + required this.environmentConfig, | ||
| 12 | + required this.userPreferencesStorage, | ||
| 13 | + }); | ||
| 14 | + | ||
| 15 | + final AppEnvironmentConfig environmentConfig; | ||
| 16 | + final UserPreferencesStorage userPreferencesStorage; | ||
| 17 | + | ||
| 18 | + @override | ||
| 19 | + void dependencies() { | ||
| 20 | + registerCoreDeps( | ||
| 21 | + environmentConfig: environmentConfig, | ||
| 22 | + userPreferencesStorage: userPreferencesStorage, | ||
| 23 | + ); | ||
| 24 | + registerUserSessionDeps(); | ||
| 25 | + | ||
| 26 | + final dioClient = Get.find<DioClient>(); | ||
| 27 | + final userPrefs = Get.find<UserPreferencesStorage>(); | ||
| 28 | + | ||
| 29 | + registerHealthDeps(dioClient); | ||
| 30 | + registerPayDeps(dioClient); | ||
| 31 | + registerConfigDeps(dioClient); | ||
| 32 | + registerInteractionDeps(dioClient, userPrefs); | ||
| 33 | + registerObsDeps(dioClient); | ||
| 34 | + } | ||
| 35 | +} |
lib/app/bootstrap/app_bootstrap.dart
0 → 100644
| 1 | +import 'package:flutter/widgets.dart'; | ||
| 2 | +import 'package:get/get.dart'; | ||
| 3 | + | ||
| 4 | +import '../../core/config/app_environment_config.dart'; | ||
| 5 | +import '../../core/logging/app_logger.dart'; | ||
| 6 | +import '../../core/services/user_state_service.dart'; | ||
| 7 | +import '../../data/local/local_storage.dart'; | ||
| 8 | +import '../../data/local/user_preferences_storage.dart'; | ||
| 9 | +import '../bindings/initial_binding.dart'; | ||
| 10 | + | ||
| 11 | +/// Application startup before [runApp]. | ||
| 12 | +abstract final class AppBootstrap { | ||
| 13 | + static Future<void> init() async { | ||
| 14 | + WidgetsFlutterBinding.ensureInitialized(); | ||
| 15 | + AppLogger.init(); | ||
| 16 | + | ||
| 17 | + final local = await LocalStorage.open(); | ||
| 18 | + | ||
| 19 | + final environmentConfig = AppEnvironmentConfig(local); | ||
| 20 | + await environmentConfig.init(); | ||
| 21 | + | ||
| 22 | + final userPreferencesStorage = | ||
| 23 | + UserPreferencesStorage(local.sharedPreferences); | ||
| 24 | + await userPreferencesStorage.init(); | ||
| 25 | + | ||
| 26 | + InitialBinding( | ||
| 27 | + environmentConfig: environmentConfig, | ||
| 28 | + userPreferencesStorage: userPreferencesStorage, | ||
| 29 | + ).dependencies(); | ||
| 30 | + | ||
| 31 | + if (local.termsAgreed) { | ||
| 32 | + await Get.find<UserStateService>().initializeSdks(); | ||
| 33 | + } | ||
| 34 | + } | ||
| 35 | +} |
lib/app/double_feel_app.dart
0 → 100644
| 1 | +import 'package:doublefeel_flutter/l10n/l10n_extensions.dart'; | ||
| 2 | +import 'package:flutter/material.dart'; | ||
| 3 | +import 'package:get/get.dart'; | ||
| 4 | + | ||
| 5 | +import 'routes/app_pages.dart'; | ||
| 6 | + | ||
| 7 | +class DoubleFeelApp extends StatelessWidget { | ||
| 8 | + const DoubleFeelApp({super.key}); | ||
| 9 | + | ||
| 10 | + @override | ||
| 11 | + Widget build(BuildContext context) { | ||
| 12 | + return GetMaterialApp( | ||
| 13 | + title: context.l10n.appName, | ||
| 14 | + initialRoute: AppPages.initialRoute, | ||
| 15 | + getPages: AppPages.routes, | ||
| 16 | + localizationsDelegates: AppLocalizations.localizationsDelegates, | ||
| 17 | + supportedLocales: AppLocalizations.supportedLocales, | ||
| 18 | + localeResolutionCallback: (deviceLocale, supportedLocales) { | ||
| 19 | + if (deviceLocale == null) return const Locale('zh'); | ||
| 20 | + for (final locale in supportedLocales) { | ||
| 21 | + if (locale.languageCode == deviceLocale.languageCode) { | ||
| 22 | + return locale; | ||
| 23 | + } | ||
| 24 | + } | ||
| 25 | + return const Locale('zh'); | ||
| 26 | + }, | ||
| 27 | + ); | ||
| 28 | + } | ||
| 29 | +} |
| 1 | +import 'package:doublefeel_flutter/app/routes/app_pages.dart'; | ||
| 2 | +import 'package:doublefeel_flutter/core/services/user_state_service.dart'; | ||
| 3 | +import 'package:doublefeel_flutter/data/local/user_preferences_storage.dart'; | ||
| 4 | +import 'package:flutter/widgets.dart'; | ||
| 5 | +import 'package:get/get.dart'; | ||
| 6 | + | ||
| 7 | +class BindPartnerController extends GetxController { | ||
| 8 | + final TextEditingController partnerIdController = TextEditingController(); | ||
| 9 | + | ||
| 10 | + final RxString partnerIdInput = ''.obs; | ||
| 11 | + | ||
| 12 | + final RxBool isSubmitting = false.obs; | ||
| 13 | + | ||
| 14 | + final RxString myInviteCode = 'AC1192'.obs; | ||
| 15 | + | ||
| 16 | + @override | ||
| 17 | + void onInit() { | ||
| 18 | + super.onInit(); | ||
| 19 | + partnerIdController.addListener(() { | ||
| 20 | + partnerIdInput.value = partnerIdController.text.trim(); | ||
| 21 | + }); | ||
| 22 | + } | ||
| 23 | + | ||
| 24 | + @override | ||
| 25 | + void onClose() { | ||
| 26 | + partnerIdController.dispose(); | ||
| 27 | + super.onClose(); | ||
| 28 | + } | ||
| 29 | + | ||
| 30 | + bool get canSubmit => partnerIdInput.value.isNotEmpty; | ||
| 31 | + | ||
| 32 | + void onShareMyCode() {} | ||
| 33 | + | ||
| 34 | + Future<void> onSubmitPartnerId() async { | ||
| 35 | + if (!canSubmit || isSubmitting.value) return; | ||
| 36 | + isSubmitting.value = true; | ||
| 37 | + try { | ||
| 38 | + final userStateService = Get.find<UserStateService>(); | ||
| 39 | + final partnerId = partnerIdInput.value; | ||
| 40 | + if (!userStateService.isVip) { | ||
| 41 | + Get.offAllNamed(AppRoutes.userOnboarding, arguments: { | ||
| 42 | + 'type': "MembershipOfferPage", | ||
| 43 | + 'needBindSuccessGuide': true | ||
| 44 | + }); | ||
| 45 | + } else { | ||
| 46 | + Get.offAllNamed(AppRoutes.home); | ||
| 47 | + } | ||
| 48 | + } catch (e) { | ||
| 49 | + } finally { | ||
| 50 | + isSubmitting.value = false; | ||
| 51 | + } | ||
| 52 | + } | ||
| 53 | + | ||
| 54 | + void onSkip() { | ||
| 55 | + final userStateService = Get.find<UserStateService>(); | ||
| 56 | + if (!userStateService.isVip) { | ||
| 57 | + Get.offAllNamed(AppRoutes.userOnboarding, arguments: { | ||
| 58 | + 'type': "MembershipOfferPage", | ||
| 59 | + 'needBindSuccessGuide': false | ||
| 60 | + }); | ||
| 61 | + } else { | ||
| 62 | + Get.offAllNamed(AppRoutes.home); | ||
| 63 | + } | ||
| 64 | + } | ||
| 65 | +} |
| 1 | +import 'package:doublefeel_flutter/app/widget/dash_divider.dart'; | ||
| 2 | +import 'package:flutter/material.dart'; | ||
| 3 | +import 'package:flutter/services.dart'; | ||
| 4 | + | ||
| 5 | +import 'package:get/get.dart'; | ||
| 6 | + | ||
| 7 | +import '../../../../l10n/l10n_extensions.dart'; | ||
| 8 | +import '../controllers/bind_partner_controller.dart'; | ||
| 9 | + | ||
| 10 | +class BindPartnerView extends GetView<BindPartnerController> { | ||
| 11 | + const BindPartnerView({super.key}); | ||
| 12 | + | ||
| 13 | + @override | ||
| 14 | + Widget build(BuildContext context) { | ||
| 15 | + return Scaffold( | ||
| 16 | + backgroundColor: Colors.white, | ||
| 17 | + resizeToAvoidBottomInset: true, | ||
| 18 | + body: PopScope( | ||
| 19 | + canPop: false, | ||
| 20 | + child: Stack( | ||
| 21 | + children: [ | ||
| 22 | + _buildGradientBackground(), | ||
| 23 | + Container( | ||
| 24 | + padding: | ||
| 25 | + EdgeInsets.only(top: MediaQuery.paddingOf(context).top + 4), | ||
| 26 | + child: ListView( | ||
| 27 | + physics: const ClampingScrollPhysics(), | ||
| 28 | + children: [ | ||
| 29 | + _buildTitle(context), | ||
| 30 | + SizedBox(height: 28), | ||
| 31 | + _buildCardArea(context), | ||
| 32 | + SizedBox(height: 58), | ||
| 33 | + _buildSkipButton(context), | ||
| 34 | + ], | ||
| 35 | + ), | ||
| 36 | + ), | ||
| 37 | + Positioned( | ||
| 38 | + top: MediaQuery.paddingOf(context).top + 92, | ||
| 39 | + left: 0, | ||
| 40 | + child: Opacity( | ||
| 41 | + opacity: 0.40, | ||
| 42 | + child: Container( | ||
| 43 | + width: 133, | ||
| 44 | + height: 124, | ||
| 45 | + decoration: BoxDecoration(color: const Color(0xFFFF0000)), | ||
| 46 | + ), | ||
| 47 | + ), | ||
| 48 | + ), | ||
| 49 | + Positioned( | ||
| 50 | + top: MediaQuery.paddingOf(context).top + 532, | ||
| 51 | + right: 0, | ||
| 52 | + child: Opacity( | ||
| 53 | + opacity: 0.40, | ||
| 54 | + child: Container( | ||
| 55 | + width: 133, | ||
| 56 | + height: 124, | ||
| 57 | + decoration: BoxDecoration(color: const Color(0xFFFF0000)), | ||
| 58 | + ), | ||
| 59 | + ), | ||
| 60 | + ), | ||
| 61 | + ], | ||
| 62 | + ), | ||
| 63 | + ), | ||
| 64 | + ); | ||
| 65 | + } | ||
| 66 | + | ||
| 67 | + /// 渐变背景 | ||
| 68 | + Widget _buildGradientBackground() { | ||
| 69 | + return Positioned.fill( | ||
| 70 | + child: Container( | ||
| 71 | + decoration: const BoxDecoration( | ||
| 72 | + gradient: LinearGradient( | ||
| 73 | + begin: Alignment.topCenter, | ||
| 74 | + end: Alignment.bottomCenter, | ||
| 75 | + stops: [0.0, 0.25, 0.75, 1.0], | ||
| 76 | + colors: [ | ||
| 77 | + Color(0xFFE6DBFF), | ||
| 78 | + Color(0xFFEDE4FF), | ||
| 79 | + Color(0xFFEEE6FF), | ||
| 80 | + Color(0xFFF9F6FF), | ||
| 81 | + ], | ||
| 82 | + ), | ||
| 83 | + ), | ||
| 84 | + ), | ||
| 85 | + ); | ||
| 86 | + } | ||
| 87 | + | ||
| 88 | + /// 标题文字 | ||
| 89 | + Widget _buildTitle(BuildContext context) { | ||
| 90 | + return Padding( | ||
| 91 | + padding: EdgeInsets.symmetric(horizontal: 37), | ||
| 92 | + child: Text( | ||
| 93 | + context.l10n.bindPartnerTitle, | ||
| 94 | + textAlign: TextAlign.center, | ||
| 95 | + style: TextStyle( | ||
| 96 | + fontSize: 20, | ||
| 97 | + fontWeight: FontWeight.w600, | ||
| 98 | + color: const Color(0xFF0F0F11), | ||
| 99 | + height: 1.4, | ||
| 100 | + ), | ||
| 101 | + ), | ||
| 102 | + ); | ||
| 103 | + } | ||
| 104 | + | ||
| 105 | + Widget _buildCardArea(BuildContext context) { | ||
| 106 | + return Container( | ||
| 107 | + margin: EdgeInsets.symmetric(horizontal: 24), | ||
| 108 | + decoration: BoxDecoration( | ||
| 109 | + color: Colors.white, | ||
| 110 | + borderRadius: BorderRadius.circular(20), | ||
| 111 | + boxShadow: [ | ||
| 112 | + BoxShadow( | ||
| 113 | + color: const Color(0xFF845EEE).withValues(alpha: 0.08), | ||
| 114 | + blurRadius: 24, | ||
| 115 | + offset: const Offset(0, 8), | ||
| 116 | + ), | ||
| 117 | + ], | ||
| 118 | + ), | ||
| 119 | + child: Column( | ||
| 120 | + children: [ | ||
| 121 | + SizedBox(height: 28), | ||
| 122 | + _buildMyInfoSection(context), | ||
| 123 | + SizedBox(height: 40), | ||
| 124 | + _buildOrDivider(context), | ||
| 125 | + SizedBox(height: 28), | ||
| 126 | + _buildInputSection(context), | ||
| 127 | + SizedBox(height: 16), | ||
| 128 | + // 继续按钮 | ||
| 129 | + Container( | ||
| 130 | + padding: EdgeInsets.symmetric(horizontal: 32), | ||
| 131 | + child: Obx(() { | ||
| 132 | + return _buildPrimaryButton( | ||
| 133 | + label: context.l10n.continueButton, | ||
| 134 | + onTap: controller.onSubmitPartnerId, | ||
| 135 | + enabled: controller.canSubmit && !controller.isSubmitting.value, | ||
| 136 | + isLoading: controller.isSubmitting.value, | ||
| 137 | + primaryColor: const Color(0xFFFF9A6E), | ||
| 138 | + ); | ||
| 139 | + }), | ||
| 140 | + ), | ||
| 141 | + SizedBox(height: 40), | ||
| 142 | + ], | ||
| 143 | + ), | ||
| 144 | + ); | ||
| 145 | + } | ||
| 146 | + | ||
| 147 | + Widget _buildMyInfoSection(BuildContext context) { | ||
| 148 | + return Padding( | ||
| 149 | + padding: EdgeInsets.symmetric(horizontal: 32), | ||
| 150 | + child: Column( | ||
| 151 | + crossAxisAlignment: CrossAxisAlignment.center, | ||
| 152 | + children: [ | ||
| 153 | + // 标签 | ||
| 154 | + Text( | ||
| 155 | + context.l10n.bindPartnerMyId, | ||
| 156 | + style: TextStyle( | ||
| 157 | + fontSize: 14, | ||
| 158 | + fontWeight: FontWeight.w400, | ||
| 159 | + color: const Color(0xFF0F0F11), | ||
| 160 | + ), | ||
| 161 | + ), | ||
| 162 | + SizedBox(height: 13), | ||
| 163 | + | ||
| 164 | + Obx(() { | ||
| 165 | + return Row( | ||
| 166 | + mainAxisAlignment: MainAxisAlignment.center, | ||
| 167 | + children: [ | ||
| 168 | + Text( | ||
| 169 | + controller.myInviteCode.value, | ||
| 170 | + style: TextStyle( | ||
| 171 | + fontSize: 32, | ||
| 172 | + fontWeight: FontWeight.w600, | ||
| 173 | + color: const Color(0xFF845EEE), | ||
| 174 | + height: 1.4, | ||
| 175 | + ), | ||
| 176 | + ), | ||
| 177 | + SizedBox(width: 8), | ||
| 178 | + // 复制图标按钮 | ||
| 179 | + GestureDetector( | ||
| 180 | + onTap: () { | ||
| 181 | + Clipboard.setData( | ||
| 182 | + ClipboardData(text: controller.myInviteCode.value), | ||
| 183 | + ); | ||
| 184 | + }, | ||
| 185 | + child: Container( | ||
| 186 | + width: 20, | ||
| 187 | + height: 20, | ||
| 188 | + decoration: BoxDecoration( | ||
| 189 | + color: const Color(0xFFF0F0F6), | ||
| 190 | + borderRadius: BorderRadius.circular(6), | ||
| 191 | + ), | ||
| 192 | + child: Icon( | ||
| 193 | + Icons.copy_rounded, | ||
| 194 | + size: 12, | ||
| 195 | + color: const Color(0xFF845EEE), | ||
| 196 | + ), | ||
| 197 | + ), | ||
| 198 | + ), | ||
| 199 | + ], | ||
| 200 | + ); | ||
| 201 | + }), | ||
| 202 | + SizedBox(height: 26), | ||
| 203 | + // 分享按钮 | ||
| 204 | + _buildPrimaryButton( | ||
| 205 | + label: context.l10n.bindPartnerShareMyCode, | ||
| 206 | + onTap: controller.onShareMyCode, | ||
| 207 | + enabled: true, | ||
| 208 | + ), | ||
| 209 | + ], | ||
| 210 | + ), | ||
| 211 | + ); | ||
| 212 | + } | ||
| 213 | + | ||
| 214 | + Widget _buildOrDivider(BuildContext context) { | ||
| 215 | + return Row( | ||
| 216 | + children: [ | ||
| 217 | + Expanded( | ||
| 218 | + child: Padding( | ||
| 219 | + padding: const EdgeInsets.only(left: 27), | ||
| 220 | + child: DashedDivider(), | ||
| 221 | + ), | ||
| 222 | + ), | ||
| 223 | + Container( | ||
| 224 | + width: 36, | ||
| 225 | + height: 36, | ||
| 226 | + decoration: const BoxDecoration( | ||
| 227 | + color: Color(0xFFEDE5FF), | ||
| 228 | + shape: BoxShape.circle, | ||
| 229 | + ), | ||
| 230 | + alignment: Alignment.center, | ||
| 231 | + child: Text( | ||
| 232 | + context.l10n.bindPartnerOr, | ||
| 233 | + style: TextStyle( | ||
| 234 | + fontSize: 14, | ||
| 235 | + fontWeight: FontWeight.w400, | ||
| 236 | + color: const Color(0xFF845EEE), | ||
| 237 | + ), | ||
| 238 | + ), | ||
| 239 | + ), | ||
| 240 | + Expanded( | ||
| 241 | + child: Padding( | ||
| 242 | + padding: const EdgeInsets.only(right: 27), | ||
| 243 | + child: DashedDivider(), | ||
| 244 | + ), | ||
| 245 | + ), | ||
| 246 | + ], | ||
| 247 | + ); | ||
| 248 | + } | ||
| 249 | + | ||
| 250 | + /// 输入伙伴 ID 区域 | ||
| 251 | + Widget _buildInputSection(BuildContext context) { | ||
| 252 | + return Padding( | ||
| 253 | + padding: EdgeInsets.symmetric(horizontal: 32), | ||
| 254 | + child: Column( | ||
| 255 | + crossAxisAlignment: CrossAxisAlignment.center, | ||
| 256 | + children: [ | ||
| 257 | + // 标签 | ||
| 258 | + Text( | ||
| 259 | + context.l10n.bindPartnerContactId, | ||
| 260 | + style: TextStyle( | ||
| 261 | + fontSize: 14, | ||
| 262 | + fontWeight: FontWeight.w400, | ||
| 263 | + color: const Color(0xFF0F0F11), | ||
| 264 | + ), | ||
| 265 | + ), | ||
| 266 | + SizedBox(height: 16), | ||
| 267 | + // 输入框 | ||
| 268 | + Container( | ||
| 269 | + height: 52, | ||
| 270 | + decoration: BoxDecoration( | ||
| 271 | + color: Colors.white, | ||
| 272 | + border: Border.all(color: const Color(0xFFF0F0F6), width: 1), | ||
| 273 | + borderRadius: BorderRadius.circular(27), | ||
| 274 | + ), | ||
| 275 | + child: TextField( | ||
| 276 | + controller: controller.partnerIdController, | ||
| 277 | + textAlign: TextAlign.center, | ||
| 278 | + style: TextStyle( | ||
| 279 | + fontSize: 32, | ||
| 280 | + fontWeight: FontWeight.w400, | ||
| 281 | + color: const Color(0xFF0F0F11), | ||
| 282 | + ), | ||
| 283 | + decoration: InputDecoration( | ||
| 284 | + hintText: context.l10n.bindPartnerInputHint, | ||
| 285 | + hintStyle: TextStyle( | ||
| 286 | + fontSize: 16, | ||
| 287 | + fontWeight: FontWeight.w400, | ||
| 288 | + color: const Color(0xFFD0D0D2), | ||
| 289 | + ), | ||
| 290 | + border: InputBorder.none, | ||
| 291 | + contentPadding: EdgeInsets.symmetric(horizontal: 20), | ||
| 292 | + ), | ||
| 293 | + ), | ||
| 294 | + ), | ||
| 295 | + ], | ||
| 296 | + ), | ||
| 297 | + ); | ||
| 298 | + } | ||
| 299 | + | ||
| 300 | + /// 通用主按钮 | ||
| 301 | + Widget _buildPrimaryButton({ | ||
| 302 | + required String label, | ||
| 303 | + required VoidCallback onTap, | ||
| 304 | + bool enabled = true, | ||
| 305 | + bool isLoading = false, | ||
| 306 | + Color primaryColor = const Color(0xFF845EEE), | ||
| 307 | + }) { | ||
| 308 | + return GestureDetector( | ||
| 309 | + onTap: enabled ? onTap : null, | ||
| 310 | + child: Container( | ||
| 311 | + width: double.infinity, | ||
| 312 | + height: 40, | ||
| 313 | + decoration: BoxDecoration( | ||
| 314 | + color: enabled ? primaryColor : primaryColor.withValues(alpha: 0.3), | ||
| 315 | + borderRadius: BorderRadius.circular(100), | ||
| 316 | + ), | ||
| 317 | + alignment: Alignment.center, | ||
| 318 | + child: isLoading | ||
| 319 | + ? SizedBox( | ||
| 320 | + width: 18, | ||
| 321 | + height: 18, | ||
| 322 | + child: const CircularProgressIndicator( | ||
| 323 | + strokeWidth: 2, | ||
| 324 | + valueColor: AlwaysStoppedAnimation<Color>(Colors.white), | ||
| 325 | + ), | ||
| 326 | + ) | ||
| 327 | + : Text( | ||
| 328 | + label, | ||
| 329 | + style: TextStyle( | ||
| 330 | + fontSize: 16, | ||
| 331 | + fontWeight: FontWeight.w600, | ||
| 332 | + color: Colors.white, | ||
| 333 | + ), | ||
| 334 | + ), | ||
| 335 | + ), | ||
| 336 | + ); | ||
| 337 | + } | ||
| 338 | + | ||
| 339 | + /// 底部"下次再说"按钮 | ||
| 340 | + Widget _buildSkipButton(BuildContext context) { | ||
| 341 | + return GestureDetector( | ||
| 342 | + onTap: controller.onSkip, | ||
| 343 | + behavior: HitTestBehavior.opaque, | ||
| 344 | + child: Container( | ||
| 345 | + width: 280, | ||
| 346 | + height: 48, | ||
| 347 | + alignment: Alignment.center, | ||
| 348 | + child: Text( | ||
| 349 | + context.l10n.bindPartnerSkip, | ||
| 350 | + style: TextStyle( | ||
| 351 | + fontSize: 16, | ||
| 352 | + fontWeight: FontWeight.w600, | ||
| 353 | + color: const Color(0xFFA1A0A5), | ||
| 354 | + ), | ||
| 355 | + ), | ||
| 356 | + ), | ||
| 357 | + ); | ||
| 358 | + } | ||
| 359 | +} |
| 1 | +import 'package:get/get.dart'; | ||
| 2 | + | ||
| 3 | +import '../controllers/home_controller.dart'; | ||
| 4 | +import '../controllers/today_controller.dart'; | ||
| 5 | + | ||
| 6 | +class HomeBinding extends Bindings { | ||
| 7 | + @override | ||
| 8 | + void dependencies() { | ||
| 9 | + Get.lazyPut<HomeController>(() => HomeController(), fenix: true); | ||
| 10 | + Get.lazyPut<TodayController>(() => TodayController(), fenix: true); | ||
| 11 | + // 其他 tab 的 controller 后续在此添加 | ||
| 12 | + // Get.lazyPut<TrendController>(() => TrendController(), fenix: true); | ||
| 13 | + // Get.lazyPut<FriendsController>(() => FriendsController(), fenix: true); | ||
| 14 | + // Get.lazyPut<MyController>(() => MyController(), fenix: true); | ||
| 15 | + } | ||
| 16 | +} |
| 1 | +import 'package:doublefeel_flutter/core/services/user_state_service.dart'; | ||
| 2 | +import 'package:get/get.dart'; | ||
| 3 | + | ||
| 4 | +class HomeController extends GetxController { | ||
| 5 | + final UserStateService userStateService = Get.find<UserStateService>(); | ||
| 6 | + | ||
| 7 | + /// 当前选中的底部 tab 索引 | ||
| 8 | + final selectedIndex = 0.obs; | ||
| 9 | + | ||
| 10 | + /// 当前选中的日期(Today tab 使用) | ||
| 11 | + final selectedDate = DateTime.now().obs; | ||
| 12 | + | ||
| 13 | + void changeTab(int index) { | ||
| 14 | + selectedIndex.value = index; | ||
| 15 | + } | ||
| 16 | + | ||
| 17 | + void changeDate(DateTime date) { | ||
| 18 | + selectedDate.value = date; | ||
| 19 | + } | ||
| 20 | +} |
| 1 | +import 'package:doublefeel_flutter/core/services/user_state_service.dart'; | ||
| 2 | +import 'package:get/get.dart'; | ||
| 3 | + | ||
| 4 | +/// 每日行动 item 数据模型 | ||
| 5 | +class DailyActionItem { | ||
| 6 | + final String label; | ||
| 7 | + final String value; | ||
| 8 | + final String unit; | ||
| 9 | + final String? subValue; | ||
| 10 | + final String? subUnit; | ||
| 11 | + | ||
| 12 | + const DailyActionItem({ | ||
| 13 | + required this.label, | ||
| 14 | + required this.value, | ||
| 15 | + required this.unit, | ||
| 16 | + this.subValue, | ||
| 17 | + this.subUnit, | ||
| 18 | + }); | ||
| 19 | +} | ||
| 20 | + | ||
| 21 | +/// HRV 趋势数据点 | ||
| 22 | +class HrvDataPoint { | ||
| 23 | + final double hour; // 0.0 ~ 24.0 | ||
| 24 | + final double hrv; | ||
| 25 | + | ||
| 26 | + const HrvDataPoint({required this.hour, required this.hrv}); | ||
| 27 | +} | ||
| 28 | + | ||
| 29 | +/// HRV tooltip 标注点 | ||
| 30 | +class HrvAnnotation { | ||
| 31 | + final double hour; | ||
| 32 | + final double hrv; | ||
| 33 | + final String stateLabel; // e.g. "状态优秀" | ||
| 34 | + final String detail; // e.g. "HRV 23ms · 11:28" | ||
| 35 | + | ||
| 36 | + const HrvAnnotation({ | ||
| 37 | + required this.hour, | ||
| 38 | + required this.hrv, | ||
| 39 | + required this.stateLabel, | ||
| 40 | + required this.detail, | ||
| 41 | + }); | ||
| 42 | +} | ||
| 43 | + | ||
| 44 | +class TodayController extends GetxController { | ||
| 45 | + final UserStateService userStateService = Get.find<UserStateService>(); | ||
| 46 | + | ||
| 47 | + // ── 压力状态 ───────────────────────────── | ||
| 48 | + final stressLabel = '状态正常'.obs; | ||
| 49 | + | ||
| 50 | + // ── HRV 表盘引导 Banner ─────────────────── | ||
| 51 | + final showHrvAdBanner = true.obs; | ||
| 52 | + | ||
| 53 | + void dismissHrvAdBanner() => showHrvAdBanner.value = false; | ||
| 54 | + | ||
| 55 | + // ── HRV 数字 + 心率 ─────────────────────── | ||
| 56 | + final avgHrv = 46.obs; | ||
| 57 | + final restingHeartRate = 63.obs; | ||
| 58 | + | ||
| 59 | + // ── HRV 趋势图 ──────────────────────────── | ||
| 60 | + final List<HrvDataPoint> hrvChartData = const [ | ||
| 61 | + HrvDataPoint(hour: 0, hrv: 30), | ||
| 62 | + HrvDataPoint(hour: 1, hrv: 45), | ||
| 63 | + HrvDataPoint(hour: 2, hrv: 40), | ||
| 64 | + HrvDataPoint(hour: 3, hrv: 55), | ||
| 65 | + HrvDataPoint(hour: 4, hrv: 50), | ||
| 66 | + HrvDataPoint(hour: 5, hrv: 60), | ||
| 67 | + HrvDataPoint(hour: 6, hrv: 65), | ||
| 68 | + HrvDataPoint(hour: 7, hrv: 70), | ||
| 69 | + HrvDataPoint(hour: 8, hrv: 62), | ||
| 70 | + HrvDataPoint(hour: 9, hrv: 58), | ||
| 71 | + HrvDataPoint(hour: 10, hrv: 75), | ||
| 72 | + HrvDataPoint(hour: 11, hrv: 80), | ||
| 73 | + HrvDataPoint(hour: 12, hrv: 72), | ||
| 74 | + HrvDataPoint(hour: 13, hrv: 68), | ||
| 75 | + HrvDataPoint(hour: 14, hrv: 55), | ||
| 76 | + HrvDataPoint(hour: 15, hrv: 50), | ||
| 77 | + HrvDataPoint(hour: 16, hrv: 45), | ||
| 78 | + HrvDataPoint(hour: 17, hrv: 42), | ||
| 79 | + HrvDataPoint(hour: 18, hrv: 38), | ||
| 80 | + ]; | ||
| 81 | + | ||
| 82 | + final List<HrvAnnotation> hrvAnnotations = const [ | ||
| 83 | + HrvAnnotation( | ||
| 84 | + hour: 11, | ||
| 85 | + hrv: 80, | ||
| 86 | + stateLabel: '状态优秀', | ||
| 87 | + detail: 'HRV 23ms · 11:28', | ||
| 88 | + ), | ||
| 89 | + ]; | ||
| 90 | + | ||
| 91 | + // ── 每日行动 ────────────────────────────── | ||
| 92 | + final List<DailyActionItem> dailyActions = const [ | ||
| 93 | + DailyActionItem( | ||
| 94 | + label: '睡眠', | ||
| 95 | + value: '7', | ||
| 96 | + unit: 'h', | ||
| 97 | + subValue: '32', | ||
| 98 | + subUnit: 'min', | ||
| 99 | + ), | ||
| 100 | + DailyActionItem( | ||
| 101 | + label: '健身', | ||
| 102 | + value: '45', | ||
| 103 | + unit: 'min', | ||
| 104 | + ), | ||
| 105 | + DailyActionItem( | ||
| 106 | + label: '步数', | ||
| 107 | + value: '8,234', | ||
| 108 | + unit: '步', | ||
| 109 | + ), | ||
| 110 | + ]; | ||
| 111 | +} |
lib/app/modules/home/views/home_page.dart
0 → 100644
| 1 | +import 'package:flutter/material.dart'; | ||
| 2 | +import 'package:get/get.dart'; | ||
| 3 | + | ||
| 4 | +import '../controllers/home_controller.dart'; | ||
| 5 | +import '../widgets/df_tab_bar.dart'; | ||
| 6 | +import 'tabs/today_tab.dart'; | ||
| 7 | +import 'tabs/trend_tab.dart'; | ||
| 8 | +import 'tabs/friends_tab.dart'; | ||
| 9 | +import 'tabs/my_tab.dart'; | ||
| 10 | + | ||
| 11 | +class HomePage extends GetView<HomeController> { | ||
| 12 | + const HomePage({super.key}); | ||
| 13 | + | ||
| 14 | + static const _tabs = [ | ||
| 15 | + TodayTab(), | ||
| 16 | + TrendTab(), | ||
| 17 | + FriendsTab(), | ||
| 18 | + MyTab(), | ||
| 19 | + ]; | ||
| 20 | + | ||
| 21 | + @override | ||
| 22 | + Widget build(BuildContext context) { | ||
| 23 | + return Scaffold( | ||
| 24 | + backgroundColor: const Color(0xFFF5F2FF), | ||
| 25 | + // 不使用系统 AppBar,Today 页自带状态栏适配 | ||
| 26 | + extendBody: true, // 让内容延伸到 bottomNavigationBar 下方 | ||
| 27 | + extendBodyBehindAppBar: true, | ||
| 28 | + | ||
| 29 | + body: Obx( | ||
| 30 | + () => IndexedStack( | ||
| 31 | + index: controller.selectedIndex.value, | ||
| 32 | + children: _tabs, | ||
| 33 | + ), | ||
| 34 | + ), | ||
| 35 | + bottomNavigationBar: Obx( | ||
| 36 | + () => DfTabBar( | ||
| 37 | + selectedIndex: controller.selectedIndex.value, | ||
| 38 | + onTap: controller.changeTab, | ||
| 39 | + ), | ||
| 40 | + ), | ||
| 41 | + ); | ||
| 42 | + } | ||
| 43 | +} |
| 1 | +import 'package:flutter/material.dart'; | ||
| 2 | + | ||
| 3 | +class FriendsTab extends StatelessWidget { | ||
| 4 | + const FriendsTab({super.key}); | ||
| 5 | + | ||
| 6 | + @override | ||
| 7 | + Widget build(BuildContext context) { | ||
| 8 | + return const Center( | ||
| 9 | + child: Text('好友', style: TextStyle(fontSize: 20, color: Color(0xFF0F0F11))), | ||
| 10 | + ); | ||
| 11 | + } | ||
| 12 | +} |
-
Please register or login to post a comment