├── .gitignore ├── LICENSE ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro ├── release │ └── app-release.apk └── src │ ├── androidTest │ └── java │ │ └── top │ │ └── jowanxu │ │ └── wanandroidclient │ │ └── ExampleInstrumentedTest.kt │ ├── main │ ├── AndroidManifest.xml │ ├── ic_launcher-web.png │ ├── java │ │ └── top │ │ │ └── jowanxu │ │ │ └── wanandroidclient │ │ │ ├── Ext.kt │ │ │ ├── adapter │ │ │ ├── BannerAdapter.kt │ │ │ ├── CommonAdapter.kt │ │ │ ├── CommonUseTagAdapter.kt │ │ │ ├── HomeAdapter.kt │ │ │ ├── HotTagAdapter.kt │ │ │ ├── SearchAdapter.kt │ │ │ ├── TypeAdapter.kt │ │ │ ├── TypeArticleAdapter.kt │ │ │ └── TypeArticlePagerAdapter.kt │ │ │ ├── base │ │ │ ├── BaseActivity.kt │ │ │ ├── BaseApplication.kt │ │ │ ├── BaseFragment.kt │ │ │ └── Preference.kt │ │ │ ├── bean │ │ │ ├── ArticleListResponse.kt │ │ │ ├── BannerResponse.kt │ │ │ ├── Data.kt │ │ │ ├── Datas.kt │ │ │ ├── FriendListResponse.kt │ │ │ ├── HomeListResponse.kt │ │ │ ├── HotKeyResponse.kt │ │ │ ├── LoginResponse.kt │ │ │ └── TreeListResponse.kt │ │ │ ├── constant │ │ │ └── Constant.kt │ │ │ ├── model │ │ │ ├── CollectArticleModel.kt │ │ │ ├── CollectOutsideArticleModel.kt │ │ │ ├── CollectOutsideArticleModelImpl.kt │ │ │ ├── HomeModel.kt │ │ │ ├── HomeModelImpl.kt │ │ │ ├── SearchModel.kt │ │ │ ├── SearchModelImpl.kt │ │ │ ├── TypeArticleModel.kt │ │ │ └── TypeArticleModelImpl.kt │ │ │ ├── presenter │ │ │ ├── CommonUseFragmentPresenterImpl.kt │ │ │ ├── ContentPresenterImpl.kt │ │ │ ├── HomeFragmentPresenterImpl.kt │ │ │ ├── HomePresenter.kt │ │ │ ├── LoginPresenterImpl.kt │ │ │ ├── SearchPresenter.kt │ │ │ ├── SearchPresenterImpl.kt │ │ │ ├── TypeArticlePresenter.kt │ │ │ ├── TypeArticlePresenterImpl.kt │ │ │ └── TypeFragmentPresenterImpl.kt │ │ │ ├── retrofit │ │ │ ├── RetrofitHelper.kt │ │ │ └── RetrofitService.kt │ │ │ ├── ui │ │ │ ├── activity │ │ │ │ ├── AboutActivity.kt │ │ │ │ ├── ContentActivity.kt │ │ │ │ ├── LoginActivity.kt │ │ │ │ ├── MainActivity.kt │ │ │ │ ├── SearchActivity.kt │ │ │ │ ├── SplashActivity.kt │ │ │ │ └── TypeContentActivity.kt │ │ │ ├── fragment │ │ │ │ ├── CommonUseFragment.kt │ │ │ │ ├── HomeFragment.kt │ │ │ │ ├── TypeArticleFragment.kt │ │ │ │ └── TypeFragment.kt │ │ │ └── view │ │ │ │ └── HorizontalRecyclerView.kt │ │ │ └── view │ │ │ ├── CollectArticleView.kt │ │ │ ├── CommonUseFragmentView.kt │ │ │ ├── HomeFragmentView.kt │ │ │ ├── LoginView.kt │ │ │ ├── SearchListView.kt │ │ │ ├── TypeArticleFragmentView.kt │ │ │ └── TypeFragmentView.kt │ └── res │ │ ├── drawable-v21 │ │ ├── item_selector.xml │ │ └── list_item_selector.xml │ │ ├── drawable-v24 │ │ └── ic_launcher_foreground.xml │ │ ├── drawable │ │ ├── banner_default_bg.xml │ │ ├── ic_action_about.xml │ │ ├── ic_action_account_circle.png │ │ ├── ic_action_browser.xml │ │ ├── ic_action_hot.xml │ │ ├── ic_action_like.xml │ │ ├── ic_action_my_bookmark.xml │ │ ├── ic_action_my_like.xml │ │ ├── ic_action_no_like.xml │ │ ├── ic_action_search.xml │ │ ├── ic_action_share.xml │ │ ├── ic_action_white_like.xml │ │ ├── ic_arrow_down.xml │ │ ├── ic_clear_black_24dp.xml │ │ ├── ic_dashboard_black_24dp.xml │ │ ├── ic_home_black_24dp.xml │ │ ├── ic_launcher_background.xml │ │ ├── ic_launcher_round.png │ │ ├── ic_notifications_black_24dp.xml │ │ ├── item_selector.xml │ │ ├── list_item_selector.xml │ │ ├── logo.png │ │ ├── side_nav_bar.xml │ │ └── splash_launch.xml │ │ ├── layout │ │ ├── activity_about.xml │ │ ├── activity_content.xml │ │ ├── activity_login.xml │ │ ├── activity_main.xml │ │ ├── activity_search.xml │ │ ├── activity_type_content.xml │ │ ├── banner_item.xml │ │ ├── bookmark_head.xml │ │ ├── common_hot.xml │ │ ├── common_hot_item.xml │ │ ├── common_list_item.xml │ │ ├── content_about.xml │ │ ├── fragment_bookmark.xml │ │ ├── fragment_common.xml │ │ ├── fragment_home.xml │ │ ├── fragment_home_empty.xml │ │ ├── fragment_type.xml │ │ ├── fragment_type_content.xml │ │ ├── home_banner.xml │ │ ├── home_list_item.xml │ │ ├── nav_header_main.xml │ │ └── type_list_item.xml │ │ ├── menu │ │ ├── activity_main_drawer.xml │ │ ├── menu_content.xml │ │ ├── menu_main.xml │ │ ├── menu_search.xml │ │ ├── menu_type_content.xml │ │ └── navigation.xml │ │ ├── mipmap-anydpi-v26 │ │ ├── ic_launcher.xml │ │ └── ic_launcher_round.xml │ │ ├── mipmap-hdpi │ │ ├── ic_launcher.png │ │ ├── ic_launcher_foreground.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-mdpi │ │ ├── ic_launcher.png │ │ ├── ic_launcher_foreground.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xhdpi │ │ ├── ic_launcher.png │ │ ├── ic_launcher_foreground.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxhdpi │ │ ├── ic_launcher.png │ │ ├── ic_launcher_foreground.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxxhdpi │ │ ├── ic_launcher.png │ │ ├── ic_launcher_foreground.png │ │ └── ic_launcher_round.png │ │ ├── values-v21 │ │ └── styles.xml │ │ ├── values-w820dp │ │ └── dimens.xml │ │ ├── values-zh │ │ └── strings.xml │ │ └── values │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── ic_launcher_background.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── top │ └── jowanxu │ └── wanandroidclient │ └── ExampleUnitTest.kt ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | # Built application files 2 | *.apk 3 | *.ap_ 4 | 5 | # Files for the ART/Dalvik VM 6 | *.dex 7 | 8 | # Java class files 9 | *.class 10 | 11 | # Generated files 12 | bin/ 13 | gen/ 14 | out/ 15 | 16 | # Gradle files 17 | .gradle/ 18 | build/ 19 | 20 | # Local configuration file (sdk path, etc) 21 | local.properties 22 | 23 | # Proguard folder generated by Eclipse 24 | proguard/ 25 | 26 | # Log Files 27 | *.log 28 | 29 | # Android Studio Navigation editor temp files 30 | .navigation/ 31 | 32 | # Android Studio captures folder 33 | captures/ 34 | 35 | # Intellij 36 | *.iml 37 | .idea/workspace.xml 38 | .idea/tasks.xml 39 | .idea/gradle.xml 40 | .idea/dictionaries 41 | .idea/libraries 42 | 43 | # Keystore files 44 | *.jks 45 | 46 | # External native build folder generated in Android Studio 2.2 and later 47 | .externalNativeBuild 48 | 49 | # Google Services (e.g. APIs or Firebase) 50 | google-services.json 51 | 52 | # Freeline 53 | freeline.py 54 | freeline/ 55 | freeline_project_description.json 56 | /.idea 57 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # WanAndroidClient 2 | Try to build a www.wanandroid.com client 3 | 4 | ## apk 5 | [1.0.3](https://raw.githubusercontent.com/wangzailfm/WanAndroidClient/master/app/release/app-release.apk) 6 | 7 | ## 接口 8 | [玩Android接口](http://www.wanandroid.com/blog/show/2) 9 | 10 | ## 代码结构 11 | **Kotlin + MVP + Kotlin-Coroutines + Retrofit2(GsonCallAdapterFactory + CoroutineCallAdapterFactory)** 12 | 13 | - [Kotlin](https://github.com/JetBrains/kotlin) 14 | - [Kotlin协程](https://github.com/Kotlin/kotlinx.coroutines/blob/master/coroutines-guide.md) 15 | - [Retrofit2](https://github.com/square/retrofit) 16 | - [Retrofit2-Kotlin协程适配器](https://github.com/JakeWharton/retrofit2-kotlin-coroutines-adapter) 17 | - [鸿神的Flowlayout](https://github.com/hongyangAndroid/FlowLayout) 18 | - [BRVAH](https://github.com/CymChad/BaseRecyclerViewAdapterHelper) 19 | - [Agentweb](https://github.com/Justson/AgentWeb) 20 | - [ImmersionBar](https://github.com/gyf-dev/ImmersionBar) 21 | - [Leakcanary](https://github.com/square/leakcanary) 22 | - [Glide](https://github.com/bumptech/glide) 23 | 24 | ## 版本 25 | ### 1.1(计划) 26 | - 搜索记录 27 | - 离线数据 28 | 29 | ### 1.0 30 | - **1.0.3** 31 | - 我的常用网站(我的书签) 32 | - ![常用网站](http://ovlhlis72.bkt.clouddn.com/18-1-5/22904350.jpg) 33 | - **1.0.2** 34 | - 收藏站外文章 35 | - **1.0.1** 36 | - 添加Banner([PagerSnapHelper](https://developer.android.google.cn/reference/android/support/v7/widget/PagerSnapHelper.html)) 37 | 38 | 39 | 40 | ## 功能 41 | - [x] 首页 42 | - [x] 知识体系 43 | - [x] 知识体系专题 44 | - [x] 搜索 45 | - [x] 登录、注册、注销 46 | - [x] 我的收藏、取消收藏、添加收藏 47 | - [x] 文章内容 48 | - [x] 分享文章、专题 49 | - [x] 常用网站 50 | - [x] 热词搜索 51 | - [x] 关于我们 52 | - [x] Banner 53 | - [ ] 搜索记录 54 | - [ ] 离线数据 55 | 56 | 57 | ![首页](/57356814.jpg) 58 | ![文章内容](/71677892.jpg) 59 | ![知识体系](/99475686.jpg) 60 | ![知识体系专题](/19601277.jpg) 61 | ![常用网站](/77418675.jpg) 62 | ![搜索](/85932183.jpg) 63 | ![我的收藏](/71040266.jpg) 64 | ![侧边栏](/5019523.jpg) 65 | ![登录注册](/90744154.jpg) 66 | -------------------------------------------------------------------------------- /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 | android { 8 | compileSdkVersion 26 9 | defaultConfig { 10 | applicationId "top.jowanxu.wanandroidclient" 11 | minSdkVersion 19 12 | targetSdkVersion 26 13 | versionCode 18 14 | versionName "1.0.3" 15 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 16 | vectorDrawables.useSupportLibrary = true 17 | } 18 | buildTypes { 19 | release { 20 | minifyEnabled false 21 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 22 | } 23 | } 24 | productFlavors { 25 | } 26 | } 27 | 28 | dependencies { 29 | implementation fileTree(include: ['*.jar'], dir: 'libs') 30 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version" 31 | implementation "com.android.support:appcompat-v7:$support_version" 32 | implementation "com.android.support:design:$support_version" 33 | implementation "com.android.support:cardview-v7:$support_version" 34 | implementation "com.android.support:support-vector-drawable:$support_version" 35 | implementation 'com.android.support.constraint:constraint-layout:1.0.2' 36 | implementation 'com.android.support:support-v4:26.1.0' 37 | testImplementation "junit:junit:$junit_version" 38 | androidTestImplementation "com.android.support.test:runner:$test_runner_version" 39 | androidTestImplementation "com.android.support.test.espresso:espresso-core:$test_espresso_version" 40 | implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$kotlin_coroutines_version" 41 | implementation "com.squareup.retrofit2:retrofit:$retrofit2_version" 42 | implementation "com.squareup.retrofit2:converter-gson:$retrofit2_converter_gson_version" 43 | implementation "com.squareup.okhttp3:logging-interceptor:$okhttp3_logging_version" 44 | implementation "com.github.CymChad:BaseRecyclerViewAdapterHelper:$brvah_version" 45 | implementation "com.github.bumptech.glide:glide:$glide_version" 46 | implementation "com.just.agentweb:agentweb:$agentweb_version" 47 | debugImplementation "com.squareup.leakcanary:leakcanary-android:$leakcanary_version" 48 | releaseImplementation "com.squareup.leakcanary:leakcanary-android-no-op:$leakcanary_version" 49 | implementation "com.gyf.barlibrary:barlibrary:$barlibrary_version" 50 | implementation "com.hyman:flowlayout-lib:$flowlayout_version" 51 | implementation "com.jakewharton.retrofit:retrofit2-kotlin-coroutines-experimental-adapter:$retrofit2_converter_kotlin_coroutines_version" 52 | } 53 | kotlin { 54 | experimental { 55 | coroutines "enable" 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /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/release/app-release.apk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangzailfm/WanAndroidClient/fef70711199ff6d06a9623f9732d684267cb3f78/app/release/app-release.apk -------------------------------------------------------------------------------- /app/src/androidTest/java/top/jowanxu/wanandroidclient/ExampleInstrumentedTest.kt: -------------------------------------------------------------------------------- 1 | package top.jowanxu.wanandroidclient 2 | 3 | import android.support.test.InstrumentationRegistry 4 | import android.support.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("top.jowanxu.wanandroidclient", appContext.packageName) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 30 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 49 | 55 | 61 | 67 | 73 | 79 | 80 | 81 | -------------------------------------------------------------------------------- /app/src/main/ic_launcher-web.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangzailfm/WanAndroidClient/fef70711199ff6d06a9623f9732d684267cb3f78/app/src/main/ic_launcher-web.png -------------------------------------------------------------------------------- /app/src/main/java/top/jowanxu/wanandroidclient/Ext.kt: -------------------------------------------------------------------------------- 1 | import android.annotation.SuppressLint 2 | import android.app.Activity 3 | import android.content.Context 4 | import android.support.annotation.LayoutRes 5 | import android.support.annotation.StringRes 6 | import android.util.Log 7 | import android.view.LayoutInflater 8 | import android.view.View 9 | import android.view.ViewGroup 10 | import android.widget.Toast 11 | import com.just.agentweb.AgentWeb 12 | import com.just.agentweb.ChromeClientCallbackManager 13 | import kotlinx.coroutines.experimental.Deferred 14 | import kotlinx.coroutines.experimental.JobCancellationException 15 | 16 | /** 17 | * Log 18 | */ 19 | fun loge(tag: String, content: String?) { 20 | Log.e(tag, content ?: tag) 21 | } 22 | 23 | /** 24 | * show toast 25 | * @param content String 26 | */ 27 | @SuppressLint("ShowToast") 28 | fun Context.toast(content: String) { 29 | Constant.showToast?.apply { 30 | setText(content) 31 | show() 32 | } ?: run { 33 | Toast.makeText(this.applicationContext, content, Toast.LENGTH_SHORT).apply { 34 | Constant.showToast = this 35 | }.show() 36 | } 37 | } 38 | 39 | /** 40 | * show toast 41 | * @param id strings.xml 42 | */ 43 | fun Context.toast(@StringRes id: Int) { 44 | toast(getString(id)) 45 | } 46 | 47 | fun Deferred?.cancelByActive() = this?.run { 48 | tryCatch { 49 | if (isActive) { 50 | cancel() 51 | } 52 | } 53 | } 54 | 55 | /** 56 | * save cookie string 57 | */ 58 | fun encodeCookie(cookies: List): String { 59 | val sb = StringBuilder() 60 | val set = HashSet() 61 | cookies 62 | .map { cookie -> 63 | cookie.split(";".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray() 64 | } 65 | .forEach { 66 | it.filterNot { set.contains(it) }.forEach { set.add(it) } 67 | } 68 | 69 | val ite = set.iterator() 70 | while (ite.hasNext()) { 71 | val cookie = ite.next() 72 | sb.append(cookie).append(";") 73 | } 74 | 75 | val last = sb.lastIndexOf(";") 76 | if (sb.length - 1 == last) { 77 | sb.deleteCharAt(last) 78 | } 79 | 80 | return sb.toString() 81 | } 82 | 83 | /** 84 | * get random color 85 | * @return 16777215 is FFFFFF, 0 is 000000 86 | */ 87 | fun getRandomColor(): String = "#${Integer.toHexString((Math.random() * 16777215).toInt())}" 88 | 89 | /** 90 | * getAgentWeb 91 | */ 92 | fun String.getAgentWeb( 93 | activity: Activity, webContent: ViewGroup, 94 | layoutParams: ViewGroup.LayoutParams, 95 | receivedTitleCallback: ChromeClientCallbackManager.ReceivedTitleCallback? 96 | ) = AgentWeb.with(activity)//传入Activity or Fragment 97 | .setAgentWebParent(webContent, layoutParams)//传入AgentWeb 的父控件 98 | .useDefaultIndicator()// 使用默认进度条 99 | .defaultProgressBarColor() // 使用默认进度条颜色 100 | .setReceivedTitleCallback(receivedTitleCallback) //设置 Web 页面的 title 回调 101 | .createAgentWeb()// 102 | .ready() 103 | .go(this)!! 104 | 105 | /** 106 | * LayoutInflater.from(this).inflate 107 | * @param resource layoutId 108 | * @return View 109 | */ 110 | fun Context.inflater(@LayoutRes resource: Int): View = 111 | LayoutInflater.from(this).inflate(resource, null) 112 | 113 | /** 114 | * In disappear assist cheng (cancel) will be submitted to the Job Cancellation Exception Exception. 115 | */ 116 | inline fun tryCatch(catchBlock: (Throwable) -> Unit = {}, tryBlock: () -> Unit) { 117 | try { 118 | tryBlock() 119 | } catch (_: JobCancellationException) { 120 | 121 | } catch (t: Throwable) { 122 | catchBlock(t) 123 | } 124 | } -------------------------------------------------------------------------------- /app/src/main/java/top/jowanxu/wanandroidclient/adapter/BannerAdapter.kt: -------------------------------------------------------------------------------- 1 | package top.jowanxu.wanandroidclient.adapter 2 | 3 | import android.content.Context 4 | import android.widget.ImageView 5 | import com.bumptech.glide.Glide 6 | import com.chad.library.adapter.base.BaseQuickAdapter 7 | import com.chad.library.adapter.base.BaseViewHolder 8 | import top.jowanxu.wanandroidclient.R 9 | import top.jowanxu.wanandroidclient.bean.BannerResponse 10 | 11 | class BannerAdapter(val context: Context, datas: MutableList) : 12 | BaseQuickAdapter(R.layout.banner_item, datas) { 13 | override fun convert(helper: BaseViewHolder, item: BannerResponse.Data?) { 14 | item ?: return 15 | helper.setText(R.id.bannerTitle, item.title.trim()) 16 | val imageView = helper.getView(R.id.bannerImage) 17 | Glide.with(context).load(item.imagePath).placeholder(R.drawable.logo).into(imageView) 18 | } 19 | } -------------------------------------------------------------------------------- /app/src/main/java/top/jowanxu/wanandroidclient/adapter/CommonAdapter.kt: -------------------------------------------------------------------------------- 1 | package top.jowanxu.wanandroidclient.adapter 2 | 3 | import android.content.Context 4 | import com.chad.library.adapter.base.BaseQuickAdapter 5 | import com.chad.library.adapter.base.BaseViewHolder 6 | import top.jowanxu.wanandroidclient.R 7 | import top.jowanxu.wanandroidclient.bean.FriendListResponse 8 | 9 | class CommonAdapter(val context: Context, datas: MutableList) : 10 | BaseQuickAdapter(R.layout.common_list_item, datas) { 11 | override fun convert(helper: BaseViewHolder, item: FriendListResponse.Data?) { 12 | item ?: return 13 | helper.setText(R.id.commonItemTitle, item.name.trim()) 14 | } 15 | } -------------------------------------------------------------------------------- /app/src/main/java/top/jowanxu/wanandroidclient/adapter/CommonUseTagAdapter.kt: -------------------------------------------------------------------------------- 1 | package top.jowanxu.wanandroidclient.adapter 2 | 3 | import android.content.Context 4 | import android.graphics.Color 5 | import android.view.LayoutInflater 6 | import android.view.View 7 | import android.widget.TextView 8 | import com.zhy.view.flowlayout.FlowLayout 9 | import com.zhy.view.flowlayout.TagAdapter 10 | import getRandomColor 11 | import top.jowanxu.wanandroidclient.R 12 | import top.jowanxu.wanandroidclient.bean.FriendListResponse 13 | 14 | 15 | class CommonUseTagAdapter(context: Context, datas: List) : 16 | TagAdapter(datas) { 17 | private val inflater: LayoutInflater = LayoutInflater.from(context) 18 | 19 | override fun getView(parent: FlowLayout, position: Int, data: FriendListResponse.Data): View { 20 | return (inflater.inflate(R.layout.common_list_item, parent, false) as TextView).apply { 21 | text = data.name 22 | val parseColor = try { 23 | Color.parseColor(getRandomColor()) 24 | } catch (_: Exception) { 25 | @Suppress("DEPRECATION") 26 | context.resources.getColor(R.color.colorAccent) 27 | } 28 | setTextColor(parseColor) 29 | } 30 | } 31 | } -------------------------------------------------------------------------------- /app/src/main/java/top/jowanxu/wanandroidclient/adapter/HomeAdapter.kt: -------------------------------------------------------------------------------- 1 | package top.jowanxu.wanandroidclient.adapter 2 | 3 | import android.content.Context 4 | import com.chad.library.adapter.base.BaseQuickAdapter 5 | import com.chad.library.adapter.base.BaseViewHolder 6 | import top.jowanxu.wanandroidclient.R 7 | import top.jowanxu.wanandroidclient.bean.Datas 8 | 9 | class HomeAdapter(val context: Context, datas: MutableList) : 10 | BaseQuickAdapter(R.layout.home_list_item, datas) { 11 | override fun convert(helper: BaseViewHolder, item: Datas?) { 12 | item ?: return 13 | @Suppress("DEPRECATION") 14 | helper.setText(R.id.homeItemTitle, item.title) 15 | .setText(R.id.homeItemAuthor, item.author) 16 | .setText(R.id.homeItemType, item.chapterName) 17 | .addOnClickListener(R.id.homeItemType) 18 | .setTextColor(R.id.homeItemType, context.resources.getColor(R.color.colorPrimary)) 19 | .linkify(R.id.homeItemType) 20 | .setText(R.id.homeItemDate, item.niceDate) 21 | .setImageResource( 22 | R.id.homeItemLike, 23 | if (item.collect) R.drawable.ic_action_like else R.drawable.ic_action_no_like 24 | ) 25 | .addOnClickListener(R.id.homeItemLike) 26 | } 27 | } -------------------------------------------------------------------------------- /app/src/main/java/top/jowanxu/wanandroidclient/adapter/HotTagAdapter.kt: -------------------------------------------------------------------------------- 1 | package top.jowanxu.wanandroidclient.adapter 2 | 3 | import android.content.Context 4 | import android.graphics.Color 5 | import android.view.LayoutInflater 6 | import android.view.View 7 | import android.widget.TextView 8 | import com.zhy.view.flowlayout.FlowLayout 9 | import com.zhy.view.flowlayout.TagAdapter 10 | import getRandomColor 11 | import top.jowanxu.wanandroidclient.R 12 | import top.jowanxu.wanandroidclient.bean.HotKeyResponse 13 | 14 | class HotTagAdapter(context: Context, datas: List) : 15 | TagAdapter(datas) { 16 | private val inflater: LayoutInflater = LayoutInflater.from(context) 17 | 18 | override fun getView(parent: FlowLayout, position: Int, data: HotKeyResponse.Data): View { 19 | return (inflater.inflate(R.layout.common_hot_item, parent, false) as TextView).apply { 20 | text = data.name 21 | val parseColor = try { 22 | Color.parseColor(getRandomColor()) 23 | } catch (_: Exception) { 24 | @Suppress("DEPRECATION") 25 | context.resources.getColor(R.color.colorAccent) 26 | } 27 | setTextColor(parseColor) 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /app/src/main/java/top/jowanxu/wanandroidclient/adapter/SearchAdapter.kt: -------------------------------------------------------------------------------- 1 | package top.jowanxu.wanandroidclient.adapter 2 | 3 | import android.content.Context 4 | import android.text.Html 5 | import com.chad.library.adapter.base.BaseQuickAdapter 6 | import com.chad.library.adapter.base.BaseViewHolder 7 | import top.jowanxu.wanandroidclient.R 8 | import top.jowanxu.wanandroidclient.bean.Datas 9 | 10 | class SearchAdapter(val context: Context, datas: MutableList) : 11 | BaseQuickAdapter(R.layout.home_list_item, datas) { 12 | override fun convert(helper: BaseViewHolder, item: Datas?) { 13 | item ?: return 14 | @Suppress("DEPRECATION") 15 | helper.setText(R.id.homeItemTitle, Html.fromHtml(item.title)) 16 | .setText(R.id.homeItemAuthor, item.author) 17 | .setText(R.id.homeItemType, item.chapterName) 18 | .setText( 19 | R.id.homeItemDate, 20 | if (item.originId != 0) context.getString( 21 | R.string.bookmark_time, 22 | item.niceDate 23 | ) else item.niceDate 24 | ) 25 | .addOnClickListener(R.id.homeItemType) 26 | .setTextColor(R.id.homeItemType, context.resources.getColor(R.color.colorPrimary)) 27 | .linkify(R.id.homeItemType) 28 | .setImageResource( 29 | R.id.homeItemLike, 30 | if (item.originId != 0 || item.collect) R.drawable.ic_action_like else R.drawable.ic_action_no_like 31 | ) 32 | .addOnClickListener(R.id.homeItemLike) 33 | } 34 | } -------------------------------------------------------------------------------- /app/src/main/java/top/jowanxu/wanandroidclient/adapter/TypeAdapter.kt: -------------------------------------------------------------------------------- 1 | package top.jowanxu.wanandroidclient.adapter 2 | 3 | import android.content.Context 4 | import com.chad.library.adapter.base.BaseQuickAdapter 5 | import com.chad.library.adapter.base.BaseViewHolder 6 | import top.jowanxu.wanandroidclient.R 7 | import top.jowanxu.wanandroidclient.bean.TreeListResponse 8 | 9 | class TypeAdapter(val context: Context, datas: MutableList) : 10 | BaseQuickAdapter(R.layout.type_list_item, datas) { 11 | override fun convert(helper: BaseViewHolder, item: TreeListResponse.Data?) { 12 | item ?: return 13 | helper.setText(R.id.typeItemFirst, item.name) 14 | item.children?.let { children -> 15 | helper.setText( 16 | R.id.typeItemSecond, 17 | children.joinToString(" ", transform = { child -> 18 | child.name 19 | }) 20 | ) 21 | } 22 | } 23 | } -------------------------------------------------------------------------------- /app/src/main/java/top/jowanxu/wanandroidclient/adapter/TypeArticleAdapter.kt: -------------------------------------------------------------------------------- 1 | package top.jowanxu.wanandroidclient.adapter 2 | 3 | import android.content.Context 4 | import com.chad.library.adapter.base.BaseQuickAdapter 5 | import com.chad.library.adapter.base.BaseViewHolder 6 | import top.jowanxu.wanandroidclient.R 7 | import top.jowanxu.wanandroidclient.bean.Datas 8 | 9 | class TypeArticleAdapter(val context: Context, datas: MutableList) : 10 | BaseQuickAdapter(R.layout.home_list_item, datas) { 11 | override fun convert(helper: BaseViewHolder, item: Datas?) { 12 | item ?: return 13 | @Suppress("DEPRECATION") 14 | helper.setText(R.id.homeItemTitle, item.title) 15 | .setText(R.id.homeItemAuthor, item.author) 16 | .setVisible(R.id.homeItemType, false) 17 | .setText(R.id.homeItemDate, item.niceDate) 18 | .setImageResource( 19 | R.id.homeItemLike, 20 | if (item.collect) R.drawable.ic_action_like else R.drawable.ic_action_no_like 21 | ) 22 | .addOnClickListener(R.id.homeItemLike) 23 | } 24 | } -------------------------------------------------------------------------------- /app/src/main/java/top/jowanxu/wanandroidclient/adapter/TypeArticlePagerAdapter.kt: -------------------------------------------------------------------------------- 1 | package top.jowanxu.wanandroidclient.adapter 2 | 3 | import android.support.v4.app.Fragment 4 | import android.support.v4.app.FragmentManager 5 | import android.support.v4.app.FragmentStatePagerAdapter 6 | import android.support.v4.view.PagerAdapter 7 | import top.jowanxu.wanandroidclient.bean.TreeListResponse.Data.Children 8 | import top.jowanxu.wanandroidclient.ui.fragment.TypeArticleFragment 9 | 10 | class TypeArticlePagerAdapter(val list: List, fm: FragmentManager) : 11 | FragmentStatePagerAdapter(fm) { 12 | private val listFragment = mutableListOf() 13 | 14 | init { 15 | list.forEach { listFragment.add(TypeArticleFragment.newInstance(it.id)) } 16 | } 17 | 18 | override fun getItem(position: Int): Fragment = listFragment[position] 19 | 20 | override fun getCount(): Int = list.size 21 | 22 | override fun getPageTitle(position: Int): CharSequence = list[position].name 23 | 24 | override fun getItemPosition(`object`: Any?): Int = PagerAdapter.POSITION_NONE 25 | } -------------------------------------------------------------------------------- /app/src/main/java/top/jowanxu/wanandroidclient/base/BaseActivity.kt: -------------------------------------------------------------------------------- 1 | package top.jowanxu.wanandroidclient.base 2 | 3 | import android.annotation.SuppressLint 4 | import android.content.Context 5 | import android.os.Bundle 6 | import android.support.v7.app.AppCompatActivity 7 | import android.view.inputmethod.InputMethodManager 8 | import com.gyf.barlibrary.ImmersionBar 9 | 10 | 11 | @SuppressLint("Registered") 12 | abstract class BaseActivity : AppCompatActivity() { 13 | 14 | protected lateinit var immersionBar: ImmersionBar 15 | 16 | private val imm: InputMethodManager by lazy { 17 | getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager 18 | } 19 | 20 | override fun onCreate(savedInstanceState: Bundle?) { 21 | super.onCreate(savedInstanceState) 22 | setContentView(setLayoutId()) 23 | initImmersionBar() 24 | } 25 | 26 | protected abstract fun setLayoutId(): Int 27 | 28 | open protected fun initImmersionBar() { 29 | //在BaseActivity里初始化 30 | immersionBar = ImmersionBar.with(this) 31 | immersionBar.init() 32 | } 33 | 34 | /** 35 | * cancel request 36 | */ 37 | protected abstract fun cancelRequest() 38 | 39 | override fun onDestroy() { 40 | super.onDestroy() 41 | immersionBar.destroy() //必须调用该方法,防止内存泄漏,不调用该方法,如果界面bar发生改变,在不关闭app的情况下,退出此界面再进入将记忆最后一次bar改变的状态 42 | cancelRequest() 43 | } 44 | 45 | override fun finish() { 46 | // if not finish 47 | if (!isFinishing) { 48 | super.finish() 49 | hideSoftKeyBoard() 50 | } 51 | } 52 | 53 | private fun hideSoftKeyBoard() { 54 | currentFocus?.let { 55 | imm.hideSoftInputFromWindow(it.windowToken, 2) 56 | } 57 | } 58 | } -------------------------------------------------------------------------------- /app/src/main/java/top/jowanxu/wanandroidclient/base/BaseApplication.kt: -------------------------------------------------------------------------------- 1 | package top.jowanxu.wanandroidclient.base 2 | 3 | import android.app.Application 4 | import android.content.ComponentCallbacks2 5 | import com.bumptech.glide.Glide 6 | import com.squareup.leakcanary.LeakCanary 7 | import top.jowanxu.wanandroidclient.BuildConfig 8 | 9 | class BaseApplication : Application() { 10 | override fun onCreate() { 11 | super.onCreate() 12 | if (BuildConfig.DEBUG) { 13 | LeakCanary.install(this) 14 | } 15 | Preference.setContext(applicationContext) 16 | } 17 | 18 | override fun onTrimMemory(level: Int) { 19 | super.onTrimMemory(level) 20 | // clear Glide cache 21 | if (level == ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN) { 22 | Glide.get(this).clearMemory() 23 | } 24 | // trim memory 25 | Glide.get(this).trimMemory(level) 26 | } 27 | 28 | override fun onLowMemory() { 29 | super.onLowMemory() 30 | // low memory clear Glide cache 31 | Glide.get(this).clearMemory() 32 | } 33 | } -------------------------------------------------------------------------------- /app/src/main/java/top/jowanxu/wanandroidclient/base/BaseFragment.kt: -------------------------------------------------------------------------------- 1 | package top.jowanxu.wanandroidclient.base 2 | 3 | import android.support.v4.app.Fragment 4 | 5 | abstract class BaseFragment : Fragment() { 6 | 7 | protected var isFirst: Boolean = true 8 | 9 | /** 10 | * cancel request 11 | */ 12 | protected abstract fun cancelRequest() 13 | 14 | override fun onDestroyView() { 15 | super.onDestroyView() 16 | cancelRequest() 17 | } 18 | } -------------------------------------------------------------------------------- /app/src/main/java/top/jowanxu/wanandroidclient/base/Preference.kt: -------------------------------------------------------------------------------- 1 | package top.jowanxu.wanandroidclient.base 2 | 3 | import Constant 4 | import android.annotation.SuppressLint 5 | import android.content.Context 6 | import android.content.SharedPreferences 7 | import kotlin.properties.ReadWriteProperty 8 | import kotlin.reflect.KProperty 9 | 10 | /** 11 | * SharedPreferences operation, you need application to invoke setContext 12 | * @param name sp key name 13 | * @param default default value 14 | */ 15 | class Preference(private val name: String, private val default: T) : ReadWriteProperty { 16 | 17 | companion object { 18 | lateinit var preferences: SharedPreferences 19 | /** 20 | * init Context 21 | * @param context Context 22 | */ 23 | fun setContext(context: Context) { 24 | preferences = context.getSharedPreferences( 25 | context.packageName + Constant.SHARED_NAME, 26 | Context.MODE_PRIVATE 27 | ) 28 | } 29 | 30 | fun clear() { 31 | preferences.edit().clear().apply() 32 | } 33 | } 34 | 35 | override fun getValue(thisRef: Any?, property: KProperty<*>): T = findPreference(name, default) 36 | 37 | override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) = putPreference(name, value) 38 | 39 | @Suppress("UNCHECKED_CAST") 40 | private fun findPreference(name: String, default: U): U = with(preferences) { 41 | val res: Any = when (default) { 42 | is Long -> getLong(name, default) 43 | is String -> getString(name, default) 44 | is Int -> getInt(name, default) 45 | is Boolean -> getBoolean(name, default) 46 | is Float -> getFloat(name, default) 47 | else -> throw IllegalArgumentException("This type can be saved into Preferences") 48 | } 49 | res as U 50 | } 51 | 52 | @SuppressLint("CommitPrefEdits") 53 | private fun putPreference(name: String, value: U) = with(preferences.edit()) { 54 | when (value) { 55 | is Long -> putLong(name, value) 56 | is String -> putString(name, value) 57 | is Int -> putInt(name, value) 58 | is Boolean -> putBoolean(name, value) 59 | is Float -> putFloat(name, value) 60 | else -> throw IllegalArgumentException("This type can be saved into Preferences") 61 | }.apply() 62 | } 63 | } -------------------------------------------------------------------------------- /app/src/main/java/top/jowanxu/wanandroidclient/bean/ArticleListResponse.kt: -------------------------------------------------------------------------------- 1 | package top.jowanxu.wanandroidclient.bean 2 | 3 | data class ArticleListResponse( 4 | var errorCode: Int, 5 | var errorMsg: String?, 6 | var data: Data 7 | ) -------------------------------------------------------------------------------- /app/src/main/java/top/jowanxu/wanandroidclient/bean/BannerResponse.kt: -------------------------------------------------------------------------------- 1 | package top.jowanxu.wanandroidclient.bean 2 | 3 | data class BannerResponse( 4 | var errorCode: Int, 5 | var errorMsg: String?, 6 | var data: List? 7 | ) { 8 | data class Data( 9 | var id: Int, 10 | var url: String, 11 | var imagePath: String, 12 | var title: String, 13 | var desc: String, 14 | var isVisible: Int, 15 | var order: Int, 16 | var `type`: Int 17 | ) 18 | } -------------------------------------------------------------------------------- /app/src/main/java/top/jowanxu/wanandroidclient/bean/Data.kt: -------------------------------------------------------------------------------- 1 | package top.jowanxu.wanandroidclient.bean 2 | 3 | data class Data( 4 | var offset: Int, 5 | var size: Int, 6 | var total: Int, 7 | var pageCount: Int, 8 | var curPage: Int, 9 | var over: Boolean, 10 | var datas: List? 11 | ) -------------------------------------------------------------------------------- /app/src/main/java/top/jowanxu/wanandroidclient/bean/Datas.kt: -------------------------------------------------------------------------------- 1 | package top.jowanxu.wanandroidclient.bean 2 | 3 | data class Datas( 4 | var id: Int, 5 | var originId: Int, 6 | var title: String, 7 | var chapterId: Int, 8 | var chapterName: String?, 9 | var envelopePic: Any, 10 | var link: String, 11 | var author: String, 12 | var origin: Any, 13 | var publishTime: Long, 14 | var zan: Any, 15 | var desc: Any, 16 | var visible: Int, 17 | var niceDate: String, 18 | var courseId: Int, 19 | var collect: Boolean 20 | ) -------------------------------------------------------------------------------- /app/src/main/java/top/jowanxu/wanandroidclient/bean/FriendListResponse.kt: -------------------------------------------------------------------------------- 1 | package top.jowanxu.wanandroidclient.bean 2 | 3 | data class FriendListResponse( 4 | var errorCode: Int, 5 | var errorMsg: String?, 6 | var data: List? 7 | ) { 8 | data class Data( 9 | var id: Int, 10 | var name: String, 11 | var link: String, 12 | var visible: Int, 13 | var order: Int, 14 | var icon: Any 15 | ) 16 | } -------------------------------------------------------------------------------- /app/src/main/java/top/jowanxu/wanandroidclient/bean/HomeListResponse.kt: -------------------------------------------------------------------------------- 1 | package top.jowanxu.wanandroidclient.bean 2 | 3 | data class HomeListResponse( 4 | var errorCode: Int, 5 | var errorMsg: String?, 6 | var data: Data 7 | ) -------------------------------------------------------------------------------- /app/src/main/java/top/jowanxu/wanandroidclient/bean/HotKeyResponse.kt: -------------------------------------------------------------------------------- 1 | package top.jowanxu.wanandroidclient.bean 2 | 3 | data class HotKeyResponse( 4 | var errorCode: Int, 5 | var errorMsg: String?, 6 | var data: List? 7 | ) { 8 | data class Data( 9 | var id: Int, 10 | var name: String, 11 | var link: Any, 12 | var visible: Int, 13 | var order: Int 14 | ) 15 | } -------------------------------------------------------------------------------- /app/src/main/java/top/jowanxu/wanandroidclient/bean/LoginResponse.kt: -------------------------------------------------------------------------------- 1 | package top.jowanxu.wanandroidclient.bean 2 | 3 | data class LoginResponse( 4 | var errorCode: Int, 5 | var errorMsg: String?, 6 | var data: Data 7 | ) { 8 | data class Data( 9 | var id: Int, 10 | var username: String, 11 | var password: String, 12 | var icon: String?, 13 | var type: Int, 14 | var collectIds: List? 15 | ) 16 | } -------------------------------------------------------------------------------- /app/src/main/java/top/jowanxu/wanandroidclient/bean/TreeListResponse.kt: -------------------------------------------------------------------------------- 1 | package top.jowanxu.wanandroidclient.bean 2 | 3 | import java.io.Serializable 4 | 5 | data class TreeListResponse( 6 | var errorCode: Int, 7 | var errorMsg: String?, 8 | var data: List 9 | ) { 10 | data class Data( 11 | var id: Int, 12 | var name: String, 13 | var courseId: Int, 14 | var parentChapterId: Int, 15 | var order: Int, 16 | var visible: Int, 17 | var children: List? 18 | ) : Serializable { 19 | data class Children( 20 | var id: Int, 21 | var name: String, 22 | var courseId: Int, 23 | var parentChapterId: Int, 24 | var order: Int, 25 | var visible: Int, 26 | var children: List? 27 | ) : Serializable 28 | } 29 | } -------------------------------------------------------------------------------- /app/src/main/java/top/jowanxu/wanandroidclient/constant/Constant.kt: -------------------------------------------------------------------------------- 1 | import android.widget.Toast 2 | 3 | /** 4 | * Constant 5 | */ 6 | object Constant { 7 | /** 8 | * baseUrl 9 | */ 10 | const val REQUEST_BASE_URL = "http://wanandroid.com/" 11 | /** 12 | * Share preferences name 13 | */ 14 | const val SHARED_NAME = "_preferences" 15 | const val LOGIN_KEY = "login" 16 | const val USERNAME_KEY = "username" 17 | const val PASSWORD_KEY = "password" 18 | /** 19 | * result null 20 | */ 21 | const val RESULT_NULL = "result null!" 22 | /** 23 | * Toast 24 | */ 25 | @JvmField 26 | var showToast: Toast? = null 27 | /** 28 | * Debug 29 | */ 30 | const val INTERCEPTOR_ENABLE = false 31 | /** 32 | * url key 33 | */ 34 | const val CONTENT_URL_KEY = "url" 35 | /** 36 | * title key 37 | */ 38 | const val CONTENT_TITLE_KEY = "title" 39 | /** 40 | * id key 41 | */ 42 | const val CONTENT_ID_KEY = "id" 43 | /** 44 | * cid key 45 | */ 46 | const val CONTENT_CID_KEY = "cid" 47 | /** 48 | * childrenData key 49 | */ 50 | const val CONTENT_CHILDREN_DATA_KEY = "childrenData" 51 | /** 52 | * target key 53 | */ 54 | const val CONTENT_TARGET_KEY = "target" 55 | /** 56 | * share key 57 | */ 58 | const val CONTENT_SHARE_TYPE = "text/plain" 59 | const val SEARCH_KEY = "search" 60 | const val LIKE_KEY = "like" 61 | 62 | const val MAIN_REQUEST_CODE = 100 63 | const val MAIN_LIKE_REQUEST_CODE = 101 64 | } -------------------------------------------------------------------------------- /app/src/main/java/top/jowanxu/wanandroidclient/model/CollectArticleModel.kt: -------------------------------------------------------------------------------- 1 | package top.jowanxu.wanandroidclient.model 2 | 3 | import top.jowanxu.wanandroidclient.presenter.HomePresenter 4 | 5 | interface CollectArticleModel { 6 | 7 | /** 8 | * add or remove collect article 9 | */ 10 | fun collectArticle( 11 | onCollectArticleListener: HomePresenter.OnCollectArticleListener, 12 | id: Int, 13 | isAdd: Boolean 14 | ) 15 | 16 | /** 17 | * cancel collect article Request 18 | */ 19 | fun cancelCollectRequest() 20 | } -------------------------------------------------------------------------------- /app/src/main/java/top/jowanxu/wanandroidclient/model/CollectOutsideArticleModel.kt: -------------------------------------------------------------------------------- 1 | package top.jowanxu.wanandroidclient.model 2 | 3 | import top.jowanxu.wanandroidclient.presenter.HomePresenter 4 | 5 | interface CollectOutsideArticleModel { 6 | 7 | /** 8 | * add or remove collect outside article 9 | * @param onCollectOutsideArticleListener HomePresenter.OnCollectOutsideArticleListener 10 | * @param title article title 11 | * @param author article author 12 | * @param link article link 13 | * @param isAdd true add, false remove 14 | */ 15 | fun collectOutsideArticle( 16 | onCollectOutsideArticleListener: HomePresenter.OnCollectOutsideArticleListener, 17 | title: String, author: String, link: String, isAdd: Boolean 18 | ) 19 | 20 | /** 21 | * cancel collect article Request 22 | */ 23 | fun cancelCollectOutsideRequest() 24 | } -------------------------------------------------------------------------------- /app/src/main/java/top/jowanxu/wanandroidclient/model/CollectOutsideArticleModelImpl.kt: -------------------------------------------------------------------------------- 1 | package top.jowanxu.wanandroidclient.model 2 | 3 | import Constant 4 | import RetrofitHelper 5 | import cancelByActive 6 | import kotlinx.coroutines.experimental.Deferred 7 | import kotlinx.coroutines.experimental.android.UI 8 | import kotlinx.coroutines.experimental.async 9 | import top.jowanxu.wanandroidclient.bean.HomeListResponse 10 | import top.jowanxu.wanandroidclient.presenter.HomePresenter 11 | import tryCatch 12 | 13 | class CollectOutsideArticleModelImpl : CollectOutsideArticleModel { 14 | 15 | /** 16 | * Collect Article async 17 | */ 18 | private var collectArticleAsync: Deferred? = null 19 | 20 | /** 21 | * add or remove collect outside article 22 | * @param onCollectOutsideArticleListener HomePresenter.OnCollectOutsideArticleListener 23 | * @param title article title 24 | * @param author article author 25 | * @param link article link 26 | * @param isAdd true add, false remove 27 | */ 28 | override fun collectOutsideArticle( 29 | onCollectOutsideArticleListener: HomePresenter.OnCollectOutsideArticleListener, 30 | title: String, author: String, link: String, isAdd: Boolean 31 | ) { 32 | async(UI) { 33 | tryCatch({ 34 | it.printStackTrace() 35 | onCollectOutsideArticleListener.collectOutsideArticleFailed(it.toString(), isAdd) 36 | }) { 37 | collectArticleAsync?.cancelByActive() 38 | // add article 39 | collectArticleAsync = 40 | RetrofitHelper.retrofitService.addCollectOutsideArticle(title, author, link) 41 | // TODO if isAdd false, remove article 42 | // collectArticleAsync = RetrofitHelper.retrofitService.removeCollectArticle(id) 43 | val result = collectArticleAsync?.await() 44 | result ?: let { 45 | onCollectOutsideArticleListener.collectOutsideArticleFailed( 46 | Constant.RESULT_NULL, 47 | isAdd 48 | ) 49 | return@async 50 | } 51 | onCollectOutsideArticleListener.collectOutsideArticleSuccess(result, isAdd) 52 | } 53 | } 54 | } 55 | 56 | /** 57 | * cancel collect article Request 58 | */ 59 | override fun cancelCollectOutsideRequest() { 60 | collectArticleAsync?.cancelByActive() 61 | } 62 | } -------------------------------------------------------------------------------- /app/src/main/java/top/jowanxu/wanandroidclient/model/HomeModel.kt: -------------------------------------------------------------------------------- 1 | package top.jowanxu.wanandroidclient.model 2 | 3 | import top.jowanxu.wanandroidclient.presenter.HomePresenter 4 | 5 | /** 6 | * 首页Model接口 7 | */ 8 | interface HomeModel { 9 | /** 10 | * get Home List 11 | * @param onHomeListListener HomePresenter.OnHomeListListener 12 | * @param page page 13 | */ 14 | fun getHomeList(onHomeListListener: HomePresenter.OnHomeListListener, page: Int = 0) 15 | 16 | /** 17 | * cancel HomeList Request 18 | */ 19 | fun cancelHomeListRequest() 20 | 21 | /** 22 | * get TypeTree List 23 | * @param onTypeTreeListListener HomePresenter.OnTypeTreeListListener 24 | */ 25 | fun getTypeTreeList(onTypeTreeListListener: HomePresenter.OnTypeTreeListListener) 26 | 27 | /** 28 | * cancel TypeTree Request 29 | */ 30 | fun cancelTypeTreeRequest() 31 | 32 | /** 33 | * login 34 | * @param onLoginListener HomePresenter.OnLoginListener 35 | * @param username username 36 | * @param password password 37 | */ 38 | fun loginWanAndroid( 39 | onLoginListener: HomePresenter.OnLoginListener, 40 | username: String, 41 | password: String 42 | ) 43 | 44 | /** 45 | * cancel login Request 46 | */ 47 | fun cancelLoginRequest() 48 | 49 | /** 50 | * register 51 | * @param onRegisterListener HomePresenter.OnRegisterListener 52 | * @param username username 53 | * @param password password 54 | * @param repassword repassword 55 | */ 56 | fun registerWanAndroid( 57 | onRegisterListener: HomePresenter.OnRegisterListener, 58 | username: String, 59 | password: String, 60 | repassword: String 61 | ) 62 | 63 | /** 64 | * cancel register Request 65 | */ 66 | fun cancelRegisterRequest() 67 | 68 | /** 69 | * get friend list 70 | * @param onFriendListListener HomePresenter.OnFriendListListener 71 | */ 72 | fun getFriendList(onFriendListListener: HomePresenter.OnFriendListListener) 73 | 74 | /** 75 | * cancel friend list Request 76 | */ 77 | fun cancelFriendRequest() 78 | 79 | /** 80 | * get banner 81 | * @param onBannerListener HomePresenter.OnBannerListener 82 | */ 83 | fun getBanner(onBannerListener: HomePresenter.OnBannerListener) 84 | 85 | /** 86 | * cancel get banner request 87 | */ 88 | fun cancelBannerRequest() 89 | 90 | } -------------------------------------------------------------------------------- /app/src/main/java/top/jowanxu/wanandroidclient/model/SearchModel.kt: -------------------------------------------------------------------------------- 1 | package top.jowanxu.wanandroidclient.model 2 | 3 | import top.jowanxu.wanandroidclient.presenter.SearchPresenter 4 | 5 | /** 6 | * 首页Model接口 7 | */ 8 | interface SearchModel { 9 | 10 | /** 11 | * 获取搜索结果列表 12 | */ 13 | fun getSearchList( 14 | onSearchListListener: SearchPresenter.OnSearchListListener, 15 | page: Int = 0, 16 | k: String 17 | ) 18 | 19 | /** 20 | * 取消请求 21 | */ 22 | fun cancelRequest() 23 | 24 | /** 25 | * get Home List 26 | * @param onLikeListListener SearchPresenter.OnLikeListListener 27 | * @param page page 28 | */ 29 | fun getLikeList(onLikeListListener: SearchPresenter.OnLikeListListener, page: Int = 0) 30 | 31 | /** 32 | * cancel HomeList Request 33 | */ 34 | fun cancelLikeListRequest() 35 | } -------------------------------------------------------------------------------- /app/src/main/java/top/jowanxu/wanandroidclient/model/SearchModelImpl.kt: -------------------------------------------------------------------------------- 1 | package top.jowanxu.wanandroidclient.model 2 | 3 | import Constant 4 | import RetrofitHelper 5 | import cancelByActive 6 | import kotlinx.coroutines.experimental.Deferred 7 | import kotlinx.coroutines.experimental.android.UI 8 | import kotlinx.coroutines.experimental.async 9 | import top.jowanxu.wanandroidclient.bean.HomeListResponse 10 | import top.jowanxu.wanandroidclient.presenter.HomePresenter 11 | import top.jowanxu.wanandroidclient.presenter.SearchPresenter 12 | import tryCatch 13 | 14 | class SearchModelImpl : SearchModel, CollectArticleModel { 15 | 16 | /** 17 | * Search list async 18 | */ 19 | private var searchListAsync: Deferred? = null 20 | /** 21 | * Home list async 22 | */ 23 | private var likeListAsync: Deferred? = null 24 | /** 25 | * Collect Article async 26 | */ 27 | private var collectArticleAsync: Deferred? = null 28 | 29 | override fun getSearchList( 30 | onSearchListListener: SearchPresenter.OnSearchListListener, 31 | page: Int, 32 | k: String 33 | ) { 34 | async(UI) { 35 | tryCatch({ 36 | it.printStackTrace() 37 | onSearchListListener.getSearchListFailed(it.toString()) 38 | }) { 39 | searchListAsync = RetrofitHelper.retrofitService.getSearchList(page, k) 40 | val result = searchListAsync?.await() 41 | result ?: let { 42 | onSearchListListener.getSearchListFailed(Constant.RESULT_NULL) 43 | return@async 44 | } 45 | onSearchListListener.getSearchListSuccess(result) 46 | } 47 | } 48 | } 49 | 50 | override fun cancelRequest() { 51 | searchListAsync?.cancelByActive() 52 | } 53 | 54 | /** 55 | * get Home List 56 | * @param onLikeListListener SearchPresenter.OnLikeListListener 57 | * @param page page 58 | */ 59 | override fun getLikeList(onLikeListListener: SearchPresenter.OnLikeListListener, page: Int) { 60 | async(UI) { 61 | tryCatch({ 62 | it.printStackTrace() 63 | onLikeListListener.getLikeListFailed(it.toString()) 64 | }) { 65 | likeListAsync?.cancelByActive() 66 | likeListAsync = RetrofitHelper.retrofitService.getLikeList(page) 67 | val result = likeListAsync?.await() 68 | result ?: let { 69 | onLikeListListener.getLikeListFailed(Constant.RESULT_NULL) 70 | return@async 71 | } 72 | onLikeListListener.getLikeListSuccess(result) 73 | } 74 | } 75 | } 76 | 77 | /** 78 | * cancel HomeList Request 79 | */ 80 | override fun cancelLikeListRequest() { 81 | likeListAsync?.cancelByActive() 82 | } 83 | 84 | /** 85 | * add or remove collect article 86 | */ 87 | override fun collectArticle( 88 | onCollectArticleListener: HomePresenter.OnCollectArticleListener, 89 | id: Int, 90 | isAdd: Boolean 91 | ) { 92 | async(UI) { 93 | tryCatch({ 94 | it.printStackTrace() 95 | onCollectArticleListener.collectArticleFailed(it.toString(), isAdd) 96 | }) { 97 | collectArticleAsync?.cancelByActive() 98 | collectArticleAsync = if (isAdd) { 99 | RetrofitHelper.retrofitService.addCollectArticle(id) 100 | } else { 101 | RetrofitHelper.retrofitService.removeCollectArticle(id) 102 | } 103 | val result = collectArticleAsync?.await() 104 | result ?: let { 105 | onCollectArticleListener.collectArticleFailed(Constant.RESULT_NULL, isAdd) 106 | return@async 107 | } 108 | onCollectArticleListener.collectArticleSuccess(result, isAdd) 109 | } 110 | } 111 | } 112 | 113 | /** 114 | * cancel collect article Request 115 | */ 116 | override fun cancelCollectRequest() { 117 | collectArticleAsync?.cancelByActive() 118 | } 119 | } -------------------------------------------------------------------------------- /app/src/main/java/top/jowanxu/wanandroidclient/model/TypeArticleModel.kt: -------------------------------------------------------------------------------- 1 | package top.jowanxu.wanandroidclient.model 2 | 3 | import top.jowanxu.wanandroidclient.presenter.TypeArticlePresenter 4 | 5 | interface TypeArticleModel { 6 | /** 7 | * get Type Article list 8 | * @param onTypeArticleListListener TypeArticlePresenter.OnTypeArticleListListener 9 | * @param page page 10 | * @param cid cid 11 | */ 12 | fun getTypeArticleList( 13 | onTypeArticleListListener: TypeArticlePresenter.OnTypeArticleListListener, 14 | page: Int = 0, 15 | cid: Int 16 | ) 17 | 18 | /** 19 | * cancel request 20 | */ 21 | fun cancelRequest() 22 | } -------------------------------------------------------------------------------- /app/src/main/java/top/jowanxu/wanandroidclient/model/TypeArticleModelImpl.kt: -------------------------------------------------------------------------------- 1 | package top.jowanxu.wanandroidclient.model 2 | 3 | import Constant 4 | import RetrofitHelper 5 | import cancelByActive 6 | import kotlinx.coroutines.experimental.Deferred 7 | import kotlinx.coroutines.experimental.android.UI 8 | import kotlinx.coroutines.experimental.async 9 | import top.jowanxu.wanandroidclient.bean.ArticleListResponse 10 | import top.jowanxu.wanandroidclient.presenter.TypeArticlePresenter 11 | import tryCatch 12 | 13 | class TypeArticleModelImpl : TypeArticleModel { 14 | 15 | /** 16 | * Type Article list list async 17 | */ 18 | private var typeArticleListAsync: Deferred? = null 19 | 20 | /** 21 | * get Type Article list 22 | * @param onTypeArticleListListener TypeArticlePresenter.OnTypeArticleListListener 23 | * @param page page 24 | * @param cid cid 25 | */ 26 | override fun getTypeArticleList( 27 | onTypeArticleListListener: TypeArticlePresenter.OnTypeArticleListListener, 28 | page: Int, 29 | cid: Int 30 | ) { 31 | async(UI) { 32 | tryCatch({ 33 | it.printStackTrace() 34 | onTypeArticleListListener.getTypeArticleListFailed(it.toString()) 35 | }) { 36 | typeArticleListAsync?.cancelByActive() 37 | typeArticleListAsync = RetrofitHelper.retrofitService.getArticleList(page, cid) 38 | val result = typeArticleListAsync?.await() 39 | result ?: let { 40 | onTypeArticleListListener.getTypeArticleListFailed(Constant.RESULT_NULL) 41 | return@async 42 | } 43 | onTypeArticleListListener.getTypeArticleListSuccess(result) 44 | } 45 | } 46 | } 47 | 48 | /** 49 | * cancel request 50 | */ 51 | override fun cancelRequest() { 52 | typeArticleListAsync?.cancelByActive() 53 | } 54 | } -------------------------------------------------------------------------------- /app/src/main/java/top/jowanxu/wanandroidclient/presenter/CommonUseFragmentPresenterImpl.kt: -------------------------------------------------------------------------------- 1 | package top.jowanxu.wanandroidclient.presenter 2 | 3 | import top.jowanxu.wanandroidclient.bean.FriendListResponse 4 | import top.jowanxu.wanandroidclient.bean.HotKeyResponse 5 | import top.jowanxu.wanandroidclient.model.HomeModel 6 | import top.jowanxu.wanandroidclient.model.HomeModelImpl 7 | import top.jowanxu.wanandroidclient.view.CommonUseFragmentView 8 | 9 | class CommonUseFragmentPresenterImpl(private val commonUseFragmentView: CommonUseFragmentView) : 10 | HomePresenter.OnFriendListListener { 11 | 12 | private val homeModel: HomeModel = HomeModelImpl() 13 | /** 14 | * get friend tree list 15 | */ 16 | override fun getFriendList() { 17 | homeModel.getFriendList(this) 18 | } 19 | 20 | /** 21 | * get friend list success 22 | */ 23 | override fun getFriendListSuccess( 24 | bookmarkResult: FriendListResponse?, 25 | commonResult: FriendListResponse, 26 | hotResult: HotKeyResponse 27 | ) { 28 | if (commonResult.errorCode != 0 || hotResult.errorCode != 0) { 29 | commonUseFragmentView.getFriendListFailed(commonResult.errorMsg) 30 | return 31 | } 32 | if (commonResult.data == null || commonResult.data == null) { 33 | commonUseFragmentView.getFriendListZero() 34 | return 35 | } 36 | if (commonResult.data?.size == 0 && hotResult.data?.size == 0) { 37 | commonUseFragmentView.getFriendListZero() 38 | return 39 | } 40 | commonUseFragmentView.getFriendListSuccess(bookmarkResult, commonResult, hotResult) 41 | } 42 | 43 | /** 44 | * get friend list failed 45 | * @param errorMessage error message 46 | */ 47 | override fun getFriendListFailed(errorMessage: String?) { 48 | commonUseFragmentView.getFriendListFailed(errorMessage) 49 | } 50 | 51 | /** 52 | * cancel request 53 | */ 54 | fun cancelRequest() { 55 | homeModel.cancelFriendRequest() 56 | } 57 | } -------------------------------------------------------------------------------- /app/src/main/java/top/jowanxu/wanandroidclient/presenter/ContentPresenterImpl.kt: -------------------------------------------------------------------------------- 1 | package top.jowanxu.wanandroidclient.presenter 2 | 3 | import top.jowanxu.wanandroidclient.bean.HomeListResponse 4 | import top.jowanxu.wanandroidclient.model.CollectArticleModel 5 | import top.jowanxu.wanandroidclient.model.CollectOutsideArticleModel 6 | import top.jowanxu.wanandroidclient.model.CollectOutsideArticleModelImpl 7 | import top.jowanxu.wanandroidclient.model.SearchModelImpl 8 | import top.jowanxu.wanandroidclient.view.CollectArticleView 9 | 10 | class ContentPresenterImpl(private val collectArticleView: CollectArticleView) : 11 | HomePresenter.OnCollectArticleListener, HomePresenter.OnCollectOutsideArticleListener { 12 | 13 | private val collectArticleModel: CollectArticleModel = SearchModelImpl() 14 | private val collectOutsideArticleModel: CollectOutsideArticleModel = 15 | CollectOutsideArticleModelImpl() 16 | 17 | /** 18 | * add or remove collect article 19 | * @param id article id 20 | * @param isAdd true add, false remove 21 | */ 22 | override fun collectArticle(id: Int, isAdd: Boolean) { 23 | collectArticleModel.collectArticle(this, id, isAdd) 24 | } 25 | 26 | /** 27 | * add collect article success 28 | * @param result HomeListResponse 29 | * @param isAdd true add, false remove 30 | */ 31 | override fun collectArticleSuccess(result: HomeListResponse, isAdd: Boolean) { 32 | if (result.errorCode != 0) { 33 | collectArticleView.collectArticleFailed(result.errorMsg, isAdd) 34 | } else { 35 | collectArticleView.collectArticleSuccess(result, isAdd) 36 | } 37 | } 38 | 39 | /** 40 | * add collect article failed 41 | * @param errorMessage error message 42 | * @param isAdd true add, false remove 43 | */ 44 | override fun collectArticleFailed(errorMessage: String?, isAdd: Boolean) { 45 | collectArticleView.collectArticleFailed(errorMessage, isAdd) 46 | } 47 | 48 | /** 49 | * add or remove outside collect article 50 | * @param title article title 51 | * @param author article author 52 | * @param link article link 53 | * @param isAdd true add, false remove 54 | */ 55 | override fun collectOutSideArticle( 56 | title: String, 57 | author: String, 58 | link: String, 59 | isAdd: Boolean 60 | ) { 61 | collectOutsideArticleModel.collectOutsideArticle(this, title, author, link, isAdd) 62 | } 63 | 64 | /** 65 | * add collect outside article success 66 | * @param result HomeListResponse 67 | * @param isAdd true add, false remove 68 | */ 69 | override fun collectOutsideArticleSuccess(result: HomeListResponse, isAdd: Boolean) { 70 | if (result.errorCode != 0) { 71 | collectArticleView.collectArticleFailed(result.errorMsg, isAdd) 72 | } else { 73 | collectArticleView.collectArticleSuccess(result, isAdd) 74 | } 75 | } 76 | 77 | /** 78 | * add collect outside article failed 79 | * @param errorMessage error message 80 | * @param isAdd true add, false remove 81 | */ 82 | override fun collectOutsideArticleFailed(errorMessage: String?, isAdd: Boolean) { 83 | collectArticleView.collectArticleFailed(errorMessage, isAdd) 84 | } 85 | 86 | fun cancelRequest() { 87 | collectArticleModel.cancelCollectRequest() 88 | collectOutsideArticleModel.cancelCollectOutsideRequest() 89 | } 90 | } -------------------------------------------------------------------------------- /app/src/main/java/top/jowanxu/wanandroidclient/presenter/HomeFragmentPresenterImpl.kt: -------------------------------------------------------------------------------- 1 | package top.jowanxu.wanandroidclient.presenter 2 | 3 | import top.jowanxu.wanandroidclient.bean.BannerResponse 4 | import top.jowanxu.wanandroidclient.bean.HomeListResponse 5 | import top.jowanxu.wanandroidclient.model.CollectArticleModel 6 | import top.jowanxu.wanandroidclient.model.HomeModel 7 | import top.jowanxu.wanandroidclient.model.HomeModelImpl 8 | import top.jowanxu.wanandroidclient.view.CollectArticleView 9 | import top.jowanxu.wanandroidclient.view.HomeFragmentView 10 | 11 | class HomeFragmentPresenterImpl( 12 | private val homeFragmentView: HomeFragmentView, 13 | private val collectArticleView: CollectArticleView 14 | ) : HomePresenter.OnHomeListListener, HomePresenter.OnCollectArticleListener, 15 | HomePresenter.OnBannerListener { 16 | 17 | private val homeModel: HomeModel = HomeModelImpl() 18 | private val collectArticleModel: CollectArticleModel = HomeModelImpl() 19 | /** 20 | * get home list 21 | * @param page page 22 | */ 23 | override fun getHomeList(page: Int) { 24 | homeModel.getHomeList(this, page) 25 | } 26 | 27 | /** 28 | * get home list success 29 | * @param result result 30 | */ 31 | override fun getHomeListSuccess(result: HomeListResponse) { 32 | if (result.errorCode != 0) { 33 | homeFragmentView.getHomeListFailed(result.errorMsg) 34 | return 35 | } 36 | // 列表总数 37 | val total = result.data.total 38 | if (total == 0) { 39 | homeFragmentView.getHomeListZero() 40 | return 41 | } 42 | // 当第一页小于一页总数时 43 | if (total < result.data.size) { 44 | homeFragmentView.getHomeListSmall(result) 45 | return 46 | } 47 | homeFragmentView.getHomeListSuccess(result) 48 | } 49 | 50 | /** 51 | * get home list failed 52 | * @param errorMessage error message 53 | */ 54 | override fun getHomeListFailed(errorMessage: String?) { 55 | homeFragmentView.getHomeListFailed(errorMessage) 56 | } 57 | 58 | /** 59 | * add or remove collect article 60 | * @param id article id 61 | * @param isAdd true add, false remove 62 | */ 63 | override fun collectArticle(id: Int, isAdd: Boolean) { 64 | collectArticleModel.collectArticle(this, id, isAdd) 65 | } 66 | 67 | /** 68 | * add collect article success 69 | * @param result HomeListResponse 70 | * @param isAdd true add, false remove 71 | */ 72 | override fun collectArticleSuccess(result: HomeListResponse, isAdd: Boolean) { 73 | if (result.errorCode != 0) { 74 | collectArticleView.collectArticleFailed(result.errorMsg, isAdd) 75 | } else { 76 | collectArticleView.collectArticleSuccess(result, isAdd) 77 | } 78 | } 79 | 80 | /** 81 | * add collect article failed 82 | * @param errorMessage error message 83 | * @param isAdd true add, false remove 84 | */ 85 | override fun collectArticleFailed(errorMessage: String?, isAdd: Boolean) { 86 | collectArticleView.collectArticleFailed(errorMessage, isAdd) 87 | } 88 | 89 | /** 90 | * get banner 91 | */ 92 | override fun getBanner() { 93 | homeModel.getBanner(this) 94 | } 95 | 96 | /** 97 | * get banner success 98 | * @param result BannerResponse 99 | */ 100 | override fun getBannerSuccess(result: BannerResponse) { 101 | if (result.errorCode != 0) { 102 | homeFragmentView.getBannerFailed(result.errorMsg) 103 | return 104 | } 105 | result.data ?: let { 106 | homeFragmentView.getBannerZero() 107 | return 108 | } 109 | homeFragmentView.getBannerSuccess(result) 110 | } 111 | 112 | /** 113 | * get banner failed 114 | * @param errorMessage error message 115 | */ 116 | override fun getBannerFailed(errorMessage: String?) { 117 | homeFragmentView.getBannerFailed(errorMessage) 118 | } 119 | 120 | /** 121 | * cancel request 122 | */ 123 | fun cancelRequest() { 124 | homeModel.cancelBannerRequest() 125 | homeModel.cancelHomeListRequest() 126 | collectArticleModel.cancelCollectRequest() 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /app/src/main/java/top/jowanxu/wanandroidclient/presenter/HomePresenter.kt: -------------------------------------------------------------------------------- 1 | package top.jowanxu.wanandroidclient.presenter 2 | 3 | import top.jowanxu.wanandroidclient.bean.* 4 | 5 | /** 6 | * 首页Presenter接口 7 | */ 8 | interface HomePresenter { 9 | 10 | /** 11 | * get home list interface 12 | */ 13 | interface OnHomeListListener { 14 | 15 | /** 16 | * get home list 17 | * @param page page 18 | */ 19 | fun getHomeList(page: Int = 0) 20 | 21 | /** 22 | * get home list success 23 | * @param result result 24 | */ 25 | fun getHomeListSuccess(result: HomeListResponse) 26 | 27 | /** 28 | * get home list failed 29 | * @param errorMessage error message 30 | */ 31 | fun getHomeListFailed(errorMessage: String?) 32 | } 33 | 34 | /** 35 | * get type tree list interface 36 | */ 37 | interface OnTypeTreeListListener { 38 | 39 | /** 40 | * get type tree list 41 | */ 42 | fun getTypeTreeList() 43 | 44 | /** 45 | * get type tree list success 46 | * @param result result 47 | */ 48 | fun getTypeTreeListSuccess(result: TreeListResponse) 49 | 50 | /** 51 | * get type tree list failed 52 | * @param errorMessage error message 53 | */ 54 | fun getTypeTreeListFailed(errorMessage: String?) 55 | } 56 | 57 | /** 58 | * login Listener 59 | */ 60 | interface OnLoginListener { 61 | /** 62 | * login 63 | * @param username username 64 | * @param password password 65 | */ 66 | fun loginWanAndroid(username: String, password: String) 67 | 68 | /** 69 | * login success 70 | * @param result LoginResponse 71 | */ 72 | fun loginSuccess(result: LoginResponse) 73 | 74 | /** 75 | * login failed 76 | * @param errorMessage error message 77 | */ 78 | fun loginFailed(errorMessage: String?) 79 | } 80 | 81 | /** 82 | * register Listener 83 | */ 84 | interface OnRegisterListener { 85 | /** 86 | * register 87 | * @param username username 88 | * @param password password 89 | * @param repassword repassword 90 | */ 91 | fun registerWanAndroid(username: String, password: String, repassword: String) 92 | 93 | /** 94 | * register success 95 | * @param result LoginResponse 96 | */ 97 | fun registerSuccess(result: LoginResponse) 98 | 99 | /** 100 | * register failed 101 | * @param errorMessage error message 102 | */ 103 | fun registerFailed(errorMessage: String?) 104 | } 105 | 106 | /** 107 | * get friend list interface 108 | */ 109 | interface OnFriendListListener { 110 | 111 | /** 112 | * get friend tree list 113 | */ 114 | fun getFriendList() 115 | 116 | /** 117 | * get friend list success 118 | */ 119 | fun getFriendListSuccess( 120 | bookmarkResult: FriendListResponse?, 121 | commonResult: FriendListResponse, 122 | hotResult: HotKeyResponse 123 | ) 124 | 125 | /** 126 | * get friend list failed 127 | * @param errorMessage error message 128 | */ 129 | fun getFriendListFailed(errorMessage: String?) 130 | } 131 | 132 | /** 133 | * collect article listener 134 | */ 135 | interface OnCollectArticleListener { 136 | /** 137 | * add or remove collect article 138 | * @param id article id 139 | * @param isAdd true add, false remove 140 | */ 141 | fun collectArticle(id: Int, isAdd: Boolean) 142 | 143 | 144 | /** 145 | * add collect article success 146 | * @param result HomeListResponse 147 | * @param isAdd true add, false remove 148 | */ 149 | fun collectArticleSuccess(result: HomeListResponse, isAdd: Boolean) 150 | 151 | /** 152 | * add collect article failed 153 | * @param errorMessage error message 154 | * @param isAdd true add, false remove 155 | */ 156 | fun collectArticleFailed(errorMessage: String?, isAdd: Boolean) 157 | } 158 | 159 | /** 160 | * collect outside article listener 161 | */ 162 | interface OnCollectOutsideArticleListener { 163 | /** 164 | * add or remove outside collect article 165 | * @param title article title 166 | * @param author article author 167 | * @param link article link 168 | * @param isAdd true add, false remove 169 | */ 170 | fun collectOutSideArticle(title: String, author: String, link: String, isAdd: Boolean) 171 | 172 | /** 173 | * add collect outside article success 174 | * @param result HomeListResponse 175 | * @param isAdd true add, false remove 176 | */ 177 | fun collectOutsideArticleSuccess(result: HomeListResponse, isAdd: Boolean) 178 | 179 | /** 180 | * add collect outside article failed 181 | * @param errorMessage error message 182 | * @param isAdd true add, false remove 183 | */ 184 | fun collectOutsideArticleFailed(errorMessage: String?, isAdd: Boolean) 185 | } 186 | 187 | /** 188 | * get banner listener 189 | */ 190 | interface OnBannerListener { 191 | /** 192 | * get banner 193 | */ 194 | fun getBanner() 195 | 196 | /** 197 | * get banner success 198 | * @param result BannerResponse 199 | */ 200 | fun getBannerSuccess(result: BannerResponse) 201 | 202 | /** 203 | * get banner failed 204 | * @param errorMessage error message 205 | */ 206 | fun getBannerFailed(errorMessage: String?) 207 | } 208 | 209 | /** 210 | * get friend list interface 211 | */ 212 | interface OnBookmarkListListener { 213 | 214 | /** 215 | * get friend tree list 216 | */ 217 | fun getFriendList() 218 | 219 | /** 220 | * get friend list success 221 | * @param result result 222 | */ 223 | fun getFriendListSuccess(result: FriendListResponse) 224 | 225 | /** 226 | * get friend list failed 227 | * @param errorMessage error message 228 | */ 229 | fun getFriendListFailed(errorMessage: String?) 230 | } 231 | } -------------------------------------------------------------------------------- /app/src/main/java/top/jowanxu/wanandroidclient/presenter/LoginPresenterImpl.kt: -------------------------------------------------------------------------------- 1 | package top.jowanxu.wanandroidclient.presenter 2 | 3 | import top.jowanxu.wanandroidclient.bean.LoginResponse 4 | import top.jowanxu.wanandroidclient.model.HomeModel 5 | import top.jowanxu.wanandroidclient.model.HomeModelImpl 6 | import top.jowanxu.wanandroidclient.view.LoginView 7 | 8 | class LoginPresenterImpl(private val loginView: LoginView) : HomePresenter.OnLoginListener, 9 | HomePresenter.OnRegisterListener { 10 | 11 | private val homeModel: HomeModel = HomeModelImpl() 12 | /** 13 | * login 14 | * @param username username 15 | * @param password password 16 | */ 17 | override fun loginWanAndroid(username: String, password: String) { 18 | homeModel.loginWanAndroid(this, username, password) 19 | } 20 | 21 | /** 22 | * login success 23 | * @param result LoginResponse 24 | */ 25 | override fun loginSuccess(result: LoginResponse) { 26 | if (result.errorCode != 0) { 27 | loginView.loginFailed(result.errorMsg) 28 | } else { 29 | loginView.loginSuccess(result) 30 | loginView.loginRegisterAfter(result) 31 | } 32 | } 33 | 34 | /** 35 | * login failed 36 | * @param errorMessage error message 37 | */ 38 | override fun loginFailed(errorMessage: String?) { 39 | loginView.loginFailed(errorMessage) 40 | } 41 | 42 | /** 43 | * register 44 | * @param username username 45 | * @param password password 46 | * @param repassword repassword 47 | */ 48 | override fun registerWanAndroid(username: String, password: String, repassword: String) { 49 | homeModel.registerWanAndroid(this, username, password, repassword) 50 | } 51 | 52 | /** 53 | * register success 54 | * @param result LoginResponse 55 | */ 56 | override fun registerSuccess(result: LoginResponse) { 57 | if (result.errorCode != 0) { 58 | loginView.registerFailed(result.errorMsg) 59 | } else { 60 | loginView.registerSuccess(result) 61 | loginView.loginRegisterAfter(result) 62 | } 63 | } 64 | 65 | /** 66 | * register failed 67 | * @param errorMessage error message 68 | */ 69 | override fun registerFailed(errorMessage: String?) { 70 | loginView.registerFailed(errorMessage) 71 | } 72 | 73 | fun cancelRequest() { 74 | homeModel.cancelLoginRequest() 75 | homeModel.cancelRegisterRequest() 76 | } 77 | } -------------------------------------------------------------------------------- /app/src/main/java/top/jowanxu/wanandroidclient/presenter/SearchPresenter.kt: -------------------------------------------------------------------------------- 1 | package top.jowanxu.wanandroidclient.presenter 2 | 3 | import top.jowanxu.wanandroidclient.bean.HomeListResponse 4 | 5 | /** 6 | * 首页Presenter接口 7 | */ 8 | interface SearchPresenter { 9 | 10 | interface OnSearchListListener { 11 | 12 | fun getSearchList(page: Int = 0, k: String) 13 | 14 | /** 15 | * 获取搜索结果列表成功 16 | */ 17 | fun getSearchListSuccess(result: HomeListResponse) 18 | 19 | /** 20 | * 获取搜索结果列表失败 21 | */ 22 | fun getSearchListFailed(errorMessage: String?) 23 | } 24 | 25 | /** 26 | * get home list interface 27 | */ 28 | interface OnLikeListListener { 29 | 30 | /** 31 | * get home list 32 | * @param page page 33 | */ 34 | fun getLikeList(page: Int = 0) 35 | 36 | /** 37 | * get home list success 38 | * @param result result 39 | */ 40 | fun getLikeListSuccess(result: HomeListResponse) 41 | 42 | /** 43 | * get home list failed 44 | * @param errorMessage error message 45 | */ 46 | fun getLikeListFailed(errorMessage: String?) 47 | } 48 | } -------------------------------------------------------------------------------- /app/src/main/java/top/jowanxu/wanandroidclient/presenter/SearchPresenterImpl.kt: -------------------------------------------------------------------------------- 1 | package top.jowanxu.wanandroidclient.presenter 2 | 3 | import top.jowanxu.wanandroidclient.bean.HomeListResponse 4 | import top.jowanxu.wanandroidclient.model.CollectArticleModel 5 | import top.jowanxu.wanandroidclient.model.SearchModel 6 | import top.jowanxu.wanandroidclient.model.SearchModelImpl 7 | import top.jowanxu.wanandroidclient.view.CollectArticleView 8 | import top.jowanxu.wanandroidclient.view.SearchListView 9 | 10 | class SearchPresenterImpl( 11 | private val searchView: SearchListView, 12 | private val collectArticleView: CollectArticleView 13 | ) : SearchPresenter.OnSearchListListener, SearchPresenter.OnLikeListListener, 14 | HomePresenter.OnCollectArticleListener { 15 | 16 | private val searchModel: SearchModel = SearchModelImpl() 17 | private val collectArticleModel: CollectArticleModel = SearchModelImpl() 18 | 19 | override fun getSearchList(page: Int, k: String) { 20 | searchModel.getSearchList(this, page, k) 21 | } 22 | 23 | override fun getSearchListSuccess(result: HomeListResponse) { 24 | if (result.errorCode != 0) { 25 | searchView.getSearchListFailed(result.errorMsg) 26 | return 27 | } 28 | // 列表总数 29 | val total = result.data.total 30 | if (total == 0) { 31 | searchView.getSearchListZero() 32 | return 33 | } 34 | // 当第一页小于一页总数时 35 | if (total < result.data.size) { 36 | searchView.getSearchListSmall(result) 37 | return 38 | } 39 | searchView.getSearchListSuccess(result) 40 | } 41 | 42 | override fun getSearchListFailed(errorMessage: String?) { 43 | searchView.getSearchListFailed(errorMessage) 44 | } 45 | 46 | /** 47 | * get home list 48 | * @param page page 49 | */ 50 | override fun getLikeList(page: Int) { 51 | searchModel.getLikeList(this, page) 52 | } 53 | 54 | /** 55 | * get home list success 56 | * @param result result 57 | */ 58 | override fun getLikeListSuccess(result: HomeListResponse) { 59 | if (result.errorCode != 0) { 60 | searchView.getLikeListFailed(result.errorMsg) 61 | return 62 | } 63 | // 列表总数 64 | val total = result.data.total 65 | if (total == 0) { 66 | searchView.getLikeListZero() 67 | return 68 | } 69 | // 当第一页小于一页总数时 70 | if (total < result.data.size) { 71 | searchView.getLikeListSmall(result) 72 | return 73 | } 74 | searchView.getLikeListSuccess(result) 75 | } 76 | 77 | /** 78 | * get home list failed 79 | * @param errorMessage error message 80 | */ 81 | override fun getLikeListFailed(errorMessage: String?) { 82 | searchView.getLikeListFailed(errorMessage) 83 | } 84 | 85 | /** 86 | * add or remove collect article 87 | * @param id article id 88 | * @param isAdd true add, false remove 89 | */ 90 | override fun collectArticle(id: Int, isAdd: Boolean) { 91 | collectArticleModel.collectArticle(this, id, isAdd) 92 | } 93 | 94 | /** 95 | * add collect article success 96 | * @param result HomeListResponse 97 | * @param isAdd true add, false remove 98 | */ 99 | override fun collectArticleSuccess(result: HomeListResponse, isAdd: Boolean) { 100 | if (result.errorCode != 0) { 101 | collectArticleView.collectArticleFailed(result.errorMsg, isAdd) 102 | } else { 103 | collectArticleView.collectArticleSuccess(result, isAdd) 104 | } 105 | } 106 | 107 | /** 108 | * add collect article failed 109 | * @param errorMessage error message 110 | * @param isAdd true add, false remove 111 | */ 112 | override fun collectArticleFailed(errorMessage: String?, isAdd: Boolean) { 113 | collectArticleView.collectArticleFailed(errorMessage, isAdd) 114 | } 115 | 116 | fun cancelRequest() { 117 | searchModel.cancelRequest() 118 | searchModel.cancelLikeListRequest() 119 | collectArticleModel.cancelCollectRequest() 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /app/src/main/java/top/jowanxu/wanandroidclient/presenter/TypeArticlePresenter.kt: -------------------------------------------------------------------------------- 1 | package top.jowanxu.wanandroidclient.presenter 2 | 3 | import top.jowanxu.wanandroidclient.bean.ArticleListResponse 4 | 5 | interface TypeArticlePresenter { 6 | /** 7 | * get Type Article list 8 | * @param page page 9 | * @param cid cid 10 | */ 11 | fun getTypeArticleList(page: Int = 0, cid: Int) 12 | 13 | /** 14 | * get Type Article list interface 15 | */ 16 | interface OnTypeArticleListListener { 17 | /** 18 | * get Type Article list success 19 | * @param result ArticleListResponse 20 | */ 21 | fun getTypeArticleListSuccess(result: ArticleListResponse) 22 | 23 | /** 24 | * get Type Article list failed 25 | * @param errorMessage error message 26 | */ 27 | fun getTypeArticleListFailed(errorMessage: String?) 28 | } 29 | } -------------------------------------------------------------------------------- /app/src/main/java/top/jowanxu/wanandroidclient/presenter/TypeArticlePresenterImpl.kt: -------------------------------------------------------------------------------- 1 | package top.jowanxu.wanandroidclient.presenter 2 | 3 | import top.jowanxu.wanandroidclient.bean.ArticleListResponse 4 | import top.jowanxu.wanandroidclient.bean.HomeListResponse 5 | import top.jowanxu.wanandroidclient.model.CollectArticleModel 6 | import top.jowanxu.wanandroidclient.model.HomeModelImpl 7 | import top.jowanxu.wanandroidclient.model.TypeArticleModel 8 | import top.jowanxu.wanandroidclient.model.TypeArticleModelImpl 9 | import top.jowanxu.wanandroidclient.view.CollectArticleView 10 | import top.jowanxu.wanandroidclient.view.TypeArticleFragmentView 11 | 12 | class TypeArticlePresenterImpl( 13 | private val typeArticleFragmentView: TypeArticleFragmentView, 14 | private val collectArticleView: CollectArticleView 15 | ) : TypeArticlePresenter, TypeArticlePresenter.OnTypeArticleListListener, 16 | HomePresenter.OnCollectArticleListener { 17 | 18 | private val typeArticleModel: TypeArticleModel = TypeArticleModelImpl() 19 | private val collectArticleModel: CollectArticleModel = HomeModelImpl() 20 | 21 | /** 22 | * get Type Article list 23 | * @param page page 24 | * @param cid cid 25 | */ 26 | override fun getTypeArticleList(page: Int, cid: Int) { 27 | typeArticleModel.getTypeArticleList(this, page, cid) 28 | } 29 | 30 | /** 31 | * get Type Article list success 32 | * @param result ArticleListResponse 33 | */ 34 | override fun getTypeArticleListSuccess(result: ArticleListResponse) { 35 | if (result.errorCode != 0) { 36 | typeArticleFragmentView.getTypeArticleListFailed(result.errorMsg) 37 | return 38 | } 39 | val total = result.data.total 40 | if (total == 0) { 41 | typeArticleFragmentView.getTypeArticleListZero() 42 | return 43 | } 44 | if (total < result.data.size) { 45 | typeArticleFragmentView.getTypeArticleListSmall(result) 46 | return 47 | } 48 | typeArticleFragmentView.getTypeArticleListSuccess(result) 49 | } 50 | 51 | /** 52 | * get Type Article list failed 53 | * @param errorMessage error message 54 | */ 55 | override fun getTypeArticleListFailed(errorMessage: String?) { 56 | typeArticleFragmentView.getTypeArticleListFailed(errorMessage) 57 | } 58 | 59 | /** 60 | * add or remove collect article 61 | * @param id article id 62 | * @param isAdd true add, false remove 63 | */ 64 | override fun collectArticle(id: Int, isAdd: Boolean) { 65 | collectArticleModel.collectArticle(this, id, isAdd) 66 | } 67 | 68 | /** 69 | * add collect article success 70 | * @param result HomeListResponse 71 | * @param isAdd true add, false remove 72 | */ 73 | override fun collectArticleSuccess(result: HomeListResponse, isAdd: Boolean) { 74 | if (result.errorCode != 0) { 75 | collectArticleView.collectArticleFailed(result.errorMsg, isAdd) 76 | } else { 77 | collectArticleView.collectArticleSuccess(result, isAdd) 78 | } 79 | } 80 | 81 | /** 82 | * add collect article failed 83 | * @param errorMessage error message 84 | * @param isAdd true add, false remove 85 | */ 86 | override fun collectArticleFailed(errorMessage: String?, isAdd: Boolean) { 87 | collectArticleView.collectArticleFailed(errorMessage, isAdd) 88 | } 89 | 90 | fun cancelRequest() { 91 | typeArticleModel.cancelRequest() 92 | collectArticleModel.cancelCollectRequest() 93 | } 94 | } -------------------------------------------------------------------------------- /app/src/main/java/top/jowanxu/wanandroidclient/presenter/TypeFragmentPresenterImpl.kt: -------------------------------------------------------------------------------- 1 | package top.jowanxu.wanandroidclient.presenter 2 | 3 | import top.jowanxu.wanandroidclient.bean.TreeListResponse 4 | import top.jowanxu.wanandroidclient.model.HomeModel 5 | import top.jowanxu.wanandroidclient.model.HomeModelImpl 6 | import top.jowanxu.wanandroidclient.view.TypeFragmentView 7 | 8 | class TypeFragmentPresenterImpl(private val typeFragmentView: TypeFragmentView) : 9 | HomePresenter.OnTypeTreeListListener { 10 | 11 | private val homeModel: HomeModel = HomeModelImpl() 12 | /** 13 | * get type tree list 14 | */ 15 | override fun getTypeTreeList() { 16 | homeModel.getTypeTreeList(this) 17 | } 18 | 19 | /** 20 | * get type tree list success 21 | * @param result result 22 | */ 23 | override fun getTypeTreeListSuccess(result: TreeListResponse) { 24 | if (result.errorCode != 0) { 25 | typeFragmentView.getTypeListFailed(result.errorMsg) 26 | return 27 | } 28 | if (result.data.isEmpty()) { 29 | typeFragmentView.getTypeListZero() 30 | return 31 | } 32 | typeFragmentView.getTypeListSuccess(result) 33 | } 34 | 35 | /** 36 | * get type tree list failed 37 | * @param errorMessage error message 38 | */ 39 | override fun getTypeTreeListFailed(errorMessage: String?) { 40 | typeFragmentView.getTypeListFailed(errorMessage) 41 | } 42 | 43 | /** 44 | * cancel request 45 | */ 46 | fun cancelRequest() { 47 | homeModel.cancelTypeTreeRequest() 48 | } 49 | } -------------------------------------------------------------------------------- /app/src/main/java/top/jowanxu/wanandroidclient/retrofit/RetrofitHelper.kt: -------------------------------------------------------------------------------- 1 | import com.jakewharton.retrofit2.adapter.kotlin.coroutines.experimental.CoroutineCallAdapterFactory 2 | import okhttp3.OkHttpClient 3 | import okhttp3.logging.HttpLoggingInterceptor 4 | import retrofit2.Retrofit 5 | import retrofit2.converter.gson.GsonConverterFactory 6 | import top.jowanxu.wanandroidclient.base.Preference 7 | import java.util.concurrent.TimeUnit 8 | 9 | object RetrofitHelper { 10 | private const val TAG = "RetrofitHelper" 11 | private const val CONTENT_PRE = "OkHttp: " 12 | private const val SAVE_USER_LOGIN_KEY = "user/login" 13 | private const val SAVE_USER_REGISTER_KEY = "user/register" 14 | private const val SET_COOKIE_KEY = "set-cookie" 15 | private const val COOKIE_NAME = "Cookie" 16 | private const val CONNECT_TIMEOUT = 30L 17 | private const val READ_TIMEOUT = 10L 18 | 19 | val retrofitService: RetrofitService = 20 | RetrofitHelper.getService(Constant.REQUEST_BASE_URL, RetrofitService::class.java) 21 | 22 | /** 23 | * create Retrofit 24 | */ 25 | private fun create(url: String): Retrofit { 26 | // okHttpClientBuilder 27 | val okHttpClientBuilder = OkHttpClient().newBuilder().apply { 28 | connectTimeout(CONNECT_TIMEOUT, TimeUnit.SECONDS) 29 | readTimeout(READ_TIMEOUT, TimeUnit.SECONDS) 30 | // get response cookie 31 | addInterceptor { 32 | val request = it.request() 33 | val response = it.proceed(request) 34 | val requestUrl = request.url().toString() 35 | val domain = request.url().host() 36 | // set-cookie maybe has multi, login to save cookie 37 | if ((requestUrl.contains(SAVE_USER_LOGIN_KEY) || requestUrl.contains( 38 | SAVE_USER_REGISTER_KEY 39 | )) 40 | && !response.headers(SET_COOKIE_KEY).isEmpty()) { 41 | val cookies = response.headers(SET_COOKIE_KEY) 42 | val cookie = encodeCookie(cookies) 43 | saveCookie(requestUrl, domain, cookie) 44 | } 45 | response 46 | } 47 | // set request cookie 48 | addInterceptor { 49 | val request = it.request() 50 | val builder = request.newBuilder() 51 | val domain = request.url().host() 52 | // get domain cookie 53 | if (domain.isNotEmpty()) { 54 | val spDomain: String by Preference(domain, "") 55 | val cookie: String = if (spDomain.isNotEmpty()) spDomain else "" 56 | if (cookie.isNotEmpty()) { 57 | builder.addHeader(COOKIE_NAME, cookie) 58 | } 59 | } 60 | it.proceed(builder.build()) 61 | } 62 | // add log print 63 | if (Constant.INTERCEPTOR_ENABLE) { 64 | // loggingInterceptor 65 | addInterceptor(HttpLoggingInterceptor(HttpLoggingInterceptor.Logger { 66 | loge(TAG, CONTENT_PRE + it) 67 | }).apply { 68 | // log level 69 | level = HttpLoggingInterceptor.Level.BODY 70 | }) 71 | } 72 | } 73 | 74 | return RetrofitBuild( 75 | url = url, 76 | client = okHttpClientBuilder.build(), 77 | gsonFactory = GsonConverterFactory.create(), 78 | coroutineCallAdapterFactory = CoroutineCallAdapterFactory() 79 | ) 80 | .retrofit 81 | } 82 | 83 | /** 84 | * get ServiceApi 85 | */ 86 | private fun getService(url: String, service: Class): T = create(url).create(service) 87 | 88 | /** 89 | * save cookie to SharePreferences 90 | */ 91 | @Suppress("ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE") 92 | private fun saveCookie(url: String?, domain: String?, cookies: String) { 93 | url ?: return 94 | var spUrl: String by Preference(url, cookies) 95 | @Suppress("UNUSED_VALUE") 96 | spUrl = cookies 97 | domain ?: return 98 | var spDomain: String by Preference(domain, cookies) 99 | @Suppress("UNUSED_VALUE") 100 | spDomain = cookies 101 | } 102 | } 103 | 104 | /** 105 | * create retrofit build 106 | */ 107 | class RetrofitBuild( 108 | url: String, client: OkHttpClient, 109 | gsonFactory: GsonConverterFactory, 110 | coroutineCallAdapterFactory: CoroutineCallAdapterFactory 111 | ) { 112 | val retrofit: Retrofit = Retrofit.Builder().apply { 113 | baseUrl(url) 114 | client(client) 115 | addConverterFactory(gsonFactory) 116 | addCallAdapterFactory(coroutineCallAdapterFactory) 117 | }.build() 118 | } -------------------------------------------------------------------------------- /app/src/main/java/top/jowanxu/wanandroidclient/retrofit/RetrofitService.kt: -------------------------------------------------------------------------------- 1 | import kotlinx.coroutines.experimental.Deferred 2 | import retrofit2.http.* 3 | import top.jowanxu.wanandroidclient.bean.* 4 | 5 | /** 6 | * Retrofit请求api 7 | */ 8 | interface RetrofitService { 9 | 10 | /** 11 | * 首页数据 12 | * http://www.wanandroid.com/article/list/0/json 13 | * @param page page 14 | */ 15 | 16 | @GET("/article/list/{page}/json") 17 | fun getHomeList( 18 | @Path("page") page: Int 19 | ): Deferred 20 | 21 | /** 22 | * 知识体系 23 | * http://www.wanandroid.com/tree/json 24 | */ 25 | @GET("/tree/json") 26 | fun getTypeTreeList(): Deferred 27 | 28 | /** 29 | * 知识体系下的文章 30 | * http://www.wanandroid.com/article/list/0/json?cid=168 31 | * @param page page 32 | * @param cid cid 33 | */ 34 | @GET("/article/list/{page}/json") 35 | fun getArticleList( 36 | @Path("page") page: Int, 37 | @Query("cid") cid: Int 38 | ): Deferred 39 | 40 | /** 41 | * 常用网站 42 | * http://www.wanandroid.com/friend/json 43 | */ 44 | @GET("/friend/json") 45 | fun getFriendList(): Deferred 46 | 47 | /** 48 | * 大家都在搜 49 | * http://www.wanandroid.com/hotkey/json 50 | */ 51 | @GET("/hotkey/json") 52 | fun getHotKeyList(): Deferred 53 | 54 | /** 55 | * 搜索 56 | * http://www.wanandroid.com/article/query/0/json 57 | * @param page page 58 | * @param k POST search key 59 | */ 60 | @POST("/article/query/{page}/json") 61 | @FormUrlEncoded 62 | fun getSearchList( 63 | @Path("page") page: Int, 64 | @Field("k") k: String 65 | ): Deferred 66 | 67 | /** 68 | * 登录 69 | * @param username username 70 | * @param password password 71 | * @return Deferred 72 | */ 73 | @POST("/user/login") 74 | @FormUrlEncoded 75 | fun loginWanAndroid( 76 | @Field("username") username: String, 77 | @Field("password") password: String 78 | ): Deferred 79 | 80 | /** 81 | * 注册 82 | * @param username username 83 | * @param password password 84 | * @param repassword repassword 85 | * @return Deferred 86 | */ 87 | @POST("/user/register") 88 | @FormUrlEncoded 89 | fun registerWanAndroid( 90 | @Field("username") username: String, 91 | @Field("password") password: String, 92 | @Field("repassword") repassowrd: String 93 | ): Deferred 94 | 95 | /** 96 | * 获取自己收藏的文章列表 97 | * @param page page 98 | * @return Deferred 99 | */ 100 | @GET("/lg/collect/list/{page}/json") 101 | fun getLikeList( 102 | @Path("page") page: Int 103 | ): Deferred 104 | 105 | /** 106 | * 收藏文章 107 | * @param id id 108 | * @return Deferred 109 | */ 110 | @POST("/lg/collect/{id}/json") 111 | fun addCollectArticle( 112 | @Path("id") id: Int 113 | ): Deferred 114 | 115 | /** 116 | * 收藏站外文章 117 | * @param title title 118 | * @param author author 119 | * @param link link 120 | * @return Deferred 121 | */ 122 | @POST("/lg/collect/add/json") 123 | @FormUrlEncoded 124 | fun addCollectOutsideArticle( 125 | @Field("title") title: String, 126 | @Field("author") author: String, 127 | @Field("link") link: String 128 | ): Deferred 129 | 130 | /** 131 | * 删除收藏文章 132 | * @param id id 133 | * @param originId -1 134 | * @return Deferred 135 | */ 136 | @POST("/lg/uncollect/{id}/json") 137 | @FormUrlEncoded 138 | fun removeCollectArticle( 139 | @Path("id") id: Int, 140 | @Field("originId") originId: Int = -1 141 | ): Deferred 142 | 143 | /** 144 | * 首页Banner 145 | * @return BannerResponse 146 | */ 147 | @GET("/banner/json") 148 | fun getBanner(): Deferred 149 | 150 | /** 151 | * 我的常用网址 152 | * @return FriendListResponse 153 | */ 154 | @GET("/lg/collect/usertools/json") 155 | fun getBookmarkList(): Deferred 156 | } -------------------------------------------------------------------------------- /app/src/main/java/top/jowanxu/wanandroidclient/ui/activity/AboutActivity.kt: -------------------------------------------------------------------------------- 1 | package top.jowanxu.wanandroidclient.ui.activity 2 | 3 | import android.os.Bundle 4 | import android.text.Html 5 | import android.text.method.LinkMovementMethod 6 | import android.view.MenuItem 7 | import kotlinx.android.synthetic.main.activity_about.* 8 | import kotlinx.android.synthetic.main.content_about.* 9 | import top.jowanxu.wanandroidclient.R 10 | import top.jowanxu.wanandroidclient.base.BaseActivity 11 | 12 | class AboutActivity : BaseActivity() { 13 | 14 | override fun setLayoutId(): Int = R.layout.activity_about 15 | 16 | override fun initImmersionBar() { 17 | super.initImmersionBar() 18 | immersionBar.titleBar(R.id.toolbar).init() 19 | } 20 | 21 | override fun onCreate(savedInstanceState: Bundle?) { 22 | super.onCreate(savedInstanceState) 23 | toolbar.run { 24 | title = getString(R.string.my_about) 25 | setSupportActionBar(this) 26 | supportActionBar?.setDisplayHomeAsUpEnabled(true) 27 | } 28 | aboutVersion.text = getString( 29 | R.string.version_code, getString(R.string.app_name), 30 | packageManager.getPackageInfo(packageName, 0).versionName 31 | ) 32 | @Suppress("DEPRECATION") 33 | aboutContent.run { 34 | text = Html.fromHtml(getString(R.string.about_content)) 35 | movementMethod = LinkMovementMethod.getInstance() 36 | } 37 | } 38 | 39 | override fun onOptionsItemSelected(item: MenuItem): Boolean { 40 | if (item.itemId == android.R.id.home) { 41 | finish() 42 | } 43 | return super.onOptionsItemSelected(item) 44 | } 45 | 46 | override fun cancelRequest() { 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /app/src/main/java/top/jowanxu/wanandroidclient/ui/activity/LoginActivity.kt: -------------------------------------------------------------------------------- 1 | package top.jowanxu.wanandroidclient.ui.activity 2 | 3 | import Constant 4 | import android.app.Activity 5 | import android.content.Intent 6 | import android.os.Bundle 7 | import android.text.TextUtils 8 | import android.view.View 9 | import com.gyf.barlibrary.ImmersionBar 10 | import kotlinx.android.synthetic.main.activity_login.* 11 | import toast 12 | import top.jowanxu.wanandroidclient.R 13 | import top.jowanxu.wanandroidclient.base.BaseActivity 14 | import top.jowanxu.wanandroidclient.base.Preference 15 | import top.jowanxu.wanandroidclient.bean.LoginResponse 16 | import top.jowanxu.wanandroidclient.presenter.LoginPresenterImpl 17 | import top.jowanxu.wanandroidclient.view.LoginView 18 | 19 | class LoginActivity : BaseActivity(), LoginView { 20 | /** 21 | * check login for SharedPreferences 22 | */ 23 | private var isLogin: Boolean by Preference(Constant.LOGIN_KEY, false) 24 | /** 25 | * local username 26 | */ 27 | private var user: String by Preference(Constant.USERNAME_KEY, "") 28 | /** 29 | * local password 30 | */ 31 | private var pwd: String by Preference(Constant.PASSWORD_KEY, "") 32 | 33 | private val loginPresenter: LoginPresenterImpl by lazy { 34 | LoginPresenterImpl(this) 35 | } 36 | 37 | override fun setLayoutId(): Int = R.layout.activity_login 38 | 39 | override fun initImmersionBar() { 40 | super.initImmersionBar() 41 | if (ImmersionBar.isSupportStatusBarDarkFont()) 42 | immersionBar.statusBarDarkFont(true).init() 43 | } 44 | 45 | override fun onCreate(savedInstanceState: Bundle?) { 46 | super.onCreate(savedInstanceState) 47 | login.setOnClickListener(onClickListener) 48 | register.setOnClickListener(onClickListener) 49 | loginExit.setOnClickListener(onClickListener) 50 | } 51 | 52 | override fun cancelRequest() { 53 | loginPresenter.cancelRequest() 54 | } 55 | 56 | /** 57 | * login or register success after operation 58 | * @param result LoginResponse 59 | */ 60 | override fun loginRegisterAfter(result: LoginResponse) { 61 | isLogin = true 62 | user = result.data.username 63 | pwd = result.data.password 64 | loginProgress.visibility = View.GONE 65 | setResult( 66 | Activity.RESULT_OK, 67 | Intent().apply { putExtra(Constant.CONTENT_TITLE_KEY, result.data.username) }) 68 | finish() 69 | } 70 | 71 | /** 72 | * login success 73 | * @param result LoginResponse 74 | */ 75 | override fun loginSuccess(result: LoginResponse) { 76 | toast(getString(R.string.login_success)) 77 | } 78 | 79 | /** 80 | * login failed 81 | * @param errorMessage error message 82 | */ 83 | override fun loginFailed(errorMessage: String?) { 84 | isLogin = false 85 | loginProgress.visibility = View.GONE 86 | errorMessage?.let { 87 | toast(it) 88 | } 89 | } 90 | 91 | /** 92 | * register success 93 | * @param result LoginResponse 94 | */ 95 | override fun registerSuccess(result: LoginResponse) { 96 | toast(getString(R.string.register_success)) 97 | } 98 | 99 | /** 100 | * register failed 101 | * @param errorMessage error message 102 | */ 103 | override fun registerFailed(errorMessage: String?) { 104 | isLogin = false 105 | loginProgress.visibility = View.GONE 106 | username.requestFocus() 107 | errorMessage?.let { 108 | toast(it) 109 | } 110 | } 111 | 112 | /** 113 | * OnClickListener 114 | */ 115 | private val onClickListener = View.OnClickListener { view -> 116 | when (view.id) { 117 | R.id.login -> { 118 | if (checkContent()) { 119 | loginProgress.visibility = View.VISIBLE 120 | loginPresenter.loginWanAndroid( 121 | username.text.toString(), 122 | password.text.toString() 123 | ) 124 | } 125 | } 126 | R.id.register -> { 127 | if (checkContent()) { 128 | loginProgress.visibility = View.VISIBLE 129 | loginPresenter.registerWanAndroid( 130 | username.text.toString(), 131 | password.text.toString(), password.text.toString() 132 | ) 133 | } 134 | } 135 | R.id.loginExit -> { 136 | finish() 137 | } 138 | } 139 | } 140 | 141 | /** 142 | * check username and password and password confirm field to login or register. 143 | * @return success return true, failed return false. 144 | */ 145 | private fun checkContent(): Boolean { 146 | // error hint 147 | username.error = null 148 | password.error = null 149 | // cancel 150 | var cancel = false 151 | // attempt to view 152 | var focusView: View? = null 153 | // if register, check password confirm 154 | val pwdText = password.text.toString() 155 | val usernameText = username.text.toString() 156 | 157 | // check password 158 | if (TextUtils.isEmpty(pwdText)) { 159 | password.error = getString(R.string.password_not_empty) 160 | focusView = password 161 | cancel = true 162 | } else if (password.text.length < 6) { 163 | password.error = getString(R.string.password_length_short) 164 | focusView = password 165 | cancel = true 166 | } 167 | 168 | // check username 169 | if (TextUtils.isEmpty(usernameText)) { 170 | username.error = getString(R.string.username_not_empty) 171 | focusView = username 172 | cancel = true 173 | } 174 | 175 | // requestFocus 176 | if (cancel) { 177 | if (focusView != null) { 178 | focusView.requestFocus() 179 | } 180 | return false 181 | } else { 182 | return true 183 | } 184 | } 185 | } -------------------------------------------------------------------------------- /app/src/main/java/top/jowanxu/wanandroidclient/ui/activity/SplashActivity.kt: -------------------------------------------------------------------------------- 1 | package top.jowanxu.wanandroidclient.ui.activity 2 | 3 | import android.content.Intent 4 | import android.os.Bundle 5 | import android.support.v7.app.AppCompatActivity 6 | 7 | class SplashActivity : AppCompatActivity() { 8 | 9 | override fun onCreate(savedInstanceState: Bundle?) { 10 | super.onCreate(savedInstanceState) 11 | startActivity(Intent(this@SplashActivity, MainActivity::class.java)) 12 | finish() 13 | } 14 | } -------------------------------------------------------------------------------- /app/src/main/java/top/jowanxu/wanandroidclient/ui/activity/TypeContentActivity.kt: -------------------------------------------------------------------------------- 1 | package top.jowanxu.wanandroidclient.ui.activity 2 | 3 | import Constant 4 | import android.content.Intent 5 | import android.os.Bundle 6 | import android.support.design.widget.TabLayout 7 | import android.view.Menu 8 | import android.view.MenuItem 9 | import kotlinx.android.synthetic.main.activity_type_content.* 10 | import top.jowanxu.wanandroidclient.R 11 | import top.jowanxu.wanandroidclient.adapter.TypeArticlePagerAdapter 12 | import top.jowanxu.wanandroidclient.base.BaseActivity 13 | import top.jowanxu.wanandroidclient.bean.TreeListResponse 14 | import top.jowanxu.wanandroidclient.bean.TreeListResponse.Data.Children 15 | 16 | class TypeContentActivity : BaseActivity() { 17 | /** 18 | * toolbar title 19 | */ 20 | private lateinit var firstTitle: String 21 | /** 22 | * Children list 23 | */ 24 | private val list = mutableListOf() 25 | /** 26 | * check click for home or search 27 | */ 28 | private var target: Boolean = false 29 | /** 30 | * Adapter 31 | */ 32 | private val typeArticlePagerAdapter: TypeArticlePagerAdapter by lazy { 33 | TypeArticlePagerAdapter(list, supportFragmentManager) 34 | } 35 | 36 | override fun setLayoutId(): Int = R.layout.activity_type_content 37 | 38 | override fun initImmersionBar() { 39 | super.initImmersionBar() 40 | immersionBar.titleBar(R.id.typeSecondToolbar).init() 41 | } 42 | 43 | override fun onCreate(savedInstanceState: Bundle?) { 44 | super.onCreate(savedInstanceState) 45 | 46 | typeSecondToolbar.run { 47 | setSupportActionBar(this) 48 | supportActionBar?.setDisplayHomeAsUpEnabled(true) 49 | } 50 | intent.extras?.let { extras -> 51 | target = extras.getBoolean(Constant.CONTENT_TARGET_KEY, false) 52 | extras.getString(Constant.CONTENT_TITLE_KEY)?.let { 53 | firstTitle = it 54 | typeSecondToolbar.title = it 55 | } 56 | if (target) { 57 | list.add( 58 | Children( 59 | extras.getInt(Constant.CONTENT_CID_KEY, 0), 60 | firstTitle, 0, 0, 0, 0, null 61 | ) 62 | ) 63 | } else { 64 | extras.getSerializable(Constant.CONTENT_CHILDREN_DATA_KEY)?.let { 65 | val data = it as TreeListResponse.Data 66 | data.children?.let { children -> 67 | list.addAll(children) 68 | } 69 | } 70 | } 71 | } 72 | typeSecondViewPager.run { 73 | adapter = typeArticlePagerAdapter 74 | } 75 | typeSecondTabs.run { 76 | setupWithViewPager(typeSecondViewPager) 77 | } 78 | typeSecondViewPager.addOnPageChangeListener( 79 | TabLayout.TabLayoutOnPageChangeListener( 80 | typeSecondTabs 81 | ) 82 | ) 83 | typeSecondTabs.addOnTabSelectedListener( 84 | TabLayout.ViewPagerOnTabSelectedListener( 85 | typeSecondViewPager 86 | ) 87 | ) 88 | } 89 | 90 | override fun onCreateOptionsMenu(menu: Menu): Boolean { 91 | menuInflater.inflate(R.menu.menu_type_content, menu) 92 | return true 93 | } 94 | 95 | override fun onOptionsItemSelected(item: MenuItem): Boolean { 96 | when (item.itemId) { 97 | android.R.id.home -> { 98 | finish() 99 | return true 100 | } 101 | R.id.menuSearch -> { 102 | Intent(this, SearchActivity::class.java).run { 103 | startActivity(this) 104 | } 105 | return true 106 | } 107 | R.id.menuShare -> { 108 | Intent().run { 109 | action = Intent.ACTION_SEND 110 | putExtra( 111 | Intent.EXTRA_TEXT, 112 | getString( 113 | R.string.share_type_url, 114 | getString(R.string.app_name), 115 | list[typeSecondTabs.selectedTabPosition].name, 116 | list[typeSecondTabs.selectedTabPosition].id 117 | ) 118 | ) 119 | type = Constant.CONTENT_SHARE_TYPE 120 | startActivity(Intent.createChooser(this, getString(R.string.share_title))) 121 | } 122 | return true 123 | } 124 | } 125 | 126 | return super.onOptionsItemSelected(item) 127 | } 128 | 129 | override fun cancelRequest() { 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /app/src/main/java/top/jowanxu/wanandroidclient/ui/fragment/TypeFragment.kt: -------------------------------------------------------------------------------- 1 | package top.jowanxu.wanandroidclient.ui.fragment 2 | 3 | import Constant 4 | import android.content.Intent 5 | import android.os.Bundle 6 | import android.support.v4.widget.SwipeRefreshLayout 7 | import android.support.v7.widget.LinearLayoutManager 8 | import android.view.LayoutInflater 9 | import android.view.View 10 | import android.view.ViewGroup 11 | import com.chad.library.adapter.base.BaseQuickAdapter 12 | import kotlinx.android.synthetic.main.fragment_type.* 13 | import toast 14 | import top.jowanxu.wanandroidclient.R 15 | import top.jowanxu.wanandroidclient.adapter.TypeAdapter 16 | import top.jowanxu.wanandroidclient.base.BaseFragment 17 | import top.jowanxu.wanandroidclient.bean.TreeListResponse 18 | import top.jowanxu.wanandroidclient.presenter.TypeFragmentPresenterImpl 19 | import top.jowanxu.wanandroidclient.ui.activity.TypeContentActivity 20 | import top.jowanxu.wanandroidclient.view.TypeFragmentView 21 | 22 | class TypeFragment : BaseFragment(), TypeFragmentView { 23 | /** 24 | * mainView 25 | */ 26 | private var mainView: View? = null 27 | private val datas = mutableListOf() 28 | private val typeFragmentPresenter: TypeFragmentPresenterImpl by lazy { 29 | TypeFragmentPresenterImpl(this) 30 | } 31 | private val typeAdapter: TypeAdapter by lazy { 32 | TypeAdapter(activity, datas) 33 | } 34 | 35 | override fun onCreateView( 36 | inflater: LayoutInflater, 37 | container: ViewGroup?, 38 | savedInstanceState: Bundle? 39 | ): View? { 40 | mainView ?: let { 41 | mainView = inflater.inflate(R.layout.fragment_type, container, false) 42 | } 43 | return mainView 44 | } 45 | 46 | override fun onActivityCreated(savedInstanceState: Bundle?) { 47 | super.onActivityCreated(savedInstanceState) 48 | typeSwipeRefreshLayout.run { 49 | isRefreshing = true 50 | setOnRefreshListener(onRefreshListener) 51 | } 52 | typeRecyclerView.run { 53 | layoutManager = LinearLayoutManager(activity) 54 | adapter = typeAdapter 55 | } 56 | typeAdapter.run { 57 | bindToRecyclerView(typeRecyclerView) 58 | setEmptyView(R.layout.fragment_home_empty) 59 | onItemClickListener = this@TypeFragment.onItemClickListener 60 | } 61 | } 62 | 63 | override fun onHiddenChanged(hidden: Boolean) { 64 | super.onHiddenChanged(hidden) 65 | if (!hidden && isFirst) { 66 | typeFragmentPresenter.getTypeTreeList() 67 | isFirst = false 68 | } 69 | } 70 | 71 | 72 | override fun cancelRequest() { 73 | typeFragmentPresenter.cancelRequest() 74 | } 75 | 76 | /** 77 | * scroll to top 78 | */ 79 | fun smoothScrollToPosition() = typeRecyclerView.scrollToPosition(0) 80 | 81 | /** 82 | * get Type list Success 83 | */ 84 | override fun getTypeListSuccess(result: TreeListResponse) { 85 | result.data.let { 86 | if (typeSwipeRefreshLayout.isRefreshing) { 87 | typeAdapter.replaceData(it) 88 | } else { 89 | typeAdapter.addData(it) 90 | } 91 | } 92 | typeSwipeRefreshLayout.isRefreshing = false 93 | } 94 | 95 | /** 96 | * get Type list Failed 97 | */ 98 | override fun getTypeListFailed(errorMessage: String?) { 99 | errorMessage?.let { 100 | activity.toast(it) 101 | } ?: let { 102 | activity.toast(getString(R.string.get_data_error)) 103 | } 104 | typeSwipeRefreshLayout.isRefreshing = false 105 | } 106 | 107 | /** 108 | * get Type list data size equal zero 109 | */ 110 | override fun getTypeListZero() { 111 | activity.toast(getString(R.string.get_data_zero)) 112 | typeSwipeRefreshLayout.isRefreshing = false 113 | } 114 | 115 | /** 116 | * refresh 117 | */ 118 | fun refreshData() { 119 | typeSwipeRefreshLayout.isRefreshing = true 120 | typeFragmentPresenter.getTypeTreeList() 121 | } 122 | 123 | /** 124 | * RefreshListener 125 | */ 126 | private val onRefreshListener = SwipeRefreshLayout.OnRefreshListener { 127 | refreshData() 128 | } 129 | /** 130 | * ItemClickListener 131 | */ 132 | private val onItemClickListener = BaseQuickAdapter.OnItemClickListener { _, _, position -> 133 | if (datas.size != 0) { 134 | Intent(activity, TypeContentActivity::class.java).run { 135 | putExtra(Constant.CONTENT_TITLE_KEY, datas[position].name) 136 | putExtra(Constant.CONTENT_CHILDREN_DATA_KEY, datas[position]) 137 | startActivity(this) 138 | } 139 | } 140 | } 141 | } -------------------------------------------------------------------------------- /app/src/main/java/top/jowanxu/wanandroidclient/ui/view/HorizontalRecyclerView.kt: -------------------------------------------------------------------------------- 1 | package top.jowanxu.wanandroidclient.ui.view 2 | 3 | import android.content.Context 4 | import android.support.v7.widget.RecyclerView 5 | import android.util.AttributeSet 6 | import android.view.MotionEvent 7 | 8 | class HorizontalRecyclerView : RecyclerView { 9 | 10 | constructor(context: Context) : this(context, null) 11 | 12 | constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0) 13 | 14 | constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super( 15 | context, 16 | attrs, 17 | defStyleAttr 18 | ) 19 | 20 | /** 21 | * don't intercept touch 22 | */ 23 | override fun dispatchTouchEvent(ev: MotionEvent): Boolean { 24 | parent.requestDisallowInterceptTouchEvent(true) 25 | return super.dispatchTouchEvent(ev) 26 | } 27 | } -------------------------------------------------------------------------------- /app/src/main/java/top/jowanxu/wanandroidclient/view/CollectArticleView.kt: -------------------------------------------------------------------------------- 1 | package top.jowanxu.wanandroidclient.view 2 | 3 | import top.jowanxu.wanandroidclient.bean.HomeListResponse 4 | 5 | interface CollectArticleView { 6 | 7 | /** 8 | * add article success 9 | * @param result HomeListResponse 10 | * @param isAdd true add, false remove 11 | */ 12 | fun collectArticleSuccess(result: HomeListResponse, isAdd: Boolean) 13 | 14 | /** 15 | * add article false 16 | * @param errorMessage error message 17 | * @param isAdd true add, false remove 18 | */ 19 | fun collectArticleFailed(errorMessage: String?, isAdd: Boolean) 20 | } -------------------------------------------------------------------------------- /app/src/main/java/top/jowanxu/wanandroidclient/view/CommonUseFragmentView.kt: -------------------------------------------------------------------------------- 1 | package top.jowanxu.wanandroidclient.view 2 | 3 | import top.jowanxu.wanandroidclient.bean.FriendListResponse 4 | import top.jowanxu.wanandroidclient.bean.HotKeyResponse 5 | 6 | /** 7 | * CommonUse Fragment View interface 8 | */ 9 | interface CommonUseFragmentView { 10 | /** 11 | * get Friend list Success 12 | */ 13 | fun getFriendListSuccess( 14 | bookmarkResult: FriendListResponse?, 15 | commonResult: FriendListResponse, 16 | hotResult: HotKeyResponse 17 | ) 18 | 19 | /** 20 | * get Friend list Failed 21 | */ 22 | fun getFriendListFailed(errorMessage: String?) 23 | 24 | /** 25 | * get Friend list data size equal zero 26 | */ 27 | fun getFriendListZero() 28 | } -------------------------------------------------------------------------------- /app/src/main/java/top/jowanxu/wanandroidclient/view/HomeFragmentView.kt: -------------------------------------------------------------------------------- 1 | package top.jowanxu.wanandroidclient.view 2 | 3 | import top.jowanxu.wanandroidclient.bean.BannerResponse 4 | import top.jowanxu.wanandroidclient.bean.HomeListResponse 5 | 6 | /** 7 | * Home Fragment View interface 8 | */ 9 | interface HomeFragmentView { 10 | /** 11 | * get Home list Success 12 | */ 13 | fun getHomeListSuccess(result: HomeListResponse) 14 | 15 | /** 16 | * get Home list Failed 17 | */ 18 | fun getHomeListFailed(errorMessage: String?) 19 | 20 | /** 21 | * get Home list data size equal zero 22 | */ 23 | fun getHomeListZero() 24 | 25 | /** 26 | * get Home list data less than 20 27 | */ 28 | fun getHomeListSmall(result: HomeListResponse) 29 | 30 | /** 31 | * get Banner Success 32 | * @param result BannerResponse 33 | */ 34 | fun getBannerSuccess(result: BannerResponse) 35 | 36 | /** 37 | * get Banner Failed 38 | * @param errorMessage error message 39 | */ 40 | fun getBannerFailed(errorMessage: String?) 41 | 42 | /** 43 | * get Banner data size equal zero 44 | */ 45 | fun getBannerZero() 46 | } -------------------------------------------------------------------------------- /app/src/main/java/top/jowanxu/wanandroidclient/view/LoginView.kt: -------------------------------------------------------------------------------- 1 | package top.jowanxu.wanandroidclient.view 2 | 3 | import top.jowanxu.wanandroidclient.bean.LoginResponse 4 | 5 | interface LoginView { 6 | 7 | /** 8 | * login success 9 | * @param result LoginResponse 10 | */ 11 | fun loginSuccess(result: LoginResponse) 12 | 13 | /** 14 | * login failed 15 | * @param errorMessage error message 16 | */ 17 | fun loginFailed(errorMessage: String?) 18 | 19 | /** 20 | * register success 21 | * @param result LoginResponse 22 | */ 23 | fun registerSuccess(result: LoginResponse) 24 | 25 | /** 26 | * register failed 27 | * @param errorMessage error message 28 | */ 29 | fun registerFailed(errorMessage: String?) 30 | 31 | /** 32 | * login or register success after operation 33 | * @param result LoginResponse 34 | */ 35 | fun loginRegisterAfter(result: LoginResponse) 36 | } -------------------------------------------------------------------------------- /app/src/main/java/top/jowanxu/wanandroidclient/view/SearchListView.kt: -------------------------------------------------------------------------------- 1 | package top.jowanxu.wanandroidclient.view 2 | 3 | import top.jowanxu.wanandroidclient.bean.HomeListResponse 4 | 5 | /** 6 | * 搜索View接口 7 | */ 8 | interface SearchListView { 9 | /** 10 | * get search result list success 11 | */ 12 | fun getSearchListSuccess(result: HomeListResponse) 13 | 14 | /** 15 | * 获取搜索结果列表失败 16 | */ 17 | fun getSearchListFailed(errorMessage: String?) 18 | 19 | /** 20 | * get search result list data size equal zero 21 | */ 22 | fun getSearchListZero() 23 | 24 | /** 25 | * get search result list data less than 20 26 | */ 27 | fun getSearchListSmall(result: HomeListResponse) 28 | 29 | /** 30 | * get Home list Success 31 | */ 32 | fun getLikeListSuccess(result: HomeListResponse) 33 | 34 | /** 35 | * get Home list Failed 36 | */ 37 | fun getLikeListFailed(errorMessage: String?) 38 | 39 | /** 40 | * get Home list data size equal zero 41 | */ 42 | fun getLikeListZero() 43 | 44 | /** 45 | * get Home list data less than 20 46 | */ 47 | fun getLikeListSmall(result: HomeListResponse) 48 | 49 | } -------------------------------------------------------------------------------- /app/src/main/java/top/jowanxu/wanandroidclient/view/TypeArticleFragmentView.kt: -------------------------------------------------------------------------------- 1 | package top.jowanxu.wanandroidclient.view 2 | 3 | import top.jowanxu.wanandroidclient.bean.ArticleListResponse 4 | 5 | interface TypeArticleFragmentView { 6 | /** 7 | * get Type Article list Success 8 | * @param result ArticleListResponse 9 | */ 10 | fun getTypeArticleListSuccess(result: ArticleListResponse) 11 | 12 | /** 13 | * get Type Article list Failed 14 | * @param errorMessage error message 15 | */ 16 | fun getTypeArticleListFailed(errorMessage: String?) 17 | 18 | /** 19 | * get Type Article list data size equal zero 20 | */ 21 | fun getTypeArticleListZero() 22 | 23 | /** 24 | * get Type Article list data less than 20 25 | * @param result ArticleListResponse 26 | */ 27 | fun getTypeArticleListSmall(result: ArticleListResponse) 28 | } -------------------------------------------------------------------------------- /app/src/main/java/top/jowanxu/wanandroidclient/view/TypeFragmentView.kt: -------------------------------------------------------------------------------- 1 | package top.jowanxu.wanandroidclient.view 2 | 3 | import top.jowanxu.wanandroidclient.bean.TreeListResponse 4 | 5 | /** 6 | * Type Fragment View interface 7 | */ 8 | interface TypeFragmentView { 9 | /** 10 | * get Type list Success 11 | */ 12 | fun getTypeListSuccess(result: TreeListResponse) 13 | 14 | /** 15 | * get Type list Failed 16 | */ 17 | fun getTypeListFailed(errorMessage: String?) 18 | 19 | /** 20 | * get Type list data size equal zero 21 | */ 22 | fun getTypeListZero() 23 | } -------------------------------------------------------------------------------- /app/src/main/res/drawable-v21/item_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v21/list_item_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /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/banner_default_bg.xml: -------------------------------------------------------------------------------- 1 | 3 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_action_about.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_action_account_circle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangzailfm/WanAndroidClient/fef70711199ff6d06a9623f9732d684267cb3f78/app/src/main/res/drawable/ic_action_account_circle.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_action_browser.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_action_hot.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_action_like.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_action_my_bookmark.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_action_my_like.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_action_no_like.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_action_search.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_action_share.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_action_white_like.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_arrow_down.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_clear_black_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_dashboard_black_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_home_black_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 11 | 16 | 21 | 26 | 31 | 36 | 41 | 46 | 51 | 56 | 61 | 66 | 71 | 76 | 81 | 86 | 91 | 96 | 101 | 106 | 111 | 116 | 121 | 126 | 131 | 136 | 141 | 146 | 151 | 156 | 161 | 166 | 171 | 172 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangzailfm/WanAndroidClient/fef70711199ff6d06a9623f9732d684267cb3f78/app/src/main/res/drawable/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_notifications_black_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/item_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/list_item_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangzailfm/WanAndroidClient/fef70711199ff6d06a9623f9732d684267cb3f78/app/src/main/res/drawable/logo.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/side_nav_bar.xml: -------------------------------------------------------------------------------- 1 | 3 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/splash_launch.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_about.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 15 | 16 | 24 | 25 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_content.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 14 | 15 | 26 | 27 | 28 | 29 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_login.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 18 | 19 | 26 | 27 | 34 | 35 | 36 | 37 | 43 | 44 | 55 | 56 | 57 | 58 | 65 | 66 |