Bladeren bron

Merge branch 'v1.0.2' into v.1.1.1_ios

# Conflicts:
#	lib/data/repository/account_repository.dart
#	lib/di/get_it.config.dart
#	lib/module/character/content/character_group_content_controller.dart
#	lib/module/main/main_controller.dart
#	lib/module/store/new_discount/new_discount_controller.dart
#	lib/module/store/store_controller.dart
#	pubspec.yaml
Destiny 10 maanden geleden
bovenliggende
commit
0b140f48da
42 gewijzigde bestanden met toevoegingen van 994 en 131 verwijderingen
  1. 1 0
      android/app/agconnect-services.json
  2. 40 2
      android/app/build.gradle.kts
  3. BIN
      android/app/libs/HiPushSDK-8.0.12.307.aar
  4. BIN
      android/app/libs/com.heytap.msp_3.5.3.aar
  5. 70 1
      android/app/proguard-rules.pro
  6. 1 1
      android/app/src/main/AndroidManifest.xml
  7. 3 0
      android/app/src/main/res/values/strings.xml
  8. 16 1
      android/build.gradle.kts
  9. 1 0
      android/settings.gradle.kts
  10. BIN
      assets/images/bg_new_discount_ticket.webp
  11. BIN
      assets/images/bg_new_discount_ticket_content.webp
  12. BIN
      assets/images/bg_new_surprise_dialog.webp
  13. BIN
      assets/images/bg_new_surprise_dialog_content.webp
  14. BIN
      assets/images/icon_new_discount_banner_531.webp
  15. BIN
      assets/images/icon_new_discount_ticket_button.webp
  16. BIN
      assets/images/icon_new_discount_ticket_shade.webp
  17. BIN
      assets/images/icon_new_surprise_dialog_531.webp
  18. BIN
      assets/images/icon_new_surprise_dialog_button.webp
  19. BIN
      assets/images/icon_new_surprise_dialog_close.webp
  20. BIN
      assets/images/icon_new_surprise_dialog_hand.webp
  21. BIN
      assets/images/icon_new_surprise_dialog_only.webp
  22. BIN
      assets/images/icon_store_banner_531.webp
  23. 19 0
      lib/data/consts/build_config.dart
  24. 24 15
      lib/data/consts/constants.dart
  25. 35 25
      lib/data/repository/account_repository.dart
  26. 7 16
      lib/di/get_it.config.dart
  27. 4 2
      lib/dialog/agreement_again_dialog.dart
  28. 6 1
      lib/dialog/agreement_dialog.dart
  29. 3 0
      lib/main.dart
  30. 4 2
      lib/module/character/content/character_group_content_controller.dart
  31. 7 8
      lib/module/store/new_discount/new_discount_controller.dart
  32. 231 0
      lib/module/store/new_surprise/new_surprise_dialog.dart
  33. 213 0
      lib/module/store/new_ticket/new_discount_ticket_dialog.dart
  34. 8 5
      lib/module/store/store_controller.dart
  35. 1 1
      lib/module/zodiac_love_intimacy/zodiac_love_intimacy_page.dart
  36. 65 0
      lib/resource/assets.gen.dart
  37. 138 0
      lib/sdk/jpush/jpush_helper.dart
  38. 3 0
      plugins/keyboard_android/android/build.gradle
  39. 12 4
      plugins/keyboard_android/android/src/main/kotlin/com/atmob/keyboard_android/keyboard/InputMethodPickerActivity.kt
  40. 73 46
      plugins/keyboard_android/android/src/main/kotlin/com/atmob/keyboard_android/mvvm/viewmodel/KeyboardViewModel.kt
  41. 8 0
      pubspec.lock
  42. 1 1
      pubspec.yaml

File diff suppressed because it is too large
+ 1 - 0
android/app/agconnect-services.json


+ 40 - 2
android/app/build.gradle.kts

@@ -1,13 +1,16 @@
 import java.time.LocalDateTime
 import java.time.format.DateTimeFormatter
 import java.time.ZoneId
+
 plugins {
     id("com.android.application")
     id("kotlin-android")
     // The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins.
     id("dev.flutter.flutter-gradle-plugin")
+    id("com.huawei.agconnect")
 }
 
+
 android {
     namespace = "com.atmob.keyboard"
     compileSdk = rootProject.extra["compileSdkVersion"] as Int
@@ -32,9 +35,24 @@ android {
         versionName = flutter.versionName
 
         ndk {
-
             abiFilters.add("arm64-v8a")
         }
+
+        manifestPlaceholders.putAll(
+            mapOf(
+                "JPUSH_PKGNAME" to applicationId!!,
+                "JPUSH_APPKEY" to "e4c8b538fa1046eccce756de",
+                "JPUSH_CHANNEL" to "developer-default",
+                "XIAOMI_APPKEY" to "5652041165266",
+                "XIAOMI_APPID" to "2882303761520411266",
+                "VIVO_APPKEY" to "37b75015089824508ddc711e385a3df3",
+                "VIVO_APPID" to "105899223",
+                "OPPO_APPKEY" to "OP-2cc9d48944b440ac9480292cf80bbac5",
+                "OPPO_APPID" to "OP-33224191",
+                "OPPO_APPSECRET" to "OP-989965607b044943b8b1b610385cf404",
+                "HONOR_APPID" to "104498449",
+            )
+        )
     }
     signingConfigs {
         create("keyboard") {
@@ -82,8 +100,28 @@ android {
             }
     }
 
+    dependencies {
+
+        implementation("cn.jiguang.sdk.plugin:xiaomi:5.7.0")
+
+        implementation("cn.jiguang.sdk.plugin:vivo:5.7.0")
+
+        implementation("cn.jiguang.sdk.plugin:oppo:5.7.0")
+
+        implementation("cn.jiguang.sdk.plugin:honor:5.7.0")
+
+        implementation("com.google.code.gson:gson:2.6.2")
+        implementation("commons-codec:commons-codec:1.6")
+        implementation(fileTree(mapOf("dir" to "libs", "include" to listOf("*.jar", "*.aar"))))
+        implementation("androidx.annotation:annotation:1.1.0")
+
+        implementation ("com.huawei.hms:push:6.12.0.300")
+        implementation ("cn.jiguang.sdk.plugin:huawei:5.7.0")
+    }
+
+
 }
 
 flutter {
-    source = "../.."
+source = "../.."
 }

BIN
android/app/libs/HiPushSDK-8.0.12.307.aar


BIN
android/app/libs/com.heytap.msp_3.5.3.aar


+ 70 - 1
android/app/proguard-rules.pro

@@ -144,4 +144,73 @@ public <methods>;
 -keepattributes Signature
 -keep class com.google.gson.reflect.TypeToken { *; }
 -keep class * extends com.google.gson.reflect.TypeToken
--keepattributes AnnotationDefault,RuntimeVisibleAnnotations
+-keepattributes AnnotationDefault,RuntimeVisibleAnnotations
+
+
+# ==================================== 小米推送 ====================================
+-dontwarn com.xiaomi.push.**
+-keep class com.xiaomi.push.** { *; }
+
+# ==================================== 小米推送 end ====================================
+
+# ==================================== oppo推送 ====================================
+-dontwarn com.coloros.mcsdk.**
+-keep class com.coloros.mcsdk.** { *; }
+
+-dontwarn com.heytap.**
+-keep class com.heytap.** { *; }
+
+-dontwarn com.mcs.**
+-keep class com.mcs.** { *; }
+
+# ==================================== oppo推送 end ====================================
+
+# ==================================== vivo推送 ====================================
+-dontwarn com.vivo.push.**
+-keep class com.vivo.push.**{*; }
+-keep class com.vivo.vms.**{*; }
+
+
+# ==================================== vivo推送 end ====================================
+
+
+# ==================================== 荣耀推送 ====================================
+
+-ignorewarnings
+-keepattributes *Annotation*
+-keepattributes Exceptions
+-keepattributes InnerClasses
+-keepattributes Signature
+-keepattributes SourceFile,LineNumberTable
+-keep class com.hihonor.push.**{*;}
+
+# ==================================== 荣耀推送 end ====================================
+
+
+#====================================华为推送 start=====================================
+-ignorewarnings
+-keepattributes *Annotation*
+-keepattributes Exceptions
+-keepattributes InnerClasses
+-keepattributes Signature
+-keepattributes SourceFile,LineNumberTable
+-keep class com.hianalytics.android.**{*;}
+-keep class com.huawei.updatesdk.**{*;}
+-keep class com.huawei.hms.**{*;}
+
+#====================================华为推送 end=====================================
+
+# ==================================极光推送 start=====================================
+
+## 极光推送
+-dontoptimize
+-dontpreverify
+
+-dontwarn cn.jpush.**
+-keep class cn.jpush.** { *; }
+
+
+-dontwarn cn.jiguang.**
+-keep class cn.jiguang.** { *; }
+
+# ================================极光推送 end==========================

+ 1 - 1
android/app/src/main/AndroidManifest.xml

@@ -7,7 +7,7 @@
         android:name=".AtmobApplication"
         android:allowBackup="false"
         android:icon="@mipmap/ic_launcher"
-        android:label="追爱小键盘">
+        android:label="@string/app_name">
 
         <activity
             android:name=".MainActivity"

+ 3 - 0
android/app/src/main/res/values/strings.xml

@@ -0,0 +1,3 @@
+<resources>
+    <string name="app_name">追爱小键盘</string>
+</resources>

+ 16 - 1
android/build.gradle.kts

@@ -1,3 +1,17 @@
+buildscript {
+
+    repositories {
+        google()
+        mavenCentral()
+        maven { url = uri("https://developer.huawei.com/repo/") }
+    }
+    dependencies {
+        classpath("com.android.tools.build:gradle:8.7.0")
+        classpath("com.huawei.agconnect:agcp:1.9.1.301")
+        classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.8.22")
+    }
+}
+
 allprojects {
     extra.apply {
         set("compileSdkVersion", 35)
@@ -11,7 +25,8 @@ allprojects {
         maven {
             url = uri("https://jitpack.io")
         }
-        google()
+        maven { url = uri("https://developer.huawei.com/repo/")}
+            google()
         mavenCentral()
     }
 }

+ 1 - 0
android/settings.gradle.kts

@@ -13,6 +13,7 @@ pluginManagement {
         google()
         mavenCentral()
         gradlePluginPortal()
+        maven { url = uri("https://developer.huawei.com/repo/") }
     }
 }
 

BIN
assets/images/bg_new_discount_ticket.webp


BIN
assets/images/bg_new_discount_ticket_content.webp


BIN
assets/images/bg_new_surprise_dialog.webp


BIN
assets/images/bg_new_surprise_dialog_content.webp


BIN
assets/images/icon_new_discount_banner_531.webp


BIN
assets/images/icon_new_discount_ticket_button.webp


BIN
assets/images/icon_new_discount_ticket_shade.webp


BIN
assets/images/icon_new_surprise_dialog_531.webp


BIN
assets/images/icon_new_surprise_dialog_button.webp


BIN
assets/images/icon_new_surprise_dialog_close.webp


BIN
assets/images/icon_new_surprise_dialog_hand.webp


BIN
assets/images/icon_new_surprise_dialog_only.webp


BIN
assets/images/icon_store_banner_531.webp


+ 19 - 0
lib/data/consts/build_config.dart

@@ -39,6 +39,25 @@ final class UmengConfig {
   }
 }
 
+final class JpushConfig {
+  JpushConfig._();
+
+  //极光推送配置
+  static const jpushAndroidAppKey = "e4c8b538fa1046eccce756de";
+  // 这个不确定是不是ios
+  static const jpushIosAppKey = " e4c8b538fa1046eccce756de";
+
+  static String get jpushAppKey {
+    if (Platform.isAndroid) {
+      return jpushAndroidAppKey;
+    } else if (Platform.isIOS) {
+      return jpushIosAppKey;
+    } else {
+      return '';
+    }
+  }
+}
+
 final class GravityConfig {
   GravityConfig._();
 

+ 24 - 15
lib/data/consts/constants.dart

@@ -1,3 +1,5 @@
+import 'dart:io';
+
 import 'package:flutter/rendering.dart';
 
 import '../../utils/mmkv_util.dart';
@@ -19,17 +21,12 @@ class Constants {
 
   static const String _prodBaseUrl = "https://project-api.atmob.com";
 
-
-
-
   static String baseUrl = getBaseUrl();
 
   static bool isProdEnv() {
     return Constants.env == Constants.envProd;
   }
 
-
-
   // TTARCLW,BDARCLWXM测试用特定渠道 Android
   static const String appDefaultChannel = "TTARCLW";
   static const int appDefaultAppId = 0;
@@ -46,8 +43,9 @@ class Constants {
 
   static const String keyIsLogin = 'keyIsLogin';
   static const String keyIsMember = 'keyIsMember';
+
   //系统键盘选中的键盘
-  static const String keyboardSelect ="keyboard_select";
+  static const String keyboardSelect = "keyboard_select";
 
   // 首次进入应用
   static const String isFirstIntro = 'isFirstIntro';
@@ -56,12 +54,11 @@ class Constants {
   static const String isFirstShowKeyboardGuide = 'isFirstShowKeyboardGuide';
 
   // 是否首先显示键盘教程
-  static const String isFirstShowKeyboardTutorial = 'isFirstShowKeyboardTutorial';
+  static const String isFirstShowKeyboardTutorial =
+      'isFirstShowKeyboardTutorial';
 
   // 是否首次进入活动页
   static const String isFirstIntoDiscount = 'isFirstIntoDiscount';
-
-
 }
 
 String getBaseUrl() {
@@ -85,8 +82,6 @@ void setFirstIntro(bool isFirst) {
   KVUtil.putBool(Constants.isFirstIntro, isFirst);
 }
 
-
-
 bool isFirstIntoDiscount() {
   return KVUtil.getBool(Constants.isFirstIntoDiscount, true);
 }
@@ -95,10 +90,24 @@ void setFirstIntoDiscount(bool isFirst) {
   KVUtil.putBool(Constants.isFirstIntoDiscount, isFirst);
 }
 
-
 bool isNotHWChannel() {
-  String? channel= KVUtil.getString(Constants.appChanelName, Constants.appDefaultChannel);
-      return  channel!= "SDZAXJPHW";
+  String? channel = KVUtil.getString(
+    Constants.appChanelName,
+    Constants.appDefaultChannel,
+  );
+  return channel != "SDZAXJPHW";
 }
 
-
+String getChannelName() {
+  if (Platform.isAndroid) {
+    String? channel = KVUtil.getString(
+      Constants.appChanelName,
+      Constants.appDefaultChannel,
+    );
+    return channel!;
+  }else if (Platform.isIOS) {
+    return "Appstore";
+  } else {
+    return Constants.appDefaultChannel;
+  }
+}

+ 35 - 25
lib/data/repository/account_repository.dart

@@ -15,6 +15,7 @@ import '../../base/app_base_request.dart';
 import '../../di/get_it.dart';
 import '../../plugins/keyboard_android_platform.dart';
 import '../../sdk/gravity/gravity_helper.dart';
+import '../../sdk/jpush/jpush_helper.dart';
 import '../../utils/async_util.dart';
 import '../../utils/atmob_log.dart';
 import '../../utils/daily_limiter_util.dart';
@@ -180,31 +181,36 @@ class AccountRepository {
         .getUserInfo(AppBaseRequest())
         .then(HttpHandler.handle(true))
         .then((response) {
-      _userInfo.value = response;
-
-      if (response.loginStatus != null) {
-        if (response.loginStatus == 1) {
-          print("loginStatus == 1");
-          isLogin.value = true;
-          KVUtil.putBool(Constants.keyIsLogin, true);
-        }
-        if (response.loginStatus == 0) {
-          print("loginStatus == 0");
-          isLogin.value = false;
-
-        }
-      }
-
-      memberStatusInfo.value = response.memberInfo;
-      if (response.memberInfo != null) {
-        KVUtil.putBool(
-          Constants.keyIsMember,
-          response.memberInfo!.isMember,
-        );
-      }
-      isRequest.value = true;
-      return response;
-    });
+          _userInfo.value = response;
+
+          if (response.loginStatus != null) {
+            if (response.loginStatus == 1) {
+              print("loginStatus == 1");
+              isLogin.value = true;
+              KVUtil.putBool(Constants.keyIsLogin, true);
+            }
+            if (response.loginStatus == 0) {
+              print("loginStatus == 0");
+              isLogin.value = false;
+
+            }
+          }
+
+          memberStatusInfo.value = response.memberInfo;
+          if (response.memberInfo != null) {
+            KVUtil.putBool(
+              Constants.keyIsMember,
+              response.memberInfo!.isMember,
+            );
+          }
+          isRequest.value = true;
+          if (isLogin.value) {
+            isVipUser
+                ? JpushHelper.getInstance().setTags(tag: ["vipUser",getChannelName()])
+                : JpushHelper.getInstance().setTags(tag: ["noVipUser",getChannelName()]);
+          }
+          return response;
+        });
   }
 
   Future<void> setUserInfo({
@@ -253,6 +259,7 @@ class AccountRepository {
     keyboardRepository.refreshData();
     // 微信登录,通知键盘刷新数据
     _notifyKeyboardPluginRefreshData();
+
   }
 
   void onAppleLoginSuccess(String authToken) {
@@ -280,6 +287,9 @@ class AccountRepository {
     GravityHelper.onLogout();
     KVUtil.putString(Constants.keyboardSelect, null);
     DailyLimiterUtil.clearDailyLimitData("SurpriseDialog");
+    // 退出登录,清除极光推送的标签
+    JpushHelper.getInstance().cleanTags();
+    JpushHelper.getInstance().setTags(tag: [getChannelName()]);
     // 退出登录,通知键盘刷新数据
     _notifyKeyboardPluginRefreshData();
 

+ 7 - 16
lib/di/get_it.config.dart

@@ -108,6 +108,7 @@ import '../module/zodiac_love_intimacy/tody/zodiac_love_today_controller.dart'
 import '../module/zodiac_love_intimacy/zodiac_love_intimacy_controller.dart'
     as _i1060;
 import '../plugins/keyboard_method_handler.dart' as _i415;
+import '../sdk/jpush/jpush_helper.dart' as _i482;
 import '../utils/intimacy_analyze_config_helper.dart' as _i738;
 import '../utils/payment_status_manager.dart' as _i779;
 import '../utils/upload/upload_file_manager.dart' as _i428;
@@ -158,25 +159,15 @@ extension GetItInjectableX on _i174.GetIt {
     gh.factory<_i101.KeyboardTutorialVideoController>(
       () => _i101.KeyboardTutorialVideoController(),
     );
-    gh.factory<_i421.KeyboardTutorialVideoIosViewController>(
-      () => _i421.KeyboardTutorialVideoIosViewController(),
-    );
-    gh.factory<_i925.KeyboardTutorialVideoAndroidViewController>(
-      () => _i925.KeyboardTutorialVideoAndroidViewController(),
-    );
-    gh.factory<_i507.KeyboardTutorialController>(
-      () => _i507.KeyboardTutorialController(),
-    );
-    gh.factory<_i842.KeyboardTutorialIosViewController>(
-      () => _i842.KeyboardTutorialIosViewController(),
-    );
-    gh.factory<_i1022.KeyboardTutorialAndroidViewController>(
-      () => _i1022.KeyboardTutorialAndroidViewController(),
+    gh.factory<_i232.DeleteProfileConfirmController>(
+      () => _i232.DeleteProfileConfirmController(),
     );
+    gh.factory<_i973.SplashController>(() => _i973.SplashController());
     gh.factory<_i333.DiscountController>(() => _i333.DiscountController());
-    gh.factory<_i827.RecoverSubscribeController>(
-      () => _i827.RecoverSubscribeController(),
+    gh.factory<_i415.KeyboardMethodHandler>(
+      () => _i415.KeyboardMethodHandler(),
     );
+    gh.singleton<_i482.JpushHelper>(() => _i482.JpushHelper());
     gh.lazySingleton<_i495.WechatLoginService>(
       () => _i495.WechatLoginService(),
     );

+ 4 - 2
lib/dialog/agreement_again_dialog.dart

@@ -39,8 +39,8 @@ class AgreementAgainDialog {
 class _AgreementAgainDialog extends Dialog {
   final VoidCallback cancelClick;
   final VoidCallback sureClick;
-
-  const _AgreementAgainDialog(this.cancelClick, this.sureClick);
+  bool _isClicked = false;
+   _AgreementAgainDialog(this.cancelClick, this.sureClick);
 
   @override
   Widget build(BuildContext context) {
@@ -148,6 +148,8 @@ class _AgreementAgainDialog extends Dialog {
                 children: [
                   Expanded(
                     child: sureText(StringName.privacyAgree, () {
+                      if (_isClicked) return;
+                      _isClicked = true;
                       sureClick();
                     }),
                   ),

+ 6 - 1
lib/dialog/agreement_dialog.dart

@@ -39,7 +39,7 @@ class AgreementDialog {
 class _AgreementDialog extends Dialog {
   final VoidCallback cancelClick;
   final VoidCallback sureClick;
-
+  bool _isClicked = false;
   _AgreementDialog(this.cancelClick, this.sureClick);
 
   @override
@@ -146,6 +146,11 @@ class _AgreementDialog extends Dialog {
 
                 SizedBox(width: 16.w),
                 sureText(StringName.privacyAgree, () {
+                  if (_isClicked) {
+                    return;
+                  }
+                  _isClicked = true;
+                  AgreementDialog.dismiss();
                   sureClick();
                 }),
               ],

+ 3 - 0
lib/main.dart

@@ -14,6 +14,7 @@ import 'package:keyboard/resource/string_source.dart';
 import 'package:keyboard/router/app_pages.dart';
 import 'package:keyboard/sdk/bugly/bugly_helper.dart';
 import 'package:keyboard/sdk/gravity/gravity_helper.dart';
+import 'package:keyboard/sdk/jpush/jpush_helper.dart';
 import 'package:keyboard/utils/app_info_util.dart';
 import 'package:keyboard/utils/atmob_log.dart';
 import 'package:keyboard/utils/channel_util.dart';
@@ -92,6 +93,8 @@ class AppInitTask implements EnsurePolicyGrant {
     GravityHelper.init();
     //友盟
     UmengHelper.initCommon();
+
+    JpushHelper.getInstance().init();
   }
 }
 

+ 4 - 2
lib/module/character/content/character_group_content_controller.dart

@@ -11,6 +11,7 @@ import 'package:keyboard/data/repository/characters_repository.dart';
 import 'package:keyboard/dialog/character_details_dialog.dart';
 import 'package:keyboard/dialog/login/login_dialog.dart';
 import 'package:keyboard/module/character/character_controller.dart';
+import 'package:keyboard/module/store/new_surprise/new_surprise_dialog.dart';
 import 'package:keyboard/module/login/login_page.dart';
 import 'package:keyboard/module/store/store_page.dart';
 import 'package:keyboard/module/store/ticket/discount_ticket_dialog.dart';
@@ -30,6 +31,7 @@ import '../../../resource/assets.gen.dart';
 import '../../../utils/error_handler.dart';
 import '../../../widget/platform_util.dart';
 import '../../store/new_discount/new_discount_page.dart';
+import '../../store/new_ticket/new_discount_ticket_dialog.dart';
 import '../../store/suprise/surprise_dialog.dart';
 
 @injectable
@@ -163,7 +165,7 @@ class CharacterGroupContentController extends BaseController {
                 characterInfo.isLock == true &&
                 !isVipUser,
             onExecute: () {
-              DiscountTicketDialog.show(
+              NewDiscountTicketDialog.show(
                 clickConfirm: () {
                   NewDiscountPage.start();
                 },
@@ -178,7 +180,7 @@ class CharacterGroupContentController extends BaseController {
                 characterInfo.isLock == true &&
                 !isVipUser,
             onExecute: () {
-              SurpriseDialog.show(
+              NewSurpriseDialog.show(
                 clickConfirm: () {
                   NewDiscountPage.start();
                 },

+ 7 - 8
lib/module/store/new_discount/new_discount_controller.dart

@@ -42,8 +42,8 @@ import '../../../utils/atmob_log.dart';
 import '../../../utils/http_handler.dart';
 import '../../../utils/payment_status_manager.dart';
 import '../../../utils/toast_util.dart';
-import '../store_banner_bean.dart';
-import '../subscribe/recover_subscribe_dialog.dart';
+import '../new_surprise/new_surprise_dialog.dart';
+import '../new_ticket/new_discount_ticket_dialog.dart';
 import '../suprise/surprise_dialog.dart';
 import '../ticket/discount_ticket_dialog.dart';
 import 'new_discount_page.dart';
@@ -61,7 +61,6 @@ class NewDiscountController extends BaseController
 
   final PaymentStatusManager paymentStatusManager;
 
-
   RxList<GoodsInfo> get goodsInfoList =>
       storeRepository.newDiscountGoodsInfoList;
 
@@ -102,7 +101,7 @@ class NewDiscountController extends BaseController
 
   /// 轮播图控制器
   final List<AssetGenImage> bannerList = [
-    Assets.images.iconNewDiscountBanner1,
+    Assets.images.iconNewDiscountBanner531,
 
     Assets.images.iconNewDiscountBanner2,
 
@@ -555,16 +554,16 @@ class NewDiscountController extends BaseController
     _storeDataFuture?.cancel();
     paymentStatusManager.unregisterPaymentSuccessCallback(this);
     if (!isFirstIntoDiscount() && !accountRepository.isVipUser) {
-      if (PlatformUtil.isAndroid) {
-        SurpriseDialog.show(
+      if (Platform.isAndroid) {
+        NewSurpriseDialog.show(
           clickConfirm: () {
             NewDiscountPage.start();
           },
           clickCancel: () {},
         );
       }
-      if (PlatformUtil.isIOS) {
-        DiscountTicketDialog.show(
+      if (Platform.isIOS) {
+        NewDiscountTicketDialog.show(
           clickConfirm: () {
             NewDiscountPage.start();
           },

+ 231 - 0
lib/module/store/new_surprise/new_surprise_dialog.dart

@@ -0,0 +1,231 @@
+import 'dart:ui';
+
+import 'package:flutter/Material.dart';
+import 'package:flutter/cupertino.dart';
+import 'package:flutter_screenutil/flutter_screenutil.dart';
+import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
+import 'package:get/get.dart';
+import 'package:keyboard/module/store/suprise/goods_surprise_controller.dart';
+import '../../../data/consts/constants.dart';
+import '../../../data/consts/event_report.dart';
+import '../../../handler/event_handler.dart';
+import '../../../resource/assets.gen.dart';
+import '../../../resource/colors.gen.dart';
+import '../../../resource/string.gen.dart';
+import '../../../widget/horizontal_dashed_line.dart';
+
+class NewSurpriseDialog {
+  static const String tag = 'NewSurpriseDialog';
+
+  static void show({VoidCallback? clickConfirm, VoidCallback? clickCancel}) {
+    EventHandler.report(EventId.event_02009);
+    if (SmartDialog.checkExist(tag: tag)) return;
+    SmartDialog.show(
+      tag: tag,
+      keepSingle: true,
+      backType: SmartBackType.block,
+      clickMaskDismiss: false,
+      maskColor: ColorName.black70,
+      onDismiss: () => Get.delete<GoodsSurpriseController>(),
+      animationType: SmartAnimationType.centerScale_otherSlide,
+      builder: (_) {
+        final controller = Get.find<GoodsSurpriseController>();
+        return Column(
+          crossAxisAlignment: CrossAxisAlignment.center,
+          mainAxisAlignment: MainAxisAlignment.start,
+          children: [
+            SizedBox(height: 243.h),
+            Stack(
+              clipBehavior: Clip.none,
+              children: [
+                Positioned(
+                  top: -153.h,
+                  child: Assets.images.iconNewSurpriseDialog531.image(
+                    width: 318.w,
+                    height: 183.h,
+                    fit: BoxFit.contain,
+                  ),
+                ),
+                Assets.images.bgNewSurpriseDialog.image(width: 351.w),
+                Positioned(
+                  left: 0,
+                  right: 0,
+                  child: Column(
+                    children: [
+                      Assets.images.iconNewSurpriseDialogOnly.image(
+                        width: 178.32.w,
+                        height: 69.31.h,
+                      ),
+                      SizedBox(height: 7.2.h),
+                      Container(
+                        width: 240.w,
+                        height: 108.h,
+                        decoration: BoxDecoration(
+                          image: DecorationImage(
+                            image:
+                                Assets.images.bgNewSurpriseDialogContent
+                                    .provider(),
+                            fit: BoxFit.contain,
+                          ),
+                        ),
+                        child: Column(
+                          mainAxisAlignment: MainAxisAlignment.center,
+                          crossAxisAlignment: CrossAxisAlignment.center,
+                          children: [
+                            SizedBox(height: 15.h),
+                            Obx(() {
+                              return _buildPricesPartOne(controller);
+                            }),
+                            HorizontalDashedLine(
+                              width: 200.w,
+                              color: Color(0xFFFFA0AE),
+                              strokeWidth: 2.h,
+                              dashLength: 5.w,
+                              dashSpace: 3.w,
+                            ),
+                            SizedBox(height: 5.h),
+                            Obx(() {
+                              return Text(
+                                controller.firstAmount?.description ?? "",
+                                style: TextStyle(
+                                  color: const Color(0xFFFFF2F4),
+                                  fontSize: 10.sp,
+                                  fontWeight: FontWeight.w400,
+                                  height: 2,
+                                ),
+                              );
+                            }),
+                          ],
+                        ),
+                      ),
+                      SizedBox(height: 7.86.h),
+                      GestureDetector(
+                        onTap: () {
+                          EventHandler.report(EventId.event_02010);
+                          clickConfirm?.call();
+                          SmartDialog.dismiss(tag: tag);
+                        },
+                        child: SizedBox(
+                          width: 240.w,
+                          height: 60.h,
+                          child: SizedBox(
+                            child: Assets.images.iconNewSurpriseDialogButton
+                                .image(width: 240.w, height: 60.h),
+                          ),
+                        ),
+                      ),
+                    ],
+                  ),
+                ),
+                Positioned(
+                  right: 20.w,
+                  bottom: -5.h,
+                  child: IgnorePointer(
+                    child: Assets.images.iconNewSurpriseDialogHand.image(
+                      width: 78.w,
+                      height: 79.h,
+                    ),
+                  ),
+                ),
+              ],
+            ),
+
+            SizedBox(height: 26.h),
+            GestureDetector(
+              onTap: () {
+                EventHandler.report(EventId.event_02011);
+                SmartDialog.dismiss(tag: tag);
+                clickCancel?.call();
+              },
+              child: Assets.images.iconNewSurpriseDialogClose.image(
+                width: 40.r,
+                height: 40.r,
+              ),
+            ),
+          ],
+        );
+      },
+    );
+  }
+
+  static Widget _buildPricesPartOne(GoodsSurpriseController controller) {
+    return Stack(
+      children: [
+        Row(
+          mainAxisAlignment: MainAxisAlignment.center,
+          crossAxisAlignment: CrossAxisAlignment.center,
+          children: [
+            Text(
+              controller.firstAmount?.priceDescNumber ?? "",
+              style: TextStyle(
+                color: Colors.white,
+                fontSize: 42.sp,
+                fontWeight: FontWeight.w900,
+                height: 0,
+              ),
+            ),
+            Column(
+              children: [
+                Container(
+                  width: 30.w,
+                  height: 18.h,
+                  decoration: BoxDecoration(
+                    image: DecorationImage(
+                      image: Assets.images.iconSurpriseDialogOnly.provider(),
+                      fit: BoxFit.cover,
+                    ),
+                  ),
+                  child: Center(
+                    child: Text(
+                      StringName.surpriseDialogOnly,
+                      style: TextStyle(
+                        color: const Color(0xFFFF451D),
+                        fontSize: 11.sp,
+                        fontWeight: FontWeight.w500,
+                      ),
+                    ),
+                  ),
+                ),
+                Text(
+                  controller.firstAmount?.priceDescUnit ?? '',
+                  style: TextStyle(
+                    color: Colors.white,
+                    fontSize: 14.sp,
+                    fontWeight: FontWeight.w700,
+                  ),
+                ),
+              ],
+            ),
+          ],
+        ),
+        Positioned(
+          top: 5.r,
+          left: 47.30.w,
+          child: Container(
+            padding: EdgeInsets.symmetric(horizontal: 2.w),
+            transform:
+                Matrix4.identity()
+                  ..translate(0.0, 0.0)
+                  ..rotateZ(-0.41),
+            decoration: ShapeDecoration(
+              color: const Color(0xFFD8FF1E),
+              shape: RoundedRectangleBorder(
+                borderRadius: BorderRadius.circular(3.r),
+              ),
+            ),
+            child: Text(
+              controller.firstAmount?.name ?? "",
+              textAlign: TextAlign.center,
+              style: TextStyle(
+                color: const Color(0xFF231815),
+                fontSize: 12.sp,
+                fontWeight: FontWeight.w700,
+                letterSpacing: -0.36,
+              ),
+            ),
+          ),
+        ),
+      ],
+    );
+  }
+}

+ 213 - 0
lib/module/store/new_ticket/new_discount_ticket_dialog.dart

@@ -0,0 +1,213 @@
+import 'dart:ui';
+
+import 'package:flutter/Material.dart';
+import 'package:flutter_screenutil/flutter_screenutil.dart';
+import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
+import 'package:get/get.dart';
+import '../../../data/consts/event_report.dart';
+import '../../../handler/event_handler.dart';
+import '../../../resource/assets.gen.dart';
+import '../../../resource/colors.gen.dart';
+import '../suprise/goods_surprise_controller.dart';
+
+class NewDiscountTicketDialog {
+  static const String tag = 'NewDiscountTicketDialog';
+
+  static void show({VoidCallback? clickConfirm, VoidCallback? clickCancel}) {
+    EventHandler.report(EventId.event_02006);
+    if (SmartDialog.checkExist(tag: tag)) return;
+    SmartDialog.show(
+      tag: tag,
+      keepSingle: true,
+      backType: SmartBackType.block,
+      clickMaskDismiss: false,
+      maskColor: ColorName.black70,
+      onDismiss: () => Get.delete<GoodsSurpriseController>(),
+      animationType: SmartAnimationType.centerScale_otherSlide,
+      builder: (_) {
+        final controller = Get.find<GoodsSurpriseController>();
+        return Column(
+          crossAxisAlignment: CrossAxisAlignment.center,
+          mainAxisAlignment: MainAxisAlignment.start,
+          children: [
+            SizedBox(height: 50.h),
+            Stack(
+              clipBehavior: Clip.none,
+              children: [
+                Container(
+                  width: 360.w,
+                  height: 567.h,
+                  decoration: BoxDecoration(
+                    image: DecorationImage(
+                      image: Assets.images.bgNewDiscountTicket.provider(),
+                      fit: BoxFit.contain,
+                    ),
+                  ),
+                  child: Column(
+                    children: [
+                      SizedBox(height: 305.h),
+                      Container(
+                        width: 240.w,
+                        height: 119.h,
+                        decoration: BoxDecoration(
+                          image: DecorationImage(
+                            image:
+                                Assets.images.bgNewDiscountTicketContent
+                                    .provider(),
+                            fit: BoxFit.contain,
+                          ),
+                        ),
+                        child: Column(
+                          mainAxisAlignment: MainAxisAlignment.start,
+                          crossAxisAlignment: CrossAxisAlignment.center,
+                          children: [
+                            SizedBox(height: 3.h),
+                            Obx(() {
+                              return Container(
+                                padding: EdgeInsets.symmetric(
+                                  horizontal: 10.w,
+                                  vertical: 2.h,
+                                ),
+                                decoration: BoxDecoration(
+                                  color: Color(0xFFFFE1D9),
+                                  borderRadius: BorderRadius.only(
+                                    bottomLeft: Radius.circular(10.r),
+                                    bottomRight: Radius.circular(10.r),
+                                  ),
+                                ),
+                                child: Text(
+                                  controller.secondAmount?.name ?? '',
+                                  style: TextStyle(
+                                    color: const Color(0xFFFF2F79),
+                                    fontSize: 13.sp,
+                                    fontWeight: FontWeight.w500,
+                                  ),
+                                ),
+                              );
+                            }),
+                            SizedBox(height: 10.h,),
+                            Row(
+                              mainAxisAlignment: MainAxisAlignment.center,
+                              crossAxisAlignment: CrossAxisAlignment.end,
+                              children: [
+                                Stack(
+                                  clipBehavior: Clip.none,
+                                  children: [
+                                    Obx(() {
+                                      return Text(
+                                        controller.secondAmount?.amountText ??
+                                            "",
+                                        style: TextStyle(
+                                          color: const Color(0xFFFF005A),
+                                          fontSize: 42.sp,
+                                          fontWeight: FontWeight.w900,
+
+                                          height: 0,
+                                        ),
+                                      );
+                                    }),
+                                    Positioned(
+                                      bottom: 5.h,
+                                      right: -12.w,
+                                      child: _unit(),
+                                    ),
+                                  ],
+                                ),
+                              ],
+                            ),
+                            Obx(() {
+                              return Text(
+                                controller.secondAmount?.description ?? "",
+                                style: TextStyle(
+                                  color: const Color(0xFFEA8AAC),
+                                  fontSize: 12.sp,
+                                  fontWeight: FontWeight.w400,
+                                ),
+                              );
+                            }),
+                          ],
+                        ),
+                      ),
+                      SizedBox(height: 18.h),
+                      GestureDetector(
+                        onTap: () {
+                          EventHandler.report(EventId.event_02010);
+                          clickConfirm?.call();
+                          SmartDialog.dismiss(tag: tag);
+                        },
+                        child: SizedBox(
+                          width: 240.w,
+                          height: 60.h,
+                          child: SizedBox(
+                            child: Assets.images.iconNewDiscountTicketButton
+                                .image(
+                                  width: 260.w,
+                                  height: 50.h,
+                                  fit: BoxFit.contain,
+                                ),
+                          ),
+                        ),
+                      ),
+                    ],
+                  ),
+                ),
+                Positioned(
+                  right: 25.w,
+                  bottom: 20.h,
+                  child: IgnorePointer(
+                    child: Assets.images.iconNewSurpriseDialogHand.image(
+                      width: 78.w,
+                      height: 79.h,
+                    ),
+                  ),
+                ),
+              ],
+            ),
+            Transform.translate(
+              offset: Offset(0, -20.h),
+              child: GestureDetector(
+                onTap: () {
+                  EventHandler.report(EventId.event_02011);
+                  SmartDialog.dismiss(tag: tag);
+                  clickCancel?.call();
+                },
+                child: Assets.images.iconNewSurpriseDialogClose.image(
+                  width: 40.r,
+                  height: 40.r,
+                ),
+              ),
+            ),
+          ],
+        );
+      },
+    );
+  }
+
+  static Widget _unit() {
+    return Container(
+      width: 20.w,
+      height: 20.w,
+      decoration: ShapeDecoration(
+        color: const Color(0xFFFF005A),
+        shape: OvalBorder(
+          side: BorderSide(
+            width: 2.w,
+            strokeAlign: BorderSide.strokeAlignCenter,
+            color: Colors.white,
+          ),
+        ),
+      ),
+      child: Center(
+        child: Text(
+          '元',
+          style: TextStyle(
+            color: Colors.white,
+            fontSize: 12.sp,
+            fontWeight: FontWeight.w700,
+            height: 1.67,
+          ),
+        ),
+      ),
+    );
+  }
+}

+ 8 - 5
lib/module/store/store_controller.dart

@@ -50,6 +50,8 @@ import '../../utils/http_handler.dart';
 import '../../utils/payment_status_manager.dart';
 import '../../utils/toast_util.dart';
 import '../login/login_page.dart';
+import 'new_surprise/new_surprise_dialog.dart';
+import 'new_ticket/new_discount_ticket_dialog.dart';
 
 @injectable
 class StoreController extends BaseController implements PaymentStatusCallback {
@@ -97,7 +99,7 @@ class StoreController extends BaseController implements PaymentStatusCallback {
 
   final List<StoreBannerBean> bannerList = [
     StoreBannerBean(
-      banner: Assets.images.iconStoreBanner1,
+      banner: Assets.images.iconStoreBanner531,
       indicatorImg: Assets.images.iconStoreIndicator1,
       unSelectedDesc: "定制人设",
     ),
@@ -227,6 +229,7 @@ class StoreController extends BaseController implements PaymentStatusCallback {
   }
 
   void clickBack() {
+
     EventHandler.report(EventId.event_02005);
     Get.back();
   }
@@ -541,16 +544,16 @@ class StoreController extends BaseController implements PaymentStatusCallback {
     if (memberStatusInfo != null && memberStatusInfo!.isMember) {
       return;
     }
-    if (PlatformUtil.isAndroid) {
-      SurpriseDialog.show(
+    if (Platform.isAndroid) {
+      NewSurpriseDialog.show(
         clickConfirm: () {
           NewDiscountPage.start();
         },
         clickCancel: () {},
       );
     }
-    if (PlatformUtil.isIOS) {
-      DiscountTicketDialog.show(
+    if (Platform.isIOS) {
+      NewDiscountTicketDialog.show(
         clickConfirm: () {
           NewDiscountPage.start();
         },

+ 1 - 1
lib/module/zodiac_love_intimacy/zodiac_love_intimacy_page.dart

@@ -153,7 +153,7 @@ class ZodiacLoveIntimacyPage extends BasePage<ZodiacLoveIntimacyController> {
             Positioned(
               left: 0,
               right: 0,
-              top: 6.h,
+              top: 8.h,
               child: Container(
                 height: 41.h,
                 // 顶部2边圆角

+ 65 - 0
lib/resource/assets.gen.dart

@@ -273,6 +273,22 @@ class $AssetsImagesGen {
   AssetGenImage get bgNewDiscountItemUnselect =>
       const AssetGenImage('assets/images/bg_new_discount_item_unselect.webp');
 
+  /// File path: assets/images/bg_new_discount_ticket.webp
+  AssetGenImage get bgNewDiscountTicket =>
+      const AssetGenImage('assets/images/bg_new_discount_ticket.webp');
+
+  /// File path: assets/images/bg_new_discount_ticket_content.webp
+  AssetGenImage get bgNewDiscountTicketContent =>
+      const AssetGenImage('assets/images/bg_new_discount_ticket_content.webp');
+
+  /// File path: assets/images/bg_new_surprise_dialog.webp
+  AssetGenImage get bgNewSurpriseDialog =>
+      const AssetGenImage('assets/images/bg_new_surprise_dialog.webp');
+
+  /// File path: assets/images/bg_new_surprise_dialog_content.webp
+  AssetGenImage get bgNewSurpriseDialogContent =>
+      const AssetGenImage('assets/images/bg_new_surprise_dialog_content.webp');
+
   /// File path: assets/images/bg_new_user_result.webp
   AssetGenImage get bgNewUserResult =>
       const AssetGenImage('assets/images/bg_new_user_result.webp');
@@ -989,6 +1005,10 @@ class $AssetsImagesGen {
   AssetGenImage get iconNewDiscountBanner3 =>
       const AssetGenImage('assets/images/icon_new_discount_banner_3.webp');
 
+  /// File path: assets/images/icon_new_discount_banner_531.webp
+  AssetGenImage get iconNewDiscountBanner531 =>
+      const AssetGenImage('assets/images/icon_new_discount_banner_531.webp');
+
   /// File path: assets/images/icon_new_discount_character_title.webp
   AssetGenImage get iconNewDiscountCharacterTitle => const AssetGenImage(
     'assets/images/icon_new_discount_character_title.webp',
@@ -1028,6 +1048,34 @@ class $AssetsImagesGen {
     'assets/images/icon_new_discount_membership_card_title.webp',
   );
 
+  /// File path: assets/images/icon_new_discount_ticket_button.webp
+  AssetGenImage get iconNewDiscountTicketButton =>
+      const AssetGenImage('assets/images/icon_new_discount_ticket_button.webp');
+
+  /// File path: assets/images/icon_new_discount_ticket_shade.webp
+  AssetGenImage get iconNewDiscountTicketShade =>
+      const AssetGenImage('assets/images/icon_new_discount_ticket_shade.webp');
+
+  /// File path: assets/images/icon_new_surprise_dialog_531.webp
+  AssetGenImage get iconNewSurpriseDialog531 =>
+      const AssetGenImage('assets/images/icon_new_surprise_dialog_531.webp');
+
+  /// File path: assets/images/icon_new_surprise_dialog_button.webp
+  AssetGenImage get iconNewSurpriseDialogButton =>
+      const AssetGenImage('assets/images/icon_new_surprise_dialog_button.webp');
+
+  /// File path: assets/images/icon_new_surprise_dialog_close.webp
+  AssetGenImage get iconNewSurpriseDialogClose =>
+      const AssetGenImage('assets/images/icon_new_surprise_dialog_close.webp');
+
+  /// File path: assets/images/icon_new_surprise_dialog_hand.webp
+  AssetGenImage get iconNewSurpriseDialogHand =>
+      const AssetGenImage('assets/images/icon_new_surprise_dialog_hand.webp');
+
+  /// File path: assets/images/icon_new_surprise_dialog_only.webp
+  AssetGenImage get iconNewSurpriseDialogOnly =>
+      const AssetGenImage('assets/images/icon_new_surprise_dialog_only.webp');
+
   /// File path: assets/images/icon_new_user_birthday_logo.webp
   AssetGenImage get iconNewUserBirthdayLogo =>
       const AssetGenImage('assets/images/icon_new_user_birthday_logo.webp');
@@ -1145,6 +1193,10 @@ class $AssetsImagesGen {
   AssetGenImage get iconStoreBanner3 =>
       const AssetGenImage('assets/images/icon_store_banner3.webp');
 
+  /// File path: assets/images/icon_store_banner_531.webp
+  AssetGenImage get iconStoreBanner531 =>
+      const AssetGenImage('assets/images/icon_store_banner_531.webp');
+
   /// File path: assets/images/icon_store_divider.webp
   AssetGenImage get iconStoreDivider =>
       const AssetGenImage('assets/images/icon_store_divider.webp');
@@ -1392,6 +1444,10 @@ class $AssetsImagesGen {
     bgMineVipCard,
     bgNewDiscountItemSelect,
     bgNewDiscountItemUnselect,
+    bgNewDiscountTicket,
+    bgNewDiscountTicketContent,
+    bgNewSurpriseDialog,
+    bgNewSurpriseDialogContent,
     bgNewUserResult,
     bgNewUserResultIntimacy,
     bgProfileEditIntimacy,
@@ -1560,6 +1616,7 @@ class $AssetsImagesGen {
     iconNewDiscountBanner1,
     iconNewDiscountBanner2,
     iconNewDiscountBanner3,
+    iconNewDiscountBanner531,
     iconNewDiscountCharacterTitle,
     iconNewDiscountItemSelect,
     iconNewDiscountMembershipCard1,
@@ -1568,6 +1625,13 @@ class $AssetsImagesGen {
     iconNewDiscountMembershipCard4,
     iconNewDiscountMembershipCard5,
     iconNewDiscountMembershipCardTitle,
+    iconNewDiscountTicketButton,
+    iconNewDiscountTicketShade,
+    iconNewSurpriseDialog531,
+    iconNewSurpriseDialogButton,
+    iconNewSurpriseDialogClose,
+    iconNewSurpriseDialogHand,
+    iconNewSurpriseDialogOnly,
     iconNewUserBirthdayLogo,
     iconNewUserOpenNow,
     iconNewUserResultLoveLeft,
@@ -1597,6 +1661,7 @@ class $AssetsImagesGen {
     iconStoreBanner1,
     iconStoreBanner2,
     iconStoreBanner3,
+    iconStoreBanner531,
     iconStoreDivider,
     iconStoreGoodsNormalSymbolIos,
     iconStoreGoodsSelectedSymbolIos,

+ 138 - 0
lib/sdk/jpush/jpush_helper.dart

@@ -0,0 +1,138 @@
+import 'dart:io';
+import 'package:get/get.dart';
+import 'package:flutter/services.dart';
+import 'package:injectable/injectable.dart';
+import 'package:jpush_flutter/jpush_flutter.dart';
+import 'package:jpush_flutter/jpush_interface.dart';
+import 'package:keyboard/module/store/new_discount/new_discount_page.dart';
+import 'package:keyboard/utils/atmob_log.dart';
+
+import '../../data/consts/build_config.dart';
+import '../../data/consts/constants.dart';
+import '../../di/get_it.dart';
+import '../../module/main/main_controller.dart';
+import '../../router/app_pages.dart';
+
+@singleton
+class JpushHelper {
+  static const String tag = "qqq JpushHelper";
+  static String registrationId = "";
+
+  static final JPushFlutterInterface _jpush = JPush.newJPush();
+
+  JpushHelper();
+
+  // Platform messages are asynchronous, so we initialize in an async method.
+  Future<void> init() async {
+    String? platformVersion;
+    AtmobLog.d(tag, "flutter init JPushHelper");
+    print("qqq flutter init JPushHelper");
+    try {
+      _jpush.addEventHandler(
+        onReceiveNotification: (Map<String, dynamic> message) async {
+          AtmobLog.d(tag, "flutter onReceiveNotification: $message");
+
+
+        },
+        onOpenNotification: (Map<String, dynamic> message) async {
+          AtmobLog.d(tag, "flutter onOpenNotification: $message");
+          if (Get.isRegistered<MainController>() &&
+              Get.currentRoute != RoutePath.newDiscount) {
+            NewDiscountPage.start();
+          }
+          //清除应用图标角标数量
+          _jpush.setBadge(-1);
+        },
+        onReceiveMessage: (Map<String, dynamic> message) async {
+          AtmobLog.d(tag, "flutter onReceiveMessage: $message");
+        },
+        onReceiveNotificationAuthorization: (
+          Map<String, dynamic> message,
+        ) async {
+          AtmobLog.d(
+            tag,
+            "flutter onReceiveNotificationAuthorization: $message",
+          );
+        },
+        onNotifyMessageUnShow: (Map<String, dynamic> message) async {
+          AtmobLog.d(tag, "flutter onNotifyMessageUnShow: $message");
+        },
+        onInAppMessageShow: (Map<String, dynamic> message) async {
+          AtmobLog.d(tag, "flutter onInAppMessageShow: $message");
+        },
+        onCommandResult: (Map<String, dynamic> message) async {
+          AtmobLog.d(tag, "flutter onCommandResult: $message");
+        },
+        onInAppMessageClick: (Map<String, dynamic> message) async {
+          AtmobLog.d(tag, "flutter onInAppMessageClick: $message");
+        },
+        onConnected: (Map<String, dynamic> message) async {
+          AtmobLog.d(tag, "flutter onConnected: $message");
+        },
+      );
+    } on PlatformException {
+      platformVersion = 'Failed to get platform version.';
+    }
+    _jpush.enableAutoWakeup(enable: true);
+    _jpush.setAuth(enable: true);
+    _jpush.setup(
+      appKey: JpushConfig.jpushAppKey,
+      channel: getChannelName(),
+      production: false,
+      debug: BuildConfig.isDebug,
+    );
+    _jpush.applyPushAuthority(
+      new NotificationSettingsIOS(sound: true, alert: true, badge: true),
+    );
+
+    // Platform messages may fail, so we use a try/catch PlatformException.
+    _jpush.getRegistrationID().then((rid) {
+      AtmobLog.d(tag, "极光id get registration id : $rid");
+      print("qqq 极光id get registration id : $rid");
+
+      registrationId = rid;
+    });
+
+    if (Platform.isIOS) {
+      // iOS要是使用应用内消息,请在页面进入离开的时候配置pageEnterTo 和  pageLeave 函数,参数为页面名。
+      // _jpush.pageEnterTo("HomePage");
+    }
+    isNotificationEnabled().then((hasPermission) {
+      AtmobLog.d(
+        "JpushHelper",
+        ("flutter isNotificationEnabled: $hasPermission"),
+      );
+      if (hasPermission) {
+        return;
+      } else {
+        requestRequiredPermission();
+      }
+    });
+  }
+
+  Future<void> setTags({required List<String> tag}) async {
+    _jpush.setTags(tag).then((result) {
+      AtmobLog.d("JpushHelper", ("flutter setTags: $result"));
+    });
+  }
+
+  Future<void> cleanTags() async {
+    _jpush.cleanTags().then((result) {
+      AtmobLog.d("JpushHelper", ("flutter cleanTags: $result"));
+    });
+  }
+
+  Future<bool> isNotificationEnabled() async {
+    return _jpush.isNotificationEnabled();
+  }
+
+  void requestRequiredPermission() {
+    _jpush.requestRequiredPermission();
+  }
+
+  void openSettingsForNotification() {
+    _jpush.openSettingsForNotification();
+  }
+
+  static JpushHelper getInstance() => getIt.get<JpushHelper>();
+}

+ 3 - 0
plugins/keyboard_android/android/build.gradle

@@ -85,6 +85,9 @@ android {
         // 让Service支持Jetpack Lifecycle组件
         implementation "androidx.lifecycle:lifecycle-service:2.6.1"
 
+        // App前后台判断
+        implementation  "androidx.lifecycle:lifecycle-process:2.8.7"
+
         // Retrofit
         implementation('com.squareup.retrofit2:retrofit:2.9.0')
         implementation('com.squareup.retrofit2:converter-gson:2.9.0')

+ 12 - 4
plugins/keyboard_android/android/src/main/kotlin/com/atmob/keyboard_android/keyboard/InputMethodPickerActivity.kt

@@ -7,6 +7,8 @@ import android.content.Intent
 import android.os.Bundle
 import android.os.Handler
 import android.os.Looper
+import androidx.lifecycle.Lifecycle
+import androidx.lifecycle.ProcessLifecycleOwner
 import com.atmob.keyboard_android.util.InputMethodUtil
 import com.atmob.keyboard_android.util.LogUtil
 
@@ -23,10 +25,16 @@ class InputMethodPickerActivity : Activity() {
          * 启动
          */
         fun start(context: Context) {
-            val intent = Intent(context, InputMethodPickerActivity::class.java)
-            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS)
-            val options = ActivityOptions.makeCustomAnimation(context, 0, 0)
-            context.startActivity(intent, options.toBundle())
+            // App在前台,直接显示输入法选择弹窗,如果统一都用透明Activity来处理,在平板下的小窗模式中,会导致透明Activity显示为小窗
+            if (ProcessLifecycleOwner.get().lifecycle.currentState == Lifecycle.State.RESUMED) {
+                InputMethodUtil.showInputMethodPicker(context)
+            } else {
+                // 在后台,使用一个透明的Activity来触发输入法选择器
+                val intent = Intent(context, InputMethodPickerActivity::class.java)
+                intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS)
+                val options = ActivityOptions.makeCustomAnimation(context, 0, 0)
+                context.startActivity(intent, options.toBundle())
+            }
         }
     }
 

+ 73 - 46
plugins/keyboard_android/android/src/main/kotlin/com/atmob/keyboard_android/mvvm/viewmodel/KeyboardViewModel.kt

@@ -2,6 +2,8 @@ package com.atmob.keyboard_android.mvvm.viewmodel
 
 import androidx.lifecycle.LiveData
 import androidx.lifecycle.MutableLiveData
+import androidx.lifecycle.asLiveData
+import androidx.lifecycle.viewModelScope
 import com.atmob.keyboard_android.enums.HelpMode
 import com.atmob.keyboard_android.enums.KeyboardGlobalType
 import com.atmob.keyboard_android.enums.KeyboardType
@@ -16,6 +18,7 @@ import com.atmob.keyboard_android.util.bridge.model.resp.KeyboardInfo
 import com.atmob.keyboard_android.util.bridge.model.resp.PrologueListResp.PrologueListItem
 import com.atmob.keyboard_android.util.bridge.model.resp.PrologueListResp.Topic
 import com.atmob.keyboard_android.util.error.ErrorHandler
+import kotlinx.coroutines.flow.MutableStateFlow
 import kotlinx.coroutines.flow.single
 
 /**
@@ -32,50 +35,57 @@ class KeyboardViewModel : BaseViewModel() {
     /**
      * 登录页,是否展示
      */
-    private val _loginPageShowing = MutableLiveData(false)
-    val loginPageShowing: LiveData<Boolean> = _loginPageShowing
+    private val _loginPageShowing = MutableStateFlow(false)
+    val loginPageShowing: LiveData<Boolean> =
+        _loginPageShowing.asLiveData(viewModelScope.coroutineContext)
 
     /**
      * 设置页,是否展示
      */
-    private val _settingPageShowing = MutableLiveData(false)
-    val settingPageShowing: LiveData<Boolean> = _settingPageShowing
+    private val _settingPageShowing = MutableStateFlow(false)
+    val settingPageShowing: LiveData<Boolean> =
+        _settingPageShowing.asLiveData(viewModelScope.coroutineContext)
 
     /**
      * VIP页,是否显示
      */
-    private val _vipPageShowing = MutableLiveData(false)
-    val vipPageShowing: LiveData<Boolean> = _vipPageShowing
+    private val _vipPageShowing = MutableStateFlow(false)
+    val vipPageShowing: LiveData<Boolean> =
+        _vipPageShowing.asLiveData(viewModelScope.coroutineContext)
 
     /**
      * 键盘选择页,是否显示
      */
-    private val _keyboardSelectPageShowing = MutableLiveData(false)
-    val keyboardSelectPageShowing: LiveData<Boolean> = _keyboardSelectPageShowing
+    private val _keyboardSelectPageShowing = MutableStateFlow(false)
+    val keyboardSelectPageShowing: LiveData<Boolean> =
+        _keyboardSelectPageShowing.asLiveData(viewModelScope.coroutineContext)
 
     /**
      * 超会说-Ai生成内容页,是否显示
      */
-    private val _superSpeakAiChatPageShowing = MutableLiveData(false)
-    val superSpeakAiChatPageShowing: LiveData<Boolean> = _superSpeakAiChatPageShowing
+    private val _superSpeakAiChatPageShowing = MutableStateFlow(false)
+    val superSpeakAiChatPageShowing: LiveData<Boolean> =
+        _superSpeakAiChatPageShowing.asLiveData(viewModelScope.coroutineContext)
 
     /**
      * 开场白-Ai生成内容页,是否显示
      */
-    private val _prologueAiChatPageShowing = MutableLiveData(false)
-    val prologueAiChatPageShowing: LiveData<Boolean> = _prologueAiChatPageShowing
+    private val _prologueAiChatPageShowing = MutableStateFlow(false)
+    val prologueAiChatPageShowing: LiveData<Boolean> =
+        _prologueAiChatPageShowing.asLiveData(viewModelScope.coroutineContext)
 
     /**
      * 帮助模式,帮聊、教你说、开场白等
      */
-    private val _helpMode = MutableLiveData(HelpMode.HELP_CHAT)
-    val helpMode: LiveData<HelpMode> = _helpMode
+    private val _helpMode = MutableStateFlow(HelpMode.HELP_CHAT)
+    val helpMode: LiveData<HelpMode> = _helpMode.asLiveData(viewModelScope.coroutineContext)
 
     /**
      * 全局键盘类型
      */
-    private val _keyboardGlobalType = MutableLiveData(KeyboardGlobalType.AI_KEYBOARD)
-    val keyboardGlobalType: LiveData<KeyboardGlobalType> = _keyboardGlobalType
+    private val _keyboardGlobalType = MutableStateFlow(KeyboardGlobalType.AI_KEYBOARD)
+    val keyboardGlobalType: LiveData<KeyboardGlobalType> =
+        _keyboardGlobalType.asLiveData(viewModelScope.coroutineContext)
 
     /**
      * 当前键盘信息
@@ -92,45 +102,52 @@ class KeyboardViewModel : BaseViewModel() {
     /**
      * 人设列表
      */
-    private val _characterList = MutableLiveData<List<CharacterInfo>>()
-    val characterList: LiveData<List<CharacterInfo>> = _characterList
+    private val _characterList = MutableStateFlow<List<CharacterInfo>>(listOf())
+    val characterList: LiveData<List<CharacterInfo>> =
+        _characterList.asLiveData(viewModelScope.coroutineContext)
 
     /**
      * 开场白列表
      */
     private val _prologueList =
-        MutableLiveData<List<PrologueListItem>>()
-    val prologueList: LiveData<List<PrologueListItem>> = _prologueList
+        MutableStateFlow<List<PrologueListItem>>(listOf())
+    val prologueList: LiveData<List<PrologueListItem>> =
+        _prologueList.asLiveData(viewModelScope.coroutineContext)
 
     /**
      * AI聊天-超会回(帮聊)结果
      */
-    private val _chatSuperReplyResult = MutableLiveData<String>()
-    val chatSuperReplyResult: LiveData<String> = _chatSuperReplyResult
+    private val _chatSuperReplyResult = MutableStateFlow<String>("")
+    val chatSuperReplyResult: LiveData<String> =
+        _chatSuperReplyResult.asLiveData(viewModelScope.coroutineContext)
 
     /**
      * AI聊天-超会说(教你说)结果
      */
-    private val _superSpeakChatListResult = MutableLiveData<List<String>>()
-    val superSpeakChatListResult: LiveData<List<String>> = _superSpeakChatListResult
+    private val _superSpeakChatListResult = MutableStateFlow<List<String>>(listOf())
+    val superSpeakChatListResult: LiveData<List<String>> =
+        _superSpeakChatListResult.asLiveData(viewModelScope.coroutineContext)
 
     /**
      * AI聊天-开场白结果
      */
-    private val _prologueChatListResult = MutableLiveData<List<String>>()
-    val prologueChatListResult: LiveData<List<String>> = _prologueChatListResult
+    private val _prologueChatListResult = MutableStateFlow<List<String>>(listOf())
+    val prologueChatListResult: LiveData<List<String>> =
+        _prologueChatListResult.asLiveData(viewModelScope.coroutineContext)
 
     /**
      * 用户的剪切板数据
      */
-    private val _userClipboardData = MutableLiveData("")
-    val userClipboardData: LiveData<String> = _userClipboardData
+    private val _userClipboardData = MutableStateFlow("")
+    val userClipboardData: LiveData<String> =
+        _userClipboardData.asLiveData(viewModelScope.coroutineContext)
 
     /**
      * 键盘选择列表数据
      */
-    private val _keyboardList = MutableLiveData<List<KeyboardInfo>>()
-    val keyboardList: LiveData<List<KeyboardInfo>> = _keyboardList
+    private val _keyboardList = MutableStateFlow<List<KeyboardInfo>>(listOf())
+    val keyboardList: LiveData<List<KeyboardInfo>> =
+        _keyboardList.asLiveData(viewModelScope.coroutineContext)
 
     // ----------------------------------- 更新状态方法 -----------------------------------
 
@@ -250,21 +267,33 @@ class KeyboardViewModel : BaseViewModel() {
         } else {
             val infos = resp.data?.keyboardInfos ?: mutableListOf<KeyboardInfo>()
             val keyboardList = infos.map {
+                // 用户未手动选择过键盘,但服务端记录选择过,先认为未选中,下面的fix函数,会以isChoose字段来赋值isSelect字段
+                // 用来解决选中了系统键盘,但服务端那边记录的值也是选中,导致2个都选中的问题
+                if (it.isSelect == null && it.isChoose == true) {
+                    it.isSelect = false
+                }
+                it
+            }.map {
                 fixKeyboardSelectField(it)
             }.toList()
+
+            // 找到系统键盘
+            val systemKeyboardList = infos.filter {
+                KeyboardType.isSystem(it.type ?: "")
+            }.toList()
+            val systemKeyboard = if (systemKeyboardList.isNotEmpty()) {
+                systemKeyboardList.first()
+            } else {
+                null
+            }
+
             // 如果所有都没选中,则默认选中通用键盘
             val hasSelectKeyboard = keyboardList.filter {
                 it.isSelect == true
             }.toList().isNotEmpty()
+            // 勾选默认键盘
             if (!hasSelectKeyboard) {
-                // 找到系统键盘
-                val systemKeyboard = infos.filter {
-                    KeyboardType.isSystem(it.type ?: "")
-                }.toList()
-                // 勾选默认键盘
-                if (systemKeyboard.isNotEmpty()) {
-                    systemKeyboard.first().isSelect = true
-                }
+                systemKeyboard?.isSelect = true
             }
             _keyboardList.value = infos
         }
@@ -358,7 +387,7 @@ class KeyboardViewModel : BaseViewModel() {
      */
     fun filterPrologueListByTab(tab: String): List<Topic> {
         // 按照选择Tab,过滤出对应Tab的开场白数据
-        val tabPrologues = _prologueList.value?.firstOrNull {
+        val tabPrologues = _prologueList.value.firstOrNull {
             it.title == tab
         }
         // 该Tab下的开场白列表
@@ -382,7 +411,7 @@ class KeyboardViewModel : BaseViewModel() {
                 // 人设Id
                 characterId = characterId,
                 // 用户粘贴板中的内容
-                content = _userClipboardData.value ?: ""
+                content = _userClipboardData.value
             )
             _chatSuperReplyResult.value = ""
             launch {
@@ -434,7 +463,7 @@ class KeyboardViewModel : BaseViewModel() {
                 // 人设Id
                 characterId = characterId,
                 // 用户粘贴板中的内容
-                content = _userClipboardData.value ?: ""
+                content = _userClipboardData.value
             )
             launch {
                 val resp = mKeyboardRepository.chatSuperSpeak(req).single()
@@ -555,11 +584,9 @@ class KeyboardViewModel : BaseViewModel() {
      * 处理isSelect字段
      */
     private fun fixKeyboardSelectField(info: KeyboardInfo): KeyboardInfo {
-        // 统一使用isSelect字段,优先使用isSelect字段,代表是用户手动在键盘中操作过的,否则就用isChoose,是其他页面中选择过的
-        info.isSelect = if (info.isSelect != null) {
-            info.isSelect == true
-        } else {
-            info.isChoose == true
+        // 如果isSelect字段为null,则使用isChoose字段来赋值
+        if (info.isSelect == null) {
+            info.isSelect = info.isChoose == true
         }
         return info
     }

+ 8 - 0
pubspec.lock

@@ -875,6 +875,14 @@ packages:
       url: "https://pub.dev"
     source: hosted
     version: "1.0.5"
+  jpush_flutter:
+    dependency: "direct main"
+    description:
+      name: jpush_flutter
+      sha256: "309ffd60169cb7ea78810026eac30a3a6b98a41f66cdef31cb63d6930486b48e"
+      url: "https://pub.dev"
+    source: hosted
+    version: "3.2.7"
   js:
     dependency: transitive
     description:

+ 1 - 1
pubspec.yaml

@@ -104,7 +104,7 @@ dependencies:
   # 基于video_player的封装库,能自定义UI
   chewie: ^1.11.3
 
-
+  jpush_flutter: ^3.2.7
 
   #QR
   qr_flutter: ^4.1.0