├── .editorconfig ├── .github └── workflows │ ├── macos.yml │ ├── ubuntu.yml │ └── windows.yml ├── .gitignore ├── LICENSE ├── README.md ├── app ├── .gitignore ├── build.gradle ├── libs │ ├── alibc_link_partner-4.1.15.aar │ ├── alibc_link_partner-4.1.23.aar │ ├── alipaysdk-15.8.00.201112210139.aar │ ├── alipaysdk-noutdid-15.8.00.201112210139.aar │ ├── apsecuritysdk-all-3.3.0.jar │ ├── avmpaar3-5.4.200.aar │ ├── avmpaar3-5.4.36.aar │ ├── mtopsdk_allinone_open-3.1.2.5.jar │ ├── mtopsdk_allinone_open-3.1.7.2.jar │ ├── securitybodyaar3-5.4.200.aar │ ├── securitybodyaar3-5.4.99.aar │ ├── securityguardaar3-5.4.171.aar │ ├── securityguardaar3-5.4.200.aar │ ├── sgmiddletieraar3-5.4.200.aar │ ├── sgmiddletieraar3-5.4.9.aar │ └── standardcashier-single-15.6.5.aar ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── qiyutech │ │ └── tbk │ │ └── ExampleInstrumentedTest.kt │ ├── main │ ├── AndroidManifest.xml │ ├── assets │ │ └── www │ │ │ └── html │ │ │ └── privacy.html │ ├── java │ │ └── com │ │ │ └── qiyutech │ │ │ └── tbk │ │ │ ├── CouponActivity.kt │ │ │ ├── DevInfoActivity.kt │ │ │ ├── GroupActivity.kt │ │ │ ├── HomeActivity.kt │ │ │ ├── ItemDetailV2Activity.kt │ │ │ ├── MeActivity.kt │ │ │ ├── MyApplication.kt │ │ │ ├── PrivacyActivity.kt │ │ │ ├── SafeImgActivity.kt │ │ │ ├── SearchActivity.kt │ │ │ ├── SearchDetailNativeActivity.kt │ │ │ ├── SettingsActivity.kt │ │ │ ├── TaoBaoActivity.kt │ │ │ ├── UserInfoActivity.kt │ │ │ ├── UserPasswordActivity.kt │ │ │ ├── activity │ │ │ ├── question │ │ │ │ └── MyJsonObjectRequest.kt │ │ │ └── taobao │ │ │ │ └── MyAuthCb.kt │ │ │ ├── api │ │ │ └── ZTK.kt │ │ │ ├── application │ │ │ ├── AliBCCallback.kt │ │ │ └── AppSwipeBack.kt │ │ │ ├── dt │ │ │ ├── DtsV2.kt │ │ │ ├── Stub.kt │ │ │ └── shared.kt │ │ │ ├── events │ │ │ ├── LoginEvent.kt │ │ │ └── LogoutEvent.kt │ │ │ ├── extend │ │ │ └── MyNetworkImageView.kt │ │ │ ├── fragments │ │ │ ├── SFooterFragment.kt │ │ │ ├── TextHeaderFragment.kt │ │ │ ├── home │ │ │ │ └── HomeFragmentGuessYouLike.kt │ │ │ ├── me │ │ │ │ ├── MeFragmentDefault.kt │ │ │ │ ├── MeFragmentSlot.kt │ │ │ │ └── MeFragmentUser.kt │ │ │ └── settings │ │ │ │ ├── SettingsFragmentLogin.kt │ │ │ │ └── SettingsFragmentUser.kt │ │ │ ├── logic │ │ │ ├── AppErrnoLogic.kt │ │ │ ├── CouponLogic.kt │ │ │ ├── DisplayLogic.kt │ │ │ ├── TaoBaoLogic.kt │ │ │ └── UserLogic.kt │ │ │ ├── utils │ │ │ ├── AppNavUtils.kt │ │ │ ├── AppUtils.kt │ │ │ ├── ClipboardUtils.kt │ │ │ ├── DialogUtils.kt │ │ │ ├── DiskImageCache.kt │ │ │ ├── LayoutUtils.kt │ │ │ ├── LoadKeywordUtils.kt │ │ │ ├── MyHttpUtils.kt │ │ │ ├── MyJsonUtils.kt │ │ │ ├── MySearchUtils.kt │ │ │ ├── MyWebViewUtils.kt │ │ │ ├── NetworkImageUtils.kt │ │ │ ├── PopupUtils.kt │ │ │ ├── PrivacyUtils.kt │ │ │ ├── PushUtils.kt │ │ │ ├── TipUtils.kt │ │ │ └── WebUtils.kt │ │ │ └── values │ │ │ ├── ApiUrlsV2.kt │ │ │ ├── AppSpKeys.kt │ │ │ ├── HttpFile.kt │ │ │ ├── HttpTags.kt │ │ │ └── LogTags.kt │ └── res │ │ ├── color │ │ └── bottom_nav_color.xml │ │ ├── drawable-hdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── drawable-mdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── drawable-xhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── drawable-xxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── drawable-xxxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── drawable │ │ ├── button_round_corner.xml │ │ ├── coupon_bg.png │ │ ├── f_icon_coupon.png │ │ ├── f_icon_group.png │ │ ├── f_icon_home.png │ │ ├── f_icon_user.png │ │ ├── forward.png │ │ ├── item_detail_coupon_bg.xml │ │ ├── search.png │ │ ├── search_button_bg.xml │ │ ├── search_view_bg.xml │ │ ├── star.png │ │ └── yw_1222.jpg │ │ ├── layout │ │ ├── activity_coupon.xml │ │ ├── activity_dev_info.xml │ │ ├── activity_group.xml │ │ ├── activity_home.xml │ │ ├── activity_item_detail_v2.xml │ │ ├── activity_me.xml │ │ ├── activity_privacy.xml │ │ ├── activity_search.xml │ │ ├── activity_search_detail_native.xml │ │ ├── activity_tao_bao.xml │ │ ├── activity_user_info.xml │ │ ├── fragment_home_guess_you_like.xml │ │ ├── fragment_me_default.xml │ │ ├── fragment_me_slot.xml │ │ ├── fragment_me_user.xml │ │ ├── fragment_s_footer.xml │ │ ├── fragment_settings_login.xml │ │ ├── fragment_settings_user.xml │ │ ├── fragment_text_header.xml │ │ ├── layout_recycle_view_item_info.xml │ │ ├── layout_recycle_view_search_detail_item_info.xml │ │ ├── me_activity_divider.xml │ │ ├── parts_simple_kv_info.xml │ │ ├── parts_tbk_sort_header.xml │ │ ├── popup_clean_cache.xml │ │ ├── s_footer.xml │ │ ├── search_search_item.xml │ │ ├── settings_activity.xml │ │ ├── t_grid_demo.xml │ │ └── user_password_activity.xml │ │ ├── menu │ │ └── home_navigation_menu.xml │ │ ├── mipmap-hdpi │ │ ├── back.png │ │ ├── forward.png │ │ ├── me_order.png │ │ ├── settings.png │ │ └── tao_bao_auth.png │ │ ├── mipmap-mdpi │ │ ├── back.png │ │ ├── forward.png │ │ ├── me_order.png │ │ ├── settings.png │ │ └── tao_bao_auth.png │ │ ├── mipmap-xhdpi │ │ ├── back.png │ │ ├── forward.png │ │ ├── me_order.png │ │ ├── settings.png │ │ └── tao_bao_auth.png │ │ ├── mipmap-xxhdpi │ │ ├── back.png │ │ ├── forward.png │ │ ├── me_order.png │ │ ├── settings.png │ │ └── tao_bao_auth.png │ │ ├── mipmap-xxxhdpi │ │ ├── back.png │ │ ├── forward.png │ │ ├── me_order.png │ │ ├── settings.png │ │ └── tao_bao_auth.png │ │ ├── values-w820dp │ │ └── dimens.xml │ │ ├── values-zh │ │ └── strings.xml │ │ └── values │ │ ├── arrays.xml │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── com │ └── qiyutech │ └── tbk │ └── ExampleUnitTest.kt ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── keystore ├── readme.md └── tbk └── settings.gradle /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | end_of_line = lf 5 | insert_final_newline = true 6 | tab_width = 4 7 | indent_size = 4 8 | indent_style = space 9 | 10 | [*.xml] 11 | max_line_length = off 12 | 13 | [*.yml] 14 | indent_size = 2 15 | 16 | [Makefile] 17 | indent_style = tab 18 | -------------------------------------------------------------------------------- /.github/workflows/macos.yml: -------------------------------------------------------------------------------- 1 | name: macOS 2 | 3 | on: [ push, pull_request ] 4 | 5 | 6 | jobs: 7 | build: 8 | runs-on: macos-latest 9 | 10 | steps: 11 | - uses: actions/checkout@v2 12 | 13 | - uses: actions/setup-java@v2 14 | with: 15 | distribution: 'adopt' 16 | java-version: '11' 17 | 18 | - name: Build APK 19 | run: ./gradlew build 20 | 21 | - uses: actions/upload-artifact@v2 22 | with: 23 | name: macos 24 | path: app/build/outputs/apk/prod/release/ 25 | -------------------------------------------------------------------------------- /.github/workflows/ubuntu.yml: -------------------------------------------------------------------------------- 1 | name: Ubuntu 2 | 3 | on: [ push, pull_request ] 4 | 5 | 6 | jobs: 7 | build: 8 | runs-on: ubuntu-20.04 9 | 10 | steps: 11 | - uses: actions/checkout@v2 12 | 13 | - uses: actions/setup-java@v2 14 | with: 15 | distribution: 'adopt' 16 | java-version: '11' 17 | 18 | - name: Build APK 19 | run: ./gradlew build 20 | 21 | - uses: actions/upload-artifact@v2 22 | with: 23 | name: ubuntu 24 | path: app/build/outputs/apk/prod/release/ 25 | -------------------------------------------------------------------------------- /.github/workflows/windows.yml: -------------------------------------------------------------------------------- 1 | name: Windows 2 | 3 | on: [ push, pull_request ] 4 | 5 | 6 | jobs: 7 | build: 8 | runs-on: windows-latest 9 | 10 | steps: 11 | - uses: actions/checkout@v2 12 | 13 | - uses: actions/setup-java@v2 14 | with: 15 | distribution: 'adopt' 16 | java-version: '11' 17 | 18 | - name: Build APK 19 | run: ./gradlew build 20 | 21 | - uses: actions/upload-artifact@v2 22 | with: 23 | name: windows 24 | path: app/build/outputs/apk/prod/release/ 25 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | demo.json 3 | *.iml 4 | .gradle 5 | local.properties 6 | .DS_Store 7 | /build 8 | /captures 9 | .externalNativeBuild 10 | .cxx 11 | 12 | app/release/app-release.apk 13 | app/release/output.json 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 奇遇淘客 Android 版 2 | 3 | ![Windows](https://github.com/QiYuTechDev/QiYuTkAndroid/workflows/Windows/badge.svg?branch=main) 4 | ![macOS](https://github.com/QiYuTechDev/QiYuTkAndroid/workflows/macOS/badge.svg?branch=main) 5 | ![Ubuntu](https://github.com/QiYuTechDev/QiYuTkAndroid/workflows/Ubuntu/badge.svg?branch=main) 6 | 7 | 8 | ## 奇遇淘客代码库 9 | 10 | * [奇遇淘客 iOS 版](https://github.com/QiYuTechDev/QiYuTkiOS) 11 | * [奇遇淘客 服务器端](https://github.com/QiYuTechDev/QiYuTkServer) 12 | 13 | ## 奇遇淘客文档 14 | 15 | [奇遇淘客 文档](https://tbk.qiyutech.tech/) 16 | [奇遇淘客 Android](https://tbk.qiyutech.tech/android/index.html) 17 | 18 | ## 博客文章 19 | 20 | [发布记录](https://blog.qiyutech.tech/202101/28_tbk_android/) 21 | 22 | ## Android Studio 版本 23 | 24 | ```text 25 | Android Studio Chipmunk | 2021.2.1 Patch 1 26 | Build #AI-212.5712.43.2112.8609683, built on May 19, 2022 27 | Runtime version: 11.0.12+0-b1504.28-7817840 x86_64 28 | VM: OpenJDK 64-Bit Server VM by JetBrains s.r.o. 29 | macOS 11.6.7 30 | GC: G1 Young Generation, G1 Old Generation 31 | Memory: 2048M 32 | Cores: 8 33 | Registry: external.system.auto.import.disabled=true 34 | ``` 35 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/libs/alibc_link_partner-4.1.15.aar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QiYuTechOrg/QiYuTkAndroid/35188be591e96b84de366098bdaf8e6bd92197ac/app/libs/alibc_link_partner-4.1.15.aar -------------------------------------------------------------------------------- /app/libs/alibc_link_partner-4.1.23.aar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QiYuTechOrg/QiYuTkAndroid/35188be591e96b84de366098bdaf8e6bd92197ac/app/libs/alibc_link_partner-4.1.23.aar -------------------------------------------------------------------------------- /app/libs/alipaysdk-15.8.00.201112210139.aar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QiYuTechOrg/QiYuTkAndroid/35188be591e96b84de366098bdaf8e6bd92197ac/app/libs/alipaysdk-15.8.00.201112210139.aar -------------------------------------------------------------------------------- /app/libs/alipaysdk-noutdid-15.8.00.201112210139.aar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QiYuTechOrg/QiYuTkAndroid/35188be591e96b84de366098bdaf8e6bd92197ac/app/libs/alipaysdk-noutdid-15.8.00.201112210139.aar -------------------------------------------------------------------------------- /app/libs/apsecuritysdk-all-3.3.0.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QiYuTechOrg/QiYuTkAndroid/35188be591e96b84de366098bdaf8e6bd92197ac/app/libs/apsecuritysdk-all-3.3.0.jar -------------------------------------------------------------------------------- /app/libs/avmpaar3-5.4.200.aar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QiYuTechOrg/QiYuTkAndroid/35188be591e96b84de366098bdaf8e6bd92197ac/app/libs/avmpaar3-5.4.200.aar -------------------------------------------------------------------------------- /app/libs/avmpaar3-5.4.36.aar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QiYuTechOrg/QiYuTkAndroid/35188be591e96b84de366098bdaf8e6bd92197ac/app/libs/avmpaar3-5.4.36.aar -------------------------------------------------------------------------------- /app/libs/mtopsdk_allinone_open-3.1.2.5.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QiYuTechOrg/QiYuTkAndroid/35188be591e96b84de366098bdaf8e6bd92197ac/app/libs/mtopsdk_allinone_open-3.1.2.5.jar -------------------------------------------------------------------------------- /app/libs/mtopsdk_allinone_open-3.1.7.2.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QiYuTechOrg/QiYuTkAndroid/35188be591e96b84de366098bdaf8e6bd92197ac/app/libs/mtopsdk_allinone_open-3.1.7.2.jar -------------------------------------------------------------------------------- /app/libs/securitybodyaar3-5.4.200.aar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QiYuTechOrg/QiYuTkAndroid/35188be591e96b84de366098bdaf8e6bd92197ac/app/libs/securitybodyaar3-5.4.200.aar -------------------------------------------------------------------------------- /app/libs/securitybodyaar3-5.4.99.aar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QiYuTechOrg/QiYuTkAndroid/35188be591e96b84de366098bdaf8e6bd92197ac/app/libs/securitybodyaar3-5.4.99.aar -------------------------------------------------------------------------------- /app/libs/securityguardaar3-5.4.171.aar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QiYuTechOrg/QiYuTkAndroid/35188be591e96b84de366098bdaf8e6bd92197ac/app/libs/securityguardaar3-5.4.171.aar -------------------------------------------------------------------------------- /app/libs/securityguardaar3-5.4.200.aar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QiYuTechOrg/QiYuTkAndroid/35188be591e96b84de366098bdaf8e6bd92197ac/app/libs/securityguardaar3-5.4.200.aar -------------------------------------------------------------------------------- /app/libs/sgmiddletieraar3-5.4.200.aar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QiYuTechOrg/QiYuTkAndroid/35188be591e96b84de366098bdaf8e6bd92197ac/app/libs/sgmiddletieraar3-5.4.200.aar -------------------------------------------------------------------------------- /app/libs/sgmiddletieraar3-5.4.9.aar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QiYuTechOrg/QiYuTkAndroid/35188be591e96b84de366098bdaf8e6bd92197ac/app/libs/sgmiddletieraar3-5.4.9.aar -------------------------------------------------------------------------------- /app/libs/standardcashier-single-15.6.5.aar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QiYuTechOrg/QiYuTkAndroid/35188be591e96b84de366098bdaf8e6bd92197ac/app/libs/standardcashier-single-15.6.5.aar -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | 23 | -keep class com.qiyutech.tbk.** {*;} 24 | 25 | -keepattributes Signature 26 | -ignorewarnings 27 | -keep class javax.ws.rs.** { *; } 28 | -keep class com.alibaba.fastjson.** { *; } 29 | -dontwarn com.alibaba.fastjson.** 30 | -keep class sun.misc.Unsafe { *; } 31 | -dontwarn sun.misc.** 32 | -keep class com.taobao.** {*;} 33 | -keep class com.alibaba.** {*;} 34 | -keep class com.alipay.** {*;} 35 | -dontwarn com.taobao.** 36 | -dontwarn com.alibaba.** 37 | -dontwarn com.alipay.** 38 | -keep class com.ut.** {*;} 39 | -dontwarn com.ut.** 40 | -keep class com.ta.** {*;} 41 | -dontwarn com.ta.** 42 | -keep class org.json.** {*;} 43 | -keep class com.ali.auth.** {*;} 44 | -dontwarn com.ali.auth.** 45 | -keep class com.taobao.securityjni.** {*;} 46 | -keep class com.taobao.wireless.security.** {*;} 47 | -keep class com.taobao.dp.**{*;} 48 | -keep class com.alibaba.wireless.security.**{*;} 49 | -keep interface mtopsdk.mtop.global.init.IMtopInitTask {*;} 50 | -keep class * implements mtopsdk.mtop.global.init.IMtopInitTask {*;} 51 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/qiyutech/tbk/ExampleInstrumentedTest.kt: -------------------------------------------------------------------------------- 1 | package com.qiyutech.tbk 2 | 3 | import androidx.test.platform.app.InstrumentationRegistry 4 | import androidx.test.ext.junit.runners.AndroidJUnit4 5 | 6 | import org.junit.Test 7 | import org.junit.runner.RunWith 8 | 9 | import org.junit.Assert.* 10 | 11 | /** 12 | * Instrumented test, which will execute on an Android device. 13 | * 14 | * See [testing documentation](http://d.android.com/tools/testing). 15 | */ 16 | @RunWith(AndroidJUnit4::class) 17 | class ExampleInstrumentedTest { 18 | @Test 19 | fun useAppContext() { 20 | // Context of the tbk under test. 21 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext 22 | assertEquals("com.qiyutech.tbk", appContext.packageName) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 23 | 26 | 30 | 33 | 37 | 41 | 46 | 50 | 55 | 59 | 63 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 79 | 83 | 87 | 91 | 96 | 100 | 101 | 102 | 103 | -------------------------------------------------------------------------------- /app/src/main/assets/www/html/privacy.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 奇遇淘客隐私协议 6 | 7 | 8 | 9 | 10 | 11 |

您的隐私协议

12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /app/src/main/java/com/qiyutech/tbk/CouponActivity.kt: -------------------------------------------------------------------------------- 1 | package com.qiyutech.tbk 2 | 3 | import android.app.SearchManager 4 | import android.os.Bundle 5 | import androidx.appcompat.app.AppCompatActivity 6 | import androidx.cursoradapter.widget.CursorAdapter 7 | import androidx.cursoradapter.widget.SimpleCursorAdapter 8 | import com.qiyutech.tbk.databinding.ActivityCouponBinding 9 | import com.qiyutech.tbk.fragments.home.HomeFragmentGuessYouLike 10 | import com.qiyutech.tbk.logic.CouponSearchQueryTextListener 11 | import com.qiyutech.tbk.logic.CouponSearchSuggestion 12 | import com.qiyutech.tbk.utils.AppUtils 13 | 14 | /** 15 | * 优惠券界面 16 | */ 17 | class CouponActivity : AppCompatActivity() { 18 | 19 | override fun onCreate(savedInstanceState: Bundle?) { 20 | super.onCreate(savedInstanceState) 21 | setContentView(R.layout.activity_coupon) 22 | 23 | this.initItemSearchView() 24 | 25 | supportFragmentManager.beginTransaction() 26 | .replace(R.id.guess_you_like_fragment, HomeFragmentGuessYouLike()) 27 | .commit() 28 | } 29 | 30 | /** 31 | * 初始化商品的搜索 只需要一次就行了 32 | */ 33 | private fun initItemSearchView() { 34 | val from = arrayOf(SearchManager.SUGGEST_COLUMN_TEXT_1) 35 | val to = intArrayOf(R.id.item_label) 36 | val cursorAdapter = SimpleCursorAdapter( 37 | this, 38 | R.layout.search_search_item, 39 | null, 40 | from, 41 | to, 42 | CursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER 43 | ) 44 | 45 | val view = AppUtils.getRootView(this) 46 | val bd = ActivityCouponBinding.bind(view) 47 | 48 | val searchView = bd.itemSearchView 49 | searchView.suggestionsAdapter = cursorAdapter 50 | searchView.setOnQueryTextListener(CouponSearchQueryTextListener(this, searchView)) 51 | searchView.setOnSuggestionListener(CouponSearchSuggestion(searchView)) 52 | } 53 | 54 | override fun onDestroy() { 55 | super.onDestroy() 56 | 57 | viewModelStore.clear() 58 | } 59 | 60 | 61 | } 62 | -------------------------------------------------------------------------------- /app/src/main/java/com/qiyutech/tbk/DevInfoActivity.kt: -------------------------------------------------------------------------------- 1 | package com.qiyutech.tbk 2 | 3 | import android.os.Bundle 4 | import androidx.appcompat.app.AppCompatActivity 5 | import com.qiyutech.tbk.databinding.ActivityDevInfoBinding 6 | import com.qiyutech.tbk.databinding.PartsSimpleKvInfoBinding 7 | import com.qiyutech.tbk.fragments.TextHeaderFragment 8 | import com.qiyutech.tbk.utils.AppUtils 9 | 10 | /** 11 | * 开发信息模式 12 | */ 13 | class DevInfoActivity : AppCompatActivity() { 14 | override fun onCreate(savedInstanceState: Bundle?) { 15 | super.onCreate(savedInstanceState) 16 | setContentView(R.layout.activity_dev_info) 17 | 18 | supportFragmentManager.beginTransaction() 19 | .replace(R.id.header, TextHeaderFragment("开发信息", true)) 20 | .commit() 21 | 22 | val rv = AppUtils.getRootView(this) 23 | val bd = ActivityDevInfoBinding.bind(rv) 24 | 25 | 26 | val debug = if (AppUtils.inDebugMode()) { 27 | "是" 28 | } else { 29 | "否" 30 | } 31 | val test = if (AppUtils.inDevEnv()) { 32 | "是" 33 | } else { 34 | "否" 35 | } 36 | 37 | setKV(bd.debug, "调试", debug) 38 | setKV(bd.test, "测试", test) 39 | setKV(bd.server, "服务器", BuildConfig.BASE_URL) 40 | setKV(bd.sdkInt, "Android SDK", android.os.Build.VERSION.SDK_INT.toString()) 41 | setKV(bd.mobileModel, "设备型号", android.os.Build.MODEL) 42 | setKV(bd.manufacturer, "制造商", android.os.Build.MANUFACTURER) 43 | } 44 | 45 | private fun setKV(p: PartsSimpleKvInfoBinding, k: String, v: String) { 46 | p.key.text = k 47 | p.value.text = v 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /app/src/main/java/com/qiyutech/tbk/GroupActivity.kt: -------------------------------------------------------------------------------- 1 | package com.qiyutech.tbk 2 | 3 | import android.os.Bundle 4 | import androidx.appcompat.app.AppCompatActivity 5 | import com.qiyutech.tbk.fragments.TextHeaderFragment 6 | 7 | 8 | /** 9 | * 微信群 界面 10 | */ 11 | class GroupActivity : AppCompatActivity() { 12 | override fun onCreate(savedInstanceState: Bundle?) { 13 | super.onCreate(savedInstanceState) 14 | setContentView(R.layout.activity_group) 15 | 16 | supportFragmentManager.beginTransaction() 17 | .replace(R.id.group_header, TextHeaderFragment("微信群")) 18 | .commit() 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /app/src/main/java/com/qiyutech/tbk/HomeActivity.kt: -------------------------------------------------------------------------------- 1 | package com.qiyutech.tbk 2 | 3 | import android.os.Bundle 4 | import android.util.Log 5 | import androidx.appcompat.app.AppCompatActivity 6 | import com.qiyutech.tbk.fragments.TextHeaderFragment 7 | import com.qiyutech.tbk.utils.AppNavUtils 8 | import com.qiyutech.tbk.utils.AppPrivacyUtils 9 | import com.qiyutech.tbk.utils.DialogUtils 10 | import com.qiyutech.tbk.utils.PushUtils 11 | import com.qiyutech.tbk.values.LogTags 12 | 13 | 14 | /** 15 | * 主页面 16 | */ 17 | class HomeActivity : AppCompatActivity() { 18 | private var mAlreadyInit = false 19 | 20 | override fun onCreate(savedInstanceState: Bundle?) { 21 | super.onCreate(savedInstanceState) 22 | setContentView(R.layout.activity_home) 23 | 24 | supportFragmentManager.beginTransaction() 25 | .replace(R.id.index_header, TextHeaderFragment("奇遇淘客")) 26 | .commit() 27 | 28 | } 29 | 30 | 31 | override fun onStart() { 32 | super.onStart() 33 | 34 | if (!mAlreadyInit) { 35 | oneTimeInit() 36 | } 37 | 38 | if (!AppPrivacyUtils.isPrivacyAgree(this)) { 39 | AppNavUtils.gotoPrivacy(this, false) 40 | } 41 | } 42 | 43 | 44 | private fun oneTimeInit() { 45 | if (mAlreadyInit) { 46 | return 47 | } 48 | PushUtils.reportPushId(this) 49 | notificationCheck() 50 | 51 | mAlreadyInit = true 52 | } 53 | 54 | private fun notificationCheck() { 55 | if (PushUtils.isNotificationEnabled(applicationContext)) { 56 | Log.i(LogTags.Push, "推送已经开启") 57 | } else { 58 | Log.i(LogTags.Push, "推送没有开启") 59 | val dialog = DialogUtils.notificationDialog(this) 60 | dialog.show() 61 | } 62 | } 63 | 64 | } 65 | -------------------------------------------------------------------------------- /app/src/main/java/com/qiyutech/tbk/ItemDetailV2Activity.kt: -------------------------------------------------------------------------------- 1 | package com.qiyutech.tbk 2 | 3 | import android.graphics.Paint 4 | import android.os.Bundle 5 | import android.view.View 6 | import androidx.appcompat.app.AppCompatActivity 7 | import com.qiyutech.tbk.databinding.ActivityItemDetailV2Binding 8 | import com.qiyutech.tbk.dt.ApiTbkItemDetailStub 9 | import com.qiyutech.tbk.dt.DtTbkItemDetailForm 10 | import com.qiyutech.tbk.extend.MyManualImageView 11 | import com.qiyutech.tbk.logic.AppErrnoLogic 12 | import com.qiyutech.tbk.logic.TaoBaoLogic 13 | import com.qiyutech.tbk.utils.AppUtils 14 | import com.qiyutech.tbk.utils.TipUtils 15 | 16 | /** 17 | * 商品详情页 v2 版本 18 | */ 19 | class ItemDetailV2Activity : AppCompatActivity() { 20 | // 商品 ID 21 | private var itemId: String = "" 22 | 23 | 24 | override fun onCreate(savedInstanceState: Bundle?) { 25 | super.onCreate(savedInstanceState) 26 | setContentView(R.layout.activity_item_detail_v2) 27 | 28 | itemId = intent.getStringExtra("item_id")!! 29 | } 30 | 31 | override fun onStart() { 32 | super.onStart() 33 | 34 | initGoodInfo() 35 | } 36 | 37 | private fun initGoodInfo() { 38 | val form = DtTbkItemDetailForm(tao_id = itemId) 39 | ApiTbkItemDetailStub.myPost(this, form, { ret -> 40 | AppErrnoLogic.genericServerErrnoProcess(ret.errno, this) 41 | 42 | val bd = this.getBinding() 43 | ret.data?.let { data -> 44 | // std details 45 | data.price_coupon?.let { 46 | bd.couponPrice.text = it.toInt().toString() 47 | } 48 | bd.productName.text = data.title_long 49 | bd.productIcon.loadImageFromUrl(data.tao_img) 50 | data.seller_logo?.let { 51 | bd.shopIcon.loadImageFromUrl(it) 52 | } 53 | bd.priceActual.text = "¥ ${data.price_actual}" 54 | bd.priceOrigin.text = "¥ ${data.price_origin}" 55 | // add middle line 56 | bd.priceOrigin.paintFlags = bd.priceOrigin.paintFlags or Paint.STRIKE_THRU_TEXT_FLAG 57 | bd.monthSale.text = data.sale_month.toString() 58 | data.seller_name?.let { 59 | bd.sellerName.text = it 60 | } 61 | bd.descScore.text = data.score_dsr.toString() 62 | bd.serviceScore.text = data.score_service.toString() 63 | bd.shipScore.text = data.score_ship.toString() 64 | 65 | 66 | data.tao_details?.let { 67 | it.forEach { url -> 68 | val img = MyManualImageView(this) 69 | bd.imageList.addView(img) 70 | img.loadImageFromUrl(url) 71 | } 72 | } 73 | } 74 | }, { 75 | TipUtils.toastLong(this, "获取商品信息失败: ${it.localizedMessage}") 76 | }) 77 | } 78 | 79 | /** 80 | * 尝试购买 商品 信息 81 | */ 82 | fun tryToBuy(view: View) { 83 | val tb = TaoBaoLogic(this) 84 | tb.buyItem(itemId) 85 | } 86 | 87 | fun shareToSys(view: View) { 88 | 89 | } 90 | 91 | @Suppress("UNUSED_PARAMETER") 92 | fun itemDetailV2Finish(view: View) { 93 | this.finish() 94 | } 95 | 96 | fun getBinding(): ActivityItemDetailV2Binding { 97 | val rv = AppUtils.getRootView(this) 98 | return ActivityItemDetailV2Binding.bind(rv) 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /app/src/main/java/com/qiyutech/tbk/MeActivity.kt: -------------------------------------------------------------------------------- 1 | package com.qiyutech.tbk 2 | 3 | import android.content.Intent 4 | import android.os.Bundle 5 | import androidx.activity.viewModels 6 | import androidx.appcompat.app.AppCompatActivity 7 | import androidx.lifecycle.MutableLiveData 8 | import androidx.lifecycle.ViewModel 9 | import com.qiyutech.tbk.fragments.SFooterFragment 10 | import com.qiyutech.tbk.fragments.me.MeFragmentDefault 11 | import com.qiyutech.tbk.fragments.me.MeFragmentUser 12 | import com.qiyutech.tbk.logic.TaoBaoLogic 13 | import com.qiyutech.tbk.utils.AppUtils 14 | 15 | 16 | /** 17 | * ViewModel 18 | */ 19 | class MeActivityUserViewModel : ViewModel() { 20 | /** 21 | * 展示的名称 22 | */ 23 | val displayName: MutableLiveData by lazy { 24 | MutableLiveData("...") 25 | } 26 | 27 | /** 28 | * 用户 ID 29 | */ 30 | val uuid: MutableLiveData by lazy { 31 | MutableLiveData("...") 32 | } 33 | 34 | } 35 | 36 | 37 | /** 38 | * 我的界面 39 | */ 40 | class MeActivity : AppCompatActivity() { 41 | 42 | private val viewModel: MeActivityUserViewModel by viewModels() 43 | 44 | 45 | override fun onCreate(savedInstanceState: Bundle?) { 46 | super.onCreate(savedInstanceState) 47 | setContentView(R.layout.activity_me) 48 | } 49 | 50 | override fun onStart() { 51 | super.onStart() 52 | 53 | supportFragmentManager 54 | .beginTransaction() 55 | .replace(R.id.home_footer_container, SFooterFragment()) 56 | .commit() 57 | } 58 | 59 | override fun onResume() { 60 | super.onResume() 61 | 62 | refreshActivityUI() 63 | } 64 | 65 | private fun refreshActivityUI() { 66 | 67 | val fragment = if (AppUtils.checkUserLogin(this)) { 68 | MeFragmentUser() 69 | } else { 70 | MeFragmentDefault() 71 | } 72 | 73 | supportFragmentManager.beginTransaction() 74 | .replace(R.id.slot, fragment) 75 | .commit() 76 | } 77 | 78 | 79 | override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { 80 | if (requestCode == AUTH_REQUEST_CODE) { 81 | TaoBaoLogic.detectTaoBaoBind(this) 82 | return 83 | } 84 | 85 | super.onActivityResult(requestCode, resultCode, data) 86 | } 87 | 88 | 89 | /** 90 | * https://developer.android.com/topic/libraries/architecture/viewmodel 91 | */ 92 | fun getUserViewModel(): MeActivityUserViewModel { 93 | return viewModel 94 | } 95 | 96 | 97 | override fun onDestroy() { 98 | super.onDestroy() 99 | 100 | viewModelStore.clear() 101 | } 102 | 103 | 104 | companion object { 105 | var AUTH_REQUEST_CODE = 2000 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /app/src/main/java/com/qiyutech/tbk/MyApplication.kt: -------------------------------------------------------------------------------- 1 | package com.qiyutech.tbk 2 | 3 | import android.app.Application 4 | import android.webkit.WebView 5 | import com.alibaba.baichuan.android.trade.AlibcTradeSDK 6 | import com.billy.android.swipe.SmartSwipeBack 7 | import com.qiyutech.tbk.application.AliBCCallback 8 | import com.qiyutech.tbk.application.AppSwipeBack 9 | import com.qiyutech.tbk.utils.AppUtils 10 | import com.qiyutech.tbk.values.AppSpKeys 11 | import java.util.* 12 | 13 | 14 | /** 15 | * 我的基础程序进程 16 | */ 17 | class MyApplication : Application() { 18 | override fun onCreate() { 19 | super.onCreate() 20 | 21 | SmartSwipeBack.activitySlidingBack(this, AppSwipeBack()) 22 | 23 | AlibcTradeSDK.asyncInit(this, AliBCCallback(this)) 24 | 25 | /// 自动生成 uuid 如果没有生成 26 | val t = AppUtils.getPreference(this) 27 | if (!t.contains(AppSpKeys.TBK_UUID)) { 28 | val uuid = "android-" + UUID.randomUUID().toString() 29 | t.edit().putString(AppSpKeys.TBK_UUID, uuid).apply() 30 | } 31 | 32 | 33 | if (AppUtils.inDevEnv()) { 34 | WebView.setWebContentsDebuggingEnabled(true) 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /app/src/main/java/com/qiyutech/tbk/PrivacyActivity.kt: -------------------------------------------------------------------------------- 1 | package com.qiyutech.tbk 2 | 3 | import android.os.Bundle 4 | import android.view.View 5 | import android.webkit.WebView 6 | import androidx.appcompat.app.AppCompatActivity 7 | import com.qiyutech.tbk.databinding.ActivityPrivacyBinding 8 | import com.qiyutech.tbk.fragments.TextHeaderFragment 9 | import com.qiyutech.tbk.utils.AppPrivacyUtils 10 | import com.qiyutech.tbk.utils.AppUtils 11 | import com.qiyutech.tbk.values.HttpFile 12 | 13 | /** 14 | * 隐私协议活动 15 | */ 16 | class PrivacyActivity : AppCompatActivity() { 17 | 18 | override fun onCreate(savedInstanceState: Bundle?) { 19 | super.onCreate(savedInstanceState) 20 | setContentView(R.layout.activity_privacy) 21 | 22 | supportFragmentManager.beginTransaction() 23 | .replace(R.id.header, TextHeaderFragment("奇遇淘客用户隐私协议", true)) 24 | .commit() 25 | 26 | val wv = getWebView() 27 | wv.loadUrl(HttpFile.privacy) 28 | } 29 | 30 | override fun onStart() { 31 | super.onStart() 32 | 33 | val viewMode = intent.getBooleanExtra("view", false) 34 | if (viewMode) { 35 | val view = AppUtils.getRootView(this) 36 | val pb = ActivityPrivacyBinding.bind(view) 37 | pb.bottomButtons.visibility = View.GONE 38 | } 39 | } 40 | 41 | /** 42 | * 同意隐私协议 43 | */ 44 | @Suppress("UNUSED_PARAMETER") 45 | fun agreePrivacy(view: View) { 46 | AppPrivacyUtils.setPrivacyAgree(this) 47 | privacyCloseActivity(view) 48 | } 49 | 50 | 51 | /** 52 | * 拒绝隐私协议 53 | * 直接退出程序 54 | */ 55 | fun disagreePrivacy(view: View) { 56 | this.finishAffinity() 57 | } 58 | 59 | fun privacyCloseActivity(view: View) { 60 | this.finish() 61 | } 62 | 63 | override fun onDestroy() { 64 | super.onDestroy() 65 | getWebView().destroy() 66 | } 67 | 68 | private fun getWebView(): WebView { 69 | val view = AppUtils.getRootView(this) 70 | val pb = ActivityPrivacyBinding.bind(view) 71 | return pb.privacyWebView 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /app/src/main/java/com/qiyutech/tbk/SafeImgActivity.kt: -------------------------------------------------------------------------------- 1 | package com.qiyutech.tbk 2 | 3 | import android.os.Bundle 4 | import androidx.appcompat.app.AppCompatActivity 5 | 6 | class SafeImgActivity : AppCompatActivity() { 7 | 8 | override fun onCreate(savedInstanceState: Bundle?) { 9 | super.onCreate(savedInstanceState) 10 | setContentView(R.layout.t_grid_demo) 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /app/src/main/java/com/qiyutech/tbk/SearchActivity.kt: -------------------------------------------------------------------------------- 1 | package com.qiyutech.tbk 2 | 3 | import android.app.SearchManager 4 | import android.database.Cursor 5 | import android.database.MatrixCursor 6 | import android.graphics.Color 7 | import android.os.Bundle 8 | import android.provider.BaseColumns 9 | import android.util.Log 10 | import android.view.View 11 | import android.view.ViewGroup 12 | import android.widget.Toast 13 | import androidx.appcompat.app.AppCompatActivity 14 | import androidx.appcompat.widget.AppCompatButton 15 | import androidx.appcompat.widget.SearchView 16 | import androidx.cursoradapter.widget.CursorAdapter 17 | import androidx.cursoradapter.widget.SimpleCursorAdapter 18 | import com.google.android.flexbox.FlexboxLayout 19 | import com.qiyutech.tbk.databinding.ActivitySearchBinding 20 | import com.qiyutech.tbk.dt.ApiDtkSearchSuggestionStub 21 | import com.qiyutech.tbk.dt.DtGoodsSearchSuggestionArgs 22 | import com.qiyutech.tbk.logic.AppErrnoLogic 23 | import com.qiyutech.tbk.utils.AppUtils 24 | import com.qiyutech.tbk.utils.LayoutUtils 25 | import com.qiyutech.tbk.utils.LoadKeywordUtils 26 | import com.qiyutech.tbk.utils.MySearchUtils 27 | import com.qiyutech.tbk.values.AppPreferenceUtils 28 | 29 | 30 | /** 31 | * 搜索 建议 32 | */ 33 | private class SearchSuggestion(private val searchView: SearchView) : 34 | SearchView.OnSuggestionListener { 35 | 36 | override fun onSuggestionClick(position: Int): Boolean { 37 | val cursor = searchView.suggestionsAdapter.getItem(position) as Cursor 38 | val selection = cursor.getString(cursor.getColumnIndex(SearchManager.SUGGEST_COLUMN_TEXT_1)) 39 | searchView.setQuery(selection, false) 40 | return true 41 | } 42 | 43 | override fun onSuggestionSelect(position: Int): Boolean { 44 | return false 45 | } 46 | } 47 | 48 | private class SearchQueryTextListener( 49 | private val activity: SearchActivity, 50 | private val searchView: SearchView 51 | ) : 52 | SearchView.OnQueryTextListener { 53 | 54 | override fun onQueryTextSubmit(query: String?): Boolean { 55 | // extract to search method 56 | if (query.isNullOrBlank()) { 57 | return false 58 | } 59 | 60 | MySearchUtils.doSearch(activity, query) 61 | 62 | return true 63 | } 64 | 65 | override fun onQueryTextChange(query: String?): Boolean { 66 | if (query.isNullOrBlank()) { 67 | return true 68 | } 69 | 70 | val args = DtGoodsSearchSuggestionArgs(keyWords = query, type = "3") 71 | ApiDtkSearchSuggestionStub.myPost(activity, args, 72 | { v -> 73 | AppErrnoLogic.genericServerErrnoProcess(v.errno, activity) 74 | if (v.errno != 0) { 75 | Log.w("request suggest failed:", v.toString()) 76 | return@myPost 77 | } 78 | val cursor = 79 | MatrixCursor(arrayOf(BaseColumns._ID, SearchManager.SUGGEST_COLUMN_TEXT_1)) 80 | 81 | v.data?.forEachIndexed { index, suggestion -> 82 | val item = arrayOf(index, suggestion) 83 | cursor.addRow(item) 84 | } 85 | 86 | this.searchView.suggestionsAdapter.changeCursor(cursor) 87 | 88 | }, 89 | { error -> Log.e("search suggest", "错误: $error") } 90 | ) 91 | 92 | return false 93 | } 94 | } 95 | 96 | /** 97 | * 商品主搜索界面 98 | */ 99 | class SearchActivity : AppCompatActivity() { 100 | override fun onCreate(savedInstanceState: Bundle?) { 101 | super.onCreate(savedInstanceState) 102 | setContentView(R.layout.activity_search) 103 | 104 | val from = arrayOf(SearchManager.SUGGEST_COLUMN_TEXT_1) 105 | val to = intArrayOf(R.id.item_label) 106 | val cursorAdapter = SimpleCursorAdapter( 107 | this, 108 | R.layout.search_search_item, 109 | null, 110 | from, 111 | to, 112 | CursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER 113 | ) 114 | 115 | val view = AppUtils.getRootView(this) 116 | val asb = ActivitySearchBinding.bind(view) 117 | 118 | val searchInput = asb.searchSearchInput 119 | searchInput.suggestionsAdapter = cursorAdapter 120 | 121 | searchInput.setOnQueryTextListener(SearchQueryTextListener(this, searchInput)) 122 | searchInput.setOnSuggestionListener(SearchSuggestion(searchInput)) 123 | } 124 | 125 | override fun onStart() { 126 | super.onStart() 127 | 128 | val lku = LoadKeywordUtils(this) 129 | lku.loadKeyword() 130 | 131 | loadSearchHistoryKeyword() 132 | } 133 | 134 | 135 | fun closeSearchActivity(view: View) { 136 | this.finish() 137 | } 138 | 139 | /** 140 | * 搜索商品 141 | */ 142 | fun doSearchItem(view: View) { 143 | val root = AppUtils.getRootView(this) 144 | val sb = ActivitySearchBinding.bind(root) 145 | val input = sb.searchSearchInput 146 | val query = input.query.toString() 147 | if (query.isBlank()) { 148 | Toast.makeText(this, "查询内容为空", Toast.LENGTH_SHORT).show() 149 | return 150 | } else { 151 | MySearchUtils.doSearch(this, query) 152 | } 153 | } 154 | 155 | /** 156 | * 获取 自定义的 btn 157 | */ 158 | private fun getBtn(): AppCompatButton { 159 | val ctx = baseContext 160 | 161 | val btn = AppCompatButton(this) 162 | btn.layoutParams = FlexboxLayout.LayoutParams( 163 | ViewGroup.LayoutParams.WRAP_CONTENT, 164 | LayoutUtils.spToInt(ctx, 36) 165 | ) 166 | 167 | val layer2 = btn.layoutParams as ViewGroup.MarginLayoutParams 168 | layer2.topMargin = LayoutUtils.spToInt(ctx, 4) 169 | layer2.bottomMargin = LayoutUtils.spToInt(ctx, 4) 170 | layer2.marginStart = LayoutUtils.spToInt(ctx, 5) 171 | layer2.marginEnd = LayoutUtils.spToInt(ctx, 5) 172 | 173 | btn.setBackgroundResource(R.drawable.search_button_bg) 174 | btn.setTextColor(Color.parseColor("#666666")) 175 | btn.setPadding(30, 0, 30, 0) 176 | 177 | return btn 178 | } 179 | 180 | /** 181 | * 加载搜索的历史 182 | */ 183 | fun loadSearchHistoryKeyword() { 184 | val view = AppUtils.getRootView(this) 185 | val asb = ActivitySearchBinding.bind(view) 186 | 187 | val searchFlexBoxLayout = asb.searchHistoryFlexBoxLayoutId 188 | searchFlexBoxLayout.removeAllViews() 189 | 190 | AppPreferenceUtils.getSearchHistory(this).map { 191 | val btn = this.getBtn() 192 | btn.text = it 193 | 194 | btn.setOnClickListener { _ -> 195 | MySearchUtils.doSearch(this, it) 196 | } 197 | 198 | btn.requestLayout() 199 | searchFlexBoxLayout.addView(btn) 200 | } 201 | searchFlexBoxLayout.requestLayout() 202 | } 203 | 204 | /// 把搜索的热词加载到界面中 205 | fun pushHotSearchKeyword(dataList: List) { 206 | val view = AppUtils.getRootView(this) 207 | val asb = ActivitySearchBinding.bind(view) 208 | 209 | val fl = asb.hotSearchFlexBoxLayoutId 210 | fl.removeAllViews() 211 | dataList.map { 212 | val btn = this.getBtn() 213 | btn.text = it 214 | btn.setOnClickListener { _ -> 215 | MySearchUtils.doSearch(this, it) 216 | } 217 | btn.requestLayout() 218 | fl.addView(btn) 219 | } 220 | fl.requestLayout() 221 | } 222 | } 223 | -------------------------------------------------------------------------------- /app/src/main/java/com/qiyutech/tbk/SettingsActivity.kt: -------------------------------------------------------------------------------- 1 | package com.qiyutech.tbk 2 | 3 | import android.annotation.SuppressLint 4 | import android.os.Bundle 5 | import android.view.View 6 | import android.widget.Toast 7 | import androidx.appcompat.app.AppCompatActivity 8 | import com.qiyutech.tbk.fragments.settings.SettingsFragmentLogin 9 | import com.qiyutech.tbk.fragments.settings.SettingsFragmentUser 10 | import com.qiyutech.tbk.logic.UserLogic 11 | import com.qiyutech.tbk.utils.AppUtils 12 | import com.qiyutech.tbk.utils.DialogUtils 13 | import com.qiyutech.tbk.utils.PopupUtils 14 | 15 | /** 16 | * 配置 UI 页面 17 | */ 18 | class SettingsActivity : AppCompatActivity() { 19 | @SuppressLint("InflateParams") 20 | override fun onCreate(savedInstanceState: Bundle?) { 21 | super.onCreate(savedInstanceState) 22 | setContentView(R.layout.settings_activity) 23 | } 24 | 25 | override fun onStart() { 26 | super.onStart() 27 | 28 | this.refreshUI() 29 | } 30 | 31 | private fun refreshUI() { 32 | val fragment = if (AppUtils.checkUserLogin(this)) { 33 | SettingsFragmentUser() 34 | } else { 35 | SettingsFragmentLogin() 36 | } 37 | 38 | supportFragmentManager.beginTransaction() 39 | .replace(R.id.setting_slot, fragment) 40 | .commit() 41 | } 42 | 43 | 44 | // 注销用户 45 | @Suppress("UNUSED_PARAMETER") 46 | fun settingUserCancel(view: View) { 47 | if (!AppUtils.checkUserLogin(this)) { 48 | return 49 | } 50 | 51 | /// 用户确认之后执行 注销用户的逻辑 52 | DialogUtils.userCancelDialog(this) { 53 | UserLogic.cancel(this) 54 | }.show() 55 | } 56 | 57 | /** 58 | * 退出登陆 59 | */ 60 | @Suppress("UNUSED_PARAMETER") 61 | fun settingUserLogout(view: View) { 62 | if (AppUtils.checkUserLogin(this)) { 63 | UserLogic.logout(this) 64 | Toast.makeText(this, "您已经退出登陆!", Toast.LENGTH_LONG).show() 65 | } else { 66 | Toast.makeText(this, "您当前没有登陆!", Toast.LENGTH_LONG).show() 67 | } 68 | setNotLoginView() 69 | } 70 | 71 | fun setNotLoginView() { 72 | // 用户已经退出登陆 73 | this.refreshUI() 74 | } 75 | 76 | /** 77 | * android 清理缓存 78 | */ 79 | fun deleteCacheFiles(view: View) { 80 | 81 | val (_, popupWindow) = PopupUtils.createPopup( 82 | view, 83 | inflater = layoutInflater, 84 | R.layout.popup_clean_cache, 85 | false 86 | ) 87 | 88 | val activity = this 89 | val cache = cacheDir 90 | 91 | Thread { 92 | cache.deleteRecursively() 93 | 94 | runOnUiThread { 95 | popupWindow.dismiss() 96 | Toast.makeText(activity, "清理缓存完成", Toast.LENGTH_LONG).show() 97 | } 98 | }.start() 99 | } 100 | 101 | 102 | /** 103 | * 检测是否有新版本 [android 检测] iOS 使用 App Store 接口就可以了 104 | */ 105 | fun checkAppUpgrade(view: View) { 106 | Toast.makeText(this, "此功能已经移除", Toast.LENGTH_LONG).show() 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /app/src/main/java/com/qiyutech/tbk/TaoBaoActivity.kt: -------------------------------------------------------------------------------- 1 | package com.qiyutech.tbk 2 | 3 | import android.annotation.SuppressLint 4 | import android.app.Activity 5 | import android.content.Intent 6 | import android.os.Bundle 7 | import android.util.Log 8 | import android.webkit.WebChromeClient 9 | import android.webkit.WebView 10 | import android.webkit.WebViewClient 11 | import android.widget.Toast 12 | import androidx.appcompat.app.AppCompatActivity 13 | import com.alibaba.baichuan.android.trade.AlibcTrade 14 | import com.alibaba.baichuan.android.trade.model.AlibcShowParams 15 | import com.alibaba.baichuan.android.trade.model.OpenType 16 | import com.alibaba.baichuan.trade.biz.applink.adapter.AlibcFailModeType 17 | import com.alibaba.baichuan.trade.biz.core.taoke.AlibcTaokeParams 18 | import com.alibaba.baichuan.trade.biz.login.AlibcLogin 19 | import com.alibaba.baichuan.trade.biz.login.AlibcLoginCallback 20 | import com.qiyutech.tbk.activity.taobao.MyAuthTradeCb 21 | import com.qiyutech.tbk.databinding.ActivityTaoBaoBinding 22 | import com.qiyutech.tbk.utils.AppUtils 23 | import com.qiyutech.tbk.values.AppPreferenceUtils 24 | import com.qiyutech.tbk.values.LogTags 25 | 26 | @SuppressLint("SetJavaScriptEnabled") 27 | class TaoBaoActivity : AppCompatActivity() { 28 | override fun onCreate(savedInstanceState: Bundle?) { 29 | super.onCreate(savedInstanceState) 30 | setContentView(R.layout.activity_tao_bao) 31 | } 32 | 33 | @SuppressLint("JavascriptInterface") 34 | override fun onStart() { 35 | super.onStart() 36 | 37 | val wv = getTaoBaoWebView() 38 | wv.settings.javaScriptEnabled = true 39 | 40 | when (intent.getStringExtra("type")) { 41 | "auth" -> { 42 | myOpenAuthPage() 43 | } 44 | else -> { 45 | this.finish() 46 | } 47 | } 48 | } 49 | 50 | 51 | override fun onDestroy() { 52 | super.onDestroy() 53 | 54 | val wv = getTaoBaoWebView() 55 | wv.destroy() 56 | } 57 | 58 | private fun getTaoBaoWebView(): WebView { 59 | val view = AppUtils.getRootView(this) 60 | val tbd = ActivityTaoBaoBinding.bind(view) 61 | return tbd.taoBaoWebView 62 | } 63 | 64 | private fun myOpenAuthPage() { 65 | val url = intent.getStringExtra("url") 66 | 67 | val activity = this 68 | 69 | /// 淘宝授权免密码输入 70 | /// https://blog.csdn.net/get_moon/article/details/102593901 71 | 72 | val alibc = AlibcLogin.getInstance() 73 | alibc.showLogin(object : AlibcLoginCallback { 74 | override fun onSuccess(LoginResult: Int, openId: String?, userNick: String?) { 75 | // loginResult(0--登录初始化成功;1--登录初始化完成;2--登录成功) 76 | // openId:用户id 77 | // userNick: 用户昵称 78 | 79 | // save user nick 80 | // save user avatar 81 | val session = alibc.session 82 | AppPreferenceUtils.setTaoId(activity, session.userid) 83 | 84 | Log.i(LogTags.AliBC, "$session") 85 | 86 | val show = AlibcShowParams() 87 | 88 | show.openType = OpenType.Auto 89 | show.clientType = "taobao" 90 | show.nativeOpenFailedMode = AlibcFailModeType.AlibcNativeFailModeJumpH5 91 | 92 | val taoke = AlibcTaokeParams("", "", "") 93 | taoke.pid = BuildConfig.ALI_PID 94 | 95 | AlibcTrade.openByUrl( 96 | activity, 97 | "", 98 | url, 99 | getTaoBaoWebView(), 100 | WebViewClient(), 101 | WebChromeClient(), 102 | show, 103 | taoke, 104 | null, 105 | MyAuthTradeCb() 106 | ) 107 | } 108 | 109 | override fun onFailure(code: Int, msg: String?) { 110 | // code 错误码 111 | // msg 错误信息 112 | Toast.makeText(activity, "淘宝授权失败($code): $msg", Toast.LENGTH_SHORT).show() 113 | } 114 | }) 115 | } 116 | 117 | companion object { 118 | fun openAuthPage(activity: Activity, url: String) { 119 | val intent = Intent(activity, TaoBaoActivity::class.java) 120 | 121 | intent.putExtra("type", "auth") // enum type 122 | intent.putExtra("url", url) 123 | 124 | // activity.startActivity(intent) 125 | activity.startActivityForResult(intent, MeActivity.AUTH_REQUEST_CODE) 126 | } 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /app/src/main/java/com/qiyutech/tbk/UserInfoActivity.kt: -------------------------------------------------------------------------------- 1 | package com.qiyutech.tbk 2 | 3 | import android.os.Bundle 4 | import androidx.appcompat.app.AppCompatActivity 5 | import com.qiyutech.tbk.databinding.ActivityUserInfoBinding 6 | import com.qiyutech.tbk.databinding.PartsSimpleKvInfoBinding 7 | import com.qiyutech.tbk.fragments.TextHeaderFragment 8 | import com.qiyutech.tbk.logic.TaoBaoLogic 9 | import com.qiyutech.tbk.utils.AppUtils 10 | import com.qiyutech.tbk.utils.DialogUtils 11 | import com.qiyutech.tbk.values.AppPreferenceUtils 12 | 13 | /** 14 | * 用户状态展示 15 | */ 16 | class UserInfoActivity : AppCompatActivity() { 17 | override fun onCreate(savedInstanceState: Bundle?) { 18 | super.onCreate(savedInstanceState) 19 | setContentView(R.layout.activity_user_info) 20 | 21 | 22 | supportFragmentManager.beginTransaction() 23 | .replace(R.id.header, TextHeaderFragment("用户信息", true)) 24 | .commit() 25 | 26 | initBtnEvent() 27 | } 28 | 29 | override fun onStart() { 30 | super.onStart() 31 | 32 | initUserInfo() 33 | } 34 | 35 | private fun initBtnEvent() { 36 | val bd = getBinding() 37 | bd.bindTb.setOnClickListener { 38 | val doBind = { 39 | val logic = TaoBaoLogic(this) 40 | logic.tryAuth() 41 | } 42 | AppPreferenceUtils.getUserInfo(this)?.let { userInfo -> 43 | userInfo.relation_id?.let { 44 | // 已经绑定了淘宝账号, 是否重新绑定 45 | DialogUtils.reBindTbDialog(this) { 46 | doBind() 47 | } 48 | return@setOnClickListener 49 | } 50 | } 51 | doBind() 52 | } 53 | } 54 | 55 | private fun initUserInfo() { 56 | val userInfo = AppPreferenceUtils.getUserInfo(this) 57 | if (userInfo == null) { 58 | this.finish() 59 | return 60 | } 61 | 62 | val bd = getBinding() 63 | 64 | setKV(bd.mobile, "手机号码", userInfo.mobile ?: "") 65 | setKV(bd.taoId, "淘宝ID", userInfo.tao_id ?: "") 66 | setKV(bd.wx, "微信", userInfo.wx ?: "") 67 | setKV(bd.relationId, "渠道ID", userInfo.relation_id ?: "") 68 | setKV(bd.aliName, "支付宝姓名", userInfo.ali_name ?: "") 69 | setKV(bd.aliAccount, "支付宝账号", userInfo.ali_account ?: "") 70 | } 71 | 72 | private fun setKV(bd: PartsSimpleKvInfoBinding, k: String, v: String) { 73 | bd.key.text = k 74 | bd.value.text = v 75 | } 76 | 77 | private fun getBinding(): ActivityUserInfoBinding { 78 | val rv = AppUtils.getRootView(this) 79 | return ActivityUserInfoBinding.bind(rv) 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /app/src/main/java/com/qiyutech/tbk/UserPasswordActivity.kt: -------------------------------------------------------------------------------- 1 | package com.qiyutech.tbk 2 | 3 | import android.os.Bundle 4 | import android.view.View 5 | import android.widget.Toast 6 | import androidx.appcompat.app.AppCompatActivity 7 | import com.qiyutech.tbk.databinding.UserPasswordActivityBinding 8 | import com.qiyutech.tbk.fragments.TextHeaderFragment 9 | import com.qiyutech.tbk.logic.UserLogic 10 | import com.qiyutech.tbk.utils.AppUtils 11 | 12 | 13 | /** 14 | * 账号密码登陆页面 15 | */ 16 | class UserPasswordActivity : AppCompatActivity() { 17 | 18 | override fun onCreate(savedInstanceState: Bundle?) { 19 | super.onCreate(savedInstanceState) 20 | setContentView(R.layout.user_password_activity) 21 | 22 | supportFragmentManager.beginTransaction() 23 | .replace(R.id.user_password_header, TextHeaderFragment("奇遇淘客登录", true)) 24 | .commit() 25 | } 26 | 27 | /** 28 | * 关闭当前的界面 29 | */ 30 | fun userPasswordClose(view: View) { 31 | this.finish() 32 | } 33 | 34 | /** 35 | * 用户密码登陆 36 | */ 37 | fun usernamePasswordLogin(view: View) { 38 | val rv = AppUtils.getRootView(this) 39 | val bind = UserPasswordActivityBinding.bind(rv) 40 | 41 | val username = bind.usernameText.text.toString() 42 | val password = bind.passwordText.text.toString() 43 | 44 | if (username.isEmpty()) { 45 | Toast.makeText(this, "账号不能为空", Toast.LENGTH_LONG).show() 46 | return 47 | } 48 | 49 | if (password.isEmpty()) { 50 | Toast.makeText(this, "密码不能为空", Toast.LENGTH_LONG).show() 51 | return 52 | } 53 | 54 | UserLogic.usernamePasswordTryLogin(this, username = username, password = password) 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /app/src/main/java/com/qiyutech/tbk/activity/question/MyJsonObjectRequest.kt: -------------------------------------------------------------------------------- 1 | package com.qiyutech.tbk.activity.question 2 | 3 | import com.android.volley.Response 4 | import com.android.volley.toolbox.JsonObjectRequest 5 | import org.json.JSONObject 6 | 7 | class MyJsonObjectRequest( 8 | i: Int, 9 | url: String, 10 | json: JSONObject, 11 | success: Response.Listener, 12 | failure: Response.ErrorListener 13 | ) : 14 | JsonObjectRequest(i, url, json, success, failure) { 15 | 16 | override fun getHeaders(): Map { 17 | return mapOf("Accept" to "application/json", "Content-Type" to "application/json") 18 | } 19 | } 20 | 21 | class MyGetRequest( 22 | url: String, 23 | success: Response.Listener, 24 | failure: Response.ErrorListener 25 | ) : JsonObjectRequest(Method.GET, url, null, success, failure) { 26 | 27 | override fun getHeaders(): Map { 28 | return mapOf("accept" to "application/json") 29 | } 30 | } 31 | 32 | 33 | class MySuggestRequest( 34 | url: String, 35 | success: Response.Listener, 36 | failure: Response.ErrorListener 37 | ) : 38 | JsonObjectRequest(url, null, success, failure) { 39 | 40 | override fun getHeaders(): Map { 41 | return mapOf("accept" to "application/json") 42 | } 43 | } 44 | 45 | -------------------------------------------------------------------------------- /app/src/main/java/com/qiyutech/tbk/activity/taobao/MyAuthCb.kt: -------------------------------------------------------------------------------- 1 | package com.qiyutech.tbk.activity.taobao 2 | 3 | import android.util.Log 4 | import com.alibaba.baichuan.android.trade.callback.AlibcTradeCallback 5 | import com.alibaba.baichuan.trade.biz.context.AlibcTradeResult 6 | import com.qiyutech.tbk.values.LogTags 7 | 8 | /** 9 | * 打开 认证页面的 回调 10 | */ 11 | class MyAuthTradeCb : AlibcTradeCallback { 12 | override fun onFailure(p0: Int, p1: String?) { 13 | Log.e(LogTags.AliBC, "错误信息: ${p0}: $p1") 14 | } 15 | 16 | override fun onTradeSuccess(p: AlibcTradeResult?) { 17 | if (p == null) { 18 | return 19 | } 20 | Log.i(LogTags.AliBC, p.toString()) 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /app/src/main/java/com/qiyutech/tbk/api/ZTK.kt: -------------------------------------------------------------------------------- 1 | package com.qiyutech.tbk.api 2 | 3 | import androidx.appcompat.app.AppCompatActivity 4 | import com.android.volley.VolleyError 5 | import com.android.volley.toolbox.JsonObjectRequest 6 | import com.android.volley.toolbox.Volley 7 | import com.qiyutech.tbk.dt.DtKeywordResponseModel 8 | import com.qiyutech.tbk.dt.DtSuggestResponseModel 9 | import com.qiyutech.tbk.utils.MyHttpUtils 10 | import com.qiyutech.tbk.values.TbkAPIUrls 11 | import java.net.URLEncoder 12 | 13 | /** 14 | * 折淘客 API 接口 15 | */ 16 | class ZTK(val activity: AppCompatActivity, val tag: String) { 17 | 18 | /** 19 | * 获取 推荐词 的请求 20 | */ 21 | fun suggestV2( 22 | q: String, 23 | success: (DtSuggestResponseModel) -> Unit, 24 | failure: (VolleyError) -> Unit 25 | ) { 26 | val url = "${TbkAPIUrls.ZtkSuggest}?content=${URLEncoder.encode(q, "UTF-8")}" 27 | val r = MyHttpUtils.getRequest(url, success, failure) 28 | addToQueue(r) 29 | } 30 | 31 | 32 | /** 33 | * 热词推荐 34 | */ 35 | fun hotKeyword(success: (DtKeywordResponseModel) -> Unit, failure: (VolleyError) -> Unit) { 36 | val r = MyHttpUtils.getRequest( 37 | TbkAPIUrls.ZtkKeyword, 38 | success, 39 | failure 40 | ) 41 | addToQueue(r) 42 | } 43 | 44 | private fun addToQueue(r: JsonObjectRequest) { 45 | r.tag = tag 46 | val volley = Volley.newRequestQueue(activity) 47 | volley.add(r) 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /app/src/main/java/com/qiyutech/tbk/application/AliBCCallback.kt: -------------------------------------------------------------------------------- 1 | package com.qiyutech.tbk.application 2 | 3 | import android.app.Application 4 | import android.util.Log 5 | import android.widget.Toast 6 | import com.alibaba.baichuan.android.trade.callback.AlibcTradeInitCallback 7 | import com.qiyutech.tbk.values.LogTags 8 | 9 | /** 10 | * 阿里百川回调 11 | */ 12 | class AliBCCallback(private val app: Application) : AlibcTradeInitCallback { 13 | override fun onFailure(p0: Int, p1: String?) { 14 | Toast.makeText(app.baseContext, "阿里百川初始化失败: $p1($p0)", Toast.LENGTH_LONG).show() 15 | Log.i(LogTags.AliBC, "初始化失败: $p1($p0)") 16 | } 17 | 18 | override fun onSuccess() { 19 | Log.i(LogTags.AliBC, "初始化成功") 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /app/src/main/java/com/qiyutech/tbk/application/AppSwipeBack.kt: -------------------------------------------------------------------------------- 1 | package com.qiyutech.tbk.application 2 | 3 | import android.app.Activity 4 | import com.billy.android.swipe.SmartSwipeBack 5 | import com.qiyutech.tbk.* 6 | 7 | /** 8 | * 侧边滑动返回 9 | * 10 | * https://qibilly.com/SmartSwipe-tutorial/pages/SmartSwipeBack.html 11 | */ 12 | class AppSwipeBack : SmartSwipeBack.ActivitySwipeBackFilter { 13 | override fun onFilter(activity: Activity?): Boolean { 14 | if (activity == null) { 15 | return false 16 | } 17 | 18 | return when (activity) { 19 | is DevInfoActivity -> true 20 | is ItemDetailV2Activity -> true 21 | is PrivacyActivity -> true 22 | is SearchActivity -> true 23 | is SearchDetailNativeActivity -> true 24 | is SettingsActivity -> true 25 | is TaoBaoActivity -> true 26 | is UserInfoActivity -> true 27 | is UserPasswordActivity -> true 28 | else -> false 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /app/src/main/java/com/qiyutech/tbk/dt/shared.kt: -------------------------------------------------------------------------------- 1 | package com.qiyutech.tbk.dt 2 | 3 | 4 | enum class TbkSortType { 5 | Common, // 综合排序 6 | Sales, // 销量 7 | Price; // 价格 8 | 9 | 10 | fun getString(): String? { 11 | return when (this) { 12 | Common -> null 13 | Sales -> "total_sales_des" 14 | Price -> "price_asc" 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /app/src/main/java/com/qiyutech/tbk/events/LoginEvent.kt: -------------------------------------------------------------------------------- 1 | package com.qiyutech.tbk.events 2 | 3 | import android.content.Context 4 | import com.qiyutech.tbk.logic.TaoBaoLogic 5 | import com.qiyutech.tbk.utils.PushUtils 6 | 7 | /** 8 | * 登陆之后的回调 9 | */ 10 | object LoginEvent { 11 | /** 12 | * 回调函数 13 | */ 14 | fun callback(ctx: Context) { 15 | /// 登陆之后 需要发送 绑定新的 push ID 16 | PushUtils.reportPushId(ctx) 17 | /// 登陆之后自动检测是否已经绑定淘宝号 18 | TaoBaoLogic.detectTaoBaoBind(ctx) 19 | } 20 | } 21 | 22 | -------------------------------------------------------------------------------- /app/src/main/java/com/qiyutech/tbk/events/LogoutEvent.kt: -------------------------------------------------------------------------------- 1 | package com.qiyutech.tbk.events 2 | 3 | import android.content.Context 4 | import com.qiyutech.tbk.utils.PushUtils 5 | 6 | /** 7 | * 退出登陆之后的事件 8 | */ 9 | object LogoutEvent { 10 | /** 11 | * 回调函数 12 | */ 13 | fun callback(ctx: Context) { 14 | PushUtils.reportPushId(ctx) 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /app/src/main/java/com/qiyutech/tbk/extend/MyNetworkImageView.kt: -------------------------------------------------------------------------------- 1 | package com.qiyutech.tbk.extend 2 | 3 | import android.content.Context 4 | import android.util.AttributeSet 5 | import androidx.appcompat.widget.AppCompatImageView 6 | import com.bumptech.glide.Glide 7 | import com.bumptech.glide.load.engine.DiskCacheStrategy 8 | import com.qiyutech.tbk.utils.NetworkImageUtils 9 | import com.qiyutech.tbk.utils.TipUtils 10 | 11 | /** 12 | * 编程自动加载图片 13 | */ 14 | class MyManualImageView(ctx: Context) : AppCompatImageView(ctx) { 15 | /** 16 | * 自动加载图片 17 | */ 18 | fun loadImageFromUrl(imageUrl: String) { 19 | val url = if (imageUrl.startsWith("//")) { 20 | "http:${imageUrl}" 21 | } else { 22 | imageUrl 23 | } 24 | 25 | Glide.with(context) 26 | .load(url) 27 | .diskCacheStrategy(DiskCacheStrategy.ALL) 28 | .skipMemoryCache(true) 29 | .into(this) 30 | } 31 | } 32 | 33 | /** 34 | * 网络图片 View 35 | * 自动加载网络图片 如果需要的话 36 | */ 37 | class MyNetworkImageView(ctx: Context, attrSet: AttributeSet) : AppCompatImageView(ctx, attrSet) { 38 | /** 39 | * 自动加载图片 40 | */ 41 | fun loadImageFromUrl(imageUrl: String, displayError: Boolean = false) { 42 | val url = if (imageUrl.startsWith("//")) { 43 | "http:${imageUrl}" 44 | } else { 45 | imageUrl 46 | } 47 | 48 | // 使用 glide 加载会导致 slot 图片不展示 49 | NetworkImageUtils.download(context, 50 | url, 51 | this.scaleType, 52 | { image -> this.setImageBitmap(image) }, 53 | { 54 | if (displayError) { 55 | TipUtils.toastShort(context, "下载图片失败: $it") 56 | } 57 | }) 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /app/src/main/java/com/qiyutech/tbk/fragments/SFooterFragment.kt: -------------------------------------------------------------------------------- 1 | package com.qiyutech.tbk.fragments 2 | 3 | import android.os.Bundle 4 | import android.view.LayoutInflater 5 | import android.view.View 6 | import android.view.ViewGroup 7 | import androidx.fragment.app.Fragment 8 | import com.qiyutech.tbk.* 9 | import com.qiyutech.tbk.databinding.SFooterBinding 10 | import com.qiyutech.tbk.utils.AppNavUtils 11 | 12 | 13 | /** 14 | * 导航依赖 15 | */ 16 | class SFooterFragment : Fragment(R.layout.fragment_s_footer) { 17 | /// 绑定视图到 Fragment 18 | /// https://developer.android.com/topic/libraries/view-binding 19 | private var _binding: SFooterBinding? = null 20 | 21 | // This property is only valid between onCreateView and 22 | // onDestroyView. 23 | private val binding get() = _binding!! 24 | 25 | 26 | override fun onCreateView( 27 | inflater: LayoutInflater, 28 | container: ViewGroup?, 29 | savedInstanceState: Bundle? 30 | ): View { 31 | _binding = SFooterBinding.inflate(inflater, container, false) 32 | 33 | return binding.root 34 | } 35 | 36 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) { 37 | super.onViewCreated(view, savedInstanceState) 38 | 39 | val menu = binding.homeFooter.menu 40 | 41 | val index = menu.getItem(0) 42 | if (activity is HomeActivity) { 43 | index.isChecked = true 44 | } else { 45 | index.setOnMenuItemClickListener { 46 | AppNavUtils.gotoHome(requireActivity()) 47 | true 48 | } 49 | } 50 | 51 | val group = menu.getItem(1) 52 | if (activity is GroupActivity) { 53 | group.isChecked = true 54 | } else { 55 | group.setOnMenuItemClickListener { 56 | AppNavUtils.gotoGroup(requireActivity()) 57 | true 58 | } 59 | } 60 | 61 | 62 | val coupon = menu.getItem(2) 63 | if (activity is CouponActivity) { 64 | coupon.isChecked = true 65 | } else { 66 | coupon.setOnMenuItemClickListener { 67 | AppNavUtils.gotoCoupon(requireActivity()) 68 | true 69 | } 70 | } 71 | 72 | val me = menu.getItem(3) 73 | if (activity is MeActivity) { 74 | me.isChecked = true 75 | } else { 76 | me.setOnMenuItemClickListener { 77 | AppNavUtils.gotoMe(requireActivity()) 78 | true 79 | } 80 | } 81 | } 82 | 83 | override fun onDestroyView() { 84 | super.onDestroyView() 85 | _binding = null 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /app/src/main/java/com/qiyutech/tbk/fragments/TextHeaderFragment.kt: -------------------------------------------------------------------------------- 1 | package com.qiyutech.tbk.fragments 2 | 3 | import android.os.Bundle 4 | import android.view.LayoutInflater 5 | import android.view.View 6 | import android.view.ViewGroup 7 | import androidx.fragment.app.Fragment 8 | import com.qiyutech.tbk.databinding.FragmentTextHeaderBinding 9 | 10 | 11 | /** 12 | * 简单的文字 header 界面 13 | * 14 | * 也许应该增加是否需要返回按钮 15 | */ 16 | class TextHeaderFragment( 17 | private val title: String, 18 | private val displayBack: Boolean = false 19 | ) : Fragment() { 20 | 21 | private var bd: FragmentTextHeaderBinding? = null 22 | 23 | override fun onCreateView( 24 | inflater: LayoutInflater, 25 | container: ViewGroup?, 26 | savedInstanceState: Bundle? 27 | ): View? { 28 | bd = FragmentTextHeaderBinding.inflate(inflater, container, false) 29 | bd?.let { 30 | it.title.text = title 31 | 32 | this.initBackButton() 33 | 34 | return it.root 35 | } 36 | return null 37 | } 38 | 39 | private fun initBackButton() { 40 | bd?.let { 41 | if (!displayBack) { 42 | it.backBtn.visibility = View.GONE 43 | } 44 | it.backBtn.setOnClickListener { 45 | this.requireActivity().finish() 46 | } 47 | } 48 | } 49 | 50 | /** 51 | * 设置新的 title 52 | */ 53 | fun setTitle(title: String) { 54 | bd?.let { 55 | it.title.text = title 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /app/src/main/java/com/qiyutech/tbk/fragments/me/MeFragmentDefault.kt: -------------------------------------------------------------------------------- 1 | package com.qiyutech.tbk.fragments.me 2 | 3 | import android.os.Bundle 4 | import android.view.LayoutInflater 5 | import android.view.View 6 | import android.view.ViewGroup 7 | import androidx.fragment.app.Fragment 8 | import com.qiyutech.tbk.databinding.FragmentMeDefaultBinding 9 | import com.qiyutech.tbk.utils.AppNavUtils 10 | 11 | 12 | /** 13 | * 我的默认界面【没有登录】 14 | */ 15 | class MeFragmentDefault : Fragment() { 16 | 17 | var bd: FragmentMeDefaultBinding? = null 18 | 19 | override fun onCreateView( 20 | inflater: LayoutInflater, container: ViewGroup?, 21 | savedInstanceState: Bundle? 22 | ): View { 23 | val t = FragmentMeDefaultBinding.inflate(inflater, container, false) 24 | bd = t 25 | return t.root 26 | } 27 | 28 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) { 29 | super.onViewCreated(view, savedInstanceState) 30 | bd?.let { 31 | 32 | it.gotoSetting.setOnClickListener { 33 | AppNavUtils.gotoSettings(requireActivity()) 34 | } 35 | 36 | it.meName.setOnClickListener { 37 | // todo login 38 | } 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /app/src/main/java/com/qiyutech/tbk/fragments/me/MeFragmentSlot.kt: -------------------------------------------------------------------------------- 1 | package com.qiyutech.tbk.fragments.me 2 | 3 | import android.os.Bundle 4 | import android.view.LayoutInflater 5 | import android.view.View 6 | import android.view.ViewGroup 7 | import androidx.fragment.app.Fragment 8 | import com.qiyutech.tbk.databinding.FragmentMeSlotBinding 9 | 10 | 11 | /** 12 | * 我的已经登陆的界面 13 | */ 14 | class MeFragmentSlot : Fragment() { 15 | 16 | var bd: FragmentMeSlotBinding? = null 17 | 18 | override fun onCreateView( 19 | inflater: LayoutInflater, container: ViewGroup?, 20 | savedInstanceState: Bundle? 21 | ): View { 22 | val t = FragmentMeSlotBinding.inflate(inflater, container, false) 23 | bd = t 24 | return t.root 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/java/com/qiyutech/tbk/fragments/me/MeFragmentUser.kt: -------------------------------------------------------------------------------- 1 | package com.qiyutech.tbk.fragments.me 2 | 3 | import android.os.Bundle 4 | import android.util.Log 5 | import android.view.LayoutInflater 6 | import android.view.View 7 | import android.view.ViewGroup 8 | import android.widget.Toast 9 | import androidx.fragment.app.Fragment 10 | import com.qiyutech.tbk.MeActivity 11 | import com.qiyutech.tbk.MeActivityUserViewModel 12 | import com.qiyutech.tbk.databinding.FragmentMeUserBinding 13 | import com.qiyutech.tbk.dt.ApiUserProfileStub 14 | import com.qiyutech.tbk.dt.DtUserTokenForm 15 | import com.qiyutech.tbk.logic.AppErrnoLogic 16 | import com.qiyutech.tbk.logic.DisplayLogic 17 | import com.qiyutech.tbk.logic.TaoBaoLogic 18 | import com.qiyutech.tbk.utils.AppNavUtils 19 | import com.qiyutech.tbk.utils.TipUtils 20 | import com.qiyutech.tbk.values.AppPreferenceUtils 21 | 22 | 23 | /** 24 | * 我的已经登陆的界面 25 | */ 26 | class MeFragmentUser : Fragment() { 27 | 28 | var bd: FragmentMeUserBinding? = null 29 | 30 | override fun onCreateView( 31 | inflater: LayoutInflater, container: ViewGroup?, 32 | savedInstanceState: Bundle? 33 | ): View { 34 | val t = FragmentMeUserBinding.inflate(inflater, container, false) 35 | bd = t 36 | return t.root 37 | } 38 | 39 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) { 40 | super.onViewCreated(view, savedInstanceState) 41 | 42 | bd?.let { 43 | initButtonEvent(it, view) 44 | } 45 | 46 | setValueAndInitObserver() 47 | initSwipeRefresh() 48 | } 49 | 50 | private fun initButtonEvent(bd: FragmentMeUserBinding, view: View) { 51 | val activity = this.requireActivity() as MeActivity 52 | 53 | bd.meIcon.setOnClickListener { 54 | AppNavUtils.gotoUserInfo(activity) 55 | } 56 | 57 | 58 | bd.gotoOrder.setOnClickListener { 59 | TipUtils.barShort(view, "功能已经移除") 60 | } 61 | 62 | 63 | 64 | bd.tryTaobaoAuth.setOnClickListener { 65 | val bind = AppPreferenceUtils.getBindTaoBao(activity) 66 | if (bind) { 67 | Toast.makeText(activity, "淘宝已经授权", Toast.LENGTH_LONG).show() 68 | return@setOnClickListener 69 | } 70 | 71 | // 尝试淘宝授权 72 | val logic = TaoBaoLogic(activity) 73 | logic.tryAuth() 74 | } 75 | 76 | 77 | 78 | bd.gotoSetting.setOnClickListener { 79 | AppNavUtils.gotoSettings(activity) 80 | } 81 | } 82 | 83 | private fun initSwipeRefresh() { 84 | bd?.let { 85 | it.swipeRefresh.setOnRefreshListener { 86 | this.doFetchUserProfile() 87 | } 88 | } 89 | } 90 | 91 | 92 | private fun doFetchUserProfile() { 93 | val activity = this.requireActivity() as MeActivity 94 | val form = DtUserTokenForm(token = AppPreferenceUtils.getUserToken(activity)) 95 | ApiUserProfileStub.myPost(activity, form, 96 | { ret -> 97 | AppErrnoLogic.genericServerErrnoProcess(ret.errno, activity) 98 | Log.i("user/profile", "$ret") 99 | try { 100 | if (ret.errno != 0) { 101 | TipUtils.toastShort(activity, "更新状态失败: ${ret.errmsg}") 102 | return@myPost 103 | } 104 | ret.data?.let { data -> 105 | AppPreferenceUtils.setUserInfo(activity, data) 106 | val viewModel = this.getUserViewModel() 107 | viewModel.displayName.value = DisplayLogic.getDisplayName(activity) 108 | viewModel.uuid.value = AppPreferenceUtils.getUserUuid(activity) 109 | TipUtils.toastShort(activity, "更新用户状态成功") 110 | } 111 | } finally { 112 | bd?.swipeRefresh?.isRefreshing = false 113 | } 114 | }, 115 | { error -> 116 | Log.e("user/profile", "错误信息: ${error.localizedMessage}") 117 | TipUtils.toastShort(activity, "更新用户状态失败: ${error.localizedMessage}") 118 | bd?.swipeRefresh?.isRefreshing = false 119 | }) 120 | } 121 | 122 | private fun setValueAndInitObserver() { 123 | val activity = this.requireActivity() as MeActivity 124 | 125 | val owner = viewLifecycleOwner 126 | // Get the ViewModel. 127 | val model = getUserViewModel() 128 | // Observe the LiveData, passing in this activity 129 | // as the LifecycleOwner and the observer. 130 | model.displayName.removeObservers(owner) 131 | model.uuid.removeObservers(owner) 132 | 133 | model.displayName.observe(owner, { newMobile -> 134 | bd!!.meName.text = newMobile 135 | }) 136 | 137 | AppPreferenceUtils.getUserInfo(activity)?.let { userInfo -> 138 | userInfo.tao_id?.let { taoId -> 139 | // extract to download image 140 | val imageUrl = 141 | "https://wwc.alicdn.com/avatar/getAvatar.do?userId=${taoId}&width=160&height=160&type=sns" 142 | bd!!.userIcon.loadImageFromUrl(imageUrl) 143 | } 144 | } 145 | 146 | // update UI element 147 | model.displayName.value = DisplayLogic.getDisplayName(activity) 148 | model.uuid.value = AppPreferenceUtils.getUserUuid(activity) 149 | 150 | } 151 | 152 | 153 | private fun getUserViewModel(): MeActivityUserViewModel { 154 | val activity = this.requireActivity() as MeActivity 155 | 156 | return activity.getUserViewModel() 157 | } 158 | } 159 | -------------------------------------------------------------------------------- /app/src/main/java/com/qiyutech/tbk/fragments/settings/SettingsFragmentLogin.kt: -------------------------------------------------------------------------------- 1 | package com.qiyutech.tbk.fragments.settings 2 | 3 | import android.os.Bundle 4 | import android.view.LayoutInflater 5 | import android.view.View 6 | import android.view.ViewGroup 7 | import androidx.fragment.app.Fragment 8 | import com.qiyutech.tbk.R 9 | import com.qiyutech.tbk.SettingsActivity 10 | import com.qiyutech.tbk.databinding.FragmentSettingsLoginBinding 11 | import com.qiyutech.tbk.fragments.TextHeaderFragment 12 | import com.qiyutech.tbk.utils.AppNavUtils 13 | import com.qiyutech.tbk.utils.AppUtils 14 | 15 | /** 16 | * 用户没有登陆的界面 17 | */ 18 | class SettingsFragmentLogin : Fragment() { 19 | /// 版本点击了多少次 20 | var versionClicked = 0 21 | 22 | private var bd: FragmentSettingsLoginBinding? = null 23 | 24 | override fun onCreateView( 25 | inflater: LayoutInflater, container: ViewGroup?, 26 | savedInstanceState: Bundle? 27 | ): View? { 28 | bd = FragmentSettingsLoginBinding.inflate(inflater, container, false) 29 | bd?.let { 30 | it.version.text = AppUtils.versionName() 31 | 32 | it.currentVersion.setOnClickListener { 33 | versionClicked += 1 34 | if (versionClicked == 6) { 35 | AppNavUtils.gotoDevInfo(requireActivity()) 36 | } 37 | } 38 | it.checkVersionUpdate.setOnClickListener { view -> 39 | val activity = this.requireActivity() as SettingsActivity 40 | activity.checkAppUpgrade(view) 41 | } 42 | it.showPrivacy.setOnClickListener { 43 | AppNavUtils.gotoPrivacy(this.requireActivity()) 44 | } 45 | it.cleanCache.setOnClickListener { view -> 46 | val activity = this.requireActivity() as SettingsActivity 47 | activity.deleteCacheFiles(view) 48 | } 49 | it.userLogin.setOnClickListener { 50 | val activity = this.requireActivity() as SettingsActivity 51 | AppNavUtils.gotoUserPassword(activity) 52 | } 53 | return it.root 54 | } 55 | return null 56 | } 57 | 58 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) { 59 | super.onViewCreated(view, savedInstanceState) 60 | 61 | val activity = this.requireActivity() 62 | activity.supportFragmentManager.beginTransaction() 63 | .replace(R.id.setting_header, TextHeaderFragment("设置", true)) 64 | .commit() 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /app/src/main/java/com/qiyutech/tbk/fragments/settings/SettingsFragmentUser.kt: -------------------------------------------------------------------------------- 1 | package com.qiyutech.tbk.fragments.settings 2 | 3 | import android.os.Bundle 4 | import android.view.LayoutInflater 5 | import android.view.View 6 | import android.view.ViewGroup 7 | import androidx.fragment.app.Fragment 8 | import com.qiyutech.tbk.R 9 | import com.qiyutech.tbk.SettingsActivity 10 | import com.qiyutech.tbk.databinding.FragmentSettingsUserBinding 11 | import com.qiyutech.tbk.fragments.TextHeaderFragment 12 | import com.qiyutech.tbk.utils.AppNavUtils 13 | import com.qiyutech.tbk.utils.AppUtils 14 | 15 | 16 | /** 17 | * 用户已经登陆的 fragment 18 | */ 19 | class SettingsFragmentUser : Fragment() { 20 | var versionClicked: Int = 0 21 | 22 | private var bd: FragmentSettingsUserBinding? = null 23 | 24 | override fun onCreateView( 25 | inflater: LayoutInflater, container: ViewGroup?, 26 | savedInstanceState: Bundle? 27 | ): View? { 28 | bd = FragmentSettingsUserBinding.inflate(inflater, container, false) 29 | bd?.let { 30 | it.version.text = AppUtils.versionName() 31 | 32 | it.currentVersion.setOnClickListener { 33 | versionClicked += 1 34 | if (versionClicked == 6) { 35 | AppNavUtils.gotoDevInfo(requireActivity()) 36 | } 37 | } 38 | it.checkVersionUpdate.setOnClickListener { view -> 39 | val activity = this.requireActivity() as SettingsActivity 40 | activity.checkAppUpgrade(view) 41 | } 42 | it.showPrivacy.setOnClickListener { 43 | AppNavUtils.gotoPrivacy(this.requireActivity()) 44 | } 45 | it.cleanCache.setOnClickListener { view -> 46 | val activity = this.requireActivity() as SettingsActivity 47 | activity.deleteCacheFiles(view) 48 | } 49 | it.exitLogin.setOnClickListener { view -> 50 | val activity = this.requireActivity() as SettingsActivity 51 | activity.settingUserLogout(view) 52 | } 53 | it.cancelUser.setOnClickListener { view -> 54 | val activity = this.requireActivity() as SettingsActivity 55 | activity.settingUserCancel(view) 56 | } 57 | 58 | return it.root 59 | } 60 | return null 61 | } 62 | 63 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) { 64 | super.onViewCreated(view, savedInstanceState) 65 | 66 | bd?.let { 67 | val activity = this.requireActivity() 68 | 69 | activity.supportFragmentManager.beginTransaction() 70 | .replace(R.id.setting_header, TextHeaderFragment("设置", true)) 71 | .commit() 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /app/src/main/java/com/qiyutech/tbk/logic/AppErrnoLogic.kt: -------------------------------------------------------------------------------- 1 | package com.qiyutech.tbk.logic 2 | 3 | import android.content.Context 4 | import android.util.Log 5 | import com.qiyutech.tbk.dt.DtAppErrno 6 | import com.qiyutech.tbk.utils.AppUtils 7 | import com.qiyutech.tbk.utils.TipUtils 8 | 9 | /** 10 | * 奇遇淘客错误处理逻辑 11 | */ 12 | object AppErrnoLogic { 13 | /** 14 | * 通用的奇遇淘客错误处理逻辑 15 | * 16 | * 每一个请求都要使用这个函数去处理错误码 17 | */ 18 | fun genericServerErrnoProcess(errno: DtAppErrno, ctx: Context) { 19 | when (errno) { 20 | 0 -> { 21 | // success do nothing 22 | } 23 | 1 -> { 24 | // 未知的错误 25 | TipUtils.toastLong(ctx, "未知错误 ~_~ 请稍后再试 (错误码: ${errno})") 26 | } 27 | 2 -> { 28 | // 系统内部错误 29 | TipUtils.toastLong(ctx, "网络错误 ~_~ 请稍后再试 (错误码: ${errno})") 30 | } 31 | 10 -> { 32 | // 无效的用输入 33 | } 34 | 11 -> { 35 | // 认证失败 [登陆失败] 36 | TipUtils.toastLong(ctx, "登录凭证已经过期,请重新登录") 37 | UserLogic.logout(ctx) 38 | } 39 | 20 -> { 40 | // not_found = 20 # 未找到指定内容 41 | } 42 | 21 -> { 43 | // token_invalid = 21 # 无效的 token [客户端应该执行退出 , 重新登录] 44 | // 执行 UserLogout 操作 45 | TipUtils.toastShort(ctx, "请登录后再试 (错误码: ${errno})") 46 | UserLogic.logout(ctx) 47 | } 48 | 22 -> { 49 | // ztk_error = 22 # 折淘客错误 50 | } 51 | 23 -> { 52 | // user_not_exists = 23 # 用户不存在 53 | } 54 | 24 -> { 55 | // 大淘客错误 56 | TipUtils.toastShort(ctx, "请求淘宝商品失败 错误($errno)") 57 | Log.i("大淘客", "请求大淘客失败") 58 | } 59 | 30 -> { 60 | // release_not_found = 30 # 没有发布的历史 61 | } 62 | 40 -> { 63 | // no_channel_id = 40 # 没有渠道 id 64 | } 65 | 41 -> { 66 | // item_not_found = 41 # 没有找到指定的商品 67 | TipUtils.toastLong(ctx, "没有找到对应的商品 (错误码: ${errno})") 68 | } 69 | else -> { 70 | // any other unknown value do nothing 71 | if (AppUtils.inDebugMode()) { 72 | TipUtils.toastLong(ctx, "系统遇到了未知的错误, 请检查是否为最新版 (错误码: ${errno})") 73 | } 74 | } 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /app/src/main/java/com/qiyutech/tbk/logic/CouponLogic.kt: -------------------------------------------------------------------------------- 1 | package com.qiyutech.tbk.logic 2 | 3 | import android.app.SearchManager 4 | import android.database.Cursor 5 | import android.database.MatrixCursor 6 | import android.provider.BaseColumns 7 | import android.util.Log 8 | import androidx.appcompat.widget.SearchView 9 | import com.qiyutech.tbk.CouponActivity 10 | import com.qiyutech.tbk.dt.ApiDtkSearchSuggestionStub 11 | import com.qiyutech.tbk.dt.DtGoodsSearchSuggestionArgs 12 | import com.qiyutech.tbk.utils.MySearchUtils 13 | 14 | 15 | class CouponSearchSuggestion(private val searchView: SearchView) : 16 | SearchView.OnSuggestionListener { 17 | 18 | override fun onSuggestionClick(position: Int): Boolean { 19 | val cursor = searchView.suggestionsAdapter.getItem(position) as Cursor 20 | val selection = cursor.getString(cursor.getColumnIndex(SearchManager.SUGGEST_COLUMN_TEXT_1)) 21 | searchView.setQuery(selection, false) 22 | return true 23 | } 24 | 25 | override fun onSuggestionSelect(position: Int): Boolean { 26 | return false 27 | } 28 | } 29 | 30 | 31 | class CouponSearchQueryTextListener( 32 | private val activity: CouponActivity, 33 | private val searchView: SearchView 34 | ) : SearchView.OnQueryTextListener { 35 | 36 | override fun onQueryTextSubmit(query: String?): Boolean { 37 | // extract to search method 38 | if (query.isNullOrBlank()) { 39 | return false 40 | } 41 | MySearchUtils.doCouponSearch(activity, query) 42 | return true 43 | } 44 | 45 | override fun onQueryTextChange(newText: String?): Boolean { 46 | if (newText.isNullOrBlank()) { 47 | return true 48 | } 49 | 50 | val args = DtGoodsSearchSuggestionArgs(keyWords = newText, type = "3") 51 | ApiDtkSearchSuggestionStub.myPost(activity, args, 52 | { v -> 53 | AppErrnoLogic.genericServerErrnoProcess(v.errno, activity) 54 | if (v.errno != 0) { 55 | Log.w("request suggest failed:", v.toString()) 56 | return@myPost 57 | } 58 | Log.i("search", v.toString()) 59 | val cursor = 60 | MatrixCursor(arrayOf(BaseColumns._ID, SearchManager.SUGGEST_COLUMN_TEXT_1)) 61 | 62 | v.data?.forEachIndexed { index, suggestion -> 63 | val item = arrayOf(index, suggestion) 64 | cursor.addRow(item) 65 | } 66 | 67 | this.searchView.suggestionsAdapter.changeCursor(cursor) 68 | 69 | }, 70 | { error -> Log.e("search suggest", "错误: $error") } 71 | ) 72 | 73 | return false 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /app/src/main/java/com/qiyutech/tbk/logic/DisplayLogic.kt: -------------------------------------------------------------------------------- 1 | package com.qiyutech.tbk.logic 2 | 3 | import android.content.Context 4 | import com.qiyutech.tbk.values.AppPreferenceUtils 5 | 6 | /** 7 | * 展示的逻辑 8 | */ 9 | object DisplayLogic { 10 | /** 11 | * 获取展示的名称 12 | * 13 | * 在我的里面展示的名称 14 | */ 15 | fun getDisplayName(ctx: Context): String { 16 | AppPreferenceUtils.getUserInfo(ctx)?.let { 17 | it.mobile?.let { mobile -> 18 | return mobile 19 | } 20 | } 21 | 22 | // 啥都没有就显示奇遇淘客 23 | return "奇遇淘客" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /app/src/main/java/com/qiyutech/tbk/logic/TaoBaoLogic.kt: -------------------------------------------------------------------------------- 1 | package com.qiyutech.tbk.logic 2 | 3 | import android.app.Activity 4 | import android.content.Context 5 | import android.util.Log 6 | import android.webkit.WebChromeClient 7 | import android.webkit.WebViewClient 8 | import com.alibaba.baichuan.android.trade.AlibcTrade 9 | import com.alibaba.baichuan.android.trade.callback.AlibcTradeCallback 10 | import com.alibaba.baichuan.android.trade.model.AlibcShowParams 11 | import com.alibaba.baichuan.android.trade.model.OpenType 12 | import com.alibaba.baichuan.trade.biz.context.AlibcResultType 13 | import com.alibaba.baichuan.trade.biz.context.AlibcTradeResult 14 | import com.alibaba.baichuan.trade.biz.core.taoke.AlibcTaokeParams 15 | import com.qiyutech.tbk.BuildConfig 16 | import com.qiyutech.tbk.TaoBaoActivity 17 | import com.qiyutech.tbk.dt.* 18 | import com.qiyutech.tbk.utils.TipUtils 19 | import com.qiyutech.tbk.values.AppPreferenceUtils 20 | import com.qiyutech.tbk.values.LogTags 21 | 22 | /** 23 | * 淘宝的逻辑 24 | */ 25 | class TaoBaoLogic(private val activity: Activity) { 26 | /** 27 | * 尝试淘宝授权 28 | */ 29 | fun tryAuth() { 30 | val form = DtAuthUrlForm(token = AppPreferenceUtils.getUserToken(activity)) 31 | 32 | ApiTaobaoAuthUrlStub.myPost(activity, form, 33 | { resp -> 34 | AppErrnoLogic.genericServerErrnoProcess(resp.errno, activity) 35 | if (resp.errno == 0) { 36 | resp.data?.let { 37 | Log.i(LogTags.TaoBao, it.url) 38 | openAliBCAuthPage(it.url) 39 | } 40 | } else { 41 | Log.e(LogTags.TaoBao, resp.errmsg) 42 | } 43 | }, 44 | { error -> 45 | TipUtils.toastShort(activity, "获取授权地址失败: ${error.localizedMessage}") 46 | }) 47 | } 48 | 49 | /** 50 | * 打开 阿里百川授权页面 51 | * showPageByUrl 52 | */ 53 | private fun openAliBCAuthPage(url: String) { 54 | 55 | TaoBaoActivity.openAuthPage(activity, url) 56 | 57 | } 58 | 59 | /** 60 | * 购买一个商品 61 | * 拉起淘宝去购买 62 | */ 63 | fun buyItem(itemId: String) { 64 | val token = AppPreferenceUtils.getUserToken(activity) 65 | if (token == "") { 66 | TipUtils.toastLong(activity, "请登陆后购买 [我的-登陆]") 67 | return 68 | } 69 | val bind = AppPreferenceUtils.getBindTaoBao(activity) 70 | if (!bind) { 71 | TipUtils.toastLong(activity, "请先进行淘宝授权 [我的-淘宝授权]") 72 | return 73 | } 74 | 75 | val form = DtGaoYongForm(item_id = itemId, token = token) 76 | ApiZtkGaoYongStub.myPost(activity, form, 77 | { ret -> 78 | AppErrnoLogic.genericServerErrnoProcess(ret.errno, activity) 79 | if (ret.errno == 0) { 80 | ret.data?.let { data -> 81 | openByUrl(data.coupon_click_url) 82 | } 83 | } else { 84 | Log.e(LogTags.AliBuy, "请求服务器失败: ${ret.errmsg}") 85 | TipUtils.toastLong(activity, "请求服务器失败,请稍后再试 ~_~!") 86 | } 87 | }, { 88 | Log.e(LogTags.AliBuy, "请求失败: ${it.localizedMessage}") 89 | }) 90 | } 91 | 92 | 93 | /** 94 | * 打开商品信息 95 | */ 96 | private fun openByUrl(url: String) { 97 | val show = AlibcShowParams() 98 | 99 | show.openType = OpenType.Auto 100 | show.clientType = "taobao" 101 | 102 | val taoke = AlibcTaokeParams("", "", "") 103 | 104 | taoke.setPid(BuildConfig.ALI_PID) 105 | // taoke.setUnionId("") 106 | taoke.setAdzoneid(BuildConfig.ALI_ADZONE_ID) 107 | 108 | AlibcTrade.openByUrl(activity, 109 | "", 110 | url, 111 | null, 112 | WebViewClient(), 113 | WebChromeClient(), 114 | show, 115 | taoke, 116 | null, 117 | object : AlibcTradeCallback { 118 | override fun onTradeSuccess(p0: AlibcTradeResult?) { 119 | if (p0 == null) { 120 | return 121 | } 122 | 123 | Log.i(LogTags.AliBuy, "购买成功") 124 | when (p0.resultType) { 125 | AlibcResultType.TYPECART -> { 126 | } 127 | AlibcResultType.TYPEPAY -> { 128 | } 129 | else -> { 130 | } 131 | } 132 | } 133 | 134 | override fun onFailure(p0: Int, p1: String?) { 135 | Log.e(LogTags.AliBuy, "错误码: $p0") 136 | Log.e(LogTags.AliBuy, "错误信息: $p1") 137 | } 138 | }) 139 | } 140 | 141 | companion object { 142 | /** 143 | * 检测淘宝是否已经绑定 144 | */ 145 | fun detectTaoBaoBind(ctx: Context) { 146 | val form = DtUserTokenForm(token = AppPreferenceUtils.getUserToken(ctx)) 147 | 148 | ApiUserTbStub.myPost(ctx, form, { ret -> 149 | AppErrnoLogic.genericServerErrnoProcess(ret.errno, ctx) 150 | if (ret.errno != 0) { 151 | Log.e(LogTags.AliBC, "授权失败!") 152 | return@myPost 153 | } 154 | 155 | if (ret.data == true) { // 已经经过淘宝认证 156 | val form2 = DtUserTokenForm(token = AppPreferenceUtils.getUserToken(ctx)) 157 | ApiUserProfileStub.myPost( 158 | ctx, form2, 159 | { ret2 -> 160 | ret2.data?.let { data -> 161 | AppPreferenceUtils.setUserInfo(ctx, data) 162 | } 163 | Log.i("user/profile", "$ret") 164 | }, 165 | { error -> 166 | Log.e("user/profile", "错误信息: ${error.localizedMessage}") 167 | TipUtils.toastShort(ctx, "更新用户状态失败: ${error.localizedMessage}") 168 | }) 169 | } 170 | }, { 171 | Log.e(LogTags.AliBC, "请求获取淘宝认证失败: $it") 172 | }) 173 | } 174 | } 175 | } 176 | -------------------------------------------------------------------------------- /app/src/main/java/com/qiyutech/tbk/logic/UserLogic.kt: -------------------------------------------------------------------------------- 1 | package com.qiyutech.tbk.logic 2 | 3 | import android.app.Activity 4 | import android.content.Context 5 | import android.util.Log 6 | import android.widget.Toast 7 | import com.qiyutech.tbk.SettingsActivity 8 | import com.qiyutech.tbk.UserPasswordActivity 9 | import com.qiyutech.tbk.dt.* 10 | import com.qiyutech.tbk.events.LoginEvent 11 | import com.qiyutech.tbk.events.LogoutEvent 12 | import com.qiyutech.tbk.utils.MyHttpUtils 13 | import com.qiyutech.tbk.utils.TipUtils 14 | import com.qiyutech.tbk.values.AppPreferenceUtils 15 | import com.qiyutech.tbk.values.LogTags 16 | import com.qiyutech.tbk.values.TbkAPIUrls 17 | 18 | 19 | object UserLogic { 20 | 21 | /** 22 | * 用户密码尝试登陆 23 | */ 24 | fun usernamePasswordTryLogin( 25 | activity: UserPasswordActivity, 26 | username: String, 27 | password: String 28 | ) { 29 | 30 | val form = DtUserNativeAuthForm(username, password) 31 | 32 | ApiUserAuthStub.myPost(activity, form, { ret -> 33 | if (ret.errno != 0) { 34 | Toast.makeText(activity, "请求失败(${ret.errno}): ${ret.errmsg}", Toast.LENGTH_LONG) 35 | .show() 36 | return@myPost 37 | } 38 | 39 | ret.data?.let { 40 | AppPreferenceUtils.setUserToken(activity, it.token) 41 | 42 | /// 登陆成功 43 | LoginEvent.callback(activity) // 回调登陆成功 44 | Toast.makeText(activity, "登陆成功", Toast.LENGTH_LONG).show() 45 | 46 | fetchProfile(activity, { info -> 47 | AppPreferenceUtils.setUserInfo(activity, info) 48 | }) { 49 | Toast.makeText(activity, "获取用户信息失败", Toast.LENGTH_LONG).show() 50 | } 51 | 52 | activity.finish() 53 | return@myPost 54 | } 55 | 56 | Toast.makeText(activity, "认证失败: ${ret.errmsg}(${ret.errno})", Toast.LENGTH_LONG).show() 57 | }) { 58 | Toast.makeText(activity, "请求服务器失败: $it", Toast.LENGTH_LONG).show() 59 | } 60 | } 61 | 62 | 63 | /** 64 | * 获取用户的状态 65 | */ 66 | fun fetchProfile( 67 | activity: Activity, 68 | success: (DtUserProfileDataModel) -> Unit, 69 | failure: () -> Unit 70 | ) { 71 | val form = DtUserTokenForm(token = AppPreferenceUtils.getUserToken(activity)) 72 | ApiUserProfileStub.myPost(activity, form, 73 | { ret -> 74 | AppErrnoLogic.genericServerErrnoProcess(ret.errno, activity) 75 | Log.i("user/profile", "$ret") 76 | if (ret.errno != 0) { 77 | TipUtils.toastShort(activity, "更新状态失败: ${ret.errmsg}") 78 | failure() 79 | } else { 80 | ret.data?.let { data -> 81 | AppPreferenceUtils.setUserInfo(activity, data) 82 | success(data) 83 | } 84 | } 85 | }, 86 | { error -> 87 | Log.e("user/profile", "错误信息: ${error.localizedMessage}") 88 | TipUtils.toastShort(activity, "更新用户状态失败: ${error.localizedMessage}") 89 | failure() 90 | }) 91 | 92 | } 93 | 94 | 95 | /** 96 | * 用户退出登陆 97 | */ 98 | fun logout(activity: Context) { 99 | // 删除 token 100 | AppPreferenceUtils.setUserToken(activity, "") 101 | // 删除已经登陆的用户信息 102 | AppPreferenceUtils.delUserInfo(activity) 103 | 104 | /// 登出之后的事件 105 | LogoutEvent.callback(activity) 106 | } 107 | 108 | /** 109 | * 用户注销账号 110 | */ 111 | fun cancel(ctx: SettingsActivity) { 112 | val form = DtUserTokenForm(token = AppPreferenceUtils.getUserToken(ctx)) 113 | 114 | val r = MyHttpUtils.postRequest( 115 | TbkAPIUrls.UserCancel, form, 116 | { ret: DtUserCancelResponseModel -> 117 | AppErrnoLogic.genericServerErrnoProcess(ret.errno, ctx) 118 | 119 | if (ret.errno == 0 && ret.data == true) { 120 | Toast.makeText(ctx, "注销用户成功", Toast.LENGTH_LONG).show() 121 | // 注销成功 自动退出登陆 122 | logout(ctx) 123 | ctx.setNotLoginView() 124 | } else { 125 | Toast.makeText(ctx, "注销用户失败(${ret.errno}): ${ret.errmsg}", Toast.LENGTH_LONG) 126 | .show() 127 | } 128 | }, 129 | { 130 | Toast.makeText(ctx, "请求服务器失败: $it", Toast.LENGTH_LONG).show() 131 | }) 132 | 133 | MyHttpUtils.addToQueue(ctx, LogTags.User, r) 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /app/src/main/java/com/qiyutech/tbk/utils/AppNavUtils.kt: -------------------------------------------------------------------------------- 1 | package com.qiyutech.tbk.utils 2 | 3 | import android.app.Activity 4 | import android.content.Intent 5 | import com.qiyutech.tbk.* 6 | 7 | /** 8 | * [AppNavUtils] 全局导航辅助类 9 | */ 10 | object AppNavUtils { 11 | 12 | /** 13 | * 从当前的 [activity] 跳转到 [SettingsActivity] 14 | */ 15 | fun gotoSettings(activity: Activity) { 16 | val intent = Intent(activity, SettingsActivity::class.java) 17 | goto(activity, intent) 18 | } 19 | 20 | /** 21 | * 从当前的 [activity] 跳转到 [GroupActivity] 22 | */ 23 | fun gotoGroup(activity: Activity) { 24 | val intent = Intent(activity, GroupActivity::class.java) 25 | goto(activity, intent) 26 | } 27 | 28 | /** 29 | * 从当前的 [activity] 跳转到 [HomeActivity] 30 | */ 31 | fun gotoHome(activity: Activity) { 32 | val intent = Intent(activity, HomeActivity::class.java) 33 | goto(activity, intent) 34 | } 35 | 36 | /** 37 | * 从当前的 [activity] 跳转到 [CouponActivity] 38 | */ 39 | fun gotoCoupon(activity: Activity) { 40 | val intent = Intent(activity, CouponActivity::class.java) 41 | goto(activity, intent) 42 | } 43 | 44 | /** 45 | * 从当前的 [activity] 跳转到 [PrivacyActivity] 46 | * 47 | * view 是否是展示模式: 48 | * 如果是展示模式则不附带 确认/不同意 按钮 49 | * 默认是 纯展示 模式 50 | */ 51 | fun gotoPrivacy(activity: Activity, view: Boolean = true) { 52 | val intent = Intent(activity, PrivacyActivity::class.java) 53 | intent.putExtra("view", view) 54 | goto(activity, intent) 55 | } 56 | 57 | 58 | /** 59 | * 从当前的 [activity] 跳转到 [SearchDetailNativeActivity] 60 | */ 61 | fun gotoSearchDetailNative(activity: Activity, query: String) { 62 | val intent = Intent(activity, SearchDetailNativeActivity::class.java) 63 | intent.putExtra("query", query) 64 | goto(activity, intent) 65 | } 66 | 67 | 68 | /** 69 | * 从当前的 [activity] 跳转到 [MeActivity] 70 | */ 71 | fun gotoMe(activity: Activity) { 72 | val intent = Intent(activity, MeActivity::class.java) 73 | goto(activity, intent) 74 | } 75 | 76 | 77 | /** 78 | * 跳转到商品详情页面 79 | */ 80 | fun gotoItemDetailV2(activity: Activity, itemId: String) { 81 | val intent = Intent(activity, ItemDetailV2Activity::class.java) 82 | intent.putExtra("item_id", itemId) 83 | goto(activity, intent) 84 | } 85 | 86 | 87 | /** 88 | * 从当前的 [activity] 跳转到 [UserPasswordActivity] 89 | * 90 | * 账号登陆 91 | */ 92 | fun gotoUserPassword(activity: Activity) { 93 | val intent = Intent(activity, UserPasswordActivity::class.java) 94 | goto(activity, intent) 95 | } 96 | 97 | 98 | /** 99 | * 跳转到开发信息界面 100 | */ 101 | fun gotoDevInfo(activity: Activity) { 102 | val intent = Intent(activity, DevInfoActivity::class.java) 103 | goto(activity, intent) 104 | } 105 | 106 | /** 107 | * 跳转到用户信息界面 108 | */ 109 | fun gotoUserInfo(activity: Activity) { 110 | val intent = Intent(activity, UserInfoActivity::class.java) 111 | goto(activity, intent) 112 | } 113 | 114 | 115 | private fun goto(activity: Activity, intent: Intent) { 116 | activity.startActivity(intent) 117 | activity.overridePendingTransition(android.R.anim.fade_in, android.R.anim.fade_out) 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /app/src/main/java/com/qiyutech/tbk/utils/AppUtils.kt: -------------------------------------------------------------------------------- 1 | package com.qiyutech.tbk.utils 2 | 3 | import android.content.Context 4 | import android.content.SharedPreferences 5 | import android.view.View 6 | import android.view.ViewGroup 7 | import androidx.appcompat.app.AppCompatActivity 8 | import com.qiyutech.tbk.BuildConfig 9 | import com.qiyutech.tbk.values.AppPreferenceUtils 10 | import com.qiyutech.tbk.values.AppSharedPreferencesName 11 | 12 | /** 13 | * App 辅助函数 14 | */ 15 | object AppUtils { 16 | /** 17 | * 获取 activity 的 RootView 18 | * 19 | * 主要是为了: 20 | * ***Binding.bind(view) 21 | */ 22 | fun getRootView(activity: AppCompatActivity): View { 23 | /// 怎么样获取 root view 24 | /// https://stackoverflow.com/questions/4486034/get-root-view-from-current-activity 25 | return activity.findViewById(android.R.id.content).getChildAt(0) 26 | } 27 | 28 | /** 29 | * 是否在开发环境 (也就是允许获取测试商品) 30 | */ 31 | fun inDevEnv(): Boolean { 32 | if (BuildConfig.ENV == "dev") { 33 | return true 34 | } 35 | return false 36 | } 37 | 38 | /** 39 | * 是否在调试环境中 40 | */ 41 | fun inDebugMode(): Boolean { 42 | return BuildConfig.DEBUG 43 | } 44 | 45 | fun versionName(): String { 46 | return if (inDevEnv()) { 47 | BuildConfig.VERSION_NAME + "-dev" 48 | } else { 49 | BuildConfig.VERSION_NAME 50 | } 51 | } 52 | 53 | /** 54 | * 获取共享的配置 55 | */ 56 | fun getPreference(ctx: Context): SharedPreferences { 57 | return ctx.getSharedPreferences(AppSharedPreferencesName.NAME, Context.MODE_PRIVATE) 58 | } 59 | 60 | /** 61 | * 检测用户是否登陆 62 | */ 63 | fun checkUserLogin(ctx: Context): Boolean { 64 | val token = AppPreferenceUtils.getUserToken(ctx) 65 | return token != "" 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /app/src/main/java/com/qiyutech/tbk/utils/ClipboardUtils.kt: -------------------------------------------------------------------------------- 1 | package com.qiyutech.tbk.utils 2 | 3 | import android.app.Activity 4 | import android.content.ClipData 5 | import android.content.ClipDescription.MIMETYPE_TEXT_PLAIN 6 | import android.content.ClipboardManager 7 | 8 | object ClipboardUtils { 9 | /** 10 | * 复制到剪切板 11 | */ 12 | fun copy(txt: String, activity: Activity) { 13 | val clip = 14 | activity.getSystemService(Activity.CLIPBOARD_SERVICE) as ClipboardManager 15 | val data = ClipData.newPlainText("TEXT", txt) 16 | clip.setPrimaryClip(data) 17 | } 18 | 19 | fun read(activity: Activity): String { 20 | val clip = activity.getSystemService(Activity.CLIPBOARD_SERVICE) as ClipboardManager 21 | 22 | clip.primaryClipDescription?.let { desc -> 23 | if (desc.hasMimeType(MIMETYPE_TEXT_PLAIN)) { 24 | clip.primaryClip?.let { 25 | it.getItemAt(0)?.let { item -> 26 | return item.text.toString() 27 | } 28 | } 29 | } 30 | } 31 | 32 | return "" 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /app/src/main/java/com/qiyutech/tbk/utils/DialogUtils.kt: -------------------------------------------------------------------------------- 1 | package com.qiyutech.tbk.utils 2 | 3 | import android.util.Log 4 | import androidx.appcompat.app.AlertDialog 5 | import androidx.appcompat.app.AppCompatActivity 6 | import com.qiyutech.tbk.values.LogTags 7 | 8 | /// 弹窗辅助类 9 | object DialogUtils { 10 | 11 | /** 12 | * 推送通知检测对话框 13 | */ 14 | fun notificationDialog(activity: AppCompatActivity): AlertDialog { 15 | val builder = AlertDialog.Builder(activity) 16 | builder.apply { 17 | setPositiveButton("去开启") { _, _ -> 18 | PushUtils.requestNotify(activity) 19 | } 20 | setNegativeButton("不用了") { _, _ -> 21 | } 22 | } 23 | 24 | builder.setTitle("开启推送") 25 | builder.setMessage("您没有给奇遇淘客开启消息推送,这样会导致错过一些重要信息, 是否去开启?") 26 | 27 | return builder.create() 28 | } 29 | 30 | /** 31 | * 淘宝重新授权 32 | */ 33 | fun reBindTbDialog( 34 | activity: AppCompatActivity, 35 | doFunc: (activity: AppCompatActivity) -> Unit 36 | ): AlertDialog { 37 | val builder = AlertDialog.Builder(activity) 38 | 39 | builder.apply { 40 | setPositiveButton("重新授权") { _, _ -> 41 | doFunc(activity) 42 | } 43 | setNegativeButton("取消") { _, _ -> 44 | } 45 | } 46 | 47 | builder.setTitle("淘宝授权") 48 | builder.setMessage("您已经绑定过淘宝账号,重新授权会导致之前绑定的账号失效?") 49 | 50 | return builder.create() 51 | } 52 | 53 | /** 54 | * 用户注销用户的弹窗 55 | */ 56 | fun userCancelDialog( 57 | activity: AppCompatActivity, 58 | doFunc: (AppCompatActivity) -> Unit 59 | ): AlertDialog { 60 | val builder = AlertDialog.Builder(activity) 61 | builder.apply { 62 | setPositiveButton("确认注销") { _, _ -> 63 | doFunc(activity) 64 | } 65 | setNegativeButton("取消") { _, _ -> 66 | } 67 | } 68 | 69 | builder.setTitle("注销账户") 70 | builder.setMessage("您是否确认注销当前的用户?\n\n注销账户之后:\n您将无法使用与会员有关的相关功能") 71 | 72 | return builder.create() 73 | } 74 | 75 | /** 76 | * 创建 dialog 77 | */ 78 | fun createDialog(activity: AppCompatActivity): AlertDialog { 79 | val builder = AlertDialog.Builder(activity) 80 | 81 | builder.apply { 82 | setPositiveButton("确认") { dialog, id -> 83 | // User clicked OK button 84 | Log.i(LogTags.Dialog, id.toString()) 85 | Log.i(LogTags.Dialog, "确认") 86 | } 87 | setNegativeButton("取消") { dialog, id -> 88 | // User cancelled the dialog 89 | Log.i(LogTags.Dialog, id.toString()) 90 | Log.i(LogTags.Dialog, "取消") 91 | } 92 | setNeutralButton("你猜") { dialog, id -> 93 | Log.i(LogTags.Dialog, id.toString()) 94 | Log.i(LogTags.Dialog, "你猜") 95 | } 96 | } 97 | 98 | // Set other dialog properties 99 | builder.setTitle("测试弹窗") 100 | builder.setMessage("这是一个测试的消息") 101 | 102 | // Create the AlertDialog 103 | return builder.create() 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /app/src/main/java/com/qiyutech/tbk/utils/DiskImageCache.kt: -------------------------------------------------------------------------------- 1 | package com.qiyutech.tbk.utils 2 | 3 | import android.content.Context 4 | import android.graphics.Bitmap 5 | import android.graphics.BitmapFactory 6 | import android.util.Log 7 | import com.bumptech.glide.disklrucache.DiskLruCache 8 | import com.qiyutech.tbk.values.LogTags 9 | import java.io.BufferedInputStream 10 | import java.io.BufferedOutputStream 11 | import java.math.BigInteger 12 | import java.security.MessageDigest 13 | 14 | object MyImageDiskCache { 15 | 16 | /// 缓存的大小 17 | private const val CACHE_SIZE: Long = 1 * 1024 * 1024 * 1024 18 | 19 | fun putImage(ctx: Context, url: String, bitmap: Bitmap) { 20 | Log.d(LogTags.CACHE_IMAGE, "put $url") 21 | val cache = DiskLruCache.open(ctx.cacheDir, 1, 1, CACHE_SIZE) 22 | val key = getCacheKey(url) 23 | cache.edit(key).let { editor -> 24 | editor.getFile(0).let { file -> 25 | val out = BufferedOutputStream(file.outputStream()) 26 | bitmap.compress(Bitmap.CompressFormat.PNG, 100, out) 27 | out.close() 28 | editor.commit() 29 | cache.flush() 30 | } 31 | } 32 | } 33 | 34 | fun getImage(ctx: Context, url: String): Bitmap? { 35 | val cache = DiskLruCache.open(ctx.cacheDir, 1, 1, CACHE_SIZE) 36 | val key = getCacheKey(url) 37 | cache.get(key)?.let { value -> 38 | value.getFile(0)?.let { file -> 39 | file.inputStream().let { input -> 40 | val buffer = BufferedInputStream(input, 1024 * 1024) 41 | Log.d(LogTags.CACHE_IMAGE, "get success: $url") 42 | return BitmapFactory.decodeStream(buffer) 43 | } 44 | } 45 | } 46 | Log.d(LogTags.CACHE_IMAGE, "get failed: $url") 47 | return null 48 | } 49 | 50 | private fun getCacheKey(url: String): String { 51 | val md = MessageDigest.getInstance("MD5") 52 | val v = md.digest(url.toByteArray(Charsets.UTF_8)) 53 | val b = BigInteger(v) 54 | return String.format("%032x", b) 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /app/src/main/java/com/qiyutech/tbk/utils/LayoutUtils.kt: -------------------------------------------------------------------------------- 1 | package com.qiyutech.tbk.utils 2 | 3 | import android.content.Context 4 | 5 | /** 6 | * @author me 7 | * @doc https://stackoverflow.com/questions/29664993/how-to-convert-dp-px-sp-among-each-other-especially-dp-and-sp 8 | */ 9 | object LayoutUtils { 10 | fun spToInt(ctx: Context, sp: Int): Int { 11 | val multi = ctx.resources.displayMetrics.scaledDensity 12 | 13 | return (sp * multi).toInt() 14 | } 15 | 16 | fun dpToInt(ctx: Context, dp: Int): Int { 17 | val multi = ctx.resources.displayMetrics.density 18 | 19 | return (dp * multi).toInt() 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /app/src/main/java/com/qiyutech/tbk/utils/LoadKeywordUtils.kt: -------------------------------------------------------------------------------- 1 | package com.qiyutech.tbk.utils 2 | 3 | import android.widget.Toast 4 | import com.qiyutech.tbk.SearchActivity 5 | import com.qiyutech.tbk.api.ZTK 6 | import com.qiyutech.tbk.values.HttpTags 7 | 8 | /** 9 | * 加载热词搜索列表 10 | */ 11 | class LoadKeywordUtils(private val activity: SearchActivity) { 12 | /** 13 | * 加载搜索热词列表 14 | */ 15 | fun loadKeyword() { 16 | val ztk = ZTK(activity, HttpTags.SEARCH) 17 | ztk.hotKeyword( 18 | { v -> 19 | if (v.errno != 0) { 20 | Toast.makeText(activity, v.errmsg, Toast.LENGTH_SHORT).show() 21 | } else { 22 | v.data?.let { data -> 23 | activity.pushHotSearchKeyword(data) 24 | } 25 | } 26 | }, 27 | { 28 | println(it) 29 | } 30 | ) 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /app/src/main/java/com/qiyutech/tbk/utils/MyHttpUtils.kt: -------------------------------------------------------------------------------- 1 | package com.qiyutech.tbk.utils 2 | 3 | import android.content.Context 4 | import com.android.volley.Request 5 | import com.android.volley.VolleyError 6 | import com.android.volley.toolbox.Volley 7 | import com.qiyutech.tbk.activity.question.MyGetRequest 8 | import com.qiyutech.tbk.activity.question.MyJsonObjectRequest 9 | 10 | object MyHttpUtils { 11 | 12 | /** 13 | * 取消所有的 HTTP 请求 14 | * 15 | * 应该在 onStop 的时候使用 16 | */ 17 | fun cancelAllRequest(ctx: Context, tag: String) { 18 | Volley.newRequestQueue(ctx).cancelAll(tag) 19 | } 20 | 21 | /** 22 | * 添加到 HTTP 处理队列 23 | * 不要忘记了 在 onStop 的时候调用 cancelAllRequest 24 | */ 25 | fun addToQueue(ctx: Context, tag: String, request: Request) { 26 | request.tag = tag 27 | Volley.newRequestQueue(ctx).add(request) 28 | } 29 | 30 | inline fun getRequest( 31 | url: String, 32 | crossinline success: (Out) -> Unit, 33 | crossinline failure: (VolleyError) -> Unit 34 | ): MyGetRequest { 35 | 36 | return MyGetRequest( 37 | url, 38 | { response -> 39 | val out = MyJsonUtils.fromJsonToClass(response, Out::class.java) 40 | success(out) 41 | }, 42 | { failure(it) }) 43 | } 44 | 45 | inline fun postRequest( 46 | url: String, 47 | data: Data, 48 | crossinline success: (Out) -> Unit, 49 | crossinline failure: (VolleyError) -> Unit 50 | ): MyJsonObjectRequest { 51 | val json = MyJsonUtils.fromClassToJson(data) 52 | 53 | return MyJsonObjectRequest( 54 | Request.Method.POST, url, json, 55 | { response -> 56 | val out = MyJsonUtils.fromJsonToClass(response, Out::class.java) 57 | success(out) 58 | }, 59 | { failure(it) }) 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /app/src/main/java/com/qiyutech/tbk/utils/MyJsonUtils.kt: -------------------------------------------------------------------------------- 1 | package com.qiyutech.tbk.utils 2 | 3 | import com.google.gson.Gson 4 | import org.json.JSONObject 5 | import java.lang.reflect.Type 6 | 7 | 8 | object MyJsonUtils { 9 | 10 | fun fromString(s: String, t: Class): T { 11 | return Gson().fromJson(s, t as Type) 12 | } 13 | 14 | fun toString(v: T): String { 15 | return Gson().toJson(v) 16 | } 17 | 18 | fun fromJsonToClass(v: JSONObject, t: Class): T { 19 | val s = v.toString() 20 | return Gson().fromJson(s, t as Type) 21 | } 22 | 23 | 24 | inline fun fromClassToJson(v: T): JSONObject { 25 | val s = Gson().toJson(v) 26 | return JSONObject(s) 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /app/src/main/java/com/qiyutech/tbk/utils/MySearchUtils.kt: -------------------------------------------------------------------------------- 1 | package com.qiyutech.tbk.utils 2 | 3 | import com.qiyutech.tbk.CouponActivity 4 | import com.qiyutech.tbk.SearchActivity 5 | import com.qiyutech.tbk.values.AppPreferenceUtils 6 | 7 | object MySearchUtils { 8 | /** 9 | * 执行搜索功能 10 | */ 11 | fun doSearch(activity: SearchActivity, query: String) { 12 | val history = AppPreferenceUtils.getSearchHistory(activity) 13 | val newHistory = history.toMutableList() 14 | newHistory.add(0, query) 15 | AppPreferenceUtils.setSearchHistory(activity, newHistory) 16 | 17 | // 重新加载搜索历史 18 | activity.loadSearchHistoryKeyword() 19 | 20 | AppNavUtils.gotoSearchDetailNative(activity, query) 21 | } 22 | 23 | /** 24 | * 优惠券界面的搜索 25 | */ 26 | fun doCouponSearch(activity: CouponActivity, query: String) { 27 | AppNavUtils.gotoSearchDetailNative(activity, query) 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /app/src/main/java/com/qiyutech/tbk/utils/MyWebViewUtils.kt: -------------------------------------------------------------------------------- 1 | package com.qiyutech.tbk.utils 2 | 3 | import android.annotation.SuppressLint 4 | import android.webkit.WebChromeClient 5 | import android.webkit.WebView 6 | import androidx.fragment.app.FragmentActivity 7 | 8 | /** 9 | * WebView 辅助函数 10 | */ 11 | object MyWebViewUtils { 12 | @SuppressLint("SetJavaScriptEnabled") 13 | fun initWebView(activity: FragmentActivity, webView: WebView) { 14 | webView.settings.javaScriptEnabled = true 15 | webView.settings.allowFileAccess = true 16 | // alert need this 17 | webView.webChromeClient = WebChromeClient() 18 | 19 | val c = AndroidWebViewInterface(activity, webView) 20 | webView.addJavascriptInterface(c, AndroidBindingName) 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /app/src/main/java/com/qiyutech/tbk/utils/NetworkImageUtils.kt: -------------------------------------------------------------------------------- 1 | package com.qiyutech.tbk.utils 2 | 3 | import android.content.Context 4 | import android.graphics.Bitmap 5 | import android.widget.ImageView 6 | import com.android.volley.VolleyError 7 | import com.android.volley.toolbox.ImageRequest 8 | import com.qiyutech.tbk.values.HttpTags 9 | 10 | 11 | /** 12 | * 网络图片加载辅助工具 13 | */ 14 | object NetworkImageUtils { 15 | /** 16 | * 下载图片 17 | */ 18 | fun download( 19 | ctx: Context, 20 | url: String, 21 | scale: ImageView.ScaleType, 22 | success: (Bitmap) -> Unit, 23 | failure: (VolleyError) -> Unit 24 | ) { 25 | val cacheImg = MyImageDiskCache.getImage(ctx, url) 26 | if (cacheImg == null) { 27 | val r = ImageRequest( 28 | url, { img -> 29 | MyImageDiskCache.putImage(ctx, url, img) 30 | success(img) 31 | }, 0, 0, scale, null 32 | ) { failure(it) } 33 | MyHttpUtils.addToQueue(ctx, HttpTags.IMAGE, r) 34 | } else { 35 | success(cacheImg) 36 | } 37 | } 38 | 39 | /** 40 | * 取消当前所有的下载 41 | */ 42 | fun cancelAll(ctx: Context) { 43 | MyHttpUtils.cancelAllRequest(ctx, HttpTags.IMAGE) 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /app/src/main/java/com/qiyutech/tbk/utils/PopupUtils.kt: -------------------------------------------------------------------------------- 1 | package com.qiyutech.tbk.utils 2 | 3 | import android.view.Gravity 4 | import android.view.LayoutInflater 5 | import android.view.View 6 | import android.widget.LinearLayout 7 | import android.widget.PopupWindow 8 | import androidx.annotation.LayoutRes 9 | 10 | /** 11 | * 弹出框辅助类 12 | */ 13 | object PopupUtils { 14 | /** 15 | * 创建弹出框 16 | * boolean focusable = true; // lets taps outside the popup also dismiss it 17 | * 18 | * doc: https://stackoverflow.com/questions/5944987/how-to-create-a-popup-window-popupwindow-in-android 19 | */ 20 | fun createPopup( 21 | view: View, 22 | inflater: LayoutInflater, 23 | @LayoutRes resource: Int, 24 | focusable: Boolean 25 | ): Pair { 26 | val popupView = inflater.inflate(resource, null) 27 | 28 | val width = LinearLayout.LayoutParams.WRAP_CONTENT 29 | val height = LinearLayout.LayoutParams.WRAP_CONTENT 30 | 31 | val popupWindow = PopupWindow(popupView, width, height, focusable) 32 | popupWindow.showAtLocation(view, Gravity.CENTER, 0, 0) 33 | 34 | return Pair(popupView, popupWindow) 35 | } 36 | 37 | fun createFullScreenPopup( 38 | view: View, 39 | inflater: LayoutInflater, 40 | @LayoutRes resource: Int, 41 | focusable: Boolean 42 | ): Pair { 43 | val popupView = inflater.inflate(resource, null) 44 | 45 | val width = LinearLayout.LayoutParams.MATCH_PARENT 46 | val height = LinearLayout.LayoutParams.MATCH_PARENT 47 | 48 | val popupWindow = PopupWindow(popupView, width, height, focusable) 49 | popupWindow.showAtLocation(view, Gravity.CENTER, 0, 0) 50 | 51 | return Pair(popupView, popupWindow) 52 | } 53 | 54 | } 55 | 56 | -------------------------------------------------------------------------------- /app/src/main/java/com/qiyutech/tbk/utils/PrivacyUtils.kt: -------------------------------------------------------------------------------- 1 | package com.qiyutech.tbk.utils 2 | 3 | import android.content.Context 4 | import com.qiyutech.tbk.values.AppPreferenceUtils 5 | 6 | /** 7 | * 奇遇淘客隐私政策辅助类 8 | */ 9 | object AppPrivacyUtils { 10 | /** 11 | * 是否已经同意隐私政策 12 | */ 13 | fun isPrivacyAgree(ctx: Context): Boolean { 14 | return AppPreferenceUtils.getPrivacyAgree(ctx) 15 | } 16 | 17 | /** 18 | * 设置已经同意隐私政策 19 | */ 20 | fun setPrivacyAgree(ctx: Context) { 21 | AppPreferenceUtils.setPrivacyAgree(ctx) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /app/src/main/java/com/qiyutech/tbk/utils/PushUtils.kt: -------------------------------------------------------------------------------- 1 | package com.qiyutech.tbk.utils 2 | 3 | import android.content.Context 4 | import android.content.Intent 5 | import android.net.Uri 6 | import android.os.Build 7 | import android.provider.Settings 8 | import androidx.core.app.NotificationManagerCompat 9 | 10 | /** 11 | * 推送活动 12 | */ 13 | object PushUtils { 14 | /** 15 | * 检测 通知消息是否已经 打开 16 | */ 17 | fun isNotificationEnabled(context: Context): Boolean { 18 | return NotificationManagerCompat.from(context).areNotificationsEnabled() 19 | } 20 | 21 | /** 22 | * 上报 设备的 推送 id 23 | * 24 | * 在 25 | * * 用户登陆 26 | * * 用户登出 27 | * * 打开 APP 28 | * 的时候需要上报 29 | */ 30 | fun reportPushId(context: Context) { 31 | } 32 | 33 | /** 34 | * 通知权限申请 35 | * @param context 36 | */ 37 | fun requestNotify(context: Context) { 38 | ///< 直接跳转到应用通知设置的代码 39 | val localIntent = Intent() 40 | 41 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { 42 | localIntent.action = Settings.ACTION_APP_NOTIFICATION_SETTINGS 43 | localIntent.putExtra(Settings.EXTRA_APP_PACKAGE, context.packageName) 44 | localIntent.putExtra(Settings.EXTRA_CHANNEL_ID, context.applicationInfo.uid) 45 | } else if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) { 46 | localIntent.action = Settings.ACTION_APPLICATION_DETAILS_SETTINGS 47 | localIntent.data = Uri.fromParts("package", context.packageName, null) 48 | } 49 | 50 | context.startActivity(localIntent) 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /app/src/main/java/com/qiyutech/tbk/utils/TipUtils.kt: -------------------------------------------------------------------------------- 1 | package com.qiyutech.tbk.utils 2 | 3 | import android.content.Context 4 | import android.view.View 5 | import android.widget.Toast 6 | import com.google.android.material.snackbar.Snackbar 7 | 8 | object TipUtils { 9 | 10 | fun toastShort(ctx: Context, s: String) { 11 | Toast.makeText(ctx, s, Toast.LENGTH_SHORT).show() 12 | } 13 | 14 | fun toastLong(ctx: Context, s: String) { 15 | Toast.makeText(ctx, s, Toast.LENGTH_LONG).show() 16 | } 17 | 18 | fun barShort(view: View, msg: String) { 19 | Snackbar.make(view, msg, Snackbar.LENGTH_SHORT).show() 20 | } 21 | 22 | fun barLong(view: View, msg: String) { 23 | Snackbar.make(view, msg, Snackbar.LENGTH_LONG).show() 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /app/src/main/java/com/qiyutech/tbk/utils/WebUtils.kt: -------------------------------------------------------------------------------- 1 | package com.qiyutech.tbk.utils 2 | 3 | import android.webkit.JavascriptInterface 4 | import android.webkit.WebView 5 | import android.webkit.WebViewClient 6 | import androidx.appcompat.app.AppCompatActivity 7 | import androidx.appcompat.widget.LinearLayoutCompat 8 | import androidx.fragment.app.FragmentActivity 9 | import com.qiyutech.tbk.BuildConfig 10 | import com.qiyutech.tbk.logic.TaoBaoLogic 11 | import com.qiyutech.tbk.values.AppPreferenceUtils 12 | import com.qiyutech.tbk.values.AppSpKeys 13 | 14 | 15 | const val AndroidBindingName: String = "MyAndroidAutoResize" 16 | 17 | /** 18 | * 自动设置 WebView 的高度 19 | * 注意: 请使用 ScrollView LinearView 包裹起来 20 | */ 21 | class MyWebViewAutoResizeClient(private val webView: WebView) : WebViewClient() { 22 | /* use js control for simplify 23 | override fun onPageFinished(view: WebView?, url: String?) { 24 | webView.loadUrl("javascript:${AndroidAutoResizeBindingName}.resize(document.body.getBoundingClientRect().height)") 25 | super.onPageFinished(view, url) 26 | } 27 | */ 28 | } 29 | 30 | class ItemDetailWebViewClient(private val itemId: String) : WebViewClient() { 31 | override fun onPageFinished(view: WebView?, url: String?) { 32 | super.onPageFinished(view, url) 33 | view!!.loadUrl("javascript:item_detail_init('${itemId}')") 34 | } 35 | } 36 | 37 | 38 | /** 39 | * 自动设置 resize 40 | * binding with this: AndroidAutoResizeBindingName 41 | */ 42 | class AndroidWebViewInterface(private var activity: FragmentActivity, private var wv: WebView) { 43 | 44 | @JavascriptInterface 45 | fun resize(height: Float) { 46 | activity.runOnUiThread { 47 | run { 48 | val dm = activity.resources.displayMetrics 49 | val w = dm.widthPixels 50 | val h = (height * dm.density).toInt() 51 | wv.layoutParams = LinearLayoutCompat.LayoutParams(w, h) 52 | } 53 | } 54 | } 55 | 56 | /// 打开一个指定的商品 57 | @JavascriptInterface 58 | fun openItem(item: String) { 59 | activity.runOnUiThread { 60 | run { 61 | AppNavUtils.gotoItemDetailV2(activity, item) 62 | } 63 | } 64 | } 65 | 66 | @JavascriptInterface 67 | fun buyItem(item: String) { 68 | activity.runOnUiThread { 69 | run { 70 | val tb = TaoBaoLogic(activity = activity as AppCompatActivity) 71 | tb.buyItem(item) 72 | } 73 | } 74 | } 75 | 76 | @JavascriptInterface 77 | fun uuid(): String { 78 | val sp = AppUtils.getPreference(activity) 79 | return sp.getString(AppSpKeys.TBK_UUID, "") ?: "" 80 | } 81 | 82 | @JavascriptInterface 83 | fun token(): String { 84 | return AppPreferenceUtils.getUserToken(activity) 85 | } 86 | 87 | /** 88 | * 获取基础的 url 89 | */ 90 | @JavascriptInterface 91 | fun baseUrl(): String { 92 | return BuildConfig.BASE_URL 93 | } 94 | 95 | 96 | @JavascriptInterface 97 | fun openSuperSubCategory(subCid: Int, title: String) { 98 | activity.runOnUiThread { 99 | run { 100 | // 跳转到超级分类 101 | // 当前已经移除 102 | } 103 | } 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /app/src/main/java/com/qiyutech/tbk/values/ApiUrlsV2.kt: -------------------------------------------------------------------------------- 1 | // 这个文件是由于 openapi.json 自动生成的 2 | // 请不要使用手工编辑 3 | 4 | package com.qiyutech.tbk.values 5 | 6 | import com.qiyutech.tbk.BuildConfig 7 | 8 | object TbkAPIUrls { 9 | 10 | 11 | const val Ping: String = BuildConfig.BASE_URL + "/ping" 12 | const val DtkFastBuy: String = BuildConfig.BASE_URL + "/dtk/fast_buy" 13 | const val DtkGoodsDetail: String = BuildConfig.BASE_URL + "/dtk/goods_detail" 14 | const val DtkGoodsList: String = BuildConfig.BASE_URL + "/dtk/goods_list" 15 | const val DtkGoodsNineOpGoodsList: String = 16 | BuildConfig.BASE_URL + "/dtk/goods_nine_op_goods_list" 17 | const val DtkGoodsPriceTrend: String = BuildConfig.BASE_URL + "/dtk/goods_price_trend" 18 | const val DtkGuessYouLike: String = BuildConfig.BASE_URL + "/dtk/guess_you_like" 19 | const val DtkPrivilegeLink: String = BuildConfig.BASE_URL + "/dtk/privilege_link" 20 | const val DtkRankingList: String = BuildConfig.BASE_URL + "/dtk/ranking_list" 21 | const val DtkSearchGoods: String = BuildConfig.BASE_URL + "/dtk/search_goods" 22 | const val DtkSearchSuggestion: String = BuildConfig.BASE_URL + "/dtk/search_suggestion" 23 | const val DtkSuperCategory: String = BuildConfig.BASE_URL + "/dtk/super_category" 24 | const val DtkSuperSearch: String = BuildConfig.BASE_URL + "/dtk/super_search" 25 | const val DtkBrandList: String = BuildConfig.BASE_URL + "/dtk/brand_list" 26 | const val DtkTbService: String = BuildConfig.BASE_URL + "/dtk/tb_service" 27 | const val DtkTop100: String = BuildConfig.BASE_URL + "/dtk/top_100" 28 | const val OrderList: String = BuildConfig.BASE_URL + "/order/list" 29 | const val ShareAndroidRelationTkl: String = BuildConfig.BASE_URL + "/share/android/relation_tkl" 30 | const val ShareIosRelationTkl: String = BuildConfig.BASE_URL + "/share/ios/relation_tkl" 31 | const val ShareIosNoRelationTkl: String = BuildConfig.BASE_URL + "/share/ios/no_relation_tkl" 32 | const val SysConfig: String = BuildConfig.BASE_URL + "/sys/config" 33 | const val TaobaoAuthUrl: String = BuildConfig.BASE_URL + "/taobao/auth_url" 34 | const val TbkDtkBrandGoods: String = BuildConfig.BASE_URL + "/tbk/dtk/brand_goods" 35 | const val TbkDtkBrandList: String = BuildConfig.BASE_URL + "/tbk/dtk/brand_list" 36 | const val TbkItemDetail: String = BuildConfig.BASE_URL + "/tbk/item_detail" 37 | const val UserAuth: String = BuildConfig.BASE_URL + "/user/auth" 38 | const val UserCancel: String = BuildConfig.BASE_URL + "/user/cancel" 39 | const val UserBind: String = BuildConfig.BASE_URL + "/user/bind" 40 | const val UserProfile: String = BuildConfig.BASE_URL + "/user/profile" 41 | const val UserTb: String = BuildConfig.BASE_URL + "/user/tb" 42 | const val ZtkBangDanTuiJian: String = BuildConfig.BASE_URL + "/ztk/bang_dan_tui_jian" 43 | const val ZtkGuessYouLike: String = BuildConfig.BASE_URL + "/ztk/guess_you_like" 44 | const val ZtkItemV2: String = BuildConfig.BASE_URL + "/ztk/item_v2" 45 | const val ZtkJuHuaSuan: String = BuildConfig.BASE_URL + "/ztk/ju_hua_suan" 46 | const val ZtkNineNine: String = BuildConfig.BASE_URL + "/ztk/nine_nine" 47 | const val ZtkSuggest: String = BuildConfig.BASE_URL + "/ztk/suggest" 48 | const val ZtkTmallChaoShi: String = BuildConfig.BASE_URL + "/ztk/tmall_chao_shi" 49 | const val ZtkTmallShangPin: String = BuildConfig.BASE_URL + "/ztk/tmall_shang_pin" 50 | const val ZtkGaoYong: String = BuildConfig.BASE_URL + "/ztk/gao_yong" 51 | const val ZtkKeyword: String = BuildConfig.BASE_URL + "/ztk/keyword" 52 | const val ZtkSearch: String = BuildConfig.BASE_URL + "/ztk/search" 53 | } 54 | 55 | -------------------------------------------------------------------------------- /app/src/main/java/com/qiyutech/tbk/values/AppSpKeys.kt: -------------------------------------------------------------------------------- 1 | package com.qiyutech.tbk.values 2 | 3 | import android.content.Context 4 | import com.google.gson.Gson 5 | import com.qiyutech.tbk.dt.DtUserProfileDataModel 6 | import com.qiyutech.tbk.utils.AppUtils 7 | import com.qiyutech.tbk.utils.MyJsonUtils 8 | 9 | object AppSharedPreferencesName { 10 | const val NAME = "TBKSharedPreference" 11 | } 12 | 13 | /** 14 | * Android Shared Preference keys 15 | */ 16 | object AppSpKeys { 17 | /// 跟设备管理的 UUID 18 | const val TBK_UUID = "TBK-uuid" 19 | 20 | /// 用户信息 21 | const val USER_INFO_BIG_KEY = "user-info-key" 22 | 23 | /// 搜索历史 24 | const val SEARCH_HISTORY = "search-history" 25 | 26 | /// 获取用户的 token 27 | const val USER_TOKEN = "user-token" 28 | 29 | /// 用户是否已经同意 隐私政策 30 | const val PRIVACY_AGREE = "privacy-agree" 31 | } 32 | 33 | object AppPreferenceUtils { 34 | 35 | 36 | /** 37 | * 设置 tao ID 38 | */ 39 | fun setTaoId(ctx: Context, taoId: String) { 40 | getUserInfo(ctx)?.let { 41 | val newData = DtUserProfileDataModel( 42 | mobile = it.mobile, 43 | tao_id = taoId, 44 | wx = it.wx, 45 | relation_id = it.relation_id, 46 | ali_name = it.ali_name, 47 | ali_account = it.ali_account 48 | ) 49 | setUserInfo(ctx, newData) 50 | } 51 | } 52 | 53 | /** 54 | * 获取 是否已经同意隐私政策 55 | */ 56 | fun getPrivacyAgree(ctx: Context): Boolean { 57 | val sp = AppUtils.getPreference(ctx) 58 | return sp.getBoolean(AppSpKeys.PRIVACY_AGREE, false) 59 | } 60 | 61 | /** 62 | * 设置为已经同意隐私政策 63 | */ 64 | fun setPrivacyAgree(ctx: Context) { 65 | val sp = AppUtils.getPreference(ctx) 66 | sp.edit().putBoolean(AppSpKeys.PRIVACY_AGREE, true).apply() 67 | } 68 | 69 | fun getSearchHistory(ctx: Context): Array { 70 | val sp = AppUtils.getPreference(ctx) 71 | val history = sp.getString(AppSpKeys.SEARCH_HISTORY, "") 72 | if (history === "") { 73 | return arrayOf() 74 | } 75 | 76 | return try { 77 | Gson().fromJson(history, Array::class.java) 78 | } catch (e: Exception) { 79 | arrayOf() 80 | } 81 | } 82 | 83 | /** 84 | * 设置 搜索历史 85 | */ 86 | fun setSearchHistory(ctx: Context, history: List) { 87 | val count = history.count() 88 | 89 | val newHistory = if (count > 10) { 90 | history.drop(count - 10) 91 | } else { 92 | history 93 | } 94 | // use set of to delete duplicated item 95 | val s = Gson().toJson(newHistory.toSet().toList()) 96 | 97 | val sp = AppUtils.getPreference(ctx) 98 | 99 | sp.edit().putString(AppSpKeys.SEARCH_HISTORY, s).apply() 100 | } 101 | 102 | 103 | /** 104 | * 获取是否已经绑定淘宝账号 105 | */ 106 | fun getBindTaoBao(ctx: Context): Boolean { 107 | getUserInfo(ctx)?.let { 108 | it.relation_id?.let { relation -> 109 | if (relation.isBlank()) { 110 | return false 111 | } 112 | return true 113 | } 114 | } 115 | return false 116 | } 117 | 118 | 119 | fun setUserToken(ctx: Context, token: String) { 120 | setKeyValue(ctx, AppSpKeys.USER_TOKEN, token) 121 | } 122 | 123 | /** 124 | * 设置用户消息 125 | */ 126 | fun setUserInfo(ctx: Context, info: DtUserProfileDataModel) { 127 | val s = MyJsonUtils.toString(info) 128 | AppUtils.getPreference(ctx) 129 | .edit() 130 | .putString(AppSpKeys.USER_INFO_BIG_KEY, s) 131 | .apply() 132 | } 133 | 134 | /** 135 | * 删除用户信息 136 | */ 137 | fun delUserInfo(ctx: Context) { 138 | AppUtils.getPreference(ctx) 139 | .edit() 140 | .remove(AppSpKeys.USER_INFO_BIG_KEY) 141 | .apply() 142 | } 143 | 144 | fun getUserInfo(ctx: Context): DtUserProfileDataModel? { 145 | val s = AppUtils.getPreference(ctx).getString(AppSpKeys.USER_INFO_BIG_KEY, "") 146 | if (s.isNullOrBlank()) { 147 | return null 148 | } 149 | 150 | return MyJsonUtils.fromString(s, DtUserProfileDataModel::class.java) 151 | } 152 | 153 | fun getUserToken(ctx: Context): String { 154 | return getOrDefault(ctx, AppSpKeys.USER_TOKEN, "") 155 | } 156 | 157 | 158 | fun getUserUuid(ctx: Context): String { 159 | return "" 160 | } 161 | 162 | 163 | private fun getOrDefault(ctx: Context, key: String, default: String): String { 164 | val sp = AppUtils.getPreference(ctx) 165 | val ret = sp.getString(key, default) 166 | return if (ret.isNullOrBlank()) { 167 | "" 168 | } else { 169 | ret 170 | } 171 | } 172 | 173 | private fun setKeyValue(ctx: Context, key: String, value: String) { 174 | val sp = AppUtils.getPreference(ctx) 175 | sp.edit().putString(key, value).apply() 176 | } 177 | } 178 | 179 | -------------------------------------------------------------------------------- /app/src/main/java/com/qiyutech/tbk/values/HttpFile.kt: -------------------------------------------------------------------------------- 1 | package com.qiyutech.tbk.values 2 | 3 | object HttpFile { 4 | // 隐私 5 | const val privacy = "file:///android_asset/www/html/privacy.html" 6 | } 7 | -------------------------------------------------------------------------------- /app/src/main/java/com/qiyutech/tbk/values/HttpTags.kt: -------------------------------------------------------------------------------- 1 | package com.qiyutech.tbk.values 2 | 3 | 4 | object HttpTags { 5 | // 搜索 6 | const val SEARCH = "search" 7 | 8 | // 下载图片 9 | const val IMAGE = "image" 10 | } 11 | -------------------------------------------------------------------------------- /app/src/main/java/com/qiyutech/tbk/values/LogTags.kt: -------------------------------------------------------------------------------- 1 | package com.qiyutech.tbk.values 2 | 3 | 4 | object LogTags { 5 | const val TaoBao = "淘宝" 6 | const val AliBC = "阿里百川" 7 | const val AliBuy = "淘宝购买" 8 | const val Push = "推送" 9 | const val Dialog = "对话框" 10 | const val User = "用户" 11 | const val CACHE_IMAGE = "图片缓存" 12 | } 13 | -------------------------------------------------------------------------------- /app/src/main/res/color/bottom_nav_color.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QiYuTechOrg/QiYuTkAndroid/35188be591e96b84de366098bdaf8e6bd92197ac/app/src/main/res/drawable-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QiYuTechOrg/QiYuTkAndroid/35188be591e96b84de366098bdaf8e6bd92197ac/app/src/main/res/drawable-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QiYuTechOrg/QiYuTkAndroid/35188be591e96b84de366098bdaf8e6bd92197ac/app/src/main/res/drawable-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QiYuTechOrg/QiYuTkAndroid/35188be591e96b84de366098bdaf8e6bd92197ac/app/src/main/res/drawable-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QiYuTechOrg/QiYuTkAndroid/35188be591e96b84de366098bdaf8e6bd92197ac/app/src/main/res/drawable-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QiYuTechOrg/QiYuTkAndroid/35188be591e96b84de366098bdaf8e6bd92197ac/app/src/main/res/drawable-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QiYuTechOrg/QiYuTkAndroid/35188be591e96b84de366098bdaf8e6bd92197ac/app/src/main/res/drawable-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QiYuTechOrg/QiYuTkAndroid/35188be591e96b84de366098bdaf8e6bd92197ac/app/src/main/res/drawable-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QiYuTechOrg/QiYuTkAndroid/35188be591e96b84de366098bdaf8e6bd92197ac/app/src/main/res/drawable-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QiYuTechOrg/QiYuTkAndroid/35188be591e96b84de366098bdaf8e6bd92197ac/app/src/main/res/drawable-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/button_round_corner.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/coupon_bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QiYuTechOrg/QiYuTkAndroid/35188be591e96b84de366098bdaf8e6bd92197ac/app/src/main/res/drawable/coupon_bg.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/f_icon_coupon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QiYuTechOrg/QiYuTkAndroid/35188be591e96b84de366098bdaf8e6bd92197ac/app/src/main/res/drawable/f_icon_coupon.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/f_icon_group.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QiYuTechOrg/QiYuTkAndroid/35188be591e96b84de366098bdaf8e6bd92197ac/app/src/main/res/drawable/f_icon_group.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/f_icon_home.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QiYuTechOrg/QiYuTkAndroid/35188be591e96b84de366098bdaf8e6bd92197ac/app/src/main/res/drawable/f_icon_home.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/f_icon_user.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QiYuTechOrg/QiYuTkAndroid/35188be591e96b84de366098bdaf8e6bd92197ac/app/src/main/res/drawable/f_icon_user.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/forward.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QiYuTechOrg/QiYuTkAndroid/35188be591e96b84de366098bdaf8e6bd92197ac/app/src/main/res/drawable/forward.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/item_detail_coupon_bg.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/search.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QiYuTechOrg/QiYuTkAndroid/35188be591e96b84de366098bdaf8e6bd92197ac/app/src/main/res/drawable/search.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/search_button_bg.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/search_view_bg.xml: -------------------------------------------------------------------------------- 1 | 4 | 6 | 7 | 8 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/star.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QiYuTechOrg/QiYuTkAndroid/35188be591e96b84de366098bdaf8e6bd92197ac/app/src/main/res/drawable/star.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/yw_1222.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QiYuTechOrg/QiYuTkAndroid/35188be591e96b84de366098bdaf8e6bd92197ac/app/src/main/res/drawable/yw_1222.jpg -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_coupon.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 19 | 20 | 21 | 25 | 35 | 36 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 59 | 60 | 61 | 62 | 63 | 71 | 72 | 79 | 80 | 81 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_dev_info.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 16 | 17 | 24 | 25 | 31 | 32 | 38 | 39 | 45 | 46 | 52 | 53 | 59 | 60 | 66 | 67 | 68 | 69 | 70 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_group.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 15 | 16 | 21 | 22 | 30 | 31 | 32 | 33 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_home.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 14 | 15 | 21 | 22 | 28 | 29 | 37 | 38 | 39 | 40 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_me.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 12 | 13 | 19 | 20 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_privacy.xml: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 20 | 21 | 22 | 30 | 31 | 38 | 39 | 46 | 47 | 57 | 58 | 59 | 60 | 61 | 68 | 69 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_search.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 19 | 20 | 30 | 31 | 34 | 47 | 48 | 57 | 58 | 59 | 60 | 61 | 62 | 68 | 69 | 72 | 73 | 82 | 83 | 84 | 88 | 89 | 96 | 97 | 98 | 99 | 100 | 106 | 107 | 110 | 111 | 119 | 120 | 121 | 122 | 126 | 127 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_search_detail_native.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 16 | 17 | 23 | 24 | 31 | 32 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_tao_bao.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_user_info.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 16 | 17 | 22 | 23 | 27 | 28 | 35 | 36 | 42 | 43 | 49 | 50 | 56 | 57 | 63 | 64 | 70 | 71 | 77 | 78 | 84 | 85 | 91 | 92 | 93 | 94 | 95 | 101 | 102 | 110 | 111 | 119 | 120 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_home_guess_you_like.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 14 | 15 | 22 | 23 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_me_default.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 15 | 16 | 17 | 18 | 26 | 27 | 36 | 37 | 44 | 45 | 46 | 47 | 57 | 58 | 66 | 67 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 95 | 96 | 97 | 98 | 99 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_me_slot.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_s_footer.xml: -------------------------------------------------------------------------------- 1 | 2 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_text_header.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 12 | 18 | 19 | 30 | 31 | 32 | 46 | 47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /app/src/main/res/layout/me_activity_divider.xml: -------------------------------------------------------------------------------- 1 | 2 | 15 | -------------------------------------------------------------------------------- /app/src/main/res/layout/parts_simple_kv_info.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 16 | 17 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /app/src/main/res/layout/parts_tbk_sort_header.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 | 11 | 15 | 16 | 22 | 23 | 24 | 25 | 29 | 30 | 36 | 37 | 38 | 39 | 43 | 44 | 50 | 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /app/src/main/res/layout/popup_clean_cache.xml: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 13 | 21 | 22 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /app/src/main/res/layout/s_footer.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 21 | -------------------------------------------------------------------------------- /app/src/main/res/layout/search_search_item.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 13 | 14 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /app/src/main/res/layout/settings_activity.xml: -------------------------------------------------------------------------------- 1 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/layout/t_grid_demo.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/layout/user_password_activity.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 12 | 13 | 18 | 19 | 29 | 30 | 43 | 44 | 54 | 55 | 68 | 69 | 70 | 80 | 81 | 82 | 83 | -------------------------------------------------------------------------------- /app/src/main/res/menu/home_navigation_menu.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 11 | 15 | 19 | 20 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/back.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QiYuTechOrg/QiYuTkAndroid/35188be591e96b84de366098bdaf8e6bd92197ac/app/src/main/res/mipmap-hdpi/back.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/forward.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QiYuTechOrg/QiYuTkAndroid/35188be591e96b84de366098bdaf8e6bd92197ac/app/src/main/res/mipmap-hdpi/forward.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/me_order.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QiYuTechOrg/QiYuTkAndroid/35188be591e96b84de366098bdaf8e6bd92197ac/app/src/main/res/mipmap-hdpi/me_order.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QiYuTechOrg/QiYuTkAndroid/35188be591e96b84de366098bdaf8e6bd92197ac/app/src/main/res/mipmap-hdpi/settings.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/tao_bao_auth.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QiYuTechOrg/QiYuTkAndroid/35188be591e96b84de366098bdaf8e6bd92197ac/app/src/main/res/mipmap-hdpi/tao_bao_auth.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/back.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QiYuTechOrg/QiYuTkAndroid/35188be591e96b84de366098bdaf8e6bd92197ac/app/src/main/res/mipmap-mdpi/back.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/forward.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QiYuTechOrg/QiYuTkAndroid/35188be591e96b84de366098bdaf8e6bd92197ac/app/src/main/res/mipmap-mdpi/forward.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/me_order.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QiYuTechOrg/QiYuTkAndroid/35188be591e96b84de366098bdaf8e6bd92197ac/app/src/main/res/mipmap-mdpi/me_order.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QiYuTechOrg/QiYuTkAndroid/35188be591e96b84de366098bdaf8e6bd92197ac/app/src/main/res/mipmap-mdpi/settings.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/tao_bao_auth.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QiYuTechOrg/QiYuTkAndroid/35188be591e96b84de366098bdaf8e6bd92197ac/app/src/main/res/mipmap-mdpi/tao_bao_auth.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/back.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QiYuTechOrg/QiYuTkAndroid/35188be591e96b84de366098bdaf8e6bd92197ac/app/src/main/res/mipmap-xhdpi/back.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/forward.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QiYuTechOrg/QiYuTkAndroid/35188be591e96b84de366098bdaf8e6bd92197ac/app/src/main/res/mipmap-xhdpi/forward.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/me_order.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QiYuTechOrg/QiYuTkAndroid/35188be591e96b84de366098bdaf8e6bd92197ac/app/src/main/res/mipmap-xhdpi/me_order.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QiYuTechOrg/QiYuTkAndroid/35188be591e96b84de366098bdaf8e6bd92197ac/app/src/main/res/mipmap-xhdpi/settings.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/tao_bao_auth.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QiYuTechOrg/QiYuTkAndroid/35188be591e96b84de366098bdaf8e6bd92197ac/app/src/main/res/mipmap-xhdpi/tao_bao_auth.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/back.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QiYuTechOrg/QiYuTkAndroid/35188be591e96b84de366098bdaf8e6bd92197ac/app/src/main/res/mipmap-xxhdpi/back.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/forward.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QiYuTechOrg/QiYuTkAndroid/35188be591e96b84de366098bdaf8e6bd92197ac/app/src/main/res/mipmap-xxhdpi/forward.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/me_order.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QiYuTechOrg/QiYuTkAndroid/35188be591e96b84de366098bdaf8e6bd92197ac/app/src/main/res/mipmap-xxhdpi/me_order.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QiYuTechOrg/QiYuTkAndroid/35188be591e96b84de366098bdaf8e6bd92197ac/app/src/main/res/mipmap-xxhdpi/settings.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/tao_bao_auth.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QiYuTechOrg/QiYuTkAndroid/35188be591e96b84de366098bdaf8e6bd92197ac/app/src/main/res/mipmap-xxhdpi/tao_bao_auth.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/back.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QiYuTechOrg/QiYuTkAndroid/35188be591e96b84de366098bdaf8e6bd92197ac/app/src/main/res/mipmap-xxxhdpi/back.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/forward.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QiYuTechOrg/QiYuTkAndroid/35188be591e96b84de366098bdaf8e6bd92197ac/app/src/main/res/mipmap-xxxhdpi/forward.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/me_order.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QiYuTechOrg/QiYuTkAndroid/35188be591e96b84de366098bdaf8e6bd92197ac/app/src/main/res/mipmap-xxxhdpi/me_order.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QiYuTechOrg/QiYuTkAndroid/35188be591e96b84de366098bdaf8e6bd92197ac/app/src/main/res/mipmap-xxxhdpi/settings.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/tao_bao_auth.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QiYuTechOrg/QiYuTkAndroid/35188be591e96b84de366098bdaf8e6bd92197ac/app/src/main/res/mipmap-xxxhdpi/tao_bao_auth.png -------------------------------------------------------------------------------- /app/src/main/res/values-w820dp/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/values-zh/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 奇遇淘客 4 | 设置 5 | 登录/注册 6 | 加载中… 7 | *** 8 | 月销: 9 | 产品名称加载中… 10 | 优惠券 11 | 商家名称加载中 12 | 0 13 | 券后价: 14 | 15 | -------------------------------------------------------------------------------- /app/src/main/res/values/arrays.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #6200EE 4 | #3700B3 5 | #03DAC5 6 | 10 | #DAA520 11 | #ff0000 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /app/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 16sp 5 | 8sp 6 | 8sp 7 | 32dp 8 | 16sp 9 | 8sp 10 | 8sp 11 | 12 | 12sp 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 奇遇淘客 3 | 4 | Settings 5 | 6 | 7 | 8 | 9 | 10 | 11 | 登录/注册 12 | 13 | 加载中… 14 | *** 15 | 月销: 16 | 产品名称加载中… 17 | 优惠券 18 | 商家名称加载中 19 | 0 20 | 券后价: 21 | 22 | -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 14 | 20 | 21 | 24 | 25 | -------------------------------------------------------------------------------- /app/src/test/java/com/qiyutech/tbk/ExampleUnitTest.kt: -------------------------------------------------------------------------------- 1 | package com.qiyutech.tbk 2 | 3 | import com.google.gson.Gson 4 | import org.json.JSONObject 5 | import org.junit.Assert.assertEquals 6 | import org.junit.Test 7 | 8 | 9 | data class Demo(val demo: String) 10 | 11 | /** 12 | * Example local unit test, which will execute on the development machine (host). 13 | * 14 | * See [testing documentation](http://d.android.com/tools/testing). 15 | */ 16 | class ExampleUnitTest { 17 | @Test 18 | fun addition_isCorrect() { 19 | assertEquals(4, 2 + 2) 20 | } 21 | 22 | @Test 23 | fun jsonDemo() { 24 | val s = Gson().toJson(Demo("hello")) 25 | assertEquals("JSON string:", "{\"demo\":\"hello\"}", s) 26 | } 27 | 28 | @Test 29 | fun good() { 30 | val v = Demo("hello") 31 | val s = Gson().toJson(v) 32 | val v2 = Gson().fromJson(s, Demo::class.java) 33 | assertEquals(v, v2) 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | ext { 3 | sourceCompatibility = kotlin_version 4 | } 5 | 6 | buildscript { 7 | ext.kotlin_version = '1.5.0' 8 | 9 | repositories { 10 | google() 11 | jcenter() 12 | mavenCentral() 13 | maven { 14 | url "http://repo.baichuan-android.taobao.com/content/groups/BaichuanRepositories/" 15 | allowInsecureProtocol = true 16 | } 17 | } 18 | 19 | dependencies { 20 | classpath 'com.android.tools.build:gradle:7.0.0' 21 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.5.21" 22 | 23 | // NOTE: Do not place your application dependencies here; they belong 24 | // in the individual module build.gradle files 25 | } 26 | } 27 | 28 | allprojects { 29 | repositories { 30 | google() 31 | jcenter() 32 | mavenCentral() 33 | maven { 34 | url "http://repo.baichuan-android.taobao.com/content/groups/BaichuanRepositories/" 35 | allowInsecureProtocol = true 36 | } 37 | 38 | // https://www.jianshu.com/p/5f0edc95a398 39 | flatDir { 40 | dirs project(':app').file('libs') 41 | } 42 | } 43 | } 44 | 45 | task clean(type: Delete) { 46 | delete rootProject.buildDir 47 | } 48 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | # IDE (e.g. Android Studio) users: 3 | # Gradle settings configured through the IDE *will override* 4 | # any settings specified in this file. 5 | # For more details on how to configure your build environment visit 6 | # http://www.gradle.org/docs/current/userguide/build_environment.html 7 | # Specifies the JVM arguments used for the daemon process. 8 | # The setting is particularly useful for tweaking memory settings. 9 | org.gradle.jvmargs=-Xmx1536m 10 | # When configured, Gradle will run in incubating parallel mode. 11 | # This option should only be used with decoupled projects. More details, visit 12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 13 | # org.gradle.parallel=true 14 | # AndroidX package structure to make it clearer which packages are bundled with the 15 | # Android operating system, and which are packaged with your tbk's APK 16 | # https://developer.android.com/topic/libraries/support-library/androidx-rn 17 | android.useAndroidX=true 18 | # Automatically convert third-party libraries to use AndroidX 19 | android.enableJetifier=true 20 | # Kotlin code style for this project: "official" or "obsolete": 21 | kotlin.code.style=official 22 | # for dev vivo install 23 | android.injected.testOnly=false 24 | ################################## 25 | # opt build time 26 | # https://stackoverflow.com/questions/45327617/very-very-slow-gradle-build-on-android-studio 27 | #org.gradle.daemon=true 28 | #org.gradle.configureondemand=true 29 | #org.gradle.parallel=true 30 | #android.enableBuildCache=true 31 | #org.gradle.caching=true 32 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QiYuTechOrg/QiYuTkAndroid/35188be591e96b84de366098bdaf8e6bd92197ac/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | zipStoreBase=GRADLE_USER_HOME 4 | zipStorePath=wrapper/dists 5 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.0.2-all.zip 6 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Attempt to set APP_HOME 10 | # Resolve links: $0 may be a link 11 | PRG="$0" 12 | # Need this for relative symlinks. 13 | while [ -h "$PRG" ] ; do 14 | ls=`ls -ld "$PRG"` 15 | link=`expr "$ls" : '.*-> \(.*\)$'` 16 | if expr "$link" : '/.*' > /dev/null; then 17 | PRG="$link" 18 | else 19 | PRG=`dirname "$PRG"`"/$link" 20 | fi 21 | done 22 | SAVED="`pwd`" 23 | cd "`dirname \"$PRG\"`/" >/dev/null 24 | APP_HOME="`pwd -P`" 25 | cd "$SAVED" >/dev/null 26 | 27 | APP_NAME="Gradle" 28 | APP_BASE_NAME=`basename "$0"` 29 | 30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 31 | DEFAULT_JVM_OPTS="" 32 | 33 | # Use the maximum available, or set MAX_FD != -1 to use that value. 34 | MAX_FD="maximum" 35 | 36 | warn () { 37 | echo "$*" 38 | } 39 | 40 | die () { 41 | echo 42 | echo "$*" 43 | echo 44 | exit 1 45 | } 46 | 47 | # OS specific support (must be 'true' or 'false'). 48 | cygwin=false 49 | msys=false 50 | darwin=false 51 | nonstop=false 52 | case "`uname`" in 53 | CYGWIN* ) 54 | cygwin=true 55 | ;; 56 | Darwin* ) 57 | darwin=true 58 | ;; 59 | MINGW* ) 60 | msys=true 61 | ;; 62 | NONSTOP* ) 63 | nonstop=true 64 | ;; 65 | esac 66 | 67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 68 | 69 | # Determine the Java command to use to start the JVM. 70 | if [ -n "$JAVA_HOME" ] ; then 71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 72 | # IBM's JDK on AIX uses strange locations for the executables 73 | JAVACMD="$JAVA_HOME/jre/sh/java" 74 | else 75 | JAVACMD="$JAVA_HOME/bin/java" 76 | fi 77 | if [ ! -x "$JAVACMD" ] ; then 78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 79 | 80 | Please set the JAVA_HOME variable in your environment to match the 81 | location of your Java installation." 82 | fi 83 | else 84 | JAVACMD="java" 85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 86 | 87 | Please set the JAVA_HOME variable in your environment to match the 88 | location of your Java installation." 89 | fi 90 | 91 | # Increase the maximum file descriptors if we can. 92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 93 | MAX_FD_LIMIT=`ulimit -H -n` 94 | if [ $? -eq 0 ] ; then 95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 96 | MAX_FD="$MAX_FD_LIMIT" 97 | fi 98 | ulimit -n $MAX_FD 99 | if [ $? -ne 0 ] ; then 100 | warn "Could not set maximum file descriptor limit: $MAX_FD" 101 | fi 102 | else 103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 104 | fi 105 | fi 106 | 107 | # For Darwin, add options to specify how the application appears in the dock 108 | if $darwin; then 109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 110 | fi 111 | 112 | # For Cygwin, switch paths to Windows format before running java 113 | if $cygwin ; then 114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 116 | JAVACMD=`cygpath --unix "$JAVACMD"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Escape application args 158 | save () { 159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 160 | echo " " 161 | } 162 | APP_ARGS=$(save "$@") 163 | 164 | # Collect all arguments for the java command, following the shell quoting and substitution rules 165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 166 | 167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong 168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then 169 | cd "$(dirname "$0")" 170 | fi 171 | 172 | exec "$JAVACMD" "$@" 173 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /keystore/readme.md: -------------------------------------------------------------------------------- 1 | 数字签名 2 | -------------------------------------------------------------------------------- /keystore/tbk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QiYuTechOrg/QiYuTkAndroid/35188be591e96b84de366098bdaf8e6bd92197ac/keystore/tbk -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'TaoBaoKe' 2 | include ':app' 3 | --------------------------------------------------------------------------------