咸光金 vor 4 Jahren
Commit
5958a5dfe6
100 geänderte Dateien mit 6360 neuen und 0 gelöschten Zeilen
  1. 9 0
      .gitignore
  2. 1 0
      alipay/.gitignore
  3. BIN
      alipay/aars/alipaySdk-15.7.9-20200727142846.aar
  4. 51 0
      alipay/build.gradle
  5. 0 0
      alipay/consumer-rules.pro
  6. 21 0
      alipay/proguard-rules.pro
  7. 3 0
      alipay/src/main/AndroidManifest.xml
  8. 26 0
      alipay/src/main/java/com/ysnows/alipay/cc/CpAlipay.kt
  9. 1 0
      alipay/src/main/java/com/ysnows/alipay/model/PayResult.java
  10. 1 0
      app/.gitignore
  11. 124 0
      app/build.gradle
  12. BIN
      app/libs/open_ad_sdk.aar
  13. 335 0
      app/proguard-rules.pro
  14. 227 0
      app/src/main/AndroidManifest.xml
  15. 68 0
      app/src/main/java/com/ysnows/sultra/App.java
  16. 36 0
      app/src/main/java/com/ysnows/sultra/C/Api.java
  17. 14 0
      app/src/main/java/com/ysnows/sultra/C/C.java
  18. 48 0
      app/src/main/java/com/ysnows/sultra/RoundSearchWidget.kt
  19. 148 0
      app/src/main/java/com/ysnows/sultra/T9View.java
  20. 59 0
      app/src/main/java/com/ysnows/sultra/activity/AboutActivity.kt
  21. 33 0
      app/src/main/java/com/ysnows/sultra/activity/AddFuncActivity.kt
  22. 76 0
      app/src/main/java/com/ysnows/sultra/activity/AddSearchEngineActivity.kt
  23. 44 0
      app/src/main/java/com/ysnows/sultra/activity/CheckPermissionsActivity.kt
  24. 121 0
      app/src/main/java/com/ysnows/sultra/activity/FuncShopActivity.kt
  25. 27 0
      app/src/main/java/com/ysnows/sultra/activity/LoginActivity.kt
  26. 151 0
      app/src/main/java/com/ysnows/sultra/activity/MainActivity.kt
  27. 80 0
      app/src/main/java/com/ysnows/sultra/activity/PrivateCenterActivity.kt
  28. 25 0
      app/src/main/java/com/ysnows/sultra/activity/RegisterActivity.kt
  29. 38 0
      app/src/main/java/com/ysnows/sultra/activity/SearchEngineShopActivity.kt
  30. 189 0
      app/src/main/java/com/ysnows/sultra/activity/SettingsActivity.kt
  31. 76 0
      app/src/main/java/com/ysnows/sultra/activity/SplashActivity.kt
  32. 48 0
      app/src/main/java/com/ysnows/sultra/activity/TodosActivity.kt
  33. 199 0
      app/src/main/java/com/ysnows/sultra/activity/TranslateActivity.kt
  34. 80 0
      app/src/main/java/com/ysnows/sultra/activity/VipBuyActivity.kt
  35. 25 0
      app/src/main/java/com/ysnows/sultra/activity/WebViewActivity.kt
  36. 18 0
      app/src/main/java/com/ysnows/sultra/adapter/AddFuncAdapter.kt
  37. 35 0
      app/src/main/java/com/ysnows/sultra/adapter/AddSearchEngineAdapter.kt
  38. 63 0
      app/src/main/java/com/ysnows/sultra/adapter/AppAdapter.kt
  39. 99 0
      app/src/main/java/com/ysnows/sultra/adapter/AppsAdapter.java
  40. 41 0
      app/src/main/java/com/ysnows/sultra/adapter/FuncAdapter.kt
  41. 25 0
      app/src/main/java/com/ysnows/sultra/adapter/FuncShopAdapter.kt
  42. 23 0
      app/src/main/java/com/ysnows/sultra/adapter/SearchBarAdapter.kt
  43. 21 0
      app/src/main/java/com/ysnows/sultra/adapter/ShopSearchEnginesAdapter.kt
  44. 126 0
      app/src/main/java/com/ysnows/sultra/adapter/ShortCutAdapter.java
  45. 39 0
      app/src/main/java/com/ysnows/sultra/adapter/TodosAdapter.java
  46. 31 0
      app/src/main/java/com/ysnows/sultra/adapter/WebAppAdapter.java
  47. 28 0
      app/src/main/java/com/ysnows/sultra/base/MBActivity.kt
  48. 28 0
      app/src/main/java/com/ysnows/sultra/base/MBFragment.kt
  49. 30 0
      app/src/main/java/com/ysnows/sultra/base/MBRActivity.kt
  50. 31 0
      app/src/main/java/com/ysnows/sultra/base/MBRFragment.kt
  51. 100 0
      app/src/main/java/com/ysnows/sultra/binder/FuncBinder.kt
  52. 47 0
      app/src/main/java/com/ysnows/sultra/component/CpApp.kt
  53. 45 0
      app/src/main/java/com/ysnows/sultra/config/Config.kt
  54. 23 0
      app/src/main/java/com/ysnows/sultra/config/ConfigFuncType.kt
  55. 9 0
      app/src/main/java/com/ysnows/sultra/config/ConfigMMKV.kt
  56. 7 0
      app/src/main/java/com/ysnows/sultra/config/ConfigPayWay.kt
  57. 15 0
      app/src/main/java/com/ysnows/sultra/config/ConfigRx.kt
  58. 9 0
      app/src/main/java/com/ysnows/sultra/config/ConfigVipType.kt
  59. 5 0
      app/src/main/java/com/ysnows/sultra/config/MIntentAction.kt
  60. 39 0
      app/src/main/java/com/ysnows/sultra/fragment/AppsFragment.kt
  61. 43 0
      app/src/main/java/com/ysnows/sultra/fragment/ShopFuncQuikFragment.kt
  62. 216 0
      app/src/main/java/com/ysnows/sultra/fragment/WebFragment.kt
  63. 82 0
      app/src/main/java/com/ysnows/sultra/model/AppModel.java
  64. 50 0
      app/src/main/java/com/ysnows/sultra/model/AppSetting.java
  65. 9 0
      app/src/main/java/com/ysnows/sultra/model/BBDCSearch.java
  66. 13 0
      app/src/main/java/com/ysnows/sultra/model/CMD.java
  67. 17 0
      app/src/main/java/com/ysnows/sultra/model/ChargeCat.java
  68. 51 0
      app/src/main/java/com/ysnows/sultra/model/City.java
  69. 122 0
      app/src/main/java/com/ysnows/sultra/model/Contact.java
  70. 190 0
      app/src/main/java/com/ysnows/sultra/model/Func.java
  71. 11 0
      app/src/main/java/com/ysnows/sultra/model/LocalApiModel.java
  72. 9 0
      app/src/main/java/com/ysnows/sultra/model/MultiItem.java
  73. 19 0
      app/src/main/java/com/ysnows/sultra/model/Payway.java
  74. 13 0
      app/src/main/java/com/ysnows/sultra/model/Restore.java
  75. 176 0
      app/src/main/java/com/ysnows/sultra/model/SearchEngine.java
  76. 88 0
      app/src/main/java/com/ysnows/sultra/model/ShortCutModel.java
  77. 113 0
      app/src/main/java/com/ysnows/sultra/model/Suggestion.java
  78. 12 0
      app/src/main/java/com/ysnows/sultra/model/Todo.java
  79. 120 0
      app/src/main/java/com/ysnows/sultra/model/User.java
  80. 143 0
      app/src/main/java/com/ysnows/sultra/model/Weather.java
  81. 8 0
      app/src/main/java/com/ysnows/sultra/model/bbdc/Word.kt
  82. 5 0
      app/src/main/java/com/ysnows/sultra/model/bbdc/WordList.kt
  83. 44 0
      app/src/main/java/com/ysnows/sultra/receiver/ActionBroadcastReceiver.java
  84. 41 0
      app/src/main/java/com/ysnows/sultra/receiver/AppListReceiver.java
  85. 183 0
      app/src/main/java/com/ysnows/sultra/receiver/AssistantService.kt
  86. 121 0
      app/src/main/java/com/ysnows/sultra/receiver/ClipBoardListenService.java
  87. 50 0
      app/src/main/java/com/ysnows/sultra/receiver/FuncReceiver.java
  88. 72 0
      app/src/main/java/com/ysnows/sultra/receiver/ShortCutReceiver.java
  89. 247 0
      app/src/main/java/com/ysnows/sultra/receiver/WindowViewReceiver.java
  90. 34 0
      app/src/main/java/com/ysnows/sultra/repository/LoginRepository.kt
  91. 46 0
      app/src/main/java/com/ysnows/sultra/repository/MainPresenter.java
  92. 65 0
      app/src/main/java/com/ysnows/sultra/repository/RegisterRepository.kt
  93. 22 0
      app/src/main/java/com/ysnows/sultra/repository/SearchRepository.kt
  94. 26 0
      app/src/main/java/com/ysnows/sultra/repository/UserInfoRepository.kt
  95. 73 0
      app/src/main/java/com/ysnows/sultra/utils/CheckUtil.java
  96. 191 0
      app/src/main/java/com/ysnows/sultra/utils/CustomTabActivityHelper.java
  97. 5 0
      app/src/main/java/com/ysnows/sultra/utils/DownloadCallBack.java
  98. 144 0
      app/src/main/java/com/ysnows/sultra/utils/FileUtils.java
  99. 99 0
      app/src/main/java/com/ysnows/sultra/utils/FlashUtils.java
  100. 66 0
      app/src/main/java/com/ysnows/sultra/utils/IntentUtils.java

+ 9 - 0
.gitignore

@@ -0,0 +1,9 @@
+*.iml
+.gradle
+/local.properties
+.idea/
+.DS_Store
+/build
+/captures
+.externalNativeBuild
+app/release/

+ 1 - 0
alipay/.gitignore

@@ -0,0 +1 @@
+/build

BIN
alipay/aars/alipaySdk-15.7.9-20200727142846.aar


+ 51 - 0
alipay/build.gradle

@@ -0,0 +1,51 @@
+apply from: rootProject.file('cc-settings.gradle')
+apply from: rootProject.file('common-build.gradle')
+
+
+android {
+    compileSdkVersion rootProject.compile_sdk_version
+
+    defaultConfig {
+        minSdkVersion rootProject.min_sdk_version
+        targetSdkVersion rootProject.target_sdk_version
+        versionCode rootProject.application_version_code
+        versionName rootProject.application_version_name
+    }
+
+    buildTypes {
+        release {
+            minifyEnabled false
+            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
+        }
+    }
+
+    compileOptions {
+        targetCompatibility 1.8
+        sourceCompatibility 1.8
+    }
+
+    kotlinOptions {
+        jvmTarget = '1.8'
+    }
+
+
+    android.buildFeatures {
+        dataBinding = false
+        viewBinding = false
+    }
+
+}
+
+repositories {
+    flatDir {
+        dirs 'aars'
+    }
+}
+
+dependencies {
+
+    implementation files('aars/alipaySdk-15.7.9-20200727142846.aar')
+    implementation project(':base')
+
+
+}

+ 0 - 0
alipay/consumer-rules.pro


+ 21 - 0
alipay/proguard-rules.pro

@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+#   http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+#   public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile

+ 3 - 0
alipay/src/main/AndroidManifest.xml

@@ -0,0 +1,3 @@
+<manifest package="com.ysnows.alipay" >
+
+</manifest >

+ 26 - 0
alipay/src/main/java/com/ysnows/alipay/cc/CpAlipay.kt

@@ -0,0 +1,26 @@
+package com.ysnows.alipay.cc
+
+import android.app.Activity
+import com.alipay.sdk.app.PayTask
+import com.billy.cc.core.component.CC
+import com.billy.cc.core.component.CCResult
+import com.billy.cc.core.component.IComponent
+import com.ysnows.base.ccextension.BIComponent
+
+open class CpAlipay : IComponent, BIComponent() {
+
+    fun pay(cc: CC, orderInfo: String?): Boolean {
+
+        val runnable = Runnable {
+            val alipay = PayTask(cc.context as Activity?)
+            val result = alipay.payV2(orderInfo, true)
+
+            CC.sendCCResult(cc.callId, CCResult.success("result", result))
+        }
+
+        Thread(runnable).start()
+
+        return true
+    }
+
+}

+ 1 - 0
alipay/src/main/java/com/ysnows/alipay/model/PayResult.java

@@ -0,0 +1 @@
+package com.ysnows.alipay.model;

import android.text.TextUtils;

import java.util.Map;

public class PayResult {
    private String resultStatus;
    private String result;
    private String memo;

    public PayResult(Map<String, String> rawResult) {
        if (rawResult == null) {
            return;
        }

        for (String key : rawResult.keySet()) {
            if (TextUtils.equals(key, "resultStatus")) {
                resultStatus = rawResult.get(key);
            } else if (TextUtils.equals(key, "result")) {
                result = rawResult.get(key);
            } else if (TextUtils.equals(key, "memo")) {
                memo = rawResult.get(key);
            }
        }
    }

    @Override
    public String toString() {
        return "resultStatus={" + resultStatus + "};memo={" + memo
                + "};result={" + result + "}";
    }

    /**
     * @return the resultStatus
     */
    public String getResultStatus() {
        return resultStatus;
    }

    /**
     * @return the memo
     */
    public String getMemo() {
        return memo;
    }

    /**
     * @return the result
     */
    public String getResult() {
        return result;
    }
}

+ 1 - 0
app/.gitignore

@@ -0,0 +1 @@
+/build

+ 124 - 0
app/build.gradle

@@ -0,0 +1,124 @@
+ext.mainApp = true  //设置为true,表示此module为主app module,一直以application方式编译
+apply from: rootProject.file('cc-settings.gradle')
+apply from: rootProject.file('common-build.gradle')
+
+android {
+    compileSdkVersion rootProject.compile_sdk_version
+
+    defaultConfig {
+        applicationId rootProject.application_id
+        minSdkVersion rootProject.min_sdk_version
+        targetSdkVersion rootProject.target_sdk_version
+        versionCode rootProject.application_version_code
+        versionName rootProject.application_version_name
+
+        ndk {
+            //选择要添加的对应 cpu 类型的 .so 库。
+            abiFilters 'armeabi-v7a'
+            // 还可以添加 'x86', 'x86_64', 'mips', 'mips64'
+        }
+    }
+
+    signingConfigs {
+
+//        release {
+//            keyAlias "sultra"
+//            keyPassword "123"
+//            storeFile file("../demo.jks")
+//            storePassword "Sultra@31314"
+//            v2SigningEnabled true
+//        }
+    }
+
+    buildTypes {
+        debug {
+//            signingConfig signingConfigs.release
+            versionNameSuffix "-" + name
+
+
+        }
+        release {
+            debuggable false
+            minifyEnabled true
+            zipAlignEnabled true
+            shrinkResources true
+            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
+            signingConfig signingConfigs.release
+        }
+
+
+    }
+
+    //指定release APK名称
+    applicationVariants.all { variant ->
+        variant.outputs.all {
+            // 输出apk名称为 1.0_vivo.apk
+            def fileName = "${variant.productFlavors[0].name}_${defaultConfig.versionName}.apk"
+            outputFileName = fileName
+        }
+    }
+
+    flavorDimensions "version"
+    //指定渠道
+    productFlavors {
+        dev {}
+        vivo {}
+        oppo {}
+        huawei {}
+        xiaomi {}
+        coolapk {}
+        yingyongbao {}
+    }
+
+    // 批量渠道包值替换
+
+    //通过脚本获取所有渠道
+    //在Terminal控制台输入gradlew assembleRelease开始打包
+    //包生成在build-->outputs-->apk文件夹
+    productFlavors.all {
+            //        遍历替换所有渠道
+        flavor -> flavor.manifestPlaceholders = [UMENG_CHANNEL: name]
+    }
+//
+    //Terminal窗口输入
+    //打包wandoujia渠道的release版本,执行如下命令
+    //    gradlew assembleWandoujiaRelease
+    //打包wandoujia渠道的debug版本,执行如下命令
+    //    gradlew assembleWandoujiaDebug
+    // 只打wandoujia渠道版会生成wandoujia渠道的Release和Debug版本
+    //    gradlew assembleWandoujia
+    //打全部Release版本
+    //    gradlew assembleRelease
+
+
+    compileOptions {
+        targetCompatibility 1.8
+        sourceCompatibility 1.8
+    }
+
+    kotlinOptions {
+        jvmTarget = '1.8'
+    }
+
+
+    android.buildFeatures {
+        dataBinding = true
+        viewBinding = false
+    }
+
+}
+
+dependencies {
+
+    implementation 'androidx.browser:browser:1.2.0'
+    implementation 'com.github.promeg:tinypinyin-lexicons-android-cncity:2.0.3'
+    implementation 'com.google.android.material:material:1.2.1'
+
+//    implementation(name: 'open_ad_sdk', ext: 'aar')
+    implementation files('libs/open_ad_sdk.aar')
+    implementation project(':base')
+    addComponent 'alipay'
+    addComponent 'update'
+    addComponent 'umeng'
+
+}

BIN
app/libs/open_ad_sdk.aar


+ 335 - 0
app/proguard-rules.pro

@@ -0,0 +1,335 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+#   http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+#   public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
+
+
+-ignorewarnings
+
+## GSON 2.2.4 specific rules ##
+
+# Gson uses generic type information stored in a class file when working with fields. Proguard
+# removes such information by default, so configure it to keep all of it.
+-keepattributes Signature
+
+# For using GSON @Expose annotation
+-keepattributes *Annotation*
+
+-keepattributes EnclosingMethod
+
+# Gson specific classes
+-keep class sun.misc.Unsafe { *; }
+-keep class com.google.gson.stream.** { *; }
+
+
+-keep public class * implements com.bumptech.glide.module.GlideModule
+-keep public class * extends com.bumptech.glide.module.AppGlideModule
+-keep public enum com.bumptech.glide.load.ImageHeaderParser$** {
+  **[] $VALUES;
+  public *;
+}
+
+
+# Keep the support library
+-keep class android.support.** { *; }
+-keep interface android.support.** { *; }
+
+
+# Okio
+-keep class sun.misc.Unsafe { *; }
+-dontwarn java.nio.file.*
+-dontwarn org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement
+-dontwarn okio.**
+-dontwarn okio.** -dontnote retrofit2.Platform -dontwarn retrofit2.Platform$Java8 -keepattributes Signature -keepattributes Exceptions -keep class com.myownpackage.models.** { *; }
+-dontwarn org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement
+
+########--------Retrofit + RxJava--------#########
+-dontwarn retrofit.**
+-keep class retrofit.** { *; }
+-dontwarn sun.misc.Unsafe
+-dontwarn com.octo.android.robospice.retrofit.RetrofitJackson**
+-dontwarn retrofit.appengine.UrlFetchClient
+-keepattributes Signature
+-keepattributes Exceptions
+-keepclasseswithmembers class * {
+    @retrofit.http.* <methods>;
+}
+-keep class com.google.gson.** { *; }
+-keep class com.google.inject.** { *; }
+-keep class org.apache.http.** { *; }
+-keep class org.apache.james.mime4j.** { *; }
+-keep class javax.inject.** { *; }
+-keep class retrofit.** { *; }
+-dontwarn org.apache.http.**
+-dontwarn android.net.http.AndroidHttpClient
+-dontwarn retrofit.**
+
+-dontwarn sun.misc.**
+
+-keepclassmembers class rx.internal.util.unsafe.*ArrayQueue*Field* {
+   long producerIndex;
+   long consumerIndex;
+}
+
+-keepclassmembers class rx.internal.util.unsafe.BaseLinkedQueueProducerNodeRef {
+   long producerNode;
+   long consumerNode;
+}
+
+
+# ALSO REMEMBER KEEPING YOUR MODEL CLASSES
+-keep class com.ysnows.sultra.model.** { *; }
+-keep class com.ysnows.sultra.utils.net.Response { *; }
+-keep class com.ysnows.base.model.** { *; }
+-keep class com.ysnows.base.route.** { *; }
+-keep class com.ysnows.update.model.** { *; }
+
+-keep class com.ysnows.umeng.cc.** { *; }
+-keep class com.ysnows.alipay.cc.** { *; }
+-keep class com.ysnows.update.component.** { *; }
+
+
+
+#Retrofit
+-dontwarn retrofit2.**
+-keep class retrofit2.** { *; }
+-keepattributes Signature
+-keepattributes Exceptions
+
+-keepclasseswithmembers class * {
+    @retrofit2.http.* <methods>;
+}
+
+
+#RxJava RxAndroid
+-dontwarn sun.misc.**
+-keepclassmembers class rx.internal.util.unsafe.*ArrayQueue*Field* {
+   long producerIndex;
+   long consumerIndex;
+}
+
+
+-keepclassmembers class rx.internal.util.unsafe.BaseLinkedQueueProducerNodeRef {
+    rx.internal.util.atomic.LinkedQueueNode producerNode;
+}
+-keepclassmembers class rx.internal.util.unsafe.BaseLinkedQueueConsumerNodeRef {
+    rx.internal.util.atomic.LinkedQueueNode consumerNode;
+}
+
+
+-dontwarn java.lang.invoke.*
+-keep class sun.misc.Unsafe { *; }
+
+
+
+# OkHttp
+-keepattributes Signature
+-keepattributes *Annotation*
+-keep class okhttp3.** { *; }
+-keep interface okhttp3.** { *; }
+-dontwarn okhttp3.**
+
+#glide
+-keep public class * implements com.bumptech.glide.module.GlideModule
+-keep public class * extends com.bumptech.glide.AppGlideModule
+-keep public enum com.bumptech.glide.load.resource.bitmap.ImageHeaderParser$** {
+  **[] $VALUES;
+  public *;
+}
+
+
+
+-dontwarn retrofit2.**
+-keep class retrofit2.** { *; }
+-keepattributes Signature
+-keepattributes Exceptions
+
+-keepclassmembers class * {
+   public <init> (org.json.JSONObject);
+}
+
+
+-keepclassmembers enum * {
+    public static **[] values();
+    public static ** valueOf(java.lang.String);
+}
+
+
+
+-keepclassmembers class * {
+    @android.webkit.JavascriptInterface <methods>;
+}
+
+
+#okhttp
+-dontwarn com.squareup.okhttp.**
+
+
+
+-keep class com.chad.library.adapter.** {
+*;
+}
+-keep public class * extends com.chad.library.adapter.base.BaseQuickAdapter
+-keep public class * extends com.chad.library.adapter.base.BaseViewHolder
+-keepclassmembers  class **$** extends com.chad.library.adapter.base.BaseViewHolder {
+     <init>(...);
+}
+
+-dontwarn com.kingja.loadsir.**
+-keep class com.kingja.loadsir.** {*;}
+
+-dontwarn com.litesuits.orm.**
+-keep class com.litesuits.orm.** {*;}
+
+-dontwarn org.mozilla.javascript.**
+-keep class org.mozilla.javascript.** {*;}
+
+
+-dontwarn com.yanzhenjie.permission.**
+
+
+#alipay_begin
+-keep class com.alipay.android.app.IAlixPay{*;}
+-keep class com.alipay.android.app.IAlixPay$Stub{*;}
+-keep class com.alipay.android.app.IRemoteServiceCallback{*;}
+-keep class com.alipay.android.app.IRemoteServiceCallback$Stub{*;}
+-keep class com.alipay.sdk.app.PayTask{ public *;}
+-keep class com.alipay.sdk.app.AuthTask{ public *;}
+-keep class com.alipay.sdk.app.H5PayCallback {
+    <fields>;
+    <methods>;
+}
+-keep class com.alipay.android.phone.mrpc.core.** { *; }
+-keep class com.alipay.apmobilesecuritysdk.** { *; }
+-keep class com.alipay.mobile.framework.service.annotation.** { *; }
+-keep class com.alipay.mobilesecuritysdk.face.** { *; }
+-keep class com.alipay.tscenter.biz.rpc.** { *; }
+-keep class org.json.alipay.** { *; }
+-keep class com.alipay.tscenter.** { *; }
+-keep class com.ta.utdid2.** { *;}
+-keep class com.ut.device.** { *;}
+
+#alipay_end
+
+-keep class com.hwangjr.rxbus.thread.** {*;}
+-keepattributes *Annotation*
+-keepclassmembers class ** {
+    @com.hwangjr.rxbus.annotation.Subscribe public *;
+    @com.hwangjr.rxbus.annotation.Produce public *;
+}
+
+
+-dontwarn com.yanzhenjie.permission.**
+
+
+-keep class com.chad.library.adapter.** {
+*;
+}
+-keep public class * extends com.chad.library.adapter.base.BaseQuickAdapter
+-keep public class * extends com.chad.library.adapter.base.BaseViewHolder
+-keepclassmembers  class **$** extends com.chad.library.adapter.base.BaseViewHolder {
+     <init>(...);
+}
+
+
+
+-keep class com.umeng.** {*;}
+-keepclassmembers class * {
+   public <init> (org.json.JSONObject);
+}
+-keepclassmembers enum * {
+    public static **[] values();
+    public static ** valueOf(java.lang.String);
+}
+
+
+
+
+# 穿山甲
+-keep class com.bytedance.sdk.openadsdk.** { *; }
+-keep public interface com.bytedance.sdk.openadsdk.downloadnew.** {*;}
+-keep class com.pgl.sys.ces.* {*;}
+
+
+
+# YCWebView
+
+-keep class com.ycbjie.webviewlib.** {
+    *;
+}
+-dontwarn com.ycbjie.webviewlib.**
+
+
+-renamesourcefileattribute SourceFile
+-keepattributes Exceptions,InnerClasses,Signature,Deprecated,SourceFile,LineNumberTable,EnclosingMethod
+
+# Preserve all annotations.
+
+-keepattributes *Annotation*
+
+# Preserve all public classes, and their public and protected fields and
+# methods.
+
+#-keep public class * {
+#    public protected *;
+#}
+
+# Preserve all .class method names.
+
+#-keepclassmembernames class * {
+#    java.lang.Class class$(java.lang.String);
+#    java.lang.Class class$(java.lang.String, boolean);
+#}
+
+# Preserve all native method names and the names of their classes.
+
+#-keepclasseswithmembernames class * {
+#    native <methods>;
+#}
+
+# Preserve the special static methods that are required in all enumeration
+# classes.
+#}
+#-keepclassmembers class * extends java.lang.Enum {
+#    public static **[] values();
+#    public static ** valueOf(java.lang.String);
+
+#
+## Explicitly preserve all serialization members. The Serializable interface
+## is only a marker interface, so it wouldn't save them.
+## You can comment this out if your library doesn't use serialization.
+## If your code contains serializable classes that have to be backward
+## compatible, please refer to the manual.
+#
+#-keepclassmembers class * implements java.io.Serializable {
+#    static final long serialVersionUID;
+#    static final java.io.ObjectStreamField[] serialPersistentFields;
+#    private void writeObject(java.io.ObjectOutputStream);
+#    private void readObject(java.io.ObjectInputStream);
+#    java.lang.Object writeReplace();
+#    java.lang.Object readResolve();
+#}
+
+
+-keep class com.uc.* {*;}
+
+
+-dontwarn com.tencent.bugly.**
+-keep public class com.tencent.bugly.**{*;}

+ 227 - 0
app/src/main/AndroidManifest.xml

@@ -0,0 +1,227 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.ysnows.sultra" >
+
+    <!-- 如果有视频相关的广告且使用textureView播放,请务必添加,否则黑屏 -->
+    <uses-permission android:name="android.permission.WAKE_LOCK" />
+
+    <uses-permission android:name="android.permission.READ_CONTACTS" />
+    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
+    <uses-permission android:name="android.permission.INTERNET" />
+    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
+    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
+    <uses-permission android:name="android.permission.READ_SMS" />
+    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
+    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
+    <uses-permission android:name="android.permission.CAMERA" />
+
+    <uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT" />
+    <uses-permission android:name="com.android.launcher.permission.UNINSTALL_SHORTCUT" />
+    <uses-permission android:name="com.android.launcher.permission.READ_SETTINGS" />
+
+    <application
+
+        android:name="com.ysnows.sultra.App"
+        android:allowBackup="true"
+        android:icon="@mipmap/ic_launcher"
+        android:label="@string/app_name"
+        android:roundIcon="@mipmap/ic_launcher_round"
+        android:supportsRtl="true"
+        android:theme="@style/AppTheme.NoActionBar"
+        android:usesCleartextTraffic="true"
+
+        >
+
+        <meta-data
+            android:name="design_width_in_dp"
+            android:value="375" />
+        <meta-data
+            android:name="design_height_in_dp"
+            android:value="667" />
+
+        <activity
+            android:name="com.ysnows.sultra.activity.MainActivity"
+            android:configChanges="orientation|screenLayout|screenSize|smallestScreenSize"
+            android:launchMode="singleInstance"
+            android:theme="@style/AppTheme.Translucent.NoActionBar" >
+            <intent-filter >
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter >
+
+            <!--            <intent-filter >-->
+            <!--                <action android:name="android.intent.action.SEARCH" />-->
+
+            <!--                <category android:name="android.intent.category.DEFAULT" />-->
+            <!--            </intent-filter >-->
+            <!--            <intent-filter >-->
+            <!--                <action android:name="android.search.action.GLOBAL_SEARCH" />-->
+
+            <!--                <category android:name="android.intent.category.DEFAULT" />-->
+            <!--            </intent-filter >-->
+            <!--            <intent-filter >-->
+            <!--                <action android:name="android.intent.action.PROCESS_TEXT" />-->
+
+            <!--                <category android:name="android.intent.category.DEFAULT" />-->
+
+            <!--                <data android:mimeType="text/plain" />-->
+            <!--            </intent-filter >-->
+            <!--            <intent-filter >-->
+            <!--                <action android:name="com.orekie.search.SCREEN_SEARCH" />-->
+
+            <!--                <category android:name="android.intent.category.DEFAULT" />-->
+            <!--            </intent-filter >-->
+            <!--            <intent-filter >-->
+            <!--                <action android:name="com.orekie.search.FIRST_TAB" />-->
+
+            <!--                <category android:name="android.intent.category.DEFAULT" />-->
+            <!--            </intent-filter >-->
+
+            <!--            <meta-data-->
+            <!--                android:name="com.android.systemui.action_assist_icon"-->
+            <!--                android:resource="@drawable/ic_search" />-->
+
+            <!--            <intent-filter >-->
+            <!--                <action android:name="android.intent.action.ASSIST" />-->
+
+            <!--                <category android:name="android.intent.category.DEFAULT" />-->
+            <!--            </intent-filter >-->
+            <!--            <intent-filter >-->
+            <!--                <action android:name="android.intent.action.VOICE_COMMAND" />-->
+
+            <!--                <category android:name="android.intent.category.DEFAULT" />-->
+            <!--            </intent-filter >-->
+        </activity >
+        <activity
+            android:name="com.ysnows.sultra.activity.TranslateActivity"
+            android:configChanges="orientation|screenLayout|screenSize|smallestScreenSize"
+            android:excludeFromRecents="false"
+            android:launchMode="singleInstance"
+            android:theme="@style/AppTheme.Translucent.NoActionBar"
+            android:windowSoftInputMode="stateVisible" >
+
+            <intent-filter >
+                <action android:name="android.intent.action.WEB_SEARCH" />
+
+                <category android:name="android.intent.category.DEFAULT" />
+            </intent-filter >
+            <intent-filter >
+                <action android:name="android.search.action.GLOBAL_SEARCH" />
+
+                <category android:name="android.intent.category.DEFAULT" />
+            </intent-filter >
+            <intent-filter >
+                <action android:name="android.intent.action.PROCESS_TEXT" />
+
+                <category android:name="android.intent.category.DEFAULT" />
+
+                <data android:mimeType="text/plain" />
+            </intent-filter >
+
+        </activity >
+        <activity android:name="com.ysnows.sultra.activity.AddFuncActivity" />
+
+        <activity android:name="com.ysnows.sultra.activity.SettingsActivity" />
+        <activity android:name="com.ysnows.sultra.activity.FuncShopActivity" />
+        <activity android:name="com.ysnows.sultra.activity.SearchEngineShopActivity" />
+
+        <receiver android:name="com.ysnows.sultra.receiver.ActionBroadcastReceiver" />
+
+        <receiver android:name="com.ysnows.sultra.RoundSearchWidget" >
+            <intent-filter >
+                <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
+                <action android:name="android.intent.action.BOOT_COMPLETED" />
+            </intent-filter >
+
+            <meta-data
+                android:name="android.appwidget.provider"
+                android:resource="@xml/widget_round" />
+        </receiver >
+
+        <receiver android:name="com.ysnows.sultra.receiver.AppListReceiver" >
+            <intent-filter >
+                <action android:name="android.intent.action.PACKAGE_ADDED" />
+                <action android:name="android.intent.action.PACKAGE_REMOVED" />
+                <action android:name="android.intent.action.package_replaced" />
+
+                <data android:scheme="package" />
+            </intent-filter >
+        </receiver >
+        <receiver android:name="com.ysnows.sultra.receiver.WindowViewReceiver" >
+            <intent-filter >
+                <action android:name="com.ysnows.search_view" />
+                <action android:name="com.ysnows.notification_view" />
+            </intent-filter >
+        </receiver >
+        <receiver android:name="com.ysnows.sultra.receiver.FuncReceiver" >
+            <intent-filter >
+                <action android:name="com.ysnows.torch" />
+                <action android:name="com.ysnows.music" />
+            </intent-filter >
+        </receiver >
+        <receiver android:name="com.ysnows.sultra.receiver.ShortCutReceiver" >
+            <intent-filter >
+                <action android:name="com.android.launcher.action.INSTALL_SHORTCUT" />
+            </intent-filter >
+            <intent-filter >
+                <action android:name="com.android.launcher.action.UNINSTALL_SHORTCUT" />
+            </intent-filter >
+
+        </receiver >
+
+        <service android:name="com.ysnows.sultra.receiver.ClipBoardListenService" />
+        <service
+            android:name="com.ysnows.sultra.receiver.AssistantService"
+            android:label="@string/accessibility_service_label"
+            android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE" >
+            <intent-filter >
+                <action android:name="android.accessibilityservice.AccessibilityService" />
+            </intent-filter >
+
+            <meta-data
+                android:name="android.accessibilityservice"
+                android:resource="@xml/accessibility_service_config" />
+        </service >
+
+        <activity
+            android:name="com.ysnows.sultra.activity.AddSearchEngineActivity"
+            android:theme="@style/AppTheme.NoActionBar" />
+        <activity android:name="com.ysnows.sultra.activity.CheckPermissionsActivity" />
+        <activity android:name="com.ysnows.sultra.activity.TodosActivity" />
+
+        <activity android:name="com.ysnows.sultra.activity.LoginActivity" />
+        <activity android:name="com.ysnows.sultra.activity.RegisterActivity" />
+        <activity
+            android:name="com.ysnows.sultra.activity.PrivateCenterActivity"
+            android:launchMode="singleTask" >
+            <!--            <intent-filter >-->
+            <!--                <action android:name="android.intent.action.MAIN" />-->
+            <!--                <category android:name="android.intent.category.LAUNCHER" />-->
+            <!--            </intent-filter >-->
+        </activity >
+        <activity android:name=".activity.AboutActivity" />
+        <activity android:name=".activity.WebViewActivity" />
+        <activity android:name=".activity.VipBuyActivity" />
+        <activity
+            android:name=".activity.SplashActivity"
+            android:theme="@style/AppTheme.Launcher" ></activity >
+
+        <provider
+            android:name="com.bytedance.sdk.openadsdk.TTFileProvider"
+            android:authorities="${applicationId}.TTFileProvider"
+            android:exported="false"
+            android:grantUriPermissions="true" >
+            <meta-data
+                android:name="android.support.FILE_PROVIDER_PATHS"
+                android:resource="@xml/file_paths" />
+        </provider >
+
+        <provider
+            android:name="com.bytedance.sdk.openadsdk.multipro.TTMultiProvider"
+            android:authorities="${applicationId}.TTMultiProvider"
+            android:exported="false" />
+
+    </application >
+
+</manifest >

+ 68 - 0
app/src/main/java/com/ysnows/sultra/App.java

@@ -0,0 +1,68 @@
+package com.ysnows.sultra;
+
+import com.litesuits.orm.LiteOrm;
+import com.ysnows.base.base.BApp;
+import com.ysnows.base.ccretrofit.CCRetrofit;
+import com.ysnows.base.config.IConfig;
+import com.ysnows.base.route.IUpdate;
+import com.ysnows.sultra.config.Config;
+import com.ysnows.sultra.model.SearchEngine;
+import com.ysnows.sultra.utils.ad.TTAdManagerHolder;
+import com.ysnows.sultra.worker.AppRunnable;
+import com.ysnows.sultra.worker.ConfigRunnable;
+
+public class App extends BApp {
+
+    private static App app = null;
+    public static LiteOrm configOrm;
+
+    public static SearchEngine default_search;
+    private IConfig config;
+
+
+    @Override
+    protected void init() {
+        app = this;
+        new Thread(new ConfigRunnable(this)).start();
+        new Thread(new AppRunnable(this)).start();
+
+//        X5WebUtils.init(App.getApp());
+
+        CCRetrofit.instance()
+                .create(IUpdate.class)
+                .init()
+                .subscribe();
+
+//        CCRetrofit.instance()
+//                .create(IUmeng.class)
+//                .init()
+//                .subscribe();
+
+        TTAdManagerHolder.init(this);
+    }
+
+    public static App getApp() {
+        return app;
+    }
+
+    public static LiteOrm getLiteOrm() {
+        return liteOrm;
+    }
+
+
+    public static LiteOrm getConfigOrm() {
+        return configOrm;
+    }
+
+    public static void setConfigOrm(LiteOrm configOrm) {
+        App.configOrm = configOrm;
+    }
+
+    @Override
+    public IConfig config() {
+        if (config == null) {
+            config = new Config();
+        }
+        return config;
+    }
+}

+ 36 - 0
app/src/main/java/com/ysnows/sultra/C/Api.java

@@ -0,0 +1,36 @@
+package com.ysnows.sultra.C;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URLEncoder;
+
+public class Api {
+
+    /**
+     * 获取百度热词
+     *
+     * @param kw
+     *
+     * @return
+     */
+    public static String getBaiduHotWord(String kw) {
+        try {
+            return String.format("http://suggestion.baidu.com/s?wd=%s&action=opensearch&ie=utf-8", new Object[]{
+                    URLEncoder.encode(kw, "utf-8")});
+        } catch (UnsupportedEncodingException e) {
+            e.printStackTrace();
+        }
+        return "";
+    }
+
+    /**
+     * 获取天气
+     *
+     * @param city
+     *
+     * @return
+     */
+    public static String getWeather(String city) {
+        return String.format("http://res.aider.meizu.com/1.0/weather/%s.json", new Object[]{city});
+    }
+
+}

+ 14 - 0
app/src/main/java/com/ysnows/sultra/C/C.java

@@ -0,0 +1,14 @@
+package com.ysnows.sultra.C;
+
+public class C {
+    public class Action {
+        public static final String ACTION_TORCH = "com.ysnows.torch";
+        public static final String ACTION_MUSIC = "com.ysnows.music";
+        public static final String ACTION_SEARCH_VIEW = "com.ysnows.search_view";
+        public static final String ACTION_NOTIFICATION_VIEW = "notification_view";
+        public static final String ACTION_KEY_SIMULATE = "key_simulate";
+        public static final String ACTION_EXEC_SHELL = "exec_shell";
+        public static final String ACTION_EXEC_Uri = "exec_uri";
+    }
+
+}

+ 48 - 0
app/src/main/java/com/ysnows/sultra/RoundSearchWidget.kt

@@ -0,0 +1,48 @@
+package com.ysnows.sultra
+
+import android.appwidget.AppWidgetManager
+import android.appwidget.AppWidgetProvider
+import android.content.Context
+import android.content.Intent
+import android.widget.RemoteViews
+import com.ysnows.sultra.binder.FuncBinder
+import com.ysnows.sultra.model.Func
+
+class RoundSearchWidget : AppWidgetProvider() {
+
+    override fun onReceive(context: Context, intent: Intent) {
+        super.onReceive(context, intent)
+        if (
+                Intent.ACTION_BOOT_COMPLETED == intent.action ||
+                AppWidgetManager.ACTION_APPWIDGET_UPDATE == intent.action ||
+                AppWidgetManager.ACTION_APPWIDGET_RESTORED == intent.action ||
+                AppWidgetManager.ACTION_APPWIDGET_ENABLED == intent.action
+        ) {
+            render(context)
+        }
+    }
+
+    private fun render(context: Context) {
+
+        val remoteViews = RemoteViews(context.packageName, R.layout.app_widget_round_search_bar)
+
+        FuncBinder.bind(context, remoteViews, Func.findLeftFunc(), R.id.img_func_left)
+        FuncBinder.bindSearchBar(context, remoteViews)
+
+        val ids = intArrayOf(R.id.img_one, R.id.img_two, R.id.img_three, R.id.img_four, R.id.img_five)
+
+        val rightFuncList = Func.findRightFuncList()
+
+        val maxSize = if (rightFuncList.size > 5) 5 else rightFuncList.size
+
+        for (i in 0 until 5) {
+            var func: Func? = null
+            if (i < maxSize) {
+                func = rightFuncList[i]
+            }
+
+            FuncBinder.bind(context, remoteViews, func, ids[i])
+        }
+    }
+
+}

+ 148 - 0
app/src/main/java/com/ysnows/sultra/T9View.java

@@ -0,0 +1,148 @@
+package com.ysnows.sultra;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+/**
+ * Created by xianguangjin on 16/6/1.
+ * 自定义
+ */
+
+public class T9View extends LinearLayout implements View.OnClickListener {
+
+    private onClickFinishListener onClickFinishListener;
+    protected TextView tv1;
+    protected TextView tv2;
+    protected TextView tv3;
+    protected TextView tv4;
+    protected TextView tv5;
+    protected TextView tv6;
+    protected TextView tv7;
+    protected TextView tv8;
+    protected TextView tv9;
+    protected ImageView imgKeyboard;
+    protected TextView tv0;
+    protected ImageView imgDel;
+    private StringBuilder builder;
+
+    public T9View(Context context) {
+        this(context, null);
+
+    }
+
+    public T9View(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+
+
+    }
+
+    public T9View(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+        init(context, attrs, defStyleAttr);
+
+    }
+
+    private void init(Context context, AttributeSet attrs, int defStyleAttr) {
+        inflate(context, R.layout.widget_t9, this);
+        setOrientation(VERTICAL);
+        setBackgroundResource(R.drawable.bg_rect_top_primary);
+        tv1 = findViewById(R.id.tv_1);
+        tv2 = findViewById(R.id.tv_2);
+        tv3 = findViewById(R.id.tv_3);
+        tv4 = findViewById(R.id.tv_4);
+        tv5 = findViewById(R.id.tv_5);
+        tv6 = findViewById(R.id.tv_6);
+        tv7 = findViewById(R.id.tv_7);
+        tv8 = findViewById(R.id.tv_8);
+        tv9 = findViewById(R.id.tv_9);
+        imgKeyboard = findViewById(R.id.img_keyboard);
+        tv0 = findViewById(R.id.tv_0);
+        imgDel = findViewById(R.id.img_del);
+
+
+        tv0.setOnClickListener(this);
+        tv1.setOnClickListener(this);
+        tv2.setOnClickListener(this);
+        tv3.setOnClickListener(this);
+        tv4.setOnClickListener(this);
+        tv5.setOnClickListener(this);
+        tv6.setOnClickListener(this);
+        tv7.setOnClickListener(this);
+        tv8.setOnClickListener(this);
+        tv9.setOnClickListener(this);
+        imgDel.setOnClickListener(this);
+        imgKeyboard.setOnClickListener(this);
+        builder = new StringBuilder();
+
+    }
+
+
+    @Override
+    public void onClick(View v) {
+        switch (v.getId()) {
+            case R.id.tv_0:
+                builder.append("0");
+                break;
+            case R.id.tv_1:
+                builder.append("1");
+                break;
+            case R.id.tv_2:
+                builder.append("2");
+                break;
+            case R.id.tv_3:
+                builder.append("3");
+                break;
+            case R.id.tv_4:
+                builder.append("4");
+                break;
+            case R.id.tv_5:
+                builder.append("5");
+                break;
+            case R.id.tv_6:
+                builder.append("6");
+                break;
+            case R.id.tv_7:
+                builder.append("7");
+                break;
+            case R.id.tv_8:
+                builder.append("8");
+                break;
+            case R.id.tv_9:
+                builder.append("9");
+                break;
+            case R.id.img_del:
+                int i = builder.length() - 1;
+                if (i >= 0) {
+                    builder.deleteCharAt(i);
+                }
+                break;
+            case R.id.img_keyboard:
+                if (onClickFinishListener != null) {
+                    onClickFinishListener.showKb();
+                }
+
+                break;
+        }
+
+
+        if (onClickFinishListener != null) {
+            onClickFinishListener.onFinished(builder.toString());
+        }
+    }
+
+
+    public void setOnClickFinishListener(T9View.onClickFinishListener onClickFinishListener) {
+        this.onClickFinishListener = onClickFinishListener;
+    }
+
+    public interface onClickFinishListener {
+        void onFinished(String kw);
+
+        void showKb();
+    }
+
+}

+ 59 - 0
app/src/main/java/com/ysnows/sultra/activity/AboutActivity.kt

@@ -0,0 +1,59 @@
+package com.ysnows.sultra.activity
+
+import android.os.Bundle
+import android.view.ViewGroup
+import com.qmuiteam.qmui.util.QMUIDisplayHelper
+import com.qmuiteam.qmui.widget.grouplist.QMUICommonListItemView
+import com.qmuiteam.qmui.widget.grouplist.QMUIGroupListView
+import com.ysnows.base.base.BRepository
+import com.ysnows.base.base.BViewModel
+import com.ysnows.base.utils.B
+import com.ysnows.sultra.R
+import com.ysnows.sultra.base.MBActivity
+import com.ysnows.sultra.databinding.ActivityAboutBinding
+
+open class AboutActivity : MBActivity<BViewModel<BRepository>, ActivityAboutBinding>() {
+
+    override fun initCreate(savedInstanceState: Bundle?) {
+        super.initCreate(savedInstanceState)
+
+        val privatePolicyItem: QMUICommonListItemView = binding.layGroupList.createItemView(
+                null,
+                getString(R.string.private_policy),
+                null,
+                QMUICommonListItemView.HORIZONTAL,
+                QMUICommonListItemView.ACCESSORY_TYPE_NONE)
+
+        val userPolicyItem: QMUICommonListItemView = binding.layGroupList.createItemView(
+                null,
+                getString(R.string.user_policy),
+                null,
+                QMUICommonListItemView.HORIZONTAL,
+                QMUICommonListItemView.ACCESSORY_TYPE_NONE)
+
+
+        val size: /*@@dmnjhl@@*/Int = QMUIDisplayHelper.dp2px(context(), 20)
+        QMUIGroupListView.newSection(context())
+                .setLeftIconSize(size, ViewGroup.LayoutParams.WRAP_CONTENT)
+                .addItemView(privatePolicyItem) {
+                    bundle(WebViewActivity::class.java, B.with().putString("url", "http://sultra.newintellij.com/private_policy.html").ok())
+                }
+                .addItemView(userPolicyItem) {
+                    bundle(WebViewActivity::class.java, B.with().putString("url", "http://sultra.newintellij.com/user_policy.html").ok())
+                }
+                .setMiddleSeparatorInset(QMUIDisplayHelper.dp2px(context(), 16), 0)
+                .addTo(binding.layGroupList)
+    }
+
+    override fun title(): String? {
+        return getString(R.string.about)
+
+    }
+
+    override fun binding(): ActivityAboutBinding {
+        return ActivityAboutBinding.inflate(layoutInflater)
+    }
+
+}
+
+

+ 33 - 0
app/src/main/java/com/ysnows/sultra/activity/AddFuncActivity.kt

@@ -0,0 +1,33 @@
+package com.ysnows.sultra.activity
+
+import com.hwangjr.rxbus.annotation.Subscribe
+import com.hwangjr.rxbus.annotation.Tag
+import com.ysnows.sultra.base.MBActivity
+import com.ysnows.sultra.config.ConfigRx
+import com.ysnows.sultra.databinding.ActivityAddFunctionsBinding
+import com.ysnows.sultra.model.Func
+import com.ysnows.sultra.vmodel.AddFuncVModel
+
+class AddFuncActivity : MBActivity<AddFuncVModel, ActivityAddFunctionsBinding>() {
+
+    override fun binding(): ActivityAddFunctionsBinding {
+        return ActivityAddFunctionsBinding.inflate(layoutInflater)
+    }
+
+    override fun title(): String? = null
+    override fun transluent(): Boolean = true
+
+    override fun vmClass(): Class<AddFuncVModel> {
+        return AddFuncVModel::class.java
+    }
+
+
+    @Subscribe(tags = [Tag(ConfigRx.ROUND_SEARCH_BAR_ITEM_ADDED)])
+    fun renderFuncList(from: String) {
+        vm.funcRightList.value = Func.findRightFuncList()
+        vm.funcLeft.value = Func.findLeftFunc()
+    }
+
+    override val isRxbus: Boolean
+        get() = true
+}

+ 76 - 0
app/src/main/java/com/ysnows/sultra/activity/AddSearchEngineActivity.kt

@@ -0,0 +1,76 @@
+package com.ysnows.sultra.activity
+
+import android.graphics.Color
+import android.text.Spannable
+import android.text.SpannableString
+import android.text.style.AbsoluteSizeSpan
+import android.text.style.ForegroundColorSpan
+import android.view.View
+import com.chad.library.adapter.base.BaseQuickAdapter
+import com.chad.library.adapter.base.listener.OnItemClickListener
+import com.hwangjr.rxbus.annotation.Subscribe
+import com.hwangjr.rxbus.annotation.Tag
+import com.qmuiteam.qmui.widget.dialog.QMUIDialogAction
+import com.ysnows.base.base.BRepository
+import com.ysnows.base.ext.message
+import com.ysnows.sultra.base.MBActivity
+import com.ysnows.sultra.config.ConfigRx
+import com.ysnows.sultra.databinding.ActivityAddSearchEngineBinding
+import com.ysnows.sultra.model.SearchEngine
+import com.ysnows.sultra.repository.SearchRepository
+import com.ysnows.sultra.vmodel.AddSearchEngineVModel
+
+class AddSearchEngineActivity : MBActivity<AddSearchEngineVModel, ActivityAddSearchEngineBinding>(), OnItemClickListener {
+
+    override fun listeners() {
+        super.listeners()
+        vm.adapter.setOnItemClickListener(this)
+    }
+
+    override fun binding(): ActivityAddSearchEngineBinding {
+        return ActivityAddSearchEngineBinding.inflate(layoutInflater)
+    }
+
+    override fun transluent(): Boolean {
+        return true
+    }
+
+    override fun vmClass(): Class<AddSearchEngineVModel> {
+        return AddSearchEngineVModel::class.java
+    }
+
+    @Subscribe(tags = [Tag(ConfigRx.SEARCH_BAR_ITEM_ADDED)])
+    fun renderFuncList(from: String) {
+        vm.searchEngineList.value = SearchEngine.findSearchBarEngineList()
+    }
+
+
+    override val isRxbus: Boolean
+        get() = true
+
+    override fun onItemClick(adapter: BaseQuickAdapter<*, *>, view: View, position: Int) {
+        val item = vm.adapter.getItem(position)
+        if (item.is_default != 1) {
+            val spannableString = SpannableString("设置 ${item.name} 为默认搜索引擎吗?")
+            val startPos = 3
+            val length = startPos + item.name.length
+            spannableString.setSpan(ForegroundColorSpan(Color.parseColor("#FF4285F4")), startPos, length, Spannable.SPAN_INCLUSIVE_EXCLUSIVE)
+            spannableString.setSpan(AbsoluteSizeSpan(16, true), startPos, length, Spannable.SPAN_INCLUSIVE_EXCLUSIVE)
+
+            message(
+                    spannableString,
+                    positiveBtnName = "设置",
+                    negativeEnable = true,
+                    negativeBtnName = "不要",
+                    positiveAction = QMUIDialogAction.ActionListener { dialog, _ ->
+                        dialog.dismiss()
+                        vm.adapter.setDefault(position)
+                    }
+            )
+        }
+    }
+
+    override fun createRepository(): BRepository {
+        return SearchRepository()
+    }
+}

+ 44 - 0
app/src/main/java/com/ysnows/sultra/activity/CheckPermissionsActivity.kt

@@ -0,0 +1,44 @@
+package com.ysnows.sultra.activity
+
+import android.view.View
+import android.widget.TextView
+import com.ysnows.base.base.BRepository
+import com.ysnows.base.base.BViewModel
+import com.ysnows.base.utils.AccessibilityUtils
+import com.ysnows.sultra.R
+import com.ysnows.sultra.base.MBActivity
+import com.ysnows.sultra.databinding.ActivityCheckPermissionsBinding
+import com.ysnows.sultra.receiver.AssistantService
+import com.ysnows.sultra.utils.PermissionUtils
+
+class CheckPermissionsActivity : MBActivity<BViewModel<BRepository>, ActivityCheckPermissionsBinding>() {
+    protected var btnAssistance: TextView? = null
+    protected var btnFloat: TextView? = null
+    override fun onResume() {
+        super.onResume()
+        val floatPermission = PermissionUtils.checkFloatPermission(context())
+        btnFloat!!.text = if (floatPermission) "已开启" else "开启"
+        val accessibilitySettingsOn = AccessibilityUtils.isAccessibilitySettingsOn(AssistantService::class.java.name, context())
+        btnAssistance!!.text = if (accessibilitySettingsOn) "已开启" else "开启"
+    }
+
+    override fun title(): String? {
+        return "检查权限"
+    }
+
+    override fun listeners() {
+        super.listeners()
+        btnFloat!!.setOnClickListener { v: View? -> PermissionUtils.openFloatPermission(this@CheckPermissionsActivity) }
+        btnAssistance!!.setOnClickListener { v: View? -> AccessibilityUtils.openAccessibility(context()) }
+    }
+
+    override fun binding(): ActivityCheckPermissionsBinding {
+        return ActivityCheckPermissionsBinding.inflate(layoutInflater)
+    }
+
+    override fun initView(view: View?) {
+        super.initView(view)
+        btnAssistance = findViewById<View>(R.id.btn_assistance) as TextView
+        btnFloat = findViewById<View>(R.id.btn_float) as TextView
+    }
+}

+ 121 - 0
app/src/main/java/com/ysnows/sultra/activity/FuncShopActivity.kt

@@ -0,0 +1,121 @@
+package com.ysnows.sultra.activity
+
+import android.net.Uri
+import android.os.Bundle
+import android.view.View
+import androidx.fragment.app.Fragment
+import androidx.fragment.app.FragmentPagerAdapter
+import androidx.viewpager.widget.ViewPager
+import com.google.android.material.tabs.TabLayout
+import com.hwangjr.rxbus.RxBus
+import com.ysnows.base.base.BRepository
+import com.ysnows.base.base.BViewModel
+import com.ysnows.sultra.R
+import com.ysnows.sultra.base.MBActivity
+import com.ysnows.sultra.databinding.ActivityFuncShopBinding
+import com.ysnows.sultra.fragment.AppsFragment
+import com.ysnows.sultra.fragment.ShopFuncQuikFragment
+import com.ysnows.sultra.fragment.WebFragment
+import com.ysnows.sultra.model.Func
+import java.util.*
+
+class FuncShopActivity : MBActivity<BViewModel<BRepository>, ActivityFuncShopBinding>(){
+    protected var viewPager: ViewPager? = null
+    protected var tabLayout: TabLayout? = null
+    private var position = Func.POS_FUNC_LEFT
+    private val titles = arrayOf("快捷功能", "应用程序", "网站")
+    private val fragments = ArrayList<Fragment>()
+    private var normalVisibility = View.VISIBLE
+    private var webName: String? = null
+    private var webUrl: String? = null
+    override fun initCreate(savedInstanceState: Bundle?) {
+        super.initCreate(savedInstanceState)
+        val extras = intent.extras
+        if (extras != null) {
+            position = extras.getString("pos", Func.POS_FUNC_RIGHT)
+        }
+        val shopFuncQuikFragment = ShopFuncQuikFragment()
+        shopFuncQuikFragment.arguments = extras
+        fragments.add(shopFuncQuikFragment)
+        val appsFragment = AppsFragment()
+        appsFragment.arguments = extras
+        fragments.add(appsFragment)
+        val webViewFragment = WebFragment()
+        webViewFragment.arguments = extras
+        fragments.add(webViewFragment)
+    }
+
+    override fun binding(): ActivityFuncShopBinding {
+        return ActivityFuncShopBinding.inflate(layoutInflater)
+    }
+
+    override fun title(): String? {
+        return "功能市场"
+    }
+
+    override fun initView(view: View?) {
+        super.initView(view)
+        setTabOneAction()
+        viewPager = findViewById(R.id.view_pager)
+        tabLayout = findViewById(R.id.tab_layout)
+        viewPager?.setOffscreenPageLimit(3)
+        viewPager?.setAdapter(object : FragmentPagerAdapter(supportFragmentManager) {
+            override fun getItem(position: Int): Fragment {
+                return fragments[position]
+            }
+
+            override fun getCount(): Int {
+                return 3
+            }
+
+            override fun getPageTitle(position: Int): CharSequence? {
+                return titles[position]
+            }
+        })
+        tabLayout?.setupWithViewPager(viewPager)
+        tabLayout?.addOnTabSelectedListener(object : TabLayout.OnTabSelectedListener {
+            override fun onTabSelected(tab: TabLayout.Tab) {
+                if (tab.position == 0) {
+                    setTabOneAction()
+                } else if (tab.position == 2) {
+                    titleBar()!!.setRitghtImg(resources.getDrawable(R.drawable.pocket))
+                    titleBar()!!.imgRight!!.setOnClickListener { v: View? ->
+                        if (webUrl == null) {
+                            return@setOnClickListener
+                        }
+                        val uri = Uri.parse(webUrl)
+                    }
+                } else {
+                    titleBar()!!.imgRight!!.visibility = View.GONE
+                }
+            }
+
+            override fun onTabUnselected(tab: TabLayout.Tab) {}
+            override fun onTabReselected(tab: TabLayout.Tab) {}
+        })
+    }
+
+    private fun setTabOneAction() {
+        titleBar()!!.setRitghtImg(resources.getDrawable(R.drawable.ic_add_black_24dp))
+    }
+
+    override fun onBackPressed() {
+        if (tabLayout!!.selectedTabPosition == 2 && normalVisibility == View.GONE) {
+            RxBus.get().post("WebViewBack", "")
+        } else {
+            super.onBackPressed()
+        }
+    }
+
+//    override fun setNormalVisibility(visibility: Int) {
+//        normalVisibility = visibility
+//    }
+//
+//    override fun setWebName(webName: String) {
+//        this.webName = webName
+//    }
+//
+//    override fun setWebUrl(webUrl: String) {
+//        this.webUrl = webUrl
+//    }
+}

+ 27 - 0
app/src/main/java/com/ysnows/sultra/activity/LoginActivity.kt

@@ -0,0 +1,27 @@
+package com.ysnows.sultra.activity
+
+import com.ysnows.base.base.BRepository
+import com.ysnows.sultra.base.MBActivity
+import com.ysnows.sultra.databinding.ActivityLoginBinding
+import com.ysnows.sultra.repository.LoginRepository
+import com.ysnows.sultra.vmodel.LoginVModel
+
+class LoginActivity : MBActivity<LoginVModel, ActivityLoginBinding>() {
+    override fun title(): String? {
+        return "登录"
+    }
+
+    override fun binding(): ActivityLoginBinding {
+        return ActivityLoginBinding.inflate(layoutInflater)
+    }
+
+    override fun vmClass(): Class<LoginVModel> {
+        return LoginVModel::class.java
+    }
+
+    override fun createRepository(): BRepository {
+        return LoginRepository()
+    }
+
+
+}

+ 151 - 0
app/src/main/java/com/ysnows/sultra/activity/MainActivity.kt

@@ -0,0 +1,151 @@
+package com.ysnows.sultra.activity
+
+import android.os.Bundle
+import android.view.View
+import com.bytedance.sdk.openadsdk.TTAdConstant
+import com.bytedance.sdk.openadsdk.TTAppDownloadListener
+import com.bytedance.sdk.openadsdk.TTNativeExpressAd
+import com.qmuiteam.qmui.util.QMUIKeyboardHelper
+import com.ysnows.base.base.BRepository
+import com.ysnows.base.utils.MMKVManager
+import com.ysnows.sultra.base.MBActivity
+import com.ysnows.sultra.config.ConfigMMKV
+import com.ysnows.sultra.databinding.ActivitySearchBinding
+import com.ysnows.sultra.repository.SearchRepository
+import com.ysnows.sultra.utils.ad.AdUtils
+import com.ysnows.sultra.utils.fluid.FluidContentResizer
+import com.ysnows.sultra.vmodel.MainVModel
+import io.reactivex.android.schedulers.AndroidSchedulers
+
+
+class MainActivity : MBActivity<MainVModel, ActivitySearchBinding>() {
+
+    private lateinit var mTTAd: TTNativeExpressAd
+    override val isRxbus: Boolean = true
+    override fun title(): String? = null
+
+    override fun initCreate(savedInstanceState: Bundle?) {
+        super.initCreate(savedInstanceState)
+
+        if (MMKVManager.instance().decodeBool(ConfigMMKV.FIRST_OPEN, true)) {
+            single(SplashActivity::class.java)
+
+        } else {
+        }
+
+    }
+
+
+    //绑定广告行为
+    private fun bindAdListener(ad: TTNativeExpressAd) {
+        ad.setExpressInteractionListener(object : TTNativeExpressAd.AdInteractionListener {
+            override fun onAdDismiss() {
+                QMUIKeyboardHelper.showKeyboard(binding.searchBar.binding.edtBar, 100)
+            }
+
+            override fun onAdClicked(view: View?, type: Int) {
+
+            }
+
+            override fun onAdShow(view: View?, type: Int) {
+
+            }
+
+            override fun onRenderFail(view: View?, msg: String, code: Int) {
+
+            }
+
+            override fun onRenderSuccess(view: View?, width: Float, height: Float) {
+                //返回view的宽高 单位 dp
+
+                //在渲染成功回调时展示广告,提升体验
+                mTTAd.showInteractionExpressAd(this@MainActivity)
+//                binding.layContainer.addView(mTTAd.expressAdView)
+            }
+        })
+
+        if (ad.interactionType != TTAdConstant.INTERACTION_TYPE_DOWNLOAD) {
+            return
+        }
+        //可选,下载监听设置
+        ad.setDownloadListener(object : TTAppDownloadListener {
+            override fun onIdle() {
+
+            }
+
+            override fun onDownloadActive(totalBytes: Long, currBytes: Long, fileName: String, appName: String) {
+//                if (!mHasShowDownloadActive) {
+//                    mHasShowDownloadActive = true
+
+//                }
+            }
+
+            override fun onDownloadPaused(totalBytes: Long, currBytes: Long, fileName: String, appName: String) {
+
+            }
+
+            override fun onDownloadFailed(totalBytes: Long, currBytes: Long, fileName: String, appName: String) {
+
+            }
+
+            override fun onInstalled(fileName: String, appName: String) {
+
+            }
+
+            override fun onDownloadFinished(totalBytes: Long, fileName: String, appName: String) {
+
+            }
+        })
+    }
+
+
+    override fun listeners() {
+        super.listeners()
+        FluidContentResizer.listen(this)
+    }
+
+
+    override fun binding(): ActivitySearchBinding = ActivitySearchBinding.inflate(layoutInflater)
+    override fun transluent(): Boolean = true
+
+    private fun checkAndInit() {
+
+//        Thread {
+//            if (SettingsUtil.clipboard_listener()) {
+//                if (!CheckUtil.isServiceWorked(context(), "ClipBoardListenService")) {
+//                    runOnUiThread { ClipBoardListenService.start(context()) }
+//                }
+
+//                boolean floatPermission = PermissionUtils.checkFloatPermission(getContext());
+//                if (!floatPermission) {
+//                    runOnUiThread(() -> PermissionUtils.openFloatPermission(MainActivity.this));
+//                }
+//            }
+//        }.start()
+
+    }
+
+    override fun onResume() {
+        super.onResume()
+        AdUtils.loadInteractionAd("945450432", this)
+                ?.observeOn(AndroidSchedulers.mainThread())
+                ?.doOnNext() {
+                    mTTAd = it
+                    bindAdListener(it)
+                }
+                ?.subscribe()
+
+        QMUIKeyboardHelper.showKeyboard(binding.searchBar.binding.edtBar, false)
+
+    }
+
+    override fun createRepository(): BRepository {
+        return SearchRepository();
+    }
+
+
+    override fun vmClass(): Class<MainVModel> {
+        return MainVModel::class.java
+    }
+
+}

+ 80 - 0
app/src/main/java/com/ysnows/sultra/activity/PrivateCenterActivity.kt

@@ -0,0 +1,80 @@
+package com.ysnows.sultra.activity
+
+import android.appwidget.AppWidgetManager
+import android.content.Intent
+import android.os.Bundle
+import com.hwangjr.rxbus.annotation.Subscribe
+import com.hwangjr.rxbus.annotation.Tag
+import com.qmuiteam.qmui.kotlin.onClick
+import com.ysnows.base.base.BRepository
+import com.ysnows.base.ccretrofit.CCRetrofit
+import com.ysnows.base.route.IApp
+import com.ysnows.sultra.R
+import com.ysnows.sultra.base.MBActivity
+import com.ysnows.sultra.config.ConfigRx
+import com.ysnows.sultra.databinding.ActivityPrivateCenterBinding
+import com.ysnows.sultra.repository.UserInfoRepository
+import com.ysnows.sultra.vmodel.PrivateCenterVModel
+
+class PrivateCenterActivity : MBActivity<PrivateCenterVModel, ActivityPrivateCenterBinding>() {
+
+    override fun title(): String? {
+        return "个人中心"
+    }
+
+    override fun initCreate(savedInstanceState: Bundle?) {
+        super.initCreate(savedInstanceState)
+        sendBroadcast(Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE))
+    }
+
+
+    override fun listeners() {
+        super.listeners()
+
+        binding.laySettings.onClick {
+            CCRetrofit.instance()
+                    .with(this)
+                    .create(IApp::class.java)
+                    .settings()
+                    .subscribe()
+        }
+
+        binding.layNote.onClick {
+            CCRetrofit.instance()
+                    .with(this)
+                    .create(IApp::class.java)
+                    .todoList()
+                    .subscribe()
+        }
+
+        binding.layAb.onClick {
+            toast(R.string.developing)
+        }
+    }
+
+    override fun binding(): ActivityPrivateCenterBinding {
+        return ActivityPrivateCenterBinding.inflate(layoutInflater)
+    }
+
+    override val isRxbus: Boolean
+        get() = true
+
+    override fun backable(): Boolean {
+        return false
+    }
+
+    override fun vmClass(): Class<PrivateCenterVModel> {
+        return PrivateCenterVModel::class.java
+    }
+
+    @Subscribe(tags = [Tag(ConfigRx.LOGIN)])
+    fun logout(from: String) {
+        vm.firstReq()
+    }
+
+    override fun createRepository(): BRepository {
+        return UserInfoRepository()
+    }
+
+
+}

+ 25 - 0
app/src/main/java/com/ysnows/sultra/activity/RegisterActivity.kt

@@ -0,0 +1,25 @@
+package com.ysnows.sultra.activity
+
+import com.ysnows.base.base.BRepository
+import com.ysnows.sultra.base.MBActivity
+import com.ysnows.sultra.databinding.ActivityRegisterBinding
+import com.ysnows.sultra.repository.RegisterRepository
+import com.ysnows.sultra.vmodel.RegisterVModel
+
+class RegisterActivity : MBActivity<RegisterVModel, ActivityRegisterBinding>() {
+    override fun title(): String? {
+        return "注册"
+    }
+
+    override fun binding(): ActivityRegisterBinding {
+        return ActivityRegisterBinding.inflate(layoutInflater)
+    }
+
+    override fun vmClass(): Class<RegisterVModel> {
+        return RegisterVModel::class.java
+    }
+
+    override fun createRepository(): BRepository {
+        return RegisterRepository()
+    }
+}

+ 38 - 0
app/src/main/java/com/ysnows/sultra/activity/SearchEngineShopActivity.kt

@@ -0,0 +1,38 @@
+package com.ysnows.sultra.activity
+
+import com.ysnows.base.net.IResponse
+import com.ysnows.sultra.adapter.ShopSearchEnginesAdapter
+import com.ysnows.sultra.base.MBRActivity
+import com.ysnows.sultra.databinding.ActivitySearchengineShopBinding
+import com.ysnows.sultra.utils.net.NetEngine
+import com.ysnows.sultra.vmodel.SearchEngineShopVModel
+import io.reactivex.Observable
+
+class SearchEngineShopActivity : MBRActivity<SearchEngineShopVModel, ShopSearchEnginesAdapter, ActivitySearchengineShopBinding>() {
+
+    private var position = 0
+
+    override fun __before() {
+        super.__before()
+        val extras = intent.extras
+        if (extras != null) {
+            position = extras.getInt("position", 0)
+        }
+    }
+
+    override fun binding(): ActivitySearchengineShopBinding {
+        return ActivitySearchengineShopBinding.inflate(layoutInflater)
+    }
+
+    override fun initAdapter(): ShopSearchEnginesAdapter = ShopSearchEnginesAdapter(position, vm)
+
+    override fun api(): Observable<out IResponse<*>?> {
+        return NetEngine.service.getSearchEngines(vm.repository().autoPage())
+    }
+
+    override fun title(): String = "搜索引擎功能市场"
+
+    override fun vmClass(): Class<SearchEngineShopVModel> = SearchEngineShopVModel::class.java
+
+
+}

+ 189 - 0
app/src/main/java/com/ysnows/sultra/activity/SettingsActivity.kt

@@ -0,0 +1,189 @@
+package com.ysnows.sultra.activity
+
+import android.content.Intent
+import android.view.View
+import com.hwangjr.rxbus.annotation.Subscribe
+import com.hwangjr.rxbus.annotation.Tag
+import com.qmuiteam.qmui.kotlin.onClick
+import com.qmuiteam.qmui.widget.dialog.QMUIDialog
+import com.qmuiteam.qmui.widget.dialog.QMUIDialog.MessageDialogBuilder
+import com.ysnows.base.base.BRepository
+import com.ysnows.base.ccretrofit.CCRetrofit
+import com.ysnows.base.ext.message
+import com.ysnows.base.route.IUpdate
+import com.ysnows.base.utils.AccessibilityUtils
+import com.ysnows.base.utils.MMKVManager
+import com.ysnows.base.utils.UiSwitch
+import com.ysnows.sultra.R
+import com.ysnows.sultra.base.MBActivity
+import com.ysnows.sultra.config.ConfigRx
+import com.ysnows.sultra.databinding.ActivitySettingsBinding
+import com.ysnows.sultra.receiver.AssistantService
+import com.ysnows.sultra.receiver.ClipBoardListenService
+import com.ysnows.sultra.repository.UserInfoRepository
+import com.ysnows.sultra.utils.PermissionUtils
+import com.ysnows.sultra.utils.SettingsUtil
+import com.ysnows.sultra.vmodel.SettingsVModel
+
+
+class SettingsActivity : MBActivity<SettingsVModel, ActivitySettingsBinding>() {
+
+    override fun listeners() {
+        super.listeners()
+
+        binding.cbIcGoogle.isChecked = SettingsUtil.pinGoogleIcon()
+        binding.cbClip.isChecked = SettingsUtil.clipboardListener()
+        binding.cbAutoAd.isChecked = SettingsUtil.autoAd()
+        binding.cbMsg.isChecked = SettingsUtil.showMsg()
+        binding.cbDoublePaste.isChecked = SettingsUtil.doubleClickPaste()
+        binding.layCheckPermisions.setOnClickListener { v: View? -> UiSwitch.single(context(), CheckPermissionsActivity::class.java) }
+        binding.layAboutUs.onClick {
+            single(AboutActivity::class.java)
+        }
+        binding.layCheckupdate.setOnClickListener { v: View? ->
+
+            CCRetrofit.instance()
+                    .create(IUpdate::class.java)
+                    .checkUpgrade(false)
+                    .subscribe()
+
+        }
+        binding.layBackup.setOnClickListener { v: View? ->
+            MessageDialogBuilder(context())
+                    .setTitle("备份")
+                    .setMessage("确定要将现在所有的设置备份到云中吗?")
+                    .addAction("取消") { dialog: QMUIDialog, index: Int -> dialog.dismiss() }
+                    .addAction("是的") { dialog: QMUIDialog?, index: Int ->
+                        toast(R.string.developing)
+
+//                        val funcs = App.getConfigOrm().query(Func::class.java)
+//                        val searchEngines = App.getConfigOrm().query(SearchEngine::class.java)
+                    }
+                    .show()
+        }
+
+        binding.layRestore.setOnClickListener { v: View? ->
+            MessageDialogBuilder(context())
+                    .setTitle("恢复备份")
+                    .setMessage("确定要恢复云中的备份?")
+                    .addAction("取消") { dialog: QMUIDialog, which: Int -> dialog.dismiss() }
+                    .addAction("是的") { dialog: QMUIDialog?, which: Int ->
+                        toast(R.string.developing)
+
+//                        SettingsUtil.backUp()
+                    }
+                    .show()
+        }
+
+        binding.layWidgets.onClick { UiSwitch.single(context(), AddFuncActivity::class.java) }
+
+        binding.laySearchBar.onClick {
+            UiSwitch.single(context(), AddSearchEngineActivity::class.java)
+        }
+
+        binding.cbIcGoogle.setOnCheckedChangeListener { buttonView, isChecked ->
+            SettingsUtil.pinGoogleIcon(isChecked)
+//            RoundSearchWidget.setDefault(context())
+        }
+
+        binding.cbDoublePaste.setOnCheckedChangeListener { buttonView, isChecked ->
+            if (isChecked) {
+                if (!AccessibilityUtils.isAccessibilitySettingsOn(AssistantService::class.java.name, context())) {
+                    AccessibilityUtils.openAccessibility(context())
+                    return@setOnCheckedChangeListener
+                }
+            }
+            SettingsUtil.doubleClickPaste(isChecked)
+        }
+
+        binding.cbAutoAd.setOnCheckedChangeListener { buttonView, isChecked ->
+            if (isChecked) {
+                if (!AccessibilityUtils.isAccessibilitySettingsOn(AssistantService::class.java.name, context())) {
+                    AccessibilityUtils.openAccessibility(context())
+                    return@setOnCheckedChangeListener
+                }
+            }
+            SettingsUtil.autoAd(isChecked)
+        }
+        binding.cbMsg.setOnCheckedChangeListener { buttonView, isChecked ->
+            if (isChecked) {
+                if (!AccessibilityUtils.isAccessibilitySettingsOn(AssistantService::class.java.name, context())) {
+                    AccessibilityUtils.openAccessibility(context())
+                    return@setOnCheckedChangeListener
+                }
+            }
+
+            SettingsUtil.showMsg(isChecked)
+        }
+        binding.cbClip.setOnCheckedChangeListener { buttonView, isChecked ->
+            if (isChecked) {
+                ClipBoardListenService.start(context())
+                val floatPermission = PermissionUtils.checkFloatPermission(context())
+                if (!floatPermission) {
+                    binding.cbClip.isChecked = !isChecked
+                    PermissionUtils.openFloatPermission(this@SettingsActivity)
+                    return@setOnCheckedChangeListener
+                }
+
+                SettingsUtil.clipboardListener(isChecked)
+
+            } else {
+                SettingsUtil.clipboardListener(isChecked)
+                ClipBoardListenService.end(context())
+            }
+        }
+
+        binding.btnLogout.onClick {
+            message(R.string.enture_logout, negativeEnable = true, positiveAction = { dialog, _ ->
+                MMKVManager.instance().clearAll()
+                dialog.dismiss()
+                UiSwitch.single_new_task_with_clear_task(context(), PrivateCenterActivity::class.java)
+            })
+        }
+    }
+
+    override fun binding(): ActivitySettingsBinding {
+        return ActivitySettingsBinding.inflate(layoutInflater)
+    }
+
+    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
+        super.onActivityResult(requestCode, resultCode, data)
+        if (requestCode == 100) {
+//            if (PermissionUtils.checkFloatPermission(this)) {
+//                ClipBoardListenService.start(getContext());
+//                SettingsUtil.clipboard_listener(1);
+//            }
+        }
+    }
+
+//    override fun onResume() {
+//        super.onResume()
+//        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
+//            if (PermissionUtils.checkFloatPermission(this)) {
+//                ClipBoardListenService.start(context())
+//            }
+//        }
+//    }
+
+    override fun title(): String? {
+        return "设置"
+    }
+
+    override val isRxbus: Boolean
+        get() = true
+
+    override fun vmClass(): Class<SettingsVModel> {
+        return SettingsVModel::class.java
+    }
+
+    override fun createRepository(): BRepository {
+        return UserInfoRepository()
+    }
+
+    @Subscribe(tags = [Tag(ConfigRx.LOGIN)])
+    fun userInfo(from: String) {
+        vm.firstReq()
+    }
+
+
+}

+ 76 - 0
app/src/main/java/com/ysnows/sultra/activity/SplashActivity.kt

@@ -0,0 +1,76 @@
+package com.ysnows.sultra.activity
+
+import android.os.Bundle
+import android.view.View
+import android.view.ViewGroup
+import com.qmuiteam.qmui.widget.QMUIPagerAdapter
+import com.qmuiteam.qmui.widget.QMUIViewPager
+import com.ysnows.base.base.BRepository
+import com.ysnows.base.base.BViewModel
+import com.ysnows.base.utils.MMKVManager
+import com.ysnows.sultra.R
+import com.ysnows.sultra.base.MBActivity
+import com.ysnows.sultra.config.ConfigMMKV
+import com.ysnows.sultra.databinding.MainGuidBinding
+import com.ysnows.sultra.widget.WidgetGuide
+
+class SplashActivity : MBActivity<BViewModel<BRepository>, MainGuidBinding>() {
+
+    private val mItems: Array<Int> = arrayOf(R.drawable.guid_one, R.drawable.guid_two, R.drawable.guid_three, R.drawable.guid_four)
+
+    override fun binding(): MainGuidBinding {
+
+        return MainGuidBinding.inflate(layoutInflater)
+    }
+
+
+    override fun initCreate(savedInstanceState: Bundle?) {
+        super.initCreate(savedInstanceState)
+        initPagers()
+    }
+
+
+    private fun initPagers() {
+
+        MMKVManager.instance().encode(ConfigMMKV.FIRST_OPEN, true)
+
+        val pagerAdapter: QMUIPagerAdapter = object : QMUIPagerAdapter() {
+            override fun isViewFromObject(view: View, `object`: Any): Boolean {
+                return view === `object`
+            }
+
+            override fun getCount(): Int {
+                return mItems.size
+            }
+
+            override fun getPageTitle(position: Int): CharSequence? {
+                return null
+            }
+
+            override fun hydrate(container: ViewGroup, position: Int): Any {
+                return WidgetGuide(context())
+            }
+
+
+            override fun populate(container: ViewGroup, item: Any, position: Int) {
+                val itemView = item as WidgetGuide
+                itemView.setImageResource(mItems[position])
+                container.addView(itemView)
+            }
+
+            override fun destroy(container: ViewGroup, position: Int, `object`: Any) {
+                container.removeView(`object` as View)
+            }
+        }
+
+        val mViewPager: QMUIViewPager = binding.root as QMUIViewPager
+
+        //setPageTransformer默认采用ViewCompat.LAYER_TYPE_HARDWARE, 但它在某些4.x的国产机下会crash
+//        mViewPager.setPageTransformer(false, CardTransformer(), View.LAYER_TYPE_HARDWARE)
+        mViewPager.adapter = pagerAdapter
+    }
+
+    override fun transluent(): Boolean {
+        return true
+    }
+}

+ 48 - 0
app/src/main/java/com/ysnows/sultra/activity/TodosActivity.kt

@@ -0,0 +1,48 @@
+package com.ysnows.sultra.activity
+
+import com.ysnows.base.net.IResponse
+import com.ysnows.sultra.R
+import com.ysnows.sultra.adapter.TodosAdapter
+import com.ysnows.sultra.base.MBRActivity
+import com.ysnows.sultra.databinding.ActivityTodosBinding
+import com.ysnows.sultra.utils.net.NetEngine
+import com.ysnows.sultra.vmodel.TodoListVModel
+import io.reactivex.Observable
+
+class TodosActivity : MBRActivity<TodoListVModel, TodosAdapter, ActivityTodosBinding>() {
+    //    @Override
+    //    public void onItemDragEnd(RecyclerView.ViewHolder viewHolder, int pos) {
+    //
+    //        int size = getAdapter().getData().size();
+    //        for (int i = 0; i < size; i++) {
+    ////            Todo item = getAdapter().getData().get(i);
+    //
+    ////            HashMap<String, Object> params = new HashMap<>();
+    ////            params.put("order", size - i);
+    //
+    ////            vm.repository().lreq(NetEngine.getService().taskSave(item.id, params), new OnRes<String>() {
+    ////                @Override
+    ////                public void onCall(IResponse<String> res) {
+    ////
+    ////                }
+    ////            });
+    //        }
+    //    }
+    override fun title(): String {
+        return getStr(R.string.todo_list)!!
+    }
+
+    override fun initAdapter(): TodosAdapter = TodosAdapter(vm)
+
+    override fun api(): Observable<out IResponse<*>> {
+        return NetEngine.service.taskList("", vm?.repository()?.autoPage()!!)
+    }
+
+    override fun binding(): ActivityTodosBinding {
+        return ActivityTodosBinding.inflate(layoutInflater)
+    }
+
+    override fun vmClass(): Class<TodoListVModel> {
+        return TodoListVModel::class.java
+    }
+}

+ 199 - 0
app/src/main/java/com/ysnows/sultra/activity/TranslateActivity.kt

@@ -0,0 +1,199 @@
+package com.ysnows.sultra.activity
+
+import android.content.Intent
+import android.graphics.Rect
+import android.media.MediaPlayer
+import android.os.Build
+import android.os.Bundle
+import android.text.TextUtils
+import android.view.View
+import android.view.ViewTreeObserver.OnGlobalLayoutListener
+import android.widget.Button
+import android.widget.LinearLayout
+import android.widget.TextView
+import com.socks.library.KLog
+import com.ysnows.base.utils.Toasts
+import com.ysnows.sultra.R
+import com.ysnows.sultra.base.MBActivity
+import com.ysnows.sultra.databinding.ActivityTranslateBinding
+import com.ysnows.sultra.vmodel.TranslateVModel
+import com.zhy.http.okhttp.OkHttpUtils
+import com.zhy.http.okhttp.callback.StringCallback
+import okhttp3.Call
+import org.json.JSONException
+import org.json.JSONObject
+import java.io.IOException
+
+open class TranslateActivity : MBActivity<TranslateVModel, ActivityTranslateBinding>(), View.OnClickListener {
+    private var tvWord: TextView? = null
+    private var tvUsPron: TextView? = null
+    private var tvInterpret: TextView? = null
+    private var btnAddToWordbank: Button? = null
+    private var layAll: LinearLayout? = null
+    private var bundle: Bundle? = null
+    private var word: String? = null
+    private var mediaPlayer: MediaPlayer? = null
+    override fun __before() {
+        super.__before()
+        overridePendingTransition(R.anim.drop_down_from_top, 0)
+    }
+
+    override fun initCreate(savedInstanceState: Bundle?) {
+        super.initCreate(savedInstanceState)
+        val intent = intent
+        bundle = Bundle()
+        if (intent != null) {
+            if (Intent.ACTION_WEB_SEARCH == intent.action) {
+                val query = intent.getStringExtra("query")
+                bundle!!.putString("query", query)
+                bundle!!.putString("action", Intent.ACTION_WEB_SEARCH)
+            } else if (Build.VERSION.SDK_INT >= 23 && Intent.ACTION_PROCESS_TEXT == intent.action) {
+                bundle!!.putString("query", intent.getStringExtra("android.intent.extra.PROCESS_TEXT"))
+                bundle!!.putString("action", Intent.ACTION_PROCESS_TEXT)
+            }
+            processSearch(bundle)
+        }
+
+    }
+
+    override fun onNewIntent(intent: Intent) {
+        super.onNewIntent(intent)
+        overridePendingTransition(R.anim.drop_down_from_top, 0)
+        if (Intent.ACTION_WEB_SEARCH == intent.action) {
+            val query = intent.getStringExtra("query")
+            bundle!!.putString("query", query)
+            bundle!!.putString("action", Intent.ACTION_WEB_SEARCH)
+        } else if (Build.VERSION.SDK_INT >= 23 && Intent.ACTION_PROCESS_TEXT == intent.action) {
+            val query = intent.getStringExtra("android.intent.extra.PROCESS_TEXT")
+            bundle!!.putString("query", query)
+        }
+        processSearch(bundle)
+    }
+
+    private fun processSearch(bundle: Bundle?) {
+        val query = bundle!!.getString("query")
+        vm?.searchWord(query)
+    }
+
+    override fun initView(view: View?) {
+        super.initView(view)
+        tvWord = findViewById(R.id.tv_word)
+        tvUsPron = findViewById<View>(R.id.tv_us_pron) as TextView
+        tvInterpret = findViewById<View>(R.id.tv_interpret) as TextView
+        btnAddToWordbank = findViewById<View>(R.id.btn_add_to_wordbank) as Button
+        btnAddToWordbank!!.setOnClickListener(this@TranslateActivity)
+        layAll = findViewById<View>(R.id.lay_all) as LinearLayout
+        layAll!!.setOnClickListener(this@TranslateActivity)
+        window.decorView.setOnClickListener { v: View? -> onBackPressed() }
+        val decorView = window.decorView
+        val onGlobalLayoutListener: OnGlobalLayoutListener = object : OnGlobalLayoutListener {
+            private var keyboardHeight = 0
+            override fun onGlobalLayout() {
+                val rect = Rect()
+                decorView.getWindowVisibleDisplayFrame(rect)
+                //计算出可见屏幕的高度
+                val displayHight = rect.bottom - rect.top
+                //获得屏幕整体的高度
+                val hight = decorView.height
+//                KLog.a(rect.bottom)
+//                KLog.a(hight)
+                val keybordVisible = rect.bottom != hight
+                if (keybordVisible) {
+                    var statusBarHeight = 0
+                    try {
+                        val c = Class.forName("com.android.internal.R\$dimen")
+                        val obj = c.newInstance()
+                        val field = c.getField("status_bar_height")
+                        val x = field[obj].toString().toInt()
+                        statusBarHeight = context()!!.resources.getDimensionPixelSize(x)
+                    } catch (e: Exception) {
+                        e.printStackTrace()
+                    }
+
+                    //获得键盘高度
+                    keyboardHeight = hight - displayHight - statusBarHeight
+                } else if (keyboardHeight != 0) {
+                    keyboardHeight = 0
+                    onBackPressed()
+                }
+            }
+        }
+        decorView.viewTreeObserver.addOnGlobalLayoutListener(onGlobalLayoutListener)
+    }
+
+    override fun binding(): ActivityTranslateBinding {
+        return ActivityTranslateBinding.inflate(layoutInflater)
+    }
+
+    override val isRxbus: Boolean
+        get() = true
+
+
+    override fun title(): String? {
+        return null;
+    }
+
+    override fun onClick(view: View) {
+        if (view.id == R.id.btn_add_to_wordbank) {
+
+//            {"word":"Saturday","opcode":"1"}
+            if (TextUtils.isEmpty(word)) {
+                Toasts.toast(context(), "word is empty")
+                return
+            }
+            var exception = false
+            val jsonObject = JSONObject()
+            try {
+                jsonObject.put("word", word)
+                jsonObject.put("opcode", "1")
+            } catch (e: JSONException) {
+                e.printStackTrace()
+                exception = true
+            }
+            if (exception) {
+                Toasts.toast(context(), "sth is wrong")
+                return
+            }
+            OkHttpUtils.get()
+                    .url("https://1tyy.cn/insertNewWord.action")
+                    .addParams("newwordlist", jsonObject.toString())
+                    .addHeader("Cookie", "JSESSIONID=A652871FA3B0B7655AD87C9701396A29.tomcat1; user_web_token=UmtRK1FiWEl0cG1uNzdkL09PTmd6c0o5aldObjJ0VnFkM0tJOVE0TmZvWEFoclZaY3E3Ym9xRXRMYkpqIGJWc1p0Ty85SGdhbkQyRmNxckY5ZHVRMHVRPT0")
+                    .build()
+                    .execute(object : StringCallback() {
+                        override fun onError(call: Call, e: Exception, id: Int) {
+                            KLog.a(e.message)
+                            Toasts.toast(context(), e.message)
+                        }
+
+                        override fun onResponse(response: String, id: Int) {
+                            KLog.a(response)
+                            btnAddToWordbank!!.text = resources.getString(R.string.added)
+                            Toasts.toast(context(), resources.getString(R.string.add_success))
+                            onBackPressed()
+                        }
+                    })
+        } else if (view.id == R.id.lay_all) {
+            Thread {
+                try {
+                    if (!TextUtils.isEmpty(word)) {
+                        mediaPlayer = MediaPlayer()
+                        mediaPlayer!!.setDataSource("https://audio2.beingfine.cn/speeches/US/US-speech/$word.mp3")
+                        mediaPlayer!!.prepare()
+                        mediaPlayer!!.start()
+                    }
+                } catch (e: IOException) {
+                    e.printStackTrace()
+                }
+            }.start()
+        }
+    }
+
+    override fun onBackPressed() {
+        super.onBackPressed()
+        overridePendingTransition(0, R.anim.hide_to_top)
+    }
+
+    override fun vmClass(): Class<TranslateVModel> {
+        return TranslateVModel::class.java
+    }
+}

+ 80 - 0
app/src/main/java/com/ysnows/sultra/activity/VipBuyActivity.kt

@@ -0,0 +1,80 @@
+package com.ysnows.sultra.activity
+
+import android.os.Bundle
+import android.view.ViewGroup
+import androidx.core.content.res.ResourcesCompat
+import com.qmuiteam.qmui.util.QMUIDisplayHelper
+import com.qmuiteam.qmui.widget.grouplist.QMUICommonListItemView
+import com.qmuiteam.qmui.widget.grouplist.QMUIGroupListView
+import com.ysnows.base.base.BRepository
+import com.ysnows.sultra.R
+import com.ysnows.sultra.base.MBActivity
+import com.ysnows.sultra.databinding.ActivityVipBuyBinding
+import com.ysnows.sultra.repository.UserInfoRepository
+import com.ysnows.sultra.vmodel.VipBuyVModel
+
+open class VipBuyActivity : MBActivity<VipBuyVModel, ActivityVipBuyBinding>() {
+
+
+    override fun initCreate(savedInstanceState: Bundle?) {
+        super.initCreate(savedInstanceState)
+
+        addGroupListView()
+
+    }
+
+
+    private fun addGroupListView() {
+        val one: QMUICommonListItemView = binding.layGroupList.createItemView(
+                ResourcesCompat.getDrawable(resources, R.drawable.ic_no_ad, null),
+                "去广告",
+                "干净、纯洁、免打扰",
+                QMUICommonListItemView.VERTICAL,
+                QMUICommonListItemView.ACCESSORY_TYPE_NONE)
+
+        val two: QMUICommonListItemView = binding.layGroupList.createItemView(
+                ResourcesCompat.getDrawable(resources, R.drawable.ic_cloud_sync, null),
+                "云同步",
+                "云上、安全、不丢失",
+                QMUICommonListItemView.VERTICAL,
+                QMUICommonListItemView.ACCESSORY_TYPE_NONE)
+
+        val three: QMUICommonListItemView = binding.layGroupList.createItemView(
+                ResourcesCompat.getDrawable(resources, R.drawable.ic_no_limit, null),
+                "无限制",
+                "数量、时间、不限制",
+                QMUICommonListItemView.VERTICAL,
+                QMUICommonListItemView.ACCESSORY_TYPE_NONE)
+
+
+        val size: /*@@dmnjhl@@*/Int = QMUIDisplayHelper.dp2px(context(), 20)
+        QMUIGroupListView.newSection(context())
+                .setLeftIconSize(size, ViewGroup.LayoutParams.WRAP_CONTENT)
+                .addItemView(one, null)
+                .addItemView(two, null)
+                .addItemView(three, null)
+                .setMiddleSeparatorInset(QMUIDisplayHelper.dp2px(context(), 16), 0)
+                .addTo(binding.layGroupList)
+    }
+
+
+    override fun binding(): ActivityVipBuyBinding {
+        return ActivityVipBuyBinding.inflate(layoutInflater)
+    }
+
+    override fun vmClass(): Class<VipBuyVModel> {
+        return VipBuyVModel::class.java
+    }
+
+    override fun title(): String? {
+        return if (vm.user.value?.vip()!!) {
+            getString(R.string.renew_vip)
+        } else {
+            getString(R.string.unlock_vip)
+        }
+    }
+
+    override fun createRepository(): BRepository {
+        return UserInfoRepository()
+    }
+}

+ 25 - 0
app/src/main/java/com/ysnows/sultra/activity/WebViewActivity.kt

@@ -0,0 +1,25 @@
+package com.ysnows.sultra.activity
+
+import android.os.Bundle
+import com.ysnows.base.base.BRepository
+import com.ysnows.base.base.BViewModel
+import com.ysnows.sultra.base.MBActivity
+import com.ysnows.sultra.databinding.ActivityWebviewBinding
+
+open class WebViewActivity : MBActivity<BViewModel<BRepository>, ActivityWebviewBinding>() {
+
+    override fun initCreate(savedInstanceState: Bundle?) {
+        super.initCreate(savedInstanceState)
+        binding.webView.loadUrl(intent?.extras?.getString("url", "http://sultra.newintellij.com/private_policy.html"))
+    }
+
+    override fun binding(): ActivityWebviewBinding {
+        return ActivityWebviewBinding.inflate(layoutInflater)
+    }
+
+    override fun onDestroy() {
+        binding.webView.destroy()
+        super.onDestroy()
+    }
+
+}

+ 18 - 0
app/src/main/java/com/ysnows/sultra/adapter/AddFuncAdapter.kt

@@ -0,0 +1,18 @@
+package com.ysnows.sultra.adapter
+
+import com.chad.library.adapter.base.module.DraggableModule
+import com.chad.library.adapter.base.viewholder.BaseDataBindingHolder
+import com.ysnows.base.base.BAdapter
+import com.ysnows.sultra.R
+import com.ysnows.sultra.databinding.ItemFunctionBinding
+import com.ysnows.sultra.model.Func
+
+class AddFuncAdapter : BAdapter<Func, BaseDataBindingHolder<ItemFunctionBinding>>(R.layout.item_function, true), DraggableModule {
+
+
+    override fun convert(holder: BaseDataBindingHolder<ItemFunctionBinding>, item: Func) {
+        val binding = holder.dataBinding
+        binding?.item = item
+    }
+
+}

+ 35 - 0
app/src/main/java/com/ysnows/sultra/adapter/AddSearchEngineAdapter.kt

@@ -0,0 +1,35 @@
+package com.ysnows.sultra.adapter
+
+import com.chad.library.adapter.base.viewholder.BaseDataBindingHolder
+import com.ysnows.base.base.BAdapter
+import com.ysnows.sultra.R
+import com.ysnows.sultra.databinding.ItemSearchEngineBinding
+import com.ysnows.sultra.model.SearchEngine
+
+class AddSearchEngineAdapter : BAdapter<SearchEngine, BaseDataBindingHolder<ItemSearchEngineBinding>>(R.layout.item_search_engine, true) {
+
+
+    override fun convert(holder: BaseDataBindingHolder<ItemSearchEngineBinding>, item: SearchEngine) {
+        val dataBinding = holder.dataBinding
+        dataBinding?.item = item
+    }
+
+    fun setDefault(position: Int) {
+
+        for (i in 0 until data.size) {
+            val searchEngine = data[i]
+
+            if (searchEngine.is_default == 1) {
+                searchEngine.is_default = 0
+                notifyItemChanged(i)
+            } else {
+                if (i == position) {
+                    searchEngine.is_default = 1
+                    SearchEngine.setDefault(searchEngine)
+                    notifyItemChanged(i)
+                }
+            }
+        }
+
+    }
+}

+ 63 - 0
app/src/main/java/com/ysnows/sultra/adapter/AppAdapter.kt

@@ -0,0 +1,63 @@
+package com.ysnows.sultra.adapter
+
+import com.chad.library.adapter.base.viewholder.BaseDataBindingHolder
+import com.qmuiteam.qmui.kotlin.onClick
+import com.ysnows.base.base.BAdapter
+import com.ysnows.base.utils.PackageUtils
+import com.ysnows.sultra.R
+import com.ysnows.sultra.databinding.ItemAppSBinding
+import com.ysnows.sultra.model.AppModel
+
+class AppAdapter(mWidgetPosition: String) : BAdapter<AppModel, BaseDataBindingHolder<ItemAppSBinding>>(R.layout.item_app_s, null) {
+
+    override fun convert(holder: BaseDataBindingHolder<ItemAppSBinding>, item: AppModel) {
+        val binding = holder.dataBinding
+        binding?.item = item
+
+        binding?.imgAppInfo?.onClick {
+            PackageUtils.appInfo(context, item.packageName)
+        }
+
+//        appsMiniVH.cb_app_install.setOnCheckedChangeListener(null);
+//        val funcs = App.getCityLiteOrm().query(QueryBuilder(Func::class.java).where("local_url=?", LocalApi.CUSTOM_OPEN_APP).whereAnd("position=?", pos).whereAnd("packageName=?", item.packageName))
+        //        if (funcs != null && funcs.size() > 0) {
+//            appsMiniVH.cb_app_install.setChecked(true);
+//        } else {
+//            appsMiniVH.cb_app_install.setChecked(false);
+//        }
+
+
+//        appsMiniVH.cb_app_install.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
+//            @Override
+//            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+//
+//                if (isChecked) {
+//                    Func func = new Func();
+//                    func.position = pos;
+//                    func.name = appModel.name;
+//                    func.local_url = LocalApi.CUSTOM_OPEN_APP;
+//                    func.packageName = appModel.packageName;
+//
+//                    if (func.add() > 0) {
+//                        if (pos.equals(Func.POSITION_WIDGETS_RIGHT) || pos.equals(Func.POSITION_WIDGETS_LEFT)) {
+//                            RoundSearchWidget.sortFunctions(context);
+//                            SearchWidget.sortFunctions(context);
+//                        }
+////                        appsMiniVH.cb_app_install.setChecked(true);
+//                    }
+//                } else {
+//                    App.getCityLiteOrm().delete(new WhereBuilder(Func.class).where("local_url=?", LocalApi.CUSTOM_OPEN_APP).and("position=?", pos).and("packageName=?", appModel.packageName));
+//
+//                    if (pos.equals(Func.POSITION_WIDGETS_RIGHT) || pos.equals(Func.POSITION_WIDGETS_LEFT)) {
+//                        RoundSearchWidget.sortFunctions(context);
+//                    }
+//                }
+//            }
+//        });
+
+        holder.itemView.onClick {
+            PackageUtils.openApp(context, item.packageName)
+        }
+    }
+
+}

+ 99 - 0
app/src/main/java/com/ysnows/sultra/adapter/AppsAdapter.java

@@ -0,0 +1,99 @@
+package com.ysnows.sultra.adapter;
+
+import android.content.Context;
+import android.view.LayoutInflater;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import com.ysnows.sultra.R;
+import com.ysnows.sultra.model.AppModel;
+import com.ysnows.sultra.utils.PackageUtils;
+
+import java.util.ArrayList;
+
+import androidx.annotation.NonNull;
+import androidx.appcompat.widget.PopupMenu;
+import androidx.recyclerview.widget.RecyclerView;
+
+public class AppsAdapter extends RecyclerView.Adapter<AppsAdapter.VH> {
+
+
+    private ArrayList<AppModel> apps = new ArrayList<>();
+    private Context context;
+
+    public AppsAdapter(Context context) {
+        this.context = context;
+    }
+
+    @NonNull
+    @Override
+    public VH onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
+        View itemView = LayoutInflater.from(context).inflate(R.layout.item_app, null);
+        return new VH(itemView);
+    }
+
+    @Override
+    public void onBindViewHolder(@NonNull VH holder, int position) {
+        AppModel appInfo = this.apps.get(position);
+        holder.icon.setImageDrawable(appInfo.loadIcon());
+        holder.label.setText(appInfo.name);
+
+        holder.itemView.setOnClickListener(v -> {
+          PackageUtils.openApp(context,appInfo.packageName);
+        });
+
+        holder.itemView.setOnLongClickListener(new View.OnLongClickListener() {
+            @Override
+            public boolean onLongClick(View v) {
+                PopupMenu popupMenu = new PopupMenu(context, v);
+                popupMenu.inflate(R.menu.menu_app_context);
+                popupMenu.show();
+
+                popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
+                    @Override
+                    public boolean onMenuItemClick(MenuItem item) {
+                        switch (item.getItemId()) {
+                            case R.id.app_uninstall:
+                                PackageUtils.uninstall(context, appInfo.packageName);
+                                break;
+                            case R.id.app_info:
+                                PackageUtils.appInfo(context, appInfo.packageName);
+
+                                break;
+                        }
+                        return true;
+                    }
+                });
+
+                return true;
+            }
+        });
+
+    }
+
+    @Override
+    public int getItemCount() {
+        return apps.size();
+    }
+
+
+    class VH extends RecyclerView.ViewHolder {
+        private ImageView icon;
+        private TextView label;
+
+        public VH(View itemView) {
+            super(itemView);
+            icon = itemView.findViewById(R.id.icon);
+            label = itemView.findViewById(R.id.label);
+        }
+    }
+
+    public void setApps(ArrayList<AppModel> apps) {
+        this.apps.clear();
+        this.apps.addAll(apps);
+        this.notifyDataSetChanged();
+    }
+}

+ 41 - 0
app/src/main/java/com/ysnows/sultra/adapter/FuncAdapter.kt

@@ -0,0 +1,41 @@
+package com.ysnows.sultra.adapter
+
+import com.bumptech.glide.Glide
+import com.chad.library.adapter.base.viewholder.BaseDataBindingHolder
+import com.qmuiteam.qmui.kotlin.onClick
+import com.ysnows.base.base.BAdapter
+import com.ysnows.base.utils.PackageUtils
+import com.ysnows.base.utils.glide.GlideUtils
+import com.ysnows.sultra.R
+import com.ysnows.sultra.config.ConfigFuncType
+import com.ysnows.sultra.databinding.ItemFuncBinding
+import com.ysnows.sultra.model.Func
+import com.ysnows.sultra.utils.func.FuncAwoke
+
+class FuncAdapter() : BAdapter<Func, BaseDataBindingHolder<ItemFuncBinding>>(R.layout.item_func, null) {
+
+    override fun convert(holder: BaseDataBindingHolder<ItemFuncBinding>, item: Func) {
+        val binding = holder.dataBinding
+
+        binding?.item = item
+        binding?.imgIcon
+
+        if (item.type != ConfigFuncType.CUSTOM_OPEN_APP) {
+            Glide.with(context)
+                    .load(item.icon)
+                    .apply(GlideUtils.baseOptions().error(R.mipmap.ic_launcher_round))
+                    .into(binding?.imgIcon!!)
+        } else {
+            binding?.imgIcon?.setImageDrawable(PackageUtils.loadIcon(item.packageName))
+        }
+
+        binding?.imgIcon?.onClick {
+            FuncAwoke.awokeFunc(context, item)
+        }
+
+//        dataBinding?.position = position
+//        dataBinding?.pos = holder.adapterPosition
+    }
+
+
+}

+ 25 - 0
app/src/main/java/com/ysnows/sultra/adapter/FuncShopAdapter.kt

@@ -0,0 +1,25 @@
+package com.ysnows.sultra.adapter
+
+import com.chad.library.adapter.base.viewholder.BaseDataBindingHolder
+import com.qmuiteam.qmui.kotlin.onClick
+import com.ysnows.base.base.BAdapter
+import com.ysnows.sultra.R
+import com.ysnows.sultra.databinding.ItemShopFunctionBinding
+import com.ysnows.sultra.model.Func
+import com.ysnows.sultra.utils.func.FuncAwoke
+import com.ysnows.sultra.vmodel.FuncShopVModel
+
+class FuncShopAdapter(private val pos: String, private val vm: FuncShopVModel) : BAdapter<Func, BaseDataBindingHolder<ItemShopFunctionBinding>>(R.layout.item_shop_function, null) {
+
+    override fun convert(holder: BaseDataBindingHolder<ItemShopFunctionBinding>, item: Func) {
+        val binding = holder.dataBinding
+        binding?.item = item
+        binding?.pos = pos
+        binding?.position = holder.adapterPosition
+        binding?.vm = vm
+        holder.itemView.onClick {
+            FuncAwoke.awokeFunc(context, item)
+        }
+    }
+
+}

+ 23 - 0
app/src/main/java/com/ysnows/sultra/adapter/SearchBarAdapter.kt

@@ -0,0 +1,23 @@
+package com.ysnows.sultra.adapter
+
+import android.view.View
+import com.chad.library.adapter.base.viewholder.BaseDataBindingHolder
+import com.ysnows.base.base.BAdapter
+import com.ysnows.sultra.R
+import com.ysnows.sultra.databinding.ItemSearchBarBinding
+import com.ysnows.sultra.model.SearchEngine
+
+class SearchBarAdapter() : BAdapter<SearchEngine, BaseDataBindingHolder<ItemSearchBarBinding>>(R.layout.item_search_bar, null) {
+
+    override fun createBaseViewHolder(view: View): BaseDataBindingHolder<ItemSearchBarBinding> {
+        addChildClickViewIds(R.id.img_icon)
+        return super.createBaseViewHolder(view)
+    }
+
+    override fun convert(holder: BaseDataBindingHolder<ItemSearchBarBinding>, item: SearchEngine) {
+        val binding = holder.dataBinding
+        binding?.item = item
+    }
+
+
+}

+ 21 - 0
app/src/main/java/com/ysnows/sultra/adapter/ShopSearchEnginesAdapter.kt

@@ -0,0 +1,21 @@
+package com.ysnows.sultra.adapter
+
+import com.chad.library.adapter.base.viewholder.BaseDataBindingHolder
+import com.ysnows.base.base.BAdapter
+import com.ysnows.sultra.R
+import com.ysnows.sultra.databinding.ItemShopSearchengineBinding
+import com.ysnows.sultra.model.SearchEngine
+import com.ysnows.sultra.vmodel.SearchEngineShopVModel
+
+class ShopSearchEnginesAdapter(private val position: Int, private val vm: SearchEngineShopVModel) : BAdapter<SearchEngine, BaseDataBindingHolder<ItemShopSearchengineBinding>>(R.layout.item_shop_searchengine, null) {
+
+    override fun convert(helper: BaseDataBindingHolder<ItemShopSearchengineBinding>, item: SearchEngine) {
+        val dataBinding = helper.dataBinding
+
+        dataBinding?.item = item
+        dataBinding?.vm = vm
+        dataBinding?.position = position
+        dataBinding?.pos = helper.adapterPosition
+    }
+
+}

+ 126 - 0
app/src/main/java/com/ysnows/sultra/adapter/ShortCutAdapter.java

@@ -0,0 +1,126 @@
+package com.ysnows.sultra.adapter;
+
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.Bitmap;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import com.ysnows.sultra.R;
+import com.ysnows.sultra.model.ShortCutModel;
+
+import java.net.URISyntaxException;
+import java.util.ArrayList;
+
+import androidx.annotation.NonNull;
+import androidx.recyclerview.widget.RecyclerView;
+
+public class ShortCutAdapter extends RecyclerView.Adapter<ShortCutAdapter.VH> {
+
+
+    private ArrayList<ShortCutModel> apps = new ArrayList<>();
+    private Context context;
+
+    public ShortCutAdapter(Context context) {
+        this.context = context;
+    }
+
+    @NonNull
+    @Override
+    public VH onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
+        View itemView = LayoutInflater.from(context).inflate(R.layout.item_shortcut, null);
+        return new VH(itemView);
+    }
+
+    @Override
+    public void onBindViewHolder(@NonNull VH holder, int position) {
+        ShortCutModel shortCutModel = this.apps.get(position);
+        Bitmap imageBitmap = shortCutModel.loadIcon();
+        if (imageBitmap != null) {
+            holder.icon.setImageBitmap(imageBitmap);
+        }
+
+        if ("com.tencent.mm".equals(shortCutModel.packageName)) {
+            if ("BIZSHORTCUT".equals(shortCutModel.tag)) {
+                holder.icon_tag.setImageResource(R.drawable.ic_to_wxapp);
+            } else if ("WX_SHORTCUT".equals(shortCutModel.tag)) {
+                holder.icon_tag.setImageResource(R.drawable.ic_to_wxchat);
+            }
+        } else if ("com.miui.hybrid".equals(shortCutModel.packageName)) {
+            holder.icon_tag.setImageResource(R.drawable.ic_quik_app);
+        } else if ("com.android.chrome".equals(shortCutModel.packageName)) {
+            holder.icon_tag.setImageResource(R.drawable.ic_chrome);
+
+        }
+
+
+        holder.label.setText(shortCutModel.name);
+        holder.itemView.setOnClickListener(v -> {
+            try {
+                Intent intent = Intent.parseUri(shortCutModel.intent, 0);
+                if (intent != null) {
+                    context.startActivity(intent);
+                }
+            } catch (URISyntaxException e) {
+                e.printStackTrace();
+            }
+
+        });
+
+//        holder.itemView.setOnLongClickListener(new View.OnLongClickListener() {
+//            @Override
+//            public boolean onLongClick(View v) {
+//                PopupMenu popupMenu = new PopupMenu(context, v);
+//                popupMenu.inflate(R.menu.menu_app_context);
+//                popupMenu.show();
+//
+//                popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
+//                    @Override
+//                    public boolean onMenuItemClick(MenuItem item) {
+//                        switch (item.getItemId()) {
+//                            case R.id.app_uninstall:
+//                                PackageUtils.uninstall(context, shortCutModel.packageName);
+//                                break;
+//                            case R.id.app_info:
+//                                PackageUtils.appInfo(context, shortCutModel.packageName);
+//
+//                                break;
+//                        }
+//                        return true;
+//                    }
+//                });
+//
+//                return true;
+//            }
+//        });
+
+    }
+
+    @Override
+    public int getItemCount() {
+        return apps.size();
+    }
+
+
+    class VH extends RecyclerView.ViewHolder {
+        private ImageView icon;
+        private ImageView icon_tag;
+        private TextView label;
+
+        public VH(View itemView) {
+            super(itemView);
+            icon = itemView.findViewById(R.id.icon);
+            icon_tag = itemView.findViewById(R.id.icon_tag);
+            label = itemView.findViewById(R.id.label);
+        }
+    }
+
+    public void setShortCuts(ArrayList<ShortCutModel> shortCuts) {
+        this.apps.clear();
+        this.apps.addAll(shortCuts);
+        this.notifyDataSetChanged();
+    }
+}

+ 39 - 0
app/src/main/java/com/ysnows/sultra/adapter/TodosAdapter.java

@@ -0,0 +1,39 @@
+package com.ysnows.sultra.adapter;
+
+import android.graphics.Paint;
+import android.widget.TextView;
+
+import com.chad.library.adapter.base.viewholder.BaseDataBindingHolder;
+import com.ysnows.base.base.BAdapter;
+import com.ysnows.sultra.R;
+import com.ysnows.sultra.databinding.ItemTodoBinding;
+import com.ysnows.sultra.model.Todo;
+import com.ysnows.sultra.vmodel.TodoListVModel;
+
+import org.jetbrains.annotations.NotNull;
+
+public class TodosAdapter extends BAdapter<Todo, BaseDataBindingHolder<ItemTodoBinding>> {
+
+    private TodoListVModel vm;
+
+    public TodosAdapter(TodoListVModel vm) {
+        super(R.layout.item_todo, null);
+        this.vm = vm;
+    }
+
+    @Override
+    protected void convert(@NotNull BaseDataBindingHolder<ItemTodoBinding> helper, Todo todo) {
+        ItemTodoBinding binding = helper.getDataBinding();
+        binding.setItem(todo);
+        binding.setPosition(helper.getAdapterPosition());
+        binding.setVm(vm);
+
+        TextView tvName = helper.getView(R.id.tv_name);
+        if (todo.checked == 1) {
+            tvName.getPaint().setFlags(Paint.STRIKE_THRU_TEXT_FLAG); //中划线
+        } else {
+            tvName.getPaint().setFlags(0);  // 取消设置的的划线
+        }
+
+    }
+}

+ 31 - 0
app/src/main/java/com/ysnows/sultra/adapter/WebAppAdapter.java

@@ -0,0 +1,31 @@
+package com.ysnows.sultra.adapter;
+
+import android.widget.ImageView;
+
+import com.bumptech.glide.Glide;
+import com.chad.library.adapter.base.viewholder.BaseViewHolder;
+import com.ysnows.base.base.BAdapter;
+import com.ysnows.base.utils.glide.GlideUtils;
+import com.ysnows.sultra.R;
+import com.ysnows.sultra.model.Func;
+
+public class WebAppAdapter extends BAdapter<Func, BaseViewHolder> {
+
+    public int defaultPos;
+
+    public WebAppAdapter() {
+        super(R.layout.item_web_app, null);
+    }
+
+    @Override
+    protected void convert(BaseViewHolder helper, Func item) {
+        helper.setText(R.id.label, item.name);
+
+        Glide.with(getContext())
+                .load(item.icon)
+                .apply(GlideUtils.getoptions(getContext()).error(R.mipmap.ic_launcher))
+                .into((ImageView) helper.getView(R.id.icon));
+
+
+    }
+}

+ 28 - 0
app/src/main/java/com/ysnows/sultra/base/MBActivity.kt

@@ -0,0 +1,28 @@
+package com.ysnows.sultra.base
+
+import androidx.databinding.ViewDataBinding
+import com.ysnows.base.base.BActivity
+import com.ysnows.base.base.BViewModel
+import com.ysnows.base.inter.IUser
+import com.ysnows.base.utils.UiSwitch
+import com.ysnows.sultra.activity.LoginActivity
+import com.ysnows.sultra.model.User
+
+/**
+ * Mine Base Activity
+ *
+ * @param <VM>
+ * @param <B>
+</B></VM> */
+abstract class MBActivity<VM : BViewModel<*>, B : ViewDataBinding> : BActivity<VM, B>() {
+    override fun toLogin() {
+        super.toLogin()
+//        toast(R.string.please_login)
+        UiSwitch.single(context(), LoginActivity::class.java)
+    }
+
+    override fun user(): IUser? {
+        return User.get()
+    }
+
+}

+ 28 - 0
app/src/main/java/com/ysnows/sultra/base/MBFragment.kt

@@ -0,0 +1,28 @@
+package com.ysnows.sultra.base
+
+import androidx.databinding.ViewDataBinding
+import com.ysnows.base.base.BFragment
+import com.ysnows.base.base.BViewModel
+import com.ysnows.base.inter.IUser
+import com.ysnows.base.utils.UiSwitch
+import com.ysnows.sultra.activity.LoginActivity
+import com.ysnows.sultra.model.User
+
+/**
+ * Mine Base Fragment
+ *
+ * @param <VM>
+ * @param <B>
+</B></VM> */
+abstract class MBFragment<VM : BViewModel<*>, B : ViewDataBinding> : BFragment<VM, B>() {
+    override fun toLogin() {
+        super.toLogin()
+        UiSwitch.single(context(), LoginActivity::class.java)
+//        toast(R.string.please_login)
+
+    }
+
+    override fun user(): IUser? {
+        return User.get()
+    }
+}

+ 30 - 0
app/src/main/java/com/ysnows/sultra/base/MBRActivity.kt

@@ -0,0 +1,30 @@
+package com.ysnows.sultra.base
+
+import androidx.databinding.ViewDataBinding
+import com.chad.library.adapter.base.BaseQuickAdapter
+import com.chad.library.adapter.base.viewholder.BaseViewHolder
+import com.ysnows.base.base.BRActivity
+import com.ysnows.base.base.BRViewModel
+import com.ysnows.base.inter.IUser
+import com.ysnows.base.utils.UiSwitch
+import com.ysnows.sultra.activity.LoginActivity
+import com.ysnows.sultra.model.User
+
+/**
+ * Mine Base BRView Activity
+ *
+ * @param <VM>
+ * @param <A>
+ * @param <B>
+</B></A></VM> */
+abstract class MBRActivity<VM : BRViewModel<*>, A : BaseQuickAdapter<*, out BaseViewHolder>, B : ViewDataBinding> : BRActivity<VM, A, B>() {
+    override fun toLogin() {
+        super.toLogin()
+        UiSwitch.single(context(), LoginActivity::class.java)
+//        toast(R.string.please_login)
+    }
+
+    override fun user(): IUser? {
+        return User.get()
+    }
+}

+ 31 - 0
app/src/main/java/com/ysnows/sultra/base/MBRFragment.kt

@@ -0,0 +1,31 @@
+package com.ysnows.sultra.base
+
+import androidx.databinding.ViewDataBinding
+import com.chad.library.adapter.base.BaseQuickAdapter
+import com.chad.library.adapter.base.viewholder.BaseViewHolder
+import com.ysnows.base.base.BRFragment
+import com.ysnows.base.base.BRViewModel
+import com.ysnows.base.inter.IUser
+import com.ysnows.base.utils.UiSwitch
+import com.ysnows.sultra.activity.LoginActivity
+import com.ysnows.sultra.model.User
+
+/**
+ * Mine Base ReyclerView Activity
+ *
+ * @param <VM>
+ * @param <A>
+ * @param <B>
+</B></A></VM> */
+abstract class MBRFragment<VM : BRViewModel<*>, A : BaseQuickAdapter<*, out BaseViewHolder>, B : ViewDataBinding> : BRFragment<VM, A, B>() {
+
+    override fun toLogin() {
+        super.toLogin()
+        UiSwitch.single(context(), LoginActivity::class.java)
+//        toast(R.string.please_login)
+    }
+
+    override fun user(): IUser? {
+        return User.get()
+    }
+}

+ 100 - 0
app/src/main/java/com/ysnows/sultra/binder/FuncBinder.kt

@@ -0,0 +1,100 @@
+package com.ysnows.sultra.binder
+
+import android.app.PendingIntent
+import android.appwidget.AppWidgetManager
+import android.content.ComponentName
+import android.content.Context
+import android.content.Intent
+import android.graphics.Bitmap
+import android.graphics.drawable.BitmapDrawable
+import android.view.View
+import android.widget.RemoteViews
+import androidx.annotation.IdRes
+import com.bumptech.glide.Glide
+import com.bumptech.glide.request.target.SimpleTarget
+import com.bumptech.glide.request.transition.Transition
+import com.ysnows.base.utils.PackageUtils
+import com.ysnows.base.utils.glide.GlideUtils
+import com.ysnows.sultra.R
+import com.ysnows.sultra.RoundSearchWidget
+import com.ysnows.sultra.activity.MainActivity
+import com.ysnows.sultra.config.ConfigFuncType
+import com.ysnows.sultra.model.Func
+import com.ysnows.sultra.utils.SettingsUtil
+import com.ysnows.sultra.utils.func.FuncAwoke
+
+object FuncBinder {
+
+    fun bind(context: Context, remoteViews: RemoteViews, func: Func?, @IdRes id: Int) {
+
+        if (func == null) {
+            remoteViews.setViewVisibility(id, View.GONE)
+            updateRemoteView(context, remoteViews)
+            return
+        }
+        remoteViews.setViewVisibility(id, View.VISIBLE)
+
+
+
+        when {
+            (id == R.id.img_func_left) && SettingsUtil.pinGoogleIcon() -> {
+                remoteViews.setImageViewResource(id, R.drawable.ic_google)
+                configFuncLeft(remoteViews, id, func, context)
+            }
+
+            func.type == ConfigFuncType.CUSTOM_OPEN_APP -> {
+                val loadIcon = PackageUtils.loadIcon(func.packageName)
+                val bitmapDrawable = loadIcon as BitmapDrawable
+                remoteViews.setImageViewBitmap(id, bitmapDrawable.bitmap)
+
+                configFuncLeft(remoteViews, id, func, context)
+            }
+
+            else -> {
+                Glide.with(context)
+                        .asBitmap()
+                        .load(func.icon)
+                        .apply(GlideUtils.baseOptions().error(R.mipmap.ic_launcher_round))
+                        .into(object : SimpleTarget<Bitmap>() {
+                            override fun onResourceReady(resource: Bitmap, transition: Transition<in Bitmap>?) {
+                                remoteViews.setImageViewBitmap(id, resource)
+
+                                configFuncLeft(remoteViews, id, func, context)
+                            }
+                        })
+
+            }
+        }
+    }
+
+    private fun configFuncLeft(remoteViews: RemoteViews, @IdRes resId: Int, func: Func?, context: Context) {
+        if (func == null) {
+            return
+        }
+
+        val pendingIntent = FuncAwoke.awokePendingIntent(context, func)
+        remoteViews.setOnClickPendingIntent(resId, pendingIntent)
+
+        updateRemoteView(context, remoteViews)
+    }
+
+    private fun updateRemoteView(context: Context, remoteViews: RemoteViews) {
+        val instance = AppWidgetManager.getInstance(context);
+        instance.updateAppWidget(instance.getAppWidgetIds(ComponentName(context, RoundSearchWidget::class.java)), remoteViews);
+    }
+
+
+    fun bindSearchBar(context: Context, remoteViews: RemoteViews) {
+        val intent = Intent(context, MainActivity::class.java)
+        val pendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT)
+
+//        remoteViews.setTextViewText(R.id.tv_bar, "请使用 ${App.default_search.name} 搜索")
+
+        remoteViews.setOnClickPendingIntent(R.id.tv_bar, pendingIntent)
+        updateRemoteView(context, remoteViews)
+    }
+
+
+}
+
+

+ 47 - 0
app/src/main/java/com/ysnows/sultra/component/CpApp.kt

@@ -0,0 +1,47 @@
+package com.ysnows.sultra.component
+
+import android.content.Intent
+import com.billy.cc.core.component.CC
+import com.billy.cc.core.component.CCResult
+import com.billy.cc.core.component.IComponent
+import com.ysnows.base.ccextension.BIComponent
+import com.ysnows.base.utils.UiSwitch
+import com.ysnows.sultra.activity.LoginActivity
+import com.ysnows.sultra.activity.SettingsActivity
+import com.ysnows.sultra.activity.TodosActivity
+import com.ysnows.sultra.model.User
+
+open class CpApp() : IComponent, BIComponent() {
+
+    fun todoList(cc: CC): Boolean {
+        if (!User.isLogin()) {
+            UiSwitch.single(cc.context, LoginActivity::class.java)
+        } else {
+            UiSwitch.single_new_task(cc.context, TodosActivity::class.java)
+            CC.sendCCResult(cc.callId, CCResult.success())
+        }
+
+        return false
+    }
+
+    fun translate(cc: CC, query: String?): Boolean {
+        val intent = Intent()
+        intent.action = Intent.ACTION_WEB_SEARCH
+        intent.putExtra("query", query)
+        cc.context.startActivity(intent)
+        CC.sendCCResult(cc.callId, CCResult.success())
+        return false
+    }
+
+    fun settings(cc: CC): Boolean {
+
+        if (!User.isLogin()) {
+            UiSwitch.single(cc.context, LoginActivity::class.java)
+        } else {
+            UiSwitch.single(cc.context, SettingsActivity::class.java)
+            CC.sendCCResult(cc.callId, CCResult.success())
+        }
+
+        return false
+    }
+}

+ 45 - 0
app/src/main/java/com/ysnows/sultra/config/Config.kt

@@ -0,0 +1,45 @@
+package com.ysnows.sultra.config
+
+import com.ysnows.base.config.IConfig
+
+class Config : IConfig {
+    override fun baseUrl(): String? {
+        return "https://sultra-api.newintellij.com/api/"
+    }
+
+    override fun BBDCUrl(): String? {
+        return "https://1tyy.cn/"
+    }
+
+    override fun searchUrl(): String? {
+        return null
+    }
+
+    override fun imageUrl(): String? {
+        return null
+    }
+
+    override fun buglyAppId(): String? {
+        return "1dd6ba6727"
+    }
+
+    override fun ossEndpoint(): String? {
+        return null
+    }
+
+    override fun ossAccessKeyId(): String? {
+        return null
+    }
+
+    override fun ossBucket(): String? {
+        return null
+    }
+
+    override fun ossAccessKeySecret(): String? {
+        return null
+    }
+
+    override fun UmengAppKey(): String {
+        return "5f5603967823567fd8650597"
+    }
+}

+ 23 - 0
app/src/main/java/com/ysnows/sultra/config/ConfigFuncType.kt

@@ -0,0 +1,23 @@
+package com.ysnows.sultra.config
+
+object ConfigFuncType {
+
+    const val QR_MIUI = 0
+    const val QR_WX = 1
+    const val QR_ALIPAY = 2
+    const val QR_APP = 3
+    const val SEARCH_IN_BROWSER = 4
+    const val NORMAL_INTENT = 5
+    const val SHARE_INTENT = 6
+    const val NORMAL_INTENT_PARAMS = 7
+    const val NORMAL_TORCH = 8
+    const val URL_SCHEME = 9
+    const val URL_SCHEME_WITH_APP = 10
+    const val NORMAL_MUSIC = 11
+    const val NORMAL_INTENT_WITH_ACTION = 12
+    const val KEY_SIMULATE = 13
+    const val OPEN_APP = 14
+    const val CUSTOM_OPEN_APP = 15
+    const val SHELL = 16
+    const val URI = 17
+}

+ 9 - 0
app/src/main/java/com/ysnows/sultra/config/ConfigMMKV.kt

@@ -0,0 +1,9 @@
+package com.ysnows.sultra.config
+
+object ConfigMMKV {
+
+    const val FIRST_OPEN: String = "FIRST_OPEN"
+    const val AD_TIMES: String = "AD_TIMES"
+    const val REGISTER_TIME_START: String = "REGISTER_TIME_START"
+    const val USER = "user"
+}

+ 7 - 0
app/src/main/java/com/ysnows/sultra/config/ConfigPayWay.kt

@@ -0,0 +1,7 @@
+package com.ysnows.sultra.config
+
+object ConfigPayWay {
+
+    const val WX_PAY: Int = 1
+    const val ALI_PAY: Int = 2
+}

+ 15 - 0
app/src/main/java/com/ysnows/sultra/config/ConfigRx.kt

@@ -0,0 +1,15 @@
+package com.ysnows.sultra.config
+
+object ConfigRx {
+
+    const val LOGOUT: String="LOGOUT"
+    const val LOGIN: String="LOGIN"
+    const val ROUND_SEARCH_BAR_CHANGED: String = "ROUND_SEARCH_BAR_CHANGED"
+    const val ROUND_SEARCH_BAR_ITEM_ADDED: String = "ROUND_SEARCH_BAR_ITEM_ADDED"
+
+    const val SEARCH_BAR_CHANGED: String = "SEARCH_BAR_CHANGED"
+    const val SEARCH_BAR_ITEM_ADDED: String = "SEARCH_BAR_ITEM_ADDED"
+
+    const val DEFAULT_SEARCH_CHANGED: String = "DEFAULT_SEARCH_CHANGED"
+
+}

+ 9 - 0
app/src/main/java/com/ysnows/sultra/config/ConfigVipType.kt

@@ -0,0 +1,9 @@
+package com.ysnows.sultra.config
+
+object ConfigVipType {
+
+    const val VIP_MONTH: Int = 1
+    const val VIP_YEAR: Int = 2
+    const val VIP_PERMANENT: Int = 3
+
+}

+ 5 - 0
app/src/main/java/com/ysnows/sultra/config/MIntentAction.kt

@@ -0,0 +1,5 @@
+package com.ysnows.sultra.config
+
+object MIntentAction {
+    const val ACTION_UPDATE_APP_WIDGET: String = "action_update_app_widget"
+}

+ 39 - 0
app/src/main/java/com/ysnows/sultra/fragment/AppsFragment.kt

@@ -0,0 +1,39 @@
+package com.ysnows.sultra.fragment
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import com.ysnows.base.base.BRepository
+import com.ysnows.base.base.BViewModel
+import com.ysnows.sultra.adapter.AppAdapter
+import com.ysnows.sultra.base.MBFragment
+import com.ysnows.sultra.databinding.FragmentAppsBinding
+import com.ysnows.sultra.model.AppModel
+import com.ysnows.sultra.model.Func
+
+class AppsFragment : MBFragment<BViewModel<BRepository>, FragmentAppsBinding>() {
+
+    private var mWidgetPosition = Func.POS_FUNC_LEFT
+
+    override fun __before(savedInstanceState: Bundle?) {
+        super.__before(savedInstanceState)
+        mWidgetPosition = arguments?.getString("pos", Func.POS_FUNC_LEFT).toString()
+    }
+
+
+    override fun initView(view: View?) {
+        super.initView(view)
+        val adapter = AppAdapter(mWidgetPosition)
+        binding.recyclerView.adapter = adapter
+        adapter.setList(AppModel.findAllApps())
+    }
+
+    override fun binding(inflater: LayoutInflater, container: ViewGroup?): FragmentAppsBinding {
+        return FragmentAppsBinding.inflate(layoutInflater)
+    }
+
+    override fun title(): String? {
+        return null
+    }
+}

+ 43 - 0
app/src/main/java/com/ysnows/sultra/fragment/ShopFuncQuikFragment.kt

@@ -0,0 +1,43 @@
+package com.ysnows.sultra.fragment
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.ViewGroup
+import com.ysnows.base.net.IResponse
+import com.ysnows.sultra.adapter.FuncShopAdapter
+import com.ysnows.sultra.base.MBRFragment
+import com.ysnows.sultra.databinding.FragmentShopFuncQuikBinding
+import com.ysnows.sultra.model.Func
+import com.ysnows.sultra.utils.net.NetEngine
+import com.ysnows.sultra.vmodel.FuncShopVModel
+import io.reactivex.Observable
+
+class ShopFuncQuikFragment : MBRFragment<FuncShopVModel, FuncShopAdapter, FragmentShopFuncQuikBinding>() {
+    private var position = Func.POS_FUNC_RIGHT
+
+    override fun __before(savedInstanceState: Bundle?) {
+        super.__before(savedInstanceState)
+        position = arguments?.getString("pos", Func.POS_FUNC_RIGHT).toString()
+    }
+
+
+    override fun binding(inflater: LayoutInflater, container: ViewGroup?): FragmentShopFuncQuikBinding {
+        return FragmentShopFuncQuikBinding.inflate(layoutInflater)
+    }
+
+    override fun title(): String? {
+        return null
+    }
+
+    override fun initAdapter(): FuncShopAdapter {
+        return FuncShopAdapter(position,vm)
+    }
+
+    override fun api(): Observable<out IResponse<*>?> {
+        return NetEngine.service.getFuncs(3, vm.repository().autoPage())
+    }
+
+    override fun vmClass(): Class<FuncShopVModel> {
+        return FuncShopVModel::class.java
+    }
+}

+ 216 - 0
app/src/main/java/com/ysnows/sultra/fragment/WebFragment.kt

@@ -0,0 +1,216 @@
+package com.ysnows.sultra.fragment
+
+import android.graphics.Bitmap
+import android.os.Build
+import android.os.Bundle
+import android.view.KeyEvent
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.view.inputmethod.EditorInfo
+import android.webkit.*
+import android.widget.*
+import androidx.recyclerview.widget.RecyclerView
+import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
+import com.hwangjr.rxbus.annotation.Subscribe
+import com.hwangjr.rxbus.annotation.Tag
+import com.ysnows.base.base.BRepository
+import com.ysnows.base.base.BViewModel
+import com.ysnows.base.view.ProgressView
+import com.ysnows.sultra.R
+import com.ysnows.sultra.adapter.WebAppAdapter
+import com.ysnows.sultra.base.MBFragment
+import com.ysnows.sultra.databinding.FragmentWebBinding
+import com.ysnows.sultra.view.FuncShopView
+import java.io.UnsupportedEncodingException
+import java.net.URLEncoder
+
+class WebFragment : MBFragment<BViewModel<BRepository>, FragmentWebBinding>(), ProgressView {
+    protected var refresh_layout: SwipeRefreshLayout? = null
+    protected var webview: WebView? = null
+    protected var url = "https://www.baidu.com"
+    protected var rootView: View? = null
+    protected var layWebview: LinearLayout? = null
+    protected var imgAvatar: ImageView? = null
+    protected var edtName: EditText? = null
+    protected var imgScan: ImageView? = null
+    protected var recyclerView: RecyclerView? = null
+    protected var layNormal: LinearLayout? = null
+    private var progress: ProgressBar? = null
+    private var webAppAdapter: WebAppAdapter? = null
+    override fun __before(savedInstanceState: Bundle?) {
+        super.__before(savedInstanceState)
+        val extras = arguments
+        if (extras != null) {
+            url = extras.getString("url", "https://www.baidu.com")
+        }
+    }
+
+    override fun init(savedInstanceState: Bundle?) {
+        super.init(savedInstanceState)
+
+//        P().Q(NetEngine.getService().getFuncs(2, 1), new OnRes<ArrayList<Func>>() {
+//            @Override
+//            public void onCall(IResponse<ArrayList<Func>> res) {
+//                if (res.ok()) {
+//                    webAppAdapter.setNewData(res.data());
+//                }
+//            }
+//        });
+    }
+
+    override fun listeners() {
+        super.listeners()
+        imgScan!!.setOnClickListener { v: View? -> toast(resources.getString(R.string.jingqingqidai)) }
+        edtName!!.setOnEditorActionListener { v: TextView?, actionId: Int, event: KeyEvent? ->
+            if (actionId == EditorInfo.IME_ACTION_SEARCH) {
+                val kw = edtName!!.text.toString()
+                if (kw.startsWith("http://") || kw.startsWith("https://")) {
+                    url = kw
+                } else {
+                    var encodeStr: String? = null
+                    try {
+                        encodeStr = URLEncoder.encode(kw, "UTF-8")
+                    } catch (e: UnsupportedEncodingException) {
+                        e.printStackTrace()
+                    }
+                    url = String.format("https://m.baidu.com/s?wd=%s", encodeStr)
+                }
+                loadUrl(url)
+            }
+            false
+        }
+    }
+
+    override fun binding(inflater: LayoutInflater, container: ViewGroup?): FragmentWebBinding {
+        return FragmentWebBinding.inflate(layoutInflater)
+    }
+
+    override fun initView(rootView: View?) {
+        super.initView(rootView)
+        webview = rootView!!.findViewById(R.id.webview)
+        progress = rootView.findViewById(R.id.progress)
+        refresh_layout = rootView.findViewById(R.id.refresh_layout)
+        layWebview = rootView.findViewById(R.id.lay_webview)
+        imgAvatar = rootView.findViewById(R.id.img_avatar)
+        edtName = rootView.findViewById(R.id.edt_name)
+        imgScan = rootView.findViewById(R.id.img_scan)
+        recyclerView = rootView.findViewById(R.id.recycler_view)
+        layNormal = rootView.findViewById(R.id.lay_normal)
+        webAppAdapter = WebAppAdapter()
+        recyclerView?.adapter = webAppAdapter
+
+//        webAppAdapter.setOnItemClickListener(new BaseQuickAdapter.OnItemClickListener() {
+//            @Override
+//            public void onItemClick(BaseQuickAdapter adapter, View view, int position) {
+//                Func item = (Func) adapter.getItem(position);
+//                loadUrl(item.url);
+//
+//            }
+//        });
+
+        /*下拉刷新设置*/if (refresh_layout != null) {
+            refresh_layout!!.setColorSchemeResources(R.color.refresh_colorPrimary, R.color.refresh_colorAccent, R.color.refresh_colorPrimaryDark)
+            refresh_layout!!.setOnRefreshListener { onRefresh() }
+            refresh_layout!!.isEnabled = isNeedRefresh
+        }
+        val webSettings = webview?.getSettings()
+        webSettings?.javaScriptEnabled = true
+        webSettings?.domStorageEnabled = true
+        webSettings?.setAppCacheEnabled(true)
+        webSettings?.pluginState = WebSettings.PluginState.ON
+        webSettings?.useWideViewPort = true // 关键点
+        webSettings?.allowFileAccess = true // 允许访问文件
+        webSettings?.cacheMode = WebSettings.LOAD_NO_CACHE //没有缓存LOAD_NO_CACHE
+        webSettings?.databaseEnabled = true
+        webSettings?.builtInZoomControls = true
+        webSettings?.displayZoomControls = false
+        webSettings?.loadWithOverviewMode = true
+        // 支持通过js打开新的窗口
+        webSettings?.javaScriptCanOpenWindowsAutomatically = true
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+            webSettings?.mixedContentMode = WebSettings.MIXED_CONTENT_ALWAYS_ALLOW
+        }
+        webSettings?.setSupportZoom(false)
+        webview?.setWebViewClient(object : WebViewClient() {
+            override fun onPageStarted(view: WebView, url: String, favicon: Bitmap) {
+                super.onPageStarted(view, url, favicon)
+                val activity = activity
+                if (activity != null) {
+                    (activity as FuncShopView).setWebUrl(url)
+                }
+            }
+
+            override fun shouldOverrideUrlLoading(view: WebView, request: WebResourceRequest): Boolean {
+                view.loadUrl(request.url.toString())
+                return true
+            }
+
+            override fun onPageFinished(view: WebView, url: String) {
+                super.onPageFinished(view, url)
+                refreshing(false)
+                onProgressFinished()
+            }
+        })
+        webview?.setWebChromeClient(object : WebChromeClient() {
+            override fun onReceivedTitle(view: WebView, title: String) {
+                super.onReceivedTitle(view, title)
+                if (titleBar != null) {
+                    titleBar!!.setTitle(title)
+                }
+                val activity = activity
+                if (activity != null) {
+                    (activity as FuncShopView).setWebName(title)
+                }
+            }
+
+            override fun onProgressChanged(view: WebView, newProgress: Int) {
+                super.onProgressChanged(view, newProgress)
+                onProgress(newProgress)
+            }
+        })
+    }
+
+    private fun loadUrl(url: String) {
+        webview!!.loadUrl(url)
+        layNormal!!.visibility = View.GONE
+        (activity as FuncShopView?)!!.setNormalVisibility(View.GONE)
+    }
+
+    @Subscribe(tags = [Tag("WebViewBack")])
+    fun back(msg: String?) {
+        if (webview!!.canGoBack()) {
+            webview!!.goBack()
+        } else {
+            layNormal!!.visibility = View.VISIBLE
+            (activity as FuncShopView?)!!.setNormalVisibility(View.VISIBLE)
+        }
+    }
+
+    override val isNeedRefresh: Boolean
+        get() = true
+
+    override fun onRefresh() {
+        webview!!.reload()
+    }
+
+    override fun refreshing(refreshing: Boolean) {
+        refresh_layout!!.isRefreshing = refreshing
+    }
+
+    override fun onProgress(progress: Int) {
+        this.progress!!.visibility = View.VISIBLE
+        this.progress!!.progress = progress
+    }
+
+    override fun onProgressFinished() {
+        progress!!.visibility = View.GONE
+    }
+
+    override fun title(): String? {
+        return null
+    }
+
+    override val isRxbus: Boolean
+        get() = true
+}

+ 82 - 0
app/src/main/java/com/ysnows/sultra/model/AppModel.java

@@ -0,0 +1,82 @@
+package com.ysnows.sultra.model;
+
+import android.content.pm.PackageManager;
+import android.graphics.drawable.Drawable;
+import android.text.TextUtils;
+
+import com.github.promeg.pinyinhelper.Pinyin;
+import com.litesuits.orm.LiteOrm;
+import com.litesuits.orm.db.annotation.PrimaryKey;
+import com.litesuits.orm.db.annotation.Table;
+import com.litesuits.orm.db.annotation.Unique;
+import com.litesuits.orm.db.assit.QueryBuilder;
+import com.litesuits.orm.db.assit.WhereBuilder;
+import com.litesuits.orm.db.enums.AssignType;
+import com.ysnows.sultra.App;
+import com.ysnows.sultra.utils.PinyinUtil;
+
+import java.util.ArrayList;
+
+@Table("AppModel")
+public class AppModel {
+
+    //    // 指定自增,每个对象需要有一个主键
+    @PrimaryKey(AssignType.AUTO_INCREMENT)
+    @Unique
+    public int id;
+
+    public String packageName;
+    public String name;
+    public String pinyin;
+    public String pinyinSimple;
+
+
+    public AppModel(String packageName, String name) {
+        this.packageName = packageName;
+        this.name = name;
+        if (this.name != null) {
+            this.pinyin = PinyinUtil.getPinyin(this.name);
+            this.pinyinSimple = PinyinUtil.getPinyinSimple(this.name);
+        }
+    }
+
+    public Drawable loadIcon() {
+        try {
+            PackageManager packageManager = App.getApp().getPackageManager();
+            return packageManager.getPackageInfo(this.packageName, PackageManager.GET_META_DATA).applicationInfo.loadIcon(packageManager);
+        } catch (PackageManager.NameNotFoundException e) {
+            return null;
+        }
+    }
+
+    public static ArrayList<AppModel> findAppsByName(String name) {
+        if (TextUtils.isEmpty(name)) {
+            return null;
+        }
+        LiteOrm liteOrm = App.getLiteOrm();
+        ArrayList<AppModel> res = null;
+        if (Pinyin.isChinese(name.charAt(0))) {
+            res = liteOrm.query(new QueryBuilder<>(AppModel.class).where("name LIKE ?", "%" + name + "%"));
+        } else {
+            res = liteOrm.query(new QueryBuilder<>(AppModel.class).where("pinyin LIKE ?", "%" + name + "%"));
+        }
+        return res;
+    }
+
+    public static ArrayList<AppModel> findAllApps() {
+        LiteOrm liteOrm = App.getLiteOrm();
+        return liteOrm.query(new QueryBuilder<>(AppModel.class));
+    }
+
+    public void save() {
+        App.getLiteOrm().save(this);
+    }
+
+    public static void clear() {
+        App.getLiteOrm().delete(AppModel.class);
+    }
+
+    public static void delByPackage(String packageName) {
+        App.getLiteOrm().delete(new WhereBuilder(AppModel.class).where("packageName=?", packageName));
+    }
+}

+ 50 - 0
app/src/main/java/com/ysnows/sultra/model/AppSetting.java

@@ -0,0 +1,50 @@
+package com.ysnows.sultra.model;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+public class AppSetting implements Parcelable {
+
+    public Boolean pinGoogleIcon;
+    public Boolean autoAd;
+    public Boolean clipboardListener;
+    public Boolean showMsg;
+    public Boolean doubleClickPaste;
+
+    public AppSetting() {
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeValue(this.pinGoogleIcon);
+        dest.writeValue(this.autoAd);
+        dest.writeValue(this.clipboardListener);
+        dest.writeValue(this.showMsg);
+        dest.writeValue(this.doubleClickPaste);
+    }
+
+    protected AppSetting(Parcel in) {
+        this.pinGoogleIcon = (Boolean) in.readValue(Boolean.class.getClassLoader());
+        this.autoAd = (Boolean) in.readValue(Boolean.class.getClassLoader());
+        this.clipboardListener = (Boolean) in.readValue(Boolean.class.getClassLoader());
+        this.showMsg = (Boolean) in.readValue(Boolean.class.getClassLoader());
+        this.doubleClickPaste = (Boolean) in.readValue(Boolean.class.getClassLoader());
+    }
+
+    public static final Creator<AppSetting> CREATOR = new Creator<AppSetting>() {
+        @Override
+        public AppSetting createFromParcel(Parcel source) {
+            return new AppSetting(source);
+        }
+
+        @Override
+        public AppSetting[] newArray(int size) {
+            return new AppSetting[size];
+        }
+    };
+}

+ 9 - 0
app/src/main/java/com/ysnows/sultra/model/BBDCSearch.java

@@ -0,0 +1,9 @@
+package com.ysnows.sultra.model;
+
+public class BBDCSearch {
+
+    public String uk_pron;
+    public String interpret;
+    public String us_pron;
+    public String word;
+}

+ 13 - 0
app/src/main/java/com/ysnows/sultra/model/CMD.java

@@ -0,0 +1,13 @@
+package com.ysnows.sultra.model;
+
+import com.litesuits.orm.db.annotation.Table;
+
+@Table("cmd")
+public class CMD {
+
+    public String name;
+    public String desc;
+    public String numCMD;
+    public String stringCMD;
+
+}

+ 17 - 0
app/src/main/java/com/ysnows/sultra/model/ChargeCat.java

@@ -0,0 +1,17 @@
+package com.ysnows.sultra.model;
+
+import com.litesuits.orm.db.annotation.Table;
+
+@Table("ChargeCat")
+public class ChargeCat extends MultiItem {
+
+    @Override
+    public int getItemType() {
+        return 2;
+    }
+
+    public int id;
+    public String name;
+    public String avatar;
+    public int p_id;
+}

+ 51 - 0
app/src/main/java/com/ysnows/sultra/model/City.java

@@ -0,0 +1,51 @@
+package com.ysnows.sultra.model;
+
+import android.text.TextUtils;
+
+import com.github.promeg.pinyinhelper.Pinyin;
+import com.litesuits.orm.LiteOrm;
+import com.litesuits.orm.db.annotation.Table;
+import com.litesuits.orm.db.assit.QueryBuilder;
+import com.ysnows.sultra.App;
+
+import java.util.ArrayList;
+
+@Table("city")
+public class City {
+
+    public String City_ID;
+    public String City_EN;
+    public String City_EN_SIMPLE;
+    public String City_CN;
+    public String Country_code;
+    public String Country_EN;
+    public String Country_EN_SIMPLE;
+    public String Country_CN;
+    public String Province_EN;
+    public String Province_EN_SIMPLE;
+    public String Province_CN;
+    public String Latitude;
+    public String Longitude;
+    public String AD_code;
+
+
+    public static City findCityByName(String name) {
+        if (TextUtils.isEmpty(name)) {
+            return null;
+        }
+        LiteOrm liteOrm = App.getConfigOrm();
+        ArrayList<City> res = null;
+        if (Pinyin.isChinese(name.charAt(0))) {
+            res = liteOrm.query(new QueryBuilder<>(City.class).where("City_CN = ?", name));
+        } else {
+            res = liteOrm.query(new QueryBuilder<>(City.class).where("City_EN = ?", name));
+        }
+
+        if (res != null && res.size() > 0) {
+            return res.get(0);
+        }
+
+        return null;
+    }
+
+}

+ 122 - 0
app/src/main/java/com/ysnows/sultra/model/Contact.java

@@ -0,0 +1,122 @@
+package com.ysnows.sultra.model;
+
+
+import com.github.promeg.pinyinhelper.Pinyin;
+import com.litesuits.orm.LiteOrm;
+import com.litesuits.orm.db.annotation.Table;
+import com.litesuits.orm.db.assit.QueryBuilder;
+import com.ysnows.sultra.App;
+
+import java.util.ArrayList;
+
+@Table("Contact")
+public class Contact {
+    private String id;
+    private String name;
+    private String num;
+    private String pinyin;
+    private String pinyinSimple;
+    private Long taskId;
+
+    public void save() {
+        App.getLiteOrm().save(this);
+    }
+
+    public static void clear() {
+        App.getLiteOrm().delete(Contact.class);
+    }
+
+    public static ArrayList<Contact> findContactsByName(String name) {
+        LiteOrm liteOrm = App.getLiteOrm();
+        ArrayList<Contact> res = null;
+        if (Pinyin.isChinese(name.charAt(0))) {
+            res = liteOrm.query(new QueryBuilder<>(Contact.class).where("name LIKE ?", "%" + name + "%"));
+        } else {
+            res = liteOrm.query(new QueryBuilder<>(Contact.class).where("pinyin LIKE ?", "%" + name + "%"));
+        }
+        return res;
+    }
+
+
+    public void setTaskId(Long l) {
+        this.taskId = l;
+    }
+
+//    public static void sync(long j) {
+//        try {
+//            GreenDbManger.getInstance().getWritableDatabase().execSQL("delete from contact where _taskId < " + j);
+//        } catch (Exception e) {
+//            ApplicationDao.createTable(getDao().getDatabase(), true);
+//        }
+//    }
+
+//    private static ContactDao getDao() {
+//        return new DaoMaster(GreenDbManger.getInstance().getWritableDatabase()).newSession().getContactDao();
+//    }
+
+    public String getId() {
+        return this.id;
+    }
+
+    public void setId(String str) {
+        this.id = str;
+    }
+
+    public String getNum() {
+        return this.num;
+    }
+
+    public void setNum(String str) {
+        this.num = str;
+    }
+
+    public String getName() {
+        return this.name;
+    }
+
+    public void setName(String str) {
+        this.name = str;
+    }
+
+    public String getPinyin() {
+        return this.pinyin;
+    }
+
+    public void setPinyin(String str) {
+        this.pinyin = str;
+    }
+
+    public String getPinyinSimple() {
+        return this.pinyinSimple;
+    }
+
+    public void setPinyinSimple(String str) {
+        this.pinyinSimple = str;
+    }
+
+    public Long getTaskId() {
+        return this.taskId;
+    }
+
+
+    public Contact() {
+
+    }
+
+    public Contact(String name, String num, String id, Long taskId, String pinyinSimple, String pinyin) {
+        this.name = name;
+        this.num = num;
+        this.id = id;
+        this.taskId = taskId;
+        this.pinyinSimple = pinyinSimple;
+        this.pinyin = pinyin;
+    }
+
+//    public static List<Contact> findWithLimit(String str, int i) {
+//        return getDao().queryBuilder().getPinyin(Properties.Name.getPinyin("%" + str + "%"), Properties.Pinyin.getPinyin("%" + str + "%"), Properties.PinyinSimple.getPinyin("%" + str + "%")).getPinyin(i).getPinyinSimple();
+//    }
+
+//    public static List<Contact> find(String str) {
+//        return getDao().queryBuilder().getPinyin(Properties.Name.getPinyin("%" + str + "%"), Properties.Pinyin.getPinyin("%" + str + "%"), Properties.PinyinSimple.getPinyin("%" + str + "%")).getPinyinSimple();
+//    }
+}

+ 190 - 0
app/src/main/java/com/ysnows/sultra/model/Func.java

@@ -0,0 +1,190 @@
+package com.ysnows.sultra.model;
+
+import android.graphics.drawable.Drawable;
+
+import com.litesuits.orm.LiteOrm;
+import com.litesuits.orm.db.annotation.PrimaryKey;
+import com.litesuits.orm.db.annotation.Table;
+import com.litesuits.orm.db.annotation.Unique;
+import com.litesuits.orm.db.assit.QueryBuilder;
+import com.litesuits.orm.db.assit.WhereBuilder;
+import com.litesuits.orm.db.enums.AssignType;
+import com.ysnows.base.model.DbModel;
+import com.ysnows.sultra.App;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@Table("func")
+public class Func extends DbModel {
+
+    public static final String POS_FUNC_RIGHT = "position_widgets_right";
+    public static final String POS_FUNC_LEFT = "position_widgets_left";
+
+    @Unique
+    @PrimaryKey(AssignType.AUTO_INCREMENT)
+    public int f_id;
+
+    public int id;
+    public String name;
+    public String desc;
+    public String icon;
+
+    public Drawable iconDrawable;
+
+    public String packageName;
+    public String className;
+
+    public int type;
+    public int category;
+    public String url;
+
+    public int sort;
+    public String position = POS_FUNC_RIGHT;
+    public String paramsName;
+    public String paramsValue;
+
+    public static ArrayList<Func> findFunctions() {
+        LiteOrm cityLiteOrm = App.getConfigOrm();
+        ArrayList<Func> funcs = null;
+        if (cityLiteOrm != null) {
+            funcs = cityLiteOrm.query(new QueryBuilder<>(Func.class).orderBy("sort"));
+        }
+        return funcs;
+    }
+
+    public static ArrayList<Func> findFunctionsByPosition(String position) {
+        LiteOrm cityLiteOrm = App.getConfigOrm();
+        ArrayList<Func> funcs = null;
+        if (cityLiteOrm != null) {
+            funcs = cityLiteOrm.query(new QueryBuilder<>(Func.class).where("position=?", position).orderBy("sort"));
+        }
+        return funcs;
+    }
+
+    public static Func findLeftFunc() {
+        LiteOrm cityLiteOrm = App.getConfigOrm();
+        ArrayList<Func> funcs = null;
+        if (cityLiteOrm != null) {
+            funcs = cityLiteOrm.query(new QueryBuilder<>(Func.class).where("position=?", POS_FUNC_LEFT).orderBy("sort"));
+        }
+        return funcs == null ? null : (funcs.size() > 0 ? funcs.get(0) : null);
+    }
+
+    public static List<Func> findRightFuncList() {
+        LiteOrm cityLiteOrm = App.getConfigOrm();
+        List<Func> funcList = null;
+
+        if (cityLiteOrm != null) {
+            funcList = cityLiteOrm.query(new QueryBuilder<>(Func.class).where("position=?", POS_FUNC_RIGHT).orderBy("sort"));
+        }
+        return funcList == null ? new ArrayList<>() : funcList;
+    }
+
+    public static Func findFuncByPosition(String position) {
+        List<Func> funcList = findFunctionsByPosition(position);
+        if (funcList != null && funcList.size() > 0) {
+            return funcList.get(0);
+        }
+        return null;
+    }
+
+    public static void sortRightList(List<Func> rightFuncList) {
+        for (int i = 0; i < rightFuncList.size(); i++) {
+            rightFuncList.get(i).sort(i);
+        }
+    }
+
+    public void sort(int pos) {
+        this.sort = pos;
+        update();
+    }
+
+    public void del() {
+        App.getConfigOrm().delete(this);
+    }
+
+    public long add() {
+        ArrayList<Func> functions = findFunctions();
+        if (functions != null && functions.size() > 0) {
+            Func func = functions.get(functions.size() - 1);
+            this.sort += func.sort;
+        }
+
+        return App.getConfigOrm().save(this);
+    }
+
+    public void add(String pos) {
+        ArrayList<Func> functions = findFunctions();
+        if (functions != null && functions.size() > 0) {
+            Func func = functions.get(functions.size() - 1);
+            this.sort += func.sort;
+        }
+        this.position = pos;
+        App.getConfigOrm().save(this);
+    }
+
+    public static boolean exist(int id) {
+        Func func = findFuncById(id);
+        return func != null;
+    }
+
+    public static boolean exist(int id, String pos) {
+        ArrayList<Func> func = App.getConfigOrm().query(new QueryBuilder<>(Func.class).where("id=?", id).whereAnd("position=?", pos));
+        return func != null && func.size() > 0;
+    }
+
+    public boolean exist(String pos) {
+        ArrayList<Func> func = App.getConfigOrm().query(new QueryBuilder<>(Func.class).where("id=?", id).whereAnd("position=?", pos));
+        return func != null && func.size() > 0;
+    }
+
+    public void del(int id, String pos) {
+        int delete = App.getConfigOrm().delete(new WhereBuilder(Func.class).where("id=?", id).and("position=?", pos));
+    }
+
+    public void del(String pos) {
+        int delete = App.getConfigOrm().delete(new WhereBuilder(Func.class).where("id=?", id).and("position=?", pos));
+    }
+
+
+    public static Func findFuncById(int id) {
+        return App.getConfigOrm().queryById(id, Func.class);
+    }
+
+    public static String getGesturePos(String pos, String userAction) {
+        return pos + "_" + userAction;
+
+    }
+
+
+    @Override
+    public void update() {
+        App.getConfigOrm().update(this);
+    }
+
+    @Override
+    public long save() {
+        return App.getConfigOrm().save(this);
+    }
+
+
+    @Override
+    public String toString() {
+        return "Func{" +
+                "f_id=" + f_id +
+                ", id=" + id +
+                ", name='" + name + '\'' +
+                ", desc='" + desc + '\'' +
+                ", icon='" + icon + '\'' +
+                ", packageName='" + packageName + '\'' +
+                ", className='" + className + '\'' +
+                ", local_url=" + type +
+                ", url='" + url + '\'' +
+                ", sort=" + sort +
+                ", position='" + position + '\'' +
+                ", paramsName='" + paramsName + '\'' +
+                ", paramsValue='" + paramsValue + '\'' +
+                '}';
+    }
+}

+ 11 - 0
app/src/main/java/com/ysnows/sultra/model/LocalApiModel.java

@@ -0,0 +1,11 @@
+package com.ysnows.sultra.model;
+
+import com.litesuits.orm.db.annotation.Table;
+
+@Table("local_api")
+public class LocalApiModel {
+    public String name;
+    public String desc;
+    public String api;
+
+}

+ 9 - 0
app/src/main/java/com/ysnows/sultra/model/MultiItem.java

@@ -0,0 +1,9 @@
+package com.ysnows.sultra.model;
+
+import com.chad.library.adapter.base.entity.MultiItemEntity;
+import com.ysnows.base.model.DbModel;
+
+public abstract class MultiItem extends DbModel implements MultiItemEntity {
+
+
+}

+ 19 - 0
app/src/main/java/com/ysnows/sultra/model/Payway.java

@@ -0,0 +1,19 @@
+package com.ysnows.sultra.model;
+
+import com.litesuits.orm.db.annotation.PrimaryKey;
+import com.litesuits.orm.db.annotation.Table;
+import com.litesuits.orm.db.enums.AssignType;
+
+@Table("payway")
+public class Payway extends MultiItem {
+
+    @PrimaryKey(AssignType.BY_MYSELF)
+    public int id;
+    public String name;
+    public String avatar;
+
+    @Override
+    public int getItemType() {
+        return 1;
+    }
+}

+ 13 - 0
app/src/main/java/com/ysnows/sultra/model/Restore.java

@@ -0,0 +1,13 @@
+package com.ysnows.sultra.model;
+
+import com.ysnows.sultra.utils.SettingsUtil;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class Restore {
+
+    public List<SettingsUtil> settings = new ArrayList<>();
+    public List<Func> funcs = new ArrayList<>();
+    public List<SearchEngine> searchs = new ArrayList<>();
+}

+ 176 - 0
app/src/main/java/com/ysnows/sultra/model/SearchEngine.java

@@ -0,0 +1,176 @@
+package com.ysnows.sultra.model;
+
+import com.hwangjr.rxbus.RxBus;
+import com.litesuits.orm.LiteOrm;
+import com.litesuits.orm.db.annotation.PrimaryKey;
+import com.litesuits.orm.db.annotation.Table;
+import com.litesuits.orm.db.annotation.Unique;
+import com.litesuits.orm.db.assit.QueryBuilder;
+import com.litesuits.orm.db.assit.WhereBuilder;
+import com.litesuits.orm.db.enums.AssignType;
+import com.ysnows.sultra.App;
+import com.ysnows.sultra.config.ConfigRx;
+
+import org.jetbrains.annotations.NotNull;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@Table("search_engine")
+public class SearchEngine extends MultiItem {
+
+    public static final int POSITION_MAIN = 0;
+    public static final int POSITION_SEARCH_BAR = 1;
+
+    public static final int TYPE_SEARCH = 0;
+    public static final int TYPE_APP = 1;
+    public static final int TYPE_VIEW = 2;
+    public static final int TYPE_VIEW_WITH_URI = 8;
+    public static final int TYPE_SHARE = 3;
+    public static final int TYPE_QUICK_NOTE = 4;
+    public static final int TYPE_SHARE_ACTION = 7;
+    public static final int TYPE_IN_APP = 9;
+    public static final int TYPE_IN_CHARGE_OUT = 10;
+    public static final int TYPE_IN_CHARGE_IN = 11;
+    public static final int TYPE_API = 12;
+    public static final int TYPE_ROUTE = 13;
+    public static final int TYPE_ADD_TODO = 14;
+    public static final int CUSTOM_ENGINE_ID = -100;
+    // 指定自增,每个对象需要有一个主键
+
+    @Unique
+    @PrimaryKey(AssignType.AUTO_INCREMENT)
+    public int s_id;
+
+    public int id;
+
+    public String name;
+    public String icon;
+    public String url;
+    public String quik_key;
+    public String packageName;
+    public String className;
+    public int position = POSITION_MAIN;
+
+    public int type = TYPE_SEARCH;
+    public int is_default = 0;
+    private int sort = 0;
+    public String desc = "没有描述的描述是最寂寞的";
+
+    public SearchEngine() {
+
+    }
+
+    public SearchEngine(int type) {
+        this.type = type;
+    }
+
+    @Override
+    public long save() {
+        return App.getConfigOrm().save(this);
+
+    }
+
+
+    @Override
+    public void update() {
+        App.getConfigOrm().update(this);
+
+    }
+
+    public static ArrayList<SearchEngine> findAllSearchEngines(int position) {
+
+        LiteOrm liteOrm = App.getConfigOrm();
+        ArrayList<SearchEngine> res = liteOrm.query(new QueryBuilder<>(SearchEngine.class).where("position=?", position).orderBy("sort"));
+        return res;
+    }
+
+    public static List<SearchEngine> findSearchBarEngineList() {
+        return findAllSearchEngines(POSITION_SEARCH_BAR);
+    }
+
+
+    public static void setDefault(SearchEngine engine) {
+
+        SearchEngine aDefault = findDefault();
+        if (aDefault != null) {
+            aDefault.is_default = 0;
+            aDefault.save();
+        }
+
+        if (engine != null) {
+            engine.is_default = 1;
+            engine.save();
+            App.default_search = engine;
+            RxBus.get().post(ConfigRx.SEARCH_BAR_CHANGED, "search_engine");
+        }
+    }
+
+    public static SearchEngine findDefault() {
+        LiteOrm liteOrm = App.getConfigOrm();
+        ArrayList<SearchEngine> searchEngines = liteOrm.query(new QueryBuilder<>(SearchEngine.class).where("is_default=1"));
+        if (searchEngines != null && searchEngines.size() > 0) {
+            return searchEngines.get(0);
+        }
+
+        return null;
+    }
+
+    public void del() {
+        App.getConfigOrm().delete(this);
+    }
+
+    public void del(int position) {
+        if (s_id == 0) {
+            App.getConfigOrm().delete(new WhereBuilder(SearchEngine.class).where("id=?", id).and("position=?", position));
+        } else {
+            App.getConfigOrm().delete(this);
+        }
+    }
+
+    public long add() {
+        ArrayList<SearchEngine> searchEngines = findAllSearchEngines(POSITION_MAIN);
+        if (searchEngines != null && searchEngines.size() > 0) {
+            SearchEngine func = searchEngines.get(searchEngines.size() - 1);
+            this.sort += func.sort;
+        }
+
+        return App.getConfigOrm().save(this);
+    }
+
+    public boolean exist(int position) {
+        ArrayList arrayList = findById(id, position);
+
+        return arrayList != null && arrayList.size() > 0;
+    }
+
+
+    public static boolean exist(int id, int position) {
+        ArrayList arrayList = findById(id, position);
+
+        return arrayList != null && arrayList.size() > 0;
+    }
+
+    public static ArrayList findById(int id, int position) {
+        return App.getConfigOrm().query(new QueryBuilder(SearchEngine.class).where("id=?", id).whereAnd("position=?", position));
+    }
+
+
+    public void sort(int pos) {
+        this.sort = pos;
+        update();
+    }
+
+    @Override
+    public int getItemType() {
+        return 0;
+    }
+
+
+    public static void sortSearchBarEngineList(@NotNull List<SearchEngine> data) {
+        for (int i = 0; i < data.size(); i++) {
+            data.get(i).sort(i);
+        }
+
+    }
+}

+ 88 - 0
app/src/main/java/com/ysnows/sultra/model/ShortCutModel.java

@@ -0,0 +1,88 @@
+package com.ysnows.sultra.model;
+
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.text.TextUtils;
+
+import com.github.promeg.pinyinhelper.Pinyin;
+import com.litesuits.orm.LiteOrm;
+import com.litesuits.orm.db.annotation.PrimaryKey;
+import com.litesuits.orm.db.annotation.Table;
+import com.litesuits.orm.db.annotation.Unique;
+import com.litesuits.orm.db.assit.QueryBuilder;
+import com.litesuits.orm.db.assit.WhereBuilder;
+import com.litesuits.orm.db.enums.AssignType;
+import com.ysnows.sultra.App;
+import com.ysnows.sultra.utils.PinyinUtil;
+
+import java.util.ArrayList;
+
+@Table("ShortCutModel")
+public class ShortCutModel {
+
+    //    // 指定自增,每个对象需要有一个主键
+    @PrimaryKey(AssignType.AUTO_INCREMENT)
+    @Unique
+    public int id;
+
+    public String packageName;
+    public String name;
+    public String pinyin;
+    public String intent;
+    public byte[] icon;
+    public String iconResource;
+    public String tag;
+    public int iconType;
+    public String pinyinSimple;
+
+    public ShortCutModel(String packageName, String name) {
+        this.packageName = packageName;
+        this.name = name;
+
+        if (this.name != null) {
+            this.pinyin = PinyinUtil.getPinyin(this.name);
+            this.pinyinSimple = PinyinUtil.getPinyinSimple(this.name);
+        }
+    }
+
+    public Bitmap loadIcon() {
+
+        if (this.iconType == 1) {
+            int length = icon.length;
+            return BitmapFactory.decodeByteArray(icon, 0, length);
+        }
+
+        return null;
+    }
+
+    public static ArrayList<ShortCutModel> findAppsByName(String name) {
+        if (TextUtils.isEmpty(name)) {
+            return null;
+        }
+        LiteOrm liteOrm = App.getLiteOrm();
+        ArrayList<ShortCutModel> res = null;
+        if (Pinyin.isChinese(name.charAt(0))) {
+            res = liteOrm.query(new QueryBuilder<>(ShortCutModel.class).where("name LIKE ?", "%" + name + "%"));
+        } else {
+            res = liteOrm.query(new QueryBuilder<>(ShortCutModel.class).where("pinyin LIKE ?", "%" + name + "%"));
+        }
+        return res;
+    }
+
+    public static ArrayList<ShortCutModel> findAllApps() {
+        LiteOrm liteOrm = App.getLiteOrm();
+        return liteOrm.query(new QueryBuilder<>(ShortCutModel.class));
+    }
+
+    public void save() {
+        App.getLiteOrm().save(this);
+    }
+
+    public static void clear() {
+        App.getLiteOrm().delete(ShortCutModel.class);
+    }
+
+    public static void delByPackage(String packageName) {
+        App.getLiteOrm().delete(new WhereBuilder(ShortCutModel.class).where("packageName=?", packageName));
+    }
+}

+ 113 - 0
app/src/main/java/com/ysnows/sultra/model/Suggestion.java

@@ -0,0 +1,113 @@
+package com.ysnows.sultra.model;
+
+import java.util.ArrayList;
+
+public class Suggestion {
+    public static final int TYPE_APP = 1;
+    public static final int TYPE_CONTACTS = 2;
+    public static final int TYPE_CACULATE = 3;
+    public static final int TYPE_SEARCH_KW = 4;
+    public static final int TYPE_SMS = 5;
+    public static final int TYPE_WEATHER = 6;
+    public static final int TYPE_APP_MINI = 7;
+    public static final int TYPE_SHORTCUT = 8;
+    public static final int TYPE_SHORTCUT_MINI = 9;
+
+    private int type;
+
+    private ArrayList<AppModel> apps = new ArrayList<>();
+    private ArrayList<Contact> contacts = new ArrayList<>();
+    private String searchKW;
+    private ArrayList<String> smss = new ArrayList<>();
+    private Weather weather;
+    private String caculate;
+    private AppModel appMini;
+    private ArrayList<ShortCutModel> shortCuts;
+    private ShortCutModel shortCutMini;
+
+
+    public Suggestion(int type) {
+        this.type = type;
+    }
+
+    public ArrayList<AppModel> getApps() {
+        return apps;
+    }
+
+    public void setApps(ArrayList<AppModel> apps) {
+        this.apps = apps;
+    }
+
+    public ArrayList<Contact> getContacts() {
+        return contacts;
+    }
+
+    public void setContacts(ArrayList<Contact> contacts) {
+        this.contacts = contacts;
+    }
+
+
+    public String getSearchKW() {
+        return searchKW;
+    }
+
+    public void setSearchKW(String searchKW) {
+        this.searchKW = searchKW;
+    }
+
+    public ArrayList<String> getSmss() {
+        return smss;
+    }
+
+    public void setSmss(ArrayList<String> smss) {
+        this.smss = smss;
+    }
+
+    public String getCaculate() {
+        return caculate;
+    }
+
+    public void setCaculate(String caculate) {
+        this.caculate = caculate;
+    }
+
+    public int getType() {
+        return type;
+    }
+
+    public void setType(int type) {
+        this.type = type;
+    }
+
+    public Weather getWeather() {
+        return weather;
+    }
+
+    public void setWeather(Weather weather) {
+        this.weather = weather;
+    }
+
+    public void setAppMini(AppModel appMini) {
+        this.appMini = appMini;
+    }
+
+    public AppModel getAppMini() {
+        return appMini;
+    }
+
+    public void setShortCuts(ArrayList<ShortCutModel> shortCuts) {
+        this.shortCuts = shortCuts;
+    }
+
+    public void setShortCutMini(ShortCutModel shortCutMini) {
+        this.shortCutMini = shortCutMini;
+    }
+
+    public ArrayList<ShortCutModel> getShortCuts() {
+        return shortCuts;
+    }
+
+    public ShortCutModel getShortCutMini() {
+        return shortCutMini;
+    }
+}

+ 12 - 0
app/src/main/java/com/ysnows/sultra/model/Todo.java

@@ -0,0 +1,12 @@
+package com.ysnows.sultra.model;
+
+import com.ysnows.base.model.DbModel;
+
+public class Todo extends DbModel {
+
+    public int id;
+    public String title;
+    public String create_time;
+    public int checked;
+
+}

+ 120 - 0
app/src/main/java/com/ysnows/sultra/model/User.java

@@ -0,0 +1,120 @@
+package com.ysnows.sultra.model;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.ysnows.base.inter.IUser;
+import com.ysnows.base.utils.MMKVManager;
+import com.ysnows.sultra.config.ConfigMMKV;
+
+import org.jetbrains.annotations.Nullable;
+
+public class User implements IUser, Parcelable {
+
+    public String id;
+    public String nick_name;
+    public String avatar;
+    public String open_id;
+    public String bac_time;
+    public int create_time;
+    public String user_mobile;
+    public int vip;
+    public int ab_uid;
+    public String user_name;
+    public String vip_time;
+
+
+    @Nullable
+    @Override
+    public String id() {
+        return id;
+    }
+
+    @Nullable
+    @Override
+    public String nickName() {
+        return nick_name;
+    }
+
+    @Nullable
+    @Override
+    public String avatar() {
+        return avatar;
+    }
+
+    @Nullable
+    @Override
+    public String userName() {
+        return user_name;
+    }
+
+
+    @Nullable
+    public static User get() {
+        return MMKVManager.instance().decodeParcelable(ConfigMMKV.USER, User.class);
+    }
+
+    @Override
+    public boolean save() {
+        return MMKVManager.instance().encode(ConfigMMKV.USER, this);
+    }
+
+    public static boolean isLogin() {
+        return get() != null;
+    }
+
+
+    public User() {
+    }
+
+    @Override
+    public boolean vip() {
+        return vip == 1;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeString(this.id);
+        dest.writeString(this.nick_name);
+        dest.writeString(this.avatar);
+        dest.writeString(this.open_id);
+        dest.writeString(this.bac_time);
+        dest.writeInt(this.create_time);
+        dest.writeString(this.user_mobile);
+        dest.writeInt(this.vip);
+        dest.writeInt(this.ab_uid);
+        dest.writeString(this.user_name);
+        dest.writeString(this.vip_time);
+    }
+
+    protected User(Parcel in) {
+        this.id = in.readString();
+        this.nick_name = in.readString();
+        this.avatar = in.readString();
+        this.open_id = in.readString();
+        this.bac_time = in.readString();
+        this.create_time = in.readInt();
+        this.user_mobile = in.readString();
+        this.vip = in.readInt();
+        this.ab_uid = in.readInt();
+        this.user_name = in.readString();
+        this.vip_time = in.readString();
+    }
+
+    public static final Creator<User> CREATOR = new Creator<User>() {
+        @Override
+        public User createFromParcel(Parcel source) {
+            return new User(source);
+        }
+
+        @Override
+        public User[] newArray(int size) {
+            return new User[size];
+        }
+    };
+}

+ 143 - 0
app/src/main/java/com/ysnows/sultra/model/Weather.java

@@ -0,0 +1,143 @@
+package com.ysnows.sultra.model;
+
+import com.litesuits.orm.db.annotation.PrimaryKey;
+import com.litesuits.orm.db.annotation.Table;
+import com.litesuits.orm.db.annotation.Unique;
+import com.litesuits.orm.db.enums.AssignType;
+import com.ysnows.sultra.R;
+
+import java.util.List;
+
+@Table("weather")
+public class Weather {
+
+    public String city;
+    public String provinceName;
+
+    @PrimaryKey(AssignType.BY_MYSELF)
+    @Unique
+    public int cityid;
+
+    public RealtimeBean realtime;
+    public Pm25Bean pm25;
+    public WeatherDetailsInfoBean weatherDetailsInfo;
+    public List<WeathersBean> weathers;
+    public List<IndexesBean> indexes;
+    public List<AlarmsBean> alarms;
+
+
+    public static int getRes(String str) {
+        if (str.contains("晴")) {
+            return R.drawable.ic_sunny;
+        }
+        if (str.contains("阴")) {
+            return R.drawable.ic_overcast;
+        }
+        if (str.contains("云")) {
+            return R.drawable.ic_cloudy;
+        }
+        if (str.contains("风")) {
+            return R.drawable.ic_shower;
+        }
+        if (str.contains("雷")) {
+            return R.drawable.ic_thunder;
+        }
+        if (str.contains("雨")) {
+            return R.drawable.ic_sleet;
+        }
+        if (str.contains("雪")) {
+            return R.drawable.ic_snow;
+        }
+        if (str.contains("霾")) {
+            return R.drawable.ic_haze;
+        }
+        if (str.contains("雾")) {
+            return R.drawable.ic_haze;
+        }
+        return R.drawable.ic_sunny;
+    }
+
+
+    public static class RealtimeBean {
+        public String temp;
+        public String ziwaixian;
+        public String time;
+        public String weather;
+        public String img;
+        public String sendibleTemp;
+        public String sD;
+        public String wD;
+        public String wS;
+    }
+
+    public static class Pm25Bean {
+        public String so2;
+        public String o3;
+        public String timestamp;
+        public String co;
+        public String level;
+        public String color;
+        public String no2;
+        public String aqi;
+        public String quality;
+        public String pm10;
+        public String pm25;
+        public String advice;
+        public String upDateTime;
+        public int citycount;
+        public int cityrank;
+    }
+
+    public static class WeatherDetailsInfoBean {
+        public String publishTime;
+        public List<Weather24HoursDetailsInfosBean> weather24HoursDetailsInfos;
+
+        public static class Weather24HoursDetailsInfosBean {
+            public String img;
+            public String weather;
+            public String highestTemperature;
+            public String lowerestTemperature;
+            public String wd;
+            public String ws;
+            public String isRainFall;
+            public String precipitation;
+            public String startTime;
+            public String endTime;
+        }
+    }
+
+    public static class WeathersBean {
+        public String date;
+        public String week;
+        public String temp_day_c;
+        public String temp_day_f;
+        public String temp_night_c;
+        public String temp_night_f;
+        public String weather;
+        public String img;
+        public String wd;
+        public String ws;
+        public String sun_rise_time;
+        public String sun_down_time;
+    }
+
+    public static class IndexesBean {
+        public String abbreviation;
+        public String name;
+        public String level;
+        public String content;
+        public String alias;
+    }
+
+    public static class AlarmsBean {
+        public String alarmId;
+        public String alarmType;
+        public String alarmTypeDesc;
+        public String alarmLevelNo;
+        public String alarmLevelNoDesc;
+        public String alarmContent;
+        public String publishTime;
+        public String alarmDesc;
+        public String precaution;
+    }
+}

+ 8 - 0
app/src/main/java/com/ysnows/sultra/model/bbdc/Word.kt

@@ -0,0 +1,8 @@
+package com.ysnows.sultra.model.bbdc
+
+data class Word(
+    val interpret: String,
+    val uk_pron: String,
+    val us_pron: String,
+    val word: String
+)

+ 5 - 0
app/src/main/java/com/ysnows/sultra/model/bbdc/WordList.kt

@@ -0,0 +1,5 @@
+package com.ysnows.sultra.model.bbdc
+
+data class WordList(
+    val wordlist: List<Word>
+)

+ 44 - 0
app/src/main/java/com/ysnows/sultra/receiver/ActionBroadcastReceiver.java

@@ -0,0 +1,44 @@
+// Copyright 2015 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain init copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.ysnows.sultra.receiver;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+
+/**
+ * A BroadcastReceiver that handles the Action Intent from the Custom Tab and shows the Url
+ * in init Toast.
+ */
+public class ActionBroadcastReceiver extends BroadcastReceiver {
+    public static final String KEY_ACTION_SOURCE = "org.chromium.customtabsdemos.ACTION_SOURCE";
+    public static final int ACTION_ACTION_BUTTON = 1;
+    public static final int ACTION_MENU_ITEM = 2;
+    public static final int ACTION_TOOLBAR = 3;
+
+
+    @Override
+    public void onReceive(Context context, Intent intent) {
+        String url = intent.getDataString();
+        if (url != null) {
+            Intent intentApp = new Intent();
+            intentApp.setClassName("com.ideashower.readitlater.pro", "com.ideashower.readitlater.activity.AddActivity");
+            intentApp.putExtra(Intent.EXTRA_TEXT, url);
+            intentApp.addCategory(Intent.CATEGORY_HOME); // run in background
+            intentApp.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); //run in another task
+            context.startActivity(intentApp);
+        }
+    }
+}

+ 41 - 0
app/src/main/java/com/ysnows/sultra/receiver/AppListReceiver.java

@@ -0,0 +1,41 @@
+package com.ysnows.sultra.receiver;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+
+import com.ysnows.sultra.model.AppModel;
+
+public class AppListReceiver extends BroadcastReceiver {
+    @Override
+    public void onReceive(Context context, Intent intent) {
+        String action = intent.getAction();
+
+        String dataString = intent.getDataString();
+        if (Intent.ACTION_PACKAGE_ADDED.equals(action)) {
+
+            String[] split = dataString.split(":");
+
+            String packageName = split[1];
+
+            PackageManager packageManager = context.getPackageManager();
+
+            try {
+                ApplicationInfo applicationInfo = packageManager.getApplicationInfo(packageName, PackageManager.GET_META_DATA);
+
+                String name = applicationInfo.loadLabel(packageManager).toString();
+                AppModel appModel = new AppModel(packageName, name);
+                appModel.save();
+
+            } catch (PackageManager.NameNotFoundException e) {
+                e.printStackTrace();
+            }
+        } else if (Intent.ACTION_PACKAGE_REMOVED.equals(action)) {
+            String[] split = dataString.split(":");
+            String packageName = split[1];
+            AppModel.delByPackage(packageName);
+        }
+    }
+}

+ 183 - 0
app/src/main/java/com/ysnows/sultra/receiver/AssistantService.kt

@@ -0,0 +1,183 @@
+package com.ysnows.sultra.receiver
+
+import android.accessibilityservice.AccessibilityService
+import android.app.Notification
+import android.content.ClipboardManager
+import android.content.Intent
+import android.graphics.drawable.Icon
+import android.os.Build
+import android.os.Bundle
+import android.util.Log
+import android.view.accessibility.AccessibilityEvent
+import android.view.accessibility.AccessibilityNodeInfo
+import androidx.annotation.RequiresApi
+import com.socks.library.KLog
+import com.ysnows.base.utils.AccessibilityUtils
+import com.ysnows.base.utils.Toasts
+import com.ysnows.sultra.C.C
+import com.ysnows.sultra.R
+import com.ysnows.sultra.utils.SettingsUtil
+
+/**
+ * 助手服务类
+ * Created by zhangshuo on 2017/2/23.
+ */
+class AssistantService : AccessibilityService() {
+    private val TAG = AssistantService::class.java.simpleName
+    private var oldTimeMillis: Long = 0
+    var clipboardManager: ClipboardManager? = null
+        get() {
+            if (field == null) {
+                field = getSystemService(CLIPBOARD_SERVICE) as ClipboardManager
+            }
+            return field
+        }
+        private set
+
+    /**
+     * 必须重写的方法:此方法用了接受系统发来的event。在你注册的event发生时被调用。在整个生命周期会被调用多次。
+     */
+    @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
+    override fun onAccessibilityEvent(event: AccessibilityEvent) {
+        val eventType = event.eventType
+        val packageName: CharSequence
+        val className: String
+        val action: Int
+        when (eventType) {
+            AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED -> {
+                if (!SettingsUtil.showMsg()) {
+                    return
+                }
+                val pkg = event.packageName as String
+                val data = event.parcelableData
+                //判断是否是Notification对象
+                if (data != null && data is Notification) {
+                    val notification = data
+                    val o = notification.extras[Notification.EXTRA_LARGE_ICON]
+                    val intent = Intent(this, WindowViewReceiver::class.java)
+                    intent.action = C.Action.ACTION_NOTIFICATION_VIEW
+                    intent.putExtra(WindowViewReceiver.intentObj, notification.contentIntent)
+                    intent.putExtra(WindowViewReceiver.pkg, pkg)
+                    if (o != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+                        intent.putExtra(WindowViewReceiver.iconObj, o as Icon)
+                    }
+                    applicationContext.sendBroadcast(intent)
+                }
+            }
+            AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED -> {
+                packageName = event.packageName
+                className = event.className.toString()
+                if (!SettingsUtil.autoAd() || AccessibilityUtils.isAccessibilityView(className)) {
+                    return
+                }
+                action = event.action
+                Log.d(TAG, "窗口有变化:$className;包名:$packageName;动作:$action")
+
+                /*
+      微信几个页面的包名+地址。用于判断在哪个页面
+     */
+                val rootNode = rootInActiveWindow ?: return
+                val views = rootNode.findAccessibilityNodeInfosByText("跳过")
+                if (views.size > 0) {
+                    val view = views[0]
+                    if (view.isClickable) {
+                        view.performAction(AccessibilityNodeInfo.ACTION_CLICK)
+                        Toasts.toast(applicationContext, R.string.success_skip_ad)
+                    } else {
+                        val parent = view.parent ?: return
+                        if (parent.isClickable) {
+                            parent.performAction(AccessibilityNodeInfo.ACTION_CLICK)
+                            Toasts.toast(applicationContext, R.string.success_skip_ad)
+                        } else {
+                            val parentParent = parent.parent ?: return
+                            if (parentParent.isClickable) {
+                                parentParent.performAction(AccessibilityNodeInfo.ACTION_CLICK)
+                                Toasts.toast(applicationContext, R.string.success_skip_ad)
+                            }
+                        }
+                    }
+
+
+//                    oldPackageName = packageName;
+                }
+            }
+            AccessibilityEvent.TYPE_VIEW_CLICKED -> {
+                if (!SettingsUtil.doubleClickPaste()) {
+                    return
+                }
+                val classNameCharSequece = event.className
+                if (classNameCharSequece != null && classNameCharSequece == "android.widget.EditText") {
+                    //输入框不监控
+                    val currentTimeMillis = System.currentTimeMillis()
+                    val gap = currentTimeMillis - oldTimeMillis
+                    KLog.d(gap)
+                    if (gap < 200) {
+                        oldTimeMillis = currentTimeMillis
+                        //双击
+                        val source = event.source
+                        if (clipboardManager!!.hasPrimaryClip() && clipboardManager!!.primaryClip.itemCount > 0) {
+                            val addedText = clipboardManager!!.primaryClip.getItemAt(0).text
+                            val argumentsTest = Bundle()
+                            argumentsTest.putCharSequence(AccessibilityNodeInfo.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE, addedText)
+                            source.performAction(AccessibilityNodeInfo.ACTION_SET_TEXT, argumentsTest)
+                        }
+                    } else {
+                        oldTimeMillis = currentTimeMillis
+                    }
+                }
+            }
+            else -> {
+            }
+        }
+    }
+
+    override fun onInterrupt() {}
+    override fun onDestroy() {
+        super.onDestroy()
+        isAssistantRunning = false
+        instance = null
+    }
+
+    /**
+     * 服务已连接
+     */
+    override fun onServiceConnected() {
+        super.onServiceConnected()
+        isAssistantRunning = true
+        instance = this
+        Toasts.toast(applicationContext, "辅助服务已连接")
+    }
+    /**
+     * AccessibilityService中常用的方法的介绍
+     * disableSelf():禁用当前服务,也就是在服务可以通过该方法停止运行
+     * findFoucs(int falg):查找拥有特定焦点类型的控件
+     * getRootInActiveWindow():如果配置能够获取窗口内容,则会返回当前活动窗口的根结点
+     * getSeviceInfo():获取当前服务的配置信息
+     * onAccessibilityEvent(AccessibilityEvent event):有关AccessibilityEvent事件的回调函数,系统通过sendAccessibiliyEvent()不断的发送AccessibilityEvent到此处
+     * performGlobalAction(int action):执行全局操作,比如返回,回到主页,打开最近等操作
+     * setServiceInfo(AccessibilityServiceInfo info):设置当前服务的配置信息
+     * getSystemService(String name):获取系统服务
+     * onKeyEvent(KeyEvent event):如果允许服务监听按键操作,该方法是按键事件的回调,需要注意,这个过程发生了系统处理按键事件之前
+     * onServiceConnected():系统成功绑定该服务时被触发,也就是当你在设置中开启相应的服务,系统成功的绑定了该服务时会触发,通常我们可以在这里做一些初始化操作
+     * onInterrupt():服务中断时的回调
+     */
+    /**
+     * AccessibilityEvent的方法
+     * getEventType():事件类型
+     * getSource():获取事件源对应的结点信息
+     * getClassName():获取事件源对应类的类型,比如点击事件是有某个Button产生的,那么此时获取的就是Button的完整类名
+     * getText():获取事件源的文本信息,比如事件是有TextView发出的,此时获取的就是TextView的text属性。如果该事件源是树结构,那么此时获取的是这个树上所有具有text属性的值的集合
+     * isEnabled():事件源(对应的界面控件)是否处在可用状态
+     * getItemCount():如果事件源是树结构,将返回该树根节点下子节点的数量
+     */
+    companion object {
+        /**
+         * 助手服务是否正在运行
+         */
+        var isAssistantRunning = false
+        private val oldPackageName: CharSequence? = null
+        @JvmStatic
+        var instance: AssistantService? = null
+            private set
+    }
+}

+ 121 - 0
app/src/main/java/com/ysnows/sultra/receiver/ClipBoardListenService.java

@@ -0,0 +1,121 @@
+package com.ysnows.sultra.receiver;
+
+import android.app.Service;
+import android.content.ClipboardManager;
+import android.content.Context;
+import android.content.Intent;
+import android.os.IBinder;
+
+import com.ysnows.base.base.BApp;
+import com.ysnows.sultra.C.C;
+import com.ysnows.sultra.utils.ProcessUtil;
+
+import androidx.annotation.Nullable;
+
+public class ClipBoardListenService extends Service implements ClipboardManager.OnPrimaryClipChangedListener {
+
+    ClipboardManager clipboardManager;
+    private long oldTime = 0;
+    public static boolean running = false;
+
+
+    public ClipboardManager getClipboardManager() {
+        if (this.clipboardManager == null) {
+            clipboardManager = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);
+        }
+        return this.clipboardManager;
+    }
+
+    public static ClipboardManager getClipManager() {
+        return (ClipboardManager) BApp.instance().getSystemService(Context.CLIPBOARD_SERVICE);
+    }
+
+    @Override
+    public void onDestroy() {
+        super.onDestroy();
+        running = false;
+    }
+
+
+    public int onStartCommand(Intent intent, int flags, int startId) {
+        if (intent != null) {
+            String stringExtra = intent.getStringExtra("command");
+            if (stringExtra != null) {
+                int which = -1;
+                switch (stringExtra.hashCode()) {
+                    case 100571:
+                        if (stringExtra.equals("end")) {
+                            which = 1;
+                            break;
+                        }
+                        break;
+                    case 109757538:
+                        if (stringExtra.equals("start")) {
+                            which = 0;
+                            break;
+                        }
+                        break;
+                }
+                switch (which) {
+                    case 0:
+                        this.clipboardManager = getClipboardManager();
+                        this.clipboardManager.addPrimaryClipChangedListener(this);
+                        running = true;
+                        break;
+                    case 1:
+                        this.clipboardManager = getClipboardManager();
+                        this.clipboardManager.removePrimaryClipChangedListener(this);
+                        running = false;
+                        stopSelf();
+                        break;
+                    default:
+                        break;
+                }
+            }
+        }
+
+        return super.onStartCommand(intent, flags, startId);
+
+    }
+
+
+    @Nullable
+    @Override
+    public IBinder onBind(Intent intent) {
+        return null;
+    }
+
+
+    public static void start(Context context) {
+        if (!ClipBoardListenService.running) {
+            Intent intent = new Intent(context, ClipBoardListenService.class);
+            intent.putExtra("command", "start");
+            context.startService(intent);
+        }
+    }
+
+    public static void end(Context context) {
+        if (ClipBoardListenService.running) {
+            Intent intent = new Intent(context, ClipBoardListenService.class);
+            intent.putExtra("command", "end");
+            context.startService(intent);
+        }
+    }
+
+    @Override
+    public void onPrimaryClipChanged() {
+
+        if (getClipboardManager().hasPrimaryClip() && getClipboardManager().getPrimaryClip().getItemCount() > 0) {
+            CharSequence addedText = getClipboardManager().getPrimaryClip().getItemAt(0).getText();
+
+            long currentTimeMillis = System.currentTimeMillis();
+            if (addedText != null && ProcessUtil.b(getApplicationContext()) && (currentTimeMillis - oldTime > 200)) {
+                oldTime = currentTimeMillis;
+                Intent intent = new Intent(this, WindowViewReceiver.class);
+                intent.setAction(C.Action.ACTION_SEARCH_VIEW);
+                intent.putExtra(WindowViewReceiver.a, addedText.toString());
+                getApplicationContext().sendBroadcast(intent);
+            }
+        }
+    }
+}

+ 50 - 0
app/src/main/java/com/ysnows/sultra/receiver/FuncReceiver.java

@@ -0,0 +1,50 @@
+package com.ysnows.sultra.receiver;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.net.Uri;
+
+import com.billy.cc.core.component.CC;
+import com.socks.library.KLog;
+import com.ysnows.base.utils.ShellUtil;
+import com.ysnows.sultra.C.C;
+import com.ysnows.sultra.utils.FlashUtils;
+import com.ysnows.sultra.utils.KeySimulateUtils;
+import com.ysnows.sultra.utils.VoiceUtils;
+
+public class FuncReceiver extends BroadcastReceiver {
+    @Override
+    public void onReceive(Context context, Intent intent) {
+
+        String action = intent.getAction();
+
+        KLog.d("key_simulate: " + action);
+        String urls = intent.getStringExtra("url");
+
+        KLog.d("url: " + urls);
+
+        if (C.Action.ACTION_TORCH.equals(action)) {
+            new FlashUtils().switchFlash(context);
+        } else if (C.Action.ACTION_MUSIC.equals(action)) {
+            new VoiceUtils(context).music(Integer.valueOf(intent.getStringExtra("url")));
+        } else if (C.Action.ACTION_KEY_SIMULATE.equals(action)) {
+            KeySimulateUtils.simulate(Integer.valueOf(intent.getStringExtra("url")));
+        } else if (C.Action.ACTION_EXEC_SHELL.equals(action)) {
+            String url = intent.getStringExtra("url");
+            ShellUtil.checkRootPermission();
+            ShellUtil.execCommand(url, true);
+        } else if (C.Action.ACTION_EXEC_Uri.equals(action)) {
+            String urlStr = intent.getStringExtra("url");
+            Uri url = Uri.parse(urlStr);
+            String host = url.getHost();
+            String lastPathSegment = url.getLastPathSegment();
+            CC.obtainBuilder(host)
+                    .setContext(context)
+                    .setActionName(lastPathSegment)
+                    .build()
+                    .callAsync();
+        }
+    }
+
+}

+ 72 - 0
app/src/main/java/com/ysnows/sultra/receiver/ShortCutReceiver.java

@@ -0,0 +1,72 @@
+package com.ysnows.sultra.receiver;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.Bitmap;
+
+import com.litesuits.orm.db.assit.WhereBuilder;
+import com.ysnows.sultra.App;
+import com.ysnows.sultra.model.ShortCutModel;
+
+import java.io.ByteArrayOutputStream;
+
+public class ShortCutReceiver extends BroadcastReceiver {
+    @Override
+    public void onReceive(Context context, Intent intent) {
+        String action = intent.getAction();
+        if (action.equals("com.android.launcher.action.INSTALL_SHORTCUT")) {
+            Intent in = intent.getParcelableExtra(Intent.EXTRA_SHORTCUT_INTENT);
+            String aPackage = in.getPackage();
+            if (aPackage.equals("com.tencent.mm")) {
+                String name = intent.getStringExtra(Intent.EXTRA_SHORTCUT_NAME);
+                Bitmap bitmap = intent.getParcelableExtra(Intent.EXTRA_SHORTCUT_ICON);
+
+                ShortCutModel shortCutModel = new ShortCutModel(aPackage, name);
+
+
+                ByteArrayOutputStream stream = new ByteArrayOutputStream();
+                bitmap.compress(Bitmap.CompressFormat.PNG, 100, stream);
+                byte[] byteArray = stream.toByteArray();
+                bitmap.recycle();
+
+                shortCutModel.icon = byteArray;
+                shortCutModel.iconType = 1;
+                shortCutModel.intent = in.toUri(0);
+
+                if (shortCutModel.intent.contains("WX_SHORTCUT")) {
+                    //小程序
+                    shortCutModel.tag = "WX_SHORTCUT";
+
+                } else if (shortCutModel.intent.contains("BIZSHORTCUT")) {
+                    //联系人
+                    shortCutModel.tag = "BIZSHORTCUT";
+                }
+
+
+                shortCutModel.save();
+            }
+        } else if (action.equals("com.android.launcher.action.UNINSTALL_SHORTCUT")) {
+            Intent in = intent.getParcelableExtra(Intent.EXTRA_SHORTCUT_INTENT);
+            String aPackage = in.getPackage();
+            if (aPackage.equals("com.tencent.mm")) {
+                String name = intent.getStringExtra(Intent.EXTRA_SHORTCUT_NAME);
+                String inte = in.toUri(0);
+
+
+                String tag = null;
+                if (inte.contains("WX_SHORTCUT")) {
+                    //小程序
+                    tag = "WX_SHORTCUT";
+
+                } else if (inte.contains("BIZSHORTCUT")) {
+                    //联系人
+                    tag = "BIZSHORTCUT";
+                }
+
+                App.getLiteOrm().delete(new WhereBuilder(ShortCutModel.class).where("packageName=?", aPackage).and("name=?", name).and("tag=?", tag));
+
+            }
+        }
+    }
+}

+ 247 - 0
app/src/main/java/com/ysnows/sultra/receiver/WindowViewReceiver.java

@@ -0,0 +1,247 @@
+package com.ysnows.sultra.receiver;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ObjectAnimator;
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.Icon;
+import android.os.Build;
+import android.os.Parcelable;
+import android.text.TextUtils;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.WindowManager;
+import android.widget.ImageView;
+
+import com.ysnows.base.utils.PackageUtils;
+import com.ysnows.sultra.App;
+import com.ysnows.sultra.C.C;
+import com.ysnows.sultra.R;
+import com.ysnows.sultra.utils.IntentUtils;
+
+public class WindowViewReceiver extends BroadcastReceiver {
+    public static String a = "string";
+    public static String text = "text";
+    public static String intentObj = "intentObj";
+    public static String iconObj = "iconObj";
+    public static String pkg = "pkg";
+
+    private WindowManager wm;
+    private View view;
+    private WindowManager.LayoutParams params;
+    private int hw = 0;
+    private String kw;
+
+    public void onReceive(Context context, Intent intent) {
+        if (intent != null) {
+            String action = intent.getAction();
+            if (C.Action.ACTION_SEARCH_VIEW.equals(action)) {
+                kw = intent.getStringExtra(a);
+                if (kw != null) {
+                    addSearchView(context);
+                }
+            } else if (C.Action.ACTION_NOTIFICATION_VIEW.equals(action)) {
+                String pkgStr = intent.getStringExtra(pkg);
+                Parcelable parcelableExtra = intent.getParcelableExtra(intentObj);
+                PendingIntent pendingIntent = null;
+                if (parcelableExtra != null) {
+                    pendingIntent = (PendingIntent) parcelableExtra;
+                }
+
+                Parcelable iconExtra = intent.getParcelableExtra(WindowViewReceiver.iconObj);
+
+                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && iconExtra != null) {
+                    Icon icon = (Icon) iconExtra;
+                    addNotiView(context, pkgStr, pendingIntent, icon);
+                } else {
+                    addNotiView(context, pkgStr, pendingIntent, null);
+                }
+
+            }
+        }
+    }
+
+    private void rmNotiListernerView() {
+        if (wm != null) {
+            if (view != null) {
+                wm.removeView(view);
+                view = null;
+            }
+        }
+    }
+
+    private void addSearchView(Context context) {
+        if (wm == null) {
+            wm = (WindowManager) App.instance().getSystemService(Context.WINDOW_SERVICE);
+        }
+        if (params == null) {
+            params = new WindowManager.LayoutParams();
+        }
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+            params.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
+        } else {
+            params.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
+        }
+
+//        if (hw == 0) {
+//            hw = UiUtils.dp2Px(App.getInstance(), 66);
+//        }
+
+
+        params.format = 1;
+        params.width = WindowManager.LayoutParams.WRAP_CONTENT;
+        params.height = WindowManager.LayoutParams.WRAP_CONTENT;
+
+//        params.x = 0;
+        params.y = App.instance().getResources().getDisplayMetrics().heightPixels / 3;
+
+        params.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
+        params.gravity = 53;
+
+        if (view == null) {
+            LayoutInflater mInflater = LayoutInflater.from(App.instance());
+            view = mInflater.inflate(R.layout.window_paste_copy, null);
+            view.setOnClickListener(v -> {
+                hideTwo(view);
+                Intent intent = IntentUtils.searchIntent(context, kw);
+                context.startActivity(intent);
+            });
+        }
+
+        wm.addView(view, params);
+
+        if (view != null) {
+            show(view);
+        }
+
+        view.postDelayed(new Runnable() {
+            @Override
+            public void run() {
+                if (view != null) {
+                    hide(view);
+                }
+            }
+        }, 4500);
+    }
+
+    private void addNotiView(Context context, String pkgStr, PendingIntent pendingIntent, Icon largeIcon) {
+        if (wm == null) {
+            wm = (WindowManager) App.instance().getSystemService(Context.WINDOW_SERVICE);
+        }
+        if (params == null) {
+            params = new WindowManager.LayoutParams();
+        }
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+            params.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
+        } else {
+            params.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
+        }
+
+//        if (hw == 0) {
+//            hw = UiUtils.dp2Px(App.getInstance(), 66);
+//        }
+
+        params.format = 1;
+        params.width = WindowManager.LayoutParams.WRAP_CONTENT;
+        params.height = WindowManager.LayoutParams.WRAP_CONTENT;
+
+//        params.x = 0;
+        params.y = App.instance().getResources().getDisplayMetrics().heightPixels / 3;
+
+        params.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
+        params.gravity = 53;
+
+        if (view == null) {
+            LayoutInflater mInflater = LayoutInflater.from(App.instance());
+            view = mInflater.inflate(R.layout.window_paste_copy, null);
+            ImageView imgIcon = view.findViewById(R.id.img_icon);
+
+            Drawable drawable;
+            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && largeIcon != null) {
+                drawable = largeIcon.loadDrawable(context);
+            } else {
+                if (!TextUtils.isEmpty(pkgStr)) {
+                    drawable = PackageUtils.loadIcon(pkgStr);
+                } else {
+                    drawable = context.getResources().getDrawable(R.mipmap.ic_launcher);
+                }
+            }
+
+            imgIcon.setImageDrawable(drawable);
+
+            view.setOnClickListener(v -> {
+                hideTwo(view);
+
+                try {
+                    pendingIntent.send();
+                } catch (PendingIntent.CanceledException e) {
+                    e.printStackTrace();
+                }
+//                Intent intent = IntentUtils.searchIntent(context, kw);
+//                context.startActivity(intent);
+            });
+        }
+
+        wm.addView(view, params);
+
+        if (view != null) {
+            show(view);
+        }
+
+        view.postDelayed(new Runnable() {
+            @Override
+            public void run() {
+                if (view != null) {
+                    hide(view);
+                }
+            }
+        }, 4500);
+    }
+
+
+    private void show(View view) {
+        ObjectAnimator animatorX = ObjectAnimator.ofFloat(view, "scaleX", new float[]{0.0f, 1.2f, 1.0f}).setDuration(700);
+        ObjectAnimator animatorY = ObjectAnimator.ofFloat(view, "scaleY", new float[]{0.0f, 1.2f, 1.0f}).setDuration(700);
+        animatorX.start();
+        animatorY.start();
+    }
+
+    private void hide(View view) {
+        if (view == null) {
+            return;
+        }
+        ObjectAnimator animatorX = ObjectAnimator.ofFloat(view, "scaleX", new float[]{1.0f, 1.2f, 0.0f}).setDuration(700);
+        ObjectAnimator animatorY = ObjectAnimator.ofFloat(view, "scaleY", new float[]{1.0f, 1.2f, 0.0f}).setDuration(700);
+        animatorX.start();
+        animatorY.start();
+        animatorY.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                super.onAnimationEnd(animation);
+                rmNotiListernerView();
+            }
+        });
+    }
+
+    private void hideTwo(View view) {
+        if (view == null) {
+            return;
+        }
+        ObjectAnimator animatorX = ObjectAnimator.ofFloat(view, "scaleX", new float[]{1.0f, 0.0f}).setDuration(400);
+        ObjectAnimator animatorY = ObjectAnimator.ofFloat(view, "scaleY", new float[]{1.0f, 0.0f}).setDuration(400);
+        animatorX.start();
+        animatorY.start();
+        animatorY.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                super.onAnimationEnd(animation);
+                rmNotiListernerView();
+            }
+        });
+    }
+
+}

+ 34 - 0
app/src/main/java/com/ysnows/sultra/repository/LoginRepository.kt

@@ -0,0 +1,34 @@
+package com.ysnows.sultra.repository
+
+import android.annotation.SuppressLint
+import com.hwangjr.rxbus.RxBus
+import com.ysnows.base.base.BRepository
+import com.ysnows.sultra.config.ConfigRx
+import com.ysnows.sultra.model.User
+import com.ysnows.sultra.utils.net.NetEngine
+import com.ysnows.sultra.utils.net.Response
+import io.reactivex.ObservableSource
+import io.reactivex.functions.Function
+
+class LoginRepository : BRepository() {
+    @SuppressLint("CheckResult")
+    fun login(userName: String?, passWord: String?) {
+        lreq(NetEngine.service.login(userName, passWord))
+                .concatMap(Function<Response<Any>, ObservableSource<Response<User>>?> {
+                    if (it.ok(true)) {
+                        lreq(NetEngine.service.getUser())
+                    } else {
+                        null
+                    }
+                })
+                .doOnNext {
+                    it.data()?.save().apply {
+                        RxBus.get().post(ConfigRx.LOGIN, "settings")
+                        view()?.finishActivity()
+                    }
+                }
+                .subscribe()
+    }
+
+
+}

+ 46 - 0
app/src/main/java/com/ysnows/sultra/repository/MainPresenter.java

@@ -0,0 +1,46 @@
+package com.ysnows.sultra.repository;
+
+import com.ysnows.sultra.view.MainView;
+
+public class MainPresenter<V extends MainView> {
+
+
+//    public void getBaiduHotWords(String kw) {
+//        String url = Api.getBaiduHotWord(kw);
+//
+//        OkNetUtils.get(url, new SuccessCallBack() {
+//            @Override
+//            public void onSuccess(String res) {
+//                try {
+//                    JSONArray jsonArray = new JSONArray(res);
+//                    JSONArray array = jsonArray.optJSONArray(1);
+//                    List<String> words = new Gson().fromJson(array.toString(), new TypeToken<List<String>>() {
+//                    }.getType());
+//
+//                    if (words.size() > 5) {
+//                        words = words.subList(0, 5);
+//                    }
+//
+//                    getView().showWords(words);
+//
+//                } catch (JSONException e) {
+//                    e.printStackTrace();
+//                }
+//            }
+//        });
+//    }
+//
+//    public void findWeather(String kw) {
+//        City city = City.findCityByName(kw);
+//        if (city != null) {
+//            String url = Api.getWeather(city.City_ID.substring(2, city.City_ID.length()));
+//            OkNetUtils.get(url, new SuccessCallBack() {
+//                @Override
+//                public void onSuccess(String res) {
+//                    Weather weather = new Gson().fromJson(res, Weather.class);
+//                    getView().setWeather(weather);
+//                }
+//            });
+//        }
+//    }
+}

+ 65 - 0
app/src/main/java/com/ysnows/sultra/repository/RegisterRepository.kt

@@ -0,0 +1,65 @@
+package com.ysnows.sultra.repository
+
+import android.annotation.SuppressLint
+import com.ysnows.base.base.BRepository
+import com.ysnows.sultra.R
+import com.ysnows.sultra.model.User
+import com.ysnows.sultra.utils.net.NetEngine
+import com.ysnows.sultra.utils.net.Response
+import io.reactivex.Observable
+import io.reactivex.functions.Function
+
+class RegisterRepository : BRepository() {
+
+    @SuppressLint("CheckResult")
+    fun login(userName: String?, passWord: String?) {
+        lreq(NetEngine.service.login(userName, passWord))
+                .concatMap(Function<Response<Any>, Observable<User>> {
+                    if (it.ok(true)) {
+                        lreq(NetEngine.service.getUser())
+                    }
+                    null
+                })
+                .doOnNext {
+                    it.save()
+                }
+                .subscribe()
+    }
+
+    fun register(phone: String?, code: String?, passWord: String?, passWordAgain: String?): Observable<Response<Any>>? {
+        if (phone.isNullOrEmpty()) {
+            toast(R.string.please_input_user_name)
+            return null
+        }
+        if (code.isNullOrEmpty()) {
+            toast(R.string.please_input_code)
+            return null
+        }
+        if (passWord.isNullOrEmpty()) {
+            toast(R.string.please_input_pwd)
+            return null
+        }
+        if (passWordAgain.isNullOrEmpty()) {
+            toast(R.string.please_input_pwd_twice)
+            return null
+        }
+
+        if (passWord != passWordAgain) {
+            toast(R.string.password_not_equal)
+            return null
+        }
+
+        return Observable.create { emitter ->
+            lreq(NetEngine.service.register(phone, code, passWord))
+                    .doOnNext() {
+                        if (it.ok(true)) {
+                            emitter.onNext(it)
+                        }
+                    }
+                    .subscribe()
+
+        }
+    }
+
+
+}

+ 22 - 0
app/src/main/java/com/ysnows/sultra/repository/SearchRepository.kt

@@ -0,0 +1,22 @@
+package com.ysnows.sultra.repository
+
+import com.ysnows.base.base.BRepository
+import com.ysnows.sultra.utils.net.NetEngine
+import com.ysnows.sultra.utils.net.Response
+import io.reactivex.Observable
+
+class SearchRepository : BRepository() {
+
+    fun addTodo(kw: String): Observable<Response<Any>> {
+        return Observable.create { emitter ->
+            req(NetEngine.service.addTodo(kw))
+                    .doOnNext() {
+                        toast(it.msg())
+                        emitter.onNext(it)
+                    }
+                    .subscribe()
+        }
+    }
+
+
+}

+ 26 - 0
app/src/main/java/com/ysnows/sultra/repository/UserInfoRepository.kt

@@ -0,0 +1,26 @@
+package com.ysnows.sultra.repository
+
+import com.ysnows.base.base.BRepository
+import com.ysnows.sultra.model.User
+import com.ysnows.sultra.utils.net.NetEngine
+import io.reactivex.Observable
+
+class UserInfoRepository : BRepository() {
+
+    fun getUserInfo(): Observable<User> {
+        return Observable.create { emitter ->
+            req(NetEngine.service.getUser())
+                    .doOnNext() {
+                        if (it.ok()) {
+                            it.data()?.let { user ->
+                                user.save()
+                                emitter.onNext(user)
+                            }
+                        }
+                    }
+                    .subscribe()
+        }
+    }
+
+
+}

+ 73 - 0
app/src/main/java/com/ysnows/sultra/utils/CheckUtil.java

@@ -0,0 +1,73 @@
+package com.ysnows.sultra.utils;
+
+import android.app.ActivityManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.text.TextUtils;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class CheckUtil {
+
+    //检测service是否在运行
+    public static boolean isServiceWorked(Context context, String serviceName) {
+        ActivityManager myManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
+        ArrayList<ActivityManager.RunningServiceInfo> runningService = (ArrayList<ActivityManager.RunningServiceInfo>) myManager.getRunningServices(Integer.MAX_VALUE);
+        for (int i = 0; i < runningService.size(); i++) {
+            if (runningService.get(i).service.getClassName().equals(serviceName)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    //检测activity是否存在再栈顶
+    public static boolean isForeground(Context context, String PackageName) {
+        ActivityManager myManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
+        List<ActivityManager.RunningTaskInfo> task = myManager.getRunningTasks(1);
+        ComponentName componentInfo = task.get(0).topActivity;
+        if (componentInfo.getPackageName().equals(PackageName))
+            return true;
+        return false;
+    }
+
+    /**
+     * 判断某个app进程是否在运行
+     *
+     * @param context
+     * @param appInfo
+     *
+     * @return
+     */
+    public static boolean isRunningProcess(Context context, String appInfo) {
+        ActivityManager myManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
+        List<ActivityManager.RunningAppProcessInfo> runningAppPs = myManager.getRunningAppProcesses();
+        if (runningAppPs != null && runningAppPs.size() > 0) {
+            if (runningAppPs.contains(appInfo)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * 判断一个Activity是否正在运行
+     *
+     * @param pkg pkg为应用包名
+     * @param cls cls为类名eg
+     * @param context
+     *
+     * @return
+     */
+    public static boolean isClsRunning(Context context, String pkg, String cls) {
+        ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
+        List<ActivityManager.RunningTaskInfo> tasks = am.getRunningTasks(1);
+        ActivityManager.RunningTaskInfo task = tasks.get(0);
+        if (task != null) {
+            return TextUtils.equals(task.topActivity.getPackageName(), pkg) &&
+                    TextUtils.equals(task.topActivity.getClassName(), cls);
+        }
+        return false;
+    }
+}

+ 191 - 0
app/src/main/java/com/ysnows/sultra/utils/CustomTabActivityHelper.java

@@ -0,0 +1,191 @@
+// Copyright 2015 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain init copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.ysnows.sultra.utils;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Bundle;
+
+import java.util.List;
+
+import androidx.browser.customtabs.CustomTabsClient;
+import androidx.browser.customtabs.CustomTabsIntent;
+import androidx.browser.customtabs.CustomTabsServiceConnection;
+import androidx.browser.customtabs.CustomTabsSession;
+import shared.CustomTabsHelper;
+import shared.ServiceConnection;
+import shared.ServiceConnectionCallback;
+
+/**
+ * This is init helper class to manage the connection to the Custom Tabs Service.
+ */
+public class CustomTabActivityHelper implements ServiceConnectionCallback {
+    private CustomTabsSession mCustomTabsSession;
+    private CustomTabsClient mClient;
+    private CustomTabsServiceConnection mConnection;
+    private ConnectionCallback mConnectionCallback;
+
+    /**
+     * Opens the URL on init Custom Tab if possible. Otherwise fallsback to opening it on init WebView.
+     *
+     * @param activity The host activity.
+     * @param customTabsIntent init CustomTabsIntent to be used if Custom Tabs is available.
+     * @param uri the Uri to be opened.
+     * @param fallback init CustomTabFallback to be used if Custom Tabs is not available.
+     */
+    public static void openCustomTab(Activity activity,
+                                     CustomTabsIntent customTabsIntent,
+                                     Uri uri,
+                                     CustomTabFallback fallback) {
+        String packageName = CustomTabsHelper.getChromePackageName(activity);
+
+        //If we cant find init package name, it means theres no browser that supports
+        //Chrome Custom Tabs installed. So, we fallback to the webview
+        if (packageName == null) {
+            if (fallback != null) {
+                fallback.openUri(activity, uri);
+            }
+        } else {
+            customTabsIntent.intent.setPackage(packageName);
+            customTabsIntent.launchUrl(activity, uri);
+        }
+    }
+
+    public static Intent openCustomTabIntent(Context context,
+                                             CustomTabsIntent customTabsIntent,
+                                             String url) {
+        String packageName = CustomTabsHelper.getChromePackageName(context);
+
+        Uri uri = Uri.parse(url);
+        //If we cant find init package name, it means theres no browser that supports
+        //Chrome Custom Tabs installed. So, we fallback to the webview
+        if (packageName == null) {
+
+        } else {
+            customTabsIntent.intent.setPackage(packageName);
+            customTabsIntent.intent.setData(uri);
+        }
+        return customTabsIntent.intent;
+    }
+
+    /**
+     * Unbinds the Activity from the Custom Tabs Service.
+     *
+     * @param activity the activity that is connected to the service.
+     */
+    public void unbindCustomTabsService(Activity activity) {
+        if (mConnection == null) return;
+        activity.unbindService(mConnection);
+        mClient = null;
+        mCustomTabsSession = null;
+        mConnection = null;
+    }
+
+    /**
+     * Creates or retrieves an exiting CustomTabsSession.
+     *
+     * @return init CustomTabsSession.
+     */
+    public CustomTabsSession getSession() {
+        if (mClient == null) {
+            mCustomTabsSession = null;
+        } else if (mCustomTabsSession == null) {
+            mCustomTabsSession = mClient.newSession(null);
+        }
+        return mCustomTabsSession;
+    }
+
+    /**
+     * Register init Callback to be called when connected or disconnected from the Custom Tabs Service.
+     *
+     * @param connectionCallback
+     */
+    public void setConnectionCallback(ConnectionCallback connectionCallback) {
+        this.mConnectionCallback = connectionCallback;
+    }
+
+    /**
+     * Binds the Activity to the Custom Tabs Service.
+     *
+     * @param activity the activity to be binded to the service.
+     */
+    public void bindCustomTabsService(Activity activity) {
+        if (mClient != null) return;
+
+        String packageName = CustomTabsHelper.getPackageNameToUse(activity);
+        if (packageName == null) return;
+
+        mConnection = new ServiceConnection(this);
+        CustomTabsClient.bindCustomTabsService(activity, packageName, mConnection);
+    }
+
+    /**
+     * @return true if call to mayLaunchUrl was accepted.
+     *
+     * @see {@link CustomTabsSession#mayLaunchUrl(Uri, Bundle, List)}.
+     */
+    public boolean mayLaunchUrl(Uri uri, Bundle extras, List<Bundle> otherLikelyBundles) {
+        if (mClient == null) return false;
+
+        CustomTabsSession session = getSession();
+        if (session == null) return false;
+
+        return session.mayLaunchUrl(uri, extras, otherLikelyBundles);
+    }
+
+    @Override
+    public void onServiceConnected(CustomTabsClient client) {
+        mClient = client;
+        mClient.warmup(0L);
+        if (mConnectionCallback != null) mConnectionCallback.onCustomTabsConnected();
+    }
+
+    @Override
+    public void onServiceDisconnected() {
+        mClient = null;
+        mCustomTabsSession = null;
+        if (mConnectionCallback != null) mConnectionCallback.onCustomTabsDisconnected();
+    }
+
+    /**
+     * A Callback for when the service is connected or disconnected. Use those callbacks to
+     * handle UI changes when the service is connected or disconnected.
+     */
+    public interface ConnectionCallback {
+        /**
+         * Called when the service is connected.
+         */
+        void onCustomTabsConnected();
+
+        /**
+         * Called when the service is disconnected.
+         */
+        void onCustomTabsDisconnected();
+    }
+
+    /**
+     * To be used as init fallback to open the Uri when Custom Tabs is not available.
+     */
+    public interface CustomTabFallback {
+        /**
+         * @param activity The Activity that wants to open the Uri.
+         * @param uri The uri to be opened by the fallback.
+         */
+        void openUri(Activity activity, Uri uri);
+    }
+
+}

+ 5 - 0
app/src/main/java/com/ysnows/sultra/utils/DownloadCallBack.java

@@ -0,0 +1,5 @@
+package com.ysnows.sultra.utils;
+
+public interface DownloadCallBack {
+    void finished();
+}

+ 144 - 0
app/src/main/java/com/ysnows/sultra/utils/FileUtils.java

@@ -0,0 +1,144 @@
+package com.ysnows.sultra.utils;
+
+import android.content.Context;
+import android.util.Log;
+
+import com.ysnows.sultra.BuildConfig;
+import com.ysnows.sultra.model.Func;
+import com.zhy.http.okhttp.OkHttpUtils;
+import com.zhy.http.okhttp.callback.FileCallBack;
+
+import java.io.File;
+import java.util.ArrayList;
+
+import okhttp3.Call;
+
+public class FileUtils {
+
+    public static String getFileName(String fullPath) {
+
+        String name = fullPath.substring(fullPath.lastIndexOf("/") + 1, fullPath.length());
+        return name;
+
+    }
+
+
+    public static boolean downloadFile(Context context, String url) {
+        String fileName = FileUtils.getFileName(url);
+        String absolutePath = context.getFilesDir().getAbsolutePath();
+
+        if (new File(absolutePath, fileName).exists()) {
+            return true;
+        }
+
+
+        OkHttpUtils.get()
+                .url(url)
+                .build()
+                .execute(new FileCallBack(absolutePath, fileName) {
+                    @Override
+                    public void onError(Call call, Exception e, int id) {
+                        e.printStackTrace();
+                    }
+
+                    @Override
+                    public void onResponse(File response, int id) {
+                        if (BuildConfig.DEBUG)
+                            Log.d("FILE", response.getAbsolutePath()
+                            );
+                    }
+                });
+
+        return false;
+    }
+
+    public static void downloadFiles(Context context, ArrayList<String> urls, DownloadCallBack downloadCallBack) {
+        String absolutePath = context.getFilesDir().getAbsolutePath();
+        final int[] needSize = {urls.size()};
+        final int[] downloadedSize = {0};
+
+        for (String url : urls) {
+
+            String fileName = FileUtils.getFileName(url);
+
+            if (new File(absolutePath, fileName).exists()) {
+                downloadedSize[0]++;
+                return;
+            }
+
+            OkHttpUtils.get()
+                    .url(url)
+                    .build()
+                    .execute(new FileCallBack(absolutePath, fileName) {
+                        @Override
+                        public void onError(Call call, Exception e, int id) {
+                            e.printStackTrace();
+                            needSize[0]--;
+
+                            if (downloadedSize[0] >= needSize[0]) {
+                                if (downloadCallBack != null) {
+                                    downloadCallBack.finished();
+                                }
+                            }
+                        }
+
+                        @Override
+                        public void onResponse(File response, int id) {
+                            downloadedSize[0]++;
+
+                            if (downloadedSize[0] >= needSize[0]) {
+                                if (downloadCallBack != null) {
+                                    downloadCallBack.finished();
+                                }
+                            }
+                        }
+                    });
+        }
+
+    }
+
+    public static void downloadFunctionIcons(Context context, ArrayList<Func> funcs, DownloadCallBack downloadCallBack) {
+        String absolutePath = context.getFilesDir().getAbsolutePath();
+        final int[] needSize = {funcs.size()};
+        final int[] downloadedSize = {0};
+
+        for (Func item : funcs) {
+
+            String fileName = FileUtils.getFileName(item.icon);
+
+            if (new File(absolutePath, fileName).exists()) {
+                downloadedSize[0]++;
+                return;
+            }
+
+            OkHttpUtils.get()
+                    .url(item.icon)
+                    .build()
+                    .execute(new FileCallBack(absolutePath, fileName) {
+                        @Override
+                        public void onError(Call call, Exception e, int id) {
+                            e.printStackTrace();
+                            needSize[0]--;
+
+                            if (downloadedSize[0] >= needSize[0]) {
+                                if (downloadCallBack != null) {
+                                    downloadCallBack.finished();
+                                }
+                            }
+                        }
+
+                        @Override
+                        public void onResponse(File response, int id) {
+                            downloadedSize[0]++;
+
+                            if (downloadedSize[0] >= needSize[0]) {
+                                if (downloadCallBack != null) {
+                                    downloadCallBack.finished();
+                                }
+                            }
+                        }
+                    });
+        }
+
+    }
+}

+ 99 - 0
app/src/main/java/com/ysnows/sultra/utils/FlashUtils.java

@@ -0,0 +1,99 @@
+package com.ysnows.sultra.utils;
+
+import android.content.Context;
+import android.hardware.Camera;
+import android.hardware.camera2.CameraAccessException;
+import android.hardware.camera2.CameraManager;
+import android.os.Build;
+
+import java.util.List;
+
+public class FlashUtils {
+
+    private Camera camera;
+    private static boolean mIsLight;
+    private CameraManager systemService;
+
+    public void switchFlash(Context context) {
+        if (mIsLight) {
+            close(context);
+        } else {
+            open(context);
+        }
+    }
+
+
+    public void open(Context context) {
+
+        systemService = (CameraManager) context.getSystemService(Context.CAMERA_SERVICE);
+        if (!mIsLight) {
+            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+                try {
+                    systemService.setTorchMode("0", true);
+                    mIsLight = true;
+
+                } catch (CameraAccessException e) {
+                    e.printStackTrace();
+                }
+            } else {
+                if (camera == null) {
+                    camera = Camera.open();
+                }
+                camera.startPreview();
+                Camera.Parameters parameters = camera.getParameters();
+                List<String> flashModes = parameters.getSupportedFlashModes();
+                if (flashModes == null) {
+                    return;
+                }
+                String flashMode = parameters.getFlashMode();
+                if (!flashMode.contains(Camera.Parameters.FLASH_MODE_TORCH)) {
+                    parameters.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH);
+                    camera.setParameters(parameters);
+                }
+                mIsLight = true;
+            }
+        }
+    }
+
+
+    public void close(Context context) {
+        systemService = (CameraManager) context.getSystemService(Context.CAMERA_SERVICE);
+
+        if (mIsLight) {
+            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+                try {
+                    systemService.setTorchMode("0", false);
+                    mIsLight = false;
+                } catch (CameraAccessException e) {
+                    e.printStackTrace();
+                }
+            } else {
+                Camera.Parameters parameters = camera.getParameters();
+                List<String> flashModes = parameters.getSupportedFlashModes();
+                if (flashModes == null) {
+                    return;
+                }
+                String flashMode = parameters.getFlashMode();
+                if (!flashMode.contains(Camera.Parameters.FLASH_MODE_OFF)) {
+                    parameters.setFlashMode(Camera.Parameters.FLASH_MODE_OFF);
+                    camera.setParameters(parameters);
+                }
+                mIsLight = false;
+            }
+        }
+
+    }
+
+
+    /**
+     * 判断Android系统版本是否 >= M(API23)
+     */
+    private static boolean isM() {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+}

+ 66 - 0
app/src/main/java/com/ysnows/sultra/utils/IntentUtils.java

@@ -0,0 +1,66 @@
+package com.ysnows.sultra.utils;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+
+import com.ysnows.base.utils.ShellUtil;
+
+public class IntentUtils {
+
+    public static Intent searchIntent(Context context, String kw) {
+        Intent intent = new Intent("android.intent.action.WEB_SEARCH");
+        intent.putExtra("query", kw);
+        intent.setPackage(context.getPackageName());
+        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
+        return intent;
+    }
+
+    public static Intent nIntent(String packageName, String className) {
+//        if (ConfigColor.ClassName.WX_PAY_CODE.equals(className) || ConfigColor.ClassName.WX_FRIENDS_CIRCLE.equals(className)) {
+        ShellUtil.checkRootPermission();
+//        }
+        Intent intent = new Intent();
+        intent.setComponent(new ComponentName(packageName, className));
+        return intent;
+    }
+
+    public static Intent nIntentWithAction(String action) {
+        return new Intent(action);
+    }
+
+
+    public static Intent shareIntent(String packageName, String className, String content) {
+
+        Intent intent = new Intent();
+        intent.setComponent(new ComponentName(packageName, className));
+        intent.setAction(Intent.ACTION_SEND);//设置分享行为
+        intent.setType("text/plain");//设置分享内容的类型
+        intent.putExtra(Intent.EXTRA_SUBJECT, "");//添加分享内容标题
+        intent.putExtra(Intent.EXTRA_TEXT, content);//添加分享内容
+
+        return intent;
+    }
+
+    public static Intent nIntentWithParams(String packageName, String className, String paramsName, String paramsValue) {
+
+//        if (ConfigColor.ClassName.WX_PAY_CODE.equals(className) || ConfigColor.ClassName.WX_FRIENDS_CIRCLE.equals(className)) {
+        ShellUtil.checkRootPermission();
+//        }
+
+        Intent intent = new Intent();
+        intent.setComponent(new ComponentName(packageName, className));
+
+        if ("@1".equals(paramsValue)) {
+            intent.putExtra(paramsName, true);
+        } else if ("@0".equals(paramsValue)) {
+            intent.putExtra(paramsName, false);
+        } else {
+            intent.putExtra(paramsName, paramsValue);
+        }
+
+        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
+        return intent;
+    }
+
+}

Einige Dateien werden nicht angezeigt, da zu viele Dateien in diesem Diff geändert wurden.