├── .github ├── FUNDING.yml └── workflows │ └── issue_check.yml ├── .gitignore ├── .idea ├── copyright │ ├── profiles_settings.xml │ └── xuexiang.xml └── gradle.xml ├── LICENSE ├── README.md ├── app ├── .gitignore ├── build.gradle ├── channel ├── debug.jks ├── multiple-channel.gradle ├── proguard-rules.pro ├── src │ ├── androidTest │ │ └── java │ │ │ └── com │ │ │ └── xuexiang │ │ │ └── templateproject │ │ │ └── ExampleInstrumentedTest.kt │ ├── main │ │ ├── AndroidManifest.xml │ │ ├── assets │ │ │ ├── protocol │ │ │ │ ├── account_protocol.txt │ │ │ │ └── privacy_protocol.txt │ │ │ └── tips.json │ │ ├── java │ │ │ └── com │ │ │ │ └── xuexiang │ │ │ │ └── templateproject │ │ │ │ ├── MyApp.kt │ │ │ │ ├── activity │ │ │ │ ├── LoginActivity.kt │ │ │ │ ├── MainActivity.kt │ │ │ │ └── SplashActivity.kt │ │ │ │ ├── adapter │ │ │ │ ├── base │ │ │ │ │ ├── broccoli │ │ │ │ │ │ ├── BroccoliRecyclerAdapter.kt │ │ │ │ │ │ └── BroccoliSimpleDelegateAdapter.kt │ │ │ │ │ └── delegate │ │ │ │ │ │ ├── BaseDelegateAdapter.kt │ │ │ │ │ │ ├── SimpleDelegateAdapter.kt │ │ │ │ │ │ ├── SingleDelegateAdapter.kt │ │ │ │ │ │ └── XDelegateAdapter.kt │ │ │ │ └── entity │ │ │ │ │ └── NewInfo.kt │ │ │ │ ├── core │ │ │ │ ├── BaseActivity.kt │ │ │ │ ├── BaseContainerFragment.kt │ │ │ │ ├── BaseFragment.kt │ │ │ │ ├── BaseSimpleListFragment.kt │ │ │ │ ├── SimpleListAdapter.kt │ │ │ │ ├── XPageTransferActivity.kt │ │ │ │ ├── http │ │ │ │ │ ├── api │ │ │ │ │ │ └── ApiService.kt │ │ │ │ │ ├── callback │ │ │ │ │ │ ├── NoTipCallBack.kt │ │ │ │ │ │ ├── TipCallBack.kt │ │ │ │ │ │ └── TipProgressLoadingCallBack.kt │ │ │ │ │ ├── entity │ │ │ │ │ │ └── TipInfo.kt │ │ │ │ │ ├── loader │ │ │ │ │ │ ├── IProgressLoaderFactory.kt │ │ │ │ │ │ ├── MiniLoadingDialogLoader.kt │ │ │ │ │ │ ├── MiniProgressLoaderFactory.kt │ │ │ │ │ │ └── ProgressLoader.kt │ │ │ │ │ └── subscriber │ │ │ │ │ │ ├── NoTipRequestSubscriber.kt │ │ │ │ │ │ ├── TipProgressLoadingSubscriber.kt │ │ │ │ │ │ └── TipRequestSubscriber.kt │ │ │ │ └── webview │ │ │ │ │ ├── AgentWebActivity.kt │ │ │ │ │ ├── AgentWebFragment.kt │ │ │ │ │ ├── BaseWebViewFragment.kt │ │ │ │ │ ├── FragmentKeyDown.kt │ │ │ │ │ ├── LollipopFixedWebView.kt │ │ │ │ │ ├── MiddlewareChromeClient.kt │ │ │ │ │ ├── MiddlewareWebViewClient.kt │ │ │ │ │ ├── UIController.kt │ │ │ │ │ ├── WebLayout.kt │ │ │ │ │ ├── WebViewInterceptDialog.kt │ │ │ │ │ └── XPageWebViewFragment.kt │ │ │ │ ├── fragment │ │ │ │ ├── news │ │ │ │ │ ├── GridItemFragment.kt │ │ │ │ │ └── NewsFragment.kt │ │ │ │ ├── other │ │ │ │ │ ├── AboutFragment.kt │ │ │ │ │ ├── LoginFragment.kt │ │ │ │ │ ├── ServiceProtocolFragment.kt │ │ │ │ │ └── SettingsFragment.kt │ │ │ │ ├── profile │ │ │ │ │ └── ProfileFragment.kt │ │ │ │ └── trending │ │ │ │ │ └── TrendingFragment.kt │ │ │ │ ├── utils │ │ │ │ ├── DemoDataProvider.kt │ │ │ │ ├── MMKVUtils.kt │ │ │ │ ├── RandomUtils.kt │ │ │ │ ├── SettingUtils.kt │ │ │ │ ├── TokenUtils.kt │ │ │ │ ├── Utils.kt │ │ │ │ ├── sdkinit │ │ │ │ │ ├── ANRWatchDogInit.kt │ │ │ │ │ ├── UMengInit.kt │ │ │ │ │ ├── XBasicLibInit.kt │ │ │ │ │ └── XUpdateInit.kt │ │ │ │ ├── service │ │ │ │ │ └── JsonSerializationService.kt │ │ │ │ └── update │ │ │ │ │ ├── CustomUpdateDownloader.kt │ │ │ │ │ ├── CustomUpdateFailureListener.kt │ │ │ │ │ ├── CustomUpdateParser.kt │ │ │ │ │ ├── UpdateTipDialog.kt │ │ │ │ │ └── XHttpUpdateHttpServiceImpl.kt │ │ │ │ └── widget │ │ │ │ ├── GuideTipsDialog.kt │ │ │ │ └── MaterialFooter.kt │ │ └── res │ │ │ ├── color │ │ │ └── selector_round_button_main_theme_color.xml │ │ │ ├── drawable-hdpi │ │ │ ├── ic_comment.png │ │ │ ├── ic_praise.png │ │ │ ├── ic_splash_app_logo_xui.png │ │ │ └── ic_splash_company_logo.png │ │ │ ├── drawable-v17 │ │ │ └── xui_config_bg_splash.xml │ │ │ ├── drawable-v21 │ │ │ └── xui_config_bg_splash.xml │ │ │ ├── drawable-v24 │ │ │ └── ic_launcher_foreground.xml │ │ │ ├── drawable-xxxhdpi │ │ │ ├── ic_web_back.png │ │ │ ├── ic_web_close.png │ │ │ └── ic_web_more.png │ │ │ ├── drawable │ │ │ ├── bg_dialog_common_tip_corner_white.xml │ │ │ ├── ic_action_close_white.xml │ │ │ ├── ic_default_head.xml │ │ │ ├── ic_launcher_background.xml │ │ │ ├── ic_login_close.xml │ │ │ ├── ic_logo_app.xml │ │ │ ├── ic_menu_about.xml │ │ │ ├── ic_menu_about_white.xml │ │ │ ├── ic_menu_issues.xml │ │ │ ├── ic_menu_news.xml │ │ │ ├── ic_menu_notifications.xml │ │ │ ├── ic_menu_person.xml │ │ │ ├── ic_menu_privacy.xml │ │ │ ├── ic_menu_search.xml │ │ │ ├── ic_menu_settings.xml │ │ │ ├── ic_menu_star.xml │ │ │ ├── ic_menu_trending.xml │ │ │ ├── ic_password.xml │ │ │ ├── ic_phone.xml │ │ │ ├── icon_arrow_right_grey.xml │ │ │ └── img_guide_tip_top.xml │ │ │ ├── layout │ │ │ ├── activity_agent_web.xml │ │ │ ├── activity_main.xml │ │ │ ├── adapter_common_grid_item.xml │ │ │ ├── adapter_item_simple_list_2.xml │ │ │ ├── adapter_news_card_view_list_item.xml │ │ │ ├── adapter_title_item.xml │ │ │ ├── dialog_guide_tips.xml │ │ │ ├── fragment_about.xml │ │ │ ├── fragment_agentweb.xml │ │ │ ├── fragment_grid_item.xml │ │ │ ├── fragment_login.xml │ │ │ ├── fragment_news.xml │ │ │ ├── fragment_profile.xml │ │ │ ├── fragment_pulldown_web.xml │ │ │ ├── fragment_service_protocol.xml │ │ │ ├── fragment_settings.xml │ │ │ ├── fragment_trending.xml │ │ │ ├── include_head_view_banner.xml │ │ │ ├── include_navigation_header.xml │ │ │ ├── include_toolbar_web.xml │ │ │ ├── layout_main_content.xml │ │ │ └── layout_news_card_item.xml │ │ │ ├── menu │ │ │ ├── menu_drawer.xml │ │ │ ├── menu_main.xml │ │ │ ├── menu_navigation_bottom.xml │ │ │ └── menu_toolbar_web.xml │ │ │ ├── mipmap-anydpi-v26 │ │ │ ├── ic_launcher.xml │ │ │ └── ic_launcher_round.xml │ │ │ ├── mipmap-hdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-mdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xhdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xxhdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xxxhdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ │ ├── values │ │ │ ├── arrays.xml │ │ │ ├── colors.xml │ │ │ ├── dimens.xml │ │ │ ├── strings.xml │ │ │ ├── styles.xml │ │ │ └── styles_widget.xml │ │ │ └── xml │ │ │ └── network_security_config.xml │ └── test │ │ └── java │ │ └── com │ │ └── xuexiang │ │ └── templateproject │ │ └── ExampleUnitTest.kt └── x-library.gradle ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── settings.gradle └── versions.gradle /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | custom: https://gitee.com/xuexiangjys/Resource/blob/master/doc/sponsor.md 4 | -------------------------------------------------------------------------------- /.github/workflows/issue_check.yml: -------------------------------------------------------------------------------- 1 | name: No Free usage issue checker # Action名字。可以自定义 2 | 3 | on: 4 | issues: 5 | types: [opened, reopened] # 在issue打开和重新打开时调用 6 | 7 | jobs: 8 | build: 9 | runs-on: ubuntu-latest 10 | 11 | steps: 12 | - uses: actions/checkout@v2 13 | - name: Check issue actor # 步骤名字。可以自定义。 14 | uses: fluttercandies/no-free-usage-action@v1.0.1 15 | with: 16 | token: ${{ secrets.GITHUB_TOKEN }} # 由GitHub提供的临时Token,必须在此处进行传递,且必须为这个值。 17 | forked: '--no-forked' 18 | words: To support our project, please file the issue after you starred the repo. Thanks! 🙂 19 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /LocalRepository 4 | /keystores 5 | /local.properties 6 | /.idea/caches 7 | /.idea/codeStyles 8 | /.idea/inspectionProfiles 9 | /.idea/libraries 10 | /.idea/dictionaries 11 | /.idea/markdown-navigator 12 | /.idea/*.xml 13 | .DS_Store 14 | /build 15 | /captures 16 | .externalNativeBuild -------------------------------------------------------------------------------- /.idea/copyright/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /.idea/copyright/xuexiang.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 18 | 19 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/channel: -------------------------------------------------------------------------------- 1 | # 美团 2 | meituan 3 | # 三星 4 | samsungapps 5 | # 小米 6 | xiaomi 7 | # 91助手 8 | 91com 9 | # 魅族 10 | meizu 11 | # 豌豆荚 12 | wandou 13 | # Google Play 14 | googleplay 15 | # 百度 16 | baidu 17 | # 360 18 | 360cn 19 | # 应用宝 20 | myapp 21 | # 华为 22 | huawei 23 | # 蒲公英 24 | pgyer 25 | github -------------------------------------------------------------------------------- /app/debug.jks: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuexiangjys/TemplateAppProject-kotlin/551bef56697c628628d42a857db37658c7670f8d/app/debug.jks -------------------------------------------------------------------------------- /app/multiple-channel.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'walle' 2 | 3 | walle { 4 | // 指定渠道包的输出路径 5 | apkOutputFolder = new File("${project.buildDir}/outputs/channels") 6 | // 定制渠道包的APK的文件名称 7 | apkFileNameFormat = '${appName}-${packageName}-${channel}-${buildType}-v${versionName}-${versionCode}-${buildTime}.apk' 8 | // 渠道配置文件 9 | channelFile = new File("${project.getProjectDir()}/channel") 10 | } -------------------------------------------------------------------------------- /app/src/androidTest/java/com/xuexiang/templateproject/ExampleInstrumentedTest.kt: -------------------------------------------------------------------------------- 1 | package com.xuexiang.templateproject 2 | 3 | import androidx.test.ext.junit.runners.AndroidJUnit4 4 | import androidx.test.platform.app.InstrumentationRegistry 5 | import org.junit.Assert 6 | import org.junit.Test 7 | import org.junit.runner.RunWith 8 | 9 | /** 10 | * Instrumented test, which will execute on an Android device. 11 | * 12 | * @see [Testing documentation](http://d.android.com/tools/testing) 13 | */ 14 | @RunWith(AndroidJUnit4::class) 15 | class ExampleInstrumentedTest { 16 | @Test 17 | fun useAppContext() { 18 | // Context of the app under test. 19 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext 20 | Assert.assertEquals("com.xuexiang.templateproject", appContext.packageName) 21 | } 22 | } -------------------------------------------------------------------------------- /app/src/main/assets/protocol/privacy_protocol.txt: -------------------------------------------------------------------------------- 1 | ####尊重并保护所有使用服务用户的个人隐私权。为了给您提供更准确、更有个性化的 服务,####会按照本隐私权政策的规定使用和披露您的个人信息。但####将以高 度的勤勉、审慎义务对待这些信息。除本隐私权政策另有规定外,在未征得您事先许可的情况下 ,####不会将这些信息对外披露或向第三方提供。####会不时更新本隐私权政策 。 您在同意####服务使用协议之时,即视为您已经同意本隐私权政策全部内容。本隐私 权政策属于####服务使用协议不可分割的一部分。 2 | 3 | 4 | 1. 适用范围 5 | 6 | a) 在您注册####帐号时,您根据####要求提供的个人注册信息; 7 | 8 | b) 在您使用####网络服务,或访问####平台网页时,####自动接收并记 录的您的浏览器和计算机上的信息,包括但不限于您的IP地址、浏览器的类型、使用的语言、访 问日期和时间、软硬件特征信息及您需求的网页记录等数据; 9 | 10 | c) ####通过合法途径从商业伙伴处取得的用户个人数据。 11 | 12 | 您了解并同意,以下信息不适用本隐私权政策: 13 | 14 | a) 您在使用####平台提供的搜索服务时输入的关键字信息; 15 | 16 | b) ####收集到的您在####发布的有关信息数据,包括但不限于参与活动、成交 信息及评价详情; 17 | 18 | c) 违反法律规定或违反####规则行为及####已对您采取的措施。 19 | 20 | 2. 信息使用 21 | 22 | a) ####不会向任何无关第三方提供、出售、出租、分享或交易您的个人信息,除非事先 得到您的许可,或该第三方和####(含####关联公司)单独或共同为您提供服务 ,且在该服务结束后,其将被禁止访问包括其以前能够访问的所有这些资料。 23 | 24 | b) ####亦不允许任何第三方以任何手段收集、编辑、出售或者无偿传播您的个人信息。 任何####平台用户如从事上述活动,一经发现,####有权立即终止与该用户的服 务协议。 25 | 26 | c) 为服务用户的目的,####可能通过使用您的个人信息,向您提供您感兴趣的信息,包 括但不限于向您发出产品和服务信息,或者与####合作伙伴共享信息以便他们向您发送 有关其产品和服务的信息(后者需要您的事先同意)。 27 | 28 | 3. 信息披露 在如下情况下,####将依据您的个人意愿或法律的规定全部或部分的披露您的个人信息 : 29 | 30 | a) 经您事先同意,向第三方披露; 31 | 32 | b) 为提供您所要求的产品和服务,而必须和第三方分享您的个人信息; 33 | 34 | c) 根据法律的有关规定,或者行政或司法机构的要求,向第三方或者行政、司法机构披露; 35 | 36 | d) 如您出现违反中国有关法律、法规或者####服务协议或相关规则的情况,需要向第三 方披露; 37 | 38 | e) 如您是适格的知识产权投诉人并已提起投诉,应被投诉人要求,向被投诉人披露,以便双方 处理可能的权利纠纷; 39 | 40 | f) 在####平台上创建的某一交易中,如交易任何一方履行或部分履行了交易义务并提出 信息披露请求的,####有权决定向该用户提供其交易对方的联络方式等必要信息,以促 成交易的完成或纠纷的解决。 41 | 42 | g) 其它####根据法律、法规或者网站政策认为合适的披露。 43 | 44 | 4. 信息存储和交换 ####收集的有关您的信息和资料将保存在####及(或)其关联公司的服务器上, 这些信息和资料可能传送至您所在国家、地区或####收集信息和资料所在地的境外并在 境外被访问、存储和展示。 45 | 46 | 5. Cookie的使用 47 | 48 | a) 在您未拒绝接受cookies的情况下,####会在您的计算机上设定或取用cookies ,以便您能登录或使用依赖于cookies的####平台服务或功能。####使用cookies 可为您提供更加周到的个性化服务,包括推广服务。 49 | 50 | b) 您有权选择接受或拒绝接受cookies。 您可以通过修改浏览器设置的方式拒绝接受cookies。但如果您选择拒绝接受cookies,则您可能 无法登录或使用依赖于cookies的####网络服务或功能。 51 | 52 | c) 通过####所设cookies所取得的有关信息,将适用本政策。 53 | 54 | 6. 信息安全 55 | 56 | a) ####帐号均有安全保护功能,请妥善保管您的用户名及密码信息。####将通 过对用户密码进行加密等安全措施确保您的信息不丢失,不被滥用和变造。尽管有前述安全措施 ,但同时也请您注意在信息网络上不存在“完善的安全措施”。 57 | 58 | b) 在使用####网络服务进行网上交易时,您不可避免的要向交易对方或潜在的交易对方 披露自己的个人信息,如联络方式或者邮政地址。请您妥善保护自己的个人信息,仅在必要的情 形下向他人提供。如您发现自己的个人信息泄密,尤其是####用户名及密码发生泄露, 请您立即联络####客服,以便####采取相应措施。 59 | 60 | 7. 接入的第三方SDK说明 61 | 62 | a) 友盟统计SDK(com.umeng) 63 | 使用目的: 统计应用运营数据 64 | 使用范围: 应用运营数据统计 65 | 66 | 8. 敏感信息收集说明 67 | 我们的产品集成友盟+SDK,友盟+SDK需要收集您的设备Mac地址、唯一设备识别码(IMEI/android ID/IDFA/OPENUDID/GUID、SIM 卡 IMSI 信息)以提供统计分析服务,并通过地理位置校准报表数据准确性,提供基础反作弊能力。 68 | 69 | 70 | 71 | -------------------------------------------------------------------------------- /app/src/main/assets/tips.json: -------------------------------------------------------------------------------- 1 | { 2 | "Code": 0, 3 | "Data": [ 4 | { 5 | "title": "微信公众号", 6 | "content": "获取更多资讯内容,欢迎微信搜索公众号:「我的Android开源之旅」" 7 | }, 8 | { 9 | "title": "关于作者", 10 | "content": "点击关注作者,了解最新动态!
Github
\n知乎
\n掘金
简书
\n思否
\n哔哩哔哩
\n今日头条" 11 | }, 12 | { 13 | "title": "赞助作者", 14 | "content": "你的打赏是我维护的动力,点击此处支持我吧!" 15 | }, 16 | { 17 | "title": "QQ交流群", 18 | "content": "XUI开源交流1号群
XUI开源交流2号群
AndroidGitHub开源交流群
XUpdate官方交流群" 19 | } 20 | ] 21 | } 22 | -------------------------------------------------------------------------------- /app/src/main/java/com/xuexiang/templateproject/MyApp.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2019 xuexiangjys(xuexiangjys@163.com) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | package com.xuexiang.templateproject 18 | 19 | import android.app.Application 20 | import android.content.Context 21 | import androidx.multidex.MultiDex 22 | import com.xuexiang.templateproject.utils.sdkinit.XBasicLibInit 23 | import com.xuexiang.templateproject.utils.sdkinit.XUpdateInit 24 | import com.xuexiang.templateproject.utils.sdkinit.UMengInit 25 | import com.xuexiang.templateproject.utils.sdkinit.ANRWatchDogInit 26 | 27 | /** 28 | * @author xuexiang 29 | * @since 2018/11/7 下午1:12 30 | */ 31 | class MyApp : Application() { 32 | override fun attachBaseContext(base: Context) { 33 | super.attachBaseContext(base) 34 | //解决4.x运行崩溃的问题 35 | MultiDex.install(this) 36 | } 37 | 38 | override fun onCreate() { 39 | super.onCreate() 40 | initLibs() 41 | } 42 | 43 | /** 44 | * 初始化基础库 45 | */ 46 | private fun initLibs() { 47 | // X系列基础库初始化 48 | XBasicLibInit.init(this) 49 | // 版本更新初始化 50 | XUpdateInit.init(this) 51 | // 运营统计数据 52 | UMengInit.init(this) 53 | // ANR监控 54 | ANRWatchDogInit.init() 55 | } 56 | 57 | companion object { 58 | /** 59 | * @return 当前app是否是调试开发模式 60 | */ 61 | val isDebug: Boolean 62 | get() = BuildConfig.DEBUG 63 | } 64 | } -------------------------------------------------------------------------------- /app/src/main/java/com/xuexiang/templateproject/activity/LoginActivity.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2019 xuexiangjys(xuexiangjys@163.com) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | package com.xuexiang.templateproject.activity 18 | 19 | import android.os.Bundle 20 | import android.view.KeyEvent 21 | import androidx.viewbinding.ViewBinding 22 | import com.xuexiang.templateproject.core.BaseActivity 23 | import com.xuexiang.templateproject.fragment.other.LoginFragment 24 | import com.xuexiang.xui.utils.KeyboardUtils 25 | import com.xuexiang.xui.utils.StatusBarUtils 26 | import com.xuexiang.xutil.display.Colors 27 | 28 | /** 29 | * 登录页面 30 | * 31 | * @author xuexiang 32 | * @since 2019-11-17 22:21 33 | */ 34 | class LoginActivity : BaseActivity() { 35 | override fun onCreate(savedInstanceState: Bundle?) { 36 | super.onCreate(savedInstanceState) 37 | openPage(LoginFragment::class.java, intent.extras) 38 | } 39 | 40 | override val isSupportSlideBack = false 41 | 42 | override fun initStatusBarStyle() { 43 | StatusBarUtils.initStatusBarStyle(this, false, Colors.WHITE) 44 | } 45 | 46 | override fun onKeyDown(keyCode: Int, event: KeyEvent): Boolean { 47 | return KeyboardUtils.onDisableBackKeyDown(keyCode) && super.onKeyDown(keyCode, event) 48 | } 49 | } -------------------------------------------------------------------------------- /app/src/main/java/com/xuexiang/templateproject/activity/SplashActivity.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2019 xuexiangjys(xuexiangjys@163.com) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | package com.xuexiang.templateproject.activity 18 | 19 | import android.view.KeyEvent 20 | import com.xuexiang.templateproject.R 21 | import com.xuexiang.templateproject.utils.SettingUtils.isAgreePrivacy 22 | import com.xuexiang.templateproject.utils.TokenUtils.hasToken 23 | import com.xuexiang.templateproject.utils.Utils.showPrivacyDialog 24 | import com.xuexiang.xui.utils.KeyboardUtils 25 | import com.xuexiang.xui.widget.activity.BaseSplashActivity 26 | import com.xuexiang.xui.widget.dialog.materialdialog.DialogAction 27 | import com.xuexiang.xui.widget.dialog.materialdialog.MaterialDialog 28 | import com.xuexiang.xutil.app.ActivityUtils 29 | import me.jessyan.autosize.internal.CancelAdapt 30 | 31 | /** 32 | * 启动页【无需适配屏幕大小】 33 | * 34 | * @author xuexiang 35 | * @since 2019-06-30 17:32 36 | */ 37 | class SplashActivity : BaseSplashActivity(), CancelAdapt { 38 | override fun getSplashDurationMillis(): Long { 39 | return 500 40 | } 41 | 42 | /** 43 | * activity启动后的初始化 44 | */ 45 | override fun onCreateActivity() { 46 | initSplashView(R.drawable.xui_config_bg_splash) 47 | startSplash(false) 48 | } 49 | 50 | /** 51 | * 启动页结束后的动作 52 | */ 53 | override fun onSplashFinished() { 54 | if (isAgreePrivacy) { 55 | loginOrGoMainPage() 56 | } else { 57 | showPrivacyDialog(this) { dialog: MaterialDialog, which: DialogAction? -> 58 | dialog.dismiss() 59 | isAgreePrivacy = true 60 | loginOrGoMainPage() 61 | } 62 | } 63 | } 64 | 65 | private fun loginOrGoMainPage() { 66 | if (hasToken()) { 67 | ActivityUtils.startActivity(MainActivity::class.java) 68 | } else { 69 | ActivityUtils.startActivity(LoginActivity::class.java) 70 | } 71 | finish() 72 | } 73 | 74 | /** 75 | * 菜单、返回键响应 76 | */ 77 | override fun onKeyDown(keyCode: Int, event: KeyEvent): Boolean { 78 | return KeyboardUtils.onDisableBackKeyDown(keyCode) && super.onKeyDown(keyCode, event) 79 | } 80 | } -------------------------------------------------------------------------------- /app/src/main/java/com/xuexiang/templateproject/adapter/base/broccoli/BroccoliRecyclerAdapter.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021 xuexiangjys(xuexiangjys@163.com) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | package com.xuexiang.templateproject.adapter.base.broccoli 18 | 19 | import android.view.View 20 | import com.xuexiang.xui.adapter.recyclerview.BaseRecyclerAdapter 21 | import com.xuexiang.xui.adapter.recyclerview.RecyclerViewHolder 22 | import com.xuexiang.xui.adapter.recyclerview.XRecyclerAdapter 23 | import me.samlss.broccoli.Broccoli 24 | import java.util.* 25 | 26 | /** 27 | * 使用Broccoli占位的基础适配器 28 | * 29 | * @author XUE 30 | * @since 2019/4/8 16:33 31 | */ 32 | abstract class BroccoliRecyclerAdapter(collection: Collection?) : 33 | BaseRecyclerAdapter(collection) { 34 | /** 35 | * 是否已经加载成功 36 | */ 37 | private var mHasLoad = false 38 | private val mBroccoliMap: MutableMap = HashMap() 39 | override fun bindData(holder: RecyclerViewHolder, position: Int, item: T) { 40 | var broccoli = mBroccoliMap[holder.itemView] 41 | if (broccoli == null) { 42 | broccoli = Broccoli() 43 | mBroccoliMap[holder.itemView] = broccoli 44 | } 45 | if (mHasLoad) { 46 | broccoli.removeAllPlaceholders() 47 | onBindData(holder, item, position) 48 | } else { 49 | onBindBroccoli(holder, broccoli) 50 | broccoli.show() 51 | } 52 | } 53 | 54 | /** 55 | * 绑定控件 56 | * 57 | * @param holder 58 | * @param model 59 | * @param position 60 | */ 61 | protected abstract fun onBindData(holder: RecyclerViewHolder?, model: T, position: Int) 62 | 63 | /** 64 | * 绑定占位控件 65 | * 66 | * @param broccoli 67 | */ 68 | protected abstract fun onBindBroccoli(holder: RecyclerViewHolder?, broccoli: Broccoli?) 69 | override fun refresh(collection: Collection): XRecyclerAdapter<*, *> { 70 | mHasLoad = true 71 | return super.refresh(collection) 72 | } 73 | 74 | /** 75 | * 资源释放,防止内存泄漏 76 | */ 77 | fun recycle() { 78 | for (broccoli in mBroccoliMap.values) { 79 | broccoli.removeAllPlaceholders() 80 | } 81 | mBroccoliMap.clear() 82 | clear() 83 | } 84 | } -------------------------------------------------------------------------------- /app/src/main/java/com/xuexiang/templateproject/adapter/base/broccoli/BroccoliSimpleDelegateAdapter.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021 xuexiangjys(xuexiangjys@163.com) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | package com.xuexiang.templateproject.adapter.base.broccoli 18 | 19 | import android.view.View 20 | import com.alibaba.android.vlayout.LayoutHelper 21 | import com.xuexiang.templateproject.adapter.base.delegate.SimpleDelegateAdapter 22 | import com.xuexiang.templateproject.adapter.base.delegate.XDelegateAdapter 23 | import com.xuexiang.xui.adapter.recyclerview.RecyclerViewHolder 24 | import me.samlss.broccoli.Broccoli 25 | 26 | /** 27 | * 使用Broccoli占位的基础适配器 28 | * 29 | * @author xuexiang 30 | * @since 2021/1/9 4:52 PM 31 | */ 32 | abstract class BroccoliSimpleDelegateAdapter : SimpleDelegateAdapter { 33 | /** 34 | * 是否已经加载成功 35 | */ 36 | private var mHasLoad = false 37 | private val mBroccoliMap: MutableMap = HashMap() 38 | 39 | constructor(layoutId: Int, layoutHelper: LayoutHelper) : super(layoutId, layoutHelper) 40 | constructor(layoutId: Int, layoutHelper: LayoutHelper, list: Collection?) : super( 41 | layoutId, 42 | layoutHelper, 43 | list 44 | ) 45 | 46 | constructor(layoutId: Int, layoutHelper: LayoutHelper, data: Array?) : super( 47 | layoutId, 48 | layoutHelper, 49 | data 50 | ) 51 | 52 | override fun bindData(holder: RecyclerViewHolder, position: Int, item: T) { 53 | var broccoli = mBroccoliMap[holder.itemView] 54 | if (broccoli == null) { 55 | broccoli = Broccoli() 56 | mBroccoliMap[holder.itemView] = broccoli 57 | } 58 | if (mHasLoad) { 59 | broccoli.removeAllPlaceholders() 60 | onBindData(holder, item, position) 61 | } else { 62 | onBindBroccoli(holder, broccoli) 63 | broccoli.show() 64 | } 65 | } 66 | 67 | /** 68 | * 绑定控件 69 | * 70 | * @param holder 71 | * @param model 72 | * @param position 73 | */ 74 | protected abstract fun onBindData(holder: RecyclerViewHolder, model: T, position: Int) 75 | 76 | /** 77 | * 绑定占位控件 78 | * 79 | * @param holder 80 | * @param broccoli 81 | */ 82 | protected abstract fun onBindBroccoli(holder: RecyclerViewHolder, broccoli: Broccoli) 83 | 84 | override fun refresh(collection: Collection?): XDelegateAdapter<*, *> { 85 | mHasLoad = true 86 | return super.refresh(collection) 87 | } 88 | 89 | /** 90 | * 资源释放,防止内存泄漏 91 | */ 92 | fun recycle() { 93 | for (broccoli in mBroccoliMap.values) { 94 | broccoli.removeAllPlaceholders() 95 | } 96 | mBroccoliMap.clear() 97 | clear() 98 | } 99 | } -------------------------------------------------------------------------------- /app/src/main/java/com/xuexiang/templateproject/adapter/base/delegate/BaseDelegateAdapter.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 xuexiangjys(xuexiangjys@163.com) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | package com.xuexiang.templateproject.adapter.base.delegate 18 | 19 | import android.view.ViewGroup 20 | import com.xuexiang.xui.adapter.recyclerview.RecyclerViewHolder 21 | 22 | /** 23 | * 通用的DelegateAdapter适配器 24 | * 25 | * @author xuexiang 26 | * @since 2020/3/20 12:44 AM 27 | */ 28 | abstract class BaseDelegateAdapter : XDelegateAdapter { 29 | constructor() : super() {} 30 | constructor(list: Collection?) : super(list) {} 31 | constructor(data: Array?) : super(data) {} 32 | 33 | /** 34 | * 适配的布局 35 | * 36 | * @param viewType 37 | * @return 38 | */ 39 | protected abstract fun getItemLayoutId(viewType: Int): Int 40 | override fun getViewHolder(parent: ViewGroup, viewType: Int): RecyclerViewHolder { 41 | return RecyclerViewHolder(inflateView(parent, getItemLayoutId(viewType))) 42 | } 43 | } -------------------------------------------------------------------------------- /app/src/main/java/com/xuexiang/templateproject/adapter/base/delegate/SimpleDelegateAdapter.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 xuexiangjys(xuexiangjys@163.com) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | package com.xuexiang.templateproject.adapter.base.delegate 18 | 19 | import com.alibaba.android.vlayout.LayoutHelper 20 | 21 | /** 22 | * 简易DelegateAdapter适配器 23 | * 24 | * @author xuexiang 25 | * @since 2020/3/20 12:55 AM 26 | */ 27 | abstract class SimpleDelegateAdapter : BaseDelegateAdapter { 28 | private var mLayoutId: Int 29 | private var mLayoutHelper: LayoutHelper 30 | 31 | constructor(layoutId: Int, layoutHelper: LayoutHelper) : super() { 32 | mLayoutId = layoutId 33 | mLayoutHelper = layoutHelper 34 | } 35 | 36 | constructor(layoutId: Int, layoutHelper: LayoutHelper, list: Collection?) : super(list) { 37 | mLayoutId = layoutId 38 | mLayoutHelper = layoutHelper 39 | } 40 | 41 | constructor(layoutId: Int, layoutHelper: LayoutHelper, data: Array?) : super(data) { 42 | mLayoutId = layoutId 43 | mLayoutHelper = layoutHelper 44 | } 45 | 46 | override fun getItemLayoutId(viewType: Int): Int { 47 | return mLayoutId 48 | } 49 | 50 | override fun onCreateLayoutHelper(): LayoutHelper { 51 | return mLayoutHelper 52 | } 53 | } -------------------------------------------------------------------------------- /app/src/main/java/com/xuexiang/templateproject/adapter/base/delegate/SingleDelegateAdapter.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 xuexiangjys(xuexiangjys@163.com) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | package com.xuexiang.templateproject.adapter.base.delegate 18 | 19 | import android.view.LayoutInflater 20 | import android.view.View 21 | import android.view.ViewGroup 22 | import androidx.annotation.LayoutRes 23 | import com.alibaba.android.vlayout.DelegateAdapter 24 | import com.alibaba.android.vlayout.LayoutHelper 25 | import com.alibaba.android.vlayout.layout.SingleLayoutHelper 26 | import com.xuexiang.xui.adapter.recyclerview.RecyclerViewHolder 27 | 28 | /** 29 | * 单独布局的DelegateAdapter 30 | * 31 | * @author xuexiang 32 | * @since 2020/3/20 1:04 AM 33 | */ 34 | abstract class SingleDelegateAdapter(private val mLayoutId: Int) : 35 | DelegateAdapter.Adapter() { 36 | override fun onCreateLayoutHelper(): LayoutHelper { 37 | return SingleLayoutHelper() 38 | } 39 | 40 | /** 41 | * 加载布局获取控件 42 | * 43 | * @param parent 父布局 44 | * @param layoutId 布局ID 45 | * @return 46 | */ 47 | protected fun inflateView(parent: ViewGroup, @LayoutRes layoutId: Int): View { 48 | return LayoutInflater.from(parent.context).inflate(layoutId, parent, false) 49 | } 50 | 51 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerViewHolder { 52 | return RecyclerViewHolder(inflateView(parent, mLayoutId)) 53 | } 54 | 55 | override fun getItemCount(): Int { 56 | return 1 57 | } 58 | } -------------------------------------------------------------------------------- /app/src/main/java/com/xuexiang/templateproject/core/BaseContainerFragment.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2019 xuexiangjys(xuexiangjys@163.com) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | package com.xuexiang.templateproject.core 18 | 19 | import android.content.res.Configuration 20 | import android.view.View 21 | import android.view.ViewGroup 22 | import android.widget.AdapterView 23 | import com.umeng.analytics.MobclickAgent 24 | import com.xuexiang.xaop.annotation.SingleClick 25 | import com.xuexiang.xpage.base.XPageContainerListFragment 26 | import com.xuexiang.xui.widget.actionbar.TitleBar 27 | import com.xuexiang.xui.widget.actionbar.TitleUtils 28 | import java.util.* 29 | 30 | /** 31 | * 修改列表样式为主副标题显示 32 | * 33 | * @author xuexiang 34 | * @since 2018/11/22 上午11:26 35 | */ 36 | abstract class BaseContainerFragment : XPageContainerListFragment() { 37 | override fun initPage() { 38 | initTitle() 39 | initViews() 40 | initListeners() 41 | } 42 | 43 | private fun initTitle(): TitleBar { 44 | return TitleUtils.addTitleBarDynamic( 45 | toolbarContainer, 46 | pageTitle 47 | ) { popToBack() } 48 | } 49 | 50 | override fun initData() { 51 | mSimpleData = initSimpleData(mSimpleData) 52 | val data: MutableList?> = ArrayList() 53 | for (content in mSimpleData) { 54 | val item: MutableMap = HashMap() 55 | val index = content.indexOf("\n") 56 | if (index > 0) { 57 | item[SimpleListAdapter.KEY_TITLE] = content.subSequence(0, index).toString() 58 | item[SimpleListAdapter.KEY_SUB_TITLE] = 59 | content.subSequence(index + 1, content.length).toString() 60 | } else { 61 | item[SimpleListAdapter.KEY_TITLE] = content 62 | item[SimpleListAdapter.KEY_SUB_TITLE] = "" 63 | } 64 | data.add(item) 65 | } 66 | listView.adapter = SimpleListAdapter(context, data) 67 | initSimply() 68 | } 69 | 70 | override fun onItemClick(adapterView: AdapterView<*>?, view: View, position: Int, id: Long) { 71 | onItemClick(view, position) 72 | } 73 | 74 | @SingleClick 75 | private fun onItemClick(view: View, position: Int) { 76 | onItemClick(position) 77 | } 78 | 79 | override fun onDestroyView() { 80 | listView.onItemClickListener = null 81 | super.onDestroyView() 82 | } 83 | 84 | override fun onConfigurationChanged(newConfig: Configuration) { 85 | //屏幕旋转时刷新一下title 86 | super.onConfigurationChanged(newConfig) 87 | val root = rootView as ViewGroup 88 | if (root.getChildAt(0) is TitleBar) { 89 | root.removeViewAt(0) 90 | initTitle() 91 | } 92 | } 93 | 94 | override fun onResume() { 95 | super.onResume() 96 | MobclickAgent.onPageStart(pageName) 97 | } 98 | 99 | override fun onPause() { 100 | super.onPause() 101 | MobclickAgent.onPageEnd(pageName) 102 | } 103 | } -------------------------------------------------------------------------------- /app/src/main/java/com/xuexiang/templateproject/core/SimpleListAdapter.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2019 xuexiangjys(xuexiangjys@163.com) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | package com.xuexiang.templateproject.core 18 | 19 | import android.content.Context 20 | import android.view.View 21 | import android.widget.TextView 22 | import com.xuexiang.templateproject.R 23 | import com.xuexiang.xui.adapter.listview.BaseListAdapter 24 | import com.xuexiang.xutil.common.StringUtils 25 | 26 | /** 27 | * 主副标题显示适配器 28 | * 29 | * @author xuexiang 30 | * @since 2018/12/19 上午12:19 31 | */ 32 | class SimpleListAdapter(context: Context?, data: List?>?) : 33 | BaseListAdapter, SimpleListAdapter.ViewHolder>(context, data) { 34 | override fun newViewHolder(convertView: View): ViewHolder { 35 | val holder = ViewHolder() 36 | holder.mTvTitle = convertView.findViewById(R.id.tv_title) 37 | holder.mTvSubTitle = convertView.findViewById(R.id.tv_sub_title) 38 | return holder 39 | } 40 | 41 | override fun getLayoutId(): Int { 42 | return R.layout.adapter_item_simple_list_2 43 | } 44 | 45 | override fun convert(holder: ViewHolder, item: Map, position: Int) { 46 | holder.mTvTitle?.text = 47 | item[KEY_TITLE] 48 | if (!StringUtils.isEmpty(item[KEY_SUB_TITLE])) { 49 | holder.mTvSubTitle?.text = 50 | item[KEY_SUB_TITLE] 51 | holder.mTvSubTitle?.visibility = View.VISIBLE 52 | } else { 53 | holder.mTvSubTitle?.visibility = View.GONE 54 | } 55 | } 56 | 57 | class ViewHolder { 58 | /** 59 | * 标题 60 | */ 61 | var mTvTitle: TextView? = null 62 | 63 | /** 64 | * 副标题 65 | */ 66 | var mTvSubTitle: TextView? = null 67 | } 68 | 69 | companion object { 70 | const val KEY_TITLE = "key_title" 71 | const val KEY_SUB_TITLE = "key_sub_title" 72 | } 73 | } -------------------------------------------------------------------------------- /app/src/main/java/com/xuexiang/templateproject/core/XPageTransferActivity.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2019 xuexiangjys(xuexiangjys@163.com) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | package com.xuexiang.templateproject.core 18 | 19 | import android.os.Bundle 20 | import androidx.viewbinding.ViewBinding 21 | import com.xuexiang.xrouter.annotation.AutoWired 22 | import com.xuexiang.xrouter.annotation.Router 23 | import com.xuexiang.xrouter.launcher.XRouter 24 | import com.xuexiang.xui.utils.XToastUtils 25 | import com.xuexiang.xutil.common.StringUtils 26 | 27 | /** 28 | * https://xuexiangjys.club/xpage/transfer?pageName=xxxxx&.... 29 | * applink的中转 30 | * 31 | * @author xuexiang 32 | * @since 2019-07-06 9:37 33 | */ 34 | @Router(path = "/xpage/transfer") 35 | class XPageTransferActivity : BaseActivity() { 36 | 37 | @JvmField 38 | @AutoWired(name = "pageName") 39 | var pageName = null 40 | 41 | override fun onCreate(savedInstanceState: Bundle?) { 42 | super.onCreate(savedInstanceState) 43 | XRouter.getInstance().inject(this) 44 | if (!StringUtils.isEmpty(pageName)) { 45 | if (openPage(pageName, intent.extras) == null) { 46 | XToastUtils.error("页面未找到!") 47 | finish() 48 | } 49 | } else { 50 | XToastUtils.error("页面未找到!") 51 | finish() 52 | } 53 | } 54 | } -------------------------------------------------------------------------------- /app/src/main/java/com/xuexiang/templateproject/core/http/api/ApiService.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021 xuexiangjys(xuexiangjys@163.com) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | package com.xuexiang.templateproject.core.http.api 18 | 19 | import com.xuexiang.templateproject.core.http.entity.TipInfo 20 | import com.xuexiang.xhttp2.model.ApiResult 21 | import io.reactivex.Observable 22 | import retrofit2.http.GET 23 | 24 | /** 25 | * @author xuexiang 26 | * @since 2021/1/9 7:01 PM 27 | */ 28 | class ApiService { 29 | /** 30 | * 使用的是retrofit的接口定义 31 | */ 32 | interface IGetService { 33 | /** 34 | * 获得小贴士 35 | */ 36 | @get:GET("/xuexiangjys/Resource/raw/master/jsonapi/tips.json") 37 | val tips: Observable?>> 38 | } 39 | } -------------------------------------------------------------------------------- /app/src/main/java/com/xuexiang/templateproject/core/http/callback/NoTipCallBack.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2019 xuexiangjys(xuexiangjys@163.com) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | package com.xuexiang.templateproject.core.http.callback 18 | 19 | import com.xuexiang.xhttp2.callback.SimpleCallBack 20 | import com.xuexiang.xhttp2.exception.ApiException 21 | import com.xuexiang.xhttp2.model.XHttpRequest 22 | import com.xuexiang.xutil.common.StringUtils 23 | import com.xuexiang.xutil.common.logger.Logger 24 | 25 | /** 26 | * 不带错误提示的网络请求回调 27 | * 28 | * @author xuexiang 29 | * @since 2019-11-18 23:02 30 | */ 31 | abstract class NoTipCallBack : SimpleCallBack { 32 | /** 33 | * 记录一下请求的url,确定出错的请求是哪个请求 34 | */ 35 | private var mUrl: String? = null 36 | 37 | constructor() {} 38 | constructor(req: XHttpRequest) : this(req.url) {} 39 | constructor(url: String?) { 40 | mUrl = url 41 | } 42 | 43 | override fun onError(e: ApiException) { 44 | if (!StringUtils.isEmpty(mUrl)) { 45 | Logger.e("网络请求的url:$mUrl", e) 46 | } else { 47 | Logger.e(e) 48 | } 49 | } 50 | } -------------------------------------------------------------------------------- /app/src/main/java/com/xuexiang/templateproject/core/http/callback/TipCallBack.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2019 xuexiangjys(xuexiangjys@163.com) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | package com.xuexiang.templateproject.core.http.callback 18 | 19 | import com.xuexiang.xhttp2.callback.SimpleCallBack 20 | import com.xuexiang.xhttp2.exception.ApiException 21 | import com.xuexiang.xhttp2.model.XHttpRequest 22 | import com.xuexiang.xui.utils.XToastUtils 23 | import com.xuexiang.xutil.common.StringUtils 24 | import com.xuexiang.xutil.common.logger.Logger 25 | 26 | /** 27 | * 带错误toast提示的网络请求回调 28 | * 29 | * @author xuexiang 30 | * @since 2019-11-18 23:02 31 | */ 32 | abstract class TipCallBack : SimpleCallBack { 33 | /** 34 | * 记录一下请求的url,确定出错的请求是哪个请求 35 | */ 36 | private var mUrl: String? = null 37 | 38 | constructor() {} 39 | constructor(req: XHttpRequest) : this(req.url) {} 40 | constructor(url: String?) { 41 | mUrl = url 42 | } 43 | 44 | override fun onError(e: ApiException) { 45 | XToastUtils.error(e) 46 | if (!StringUtils.isEmpty(mUrl)) { 47 | Logger.e("网络请求的url:$mUrl", e) 48 | } else { 49 | Logger.e(e) 50 | } 51 | } 52 | } -------------------------------------------------------------------------------- /app/src/main/java/com/xuexiang/templateproject/core/http/callback/TipProgressLoadingCallBack.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2019 xuexiangjys(xuexiangjys@163.com) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | package com.xuexiang.templateproject.core.http.callback 18 | 19 | import com.xuexiang.templateproject.core.BaseFragment 20 | import com.xuexiang.xhttp2.callback.ProgressLoadingCallBack 21 | import com.xuexiang.xhttp2.exception.ApiException 22 | import com.xuexiang.xhttp2.model.XHttpRequest 23 | import com.xuexiang.xhttp2.subsciber.impl.IProgressLoader 24 | import com.xuexiang.xui.utils.XToastUtils 25 | import com.xuexiang.xutil.common.StringUtils 26 | import com.xuexiang.xutil.common.logger.Logger 27 | 28 | /** 29 | * 带错误toast提示和加载进度条的网络请求回调 30 | * 31 | * @author xuexiang 32 | * @since 2019-11-18 23:16 33 | */ 34 | abstract class TipProgressLoadingCallBack : ProgressLoadingCallBack { 35 | /** 36 | * 记录一下请求的url,确定出错的请求是哪个请求 37 | */ 38 | private var mUrl: String? = null 39 | 40 | constructor(fragment: BaseFragment<*>) : super(fragment.getProgressLoader()) {} 41 | constructor(iProgressLoader: IProgressLoader?) : super(iProgressLoader) {} 42 | constructor(req: XHttpRequest, iProgressLoader: IProgressLoader?) : this( 43 | req.url, 44 | iProgressLoader 45 | ) { 46 | } 47 | 48 | constructor(url: String?, iProgressLoader: IProgressLoader?) : super(iProgressLoader) { 49 | mUrl = url 50 | } 51 | 52 | override fun onError(e: ApiException) { 53 | super.onError(e) 54 | XToastUtils.error(e) 55 | if (!StringUtils.isEmpty(mUrl)) { 56 | Logger.e("网络请求的url:$mUrl", e) 57 | } else { 58 | Logger.e(e) 59 | } 60 | } 61 | } -------------------------------------------------------------------------------- /app/src/main/java/com/xuexiang/templateproject/core/http/entity/TipInfo.kt: -------------------------------------------------------------------------------- 1 | package com.xuexiang.templateproject.core.http.entity 2 | 3 | import androidx.annotation.Keep 4 | 5 | /** 6 | * @author xuexiang 7 | * @since 2019-08-28 15:35 8 | */ 9 | @Keep 10 | class TipInfo { 11 | /** 12 | * title : 小贴士3 13 | * content : 14 | * 15 | *欢迎关注我的微信公众号:我的Android开源之旅。 16 | * 17 | *

18 | */ 19 | var title: String? = null 20 | var content: String? = null 21 | override fun toString(): String { 22 | return "TipInfo{" + 23 | "title='" + title + '\'' + 24 | ", content='" + content + '\'' + 25 | '}' 26 | } 27 | } -------------------------------------------------------------------------------- /app/src/main/java/com/xuexiang/templateproject/core/http/loader/IProgressLoaderFactory.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2019 xuexiangjys(xuexiangjys@163.com) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | package com.xuexiang.templateproject.core.http.loader 18 | 19 | import android.content.Context 20 | import com.xuexiang.xhttp2.subsciber.impl.IProgressLoader 21 | 22 | /** 23 | * IProgressLoader的创建工厂实现接口 24 | * 25 | * @author xuexiang 26 | * @since 2019-11-18 23:17 27 | */ 28 | interface IProgressLoaderFactory { 29 | /** 30 | * 创建进度加载者 31 | * 32 | * @param context 33 | * @return 34 | */ 35 | fun create(context: Context?): IProgressLoader? 36 | 37 | /** 38 | * 创建进度加载者 39 | * 40 | * @param context 41 | * @param message 默认提示 42 | * @return 43 | */ 44 | fun create(context: Context?, message: String?): IProgressLoader? 45 | } -------------------------------------------------------------------------------- /app/src/main/java/com/xuexiang/templateproject/core/http/loader/MiniLoadingDialogLoader.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2019 xuexiangjys(xuexiangjys@163.com) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | package com.xuexiang.templateproject.core.http.loader 18 | 19 | import android.content.Context 20 | import kotlin.jvm.JvmOverloads 21 | import com.xuexiang.xhttp2.subsciber.impl.IProgressLoader 22 | import com.xuexiang.xui.widget.dialog.MiniLoadingDialog 23 | import com.xuexiang.xhttp2.subsciber.impl.OnProgressCancelListener 24 | import android.content.DialogInterface 25 | 26 | /** 27 | * 默认进度加载 28 | * 29 | * @author xuexiang 30 | * @since 2019-11-18 23:07 31 | */ 32 | class MiniLoadingDialogLoader @JvmOverloads constructor( 33 | context: Context?, 34 | msg: String? = "请求中..." 35 | ) : IProgressLoader { 36 | /** 37 | * 进度loading弹窗 38 | */ 39 | private val mDialog: MiniLoadingDialog? 40 | 41 | /** 42 | * 进度框取消监听 43 | */ 44 | private var mOnProgressCancelListener: OnProgressCancelListener? = null 45 | 46 | override fun isLoading(): Boolean { 47 | return mDialog != null && mDialog.isShowing 48 | } 49 | 50 | override fun updateMessage(msg: String) { 51 | mDialog?.updateMessage(msg) 52 | } 53 | 54 | override fun showLoading() { 55 | if (mDialog != null && !mDialog.isShowing) { 56 | mDialog.show() 57 | } 58 | } 59 | 60 | override fun dismissLoading() { 61 | if (mDialog != null && mDialog.isShowing) { 62 | mDialog.dismiss() 63 | } 64 | } 65 | 66 | override fun setCancelable(flag: Boolean) { 67 | mDialog?.setCancelable(flag) 68 | if (flag) { 69 | mDialog?.setOnCancelListener { 70 | mOnProgressCancelListener?.onCancelProgress() 71 | } 72 | } 73 | } 74 | 75 | override fun setOnProgressCancelListener(listener: OnProgressCancelListener) { 76 | mOnProgressCancelListener = listener 77 | } 78 | 79 | init { 80 | mDialog = MiniLoadingDialog(context, msg) 81 | } 82 | } -------------------------------------------------------------------------------- /app/src/main/java/com/xuexiang/templateproject/core/http/loader/MiniProgressLoaderFactory.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2019 xuexiangjys(xuexiangjys@163.com) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | package com.xuexiang.templateproject.core.http.loader 18 | 19 | import android.content.Context 20 | import com.xuexiang.xhttp2.subsciber.impl.IProgressLoader 21 | 22 | /** 23 | * 迷你加载框创建工厂 24 | * 25 | * @author xuexiang 26 | * @since 2019-11-18 23:23 27 | */ 28 | class MiniProgressLoaderFactory : IProgressLoaderFactory { 29 | 30 | override fun create(context: Context?): IProgressLoader { 31 | return MiniLoadingDialogLoader(context) 32 | } 33 | 34 | override fun create(context: Context?, message: String?): IProgressLoader { 35 | return MiniLoadingDialogLoader(context, message) 36 | } 37 | } -------------------------------------------------------------------------------- /app/src/main/java/com/xuexiang/templateproject/core/http/loader/ProgressLoader.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2019 xuexiangjys(xuexiangjys@163.com) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | package com.xuexiang.templateproject.core.http.loader 18 | 19 | import android.content.Context 20 | import com.xuexiang.xhttp2.subsciber.impl.IProgressLoader 21 | 22 | /** 23 | * 创建进度加载者 24 | * 25 | * @author xuexiang 26 | * @since 2019-07-02 12:51 27 | */ 28 | object ProgressLoader { 29 | 30 | private var sIProgressLoaderFactory: IProgressLoaderFactory = MiniProgressLoaderFactory() 31 | 32 | fun setIProgressLoaderFactory(sIProgressLoaderFactory: IProgressLoaderFactory) { 33 | ProgressLoader.sIProgressLoaderFactory = sIProgressLoaderFactory 34 | } 35 | 36 | /** 37 | * 创建进度加载者 38 | * 39 | * @param context 40 | * @return 41 | */ 42 | fun create(context: Context?): IProgressLoader? { 43 | return sIProgressLoaderFactory.create(context) 44 | } 45 | 46 | /** 47 | * 创建进度加载者 48 | * 49 | * @param context 50 | * @param message 默认提示信息 51 | * @return 52 | */ 53 | fun create(context: Context?, message: String?): IProgressLoader? { 54 | return sIProgressLoaderFactory.create(context, message) 55 | } 56 | } -------------------------------------------------------------------------------- /app/src/main/java/com/xuexiang/templateproject/core/http/subscriber/NoTipRequestSubscriber.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2019 xuexiangjys(xuexiangjys@163.com) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | package com.xuexiang.templateproject.core.http.subscriber 18 | 19 | import com.xuexiang.xhttp2.exception.ApiException 20 | import com.xuexiang.xhttp2.model.XHttpRequest 21 | import com.xuexiang.xhttp2.subsciber.BaseSubscriber 22 | import com.xuexiang.xutil.common.StringUtils 23 | import com.xuexiang.xutil.common.logger.Logger 24 | 25 | /** 26 | * 不带错误toast提示的网络请求订阅,只存储错误的日志 27 | * 28 | * @author xuexiang 29 | * @since 2019-11-18 23:11 30 | */ 31 | abstract class NoTipRequestSubscriber : BaseSubscriber { 32 | /** 33 | * 记录一下请求的url,确定出错的请求是哪个请求 34 | */ 35 | private var mUrl: String? = null 36 | 37 | constructor() 38 | constructor(req: XHttpRequest) : this(req.url) 39 | constructor(url: String?) { 40 | mUrl = url 41 | } 42 | 43 | public override fun onError(e: ApiException) { 44 | if (!StringUtils.isEmpty(mUrl)) { 45 | Logger.e("网络请求的url:$mUrl", e) 46 | } else { 47 | Logger.e(e) 48 | } 49 | } 50 | } -------------------------------------------------------------------------------- /app/src/main/java/com/xuexiang/templateproject/core/http/subscriber/TipProgressLoadingSubscriber.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2019 xuexiangjys(xuexiangjys@163.com) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | package com.xuexiang.templateproject.core.http.subscriber 18 | 19 | import com.xuexiang.templateproject.core.BaseFragment 20 | import com.xuexiang.xhttp2.exception.ApiException 21 | import com.xuexiang.xhttp2.model.XHttpRequest 22 | import com.xuexiang.xhttp2.subsciber.ProgressLoadingSubscriber 23 | import com.xuexiang.xhttp2.subsciber.impl.IProgressLoader 24 | import com.xuexiang.xui.utils.XToastUtils 25 | import com.xuexiang.xutil.common.StringUtils 26 | import com.xuexiang.xutil.common.logger.Logger 27 | 28 | /** 29 | * 带错误toast提示和加载进度条的网络请求订阅 30 | * 31 | * @author xuexiang 32 | * @since 2019-11-18 23:11 33 | */ 34 | abstract class TipProgressLoadingSubscriber : ProgressLoadingSubscriber { 35 | /** 36 | * 记录一下请求的url,确定出错的请求是哪个请求 37 | */ 38 | private var mUrl: String? = null 39 | 40 | constructor() : super() {} 41 | constructor(fragment: BaseFragment<*>) : super(fragment.getProgressLoader()) {} 42 | constructor(iProgressLoader: IProgressLoader?) : super(iProgressLoader) {} 43 | constructor(req: XHttpRequest) : this(req.url) {} 44 | constructor(url: String?) : super() { 45 | mUrl = url 46 | } 47 | 48 | override fun onError(e: ApiException) { 49 | super.onError(e) 50 | XToastUtils.error(e) 51 | if (!StringUtils.isEmpty(mUrl)) { 52 | Logger.e("网络请求的url:$mUrl", e) 53 | } else { 54 | Logger.e(e) 55 | } 56 | } 57 | } -------------------------------------------------------------------------------- /app/src/main/java/com/xuexiang/templateproject/core/http/subscriber/TipRequestSubscriber.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2019 xuexiangjys(xuexiangjys@163.com) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | package com.xuexiang.templateproject.core.http.subscriber 18 | 19 | import com.xuexiang.xhttp2.exception.ApiException 20 | import com.xuexiang.xhttp2.model.XHttpRequest 21 | import com.xuexiang.xhttp2.subsciber.BaseSubscriber 22 | import com.xuexiang.xui.utils.XToastUtils 23 | import com.xuexiang.xutil.common.StringUtils 24 | import com.xuexiang.xutil.common.logger.Logger 25 | 26 | /** 27 | * 带错误toast提示的网络请求订阅 28 | * 29 | * @author xuexiang 30 | * @since 2019-11-18 23:10 31 | */ 32 | abstract class TipRequestSubscriber : BaseSubscriber { 33 | /** 34 | * 记录一下请求的url,确定出错的请求是哪个请求 35 | */ 36 | private var mUrl: String? = null 37 | 38 | constructor() {} 39 | constructor(req: XHttpRequest) : this(req.url) {} 40 | constructor(url: String?) { 41 | mUrl = url 42 | } 43 | 44 | public override fun onError(e: ApiException) { 45 | XToastUtils.error(e) 46 | if (!StringUtils.isEmpty(mUrl)) { 47 | Logger.e("网络请求的url:$mUrl", e) 48 | } else { 49 | Logger.e(e) 50 | } 51 | } 52 | } -------------------------------------------------------------------------------- /app/src/main/java/com/xuexiang/templateproject/core/webview/AgentWebActivity.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2019 xuexiangjys(xuexiangjys@163.com) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | package com.xuexiang.templateproject.core.webview 18 | 19 | import android.content.Context 20 | import android.content.Intent 21 | import android.os.Bundle 22 | import android.view.KeyEvent 23 | import androidx.appcompat.app.AppCompatActivity 24 | import com.xuexiang.templateproject.R 25 | import com.xuexiang.xrouter.facade.Postcard 26 | import com.xuexiang.xrouter.facade.callback.NavCallback 27 | import com.xuexiang.xrouter.launcher.XRouter 28 | import com.xuexiang.xui.utils.XToastUtils 29 | import com.xuexiang.xui.widget.slideback.SlideBack 30 | 31 | /** 32 | * 壳浏览器 33 | * 34 | * @author xuexiang 35 | * @since 2019/1/5 上午12:15 36 | */ 37 | class AgentWebActivity : AppCompatActivity() { 38 | override fun onCreate(savedInstanceState: Bundle?) { 39 | super.onCreate(savedInstanceState) 40 | setContentView(R.layout.activity_agent_web) 41 | SlideBack.with(this) 42 | .haveScroll(true) 43 | .callBack { finish() } 44 | .register() 45 | val uri = intent.data 46 | if (uri != null) { 47 | XRouter.getInstance().build(uri).navigation(this, object : NavCallback() { 48 | override fun onArrival(postcard: Postcard) { 49 | finish() 50 | } 51 | 52 | override fun onLost(postcard: Postcard) { 53 | loadUrl(uri.toString()) 54 | } 55 | }) 56 | } else { 57 | val url = intent.getStringExtra(AgentWebFragment.KEY_URL) 58 | loadUrl(url) 59 | } 60 | } 61 | 62 | private fun loadUrl(url: String?) { 63 | if (url != null) { 64 | openFragment(url) 65 | } else { 66 | XToastUtils.error("数据出错!") 67 | finish() 68 | } 69 | } 70 | 71 | private var mAgentWebFragment: AgentWebFragment? = null 72 | private fun openFragment(url: String) { 73 | val ft = supportFragmentManager.beginTransaction() 74 | ft.add( 75 | R.id.container_frame_layout, 76 | AgentWebFragment.getInstance(url).also { mAgentWebFragment = it }) 77 | ft.commit() 78 | } 79 | 80 | override fun onKeyDown(keyCode: Int, event: KeyEvent): Boolean { 81 | val agentWebFragment = mAgentWebFragment 82 | return if (agentWebFragment != null) { 83 | if ((agentWebFragment as FragmentKeyDown).onFragmentKeyDown(keyCode, event)) { 84 | true 85 | } else { 86 | super.onKeyDown(keyCode, event) 87 | } 88 | } else super.onKeyDown(keyCode, event) 89 | } 90 | 91 | override fun onDestroy() { 92 | SlideBack.unregister(this) 93 | super.onDestroy() 94 | } 95 | 96 | companion object { 97 | /** 98 | * 请求浏览器 99 | * 100 | * @param url 101 | */ 102 | fun goWeb(context: Context?, url: String?) { 103 | val intent = Intent(context, AgentWebActivity::class.java) 104 | intent.putExtra(AgentWebFragment.KEY_URL, url) 105 | context?.startActivity(intent) 106 | } 107 | } 108 | } -------------------------------------------------------------------------------- /app/src/main/java/com/xuexiang/templateproject/core/webview/BaseWebViewFragment.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2019 xuexiangjys(xuexiangjys@163.com) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | package com.xuexiang.templateproject.core.webview 18 | 19 | import android.view.KeyEvent 20 | import androidx.viewbinding.ViewBinding 21 | import com.just.agentweb.core.AgentWeb 22 | import com.xuexiang.templateproject.core.BaseFragment 23 | 24 | /** 25 | * 基础web 26 | * 27 | * @author xuexiang 28 | * @since 2019/5/28 10:22 29 | */ 30 | abstract class BaseWebViewFragment : BaseFragment() { 31 | 32 | protected var mAgentWeb: AgentWeb? = null 33 | 34 | //===================生命周期管理===========================// 35 | override fun onResume() { 36 | mAgentWeb?.webLifeCycle?.onResume() 37 | super.onResume() 38 | } 39 | 40 | override fun onPause() { 41 | //暂停应用内所有WebView , 调用mWebView.resumeTimers();/mAgentWeb.getWebLifeCycle().onResume(); 恢复。 42 | mAgentWeb?.webLifeCycle?.onPause() 43 | super.onPause() 44 | } 45 | 46 | override fun onKeyDown(keyCode: Int, event: KeyEvent): Boolean { 47 | return mAgentWeb?.handleKeyEvent(keyCode, event) ?: false 48 | } 49 | 50 | override fun onDestroyView() { 51 | mAgentWeb?.destroy() 52 | super.onDestroyView() 53 | } 54 | } -------------------------------------------------------------------------------- /app/src/main/java/com/xuexiang/templateproject/core/webview/FragmentKeyDown.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2019 xuexiangjys(xuexiangjys@163.com) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | package com.xuexiang.templateproject.core.webview 18 | 19 | import android.view.KeyEvent 20 | 21 | /** 22 | * 23 | * 24 | * @author xuexiang 25 | * @since 2019/1/4 下午11:32 26 | */ 27 | interface FragmentKeyDown { 28 | /** 29 | * fragment按键监听 30 | * @param keyCode 31 | * @param event 32 | * @return 33 | */ 34 | fun onFragmentKeyDown(keyCode: Int, event: KeyEvent?): Boolean 35 | } -------------------------------------------------------------------------------- /app/src/main/java/com/xuexiang/templateproject/core/webview/LollipopFixedWebView.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2019 xuexiangjys(xuexiangjys@163.com) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | package com.xuexiang.templateproject.core.webview 18 | 19 | import android.annotation.TargetApi 20 | import android.content.Context 21 | import android.content.res.Configuration 22 | import android.os.Build 23 | import android.util.AttributeSet 24 | import android.webkit.WebView 25 | 26 | /** 27 | * 修复 Android 5.0 & 5.1 打开 WebView 闪退问题: 28 | * 参阅 https://stackoverflow.com/questions/41025200/android-view-inflateexception-error-inflating-class-android-webkit-webview 29 | */ 30 | class LollipopFixedWebView : WebView { 31 | constructor(context: Context) : super(getFixedContext(context)) {} 32 | constructor(context: Context, attrs: AttributeSet?) : super(getFixedContext(context), attrs) {} 33 | constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super( 34 | getFixedContext(context), attrs, defStyleAttr 35 | ) { 36 | } 37 | 38 | @TargetApi(Build.VERSION_CODES.LOLLIPOP) 39 | constructor( 40 | context: Context, 41 | attrs: AttributeSet?, 42 | defStyleAttr: Int, 43 | defStyleRes: Int 44 | ) : super( 45 | getFixedContext(context), attrs, defStyleAttr, defStyleRes 46 | ) { 47 | } 48 | 49 | constructor( 50 | context: Context, 51 | attrs: AttributeSet?, 52 | defStyleAttr: Int, 53 | privateBrowsing: Boolean 54 | ) : super( 55 | getFixedContext(context), attrs, defStyleAttr, privateBrowsing 56 | ) { 57 | } 58 | 59 | companion object { 60 | fun getFixedContext(context: Context): Context { 61 | return if (isLollipopWebViewBug) { 62 | // Avoid crashing on Android 5 and 6 (API level 21 to 23) 63 | context.createConfigurationContext(Configuration()) 64 | } else context 65 | } 66 | 67 | val isLollipopWebViewBug: Boolean 68 | get() = Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && Build.VERSION.SDK_INT < Build.VERSION_CODES.M 69 | } 70 | } -------------------------------------------------------------------------------- /app/src/main/java/com/xuexiang/templateproject/core/webview/MiddlewareChromeClient.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2019 xuexiangjys(xuexiangjys@163.com) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | package com.xuexiang.templateproject.core.webview 18 | 19 | import android.util.Log 20 | import com.just.agentweb.core.client.MiddlewareWebChromeBase 21 | import android.webkit.WebView 22 | import android.webkit.JsResult 23 | 24 | /** 25 | * WebChrome(WebChromeClient主要辅助WebView处理JavaScript的对话框、网站图片、网站title、加载进度等)中间件 26 | * 【浏览器】 27 | * @author xuexiang 28 | * @since 2019/1/4 下午11:31 29 | */ 30 | open class MiddlewareChromeClient : MiddlewareWebChromeBase() { 31 | override fun onJsAlert(view: WebView, url: String, message: String, result: JsResult): Boolean { 32 | Log.i("Info", "onJsAlert:$url") 33 | return super.onJsAlert(view, url, message, result) 34 | } 35 | 36 | override fun onProgressChanged(view: WebView, newProgress: Int) { 37 | super.onProgressChanged(view, newProgress) 38 | Log.i("Info", "onProgressChanged:") 39 | } 40 | } -------------------------------------------------------------------------------- /app/src/main/java/com/xuexiang/templateproject/core/webview/UIController.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2019 xuexiangjys(xuexiangjys@163.com) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | package com.xuexiang.templateproject.core.webview 18 | 19 | import android.app.Activity 20 | import android.os.Handler 21 | import android.util.Log 22 | import com.just.agentweb.core.web.AgentWebUIControllerImplBase 23 | import android.webkit.WebView 24 | import java.lang.ref.WeakReference 25 | 26 | /** 27 | * 如果你需要修改某一个AgentWeb 内部的某一个弹窗 ,请看下面的例子 28 | * 注意写法一定要参照 DefaultUIController 的写法 ,因为UI自由定制,但是回调的方式是固定的,并且一定要回调。 29 | * 30 | * @author xuexiang 31 | * @since 2019-10-30 23:18 32 | */ 33 | class UIController(activity: Activity) : AgentWebUIControllerImplBase() { 34 | private val mActivity: WeakReference 35 | override fun onShowMessage(message: String, from: String) { 36 | super.onShowMessage(message, from) 37 | Log.i(TAG, "message:$message") 38 | } 39 | 40 | override fun onSelectItemsPrompt( 41 | view: WebView, 42 | url: String, 43 | items: Array, 44 | callback: Handler.Callback 45 | ) { 46 | // 使用默认的UI 47 | super.onSelectItemsPrompt(view, url, items, callback) 48 | } 49 | 50 | init { 51 | mActivity = WeakReference(activity) 52 | } 53 | } -------------------------------------------------------------------------------- /app/src/main/java/com/xuexiang/templateproject/core/webview/WebLayout.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2019 xuexiangjys(xuexiangjys@163.com) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | package com.xuexiang.templateproject.core.webview 18 | 19 | import android.app.Activity 20 | import android.view.LayoutInflater 21 | import android.view.ViewGroup 22 | import android.webkit.WebView 23 | import com.just.agentweb.widget.IWebLayout 24 | import com.scwang.smart.refresh.layout.SmartRefreshLayout 25 | import com.xuexiang.templateproject.R 26 | 27 | /** 28 | * 定义支持下来回弹的WebView 29 | * 30 | * @author xuexiang 31 | * @since 2019/1/5 上午2:01 32 | */ 33 | class WebLayout(activity: Activity?) : IWebLayout { 34 | private val mSmartRefreshLayout: SmartRefreshLayout 35 | private val mWebView: WebView 36 | override fun getLayout(): ViewGroup { 37 | return mSmartRefreshLayout 38 | } 39 | 40 | override fun getWebView(): WebView { 41 | return mWebView 42 | } 43 | 44 | init { 45 | mSmartRefreshLayout = LayoutInflater.from(activity) 46 | .inflate(R.layout.fragment_pulldown_web, null) as SmartRefreshLayout 47 | mWebView = mSmartRefreshLayout.findViewById(R.id.webView) 48 | } 49 | } -------------------------------------------------------------------------------- /app/src/main/java/com/xuexiang/templateproject/fragment/news/GridItemFragment.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021 xuexiangjys(xuexiangjys@163.com) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | package com.xuexiang.templateproject.fragment.news 18 | 19 | import android.view.LayoutInflater 20 | import android.view.ViewGroup 21 | import com.xuexiang.templateproject.core.BaseFragment 22 | import com.xuexiang.templateproject.databinding.FragmentGridItemBinding 23 | import com.xuexiang.xpage.annotation.Page 24 | import com.xuexiang.xrouter.annotation.AutoWired 25 | import com.xuexiang.xrouter.launcher.XRouter 26 | 27 | /** 28 | * @author xuexiang 29 | * @since 2021/6/30 1:21 AM 30 | */ 31 | @Page 32 | class GridItemFragment : BaseFragment() { 33 | /** 34 | * 自动注入参数,不能是private 35 | */ 36 | @JvmField 37 | @AutoWired(name = KEY_TITLE_NAME) 38 | var title: String? = null 39 | 40 | override fun viewBindingInflate( 41 | inflater: LayoutInflater, 42 | container: ViewGroup?, 43 | attachToRoot: Boolean 44 | ): FragmentGridItemBinding { 45 | return FragmentGridItemBinding.inflate(inflater, container, attachToRoot) 46 | } 47 | 48 | override fun initArgs() { 49 | // 自动注入参数必须在initArgs里进行注入 50 | XRouter.getInstance().inject(this) 51 | } 52 | 53 | override fun getPageTitle(): String? { 54 | return title 55 | } 56 | 57 | override fun initViews() {} 58 | 59 | companion object { 60 | const val KEY_TITLE_NAME = "title_name" 61 | } 62 | } -------------------------------------------------------------------------------- /app/src/main/java/com/xuexiang/templateproject/fragment/other/AboutFragment.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021 xuexiangjys(xuexiangjys@163.com) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | package com.xuexiang.templateproject.fragment.other 18 | 19 | import android.view.LayoutInflater 20 | import android.view.ViewGroup 21 | import com.xuexiang.templateproject.R 22 | import com.xuexiang.templateproject.core.BaseFragment 23 | import com.xuexiang.templateproject.core.webview.AgentWebActivity 24 | import com.xuexiang.templateproject.databinding.FragmentAboutBinding 25 | import com.xuexiang.templateproject.utils.Utils.gotoProtocol 26 | import com.xuexiang.xpage.annotation.Page 27 | import com.xuexiang.xui.widget.grouplist.XUIGroupListView 28 | import com.xuexiang.xutil.app.AppUtils 29 | import java.text.SimpleDateFormat 30 | import java.util.* 31 | 32 | /** 33 | * @author xuexiang 34 | * @since 2019-10-30 00:02 35 | */ 36 | @Page(name = "关于") 37 | class AboutFragment : BaseFragment() { 38 | 39 | override fun initViews() { 40 | binding?.tvVersion?.text = String.format("版本号:%s", AppUtils.getAppVersionName()) 41 | XUIGroupListView.newSection(context) 42 | .addItemView(binding?.aboutList?.createItemView(resources.getString(R.string.about_item_homepage))) { 43 | AgentWebActivity.goWeb( 44 | context, getString(R.string.url_project_github) 45 | ) 46 | } 47 | .addItemView(binding?.aboutList?.createItemView(resources.getString(R.string.about_item_author_github))) { 48 | AgentWebActivity.goWeb( 49 | context, getString(R.string.url_author_github) 50 | ) 51 | } 52 | .addItemView(binding?.aboutList?.createItemView(resources.getString(R.string.about_item_donation_link))) { 53 | AgentWebActivity.goWeb( 54 | context, getString(R.string.url_donation_link) 55 | ) 56 | } 57 | .addItemView(binding?.aboutList?.createItemView(resources.getString(R.string.about_item_add_qq_group))) { 58 | AgentWebActivity.goWeb( 59 | context, getString(R.string.url_add_qq_group) 60 | ) 61 | } 62 | .addItemView(binding?.aboutList?.createItemView(resources.getString(R.string.title_user_protocol))) { 63 | gotoProtocol( 64 | this, 65 | isPrivacy = false, 66 | isImmersive = false 67 | ) 68 | } 69 | .addItemView(binding?.aboutList?.createItemView(resources.getString(R.string.title_privacy_protocol))) { 70 | gotoProtocol( 71 | this, 72 | isPrivacy = true, 73 | isImmersive = false 74 | ) 75 | } 76 | .addTo(binding?.aboutList) 77 | val dateFormat = SimpleDateFormat("yyyy", Locale.CHINA) 78 | val currentYear = dateFormat.format(Date()) 79 | binding?.tvCopyright?.text = 80 | String.format(resources.getString(R.string.about_copyright), currentYear) 81 | } 82 | 83 | override fun viewBindingInflate( 84 | inflater: LayoutInflater, 85 | container: ViewGroup?, 86 | attachToRoot: Boolean 87 | ): FragmentAboutBinding { 88 | return FragmentAboutBinding.inflate(inflater, container, attachToRoot) 89 | } 90 | } -------------------------------------------------------------------------------- /app/src/main/java/com/xuexiang/templateproject/fragment/other/ServiceProtocolFragment.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021 xuexiangjys(xuexiangjys@163.com) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | package com.xuexiang.templateproject.fragment.other 18 | 19 | import android.view.LayoutInflater 20 | import android.view.ViewGroup 21 | import com.xuexiang.templateproject.R 22 | import com.xuexiang.templateproject.core.BaseFragment 23 | import com.xuexiang.templateproject.databinding.FragmentServiceProtocolBinding 24 | import com.xuexiang.xaop.annotation.MemoryCache 25 | import com.xuexiang.xpage.annotation.Page 26 | import com.xuexiang.xrouter.annotation.AutoWired 27 | import com.xuexiang.xrouter.launcher.XRouter 28 | import com.xuexiang.xui.widget.actionbar.TitleBar 29 | import com.xuexiang.xutil.resource.ResUtils 30 | import com.xuexiang.xutil.resource.ResourceUtils 31 | 32 | /** 33 | * 服务协议【本地加载】 34 | * 35 | * @author xuexiang 36 | * @since 2021/5/18 1:35 AM 37 | */ 38 | @Page 39 | class ServiceProtocolFragment : BaseFragment() { 40 | @JvmField 41 | @AutoWired(name = KEY_PROTOCOL_TITLE) 42 | var title: String? = null 43 | 44 | @JvmField 45 | @AutoWired(name = KEY_IS_IMMERSIVE) 46 | var isImmersive = false 47 | override fun initArgs() { 48 | XRouter.getInstance().inject(this) 49 | } 50 | 51 | override fun viewBindingInflate( 52 | inflater: LayoutInflater, 53 | container: ViewGroup?, 54 | attachToRoot: Boolean 55 | ): FragmentServiceProtocolBinding { 56 | return FragmentServiceProtocolBinding.inflate(inflater, container, attachToRoot) 57 | } 58 | 59 | override fun initTitle(): TitleBar? { 60 | return super.initTitle()?.setTitle(title)?.setImmersive(isImmersive) 61 | } 62 | 63 | /** 64 | * 初始化控件 65 | */ 66 | override fun initViews() { 67 | if (title == ResUtils.getString(R.string.title_user_protocol)) { 68 | binding?.tvProtocolText?.text = accountProtocol 69 | } else { 70 | binding?.tvProtocolText?.text = privacyProtocol 71 | } 72 | } 73 | 74 | @get:MemoryCache("account_protocol") 75 | private val accountProtocol: String 76 | get() = ResourceUtils.readStringFromAssert(ACCOUNT_PROTOCOL_ASSET_PATH) 77 | 78 | @get:MemoryCache("privacy_protocol") 79 | private val privacyProtocol: String 80 | get() = ResourceUtils.readStringFromAssert(PRIVACY_PROTOCOL_ASSET_PATH) 81 | 82 | companion object { 83 | const val KEY_PROTOCOL_TITLE = "key_protocol_title" 84 | const val KEY_IS_IMMERSIVE = "key_is_immersive" 85 | 86 | /** 87 | * 用户协议asset本地保存路径 88 | */ 89 | private const val ACCOUNT_PROTOCOL_ASSET_PATH = "protocol/account_protocol.txt" 90 | 91 | /** 92 | * 隐私政策asset本地保存路径 93 | */ 94 | private const val PRIVACY_PROTOCOL_ASSET_PATH = "protocol/privacy_protocol.txt" 95 | } 96 | } -------------------------------------------------------------------------------- /app/src/main/java/com/xuexiang/templateproject/fragment/other/SettingsFragment.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021 xuexiangjys(xuexiangjys@163.com) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | package com.xuexiang.templateproject.fragment.other 18 | 19 | import android.content.DialogInterface 20 | import android.view.LayoutInflater 21 | import android.view.ViewGroup 22 | import com.xuexiang.templateproject.R 23 | import com.xuexiang.templateproject.core.BaseFragment 24 | import com.xuexiang.templateproject.databinding.FragmentSettingsBinding 25 | import com.xuexiang.templateproject.utils.TokenUtils.handleLogoutSuccess 26 | import com.xuexiang.xaop.annotation.SingleClick 27 | import com.xuexiang.xpage.annotation.Page 28 | import com.xuexiang.xui.utils.XToastUtils 29 | import com.xuexiang.xui.widget.dialog.DialogLoader 30 | import com.xuexiang.xui.widget.textview.supertextview.SuperTextView 31 | import com.xuexiang.xui.widget.textview.supertextview.SuperTextView.OnSuperTextViewClickListener 32 | import com.xuexiang.xutil.XUtil 33 | 34 | /** 35 | * @author xuexiang 36 | * @since 2019-10-15 22:38 37 | */ 38 | @Page(name = "设置") 39 | class SettingsFragment : BaseFragment(), OnSuperTextViewClickListener { 40 | 41 | override fun viewBindingInflate( 42 | inflater: LayoutInflater, 43 | container: ViewGroup?, 44 | attachToRoot: Boolean 45 | ): FragmentSettingsBinding { 46 | return FragmentSettingsBinding.inflate(inflater, container, attachToRoot) 47 | } 48 | 49 | override fun initViews() { 50 | binding?.menuCommon?.setOnSuperTextViewClickListener(this) 51 | binding?.menuPrivacy?.setOnSuperTextViewClickListener(this) 52 | binding?.menuPush?.setOnSuperTextViewClickListener(this) 53 | binding?.menuHelper?.setOnSuperTextViewClickListener(this) 54 | binding?.menuChangeAccount?.setOnSuperTextViewClickListener(this) 55 | binding?.menuLogout?.setOnSuperTextViewClickListener(this) 56 | } 57 | 58 | @SingleClick 59 | override fun onClick(superTextView: SuperTextView) { 60 | val id = superTextView.id 61 | if (id == R.id.menu_common || id == R.id.menu_privacy || id == R.id.menu_push || id == R.id.menu_helper) { 62 | XToastUtils.toast(superTextView.leftString) 63 | } else if (id == R.id.menu_change_account) { 64 | XToastUtils.toast(superTextView.centerString) 65 | } else if (id == R.id.menu_logout) { 66 | DialogLoader.getInstance().showConfirmDialog( 67 | context, 68 | getString(R.string.lab_logout_confirm), 69 | getString(R.string.lab_yes), 70 | { dialog: DialogInterface, _: Int -> 71 | dialog.dismiss() 72 | XUtil.getActivityLifecycleHelper().exit() 73 | handleLogoutSuccess() 74 | }, 75 | getString(R.string.lab_no) 76 | ) { dialog: DialogInterface, _: Int -> dialog.dismiss() } 77 | } 78 | } 79 | } -------------------------------------------------------------------------------- /app/src/main/java/com/xuexiang/templateproject/fragment/profile/ProfileFragment.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2019 xuexiangjys(xuexiangjys@163.com) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | package com.xuexiang.templateproject.fragment.profile 18 | 19 | import android.view.LayoutInflater 20 | import android.view.ViewGroup 21 | import com.xuexiang.templateproject.R 22 | import com.xuexiang.templateproject.core.BaseFragment 23 | import com.xuexiang.templateproject.databinding.FragmentProfileBinding 24 | import com.xuexiang.templateproject.fragment.other.AboutFragment 25 | import com.xuexiang.templateproject.fragment.other.SettingsFragment 26 | import com.xuexiang.xaop.annotation.SingleClick 27 | import com.xuexiang.xpage.annotation.Page 28 | import com.xuexiang.xpage.enums.CoreAnim 29 | import com.xuexiang.xui.widget.actionbar.TitleBar 30 | import com.xuexiang.xui.widget.textview.supertextview.SuperTextView 31 | import com.xuexiang.xui.widget.textview.supertextview.SuperTextView.OnSuperTextViewClickListener 32 | 33 | /** 34 | * @author xuexiang 35 | * @since 2019-10-30 00:18 36 | */ 37 | @Page(anim = CoreAnim.none) 38 | class ProfileFragment : BaseFragment(), OnSuperTextViewClickListener { 39 | 40 | override fun viewBindingInflate( 41 | inflater: LayoutInflater, 42 | container: ViewGroup?, 43 | attachToRoot: Boolean 44 | ): FragmentProfileBinding { 45 | return FragmentProfileBinding.inflate(inflater, container, attachToRoot) 46 | } 47 | 48 | /** 49 | * @return 返回为 null意为不需要导航栏 50 | */ 51 | override fun initTitle(): TitleBar? { 52 | return null 53 | } 54 | 55 | /** 56 | * 初始化控件 57 | */ 58 | override fun initViews() {} 59 | 60 | override fun initListeners() { 61 | binding?.menuSettings?.setOnSuperTextViewClickListener(this) 62 | binding?.menuAbout?.setOnSuperTextViewClickListener(this) 63 | } 64 | 65 | @SingleClick 66 | override fun onClick(view: SuperTextView) { 67 | val id = view.id 68 | if (id == R.id.menu_settings) { 69 | openNewPage(SettingsFragment::class.java) 70 | } else if (id == R.id.menu_about) { 71 | openNewPage(AboutFragment::class.java) 72 | } 73 | } 74 | } -------------------------------------------------------------------------------- /app/src/main/java/com/xuexiang/templateproject/fragment/trending/TrendingFragment.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2019 xuexiangjys(xuexiangjys@163.com) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | package com.xuexiang.templateproject.fragment.trending 18 | 19 | import android.view.LayoutInflater 20 | import android.view.ViewGroup 21 | import com.xuexiang.templateproject.core.BaseFragment 22 | import com.xuexiang.templateproject.databinding.FragmentTrendingBinding 23 | import com.xuexiang.xpage.annotation.Page 24 | import com.xuexiang.xpage.enums.CoreAnim 25 | import com.xuexiang.xui.widget.actionbar.TitleBar 26 | 27 | /** 28 | * @author xuexiang 29 | * @since 2019-10-30 00:19 30 | */ 31 | @Page(anim = CoreAnim.none) 32 | class TrendingFragment : BaseFragment() { 33 | 34 | override fun viewBindingInflate( 35 | inflater: LayoutInflater, 36 | container: ViewGroup?, 37 | attachToRoot: Boolean 38 | ): FragmentTrendingBinding { 39 | return FragmentTrendingBinding.inflate(inflater, container, attachToRoot) 40 | } 41 | 42 | /** 43 | * @return 返回为 null意为不需要导航栏 44 | */ 45 | override fun initTitle(): TitleBar? { 46 | return null 47 | } 48 | 49 | /** 50 | * 初始化控件 51 | */ 52 | override fun initViews() {} 53 | } -------------------------------------------------------------------------------- /app/src/main/java/com/xuexiang/templateproject/utils/SettingUtils.kt: -------------------------------------------------------------------------------- 1 | package com.xuexiang.templateproject.utils 2 | 3 | /** 4 | * SharedPreferences管理工具基类 5 | * 6 | * @author xuexiang 7 | * @since 2018/11/27 下午5:16 8 | */ 9 | object SettingUtils { 10 | private const val IS_FIRST_OPEN_KEY = "is_first_open_key" 11 | private const val IS_AGREE_PRIVACY_KEY = "is_agree_privacy_key" 12 | /** 13 | * 是否是第一次启动 14 | */ 15 | /** 16 | * 设置是否是第一次启动 17 | */ 18 | var isFirstOpen: Boolean 19 | get() = MMKVUtils.getBoolean(IS_FIRST_OPEN_KEY, true) 20 | set(isFirstOpen) { 21 | MMKVUtils.put(IS_FIRST_OPEN_KEY, isFirstOpen) 22 | } 23 | /** 24 | * 获取是否同意隐私政策 25 | * 26 | * @return 是否同意隐私政策 27 | */ 28 | /** 29 | * 设置是否同意隐私政策 30 | * 31 | * @param isAgreePrivacy 是否同意隐私政策 32 | */ 33 | @JvmStatic 34 | var isAgreePrivacy: Boolean 35 | get() = MMKVUtils.getBoolean(IS_AGREE_PRIVACY_KEY, false) 36 | set(isAgreePrivacy) { 37 | MMKVUtils.put(IS_AGREE_PRIVACY_KEY, isAgreePrivacy) 38 | } 39 | } -------------------------------------------------------------------------------- /app/src/main/java/com/xuexiang/templateproject/utils/TokenUtils.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2019 xuexiangjys(xuexiangjys@163.com) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | package com.xuexiang.templateproject.utils 18 | 19 | import android.content.Context 20 | import com.umeng.analytics.MobclickAgent 21 | import com.xuexiang.templateproject.activity.LoginActivity 22 | import com.xuexiang.xui.utils.XToastUtils 23 | import com.xuexiang.xutil.app.ActivityUtils 24 | import com.xuexiang.xutil.common.StringUtils 25 | 26 | /** 27 | * Token管理工具 28 | * 29 | * @author xuexiang 30 | * @since 2019-11-17 22:37 31 | */ 32 | object TokenUtils { 33 | private var sToken: String? = null 34 | private const val KEY_TOKEN = "com.xuexiang.templateproject.utils.KEY_TOKEN" 35 | private const val KEY_PROFILE_CHANNEL = "github" 36 | 37 | /** 38 | * 初始化Token信息 39 | */ 40 | @JvmStatic 41 | fun init(context: Context) { 42 | MMKVUtils.init(context) 43 | sToken = MMKVUtils.getString(KEY_TOKEN, "") 44 | } 45 | 46 | fun clearToken() { 47 | sToken = null 48 | MMKVUtils.remove(KEY_TOKEN) 49 | } 50 | 51 | var token: String? 52 | get() = sToken 53 | set(token) { 54 | sToken = token 55 | MMKVUtils.put(KEY_TOKEN, token) 56 | } 57 | 58 | @JvmStatic 59 | fun hasToken(): Boolean { 60 | return MMKVUtils.containsKey(KEY_TOKEN) 61 | } 62 | 63 | /** 64 | * 处理登录成功的事件 65 | * 66 | * @param loginToken 账户信息 67 | */ 68 | @JvmStatic 69 | fun handleLoginSuccess(loginToken: String?): Boolean { 70 | return if (!StringUtils.isEmpty(loginToken)) { 71 | XToastUtils.success("登录成功!") 72 | MobclickAgent.onProfileSignIn(KEY_PROFILE_CHANNEL, token) 73 | token = loginToken 74 | true 75 | } else { 76 | XToastUtils.error("登录失败!") 77 | false 78 | } 79 | } 80 | 81 | /** 82 | * 处理登出的事件 83 | */ 84 | @JvmStatic 85 | fun handleLogoutSuccess() { 86 | MobclickAgent.onProfileSignOff() 87 | //登出时,清除账号信息 88 | clearToken() 89 | XToastUtils.success("登出成功!") 90 | SettingUtils.isAgreePrivacy = false 91 | //跳转到登录页 92 | ActivityUtils.startActivity(LoginActivity::class.java) 93 | } 94 | } -------------------------------------------------------------------------------- /app/src/main/java/com/xuexiang/templateproject/utils/sdkinit/ANRWatchDogInit.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 xuexiangjys(xuexiangjys@163.com) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | package com.xuexiang.templateproject.utils.sdkinit 18 | 19 | import com.github.anrwatchdog.ANRError 20 | import com.github.anrwatchdog.ANRWatchDog 21 | import com.github.anrwatchdog.ANRWatchDog.ANRListener 22 | import com.xuexiang.xutil.common.logger.Logger 23 | 24 | /** 25 | * ANR看门狗监听器初始化 26 | * 27 | * @author xuexiang 28 | * @since 2020-02-18 15:08 29 | */ 30 | object ANRWatchDogInit { 31 | private const val TAG = "ANRWatchDog" 32 | 33 | /** 34 | * ANR看门狗 35 | */ 36 | private var mANRWatchDog: ANRWatchDog? = null 37 | 38 | /** 39 | * ANR监听触发的时间 40 | */ 41 | private const val ANR_DURATION = 4000 42 | 43 | /** 44 | * ANR静默处理【就是不处理,直接记录一下日志】 45 | */ 46 | private val SILENT_LISTENER = ANRListener { error: ANRError? -> Logger.eTag(TAG, error) } 47 | 48 | /** 49 | * ANR自定义处理【可以是记录日志用于上传】 50 | */ 51 | private val CUSTOM_LISTENER = ANRListener { error: ANRError -> 52 | Logger.eTag(TAG, "Detected Application Not Responding!", error) 53 | throw error 54 | } 55 | 56 | fun init() { 57 | //这里设置监听的间隔为2秒 58 | mANRWatchDog = ANRWatchDog(2000) 59 | mANRWatchDog?.setANRInterceptor { duration: Long -> 60 | val ret = ANR_DURATION - duration 61 | if (ret > 0) { 62 | Logger.wTag( 63 | TAG, 64 | "Intercepted ANR that is too short ($duration ms), postponing for $ret ms." 65 | ) 66 | } 67 | ret 68 | }?.setANRListener(SILENT_LISTENER)?.start() 69 | } 70 | } -------------------------------------------------------------------------------- /app/src/main/java/com/xuexiang/templateproject/utils/sdkinit/UMengInit.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2019 xuexiangjys(xuexiangjys@163.com) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | package com.xuexiang.templateproject.utils.sdkinit 18 | 19 | import android.app.Application 20 | import android.content.Context 21 | import com.meituan.android.walle.WalleChannelReader 22 | import com.umeng.analytics.MobclickAgent 23 | import com.umeng.commonsdk.UMConfigure 24 | import com.xuexiang.templateproject.BuildConfig 25 | import com.xuexiang.templateproject.MyApp 26 | import com.xuexiang.templateproject.utils.SettingUtils.isAgreePrivacy 27 | import com.xuexiang.xui.XUI 28 | 29 | /** 30 | * UMeng 统计 SDK初始化 31 | * 32 | * @author xuexiang 33 | * @since 2019-06-18 15:49 34 | */ 35 | object UMengInit { 36 | private const val DEFAULT_CHANNEL_ID = "github" 37 | /** 38 | * 初始化SDK,合规指南【先进行预初始化,如果用户隐私同意后可以初始化UmengSDK进行信息上报】 39 | */ 40 | /** 41 | * 初始化SDK,合规指南【先进行预初始化,如果用户隐私同意后可以初始化UmengSDK进行信息上报】 42 | */ 43 | @JvmOverloads 44 | fun init(context: Context = XUI.getContext()) { 45 | val appContext = context.applicationContext 46 | if (appContext is Application) { 47 | initApplication(appContext) 48 | } 49 | } 50 | 51 | /** 52 | * 初始化SDK,合规指南【先进行预初始化,如果用户隐私同意后可以初始化UmengSDK进行信息上报】 53 | */ 54 | fun initApplication(application: Application?) { 55 | // 运营统计数据调试运行时不初始化 56 | if (MyApp.isDebug) { 57 | return 58 | } 59 | UMConfigure.setLogEnabled(false) 60 | UMConfigure.preInit(application, BuildConfig.APP_ID_UMENG, getChannel(application)) 61 | // 用户同意了隐私协议 62 | if (isAgreePrivacy) { 63 | realInit(application) 64 | } 65 | } 66 | 67 | /** 68 | * 真实的初始化UmengSDK【进行设备信息的统计上报,必须在获得用户隐私同意后方可调用】 69 | */ 70 | private fun realInit(application: Application?) { 71 | // 运营统计数据调试运行时不初始化 72 | if (MyApp.isDebug) { 73 | return 74 | } 75 | //初始化组件化基础库, 注意: 即使您已经在AndroidManifest.xml中配置过appkey和channel值,也需要在App代码中调用初始化接口(如需要使用AndroidManifest.xml中配置好的appkey和channel值,UMConfigure.init调用中appkey和channel参数请置为null)。 76 | //第二个参数是appkey,最后一个参数是pushSecret 77 | //这里BuildConfig.APP_ID_UMENG是根据local.properties中定义的APP_ID_UMENG生成的,只是运行看效果的话,可以不初始化该SDK 78 | UMConfigure.init( 79 | application, 80 | BuildConfig.APP_ID_UMENG, 81 | getChannel(application), 82 | UMConfigure.DEVICE_TYPE_PHONE, 83 | "" 84 | ) 85 | //统计SDK是否支持采集在子进程中打点的自定义事件,默认不支持 86 | //支持多进程打点 87 | UMConfigure.setProcessEvent(true) 88 | MobclickAgent.setPageCollectionMode(MobclickAgent.PageMode.AUTO) 89 | } 90 | 91 | /** 92 | * 获取渠道信息 93 | * 94 | * @param context 95 | * @return 96 | */ 97 | fun getChannel(context: Context?): String? { 98 | return WalleChannelReader.getChannel(context!!, DEFAULT_CHANNEL_ID) 99 | } 100 | } -------------------------------------------------------------------------------- /app/src/main/java/com/xuexiang/templateproject/utils/sdkinit/XUpdateInit.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2019 xuexiangjys(xuexiangjys@163.com) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | package com.xuexiang.templateproject.utils.sdkinit 18 | 19 | import android.app.Application 20 | import android.content.Context 21 | import com.xuexiang.templateproject.MyApp 22 | import com.xuexiang.templateproject.utils.update.CustomUpdateDownloader 23 | import com.xuexiang.templateproject.utils.update.CustomUpdateFailureListener 24 | import com.xuexiang.templateproject.utils.update.XHttpUpdateHttpServiceImpl 25 | import com.xuexiang.xupdate.XUpdate 26 | import com.xuexiang.xupdate.utils.UpdateUtils 27 | import com.xuexiang.xutil.common.StringUtils 28 | 29 | /** 30 | * XUpdate 版本更新 SDK 初始化 31 | * 32 | * 详细使用参见:https://github.com/xuexiangjys/XUpdate/wiki 33 | * 34 | * @author xuexiang 35 | * @since 2019-06-18 15:51 36 | */ 37 | object XUpdateInit { 38 | /** 39 | * 应用版本更新的检查地址 40 | */ 41 | // TODO: 2021/5/26 需要开启版本更新功能的话,就需要配置一下版本更新的地址 42 | private const val KEY_UPDATE_URL = "" 43 | fun init(application: Application) { 44 | XUpdate.get() 45 | .debug(MyApp.isDebug) //默认设置只在wifi下检查版本更新 46 | .isWifiOnly(false) //默认设置使用get请求检查版本 47 | .isGet(true) //默认设置非自动模式,可根据具体使用配置 48 | .isAutoMode(false) //设置默认公共请求参数 49 | .param("versionCode", UpdateUtils.getVersionCode(application)) 50 | .param("appKey", application.packageName) //这个必须设置!实现网络请求功能。 51 | .setIUpdateHttpService(XHttpUpdateHttpServiceImpl()) 52 | .setIUpdateDownLoader(CustomUpdateDownloader()) //这个必须初始化 53 | .init(application) 54 | } 55 | 56 | /** 57 | * 进行版本更新检查 58 | */ 59 | fun checkUpdate(context: Context, needErrorTip: Boolean) { 60 | checkUpdate(context, KEY_UPDATE_URL, needErrorTip) 61 | } 62 | 63 | /** 64 | * 进行版本更新检查 65 | * 66 | * @param context 上下文 67 | * @param url 版本更新检查的地址 68 | * @param needErrorTip 是否需要错误的提示 69 | */ 70 | private fun checkUpdate(context: Context, url: String, needErrorTip: Boolean) { 71 | if (StringUtils.isEmpty(url)) { 72 | return 73 | } 74 | XUpdate.newBuild(context).updateUrl(url).update() 75 | XUpdate.get().setOnUpdateFailureListener(CustomUpdateFailureListener(needErrorTip)) 76 | } 77 | } -------------------------------------------------------------------------------- /app/src/main/java/com/xuexiang/templateproject/utils/service/JsonSerializationService.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2019 xuexiangjys(xuexiangjys@163.com) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | package com.xuexiang.templateproject.utils.service 18 | 19 | import android.content.Context 20 | import com.xuexiang.xrouter.annotation.Router 21 | import com.xuexiang.xrouter.facade.service.SerializationService 22 | import com.xuexiang.xutil.net.JsonUtil 23 | import java.lang.reflect.Type 24 | 25 | /** 26 | * @author XUE 27 | * @since 2019/3/27 16:39 28 | */ 29 | @Router(path = "/service/json") 30 | class JsonSerializationService : SerializationService { 31 | /** 32 | * 对象序列化为json 33 | * 34 | * @param instance obj 35 | * @return json string 36 | */ 37 | override fun object2Json(instance: Any): String { 38 | return JsonUtil.toJson(instance) 39 | } 40 | 41 | /** 42 | * json反序列化为对象 43 | * 44 | * @param input json string 45 | * @param clazz object type 46 | * @return instance of object 47 | */ 48 | override fun parseObject(input: String, clazz: Type): T { 49 | return JsonUtil.fromJson(input, clazz) 50 | } 51 | 52 | /** 53 | * 进程初始化的方法 54 | * 55 | * @param context 上下文 56 | */ 57 | override fun init(context: Context) {} 58 | } -------------------------------------------------------------------------------- /app/src/main/java/com/xuexiang/templateproject/utils/update/CustomUpdateDownloader.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2019 xuexiangjys(xuexiangjys@163.com) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | package com.xuexiang.templateproject.utils.update 18 | 19 | import com.xuexiang.templateproject.utils.update.UpdateTipDialog 20 | import com.xuexiang.xupdate.entity.UpdateEntity 21 | import com.xuexiang.xupdate.proxy.impl.DefaultUpdateDownloader 22 | import com.xuexiang.xupdate.service.OnFileDownloadListener 23 | import com.xuexiang.xutil.app.ActivityUtils 24 | 25 | /** 26 | * 重写DefaultUpdateDownloader,在取消下载时,弹出提示 27 | * 28 | * @author xuexiang 29 | * @since 2019-06-14 23:47 30 | */ 31 | class CustomUpdateDownloader : DefaultUpdateDownloader() { 32 | private var mIsStartDownload = false 33 | override fun startDownload( 34 | updateEntity: UpdateEntity, 35 | downloadListener: OnFileDownloadListener? 36 | ) { 37 | super.startDownload(updateEntity, downloadListener) 38 | mIsStartDownload = true 39 | } 40 | 41 | override fun cancelDownload() { 42 | super.cancelDownload() 43 | if (mIsStartDownload) { 44 | mIsStartDownload = false 45 | ActivityUtils.startActivity(UpdateTipDialog::class.java) 46 | } 47 | } 48 | } -------------------------------------------------------------------------------- /app/src/main/java/com/xuexiang/templateproject/utils/update/CustomUpdateFailureListener.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2019 xuexiangjys(xuexiangjys@163.com) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | package com.xuexiang.templateproject.utils.update 18 | 19 | import com.xuexiang.templateproject.utils.update.UpdateTipDialog.Companion.show 20 | import com.xuexiang.xui.utils.XToastUtils 21 | import kotlin.jvm.JvmOverloads 22 | import com.xuexiang.xupdate.listener.OnUpdateFailureListener 23 | import com.xuexiang.xupdate.entity.UpdateError 24 | 25 | /** 26 | * 自定义版本更新提示 27 | * 28 | * @author xuexiang 29 | * @since 2019/4/15 上午12:01 30 | */ 31 | class CustomUpdateFailureListener @JvmOverloads constructor( 32 | /** 33 | * 是否需要错误提示 34 | */ 35 | private val mNeedErrorTip: Boolean = true 36 | ) : OnUpdateFailureListener { 37 | /** 38 | * 更新失败 39 | * 40 | * @param error 错误 41 | */ 42 | override fun onFailure(error: UpdateError) { 43 | if (mNeedErrorTip) { 44 | XToastUtils.error(error.detailMsg) 45 | } 46 | if (error.code == UpdateError.ERROR.DOWNLOAD_FAILED) { 47 | show("应用下载失败,是否考虑切换" + UpdateTipDialog.DOWNLOAD_TYPE_NAME + "下载?") 48 | } 49 | } 50 | } -------------------------------------------------------------------------------- /app/src/main/java/com/xuexiang/templateproject/utils/update/CustomUpdateParser.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 xuexiangjys(xuexiangjys@163.com) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | package com.xuexiang.templateproject.utils.update 18 | 19 | import com.xuexiang.xupdate.proxy.impl.AbstractUpdateParser 20 | import kotlin.Throws 21 | import com.xuexiang.xupdate.entity.UpdateEntity 22 | import java.lang.Exception 23 | 24 | /** 25 | * 版本更新信息自定义json解析器 26 | * 具体使用参见: https://github.com/xuexiangjys/XUpdate/wiki/%E9%AB%98%E9%98%B6%E4%BD%BF%E7%94%A8#%E8%87%AA%E5%AE%9A%E4%B9%89%E7%89%88%E6%9C%AC%E6%9B%B4%E6%96%B0%E8%A7%A3%E6%9E%90%E5%99%A8 27 | * 28 | * @author xuexiang 29 | * @since 2020-02-18 13:01 30 | */ 31 | class CustomUpdateParser : AbstractUpdateParser() { 32 | @Throws(Exception::class) 33 | override fun parseJson(json: String): UpdateEntity? { 34 | // TODO: 2020-02-18 这里填写你需要自定义的json格式,如果使用默认的API就不需要设置 35 | return null 36 | } 37 | } -------------------------------------------------------------------------------- /app/src/main/java/com/xuexiang/templateproject/utils/update/UpdateTipDialog.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2019 xuexiangjys(xuexiangjys@163.com) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | package com.xuexiang.templateproject.utils.update 18 | 19 | import android.content.DialogInterface 20 | import android.content.Intent 21 | import android.os.Bundle 22 | import android.text.TextUtils 23 | import androidx.appcompat.app.AppCompatActivity 24 | import com.xuexiang.templateproject.utils.Utils.goWeb 25 | import com.xuexiang.xui.widget.dialog.DialogLoader 26 | import com.xuexiang.xupdate.XUpdate 27 | 28 | /** 29 | * 版本更新提示弹窗 30 | * 31 | * @author xuexiang 32 | * @since 2019-06-15 00:06 33 | */ 34 | class UpdateTipDialog : AppCompatActivity(), DialogInterface.OnDismissListener { 35 | override fun onCreate(savedInstanceState: Bundle?) { 36 | super.onCreate(savedInstanceState) 37 | var content = intent.getStringExtra(KEY_CONTENT) 38 | if (TextUtils.isEmpty(content)) { 39 | content = "应用下载速度太慢了,是否考虑切换" + DOWNLOAD_TYPE_NAME + "下载?" 40 | } 41 | DialogLoader.getInstance() 42 | .showConfirmDialog(this, content, "是", { dialog: DialogInterface, which: Int -> 43 | dialog.dismiss() 44 | goWeb(this@UpdateTipDialog, DOWNLOAD_URL) 45 | }, "否") 46 | .setOnDismissListener(this) 47 | } 48 | 49 | override fun onDismiss(dialog: DialogInterface) { 50 | finish() 51 | } 52 | 53 | companion object { 54 | const val KEY_CONTENT = "com.xuexiang.templateproject.utils.update.KEY_CONTENT" 55 | 56 | // TODO: 2021/5/11 填写你应用下载类型名 57 | const val DOWNLOAD_TYPE_NAME = "蒲公英" 58 | 59 | // TODO: 2021/5/11 填写你应用下载页面的链接 60 | private const val DOWNLOAD_URL = "这里填写你应用下载页面的链接" 61 | 62 | /** 63 | * 显示版本更新重试提示弹窗 64 | * 65 | * @param content 66 | */ 67 | @JvmStatic 68 | fun show(content: String?) { 69 | val intent = Intent(XUpdate.getContext(), UpdateTipDialog::class.java) 70 | intent.putExtra(KEY_CONTENT, content) 71 | intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) 72 | XUpdate.getContext().startActivity(intent) 73 | } 74 | } 75 | } -------------------------------------------------------------------------------- /app/src/main/java/com/xuexiang/templateproject/widget/MaterialFooter.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 xuexiangjys(xuexiangjys@163.com) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | package com.xuexiang.templateproject.widget 18 | 19 | import android.annotation.SuppressLint 20 | import android.content.Context 21 | import android.util.AttributeSet 22 | import android.view.View 23 | import android.widget.FrameLayout 24 | import android.widget.ProgressBar 25 | import com.scwang.smart.refresh.layout.api.RefreshFooter 26 | import com.scwang.smart.refresh.layout.api.RefreshKernel 27 | import com.scwang.smart.refresh.layout.api.RefreshLayout 28 | import com.scwang.smart.refresh.layout.constant.RefreshState 29 | import com.scwang.smart.refresh.layout.constant.SpinnerStyle 30 | import com.xuexiang.xui.utils.DensityUtils 31 | 32 | /** 33 | * Material风格的上拉加载 34 | * 35 | * @author xuexiang 36 | * @since 2019-08-03 11:14 37 | */ 38 | @SuppressLint("RestrictedApi") 39 | class MaterialFooter @JvmOverloads constructor(context: Context?, attrs: AttributeSet? = null) : 40 | ProgressBar(context, attrs), RefreshFooter { 41 | private fun initView() { 42 | visibility = GONE 43 | val params = FrameLayout.LayoutParams( 44 | FrameLayout.LayoutParams.MATCH_PARENT, 45 | FrameLayout.LayoutParams.WRAP_CONTENT 46 | ) 47 | setPadding(0, DensityUtils.dp2px(context, 10f), 0, DensityUtils.dp2px(context, 10f)) 48 | layoutParams = params 49 | } 50 | 51 | override fun setNoMoreData(noMoreData: Boolean): Boolean { 52 | return false 53 | } 54 | 55 | override fun getView(): View { 56 | return this 57 | } 58 | 59 | override fun getSpinnerStyle(): SpinnerStyle { 60 | //指定为平移,不能null 61 | return SpinnerStyle.Translate 62 | } 63 | 64 | override fun onStartAnimator(refreshLayout: RefreshLayout, height: Int, maxDragHeight: Int) { 65 | visibility = VISIBLE 66 | } 67 | 68 | override fun onFinish(refreshLayout: RefreshLayout, success: Boolean): Int { 69 | visibility = GONE 70 | return 100 71 | } 72 | 73 | override fun onStateChanged( 74 | refreshLayout: RefreshLayout, 75 | oldState: RefreshState, 76 | newState: RefreshState 77 | ) { 78 | } 79 | 80 | override fun setPrimaryColors(vararg colors: Int) {} 81 | override fun onInitialized(kernel: RefreshKernel, height: Int, maxDragHeight: Int) {} 82 | override fun onMoving( 83 | isDragging: Boolean, 84 | percent: Float, 85 | offset: Int, 86 | height: Int, 87 | maxDragHeight: Int 88 | ) { 89 | } 90 | 91 | override fun onReleased(refreshLayout: RefreshLayout, height: Int, maxDragHeight: Int) {} 92 | override fun onHorizontalDrag(percentX: Float, offsetX: Int, offsetMax: Int) {} 93 | override fun isSupportHorizontalDrag(): Boolean { 94 | return false 95 | } 96 | 97 | override fun autoOpen(duration: Int, dragRate: Float, animationOnly: Boolean): Boolean { 98 | return false 99 | } 100 | 101 | init { 102 | initView() 103 | } 104 | } -------------------------------------------------------------------------------- /app/src/main/res/color/selector_round_button_main_theme_color.xml: -------------------------------------------------------------------------------- 1 | 2 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_comment.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuexiangjys/TemplateAppProject-kotlin/551bef56697c628628d42a857db37658c7670f8d/app/src/main/res/drawable-hdpi/ic_comment.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_praise.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuexiangjys/TemplateAppProject-kotlin/551bef56697c628628d42a857db37658c7670f8d/app/src/main/res/drawable-hdpi/ic_praise.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_splash_app_logo_xui.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuexiangjys/TemplateAppProject-kotlin/551bef56697c628628d42a857db37658c7670f8d/app/src/main/res/drawable-hdpi/ic_splash_app_logo_xui.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_splash_company_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuexiangjys/TemplateAppProject-kotlin/551bef56697c628628d42a857db37658c7670f8d/app/src/main/res/drawable-hdpi/ic_splash_company_logo.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-v17/xui_config_bg_splash.xml: -------------------------------------------------------------------------------- 1 | 17 | 18 | 19 | 21 | 22 | 23 | 24 | 27 | 28 | 29 | 30 | 33 | 34 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v21/xui_config_bg_splash.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 10 | 11 | 12 | 13 | 16 | 17 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 12 | 13 | 19 | 22 | 25 | 26 | 27 | 28 | 34 | 35 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/ic_web_back.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuexiangjys/TemplateAppProject-kotlin/551bef56697c628628d42a857db37658c7670f8d/app/src/main/res/drawable-xxxhdpi/ic_web_back.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/ic_web_close.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuexiangjys/TemplateAppProject-kotlin/551bef56697c628628d42a857db37658c7670f8d/app/src/main/res/drawable-xxxhdpi/ic_web_close.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/ic_web_more.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuexiangjys/TemplateAppProject-kotlin/551bef56697c628628d42a857db37658c7670f8d/app/src/main/res/drawable-xxxhdpi/ic_web_more.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/bg_dialog_common_tip_corner_white.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_action_close_white.xml: -------------------------------------------------------------------------------- 1 | 6 | 14 | 22 | 23 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_default_head.xml: -------------------------------------------------------------------------------- 1 | 17 | 18 | 23 | 26 | 27 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_login_close.xml: -------------------------------------------------------------------------------- 1 | 17 | 18 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_logo_app.xml: -------------------------------------------------------------------------------- 1 | 17 | 18 | 23 | 26 | 29 | 30 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_menu_about.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 19 | 20 | 25 | 28 | 29 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_menu_about_white.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 19 | 20 | 25 | 28 | 29 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_menu_issues.xml: -------------------------------------------------------------------------------- 1 | 17 | 18 | 23 | 26 | 27 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_menu_news.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 19 | 20 | 25 | 28 | 29 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_menu_notifications.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 19 | 20 | 25 | 28 | 29 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_menu_person.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 19 | 20 | 25 | 28 | 29 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_menu_privacy.xml: -------------------------------------------------------------------------------- 1 | 17 | 18 | 23 | 26 | 29 | 30 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_menu_search.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 19 | 20 | 25 | 28 | 29 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_menu_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 19 | 20 | 25 | 28 | 29 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_menu_star.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 19 | 20 | 25 | 28 | 29 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_menu_trending.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 19 | 20 | 25 | 28 | 29 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_password.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 12 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_phone.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/icon_arrow_right_grey.xml: -------------------------------------------------------------------------------- 1 | 17 | 18 | 23 | 26 | 29 | 30 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/img_guide_tip_top.xml: -------------------------------------------------------------------------------- 1 | 6 | 12 | 18 | 24 | 30 | 36 | 37 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_agent_web.xml: -------------------------------------------------------------------------------- 1 | 17 | 18 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 18 | 19 | 26 | 27 | 28 | 33 | 34 | 35 | 42 | 43 | -------------------------------------------------------------------------------- /app/src/main/res/layout/adapter_common_grid_item.xml: -------------------------------------------------------------------------------- 1 | 17 | 24 | 25 | 28 | 29 | 34 | 35 | 41 | 42 | 43 | 44 | 45 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /app/src/main/res/layout/adapter_item_simple_list_2.xml: -------------------------------------------------------------------------------- 1 | 17 | 26 | 27 | 31 | 32 | 37 | 38 | -------------------------------------------------------------------------------- /app/src/main/res/layout/adapter_news_card_view_list_item.xml: -------------------------------------------------------------------------------- 1 | 17 | 18 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /app/src/main/res/layout/adapter_title_item.xml: -------------------------------------------------------------------------------- 1 | 17 | 18 | 24 | 25 | 34 | 35 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_about.xml: -------------------------------------------------------------------------------- 1 | 16 | 17 | 20 | 21 | 22 | 23 | 30 | 31 | 32 | 37 | 38 | 45 | 46 | 53 | 54 | 59 | 60 | 64 | 65 | 72 | 73 | 74 | 75 | 76 | 77 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_agentweb.xml: -------------------------------------------------------------------------------- 1 | 16 | 17 | 21 | 22 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_grid_item.xml: -------------------------------------------------------------------------------- 1 | 17 | 18 | 22 | 23 | 24 | 31 | 32 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_news.xml: -------------------------------------------------------------------------------- 1 | 17 | 18 | 27 | 28 | 31 | 32 | 38 | 39 | 40 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_profile.xml: -------------------------------------------------------------------------------- 1 | 17 | 18 | 22 | 23 | 24 | 25 | 30 | 31 | 35 | 36 | 44 | 45 | 46 | 47 | 50 | 51 | 54 | 55 | 59 | 60 | 61 | 66 | 67 | 72 | 73 | 78 | 79 | 80 | 81 | 82 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_pulldown_web.xml: -------------------------------------------------------------------------------- 1 | 17 | 18 | 21 | 22 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_service_protocol.xml: -------------------------------------------------------------------------------- 1 | 17 | 18 | 22 | 23 | 28 | 29 | 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_settings.xml: -------------------------------------------------------------------------------- 1 | 17 | 18 | 21 | 22 | 23 | 24 | 29 | 30 | 34 | 35 | 39 | 40 | 44 | 45 | 50 | 51 | 57 | 58 | 65 | 66 | 67 | 68 | 69 | 70 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_trending.xml: -------------------------------------------------------------------------------- 1 | 17 | 18 | 23 | 24 | 29 | 30 | -------------------------------------------------------------------------------- /app/src/main/res/layout/include_head_view_banner.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /app/src/main/res/layout/include_navigation_header.xml: -------------------------------------------------------------------------------- 1 | 17 | 18 | 25 | 26 | 29 | 30 | 38 | 39 | 49 | 50 | 54 | 55 | 56 | 57 | 66 | 67 | 70 | 71 | -------------------------------------------------------------------------------- /app/src/main/res/layout/include_toolbar_web.xml: -------------------------------------------------------------------------------- 1 | 17 | 18 | 26 | 27 | 31 | 32 | 39 | 40 | 48 | 49 | 56 | 57 | 65 | 66 | 73 | 74 | 75 | 76 | 77 | 78 | -------------------------------------------------------------------------------- /app/src/main/res/layout/layout_main_content.xml: -------------------------------------------------------------------------------- 1 | 17 | 18 | 22 | 23 | 28 | 29 | 36 | 37 | 38 | 39 | 40 | 47 | 48 | 49 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /app/src/main/res/menu/menu_drawer.xml: -------------------------------------------------------------------------------- 1 | 17 | 18 | 19 | 20 | 21 | 24 | 25 | 29 | 30 | 34 | 35 | 39 | 40 | 41 | 42 | 43 | 46 | 47 | 52 | 53 | 58 | 59 | 64 | 65 | 66 | 69 | 74 | 79 | 80 | 81 | 82 | 83 | -------------------------------------------------------------------------------- /app/src/main/res/menu/menu_main.xml: -------------------------------------------------------------------------------- 1 | 17 | 18 | 20 | 21 | 27 | 28 | 34 | 35 | -------------------------------------------------------------------------------- /app/src/main/res/menu/menu_navigation_bottom.xml: -------------------------------------------------------------------------------- 1 | 2 | 18 | 19 | 20 | 21 | 22 | 26 | 27 | 31 | 32 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /app/src/main/res/menu/menu_toolbar_web.xml: -------------------------------------------------------------------------------- 1 | 2 | 18 | 19 | 21 | 22 | 27 | 32 | 37 | 42 | 43 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuexiangjys/TemplateAppProject-kotlin/551bef56697c628628d42a857db37658c7670f8d/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuexiangjys/TemplateAppProject-kotlin/551bef56697c628628d42a857db37658c7670f8d/app/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuexiangjys/TemplateAppProject-kotlin/551bef56697c628628d42a857db37658c7670f8d/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuexiangjys/TemplateAppProject-kotlin/551bef56697c628628d42a857db37658c7670f8d/app/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuexiangjys/TemplateAppProject-kotlin/551bef56697c628628d42a857db37658c7670f8d/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuexiangjys/TemplateAppProject-kotlin/551bef56697c628628d42a857db37658c7670f8d/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuexiangjys/TemplateAppProject-kotlin/551bef56697c628628d42a857db37658c7670f8d/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuexiangjys/TemplateAppProject-kotlin/551bef56697c628628d42a857db37658c7670f8d/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuexiangjys/TemplateAppProject-kotlin/551bef56697c628628d42a857db37658c7670f8d/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuexiangjys/TemplateAppProject-kotlin/551bef56697c628628d42a857db37658c7670f8d/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/values/arrays.xml: -------------------------------------------------------------------------------- 1 | 2 | 18 | 19 | 20 | 21 | 22 | @string/menu_news 23 | @string/menu_trending 24 | @string/menu_profile 25 | 26 | 27 | 28 | ubmcmm.baidustatic.com 29 | gss1.bdstatic.com/ 30 | cpro2.baidustatic.com 31 | cpro.baidustatic.com 32 | lianmeng.360.cn 33 | nsclick.baidu.com 34 | caclick.baidu.com/ 35 | jieaogd.com 36 | publish-pic-cpu.baidu.com/ 37 | cpro.baidustatic.com/ 38 | hao61.net/ 39 | cpu.baidu.com/ 40 | pos.baidu.com 41 | cbjs.baidu.com 42 | cpro.baidu.com 43 | images.sohu.com/cs/jsfile/js/c.js 44 | union.sogou.com/ 45 | sogou.com/ 46 | 5txs.cn/ 47 | liuzhi520.com/ 48 | yhzm.cc/ 49 | jieaogd.com 50 | a.baidu.com 51 | c.baidu.com 52 | mlnbike.com 53 | alipays://platformapi 54 | alipay.com/ 55 | jieaogd.com 56 | vipshop.com 57 | bayimob.com 58 | 59 | 60 | 61 | 美食 62 | 甜点 63 | 烧烤 64 | 夜宵 65 | 水果 66 | 药品 67 | 蔬菜 68 | 跑腿 69 | 70 | 71 | 72 | 73 | @color/app_color_theme_1 74 | @color/app_color_theme_2 75 | @color/app_color_theme_3 76 | @color/app_color_theme_4 77 | @color/app_color_theme_5 78 | @color/app_color_theme_6 79 | @color/app_color_theme_7 80 | @color/app_color_theme_8 81 | 82 | 83 | -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #299EE3 4 | #299EE3 5 | #299EE3 6 | 7 | #FFF1F1F1 8 | 9 | 10 | 11 | @color/xui_config_color_white 12 | @color/xui_config_color_red 13 | @color/colorAccent 14 | #388E3C 15 | @color/xui_config_color_waring 16 | #353A3E 17 | 18 | #EF5362 19 | #FE6D4B 20 | #FFCF47 21 | #9FD661 22 | #3FD0AD 23 | #2BBDF3 24 | #5A9AEF 25 | #AC8FEF 26 | #EE85C1 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /app/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 24dp 4 | 5 | 4dp 6 | 5dp 7 | 6dp 8 | 8dp 9 | 10dp 10 | 12dp 11 | 14dp 12 | 16dp 13 | 18dp 14 | 20dp 15 | 24dp 16 | 30dp 17 | 18 | 4dp 19 | 5dp 20 | 6dp 21 | 8dp 22 | 10dp 23 | 12dp 24 | 14dp 25 | 16dp 26 | 18dp 27 | 20dp 28 | 24dp 29 | 30dp 30 | 31 | -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 | 9 | 10 | 17 | 18 | 25 | 26 | 27 | 32 | 33 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /app/src/main/res/xml/network_security_config.xml: -------------------------------------------------------------------------------- 1 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /app/src/test/java/com/xuexiang/templateproject/ExampleUnitTest.kt: -------------------------------------------------------------------------------- 1 | package com.xuexiang.templateproject 2 | 3 | import com.xuexiang.templateproject.core.http.entity.TipInfo 4 | import com.xuexiang.xhttp2.model.ApiResult 5 | import com.xuexiang.xutil.net.JsonUtil 6 | import org.junit.Assert 7 | import org.junit.Test 8 | import java.util.* 9 | 10 | /** 11 | * Example local unit test, which will execute on the development machine (host). 12 | * 13 | * @see [Testing documentation](http://d.android.com/tools/testing) 14 | */ 15 | class ExampleUnitTest { 16 | @Test 17 | fun addition_isCorrect() { 18 | Assert.assertEquals(4, (2 + 2).toLong()) 19 | val info = TipInfo() 20 | info.title = "微信公众号" 21 | info.content = "获取更多资讯,欢迎关注我的微信公众号:【我的Android开源之旅】" 22 | val list: MutableList = ArrayList() 23 | for (i in 0..4) { 24 | list.add(info) 25 | } 26 | val result = ApiResult>() 27 | result.data = list 28 | println(JsonUtil.toJson(result)) 29 | } 30 | } -------------------------------------------------------------------------------- /app/x-library.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.xuexiang.xrouter' 2 | apply plugin: 'kotlin-kapt' 3 | apply plugin: 'android-aspectjx' 4 | apply plugin: 'com.xuexiang.xaop' 5 | 6 | //自动添加依赖 7 | configurations.each { configuration -> 8 | def dependencies = getProject().dependencies 9 | if (configuration.name == "implementation") { 10 | //为Project加入X-Library依赖 11 | //XUI框架 12 | configuration.dependencies.add(dependencies.create(deps.xlibrary.xui)) 13 | configuration.dependencies.add(dependencies.create(deps.androidx.appcompat)) 14 | configuration.dependencies.add(dependencies.create(deps.androidx.recyclerview)) 15 | configuration.dependencies.add(dependencies.create(deps.androidx.design)) 16 | configuration.dependencies.add(dependencies.create(deps.glide)) 17 | //XUtil工具类 18 | configuration.dependencies.add(dependencies.create(deps.xlibrary.xutil_core)) 19 | //XAOP切片 20 | configuration.dependencies.add(dependencies.create(deps.xlibrary.xaop_runtime)) 21 | //XUpdate版本更新 22 | configuration.dependencies.add(dependencies.create(deps.xlibrary.xupdate)) 23 | //XHttp2 24 | configuration.dependencies.add(dependencies.create(deps.xlibrary.xhttp2)) 25 | configuration.dependencies.add(dependencies.create(deps.rxjava2)) 26 | configuration.dependencies.add(dependencies.create(deps.rxandroid)) 27 | configuration.dependencies.add(dependencies.create(deps.okhttp3)) 28 | configuration.dependencies.add(dependencies.create(deps.gson)) 29 | //XPage 30 | configuration.dependencies.add(dependencies.create(deps.xlibrary.xpage_lib)) 31 | //页面路由 32 | configuration.dependencies.add(dependencies.create(deps.xlibrary.xrouter_runtime)) 33 | } 34 | 35 | if (configuration.name == "kapt") { 36 | //XPage 37 | configuration.dependencies.add(dependencies.create(deps.xlibrary.xpage_compiler)) 38 | //页面路由 39 | configuration.dependencies.add(dependencies.create(deps.xlibrary.xrouter_compiler)) 40 | } 41 | 42 | if (configuration.name == "debugImplementation") { 43 | //内存泄漏监测leak 44 | configuration.dependencies.add(dependencies.create(deps.leakcanary)) 45 | } 46 | } 47 | 48 | configurations.all { 49 | resolutionStrategy.force deps.okhttp3 50 | } 51 | 52 | // TODO 这里需要修改包名 53 | aspectjx { 54 | include 'com.xuexiang.templateproject' 55 | } -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | apply from: './versions.gradle' 5 | addRepos(repositories) //增加代码仓库 6 | dependencies { 7 | classpath deps.android_gradle_plugin 8 | classpath deps.android_maven_gradle_plugin 9 | 10 | classpath 'com.chenenyu:img-optimizer:1.2.0' // 图片压缩 11 | //美团多渠道打包 12 | classpath 'com.meituan.android.walle:plugin:1.1.6' 13 | //滴滴的质量优化框架 14 | if (isNeedPackage.toBoolean() && isUseBooster.toBoolean()) { 15 | classpath deps.booster.gradle_plugin 16 | classpath deps.booster.task_processed_res 17 | classpath deps.booster.task_resource_deredundancy 18 | } 19 | } 20 | } 21 | 22 | allprojects { 23 | addRepos(repositories) 24 | } 25 | 26 | task clean(type: Delete) { 27 | delete rootProject.buildDir 28 | } 29 | 30 | -------------------------------------------------------------------------------- /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 | 15 | # 是否打包APK,打正式包时请设置为true,使用正式的签名 16 | isNeedPackage=false 17 | # 是否使用booster优化APK,这里需要注意gradle的版本,对于最新的gradle版本可能存在兼容问题 18 | isUseBooster=false 19 | android.precompileDependenciesResources=false 20 | 21 | android.useAndroidX=true 22 | android.enableJetifier=true 23 | 24 | android.enableD8=true 25 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuexiangjys/TemplateAppProject-kotlin/551bef56697c628628d42a857db37658c7670f8d/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Fri Jun 28 16:23:16 CST 2019 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.6.1-bin.zip 7 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | --------------------------------------------------------------------------------