Commit 1ac8d16e07f6b87e47859d6b26724461890332aa

Authored by 常守达
0 parents

init

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.

  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
  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'
  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.
  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
  1 +gradle-wrapper.jar
  2 +/.gradle
  3 +/captures/
  4 +/gradlew
  5 +/gradlew.bat
  6 +/local.properties
  7 +GeneratedPluginRegistrant.java
  8 +
  9 +# Remember to never publicly share your keystore.
  10 +# See https://flutter.dev/to/reference-keystore
  11 +key.properties
  12 +**/*.keystore
  13 +**/*.jks
  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"}}]}
  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 +}
  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>
  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>
  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>
  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 +}
  1 +org.gradle.jvmargs=-Xmx4G -XX:MaxMetaspaceSize=2G -XX:+HeapDumpOnOutOfMemoryError
  2 +android.useAndroidX=true
  3 +android.enableJetifier=true
  1 +distributionBase=GRADLE_USER_HOME
  2 +distributionPath=wrapper/dists
  3 +zipStoreBase=GRADLE_USER_HOME
  4 +zipStorePath=wrapper/dists
  5 +distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-all.zip
  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"
No preview for this file type
  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>
  1 +targets:
  2 + $default:
  3 + builders:
  4 + json_serializable:
  5 + options:
  6 + explicit_to_json: true
  7 + include_if_null: false
  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
  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>
  1 +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
  2 +#include "Generated.xcconfig"
  1 +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
  2 +#include "Generated.xcconfig"
  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
  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
  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 +<Workspace
  3 + version = "1.0">
  4 + <FileRef
  5 + location = "self:">
  6 + </FileRef>
  7 +</Workspace>
  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>IDEDidComputeMac32BitWarning</key>
  6 + <true/>
  7 +</dict>
  8 +</plist>
  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>PreviewsEnabled</key>
  6 + <false/>
  7 +</dict>
  8 +</plist>
  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>
  1 +<?xml version="1.0" encoding="UTF-8"?>
  2 +<Workspace
  3 + version = "1.0">
  4 + <FileRef
  5 + location = "group:Runner.xcodeproj">
  6 + </FileRef>
  7 + <FileRef
  8 + location = "group:Pods/Pods.xcodeproj">
  9 + </FileRef>
  10 +</Workspace>
  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>IDEDidComputeMac32BitWarning</key>
  6 + <true/>
  7 +</dict>
  8 +</plist>
  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>PreviewsEnabled</key>
  6 + <false/>
  7 +</dict>
  8 +</plist>
  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 +}
  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 +}
  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>
  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>
  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>
  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 +}
  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 +}
  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 +}
  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 +}
  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 +}
  1 +#import "GeneratedPluginRegistrant.h"
  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 +}
  1 +arb-dir: lib/l10n
  2 +template-arb-file: app_zh.arb
  3 +output-class: AppLocalizations
  4 +output-dir: lib/l10n/gen
  5 +output-localization-file: app_localizations.dart
  6 +source-language: zh
  7 +synthetic-package: false
  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 +}
  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 +}
  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 +}
  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:get/get.dart';
  2 +
  3 +import '../controllers/bind_partner_controller.dart';
  4 +
  5 +class BindPartnerBinding extends Bindings {
  6 + @override
  7 + void dependencies() {
  8 + Get.put(BindPartnerController());
  9 + }
  10 +}
  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 +}
  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 +}