├── .gitignore
├── README.md
├── app
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── devyk
│ │ └── kotlin_github
│ │ └── ExampleInstrumentedTest.kt
│ ├── main
│ ├── AndroidManifest.xml
│ ├── java
│ │ └── com
│ │ │ └── devyk
│ │ │ └── kotlin_github
│ │ │ ├── GitHubApp.kt
│ │ │ ├── adapter
│ │ │ ├── IssueListAdapter.kt
│ │ │ ├── PeopleListAdapter.kt
│ │ │ └── RepoListAdapter.kt
│ │ │ ├── api
│ │ │ ├── ActivityService.kt
│ │ │ ├── AuthService.kt
│ │ │ ├── IssueService.kt
│ │ │ ├── RepositoryService.kt
│ │ │ └── UserService.kt
│ │ │ ├── config
│ │ │ ├── Contacts.kt
│ │ │ ├── NavViewItem.kt
│ │ │ ├── NaviViewExt.kt
│ │ │ ├── Themer.kt
│ │ │ ├── UserConfig.kt
│ │ │ └── settings
│ │ │ │ ├── Configs.kt
│ │ │ │ └── Settings.kt
│ │ │ ├── mvp
│ │ │ ├── base
│ │ │ │ ├── BaseDetailActivity.kt
│ │ │ │ ├── CommonListAdapter.kt
│ │ │ │ ├── CommonListFragment.kt
│ │ │ │ ├── CommonListPresenter.kt
│ │ │ │ ├── CommonSinglePageFragment.kt
│ │ │ │ ├── CommonViewPageAdapter.kt
│ │ │ │ ├── CommonViewPagerFragment.kt
│ │ │ │ ├── DataProvider.kt
│ │ │ │ ├── GitHubPaging.kt
│ │ │ │ └── ListPage.kt
│ │ │ ├── m
│ │ │ │ ├── AccountManager.kt
│ │ │ │ ├── IssueModel.kt
│ │ │ │ ├── PeopleModel.kt
│ │ │ │ ├── RepoModel.kt
│ │ │ │ └── entity
│ │ │ │ │ ├── AccountEntities.kt
│ │ │ │ │ ├── Issue.kt
│ │ │ │ │ ├── PagingWrapper.kt
│ │ │ │ │ ├── Repository.kt
│ │ │ │ │ ├── SearchRepositories.kt
│ │ │ │ │ ├── SubscriptionBody.kt
│ │ │ │ │ ├── SubscriptionResponse.kt
│ │ │ │ │ └── User.kt
│ │ │ ├── p
│ │ │ │ ├── LoginPresenter.kt
│ │ │ │ ├── MainPersenter.kt
│ │ │ │ ├── MyIssuePresenter.kt
│ │ │ │ ├── PeopleListPresenter.kt
│ │ │ │ └── RepoListPresenter.kt
│ │ │ └── v
│ │ │ │ ├── AboutFragment.kt
│ │ │ │ ├── MainActivity.kt
│ │ │ │ ├── RepoDetailActivity.kt
│ │ │ │ ├── issue
│ │ │ │ ├── MyIssueFragment.kt
│ │ │ │ └── MyIssueListFragment.kt
│ │ │ │ ├── login
│ │ │ │ └── LoginActivity.kt
│ │ │ │ ├── people
│ │ │ │ ├── PeopleFragment.kt
│ │ │ │ └── PeopleListFragment.kt
│ │ │ │ └── repo
│ │ │ │ ├── RepoFragment.kt
│ │ │ │ └── RepoListFragment.kt
│ │ │ └── widget
│ │ │ ├── ActionBarController.kt
│ │ │ ├── DetailItemView.kt
│ │ │ ├── FixLuRecyclerView.java
│ │ │ └── NavigationController.kt
│ └── res
│ │ ├── drawable-v24
│ │ └── ic_launcher_foreground.xml
│ │ ├── drawable
│ │ ├── ic_about_us.xml
│ │ ├── ic_day.xml
│ │ ├── ic_fork.xml
│ │ ├── ic_github.xml
│ │ ├── ic_go.xml
│ │ ├── ic_issue.xml
│ │ ├── ic_issue_closed.xml
│ │ ├── ic_issue_open.xml
│ │ ├── ic_launcher_background.xml
│ │ ├── ic_night.xml
│ │ ├── ic_people.xml
│ │ ├── ic_repository.xml
│ │ ├── ic_round.xml
│ │ ├── ic_speech_bubble.xml
│ │ ├── ic_star.xml
│ │ ├── ic_star_o.xml
│ │ ├── ic_unwatch.xml
│ │ ├── ic_watch.xml
│ │ ├── sel_daynight.xml
│ │ ├── sel_star.xml
│ │ ├── sel_watch.xml
│ │ ├── side_nav_bar.xml
│ │ └── side_nav_bar_night.xml
│ │ ├── layout
│ │ ├── activity_login.xml
│ │ ├── activity_main.xml
│ │ ├── activity_repo_details.xml
│ │ ├── app_bar_details.xml
│ │ ├── app_bar_main.xml
│ │ ├── app_bar_simple.xml
│ │ ├── detail_item.xml
│ │ ├── fragment_common_list.xml
│ │ ├── item_card.xml
│ │ ├── item_issue.xml
│ │ ├── item_repo.xml
│ │ ├── item_user.xml
│ │ ├── menu_item_daynight.xml
│ │ └── nav_header_main.xml
│ │ ├── menu
│ │ ├── activity_actionbar.xml
│ │ ├── activity_main_drawer.xml
│ │ └── activity_main_drawer_no_logged_in.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
│ │ ├── github.png
│ │ ├── github_about.png
│ │ ├── 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
│ │ ├── colors.xml
│ │ ├── dimens.xml
│ │ ├── ids.xml
│ │ ├── strings.xml
│ │ └── styles.xml
│ └── test
│ └── java
│ └── com
│ └── devyk
│ └── kotlin_github
│ ├── BooleanExpTest.kt
│ └── ExampleUnitTest.kt
├── build.gradle
├── common
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── devyk
│ │ └── common
│ │ └── ExampleInstrumentedTest.java
│ ├── main
│ ├── AndroidManifest.xml
│ ├── java
│ │ ├── android
│ │ │ └── support
│ │ │ │ └── v7
│ │ │ │ └── widget
│ │ │ │ └── TintableToggleButton.kt
│ │ ├── com
│ │ │ └── devyk
│ │ │ │ └── common
│ │ │ │ ├── App.kt
│ │ │ │ ├── anno
│ │ │ │ └── PoKo.kt
│ │ │ │ ├── compat
│ │ │ │ ├── Tls12.kt
│ │ │ │ └── Tls12SocketFactory.java
│ │ │ │ ├── config
│ │ │ │ └── UserInfo.kt
│ │ │ │ ├── ext
│ │ │ │ ├── BooleanExp.kt
│ │ │ │ ├── ConfirmDialog.kt
│ │ │ │ ├── CoroutinesExt.kt
│ │ │ │ ├── DeviceId.kt
│ │ │ │ ├── FileExt.kt
│ │ │ │ ├── FragmentContainerExt.kt
│ │ │ │ ├── GlideExt.kt
│ │ │ │ ├── GsonExt.kt
│ │ │ │ ├── InputMethod.kt
│ │ │ │ ├── LogExt.kt
│ │ │ │ ├── NumberExt.kt
│ │ │ │ ├── PrefExt.kt
│ │ │ │ ├── PreferencesExp.kt
│ │ │ │ ├── PropertiesDelegate.kt
│ │ │ │ ├── Result.java
│ │ │ │ ├── RxJavaExt.kt
│ │ │ │ ├── ViewExt.kt
│ │ │ │ ├── bindExtra.kt
│ │ │ │ └── delegateOf.kt
│ │ │ │ ├── mvp
│ │ │ │ ├── ILifecycle.kt
│ │ │ │ ├── impl
│ │ │ │ │ ├── BaseActivity.kt
│ │ │ │ │ ├── BaseFragment.kt
│ │ │ │ │ └── BasePresenter.kt
│ │ │ │ └── mvps.kt
│ │ │ │ ├── network
│ │ │ │ ├── RESTFulService.kt
│ │ │ │ └── interceptor
│ │ │ │ │ ├── AcceptInterceptor.kt
│ │ │ │ │ ├── AuthInterceptor.kt
│ │ │ │ │ └── CacheInterceptor.kt
│ │ │ │ ├── utils
│ │ │ │ ├── AdapterList.kt
│ │ │ │ ├── Network.kt
│ │ │ │ ├── ViewPagerAdapterList.kt
│ │ │ │ ├── Weak.kt
│ │ │ │ └── githubDateFormatter.kt
│ │ │ │ └── weiget
│ │ │ │ ├── AppBarLayoutBehavior.kt
│ │ │ │ ├── AppCompatAvatarImageView.java
│ │ │ │ └── ErrorInfoView.kt
│ │ └── retrofit2
│ │ │ └── adapter
│ │ │ └── rxjava2
│ │ │ ├── RxJava2CallAdapter2.java
│ │ │ └── RxJava2CallAdapterFactory2.java
│ └── res
│ │ ├── anim
│ │ ├── left_in.xml
│ │ ├── left_out.xml
│ │ ├── rignt_in.xml
│ │ └── rignt_out.xml
│ │ ├── drawable
│ │ ├── side_nav_bar.xml
│ │ └── side_nav_bar_night.xml
│ │ ├── values-sw1024dp
│ │ └── dimens.xml
│ │ ├── values-sw1280dp
│ │ └── dimens.xml
│ │ ├── values-sw384dp
│ │ └── dimens.xml
│ │ ├── values-sw392dp
│ │ └── dimens.xml
│ │ ├── values-sw400dp
│ │ └── dimens.xml
│ │ ├── values-sw410dp
│ │ └── dimens.xml
│ │ ├── values-sw411dp
│ │ └── dimens.xml
│ │ ├── values-sw432dp
│ │ └── dimens.xml
│ │ ├── values-sw480dp
│ │ └── dimens.xml
│ │ ├── values-sw533dp
│ │ └── dimens.xml
│ │ ├── values-sw592dp
│ │ └── dimens.xml
│ │ ├── values-sw600dp
│ │ └── dimens.xml
│ │ ├── values-sw640dp
│ │ └── dimens.xml
│ │ ├── values-sw662dp
│ │ └── dimens.xml
│ │ ├── values-sw720dp
│ │ └── dimens.xml
│ │ ├── values-sw768dp
│ │ └── dimens.xml
│ │ ├── values-sw800dp
│ │ └── dimens.xml
│ │ ├── values-sw820dp
│ │ └── dimens.xml
│ │ ├── values-sw960dp
│ │ └── dimens.xml
│ │ └── values
│ │ ├── attrs.xml
│ │ ├── colors.xml
│ │ ├── dimens.xml
│ │ ├── strings.xml
│ │ └── styles.xml
│ └── test
│ └── java
│ └── com
│ └── devyk
│ └── common
│ └── ExampleUnitTest.java
├── config.gradle
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── screenMatch.properties
└── settings.gradle
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | local.properties
4 | .idea
5 | .DS_Store
6 | build
7 | captures
8 | .externalNativeBuild
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## 介绍
2 |
3 | 由于官方推荐使用 Kotlin 语言来开发 Android 程序,之前一直没有时间来学习这门语言,最近抽出了一点时间写了一个 kotlin 版本的 APP ,现在把它开源出来,效果图如下:
4 |
5 | 效果图看不见请移步:https://juejin.im/post/5dc294d5f265da4d4434afc9
6 |
7 | 
8 |
9 | ## 使用框架
10 |
11 | - MVP
12 | - retrofit
13 | - glide
14 | - anko
15 | - okhttp
16 | - RxJava
17 | - sw 屏幕适配
18 |
19 | ## 项目地址
20 |
21 | [Kotlin_GitHub](https://github.com/yangkun19921001/Kotlin_GitHub.git)
22 |
23 | 由于作者是第一次接触 Kotlin 开发 APP , 写的不好的地方还望多多指教,此项目非常适合新手入门。
24 |
25 |
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | apply plugin: 'kotlin-android'
4 |
5 | apply plugin: 'kotlin-android-extensions'
6 |
7 |
8 |
9 | kotlin {
10 | androidExtensions {
11 | experimental = true
12 | }
13 | }
14 |
15 |
16 | android {
17 | compileSdkVersion rootProject.ext.android.compileSdkVersion
18 | buildToolsVersion "28.0.3"
19 | defaultConfig {
20 | applicationId "com.devyk.kotlin_github"
21 | minSdkVersion rootProject.ext.android.minSdkVersion
22 | targetSdkVersion rootProject.ext.android.targetSdkVersion
23 | versionCode rootProject.ext.android.versionCode
24 | versionName rootProject.ext.android.versionName
25 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
26 |
27 | //dex 分包
28 | multiDexEnabled true
29 |
30 | // 如果需要使用兼容库对svg的支持,就需要这样配置
31 | vectorDrawables.useSupportLibrary = true
32 | }
33 | buildTypes {
34 | release {
35 | minifyEnabled false
36 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
37 | }
38 | }
39 | }
40 |
41 | dependencies {
42 | implementation fileTree(dir: 'libs', include: ['*.jar'])
43 | testImplementation 'junit:junit:4.12'
44 |
45 | api project(path: ':common')
46 |
47 | //Dex 分包
48 | implementation 'com.android.support:multidex:1.0.1'
49 |
50 | implementation 'com.github.CymChad:BaseRecyclerViewAdapterHelper:2.9.46'
51 |
52 | implementation 'com.github.jdsjlzx:LRecyclerView:1.5.0'
53 |
54 |
55 | }
56 |
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/app/src/androidTest/java/com/devyk/kotlin_github/ExampleInstrumentedTest.kt:
--------------------------------------------------------------------------------
1 | package com.devyk.kotlin_github
2 |
3 | import androidx.test.InstrumentationRegistry
4 | import androidx.test.runner.AndroidJUnit4
5 |
6 | import org.junit.Test
7 | import org.junit.runner.RunWith
8 |
9 | import org.junit.Assert.*
10 |
11 | /**
12 | * Instrumented test, which will execute on an Android device.
13 | *
14 | * See [testing documentation](http://d.android.com/tools/testing).
15 | */
16 | @RunWith(AndroidJUnit4::class)
17 | class ExampleInstrumentedTest {
18 | @Test
19 | fun useAppContext() {
20 | // Context of the app under test.
21 | val appContext = InstrumentationRegistry.getTargetContext()
22 | assertEquals("com.devyk.kotlin_github", appContext.packageName)
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
12 | * author : devyk on 2019-10-30 16:09 13 | * blog : https://juejin.im/user/578259398ac2470061f3a3fb/posts 14 | * github : https://github.com/yangkun19921001 15 | * mailbox : yang1001yk@gmail.com 16 | * desc : This is GitHubApp 17 | *18 | */ 19 | 20 | 21 | class GitHubApp : Application(){ 22 | 23 | 24 | 25 | 26 | /** 27 | * 声明一个伴生对象 28 | */ 29 | companion object { 30 | /** 31 | * lateinit : 允许在构造函数之外初始化非空属性 32 | * 为应用级别的 APP 提供全局 Context 33 | */ 34 | lateinit var instance: GitHubApp; 35 | 36 | } 37 | 38 | 39 | /** 40 | * 重写 Application onCreate 生命周期函数 41 | */ 42 | override fun onCreate() { 43 | super.onCreate() 44 | //init GitHubApp 全局上下文 45 | instance = this; 46 | //滑动关闭 Activity 47 | SwipeFinishable.INSTANCE.init(this); 48 | //适配低版本向量图 49 | AppCompatDelegate.setCompatVectorFromResourcesEnabled(true) 50 | //init App 可以获取内部的 Application 级别的 Context 51 | App.init(this); 52 | 53 | 54 | 55 | } 56 | 57 | 58 | /** 59 | * 重写 Application 生命周期函数,刚刚创建出来,比 onCreate 更早 60 | */ 61 | override fun attachBaseContext(base: Context?) { 62 | MultiDex.install(this); 63 | super.attachBaseContext(base) 64 | } 65 | } -------------------------------------------------------------------------------- /app/src/main/java/com/devyk/kotlin_github/adapter/IssueListAdapter.kt: -------------------------------------------------------------------------------- 1 | package com.devyk.kotlin_github.adapter 2 | 3 | import android.support.v7.widget.RecyclerView 4 | import android.view.View 5 | import com.devyk.common.ext.htmlText 6 | import com.devyk.common.utils.githubTimeToDate 7 | import com.devyk.common.utils.view 8 | import com.devyk.kotlin_github.R 9 | import com.devyk.kotlin_github.mvp.base.CommonListAdapter 10 | import com.devyk.kotlin_github.mvp.m.entity.Issue 11 | import kotlinx.android.synthetic.main.item_issue.view.* 12 | import org.jetbrains.anko.imageResource 13 | 14 | /** 15 | *
16 | * author : devyk on 2019-11-05 11:01 17 | * blog : https://juejin.im/user/578259398ac2470061f3a3fb/posts 18 | * github : https://github.com/yangkun19921001 19 | * mailbox : yang1001yk@gmail.com 20 | * desc : This is IssueListAdapter 21 | *22 | */ 23 | class IssueListAdapter : CommonListAdapter
13 | * author : devyk on 2019-11-06 10:02 14 | * blog : https://juejin.im/user/578259398ac2470061f3a3fb/posts 15 | * github : https://github.com/yangkun19921001 16 | * mailbox : yang1001yk@gmail.com 17 | * desc : This is PeopleListAdapter 18 | *19 | */ 20 | class PeopleListAdapter : CommonListAdapter
20 | * author : devyk on 2019-11-05 13:56 21 | * blog : https://juejin.im/user/578259398ac2470061f3a3fb/posts 22 | * github : https://github.com/yangkun19921001 23 | * mailbox : yang1001yk@gmail.com 24 | * desc : This is RepoListAdapter 25 | *26 | */ 27 | class RepoListAdapter() : CommonListAdapter
15 | * author : devyk on 2019-11-05 13:18 16 | * blog : https://juejin.im/user/578259398ac2470061f3a3fb/posts 17 | * github : https://github.com/yangkun19921001 18 | * mailbox : yang1001yk@gmail.com 19 | * desc : This is RepositoryService 20 | *21 | */ 22 | 23 | interface RepositoryApi{ 24 | 25 | @GET("/users/{owner}/repos?type=all") 26 | fun listRepositoriesOfUser(@Path("owner") owner: String, @Query("page") page: Int = 1, @Query("per_page") per_page: Int = 20): Observable
5 | * author : devyk on 2019-10-31 12:50 6 | * blog : https://juejin.im/user/578259398ac2470061f3a3fb/posts 7 | * github : https://github.com/yangkun19921001 8 | * mailbox : yang1001yk@gmail.com 9 | * desc : This is Contacts 10 | *11 | */ 12 | class Contacts { 13 | 14 | public val REQUIRED_TYPE: String 15 | get() = "type" 16 | 17 | val OPTIONAL_LOGIN: String 18 | get() = "login" 19 | } 20 | -------------------------------------------------------------------------------- /app/src/main/java/com/devyk/kotlin_github/config/NavViewItem.kt: -------------------------------------------------------------------------------- 1 | package com.devyk.kotlin_github.config 2 | 3 | import android.os.Bundle 4 | import android.support.annotation.DrawableRes 5 | import android.support.annotation.IdRes 6 | import android.support.v4.app.Fragment 7 | import com.devyk.kotlin_github.R 8 | import com.devyk.kotlin_github.mvp.v.AboutFragment 9 | import com.devyk.kotlin_github.mvp.v.issue.MyIssueFragment 10 | import com.devyk.kotlin_github.mvp.v.people.PeopleFragment 11 | import com.devyk.kotlin_github.mvp.v.repo.RepoFragment 12 | 13 | 14 | class NavViewItem private constructor(val groupId: Int = 0, val title: String, @DrawableRes val icon: Int, val fragmentClass: Class
7 | * author : devyk on 2019-10-31 11:11 8 | * blog : https://juejin.im/user/578259398ac2470061f3a3fb/posts 9 | * github : https://github.com/yangkun19921001 10 | * mailbox : yang1001yk@gmail.com 11 | * desc : This is UserConfig 用户信息管理类 12 | *13 | */ 14 | class UserConfig(path: String) : PropertiesDelegate.AbsProperties(path) { 15 | /** 16 | * 通过属性代理 17 | * 将接口的实现委托给另一个对象 18 | * 将属性访问器的实现委托给另一个对象 19 | */ 20 | var name: String by PROPERTIES 21 | var email: String by PROPERTIES 22 | 23 | 24 | fun config( 25 | name: String = "yangkun19921001", 26 | email: String = "yang1001yk@gmail.com" 27 | 28 | /** 29 | * let 语法支持传递当前this 进去,默认就返回当前 this 30 | */ 31 | ) = let { 32 | it.name = name 33 | it.email = email; 34 | } 35 | 36 | } 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /app/src/main/java/com/devyk/kotlin_github/config/settings/Configs.kt: -------------------------------------------------------------------------------- 1 | 2 | import com.bennyhuo.common.log.logger 3 | import com.devyk.common.App 4 | import com.devyk.common.ext.deviceId 5 | 6 | object Configs { 7 | 8 | object Account{ 9 | val SCOPES = listOf("user", "repo", "notifications", "gist", "admin:org") 10 | const val clientId = "978939bf3ceadc720e5e" 11 | const val clientSecret = "4aa3d83510fb20800e97c55144ccc451f5eaba90" 12 | const val note = "kotlin" 13 | const val noteUrl = "https://github.com/yangkun19921001" 14 | 15 | val fingerPrint by lazy { 16 | (App.getInstance().deviceId + clientId).also { logger.info("fingerPrint: "+it) } 17 | } 18 | } 19 | 20 | } -------------------------------------------------------------------------------- /app/src/main/java/com/devyk/kotlin_github/config/settings/Settings.kt: -------------------------------------------------------------------------------- 1 | 2 | import com.devyk.common.App 3 | import com.devyk.common.config.UserInfo 4 | import com.devyk.common.ext.pref 5 | import com.devyk.kotlin_github.R 6 | 7 | 8 | object Settings { 9 | var lastPage: Int 10 | get() = if(lastPageIdString.isEmpty()) 0 else App.getInstance().resources.getIdentifier(lastPageIdString, "id", App.getInstance().packageName) 11 | set(value) { 12 | lastPageIdString = App.getInstance().resources.getResourceEntryName(value) 13 | } 14 | 15 | val defaultPage 16 | get() = if(UserInfo.isLoginIn()) defaultPageForUser else defaultPageForVisitor 17 | 18 | private var defaultPageForUser by pref(R.id.navRepos) 19 | 20 | private var defaultPageForVisitor by pref(R.id.navRepos) 21 | 22 | private var lastPageIdString by pref("") 23 | 24 | var themeMode by pref("DAY") 25 | 26 | 27 | 28 | } -------------------------------------------------------------------------------- /app/src/main/java/com/devyk/kotlin_github/mvp/base/BaseDetailActivity.kt: -------------------------------------------------------------------------------- 1 | package com.devyk.kotlin_github.mvp.base 2 | 3 | import android.os.Bundle 4 | import android.support.v7.app.AppCompatActivity 5 | import android.view.GestureDetector 6 | import android.view.MenuItem 7 | import android.view.MotionEvent 8 | import com.bennyhuo.swipefinishable.SwipeFinishable 9 | import com.devyk.kotlin_github.R 10 | import com.devyk.kotlin_github.config.Themer 11 | import org.jetbrains.anko.dip 12 | 13 | /** 14 | *
15 | * author : devyk on 2019-11-06 10:22 16 | * blog : https://juejin.im/user/578259398ac2470061f3a3fb/posts 17 | * github : https://github.com/yangkun19921001 18 | * mailbox : yang1001yk@gmail.com 19 | * desc : This is BaseDetailActivity 20 | *21 | */ 22 | abstract class BaseDetailActivity : AppCompatActivity() { 23 | 24 | 25 | /** 26 | * 定义一个滑动返回的委托属性 27 | */ 28 | private val swipeBackTouchDelegate by lazy { 29 | SwipeBackTouchDelegate(this, ::finish) 30 | } 31 | 32 | 33 | override fun onCreate(savedInstanceState: Bundle?) { 34 | super.onCreate(savedInstanceState) 35 | Themer.applyProperTheme(this) 36 | } 37 | 38 | override fun onOptionsItemSelected(item: MenuItem?): Boolean { 39 | when (item!!.itemId) { 40 | android.R.id.home -> { 41 | finish() 42 | } 43 | } 44 | return super.onOptionsItemSelected(item) 45 | } 46 | 47 | override fun finish() { 48 | super.finish() 49 | overridePendingTransition(R.anim.left_in, R.anim.rignt_out) 50 | } 51 | 52 | override fun dispatchTouchEvent(ev: MotionEvent): Boolean { 53 | return swipeBackTouchDelegate.onTouchEvent(ev) || super.dispatchTouchEvent(ev) 54 | } 55 | } 56 | 57 | 58 | class SwipeBackTouchDelegate(val activity: AppCompatActivity, block: () -> Unit) { 59 | companion object { 60 | private const val MIN_FLING_TO_BACK = 2000 61 | } 62 | 63 | private val minFLlingToBack by lazy { 64 | activity.dip(MIN_FLING_TO_BACK) 65 | } 66 | 67 | private val swipeBackDelegate by lazy { 68 | GestureDetector(activity, object : GestureDetector.SimpleOnGestureListener() { 69 | override fun onFling(e1: MotionEvent?, e2: MotionEvent?, velocityX: Float, velocityY: Float): Boolean { 70 | //如果滑动的距离超过 2000 就关闭 71 | return if (velocityX > minFLlingToBack) { 72 | block() 73 | true 74 | } else { 75 | false 76 | } 77 | } 78 | }) 79 | 80 | } 81 | 82 | fun onTouchEvent(event: MotionEvent) = swipeBackDelegate.onTouchEvent(event) 83 | 84 | } 85 | 86 | abstract class BaseDetailSwipeFinishableActivity : AppCompatActivity(), SwipeFinishable.SwipeFinishableActivity { 87 | override fun onCreate(savedInstanceState: Bundle?) { 88 | super.onCreate(savedInstanceState) 89 | Themer.applyProperTheme(this, true) 90 | } 91 | 92 | override fun onOptionsItemSelected(item: MenuItem?): Boolean { 93 | when (item!!.itemId) { 94 | android.R.id.home 95 | -> { 96 | finish() 97 | return true 98 | } 99 | } 100 | return super.onOptionsItemSelected(item) 101 | } 102 | 103 | override fun finishThisActivity() { 104 | super.finish() 105 | } 106 | 107 | override fun finish() { 108 | SwipeFinishable.INSTANCE.finishCurrentActivity() 109 | } 110 | } -------------------------------------------------------------------------------- /app/src/main/java/com/devyk/kotlin_github/mvp/base/CommonListAdapter.kt: -------------------------------------------------------------------------------- 1 | package com.devyk.kotlin_github.mvp.base 2 | 3 | import android.animation.ObjectAnimator 4 | import android.support.annotation.LayoutRes 5 | import android.support.v4.view.ViewCompat 6 | import android.support.v7.widget.RecyclerView 7 | import android.support.v7.widget.RecyclerView.ViewHolder 8 | import android.view.LayoutInflater 9 | import android.view.MotionEvent 10 | import android.view.View 11 | import android.view.ViewGroup 12 | import com.devyk.common.utils.AdapterList 13 | import com.devyk.kotlin_github.R 14 | import kotlinx.android.synthetic.main.item_card.view.* 15 | import org.jetbrains.anko.dip 16 | import org.jetbrains.anko.sdk15.coroutines.onClick 17 | 18 | abstract class CommonListAdapter
11 | * author : devyk on 2019-11-04 14:20 12 | * blog : https://juejin.im/user/578259398ac2470061f3a3fb/posts 13 | * github : https://github.com/yangkun19921001 14 | * mailbox : yang1001yk@gmail.com 15 | * desc : This is CommonListPresenter 16 | *17 | */ 18 | abstract class CommonListPresenter
10 | * author : devyk on 2019-11-06 13:28 11 | * blog : https://juejin.im/user/578259398ac2470061f3a3fb/posts 12 | * github : https://github.com/yangkun19921001 13 | * mailbox : yang1001yk@gmail.com 14 | * desc : This is CommonSinglePageFragment 15 | *16 | */ 17 | 18 | abstract class CommonSinglePageFragment:Fragment(){ 19 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) { 20 | super.onViewCreated(view, savedInstanceState) 21 | (activity as MainActivity).actionBarController.setupWithViewPager(null) 22 | } 23 | } -------------------------------------------------------------------------------- /app/src/main/java/com/devyk/kotlin_github/mvp/base/CommonViewPageAdapter.kt: -------------------------------------------------------------------------------- 1 | package com.devyk.kotlin_github.mvp.base 2 | 3 | import android.support.v4.app.Fragment 4 | import android.support.v4.app.FragmentManager 5 | import android.support.v4.app.FragmentPagerAdapter 6 | import android.support.v4.view.PagerAdapter 7 | import android.view.View 8 | import com.devyk.common.utils.ViewPagerAdapterList 9 | 10 | class CommonViewPageAdapter(childFragmentManager: FragmentManager) : FragmentPagerAdapter(childFragmentManager) { 11 | 12 | val fragmentPages = ViewPagerAdapterList
24 | * author : devyk on 2019-11-01 17:55 25 | * blog : https://juejin.im/user/578259398ac2470061f3a3fb/posts 26 | * github : https://github.com/yangkun19921001 27 | * mailbox : yang1001yk@gmail.com 28 | * desc : This is CommonViewPager 29 | *30 | */ 31 | abstract class CommonViewPagerFragment : Fragment(), OnAccountStateChangeLister, ViewPagerFragmentConfig { 32 | 33 | /** 34 | * lateinit 延迟初始化 ViewPager 35 | */ 36 | private lateinit var viewPager: ViewPager 37 | /** 38 | * 延迟加载 ViewPagerAdapter 39 | */ 40 | private val viewPageAdapter by lazy { 41 | CommonViewPageAdapter(childFragmentManager) 42 | } 43 | 44 | 45 | override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { 46 | //使用 anko 创建动态布局,比 XML 快 4 倍 但是能使用 XML 的地方还是尽力使用 XML 布局 47 | return UI { 48 | verticalLayout { 49 | viewPager = viewPager { 50 | id = R.id.viewPager 51 | } 52 | viewPager.adapter = viewPageAdapter 53 | } 54 | }.view 55 | } 56 | 57 | 58 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) { 59 | super.onViewCreated(view, savedInstanceState) 60 | // tablayout set ViewPager 61 | (activity as MainActivity).actionBarController.setupWithViewPager(viewPager) 62 | //根据配置添加 主页面 63 | viewPageAdapter.fragmentPages.addAll( 64 | if (UserInfo.isLoginIn()) { 65 | //交于子类决定 66 | getFragmentPagesLoggedIn() 67 | } else { 68 | //交于子类决定 69 | getFragmentPagesNotLoggedIn() 70 | } 71 | ) 72 | } 73 | 74 | 75 | override fun onLogin(user: User) { 76 | viewPageAdapter.fragmentPages.clear() 77 | viewPageAdapter.fragmentPages.addAll(getFragmentPagesLoggedIn()) 78 | } 79 | 80 | override fun onLogOut() { 81 | viewPageAdapter.fragmentPages.clear() 82 | viewPageAdapter.fragmentPages.addAll(getFragmentPagesNotLoggedIn()) 83 | } 84 | 85 | 86 | override fun onCreate(savedInstanceState: Bundle?) { 87 | super.onCreate(savedInstanceState) 88 | //添加登录成功或失败的监听 89 | AccountManager.onAccountStateChangeLister.add(this) 90 | } 91 | 92 | override fun onDestroy() { 93 | super.onDestroy() 94 | AccountManager.onAccountStateChangeLister.remove(this) 95 | } 96 | } 97 | 98 | 99 | interface ViewPagerFragmentConfig { 100 | /** 101 | * 登录成功需要的模块 102 | */ 103 | fun getFragmentPagesLoggedIn(): List
8 | * author : devyk on 2019-11-04 16:00 9 | * blog : https://juejin.im/user/578259398ac2470061f3a3fb/posts 10 | * github : https://github.com/yangkun19921001 11 | * mailbox : yang1001yk@gmail.com 12 | * desc : This is DataProvider 13 | *14 | */ 15 | interface DataProvider
8 | * author : devyk on 2019-11-04 14:58 9 | * blog : https://juejin.im/user/578259398ac2470061f3a3fb/posts 10 | * github : https://github.com/yangkun19921001 11 | * mailbox : yang1001yk@gmail.com 12 | * desc : This is GitHubPaging 13 | *14 | */ 15 | 16 | class GitHubPaging
10 | * author : devyk on 2019-11-04 15:56 11 | * blog : https://juejin.im/user/578259398ac2470061f3a3fb/posts 12 | * github : https://github.com/yangkun19921001 13 | * mailbox : yang1001yk@gmail.com 14 | * desc : This is ListPage 15 | *16 | */ 17 | 18 | abstract class ListPage
22 | * author : devyk on 2019-10-31 15:09 23 | * blog : https://juejin.im/user/578259398ac2470061f3a3fb/posts 24 | * github : https://github.com/yangkun19921001 25 | * mailbox : yang1001yk@gmail.com 26 | * desc : This is AccountManager 27 | *28 | */ 29 | 30 | /** 31 | * 定义一个回调 32 | */ 33 | interface OnAccountStateChangeLister { 34 | fun onLogin(user: User) 35 | fun onLogOut() 36 | } 37 | 38 | 39 | /** 40 | * 直接把 AccountManager 以 object 定义成单例 41 | */ 42 | object AccountManager { 43 | 44 | 45 | private var userJson by pref(""); 46 | 47 | var currentUser: User? = null 48 | get() { 49 | if (field == null && userJson.isNotEmpty()) { 50 | field = Gson().fromJson
11 | * author : devyk on 2019-11-05 10:55 12 | * blog : https://juejin.im/user/578259398ac2470061f3a3fb/posts 13 | * github : https://github.com/yangkun19921001 14 | * mailbox : yang1001yk@gmail.com 15 | * desc : This is IssueModel 16 | *17 | */ 18 | class MyIssuePage : ListPage
11 | * author : devyk on 2019-11-06 09:52 12 | * blog : https://juejin.im/user/578259398ac2470061f3a3fb/posts 13 | * github : https://github.com/yangkun19921001 14 | * mailbox : yang1001yk@gmail.com 15 | * desc : This is PeopleModel 16 | *17 | */ 18 | 19 | class PeoplePageParams(val type: String, val login: String?) 20 | 21 | class PeoplePage(val params: PeoplePageParams) : ListPage
16 | * author : devyk on 2019-11-05 13:09 17 | * blog : https://juejin.im/user/578259398ac2470061f3a3fb/posts 18 | * github : https://github.com/yangkun19921001 19 | * mailbox : yang1001yk@gmail.com 20 | * desc : This is RepoModel 21 | *22 | */ 23 | class RepoListPage(val owner: User?) : ListPage
10 | * author : devyk on 2019-10-30 15:58 11 | * blog : https://juejin.im/user/578259398ac2470061f3a3fb/posts 12 | * github : https://github.com/yangkun19921001 13 | * mailbox : yang1001yk@gmail.com 14 | * desc : This is LoginPresenter 15 | *16 | */ 17 | class LoginPresenter : BasePresenter
11 | * author : devyk on 2019-11-01 11:10 12 | * blog : https://juejin.im/user/578259398ac2470061f3a3fb/posts 13 | * github : https://github.com/yangkun19921001 14 | * mailbox : yang1001yk@gmail.com 15 | * desc : This is MainPersenter 16 | *17 | */ 18 | class MainPersenter : BasePresenter
11 | * author : devyk on 2019-11-05 10:53 12 | * blog : https://juejin.im/user/578259398ac2470061f3a3fb/posts 13 | * github : https://github.com/yangkun19921001 14 | * mailbox : yang1001yk@gmail.com 15 | * desc : This is MyIssuePresenter 16 | *17 | */ 18 | class MyIssuePresenter() : CommonListPresenter
12 | * author : devyk on 2019-11-06 09:58 13 | * blog : https://juejin.im/user/578259398ac2470061f3a3fb/posts 14 | * github : https://github.com/yangkun19921001 15 | * mailbox : yang1001yk@gmail.com 16 | * desc : This is PeopleListPresenter 17 | *18 | */ 19 | class PeopleListPresenter : CommonListPresenter
11 | * author : devyk on 2019-11-05 13:06 12 | * blog : https://juejin.im/user/578259398ac2470061f3a3fb/posts 13 | * github : https://github.com/yangkun19921001 14 | * mailbox : yang1001yk@gmail.com 15 | * desc : This is RepoListPresenter 16 | *17 | */ 18 | class RepoListPresenter : CommonListPresenter
21 | * author : devyk on 2019-11-01 11:32 22 | * blog : https://juejin.im/user/578259398ac2470061f3a3fb/posts 23 | * github : https://github.com/yangkun19921001 24 | * mailbox : yang1001yk@gmail.com 25 | * desc : This is AboutFragment 26 | *27 | */ 28 | class AboutFragment : CommonSinglePageFragment() { 29 | override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { 30 | return AboutFragmentUIManager().createView(AnkoContext.Companion.create(context!!, this)) 31 | } 32 | } 33 | 34 | class AboutFragmentUIManager : AnkoComponent
9 | * author : devyk on 2019-11-01 11:31 10 | * blog : https://juejin.im/user/578259398ac2470061f3a3fb/posts 11 | * github : https://github.com/yangkun19921001 12 | * mailbox : yang1001yk@gmail.com 13 | * desc : This is MyIssueFragment 14 | *15 | */ 16 | class MyIssueFragment : CommonViewPagerFragment() { 17 | override fun getFragmentPagesLoggedIn(): List
11 | * author : devyk on 2019-11-01 11:31 12 | * blog : https://juejin.im/user/578259398ac2470061f3a3fb/posts 13 | * github : https://github.com/yangkun19921001 14 | * mailbox : yang1001yk@gmail.com 15 | * desc : This is PeopleFragment 16 | *17 | */ 18 | class PeopleFragment : CommonViewPagerFragment() { 19 | 20 | 21 | /** 22 | * 当登录成功的时候加载 Followers、Following、ALL 3 个页面 23 | */ 24 | override fun getFragmentPagesNotLoggedIn(): List
22 | * author : devyk on 2019-11-04 11:07 23 | * blog : https://juejin.im/user/578259398ac2470061f3a3fb/posts 24 | * github : https://github.com/yangkun19921001 25 | * mailbox : yang1001yk@gmail.com 26 | * desc : This is PeopleListFragment 27 | *28 | */ 29 | class PeopleListFragment : CommonListFragment
12 | * author : devyk on 2019-11-01 11:30 13 | * blog : https://juejin.im/user/578259398ac2470061f3a3fb/posts 14 | * github : https://github.com/yangkun19921001 15 | * mailbox : yang1001yk@gmail.com 16 | * desc : This is RepoFragment 17 | *18 | */ 19 | class RepoFragment : CommonViewPagerFragment() { 20 | override fun getFragmentPagesLoggedIn(): List
12 | * author : devyk on 2019-11-05 13:05 13 | * blog : https://juejin.im/user/578259398ac2470061f3a3fb/posts 14 | * github : https://github.com/yangkun19921001 15 | * mailbox : yang1001yk@gmail.com 16 | * desc : This is RepoListFragment 17 | *18 | */ 19 | class RepoListFragment : CommonListFragment
9 | * author : devyk on 2019-10-29 16:11 10 | * blog : https://juejin.im/user/578259398ac2470061f3a3fb/posts 11 | * github : https://github.com/yangkun19921001 12 | * mailbox : yang1001yk@gmail.com 13 | * desc : This is BooleanExpTest 14 | *15 | */ 16 | class BooleanExpTest { 17 | 18 | 19 | @Test 20 | fun test(){ 21 | true.yes { } 22 | } 23 | } -------------------------------------------------------------------------------- /app/src/test/java/com/devyk/kotlin_github/ExampleUnitTest.kt: -------------------------------------------------------------------------------- 1 | package com.devyk.kotlin_github 2 | 3 | import org.junit.Test 4 | 5 | import org.junit.Assert.* 6 | 7 | /** 8 | * Example local unit test, which will execute on the development machine (host). 9 | * 10 | * See [testing documentation](http://d.android.com/tools/testing). 11 | */ 12 | class ExampleUnitTest { 13 | @Test 14 | fun addition_isCorrect() { 15 | assertEquals(4, 2 + 2) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | apply from: "config.gradle" 3 | buildscript { 4 | ext.kotlin_version = '1.3.50' 5 | ext.support_version = '28.0.0' 6 | ext.kotlinx_coroutines_version = '1.1.1' 7 | ext.anko_version='0.10.8' 8 | repositories { 9 | google() 10 | jcenter() 11 | 12 | } 13 | dependencies { 14 | classpath 'com.android.tools.build:gradle:3.4.1' 15 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 16 | // NOTE: Do not place your application dependencies here; they belong 17 | // in the individual module build.gradle files 18 | } 19 | } 20 | 21 | allprojects { 22 | repositories { 23 | google() 24 | jcenter() 25 | maven { url "https://jitpack.io" } 26 | } 27 | } 28 | 29 | task clean(type: Delete) { 30 | delete rootProject.buildDir 31 | } 32 | -------------------------------------------------------------------------------- /common/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /common/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | 3 | apply plugin: 'kotlin-android' 4 | 5 | android { 6 | compileSdkVersion rootProject.ext.android.compileSdkVersion 7 | 8 | defaultConfig { 9 | minSdkVersion rootProject.ext.android.minSdkVersion 10 | targetSdkVersion rootProject.ext.android.targetSdkVersion 11 | versionCode rootProject.ext.android.versionCode 12 | versionName rootProject.ext.android.versionName 13 | 14 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 15 | 16 | } 17 | 18 | buildTypes { 19 | release { 20 | minifyEnabled false 21 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 22 | } 23 | } 24 | 25 | } 26 | 27 | dependencies { 28 | implementation fileTree(dir: 'libs', include: ['*.jar']) 29 | 30 | 31 | testImplementation rootProject.ext.testDeps["junit"] 32 | androidTestImplementation rootProject.ext.testDeps["runner"] 33 | androidTestImplementation rootProject.ext.testDeps["espresso-core"] 34 | 35 | 36 | api"org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" 37 | api "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version" 38 | 39 | api "org.jetbrains.kotlinx:kotlinx-coroutines-core:$kotlinx_coroutines_version" 40 | api "org.jetbrains.kotlinx:kotlinx-coroutines-android:$kotlinx_coroutines_version" 41 | 42 | api rootProject.ext.supportDeps["design"] 43 | api rootProject.ext.supportDeps["cardview"] 44 | api rootProject.ext.supportDeps["appcompatv7"] 45 | 46 | api "com.squareup.okhttp3:logging-interceptor:3.8.0" 47 | api "com.squareup.okhttp3:okhttp:3.8.0" 48 | api "com.squareup.retrofit2:converter-gson:2.3.0" 49 | api "com.squareup.retrofit2:adapter-rxjava2:2.6.0" 50 | api "com.jakewharton.retrofit:retrofit2-kotlin-coroutines-experimental-adapter:1.0.0" 51 | api "io.reactivex.rxjava2:rxandroid:2.1.1" 52 | api "io.reactivex.rxjava2:rxjava:2.2.13" 53 | api 'com.github.bumptech.glide:glide:4.3.1' 54 | 55 | 56 | // Appcompat-v7 (Anko Layouts) 57 | // implementation "org.jetbrains.anko:anko-design-coroutines:$anko_version" 58 | api "org.jetbrains.anko:anko-appcompat-v7:$anko_version" 59 | // implementation "org.jetbrains.anko:anko-design-coroutines:$anko_version" 60 | api "org.jetbrains.anko:anko-coroutines:$anko_version" 61 | 62 | // CardView-v7 63 | api "org.jetbrains.anko:anko-cardview-v7:$anko_version" 64 | 65 | 66 | // GridLayout-v7 67 | api "org.jetbrains.anko:anko-gridlayout-v7:$anko_version" 68 | 69 | // Percent 70 | api "org.jetbrains.anko:anko-percent:$anko_version" 71 | 72 | // RecyclerView-v7 73 | api "org.jetbrains.anko:anko-recyclerview-v7:$anko_version" 74 | api "org.jetbrains.anko:anko-recyclerview-v7-coroutines:$anko_version" 75 | 76 | // Support-v4 (only Anko Commons) 77 | api "org.jetbrains.anko:anko-support-v4-commons:$anko_version" 78 | 79 | // Support-v4 (Anko Layouts) 80 | api "org.jetbrains.anko:anko-support-v4:$anko_version" 81 | 82 | // ConstraintLayout 83 | api "org.jetbrains.anko:anko-constraint-layout:$anko_version" 84 | 85 | 86 | // 左滑关闭 Activity https://github.com/enbandari/SwipeFinishableActivity 87 | api "com.bennyhuo.swipefinishable:swipefinishable:1.0-rc2" 88 | // Appcompat-v7 (only Anko Commons) 89 | api "org.jetbrains.anko:anko-appcompat-v7-commons:$anko_version" 90 | api "org.jetbrains.anko:anko-sdk15-coroutines:$anko_version" 91 | api "org.jetbrains.anko:anko-sdk15:$anko_version" 92 | 93 | api 'org.slf4j:slf4j-api:1.7.21' 94 | 95 | /* 源码地址:https://github.com/enbandari/RichText;这个项目是从 https://github.com/zzhoujay/RichText 修改而来的 96 |
原因:原框架使用了 Android 系统的 Html 解析器,对 pre 和 code 没有支持
97 | 框架中使用了修改自 https://github.com/Pixplicity/HtmlCompat 的 Html 解析器
98 | */
99 | implementation('com.github.enbandari.RichText:richtext:e85882c698') {
100 | exclude(group: "com.android.support")
101 | }
102 |
103 |
104 | }
105 |
--------------------------------------------------------------------------------
/common/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/common/src/androidTest/java/com/devyk/common/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package com.devyk.common;
2 |
3 | import android.content.Context;
4 | import androidx.test.InstrumentationRegistry;
5 | import androidx.test.runner.AndroidJUnit4;
6 |
7 | import org.junit.Test;
8 | import org.junit.runner.RunWith;
9 |
10 | import static org.junit.Assert.*;
11 |
12 | /**
13 | * Instrumented test, which will execute on an Android device.
14 | *
15 | * @see Testing documentation
16 | */
17 | @RunWith(AndroidJUnit4.class)
18 | public class ExampleInstrumentedTest {
19 | @Test
20 | public void useAppContext() {
21 | // Context of the app under test.
22 | Context appContext = InstrumentationRegistry.getTargetContext();
23 |
24 | assertEquals("com.devyk.common.test", appContext.getPackageName());
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/common/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
9 | * author : devyk on 2019-10-31 13:59 10 | * blog : https://juejin.im/user/578259398ac2470061f3a3fb/posts 11 | * github : https://github.com/yangkun19921001 12 | * mailbox : yang1001yk@gmail.com 13 | * desc : This is App 14 | *15 | */ 16 | object App { 17 | 18 | private lateinit var instance: Context 19 | 20 | 21 | fun init(context: Context) { 22 | instance = context 23 | } 24 | 25 | 26 | fun getInstance(): Context { 27 | return instance; 28 | } 29 | } -------------------------------------------------------------------------------- /common/src/main/java/com/devyk/common/anno/PoKo.kt: -------------------------------------------------------------------------------- 1 | package com.devyk.common.anno 2 | 3 | 4 | @Retention(AnnotationRetention.BINARY)//注解被编译到二进制文件,但不会被加载到 JVM 中。 反射不可见。 5 | @Target(AnnotationTarget.CLASS)//用于类上 6 | annotation class PoKo //可以给一个类型进行注解,类、接口、对象、甚至注解类本身 -------------------------------------------------------------------------------- /common/src/main/java/com/devyk/common/compat/Tls12.kt: -------------------------------------------------------------------------------- 1 | package com.bennyhuo.github.network.compat 2 | 3 | import android.os.Build 4 | import android.util.Log 5 | import com.devyk.common.compat.Tls12SocketFactory 6 | import okhttp3.ConnectionSpec 7 | import okhttp3.OkHttpClient 8 | import okhttp3.TlsVersion 9 | import javax.net.ssl.SSLContext 10 | 11 | 12 | 13 | fun OkHttpClient.Builder.enableTls12OnPreLollipop(): OkHttpClient.Builder { 14 | if (Build.VERSION.SDK_INT in 16..21) { 15 | try { 16 | val sc = SSLContext.getInstance("TLSv1.2") 17 | sc.init(null, null, null) 18 | sslSocketFactory(Tls12SocketFactory(sc.getSocketFactory())) 19 | 20 | val cs = ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS) 21 | .tlsVersions(TlsVersion.TLS_1_2) 22 | .build() 23 | 24 | val specs = listOf(cs, ConnectionSpec.COMPATIBLE_TLS, ConnectionSpec.CLEARTEXT) 25 | connectionSpecs(specs) 26 | } catch (exc: Exception) { 27 | Log.e("OkHttpTLSCompat", "Error while setting TLS 1.2", exc) 28 | } 29 | 30 | } 31 | 32 | return this 33 | } -------------------------------------------------------------------------------- /common/src/main/java/com/devyk/common/compat/Tls12SocketFactory.java: -------------------------------------------------------------------------------- 1 | package com.devyk.common.compat; 2 | 3 | import javax.net.ssl.SSLSocket; 4 | import javax.net.ssl.SSLSocketFactory; 5 | import java.io.IOException; 6 | import java.net.InetAddress; 7 | import java.net.Socket; 8 | import java.net.UnknownHostException; 9 | 10 | /** 11 | * Enables TLS v1.2 when creating SSLSockets. 12 | * 13 | * For some reason, android supports TLS v1.2 from API 16, but enables it by 14 | * default only from API 20. 15 | * @link https://developer.android.com/reference/javax/net/ssl/SSLSocket.html 16 | * @see SSLSocketFactory 17 | */ 18 | public class Tls12SocketFactory extends SSLSocketFactory { 19 | private static final String[] TLS_V12_ONLY = {"TLSv1.2"}; 20 | 21 | final SSLSocketFactory delegate; 22 | 23 | public Tls12SocketFactory(SSLSocketFactory base) { 24 | this.delegate = base; 25 | } 26 | 27 | @Override 28 | public String[] getDefaultCipherSuites() { 29 | return delegate.getDefaultCipherSuites(); 30 | } 31 | 32 | @Override 33 | public String[] getSupportedCipherSuites() { 34 | return delegate.getSupportedCipherSuites(); 35 | } 36 | 37 | @Override 38 | public Socket createSocket(Socket s, String host, int port, boolean autoClose) throws IOException { 39 | return patch(delegate.createSocket(s, host, port, autoClose)); 40 | } 41 | 42 | @Override 43 | public Socket createSocket(String host, int port) throws IOException, UnknownHostException { 44 | return patch(delegate.createSocket(host, port)); 45 | } 46 | 47 | @Override 48 | public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException, UnknownHostException { 49 | return patch(delegate.createSocket(host, port, localHost, localPort)); 50 | } 51 | 52 | @Override 53 | public Socket createSocket(InetAddress host, int port) throws IOException { 54 | return patch(delegate.createSocket(host, port)); 55 | } 56 | 57 | @Override 58 | public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException { 59 | return patch(delegate.createSocket(address, port, localAddress, localPort)); 60 | } 61 | 62 | private Socket patch(Socket s) { 63 | if (s instanceof SSLSocket) { 64 | ((SSLSocket) s).setEnabledProtocols(TLS_V12_ONLY); 65 | } 66 | return s; 67 | } 68 | } -------------------------------------------------------------------------------- /common/src/main/java/com/devyk/common/config/UserInfo.kt: -------------------------------------------------------------------------------- 1 | package com.devyk.common.config 2 | 3 | import com.devyk.common.ext.pref 4 | 5 | /** 6 | *
7 | * author : devyk on 2019-11-01 09:47 8 | * blog : https://juejin.im/user/578259398ac2470061f3a3fb/posts 9 | * github : https://github.com/yangkun19921001 10 | * mailbox : yang1001yk@gmail.com 11 | * desc : This is UserInfo 12 | *13 | */ 14 | object UserInfo { 15 | /** 16 | * 属性委托代理执行 17 | */ 18 | var authID by pref(-1) 19 | var username by pref("") 20 | var password by pref("") 21 | var token by pref("") 22 | 23 | /** 24 | * 判断是否登录 25 | * 26 | */ 27 | fun isLoginIn(): Boolean = token.isNotEmpty() 28 | } -------------------------------------------------------------------------------- /common/src/main/java/com/devyk/common/ext/BooleanExp.kt: -------------------------------------------------------------------------------- 1 | package com.devyk.common.ext 2 | 3 | /** 4 | *
5 | * author : devyk on 2019-10-29 15:54 6 | * blog : https://juejin.im/user/578259398ac2470061f3a3fb/posts 7 | * github : https://github.com/yangkun19921001 8 | * mailbox : yang1001yk@gmail.com 9 | * desc : This is BooleanExp 10 | *11 | */ 12 | 13 | /** 14 | * sealed: 声明一个密封类(限制子类化的类)@see http://www.kotlincn.net/docs/reference/sealed-classes.html 15 | * out : 将类型参数标记为型变 16 | */ 17 | sealed class BooleanExp
5 | * author : devyk on 2019-11-05 13:57 6 | * blog : https://juejin.im/user/578259398ac2470061f3a3fb/posts 7 | * github : https://github.com/yangkun19921001 8 | * mailbox : yang1001yk@gmail.com 9 | * desc : This is NumberExt 10 | *11 | */ 12 | fun Int.toKilo(): String{ 13 | return if(this > 700){ 14 | "${(Math.round(this / 100f) / 10f)}k" 15 | }else{ 16 | "$this" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /common/src/main/java/com/devyk/common/ext/PrefExt.kt: -------------------------------------------------------------------------------- 1 | package com.devyk.common.ext 2 | 3 | import com.devyk.common.App 4 | import kotlin.reflect.jvm.jvmName 5 | 6 | 7 | inline fun
10 | * author : devyk on 2019-10-29 16:13 11 | * blog : https://juejin.im/user/578259398ac2470061f3a3fb/posts 12 | * github : https://github.com/yangkun19921001 13 | * mailbox : yang1001yk@gmail.com 14 | * desc : This is PreferencesExp SharedpreFerences 扩展 15 | *16 | */ 17 | 18 | class Preference
12 | * author : devyk on 2019-10-30 18:21 13 | * blog : https://juejin.im/user/578259398ac2470061f3a3fb/posts 14 | * github : https://github.com/yangkun19921001 15 | * mailbox : yang1001yk@gmail.com 16 | * desc : This is PropertiesDelegate 读取配置文件封装 17 | *18 | */ 19 | class PropertiesDelegate(private val path: String) { 20 | 21 | 22 | 23 | 24 | 25 | /** 26 | * 利用 lateinit 关键字,允许初始化一个非空属性 27 | */ 28 | private lateinit var url :URL 29 | 30 | 31 | 32 | 33 | /** 34 | * 将 Properties 对象委托给 properties 属性 ,通过 by lazy 来延迟加载 35 | */ 36 | private val properties :Properties by lazy { 37 | val pro = Properties() 38 | /** 39 | * run 函数 40 | */ 41 | url.run { 42 | 43 | /** 44 | * use 是 Closeable 的扩展函数,内部已经调用 try 捕获异常了 45 | */ 46 | javaClass.getResourceAsStream(path).use { 47 | pro.load(it) 48 | } 49 | javaClass.getResource(path) 50 | } 51 | 52 | //要求最后一行返回 Properties 对象 53 | pro 54 | } 55 | 56 | 57 | 58 | operator fun
14 | * author : devyk on 2019-11-05 11:07 15 | * blog : https://juejin.im/user/578259398ac2470061f3a3fb/posts 16 | * github : https://github.com/yangkun19921001 17 | * mailbox : yang1001yk@gmail.com 18 | * desc : This is ViewExt 19 | *20 | */ 21 | 22 | var TextView.markdownText: String 23 | set(value) { 24 | RichText.fromMarkdown(value).into(this) 25 | } 26 | get() = text.toString() 27 | 28 | var TextView.htmlText: String 29 | set(value) { 30 | RichText.fromHtml(value).into(this) 31 | } 32 | get() = text.toString() 33 | 34 | inline fun ViewManager.avatarImageView(): AppCompatAvatarImageView = avatarImageView() {} 35 | inline fun ViewManager.avatarImageView(init: (@AnkoViewDslMarker AppCompatAvatarImageView).() -> Unit): AppCompatAvatarImageView { 36 | return ankoView({ ctx: Context -> AppCompatAvatarImageView(ctx) }, theme = 0) { init() } 37 | } -------------------------------------------------------------------------------- /common/src/main/java/com/devyk/common/ext/bindExtra.kt: -------------------------------------------------------------------------------- 1 | package com.devyk.common.ext 2 | 3 | import android.app.Activity 4 | import android.support.v4.app.Fragment 5 | import kotlin.properties.ReadOnlyProperty 6 | import kotlin.reflect.KProperty 7 | 8 | fun Activity.bindExtra(key: String) = BindLoader(key) 9 | 10 | fun Fragment.bindArgument(key: String) = BindLoader(key) 11 | 12 | fun android.app.Fragment.bindArgument(key: String) = BindLoader(key) 13 | 14 | private class IntentDelegate
{ 12 | 13 | protected val TAG = javaClass.simpleName; 14 | 15 | final override val p: P 16 | 17 | init { 18 | p = createPresenterKt() 19 | p.v = this 20 | } 21 | 22 | private fun createPresenterKt(): P { 23 | sequence { 24 | var thisClass: KClass<*> = this@BaseActivity::class 25 | while (true) { 26 | yield(thisClass.supertypes) 27 | thisClass = thisClass.supertypes.firstOrNull()?.jvmErasure ?: break 28 | } 29 | }.flatMap { 30 | it.flatMap { it.arguments }.asSequence() 31 | }.first { 32 | it.type?.jvmErasure?.isSubclassOf(IPresenter::class) ?: false 33 | }.let { 34 | return it.type!!.jvmErasure.primaryConstructor!!.call() as P 35 | } 36 | } 37 | 38 | private fun createPresenter(): P { 39 | sequence{ 40 | var thisClass: Class<*> = this@BaseActivity.javaClass 41 | while (true) { 42 | yield(thisClass.genericSuperclass) 43 | thisClass = thisClass.superclass ?: break 44 | } 45 | }.filter { 46 | it is ParameterizedType 47 | }.flatMap { 48 | (it as ParameterizedType).actualTypeArguments.asSequence() 49 | }.first { 50 | it is Class<*> && IPresenter::class.java.isAssignableFrom(it) 51 | }.let { 52 | return (it as Class
).newInstance()
53 | }
54 | }
55 |
56 | override fun onCreate(savedInstanceState: Bundle?) {
57 | super.onCreate(savedInstanceState)
58 | p.onCreate(savedInstanceState)
59 | }
60 |
61 | override fun onViewStateRestored(savedInstanceState: Bundle?) {}
62 |
63 | override fun onStart() {
64 | super.onStart()
65 | p.onStart()
66 | }
67 |
68 | override fun onResume() {
69 | super.onResume()
70 | p.onResume()
71 | }
72 |
73 | override fun onPause() {
74 | super.onPause()
75 | p.onPause()
76 | }
77 |
78 | override fun onStop() {
79 | super.onStop()
80 | p.onStop()
81 | }
82 |
83 | override fun onDestroy() {
84 | p.onDestroy()
85 | super.onDestroy()
86 | }
87 |
88 | override fun onSaveInstanceState(outState: Bundle) {
89 | super.onSaveInstanceState(outState)
90 | p.onSaveInstanceState(outState)
91 | }
92 |
93 | override fun onRestoreInstanceState(savedInstanceState: Bundle?) {
94 | super.onRestoreInstanceState(savedInstanceState)
95 | onViewStateRestored(savedInstanceState)
96 | p.onViewStateRestored(savedInstanceState)
97 | }
98 |
99 |
100 | }
101 |
--------------------------------------------------------------------------------
/common/src/main/java/com/devyk/common/mvp/impl/BaseFragment.kt:
--------------------------------------------------------------------------------
1 |
2 | import android.os.Bundle
3 | import android.support.v4.app.Fragment
4 | import java.lang.reflect.ParameterizedType
5 | import java.lang.reflect.Type
6 | import kotlin.reflect.KClass
7 | import kotlin.reflect.full.isSubclassOf
8 | import kotlin.reflect.full.primaryConstructor
9 | import kotlin.reflect.jvm.jvmErasure
10 |
11 | abstract class BaseFragment , Fragment() {
12 | override val p: P
13 |
14 | init {
15 | p = createpKt()
16 | p.v = this
17 | }
18 |
19 | private fun createpKt(): P {
20 | sequence {
21 | var thisClass: KClass<*> = this@BaseFragment::class
22 | while (true){
23 | yield(thisClass.supertypes)
24 | thisClass = thisClass.supertypes.firstOrNull()?.jvmErasure?: break
25 | }
26 | }.flatMap {
27 | it.flatMap { it.arguments }.asSequence()
28 | }.first {
29 | it.type?.jvmErasure?.isSubclassOf(IPresenter::class) ?: false
30 | }.let {
31 | return it.type!!.jvmErasure.primaryConstructor!!.call() as P
32 | }
33 | }
34 |
35 | private fun createp(): P {
36 | sequence ).newInstance()
50 | }
51 | }
52 |
53 | override fun onCreate(savedInstanceState: Bundle?) {
54 | super.onCreate(savedInstanceState)
55 | p.onCreate(savedInstanceState)
56 | }
57 |
58 | override fun onStart() {
59 | super.onStart()
60 | p.onStart()
61 | }
62 |
63 | override fun onResume() {
64 | super.onResume()
65 | p.onResume()
66 | }
67 |
68 | override fun onPause() {
69 | super.onPause()
70 | p.onPause()
71 | }
72 |
73 | override fun onStop() {
74 | super.onStop()
75 | p.onStop()
76 | }
77 |
78 | override fun onDestroy() {
79 | p.onDestroy()
80 | super.onDestroy()
81 | }
82 |
83 | override fun onSaveInstanceState(outState: Bundle) {
84 | super.onSaveInstanceState(outState)
85 | p.onSaveInstanceState(outState)
86 | }
87 |
88 | override fun onViewStateRestored(savedInstanceState: Bundle?) {
89 | super.onViewStateRestored(savedInstanceState)
90 | p.onViewStateRestored(savedInstanceState)
91 | }
92 | }
--------------------------------------------------------------------------------
/common/src/main/java/com/devyk/common/mvp/impl/BasePresenter.kt:
--------------------------------------------------------------------------------
1 |
2 | import android.content.res.Configuration
3 | import android.os.Bundle
4 |
5 | abstract class BasePresenter
24 | * author : devyk on 2019-10-31 12:53
25 | * blog : https://juejin.im/user/578259398ac2470061f3a3fb/posts
26 | * github : https://github.com/yangkun19921001
27 | * mailbox : yang1001yk@gmail.com
28 | * desc : This is RESTFulService
29 | *
30 | */
31 |
32 | private const val BASE_URL = "https://api.github.com"
33 |
34 |
35 | //通过一个 QueryParameter 让 CacheInterceptor 添加 no-cache
36 | public const val FORCE_NETWORK = "forceNetwork"
37 | /**
38 | * 缓存大小
39 | */
40 | private const val OKHTTP_CACHE_SIZE = 1024 * 1024 * 10L
41 |
42 | /**
43 | * 定义一个 cache
44 | */
45 | private val cacheFile by lazy {
46 | File(App.getInstance().cacheDir,"Kotlin_GitHub").apply { ensureDir() }
47 | }
48 |
49 | /**
50 | * 定义 retrofit 对象
51 | */
52 | val RETROFIT by lazy {
53 | Retrofit.Builder()
54 | //支持 Rxjava2 默认添加 子线程 + 主线程
55 | .addCallAdapterFactory(RxJava2CallAdapterFactory2.createWithScheduler(Schedulers.io(),AndroidSchedulers.mainThread()))
56 | //支持数据转换
57 | .addConverterFactory(GsonConverterFactory.create())
58 | .client(OKHTTPCLIENT)
59 | .baseUrl(BASE_URL)
60 | .build()
61 |
62 |
63 | }
64 |
65 |
66 |
67 | /**
68 | * 定义 OKHttpClient
69 | */
70 | private val OKHTTPCLIENT by lazy {
71 | OkHttpClient.Builder()
72 | .addInterceptor(AcceptInterceptor())
73 | .addInterceptor(HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY))
74 | .addInterceptor(CacheInterceptor())
75 | .addInterceptor(AuthInterceptor())
76 | .connectTimeout(60,TimeUnit.SECONDS)
77 | .readTimeout(60,TimeUnit.SECONDS)
78 | .writeTimeout(60,TimeUnit.SECONDS)
79 | .cache(Cache(cacheFile,OKHTTP_CACHE_SIZE))
80 | .enableTls12OnPreLollipop()
81 | .build()
82 | }
--------------------------------------------------------------------------------
/common/src/main/java/com/devyk/common/network/interceptor/AcceptInterceptor.kt:
--------------------------------------------------------------------------------
1 | package com.devyk.common.network.interceptor
2 |
3 | import okhttp3.Interceptor
4 | import okhttp3.Interceptor.Chain
5 | import okhttp3.Response
6 |
7 | class AcceptInterceptor : Interceptor {
8 | override fun intercept(chain: Chain): Response {
9 | val original = chain.request()
10 | return chain.proceed(original.newBuilder()
11 | .apply {
12 | header("accept", "application/vnd.github.v3.full+json, ${original.header("accept") ?: ""}")
13 | }
14 | .build())
15 | }
16 | }
--------------------------------------------------------------------------------
/common/src/main/java/com/devyk/common/network/interceptor/AuthInterceptor.kt:
--------------------------------------------------------------------------------
1 | package com.devyk.common.network.interceptor
2 |
3 | import android.accounts.AccountManager
4 | import android.util.Base64
5 | import com.devyk.common.config.UserInfo
6 | import okhttp3.Interceptor
7 | import okhttp3.Interceptor.Chain
8 | import okhttp3.Response
9 |
10 | class AuthInterceptor: Interceptor{
11 | override fun intercept(chain: Chain): Response {
12 | val original = chain.request()
13 | return chain.proceed(original.newBuilder()
14 | .apply {
15 | when{
16 | original.url().pathSegments().contains("authorizations") ->{
17 | val userCredentials = UserInfo.username + ":" + UserInfo.password
18 | val auth = "Basic " + String(Base64.encode(userCredentials.toByteArray(), Base64.DEFAULT)).trim()
19 | header("Authorization", auth)
20 | }
21 | UserInfo.isLoginIn() -> {
22 | val auth = "Token " + UserInfo.token
23 | header("Authorization", auth)
24 | }
25 | else -> removeHeader("Authorization")
26 | }
27 | }
28 | .build())
29 | return chain.proceed(chain.request())
30 | }
31 | }
--------------------------------------------------------------------------------
/common/src/main/java/com/devyk/common/network/interceptor/CacheInterceptor.kt:
--------------------------------------------------------------------------------
1 | package com.devyk.common.network.interceptor
2 |
3 |
4 | import com.bennyhuo.common.log.logger
5 | import com.devyk.common.App
6 | import com.devyk.common.ext.no
7 | import com.devyk.common.ext.otherwise
8 | import com.devyk.common.ext.yes
9 | import com.devyk.common.network.FORCE_NETWORK
10 | import com.devyk.common.utils.Network
11 | import okhttp3.CacheControl
12 | import okhttp3.Interceptor
13 | import okhttp3.Interceptor.Chain
14 | import okhttp3.Response
15 | import java.util.concurrent.TimeUnit
16 |
17 |
18 | class CacheInterceptor : Interceptor {
19 | override fun intercept(chain: Chain): Response {
20 | var request = chain.request()
21 | request = Network.isAvailable()
22 | .no {
23 | request.newBuilder()
24 | .cacheControl(CacheControl.FORCE_CACHE)
25 | .build()
26 | }
27 | .otherwise {
28 | request.url().queryParameter(FORCE_NETWORK)?.toBoolean()?.let {
29 | it.yes {
30 | //注意 noCache | noStore,前者不会读缓存;后者既不读缓存,也不对响应进行缓存
31 | //尽管看上去 noCache 比较符合我们的需求,但服务端仍然可能返回服务端的缓存
32 | //request.newBuilder().cacheControl(CacheControl.Builder().noCache().build()).build()
33 | request.newBuilder().cacheControl(CacheControl.Builder().maxAge(0, TimeUnit.SECONDS).build()).build()
34 | }.otherwise {
35 | request
36 | }
37 | } ?: request
38 | }
39 |
40 | request = request.newBuilder().url(request.url().newBuilder().removeAllQueryParameters(FORCE_NETWORK).build()).build()
41 | return chain.proceed(request).also { response ->
42 | logger.error("Cache: ${response.cacheResponse()}, Network: ${response.networkResponse()}")
43 |
44 | }
45 | }
46 | }
--------------------------------------------------------------------------------
/common/src/main/java/com/devyk/common/utils/AdapterList.kt:
--------------------------------------------------------------------------------
1 | package com.devyk.common.utils
2 |
3 | import android.support.v7.widget.RecyclerView
4 |
5 |
6 | class AdapterList
7 | * author : devyk on 2019-11-01 18:05
8 | * blog : https://juejin.im/user/578259398ac2470061f3a3fb/posts
9 | * github : https://github.com/yangkun19921001
10 | * mailbox : yang1001yk@gmail.com
11 | * desc : This is ViewPagerAdapterList
12 | *
13 | */
14 | class ViewPagerAdapterList
9 | * author : devyk on 2019-11-04 10:13
10 | * blog : https://juejin.im/user/578259398ac2470061f3a3fb/posts
11 | * github : https://github.com/yangkun19921001
12 | * mailbox : yang1001yk@gmail.com
13 | * desc : This is Weak
14 | *
15 | */
16 | class Weak