├── .gitignore ├── LICENSE ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro ├── release │ └── WanAndroid.apk └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── githubly │ │ └── wanandroid │ │ └── ExampleInstrumentedTest.kt │ ├── main │ ├── AndroidManifest.xml │ ├── assets │ │ ├── chapters │ │ ├── projects │ │ └── web │ │ │ └── about.html │ ├── java │ │ └── com │ │ │ └── githubly │ │ │ └── wanandroid │ │ │ ├── App.kt │ │ │ ├── MainActivity.kt │ │ │ ├── activity │ │ │ ├── CollectListActivity.kt │ │ │ ├── LoginActivity.kt │ │ │ ├── SplashActivity.kt │ │ │ ├── WebActivity.kt │ │ │ └── base │ │ │ │ └── BaseActivity.kt │ │ │ ├── adapter │ │ │ ├── HomeAdapter.kt │ │ │ ├── HomeViewPagerAdapter.kt │ │ │ ├── ProjectArticleAdapter.kt │ │ │ └── WXArticleAdapter.kt │ │ │ ├── contract │ │ │ ├── IArticlePageContract.kt │ │ │ ├── ICollectListContract.kt │ │ │ ├── IContentContract.kt │ │ │ ├── IHomeContract.kt │ │ │ ├── ILoginContract.kt │ │ │ ├── ILogoutContract.kt │ │ │ └── IProjectPageContract.kt │ │ │ ├── fragment │ │ │ ├── ArticleFragment.kt │ │ │ ├── ArticlePageFragment.kt │ │ │ ├── HomeFragment.kt │ │ │ ├── MyFragment.kt │ │ │ ├── ProjectFragment.kt │ │ │ ├── ProjectPageFragment.kt │ │ │ └── base │ │ │ │ └── BaseFragment.kt │ │ │ ├── model │ │ │ ├── ArticleItem.kt │ │ │ ├── Banner.kt │ │ │ ├── BaseListData.kt │ │ │ ├── BaseResult.kt │ │ │ ├── Chapter.kt │ │ │ └── User.kt │ │ │ ├── net │ │ │ ├── ApiCallBack.kt │ │ │ ├── ApiHelper.kt │ │ │ ├── ApiService.kt │ │ │ ├── ReadCookiesInterceptor.kt │ │ │ └── SaveCookiesInterceptor.kt │ │ │ ├── presenter │ │ │ ├── ArticlePagePresenter.kt │ │ │ ├── CollectListPresenter.kt │ │ │ ├── ContentPresenter.kt │ │ │ ├── HomePresenter.kt │ │ │ ├── LoginPresenter.kt │ │ │ ├── LogoutPresenter.kt │ │ │ ├── ProjectPagePresenter.kt │ │ │ └── base │ │ │ │ ├── BasePresenter.kt │ │ │ │ └── IView.kt │ │ │ ├── utils │ │ │ ├── AppUtils.kt │ │ │ ├── BuglyFileProvider.kt │ │ │ ├── ContentUtil.kt │ │ │ ├── DialogUtil.kt │ │ │ ├── FileUtils.kt │ │ │ ├── UserInfoHelper.kt │ │ │ └── ViewUtil.kt │ │ │ └── widget │ │ │ ├── HackyViewPager.kt │ │ │ ├── LoadingStateView.kt │ │ │ ├── OtherBottomDialog.kt │ │ │ └── ScrollTextView.kt │ └── res │ │ ├── color │ │ ├── color_main_page_bottom_tab.xml │ │ └── selector_back.xml │ │ ├── drawable-v24 │ │ └── ic_launcher_foreground.xml │ │ ├── drawable │ │ ├── color_cursor.xml │ │ ├── ic_launcher_background.xml │ │ ├── line_et_bg.xml │ │ ├── line_et_focus.xml │ │ ├── line_et_normal.xml │ │ ├── progress_horizontal.xml │ │ ├── selector_banner_point.xml │ │ ├── selector_tab_article.xml │ │ ├── selector_tab_category.xml │ │ ├── selector_tab_home.xml │ │ ├── selector_tab_my.xml │ │ ├── shape_head_blue.xml │ │ ├── shape_head_green.xml │ │ ├── shape_head_orange.xml │ │ ├── shape_head_red.xml │ │ ├── shape_login_btn.xml │ │ ├── shape_other_dialog.xml │ │ ├── shape_other_item.xml │ │ ├── shape_project_collect.xml │ │ ├── shape_round_3dp_ebebeb.xml │ │ ├── shape_update_bg.xml │ │ ├── shape_user_head.xml │ │ └── splash.xml │ │ ├── font │ │ └── font_title.ttf │ │ ├── layout │ │ ├── activity_collect_list.xml │ │ ├── activity_login.xml │ │ ├── activity_main.xml │ │ ├── activity_splash.xml │ │ ├── activity_web.xml │ │ ├── dialog_other_bottom.xml │ │ ├── fragment_article.xml │ │ ├── fragment_article_page.xml │ │ ├── fragment_home.xml │ │ ├── fragment_my.xml │ │ ├── fragment_project.xml │ │ ├── fragment_project_page.xml │ │ ├── item_home_article.xml │ │ ├── item_project.xml │ │ ├── item_wx_article.xml │ │ ├── layout_home_banner.xml │ │ ├── layout_login.xml │ │ ├── layout_page_state.xml │ │ ├── upgrade_dialog.xml │ │ └── upgrade_tips_dialog.xml │ │ ├── mipmap-xhdpi │ │ ├── ic_about.png │ │ ├── ic_android.png │ │ ├── ic_arrow.png │ │ ├── ic_back_def.png │ │ ├── ic_banner_point.png │ │ ├── ic_banner_point_selected.png │ │ ├── ic_browser.png │ │ ├── ic_clear.png │ │ ├── ic_close.png │ │ ├── ic_collect.png │ │ ├── ic_collect_tag.png │ │ ├── ic_copy_url.png │ │ ├── ic_empty.png │ │ ├── ic_empty_banner.png │ │ ├── ic_head_default.png │ │ ├── ic_heart.png │ │ ├── ic_knowledge_system.png │ │ ├── ic_launcher.png │ │ ├── ic_login_bg.jpg │ │ ├── ic_other.png │ │ ├── ic_search_article.png │ │ ├── ic_share.png │ │ ├── ic_tag.png │ │ ├── ic_todo.png │ │ └── ic_update.png │ │ ├── mipmap-xxhdpi │ │ ├── ic_article.png │ │ ├── ic_article_fill.png │ │ ├── ic_category.png │ │ ├── ic_category_fill.png │ │ ├── ic_home.png │ │ ├── ic_home_fill.png │ │ ├── ic_launcher.png │ │ ├── ic_me.png │ │ └── ic_me_fill.png │ │ └── values │ │ ├── attrs.xml │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── com │ └── githubly │ └── wanandroid │ └── ExampleUnitTest.kt ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── screenshot ├── 1.png ├── 10.png ├── 11.png ├── 12.jpg ├── 2.png ├── 3.png ├── 4.png ├── 5.png ├── 6.png ├── 7.png ├── 8.png ├── 9.png └── QRCode.png ├── settings.gradle └── wanAndroid.jks /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/caches/build_file_checksums.ser 5 | /.idea/libraries 6 | /.idea/modules.xml 7 | /.idea/workspace.xml 8 | .DS_Store 9 | /build 10 | /captures 11 | .externalNativeBuild 12 | -------------------------------------------------------------------------------- /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 | apply plugin: 'kotlin-kapt' 8 | 9 | android { 10 | compileSdkVersion 28 11 | defaultConfig { 12 | applicationId "com.githubly.wanandroid" 13 | minSdkVersion 21 14 | targetSdkVersion 28 15 | versionCode 5 16 | versionName "1.0.1.0" 17 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 18 | ndk { 19 | //设置支持的SO库架构 20 | abiFilters 'armeabi' //, 'x86', 'armeabi-v7a', 'x86_64', 'arm64-v8a' 21 | } 22 | } 23 | signingConfigs { 24 | wanAndroid { 25 | keyAlias ALIAS_NAME 26 | keyPassword ALIAS_PWD 27 | storeFile file(KEY_PATH) 28 | storePassword KEY_PWD 29 | v2SigningEnabled false 30 | } 31 | } 32 | buildTypes { 33 | release { 34 | minifyEnabled true 35 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 36 | zipAlignEnabled true 37 | debuggable false 38 | signingConfig signingConfigs.wanAndroid 39 | // 移除无用的resource文件 40 | shrinkResources true 41 | buildConfigField("String", "Environment", "\"online\"") 42 | buildConfigField("String", "BuglyID", BUGLY_ID) 43 | } 44 | 45 | debug { 46 | minifyEnabled false 47 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 48 | debuggable true 49 | signingConfig signingConfigs.wanAndroid 50 | // 移除无用的resource文件 51 | shrinkResources false 52 | buildConfigField("String", "Environment", "\"test\"") 53 | buildConfigField("String", "BuglyID", BUGLY_ID) 54 | } 55 | 56 | applicationVariants.all { variant -> 57 | variant.outputs.all { output -> 58 | def fileName 59 | fileName = "WanAndroid_${variant.versionName}.apk" 60 | output.outputFileName = fileName 61 | } 62 | } 63 | } 64 | } 65 | 66 | dependencies { 67 | implementation fileTree(include: ['*.jar'], dir: 'libs') 68 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" 69 | implementation "org.jetbrains.anko:anko:$anko_version" 70 | implementation 'com.android.support:appcompat-v7:28.0.0' 71 | implementation 'com.android.support.constraint:constraint-layout:1.1.3' 72 | implementation 'com.android.support:support-v4:28.0.0' 73 | testImplementation 'junit:junit:4.12' 74 | androidTestImplementation 'com.android.support.test:runner:1.0.2' 75 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' 76 | implementation 'com.squareup.retrofit2:retrofit:2.3.0' 77 | implementation 'com.squareup.okhttp3:okhttp:3.10.0' 78 | implementation 'com.squareup.okio:okio:1.14.0' 79 | implementation 'com.google.code.gson:gson:2.8.5' 80 | implementation 'com.squareup.retrofit2:converter-gson:2.3.0' 81 | implementation 'com.squareup.okhttp3:logging-interceptor:3.9.0' 82 | implementation 'com.gyf.barlibrary:barlibrary:2.3.0' 83 | implementation 'cn.bingoogolapple:bga-swipebacklayout:1.1.9@aar' 84 | implementation 'cn.bingoogolapple:bga-banner:2.2.4@aar' 85 | implementation 'com.github.CymChad:BaseRecyclerViewAdapterHelper:2.9.34' 86 | implementation 'com.android.support:design:28.0.0' 87 | implementation 'com.github.bumptech.glide:glide:4.8.0' 88 | implementation 'com.yqritc:recyclerview-flexibledivider:1.4.0' 89 | implementation 'com.flyco.tablayout:FlycoTabLayout_Lib:2.1.2@aar' 90 | implementation 'de.hdodenhof:circleimageview:2.2.0' 91 | implementation 'org.greenrobot:eventbus:3.1.1' 92 | implementation 'com.yanzhenjie:loading:1.0.2' 93 | implementation 'com.tencent.bugly:crashreport_upgrade:1.3.4' 94 | implementation 'com.tencent.bugly:nativecrashreport:3.3.1' 95 | implementation('com.github.hotchemi:permissionsdispatcher:3.3.1') { exclude module: 'support-v13' } 96 | kapt 'com.github.hotchemi:permissionsdispatcher-processor:3.3.1' 97 | } 98 | kotlin { 99 | experimental { 100 | coroutines 'enable' 101 | } 102 | } -------------------------------------------------------------------------------- /app/release/WanAndroid.apk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leiyun-studio/WanAndroid/abd7c07203f9e03e40ce436f23c4086913a0b0ec/app/release/WanAndroid.apk -------------------------------------------------------------------------------- /app/src/androidTest/java/com/githubly/wanandroid/ExampleInstrumentedTest.kt: -------------------------------------------------------------------------------- 1 | package com.githubly.wanandroid 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("com.githubly.wanandroid", appContext.packageName) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 20 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 35 | 38 | 41 | 44 | 48 | 49 | 55 | 59 | 60 | 61 | 62 | 63 | 64 | -------------------------------------------------------------------------------- /app/src/main/assets/chapters: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "children": [], 4 | "courseId": 13, 5 | "id": 408, 6 | "name": "鸿洋", 7 | "order": 190000, 8 | "parentChapterId": 407, 9 | "userControlSetTop": false, 10 | "visible": 1 11 | }, 12 | { 13 | "children": [], 14 | "courseId": 13, 15 | "id": 409, 16 | "name": "郭霖", 17 | "order": 190001, 18 | "parentChapterId": 407, 19 | "userControlSetTop": false, 20 | "visible": 1 21 | }, 22 | { 23 | "children": [], 24 | "courseId": 13, 25 | "id": 410, 26 | "name": "玉刚说", 27 | "order": 190002, 28 | "parentChapterId": 407, 29 | "userControlSetTop": false, 30 | "visible": 1 31 | }, 32 | { 33 | "children": [], 34 | "courseId": 13, 35 | "id": 411, 36 | "name": "承香墨影", 37 | "order": 190003, 38 | "parentChapterId": 407, 39 | "userControlSetTop": false, 40 | "visible": 1 41 | }, 42 | { 43 | "children": [], 44 | "courseId": 13, 45 | "id": 413, 46 | "name": "Android群英传", 47 | "order": 190004, 48 | "parentChapterId": 407, 49 | "userControlSetTop": false, 50 | "visible": 1 51 | }, 52 | { 53 | "children": [], 54 | "courseId": 13, 55 | "id": 414, 56 | "name": "code小生", 57 | "order": 190005, 58 | "parentChapterId": 407, 59 | "userControlSetTop": false, 60 | "visible": 1 61 | }, 62 | { 63 | "children": [], 64 | "courseId": 13, 65 | "id": 415, 66 | "name": "谷歌开发者", 67 | "order": 190006, 68 | "parentChapterId": 407, 69 | "userControlSetTop": false, 70 | "visible": 1 71 | }, 72 | { 73 | "children": [], 74 | "courseId": 13, 75 | "id": 416, 76 | "name": "奇卓社", 77 | "order": 190007, 78 | "parentChapterId": 407, 79 | "userControlSetTop": false, 80 | "visible": 1 81 | }, 82 | { 83 | "children": [], 84 | "courseId": 13, 85 | "id": 417, 86 | "name": "美团技术团队", 87 | "order": 190008, 88 | "parentChapterId": 407, 89 | "userControlSetTop": false, 90 | "visible": 1 91 | } 92 | ] -------------------------------------------------------------------------------- /app/src/main/assets/web/about.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 7 | 关于WanAndroid 8 | 9 | 34 | 35 | 36 | 37 |
38 |
39 |

网站内容

40 |

本网站每天新增20~30篇优质文章,并加入到现有分类中,力求整理出一份优质而又详尽的知识体系,闲暇时间不妨上来学习下知识; 41 | 除此以外,并为大家提供平时开发过程中常用的工具以及常用的网址导航。

42 |

当然这只是我们目前的功能,未来我们将提供更多更加便捷的功能...

43 |

如果您有任何好的建议:

44 | 49 |

可以在 hongyangAndroid/xueandroid 项目中以issue的形式提出,我将及时跟进。 50 |

51 |

如果您希望长期关注本站,可以加入我们的QQ群:591683946

52 |

关于网站作者

53 |

我是鸿洋,长期在CSDN上编写高质量的博客: 54 | blog.csdn.net/lmj623565791 55 | 并维护着一个微信公众号[hongyangAndroid],欢迎关注一下表示对我的支持:

56 |

"每天早晨7点30分,为你推荐优秀技术博文,提升从上班路上的闲暇时间开始~"

57 |

关于本App

58 |

这是基于鸿洋大神开放的Api做的练手App 59 | https://github.com/leiyun1993/WanAndroid 60 | 非常高兴能再这里遇到你,希望能给个Star支持一下,如果愿意帮忙试用,也希望能在github中以issue提出你的宝贵意见和建议,谢谢~

61 |
62 |
63 | 64 | 65 | -------------------------------------------------------------------------------- /app/src/main/java/com/githubly/wanandroid/App.kt: -------------------------------------------------------------------------------- 1 | package com.githubly.wanandroid 2 | 3 | import android.app.Application 4 | import cn.bingoogolapple.swipebacklayout.BGASwipeBackHelper 5 | import com.githubly.wanandroid.model.User 6 | import com.githubly.wanandroid.utils.UserInfoHelper 7 | import com.tencent.bugly.Bugly 8 | import com.tencent.bugly.beta.Beta 9 | import kotlin.properties.Delegates 10 | 11 | /** 12 | * 类名:App 13 | * 作者:Yun.Lei 14 | * 功能: 15 | * 创建日期:2018-10-19 10:05 16 | * 修改人: 17 | * 修改时间: 18 | * 修改备注: 19 | */ 20 | class App : Application() { 21 | 22 | companion object { 23 | var instance: App by Delegates.notNull() //实例用它 24 | var mAppContext: Application by Delegates.notNull() //applicationContext用它 25 | } 26 | 27 | var user: User? = null 28 | set(value) { 29 | field = value 30 | if (value != null) { 31 | UserInfoHelper.saveUser(value) 32 | } else { 33 | UserInfoHelper.clearUser() 34 | } 35 | } 36 | get() { 37 | if (field == null) 38 | field = UserInfoHelper.getUser() 39 | return field 40 | } 41 | 42 | var isLogin: Boolean = false 43 | get() { 44 | field = user != null 45 | return field 46 | } 47 | 48 | override fun onCreate() { 49 | super.onCreate() 50 | instance = this 51 | mAppContext = this 52 | UserInfoHelper.init(this) 53 | BGASwipeBackHelper.init(this, null) 54 | initUpdate() 55 | } 56 | 57 | private fun initUpdate() { 58 | Beta.enableHotfix = false 59 | Beta.enableNotification = true 60 | Beta.autoCheckUpgrade = true 61 | Beta.largeIconId = R.mipmap.ic_launcher 62 | Beta.smallIconId = R.mipmap.ic_launcher 63 | Beta.upgradeDialogLayoutId = R.layout.upgrade_dialog 64 | Beta.tipsDialogLayoutId = R.layout.upgrade_tips_dialog 65 | Beta.canShowUpgradeActs.add(MainActivity::class.java) 66 | Bugly.init(applicationContext, BuildConfig.BuglyID, BuildConfig.DEBUG) 67 | } 68 | 69 | } -------------------------------------------------------------------------------- /app/src/main/java/com/githubly/wanandroid/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.githubly.wanandroid 2 | 3 | import android.support.v4.app.Fragment 4 | import android.support.v4.view.ViewPager 5 | import android.view.View 6 | import com.githubly.wanandroid.activity.base.BaseActivity 7 | import com.githubly.wanandroid.adapter.HomeViewPagerAdapter 8 | import com.githubly.wanandroid.fragment.ArticleFragment 9 | import com.githubly.wanandroid.fragment.HomeFragment 10 | import com.githubly.wanandroid.fragment.MyFragment 11 | import com.githubly.wanandroid.fragment.ProjectFragment 12 | import com.githubly.wanandroid.presenter.base.BasePresenter 13 | import kotlinx.android.synthetic.main.activity_main.* 14 | import org.jetbrains.anko.toast 15 | 16 | /** 17 | * MainActivity 18 | */ 19 | class MainActivity : BaseActivity>(), View.OnClickListener, ViewPager.OnPageChangeListener { 20 | private val fragments = mutableListOf() 21 | private var bottomViews = mutableListOf() 22 | override val inflateId: Int 23 | get() = R.layout.activity_main 24 | 25 | 26 | override fun initView() { 27 | fragments.add(HomeFragment()) 28 | fragments.add(ArticleFragment()) 29 | fragments.add(ProjectFragment()) 30 | fragments.add(MyFragment()) 31 | 32 | homeViewPager.adapter = HomeViewPagerAdapter(fragments, supportFragmentManager) 33 | homeViewPager.offscreenPageLimit = 4 34 | homeViewPager.addOnPageChangeListener(this) 35 | bottomViews.add(rl_home) 36 | bottomViews.add(rl_article) 37 | bottomViews.add(rl_category) 38 | bottomViews.add(rl_my) 39 | 40 | for (view in bottomViews) { 41 | view.setOnClickListener(this) 42 | } 43 | setBottomBarSelect(0) 44 | } 45 | 46 | override fun initData() { 47 | 48 | } 49 | 50 | override fun initPresenter(): BasePresenter<*>? = null 51 | 52 | override fun isSupportSwipeBack(): Boolean { 53 | return false 54 | } 55 | 56 | override fun onClick(v: View?) { 57 | for (bottomView in bottomViews) { 58 | if (v == bottomView) { 59 | homeViewPager.setCurrentItem(bottomViews.indexOf(bottomView), false) 60 | setBottomBarSelect(bottomViews.indexOf(bottomView)) 61 | } 62 | } 63 | } 64 | 65 | private fun setBottomBarSelect(index: Int) { 66 | for (view in bottomViews) { 67 | view.isSelected = false 68 | } 69 | bottomViews[index].isSelected = true 70 | } 71 | 72 | override fun onPageScrollStateChanged(p0: Int) { 73 | 74 | } 75 | 76 | override fun onPageScrolled(p0: Int, p1: Float, p2: Int) { 77 | } 78 | 79 | override fun onPageSelected(p0: Int) { 80 | setBottomBarSelect(p0) 81 | } 82 | 83 | private var lastClickTime = 0L 84 | override fun onBackPressed() { 85 | val currentTimeMillis = System.currentTimeMillis() 86 | if (currentTimeMillis - lastClickTime > 3000) { 87 | toast("再点就退出了...") 88 | lastClickTime = currentTimeMillis 89 | } else { 90 | super.onBackPressed() 91 | } 92 | } 93 | 94 | } 95 | -------------------------------------------------------------------------------- /app/src/main/java/com/githubly/wanandroid/activity/CollectListActivity.kt: -------------------------------------------------------------------------------- 1 | package com.githubly.wanandroid.activity 2 | 3 | import android.app.Activity 4 | import android.support.v7.widget.LinearLayoutManager 5 | import com.githubly.wanandroid.R 6 | import com.githubly.wanandroid.activity.base.BaseActivity 7 | import com.githubly.wanandroid.adapter.HomeAdapter 8 | import com.githubly.wanandroid.contract.ICollectListContract 9 | import com.githubly.wanandroid.model.ArticleItem 10 | import com.githubly.wanandroid.model.BaseListData 11 | import com.githubly.wanandroid.model.EventRemoveCollectPageArticle 12 | import com.githubly.wanandroid.presenter.CollectListPresenter 13 | import com.yqritc.recyclerviewflexibledivider.HorizontalDividerItemDecoration 14 | import kotlinx.android.synthetic.main.activity_collect_list.* 15 | import org.greenrobot.eventbus.EventBus 16 | import org.greenrobot.eventbus.Subscribe 17 | import org.greenrobot.eventbus.ThreadMode 18 | import org.jetbrains.anko.act 19 | import org.jetbrains.anko.dip 20 | import org.jetbrains.anko.startActivity 21 | import org.jetbrains.anko.toast 22 | 23 | /** 24 | * CollectListActivity 25 | */ 26 | class CollectListActivity : BaseActivity(), ICollectListContract.View { 27 | 28 | companion object { 29 | fun active(act: Activity) { 30 | act.startActivity() 31 | } 32 | } 33 | 34 | private var page = 1 35 | private val mAdapter by lazy { HomeAdapter() } 36 | override val inflateId: Int 37 | get() = R.layout.activity_collect_list 38 | 39 | override fun initView() { 40 | EventBus.getDefault().register(this) 41 | btnBack.setOnClickListener { onBackPressed() } 42 | recyclerView.adapter = mAdapter 43 | recyclerView.layoutManager = LinearLayoutManager(this) 44 | recyclerView.addItemDecoration( 45 | HorizontalDividerItemDecoration.Builder(this).color(act.resources.getColor(R.color.backgroundColor)).size( 46 | dip(8) 47 | ).build() 48 | ) 49 | mAdapter.setOnLoadMoreListener({ 50 | page++ 51 | mPresenter?.getCollectList(page) 52 | }, recyclerView) 53 | mAdapter.setPreLoadNumber(2) 54 | refreshLayout.setOnRefreshListener { 55 | initData() 56 | } 57 | mAdapter.emptyView = mLoadingStateView 58 | mAdapter.setOnItemClickListener { _, _, position -> 59 | mAdapter.data[position]?.apply { 60 | WebActivity.active(act, link, id, author, title, true, if (originId > 0) originId else -1) 61 | } 62 | } 63 | } 64 | 65 | override fun initData() { 66 | mLoadingStateView.loading() 67 | page = 1 68 | mPresenter?.getCollectList(page) 69 | } 70 | 71 | override fun initPresenter(): CollectListPresenter? = CollectListPresenter(this) 72 | 73 | override fun onListSuccess(data: BaseListData) { 74 | if (data.curPage == 1) { 75 | mAdapter.setNewData(data.datas) 76 | refreshLayout.isRefreshing = false 77 | } else { 78 | mAdapter.addData(data.datas) 79 | mAdapter.loadMoreComplete() 80 | } 81 | page = data.curPage 82 | if (data.over) { 83 | mAdapter.loadMoreEnd() 84 | } 85 | mAdapter.setEnableLoadMore(!data.over) 86 | mLoadingStateView.success() 87 | } 88 | 89 | override fun onListFailed(msg: String) { 90 | if (page == 1) { 91 | mAdapter.setNewData(mutableListOf()) 92 | mLoadingStateView.failed(msg) 93 | refreshLayout.isRefreshing = false 94 | } else { 95 | toast(msg) 96 | mAdapter.loadMoreComplete() 97 | } 98 | } 99 | 100 | @Subscribe(threadMode = ThreadMode.MAIN) 101 | fun onEventCollectRemove(event: EventRemoveCollectPageArticle) { 102 | val id = event.id 103 | val item = mAdapter.data.find { it.id == id } 104 | if (item != null) { 105 | val index = mAdapter.data.indexOf(item) 106 | mAdapter.remove(index) 107 | if (mAdapter.data.size <= 0) { 108 | mLoadingStateView.failed("暂无收藏数据!") 109 | } 110 | } 111 | } 112 | 113 | override fun onDestroy() { 114 | super.onDestroy() 115 | EventBus.getDefault().unregister(this) 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /app/src/main/java/com/githubly/wanandroid/activity/LoginActivity.kt: -------------------------------------------------------------------------------- 1 | package com.githubly.wanandroid.activity 2 | 3 | import android.app.Activity 4 | import android.view.View 5 | import com.githubly.wanandroid.App 6 | import com.githubly.wanandroid.R 7 | import com.githubly.wanandroid.activity.base.BaseActivity 8 | import com.githubly.wanandroid.contract.ILoginContract 9 | import com.githubly.wanandroid.model.User 10 | import com.githubly.wanandroid.presenter.LoginPresenter 11 | import com.githubly.wanandroid.utils.hideSoftInput 12 | import kotlinx.android.synthetic.main.activity_login.* 13 | import kotlinx.android.synthetic.main.layout_login.* 14 | import org.greenrobot.eventbus.EventBus 15 | import org.jetbrains.anko.startActivity 16 | import org.jetbrains.anko.toast 17 | 18 | /** 19 | * LoginActivity 20 | */ 21 | class LoginActivity : BaseActivity(), ILoginContract.View { 22 | 23 | 24 | companion object { 25 | fun active(act: Activity) { 26 | act.startActivity() 27 | } 28 | } 29 | 30 | private var isSelectLogin: Boolean = true 31 | 32 | override val inflateId: Int 33 | get() = R.layout.activity_login 34 | 35 | override fun initView() { 36 | btnBack.setOnClickListener { 37 | onBackPressed() 38 | } 39 | loginTag.setColorFilter(resources.getColor(R.color.black_1)) 40 | registerTag.setColorFilter(resources.getColor(R.color.black_1)) 41 | loginBtn.setOnClickListener { 42 | showLoginOrRegister(true) 43 | } 44 | registerBtn.setOnClickListener { 45 | showLoginOrRegister(false) 46 | } 47 | btnGoLogin.setOnClickListener { 48 | login() 49 | } 50 | btnGoRegister.setOnClickListener { 51 | register() 52 | } 53 | } 54 | 55 | override fun initData() { 56 | 57 | } 58 | 59 | override fun initPresenter(): LoginPresenter? = LoginPresenter(this) 60 | 61 | private fun login() { 62 | val userName = loginNameTV.text.toString() 63 | val password = loginPasswordTv.text.toString() 64 | if (userName.isBlank()) { 65 | toast("请输入用户名") 66 | return 67 | } 68 | if (password.isBlank()) { 69 | toast("请输入密码") 70 | return 71 | } 72 | hideSoftInput() 73 | showLoading() 74 | mPresenter?.login(userName, password) 75 | } 76 | 77 | private fun register() { 78 | val userName = registerNameTv.text.toString() 79 | val password = registerPwdTv.text.toString() 80 | val rePassword = registerRePwdTv.text.toString() 81 | if (userName.isBlank()) { 82 | toast("请输入用户名") 83 | return 84 | } 85 | if (password.isBlank()) { 86 | toast("请输入密码") 87 | return 88 | } 89 | if (rePassword.isBlank()) { 90 | toast("请输入密码") 91 | return 92 | } 93 | if (password != rePassword) { 94 | toast("密码不一致,请确认") 95 | return 96 | } 97 | hideSoftInput() 98 | showLoading() 99 | mPresenter?.register(userName, password, rePassword) 100 | } 101 | 102 | private fun showLoginOrRegister(isLogin: Boolean) { 103 | isSelectLogin = isLogin 104 | loginTag.visibility = if (isLogin) View.VISIBLE else View.INVISIBLE 105 | registerTag.visibility = if (!isLogin) View.VISIBLE else View.INVISIBLE 106 | loginLayout.visibility = if (isLogin) View.VISIBLE else View.INVISIBLE 107 | registerLayout.visibility = if (!isLogin) View.VISIBLE else View.INVISIBLE 108 | } 109 | 110 | override fun onLoginSuccess(user: User) { 111 | dismissLoading() 112 | App.instance.user = user 113 | EventBus.getDefault().post(user) 114 | finish() 115 | } 116 | 117 | override fun onLoginFailed(msg: String) { 118 | dismissLoading() 119 | toast(msg) 120 | } 121 | 122 | override fun onRegisterSuccess(user: User) { 123 | dismissLoading() 124 | toast("注册并成功登录") 125 | App.instance.user = user 126 | EventBus.getDefault().post(user) 127 | finish() 128 | } 129 | 130 | override fun onRegisterFailed(msg: String) { 131 | dismissLoading() 132 | toast(msg) 133 | } 134 | } 135 | -------------------------------------------------------------------------------- /app/src/main/java/com/githubly/wanandroid/activity/SplashActivity.kt: -------------------------------------------------------------------------------- 1 | package com.githubly.wanandroid.activity 2 | 3 | import android.Manifest 4 | import android.annotation.SuppressLint 5 | import android.content.Intent 6 | import android.support.v7.app.AlertDialog 7 | import com.githubly.wanandroid.MainActivity 8 | import com.githubly.wanandroid.R 9 | import com.githubly.wanandroid.activity.base.BaseActivity 10 | import com.githubly.wanandroid.presenter.base.BasePresenter 11 | import com.githubly.wanandroid.utils.AppUtils 12 | import com.githubly.wanandroid.utils.toAppDetail 13 | import com.gyf.barlibrary.ImmersionBar 14 | import kotlinx.android.synthetic.main.activity_splash.* 15 | import org.jetbrains.anko.startActivity 16 | import permissions.dispatcher.NeedsPermission 17 | import permissions.dispatcher.OnNeverAskAgain 18 | import permissions.dispatcher.OnPermissionDenied 19 | import permissions.dispatcher.RuntimePermissions 20 | 21 | /** 22 | * SplashActivity 23 | */ 24 | @RuntimePermissions 25 | class SplashActivity : BaseActivity>() { 26 | 27 | override val inflateId: Int 28 | get() = R.layout.activity_splash 29 | 30 | override fun setStatusBar() { 31 | mBaseImmersionBar = ImmersionBar.with(this) 32 | mBaseImmersionBar?.apply { 33 | statusBarColor(R.color.transparent) 34 | statusBarDarkFont(true, 0.2f) 35 | init() 36 | } 37 | } 38 | 39 | @SuppressLint("SetTextI18n") 40 | override fun initView() { 41 | versionTv.text = "v${AppUtils.getVersionName(this)}" 42 | } 43 | 44 | 45 | override fun initData() { 46 | goMainWithPermissionCheck() 47 | } 48 | 49 | @NeedsPermission( 50 | Manifest.permission.READ_EXTERNAL_STORAGE, 51 | Manifest.permission.WRITE_EXTERNAL_STORAGE 52 | ) 53 | fun goMain() { 54 | versionTv.postDelayed({ 55 | startActivity() 56 | finish() 57 | }, 1000) 58 | } 59 | 60 | override fun initPresenter(): BasePresenter<*>? = null 61 | 62 | @OnPermissionDenied( 63 | Manifest.permission.READ_EXTERNAL_STORAGE, 64 | Manifest.permission.WRITE_EXTERNAL_STORAGE 65 | ) 66 | fun permissionDenied() { 67 | showPermissionDeniedDialog() 68 | } 69 | 70 | @OnNeverAskAgain( 71 | Manifest.permission.READ_EXTERNAL_STORAGE, 72 | Manifest.permission.WRITE_EXTERNAL_STORAGE 73 | ) 74 | fun neverAskAgain() { 75 | showPermissionDeniedDialog() 76 | } 77 | 78 | private fun showPermissionDeniedDialog() { 79 | AlertDialog.Builder(this).apply { 80 | setTitle("温馨提示") 81 | setMessage("你拒绝了权限请求,会影响应用更新等功能的正常使用!") 82 | setPositiveButton("去设置") { _, _ -> 83 | toAppDetail(0x99) 84 | dismissLoading() 85 | } 86 | setNegativeButton("取消") { _, _ -> 87 | goMain() 88 | dismissLoading() 89 | } 90 | setCancelable(false) 91 | setFinishOnTouchOutside(false) 92 | }.create().show() 93 | } 94 | 95 | override fun onRequestPermissionsResult(requestCode: Int, permissions: Array, grantResults: IntArray) { 96 | super.onRequestPermissionsResult(requestCode, permissions, grantResults) 97 | onRequestPermissionsResult(requestCode, grantResults) 98 | } 99 | 100 | override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { 101 | super.onActivityResult(requestCode, resultCode, data) 102 | if (requestCode == 99) { 103 | goMain() 104 | } 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /app/src/main/java/com/githubly/wanandroid/activity/base/BaseActivity.kt: -------------------------------------------------------------------------------- 1 | package com.githubly.wanandroid.activity.base 2 | 3 | import android.os.Bundle 4 | import android.support.v7.app.AppCompatActivity 5 | import cn.bingoogolapple.swipebacklayout.BGASwipeBackHelper 6 | import com.githubly.wanandroid.R 7 | import com.githubly.wanandroid.presenter.base.BasePresenter 8 | import com.githubly.wanandroid.utils.ILoading 9 | import com.githubly.wanandroid.widget.LoadingStateView 10 | import com.gyf.barlibrary.ImmersionBar 11 | import com.yanzhenjie.loading.dialog.LoadingDialog 12 | 13 | /** 14 | * 类名:BaseActivity 15 | * 作者:Yun.Lei 16 | * 功能: 17 | * 创建日期:2018-10-18 19:11 18 | * 修改人: 19 | * 修改时间: 20 | * 修改备注: 21 | */ 22 | abstract class BaseActivity> : AppCompatActivity(), BGASwipeBackHelper.Delegate, ILoading { 23 | 24 | protected var mBaseImmersionBar: ImmersionBar? = null 25 | protected var mSwipeBackHelper: BGASwipeBackHelper? = null 26 | /** 27 | * 当前页面需要加载的layoutId,等价setContentView 28 | */ 29 | abstract val inflateId: Int 30 | 31 | /** 32 | * 初始化视图操作在这里执行,执行时机为onCreate之后 33 | */ 34 | abstract fun initView(): Unit 35 | 36 | /** 37 | * 数据初始化在这里执行,执行时机为initView之后 38 | */ 39 | abstract fun initData(): Unit 40 | 41 | //kotlin 懒加载,在第一次使用Presenter时初始化,这种设计是针对一个View只针对一个Presenter。 42 | //多个Presenter的情况此处不应该使用泛型 43 | protected val mPresenter: P? by lazy { initPresenter() } 44 | 45 | abstract fun initPresenter(): P? 46 | 47 | private val mWaitDialog by lazy { LoadingDialog(this) } 48 | 49 | protected val mLoadingStateView by lazy { LoadingStateView(this) } 50 | 51 | override fun onCreate(savedInstanceState: Bundle?) { 52 | initSwipeBackFinish() 53 | super.onCreate(savedInstanceState) 54 | setContentView(inflateId) 55 | initView() 56 | initData() 57 | setStatusBar() 58 | } 59 | 60 | open fun setStatusBar() { 61 | mBaseImmersionBar = ImmersionBar.with(this) 62 | mBaseImmersionBar?.apply { 63 | statusBarColor(R.color.white) 64 | fitsSystemWindows(true) 65 | statusBarDarkFont(true, 0.2f) 66 | keyboardEnable(true) 67 | init() 68 | } 69 | } 70 | 71 | private fun initSwipeBackFinish() { 72 | mSwipeBackHelper = BGASwipeBackHelper(this, this) 73 | } 74 | 75 | override fun onSwipeBackLayoutExecuted() { 76 | mSwipeBackHelper?.swipeBackward() 77 | } 78 | 79 | override fun onSwipeBackLayoutSlide(slideOffset: Float) { 80 | } 81 | 82 | override fun onSwipeBackLayoutCancel() { 83 | } 84 | 85 | override fun isSupportSwipeBack(): Boolean = true 86 | 87 | override fun onBackPressed() { 88 | if (mSwipeBackHelper?.isSliding == true) { 89 | return 90 | } 91 | super.onBackPressed() 92 | } 93 | 94 | override fun onDestroy() { 95 | super.onDestroy() 96 | mBaseImmersionBar?.destroy() 97 | dismissLoading() 98 | } 99 | 100 | override fun showLoading(msg: String) { 101 | mWaitDialog.setMessage(msg) 102 | mWaitDialog.setCancelable(false) 103 | mWaitDialog.setCanceledOnTouchOutside(false) 104 | if (!mWaitDialog.isShowing) { 105 | mWaitDialog.show() 106 | } 107 | } 108 | 109 | override fun dismissLoading() { 110 | if (mWaitDialog.isShowing) { 111 | mWaitDialog.dismiss() 112 | } 113 | } 114 | } -------------------------------------------------------------------------------- /app/src/main/java/com/githubly/wanandroid/adapter/HomeAdapter.kt: -------------------------------------------------------------------------------- 1 | package com.githubly.wanandroid.adapter 2 | 3 | import com.chad.library.adapter.base.BaseQuickAdapter 4 | import com.chad.library.adapter.base.BaseViewHolder 5 | import com.githubly.wanandroid.R 6 | import com.githubly.wanandroid.model.ArticleItem 7 | import kotlinx.android.synthetic.main.item_home_article.view.* 8 | import java.util.* 9 | 10 | /** 11 | * 类名:HomeAdapter 12 | * 作者:Yun.Lei 13 | * 功能: 14 | * 创建日期:2018-10-19 11:11 15 | * 修改人: 16 | * 修改时间: 17 | * 修改备注: 18 | */ 19 | class HomeAdapter : BaseQuickAdapter(R.layout.item_home_article) { 20 | 21 | private val colorRess = mutableListOf( 22 | R.drawable.shape_head_red, 23 | R.drawable.shape_head_blue, 24 | R.drawable.shape_head_orange, 25 | R.drawable.shape_head_green) 26 | 27 | override fun convert(helper: BaseViewHolder?, item: ArticleItem?) { 28 | val itemView = helper?.itemView 29 | itemView?.apply { 30 | item?.let { 31 | nameHeadTV.text = getStrFirstChat(it.author) 32 | nameHeadTV.setBackgroundResource(getRandomColor()) 33 | nameTv.text = it.author 34 | titleTv.text = it.title 35 | descTv.text = if (it.desc.isNullOrBlank()) { 36 | it.link 37 | } else { 38 | it.desc 39 | } 40 | timeTv.text = it.niceDate 41 | typeTv.text = getType(it) 42 | heartIV.setColorFilter(context.resources.getColor(if (it.collect) { 43 | R.color.red 44 | } else { 45 | R.color.gray_1 46 | })) 47 | } 48 | } 49 | } 50 | 51 | private fun getType(item: ArticleItem): String { 52 | return if (item.superChapterName.isNullOrBlank()) { 53 | item.chapterName 54 | } else { 55 | "${item.chapterName} / ${item.superChapterName}" 56 | } 57 | } 58 | 59 | private fun getRandomColor(): Int { 60 | val index = Random().nextInt(4) 61 | return colorRess[index] 62 | } 63 | 64 | private fun getStrFirstChat(str: String): String { 65 | return str.substring(0, 1) 66 | } 67 | } -------------------------------------------------------------------------------- /app/src/main/java/com/githubly/wanandroid/adapter/HomeViewPagerAdapter.kt: -------------------------------------------------------------------------------- 1 | package com.githubly.wanandroid.adapter 2 | 3 | import android.support.v4.app.Fragment 4 | import android.support.v4.app.FragmentManager 5 | import android.support.v4.app.FragmentPagerAdapter 6 | 7 | /** 8 | * 类名:HomeViewPagerAdapter 9 | * 作者:Yun.Lei 10 | * 功能: 11 | * 创建日期:2017-10-17 15:05 12 | * 修改人: 13 | * 修改时间: 14 | * 修改备注: 15 | */ 16 | class HomeViewPagerAdapter(private val fragments: MutableList, fm: FragmentManager) : FragmentPagerAdapter(fm) { 17 | override fun getItem(position: Int): Fragment = fragments[position] 18 | 19 | override fun getCount(): Int = fragments.size 20 | } -------------------------------------------------------------------------------- /app/src/main/java/com/githubly/wanandroid/adapter/ProjectArticleAdapter.kt: -------------------------------------------------------------------------------- 1 | package com.githubly.wanandroid.adapter 2 | 3 | import android.view.View 4 | import com.chad.library.adapter.base.BaseQuickAdapter 5 | import com.chad.library.adapter.base.BaseViewHolder 6 | import com.githubly.wanandroid.R 7 | import com.githubly.wanandroid.model.ArticleItem 8 | import com.githubly.wanandroid.utils.loadImage 9 | import kotlinx.android.synthetic.main.item_project.view.* 10 | 11 | /** 12 | * 类名:ProjectArticleAdapter 13 | * 作者:Yun.Lei 14 | * 功能: 15 | * 创建日期:2018-10-19 11:11 16 | * 修改人: 17 | * 修改时间: 18 | * 修改备注: 19 | */ 20 | class ProjectArticleAdapter : BaseQuickAdapter(R.layout.item_project) { 21 | 22 | private val colorRess = mutableListOf( 23 | R.drawable.shape_head_red, 24 | R.drawable.shape_head_blue, 25 | R.drawable.shape_head_orange, 26 | R.drawable.shape_head_green) 27 | 28 | override fun convert(helper: BaseViewHolder?, item: ArticleItem?) { 29 | val itemView = helper?.itemView 30 | itemView?.apply { 31 | item?.let { 32 | nameHeadTV.text = getStrFirstChat(it.author) 33 | nameHeadTV.setBackgroundResource(getRandomColor(it.chapterId)) 34 | nameTv.text = it.author 35 | titleTV.text = it.title 36 | timeTv.text = it.niceDate 37 | envelopePicIV.loadImage(it.envelopePic) 38 | collectTagTv.visibility = if (it.collect) { 39 | View.VISIBLE 40 | } else { 41 | View.GONE 42 | } 43 | } 44 | } 45 | } 46 | 47 | private fun getRandomColor(userID: Int): Int { 48 | return colorRess[userID % 4] 49 | } 50 | 51 | private fun getStrFirstChat(str: String): String { 52 | return str.substring(0, 1) 53 | } 54 | } -------------------------------------------------------------------------------- /app/src/main/java/com/githubly/wanandroid/adapter/WXArticleAdapter.kt: -------------------------------------------------------------------------------- 1 | package com.githubly.wanandroid.adapter 2 | 3 | import com.chad.library.adapter.base.BaseQuickAdapter 4 | import com.chad.library.adapter.base.BaseViewHolder 5 | import com.githubly.wanandroid.R 6 | import com.githubly.wanandroid.model.ArticleItem 7 | import kotlinx.android.synthetic.main.item_wx_article.view.* 8 | 9 | /** 10 | * 类名:WXArticleAdapter 11 | * 作者:Yun.Lei 12 | * 功能: 13 | * 创建日期:2018-10-19 11:11 14 | * 修改人: 15 | * 修改时间: 16 | * 修改备注: 17 | */ 18 | class WXArticleAdapter : BaseQuickAdapter(R.layout.item_wx_article) { 19 | 20 | var userID: Int = 0 21 | private val colorRess = mutableListOf( 22 | R.drawable.shape_head_red, 23 | R.drawable.shape_head_blue, 24 | R.drawable.shape_head_orange, 25 | R.drawable.shape_head_green) 26 | 27 | override fun convert(helper: BaseViewHolder?, item: ArticleItem?) { 28 | val itemView = helper?.itemView 29 | itemView?.apply { 30 | item?.let { 31 | nameHeadTV.text = getStrFirstChat(it.author) 32 | nameHeadTV.setBackgroundResource(getRandomColor()) 33 | nameTv.text = it.author 34 | titleTv.text = it.title 35 | timeTv.text = it.niceDate 36 | heartIV.setColorFilter(context.resources.getColor(if (it.collect) { 37 | R.color.red 38 | } else { 39 | R.color.gray_1 40 | })) 41 | } 42 | } 43 | } 44 | 45 | private fun getRandomColor(): Int { 46 | return colorRess[userID % 4] 47 | } 48 | 49 | private fun getStrFirstChat(str: String): String { 50 | return str.substring(0, 1) 51 | } 52 | } -------------------------------------------------------------------------------- /app/src/main/java/com/githubly/wanandroid/contract/IArticlePageContract.kt: -------------------------------------------------------------------------------- 1 | package com.githubly.wanandroid.contract 2 | 3 | import com.githubly.wanandroid.model.ArticleItem 4 | import com.githubly.wanandroid.model.BaseListData 5 | import com.githubly.wanandroid.presenter.base.IView 6 | 7 | /** 8 | * 类名:IArticlePageContract 9 | * 作者:Yun.Lei 10 | * 功能: 11 | * 创建日期:2018-10-19 17:11 12 | * 修改人: 13 | * 修改时间: 14 | * 修改备注: 15 | */ 16 | interface IArticlePageContract { 17 | 18 | interface Presenter{ 19 | fun getWXArticle(userID:Int,page:Int) 20 | } 21 | 22 | interface View:IView{ 23 | fun onArticleSuccess(data: BaseListData) 24 | fun onArticleFailed(msg: String) 25 | } 26 | } -------------------------------------------------------------------------------- /app/src/main/java/com/githubly/wanandroid/contract/ICollectListContract.kt: -------------------------------------------------------------------------------- 1 | package com.githubly.wanandroid.contract 2 | 3 | import com.githubly.wanandroid.model.ArticleItem 4 | import com.githubly.wanandroid.model.BaseListData 5 | import com.githubly.wanandroid.presenter.base.IView 6 | 7 | /** 8 | * 类名:ICollectListContract 9 | * 作者:Yun.Lei 10 | * 功能: 11 | * 创建日期:2018-10-22 17:46 12 | * 修改人: 13 | * 修改时间: 14 | * 修改备注: 15 | */ 16 | interface ICollectListContract { 17 | 18 | interface Presenter{ 19 | fun getCollectList(page:Int) 20 | } 21 | 22 | interface View:IView{ 23 | fun onListSuccess(data: BaseListData) 24 | fun onListFailed(msg:String) 25 | } 26 | 27 | } -------------------------------------------------------------------------------- /app/src/main/java/com/githubly/wanandroid/contract/IContentContract.kt: -------------------------------------------------------------------------------- 1 | package com.githubly.wanandroid.contract 2 | 3 | import com.githubly.wanandroid.presenter.base.IView 4 | 5 | /** 6 | * 类名:IContentContract 7 | * 作者:Yun.Lei 8 | * 功能: 9 | * 创建日期:2018-10-23 16:13 10 | * 修改人: 11 | * 修改时间: 12 | * 修改备注: 13 | */ 14 | interface IContentContract { 15 | 16 | interface Presenter { 17 | fun articleCollect(id: Int) 18 | fun articleUncollect(id: Int) 19 | fun articleUncollectPage(id: Int,originId:Int) 20 | } 21 | 22 | interface View : IView { 23 | fun onCollectSuccess() 24 | fun onCollectFailed(msg: String) 25 | fun onUncollectSuccess() 26 | fun onUncollectFailed(msg: String) 27 | fun onUncollectPageSuccess() 28 | fun onUncollectPageFailed(msg: String) 29 | } 30 | 31 | } -------------------------------------------------------------------------------- /app/src/main/java/com/githubly/wanandroid/contract/IHomeContract.kt: -------------------------------------------------------------------------------- 1 | package com.githubly.wanandroid.contract 2 | 3 | import com.githubly.wanandroid.model.ArticleItem 4 | import com.githubly.wanandroid.model.Banner 5 | import com.githubly.wanandroid.model.BaseListData 6 | import com.githubly.wanandroid.presenter.base.IView 7 | 8 | /** 9 | * 类名:IHomeContract 10 | * 作者:Yun.Lei 11 | * 功能: 12 | * 创建日期:2018-10-19 11:33 13 | * 修改人: 14 | * 修改时间: 15 | * 修改备注: 16 | */ 17 | interface IHomeContract { 18 | 19 | interface Presenter { 20 | fun getBanner() 21 | fun getHomeArticle(page:Int) 22 | } 23 | 24 | interface View : IView { 25 | fun onBannerSuccess(banners: MutableList) 26 | fun onBannerFailed(msg: String) 27 | fun onArticleSuccess(data:BaseListData) 28 | fun onArticleFailed(msg: String) 29 | } 30 | } -------------------------------------------------------------------------------- /app/src/main/java/com/githubly/wanandroid/contract/ILoginContract.kt: -------------------------------------------------------------------------------- 1 | package com.githubly.wanandroid.contract 2 | 3 | import com.githubly.wanandroid.model.User 4 | import com.githubly.wanandroid.presenter.base.IView 5 | 6 | /** 7 | * 类名:ILoginContract 8 | * 作者:Yun.Lei 9 | * 功能: 10 | * 创建日期:2018-10-22 14:43 11 | * 修改人: 12 | * 修改时间: 13 | * 修改备注: 14 | */ 15 | interface ILoginContract { 16 | 17 | interface Presenter { 18 | fun login(userName: String, password: String) 19 | fun register(userName: String, password: String, rePassword: String) 20 | } 21 | 22 | interface View : IView { 23 | fun onLoginSuccess(user: User) 24 | fun onLoginFailed(msg: String) 25 | 26 | fun onRegisterSuccess(user: User) 27 | fun onRegisterFailed(msg: String) 28 | } 29 | } -------------------------------------------------------------------------------- /app/src/main/java/com/githubly/wanandroid/contract/ILogoutContract.kt: -------------------------------------------------------------------------------- 1 | package com.githubly.wanandroid.contract 2 | 3 | import com.githubly.wanandroid.presenter.base.IView 4 | 5 | /** 6 | * 类名:ILogoutContract 7 | * 作者:Yun.Lei 8 | * 功能: 9 | * 创建日期:2018-10-22 16:39 10 | * 修改人: 11 | * 修改时间: 12 | * 修改备注: 13 | */ 14 | interface ILogoutContract { 15 | 16 | interface Presenter{ 17 | 18 | fun logout() 19 | } 20 | 21 | interface View:IView{ 22 | fun onLogoutSuccess() 23 | fun onLogoutFailed(msg:String) 24 | } 25 | } -------------------------------------------------------------------------------- /app/src/main/java/com/githubly/wanandroid/contract/IProjectPageContract.kt: -------------------------------------------------------------------------------- 1 | package com.githubly.wanandroid.contract 2 | 3 | import com.githubly.wanandroid.model.ArticleItem 4 | import com.githubly.wanandroid.model.BaseListData 5 | import com.githubly.wanandroid.presenter.base.IView 6 | 7 | /** 8 | * 类名:IProjectPageContract 9 | * 作者:Yun.Lei 10 | * 功能: 11 | * 创建日期:2018-10-19 17:11 12 | * 修改人: 13 | * 修改时间: 14 | * 修改备注: 15 | */ 16 | interface IProjectPageContract { 17 | 18 | interface Presenter{ 19 | fun getProjectArticle(userID:Int,page:Int) 20 | } 21 | 22 | interface View:IView{ 23 | fun onArticleSuccess(data: BaseListData) 24 | fun onArticleFailed(msg: String) 25 | } 26 | } -------------------------------------------------------------------------------- /app/src/main/java/com/githubly/wanandroid/fragment/ArticleFragment.kt: -------------------------------------------------------------------------------- 1 | package com.githubly.wanandroid.fragment 2 | 3 | import android.support.v4.app.Fragment 4 | import android.support.v4.app.FragmentManager 5 | import android.support.v4.app.FragmentPagerAdapter 6 | import com.githubly.wanandroid.R 7 | import com.githubly.wanandroid.fragment.base.BaseFragment 8 | import com.githubly.wanandroid.model.Chapter 9 | import com.githubly.wanandroid.presenter.base.BasePresenter 10 | import com.githubly.wanandroid.utils.FileUtils 11 | import com.google.gson.Gson 12 | import com.google.gson.reflect.TypeToken 13 | import kotlinx.android.synthetic.main.fragment_article.* 14 | import org.jetbrains.anko.support.v4.act 15 | 16 | /** 17 | * 类名:ArticleFragment 18 | * 作者:Yun.Lei 19 | * 功能: 20 | * 创建日期:2018-10-19 16:12 21 | * 修改人: 22 | * 修改时间: 23 | * 修改备注: 24 | */ 25 | class ArticleFragment : BaseFragment>() { 26 | 27 | private lateinit var chapterList: MutableList 28 | 29 | override val inflateId: Int 30 | get() = R.layout.fragment_article 31 | 32 | override fun initView() { 33 | 34 | } 35 | 36 | override fun initData() { 37 | val readFileFromAssets = FileUtils.getFromAssets(act, "chapters") 38 | chapterList = Gson().fromJson(readFileFromAssets, object : TypeToken>() {}.type) 39 | viewPager.adapter = ArticlePagerAdapter(chapterList, childFragmentManager) 40 | tabLayout.setViewPager(viewPager) 41 | } 42 | 43 | override fun initPresenter(): BasePresenter<*>? = null 44 | } 45 | 46 | class ArticlePagerAdapter(private val chapterList: MutableList, fm: FragmentManager) : 47 | FragmentPagerAdapter(fm) { 48 | 49 | override fun getItem(position: Int): Fragment = ArticlePageFragment.getNewInstance(chapterList[position].id) 50 | 51 | override fun getCount(): Int = chapterList.size 52 | 53 | override fun getPageTitle(position: Int): CharSequence? = chapterList[position].name 54 | } -------------------------------------------------------------------------------- /app/src/main/java/com/githubly/wanandroid/fragment/ArticlePageFragment.kt: -------------------------------------------------------------------------------- 1 | package com.githubly.wanandroid.fragment 2 | 3 | import android.os.Bundle 4 | import android.support.v7.widget.LinearLayoutManager 5 | import com.githubly.wanandroid.R 6 | import com.githubly.wanandroid.activity.WebActivity 7 | import com.githubly.wanandroid.adapter.WXArticleAdapter 8 | import com.githubly.wanandroid.contract.IArticlePageContract 9 | import com.githubly.wanandroid.fragment.base.BaseFragment 10 | import com.githubly.wanandroid.model.ArticleItem 11 | import com.githubly.wanandroid.model.BaseListData 12 | import com.githubly.wanandroid.model.EventArticleCollectChange 13 | import com.githubly.wanandroid.model.EventRemoveCollectPageArticle 14 | import com.githubly.wanandroid.presenter.ArticlePagePresenter 15 | import kotlinx.android.synthetic.main.fragment_article_page.* 16 | import org.greenrobot.eventbus.EventBus 17 | import org.greenrobot.eventbus.Subscribe 18 | import org.greenrobot.eventbus.ThreadMode 19 | import org.jetbrains.anko.support.v4.act 20 | import org.jetbrains.anko.support.v4.toast 21 | import org.jetbrains.anko.support.v4.withArguments 22 | 23 | /** 24 | * 类名:ArticlePageFragment 25 | * 作者:Yun.Lei 26 | * 功能: 27 | * 创建日期:2018-10-19 16:42 28 | * 修改人: 29 | * 修改时间: 30 | * 修改备注: 31 | */ 32 | class ArticlePageFragment : BaseFragment(), IArticlePageContract.View { 33 | 34 | 35 | companion object { 36 | fun getNewInstance(userId: Int): ArticlePageFragment { 37 | val frag = ArticlePageFragment() 38 | frag.withArguments("userId" to userId) 39 | return frag 40 | } 41 | } 42 | 43 | private val mAdapter by lazy { WXArticleAdapter() } 44 | private var page = 1 45 | private var userId = 408 46 | override val inflateId: Int 47 | get() = R.layout.fragment_article_page 48 | 49 | override fun onCreate(savedInstanceState: Bundle?) { 50 | super.onCreate(savedInstanceState) 51 | userId = arguments?.getInt("userId") ?: 408 52 | EventBus.getDefault().register(this) 53 | } 54 | 55 | override fun initView() { 56 | mAdapter.userID = userId 57 | recyclerView.adapter = mAdapter 58 | recyclerView.layoutManager = LinearLayoutManager(activity) 59 | /*recyclerView.addItemDecoration( 60 | HorizontalDividerItemDecoration.Builder(activity).color(act.resources.getColor(R.color.backgroundColor)).size( 61 | dip(8) 62 | ).build() 63 | )*/ 64 | mAdapter.setOnLoadMoreListener({ 65 | page++ 66 | mPresenter?.getWXArticle(userId, page) 67 | }, recyclerView) 68 | mAdapter.setPreLoadNumber(2) 69 | refreshLayout.setOnRefreshListener { 70 | initData() 71 | } 72 | mAdapter.emptyView = mLoadingStateView 73 | mLoadingStateView.setOnReloadClickListener { 74 | initData() 75 | } 76 | mAdapter.setOnItemClickListener { _, _, position -> 77 | mAdapter.data[position]?.apply { 78 | WebActivity.active(act, link, id, author, title, collect) 79 | } 80 | } 81 | } 82 | 83 | override fun initPresenter(): ArticlePagePresenter? = ArticlePagePresenter(this) 84 | 85 | override fun initData() { 86 | mLoadingStateView.loading() 87 | page = 1 88 | mPresenter?.getWXArticle(userId, page) 89 | } 90 | 91 | 92 | override fun onArticleSuccess(data: BaseListData) { 93 | if (data.curPage == 1) { 94 | mAdapter.setNewData(data.datas) 95 | refreshLayout.isRefreshing = false 96 | } else { 97 | mAdapter.addData(data.datas) 98 | mAdapter.loadMoreComplete() 99 | } 100 | page = data.curPage 101 | if (data.over) { 102 | mAdapter.loadMoreEnd() 103 | } 104 | mAdapter.setEnableLoadMore(!data.over) 105 | mLoadingStateView.success() 106 | } 107 | 108 | override fun onArticleFailed(msg: String) { 109 | if (page == 1) { 110 | mAdapter.setNewData(mutableListOf()) 111 | mLoadingStateView.failed(msg) 112 | refreshLayout.isRefreshing = false 113 | } else { 114 | toast(msg) 115 | mAdapter.loadMoreComplete() 116 | } 117 | } 118 | 119 | @Subscribe(threadMode = ThreadMode.MAIN) 120 | fun onEventArticleCollectChange(event: EventArticleCollectChange) { 121 | val id = event.id 122 | val item = mAdapter.data.find { it.id == id } 123 | if (item != null) { 124 | item.collect = event.collect 125 | mAdapter.notifyDataSetChanged() 126 | } 127 | } 128 | 129 | @Subscribe(threadMode = ThreadMode.MAIN) 130 | fun onEventCollectRemove(event: EventRemoveCollectPageArticle) { 131 | val id = event.id 132 | onEventArticleCollectChange(EventArticleCollectChange(id, false)) 133 | } 134 | 135 | override fun onDestroy() { 136 | super.onDestroy() 137 | EventBus.getDefault().unregister(this) 138 | } 139 | } -------------------------------------------------------------------------------- /app/src/main/java/com/githubly/wanandroid/fragment/HomeFragment.kt: -------------------------------------------------------------------------------- 1 | package com.githubly.wanandroid.fragment 2 | 3 | 4 | import android.os.Bundle 5 | import android.support.v7.widget.LinearLayoutManager 6 | import android.view.View 7 | import android.widget.ImageView 8 | import cn.bingoogolapple.bgabanner.BGABanner 9 | import com.githubly.wanandroid.R 10 | import com.githubly.wanandroid.activity.WebActivity 11 | import com.githubly.wanandroid.adapter.HomeAdapter 12 | import com.githubly.wanandroid.contract.IHomeContract 13 | import com.githubly.wanandroid.fragment.base.BaseFragment 14 | import com.githubly.wanandroid.model.* 15 | import com.githubly.wanandroid.presenter.HomePresenter 16 | import com.githubly.wanandroid.utils.loadImage 17 | import com.yqritc.recyclerviewflexibledivider.HorizontalDividerItemDecoration 18 | import kotlinx.android.synthetic.main.fragment_home.* 19 | import kotlinx.android.synthetic.main.layout_home_banner.view.* 20 | import org.greenrobot.eventbus.EventBus 21 | import org.greenrobot.eventbus.Subscribe 22 | import org.greenrobot.eventbus.ThreadMode 23 | import org.jetbrains.anko.support.v4.act 24 | import org.jetbrains.anko.support.v4.dip 25 | import org.jetbrains.anko.support.v4.toast 26 | 27 | /** 28 | * HomeFragment 29 | * 30 | */ 31 | class HomeFragment : BaseFragment(), IHomeContract.View { 32 | 33 | 34 | private val mAdapter by lazy { HomeAdapter() } 35 | private lateinit var mBannerView: BGABanner 36 | private var page = 1 37 | 38 | override val inflateId: Int 39 | get() = R.layout.fragment_home 40 | 41 | override fun onCreate(savedInstanceState: Bundle?) { 42 | super.onCreate(savedInstanceState) 43 | EventBus.getDefault().register(this) 44 | } 45 | 46 | override fun initView() { 47 | val bannerView = View.inflate(activity, R.layout.layout_home_banner, null) 48 | mBannerView = bannerView.bannerView 49 | recyclerView.adapter = mAdapter 50 | recyclerView.layoutManager = LinearLayoutManager(activity) 51 | recyclerView.addItemDecoration( 52 | HorizontalDividerItemDecoration.Builder(activity).color(act.resources.getColor(R.color.backgroundColor)).size( 53 | dip(8) 54 | ).visibilityProvider { position, parent -> 55 | position == 0 56 | }.build() 57 | ) 58 | mAdapter.addHeaderView(bannerView) 59 | mBannerView.setAdapter { banner, itemView, model, position -> 60 | val imageView: ImageView = itemView as ImageView 61 | val bannerItem = model as Banner 62 | imageView.loadImage(bannerItem.imagePath) 63 | } 64 | mAdapter.setOnLoadMoreListener({ 65 | page++ 66 | mPresenter?.getHomeArticle(page) 67 | }, recyclerView) 68 | mAdapter.setPreLoadNumber(2) 69 | refreshLayout.setOnRefreshListener { 70 | initData() 71 | } 72 | mAdapter.setOnItemClickListener { adapter, view, position -> 73 | mAdapter.data[position]?.apply { 74 | WebActivity.active(act, link, id, author, title, collect) 75 | } 76 | } 77 | mAdapter.emptyView = mLoadingStateView 78 | mLoadingStateView.setOnReloadClickListener { 79 | initData() 80 | } 81 | mBannerView.setDelegate { _, _, model, _ -> 82 | val bannerItem = model as Banner 83 | bannerItem.apply { 84 | WebActivity.active(act, url, -1, "wanAndroid", title, collect = false) 85 | } 86 | } 87 | } 88 | 89 | override fun initPresenter(): HomePresenter? = HomePresenter(this) 90 | 91 | override fun initData() { 92 | mLoadingStateView.loading() 93 | page = 1 94 | mPresenter?.getBanner() 95 | mPresenter?.getHomeArticle(page) 96 | } 97 | 98 | override fun onBannerSuccess(banners: MutableList) { 99 | val tips = mutableListOf() 100 | banners.forEach { 101 | tips.add(it.title) 102 | } 103 | mBannerView.setData(banners, tips) 104 | } 105 | 106 | override fun onBannerFailed(msg: String) { 107 | 108 | } 109 | 110 | override fun onArticleSuccess(data: BaseListData) { 111 | if (data.curPage == 1) { 112 | mAdapter.setNewData(data.datas) 113 | refreshLayout.isRefreshing = false 114 | } else { 115 | mAdapter.addData(data.datas) 116 | mAdapter.loadMoreComplete() 117 | } 118 | page = data.curPage 119 | if (data.over) { 120 | mAdapter.loadMoreEnd() 121 | } 122 | mAdapter.setEnableLoadMore(!data.over) 123 | mLoadingStateView.success() 124 | } 125 | 126 | override fun onArticleFailed(msg: String) { 127 | if (page == 1) { 128 | mAdapter.setNewData(mutableListOf()) 129 | mLoadingStateView.failed(msg) 130 | refreshLayout.isRefreshing = false 131 | } else { 132 | toast(msg) 133 | mAdapter.loadMoreComplete() 134 | } 135 | } 136 | 137 | @Subscribe(threadMode = ThreadMode.MAIN) 138 | fun onEventArticleCollectChange(event: EventArticleCollectChange) { 139 | val id = event.id 140 | val item = mAdapter.data.find { it.id == id } 141 | if (item != null) { 142 | item.collect = event.collect 143 | mAdapter.notifyDataSetChanged() 144 | } 145 | } 146 | 147 | @Subscribe(threadMode = ThreadMode.MAIN) 148 | fun onEventCollectRemove(event: EventRemoveCollectPageArticle) { 149 | val id = event.id 150 | onEventArticleCollectChange(EventArticleCollectChange(id, false)) 151 | } 152 | 153 | override fun onDestroy() { 154 | super.onDestroy() 155 | EventBus.getDefault().unregister(this) 156 | } 157 | } 158 | -------------------------------------------------------------------------------- /app/src/main/java/com/githubly/wanandroid/fragment/MyFragment.kt: -------------------------------------------------------------------------------- 1 | package com.githubly.wanandroid.fragment 2 | 3 | import android.os.Bundle 4 | import android.view.View 5 | import com.githubly.wanandroid.App 6 | import com.githubly.wanandroid.R 7 | import com.githubly.wanandroid.activity.CollectListActivity 8 | import com.githubly.wanandroid.activity.LoginActivity 9 | import com.githubly.wanandroid.activity.WebActivity 10 | import com.githubly.wanandroid.contract.ILogoutContract 11 | import com.githubly.wanandroid.fragment.base.BaseFragment 12 | import com.githubly.wanandroid.model.User 13 | import com.githubly.wanandroid.presenter.LogoutPresenter 14 | import com.tencent.bugly.beta.Beta 15 | import kotlinx.android.synthetic.main.fragment_my.* 16 | import org.greenrobot.eventbus.EventBus 17 | import org.greenrobot.eventbus.Subscribe 18 | import org.greenrobot.eventbus.ThreadMode 19 | import org.jetbrains.anko.support.v4.act 20 | import org.jetbrains.anko.support.v4.toast 21 | 22 | /** 23 | * 类名:MyFragment 24 | * 作者:Yun.Lei 25 | * 功能: 26 | * 创建日期:2018-10-22 11:01 27 | * 修改人: 28 | * 修改时间: 29 | * 修改备注: 30 | */ 31 | class MyFragment : BaseFragment(), ILogoutContract.View { 32 | 33 | override val inflateId: Int 34 | get() = R.layout.fragment_my 35 | 36 | override fun onCreate(savedInstanceState: Bundle?) { 37 | super.onCreate(savedInstanceState) 38 | EventBus.getDefault().register(this) 39 | } 40 | 41 | override fun initView() { 42 | btnLogin.setOnClickListener { 43 | LoginActivity.active(act) 44 | } 45 | btnLogout.setOnClickListener { 46 | showLoading() 47 | mPresenter?.logout() 48 | } 49 | btnCollectList.setOnClickListener { 50 | if (App.instance.isLogin) { 51 | CollectListActivity.active(activity!!) 52 | } else { 53 | LoginActivity.active(act) 54 | } 55 | } 56 | btnAbout.setOnClickListener { 57 | val link = "file:///android_asset/web/about.html" 58 | WebActivity.active(act, link, -1, "wanAndroid", "", false) 59 | } 60 | btnTodo.setOnClickListener { 61 | toast("待完成...") 62 | } 63 | btnKnowSystem.setOnClickListener { 64 | toast("待完成...") 65 | } 66 | btnUpdate.setOnClickListener { 67 | Beta.checkUpgrade() 68 | } 69 | } 70 | 71 | override fun initData() { 72 | setUserInfo() 73 | } 74 | 75 | override fun initPresenter(): LogoutPresenter? = LogoutPresenter(this) 76 | 77 | @Subscribe(threadMode = ThreadMode.MAIN) 78 | fun onEventLoginSuccess(userEvent: User) { 79 | setUserInfo() 80 | } 81 | 82 | private fun setUserInfo() { 83 | val user = App.instance.user 84 | user?.let { 85 | nameImgTv.text = it.username.substring(0, 1) 86 | nameTv.text = it.username 87 | btnLogin.visibility = View.GONE 88 | nameTv.visibility = View.VISIBLE 89 | btnLogout.visibility = View.VISIBLE 90 | logoutLine.visibility = View.VISIBLE 91 | } ?: setLogout() 92 | } 93 | 94 | private fun setLogout() { 95 | nameImgTv.text = "" 96 | nameTv.text = "" 97 | btnLogin.visibility = View.VISIBLE 98 | nameTv.visibility = View.GONE 99 | btnLogout.visibility = View.GONE 100 | logoutLine.visibility = View.GONE 101 | } 102 | 103 | override fun onDestroy() { 104 | super.onDestroy() 105 | EventBus.getDefault().unregister(this) 106 | } 107 | 108 | override fun onLogoutSuccess() { 109 | dismissLoading() 110 | App.instance.user = null 111 | setLogout() 112 | } 113 | 114 | override fun onLogoutFailed(msg: String) { 115 | dismissLoading() 116 | toast(msg) 117 | } 118 | 119 | } -------------------------------------------------------------------------------- /app/src/main/java/com/githubly/wanandroid/fragment/ProjectFragment.kt: -------------------------------------------------------------------------------- 1 | package com.githubly.wanandroid.fragment 2 | 3 | import android.support.v4.app.Fragment 4 | import android.support.v4.app.FragmentManager 5 | import android.support.v4.app.FragmentPagerAdapter 6 | import com.githubly.wanandroid.R 7 | import com.githubly.wanandroid.fragment.base.BaseFragment 8 | import com.githubly.wanandroid.model.Chapter 9 | import com.githubly.wanandroid.presenter.base.BasePresenter 10 | import com.githubly.wanandroid.utils.FileUtils 11 | import com.google.gson.Gson 12 | import com.google.gson.reflect.TypeToken 13 | import kotlinx.android.synthetic.main.fragment_project.* 14 | import org.jetbrains.anko.support.v4.act 15 | 16 | /** 17 | * 类名:ArticleFragment 18 | * 作者:Yun.Lei 19 | * 功能: 20 | * 创建日期:2018-10-19 16:12 21 | * 修改人: 22 | * 修改时间: 23 | * 修改备注: 24 | */ 25 | class ProjectFragment : BaseFragment>() { 26 | 27 | private lateinit var chapterList: MutableList 28 | 29 | override val inflateId: Int 30 | get() = R.layout.fragment_project 31 | 32 | override fun initView() { 33 | 34 | } 35 | 36 | override fun initData() { 37 | val readFileFromAssets = FileUtils.getFromAssets(act, "projects") 38 | chapterList = Gson().fromJson(readFileFromAssets, object : TypeToken>() {}.type) 39 | viewPager.adapter = ProjectFragmentPagerAdapter(chapterList, childFragmentManager) 40 | tabLayout.setViewPager(viewPager) 41 | } 42 | 43 | override fun initPresenter(): BasePresenter<*>? = null 44 | } 45 | 46 | class ProjectFragmentPagerAdapter(private val chapterList: MutableList, fm: FragmentManager) : 47 | FragmentPagerAdapter(fm) { 48 | 49 | override fun getItem(position: Int): Fragment = ProjectPageFragment.getNewInstance(chapterList[position].id) 50 | 51 | override fun getCount(): Int = chapterList.size 52 | 53 | override fun getPageTitle(position: Int): CharSequence? = chapterList[position].name 54 | } -------------------------------------------------------------------------------- /app/src/main/java/com/githubly/wanandroid/fragment/ProjectPageFragment.kt: -------------------------------------------------------------------------------- 1 | package com.githubly.wanandroid.fragment 2 | 3 | import android.os.Bundle 4 | import android.support.v7.widget.StaggeredGridLayoutManager 5 | import com.githubly.wanandroid.R 6 | import com.githubly.wanandroid.activity.WebActivity 7 | import com.githubly.wanandroid.adapter.ProjectArticleAdapter 8 | import com.githubly.wanandroid.contract.IProjectPageContract 9 | import com.githubly.wanandroid.fragment.base.BaseFragment 10 | import com.githubly.wanandroid.model.ArticleItem 11 | import com.githubly.wanandroid.model.BaseListData 12 | import com.githubly.wanandroid.model.EventArticleCollectChange 13 | import com.githubly.wanandroid.model.EventRemoveCollectPageArticle 14 | import com.githubly.wanandroid.presenter.ProjectPagePresenter 15 | import kotlinx.android.synthetic.main.fragment_project_page.* 16 | import org.greenrobot.eventbus.EventBus 17 | import org.greenrobot.eventbus.Subscribe 18 | import org.greenrobot.eventbus.ThreadMode 19 | import org.jetbrains.anko.support.v4.act 20 | import org.jetbrains.anko.support.v4.toast 21 | import org.jetbrains.anko.support.v4.withArguments 22 | 23 | /** 24 | * 类名:ProjectPageFragment 25 | * 作者:Yun.Lei 26 | * 功能: 27 | * 创建日期:2018-10-19 16:42 28 | * 修改人: 29 | * 修改时间: 30 | * 修改备注: 31 | */ 32 | class ProjectPageFragment : BaseFragment(), IProjectPageContract.View { 33 | 34 | 35 | companion object { 36 | fun getNewInstance(userId: Int): ProjectPageFragment { 37 | val frag = ProjectPageFragment() 38 | frag.withArguments("userId" to userId) 39 | return frag 40 | } 41 | } 42 | 43 | private val mAdapter by lazy { ProjectArticleAdapter() } 44 | private var page = 1 45 | private var userId = 99999 46 | override val inflateId: Int 47 | get() = R.layout.fragment_project_page 48 | 49 | override fun onCreate(savedInstanceState: Bundle?) { 50 | super.onCreate(savedInstanceState) 51 | EventBus.getDefault().register(this) 52 | userId = arguments?.getInt("userId") ?: 99999 53 | } 54 | 55 | override fun initView() { 56 | recyclerView.adapter = mAdapter 57 | recyclerView.layoutManager = StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL) 58 | /*recyclerView.addItemDecoration( 59 | HorizontalDividerItemDecoration.Builder(activity).color(act.resources.getColor(R.color.backgroundColor)).size( 60 | dip(8) 61 | ).build() 62 | )*/ 63 | mAdapter.setOnLoadMoreListener({ 64 | page++ 65 | mPresenter?.getProjectArticle(userId, page) 66 | }, recyclerView) 67 | mAdapter.setPreLoadNumber(2) 68 | refreshLayout.setOnRefreshListener { 69 | initData() 70 | } 71 | mAdapter.emptyView = mLoadingStateView 72 | mLoadingStateView.setOnReloadClickListener { 73 | initData() 74 | } 75 | mAdapter.setOnItemClickListener { _, _, position -> 76 | mAdapter.data[position]?.apply { 77 | WebActivity.active(act, link, id, author, title, collect) 78 | } 79 | } 80 | } 81 | 82 | override fun initPresenter(): ProjectPagePresenter? = ProjectPagePresenter(this) 83 | 84 | override fun initData() { 85 | mLoadingStateView.loading() 86 | page = 1 87 | mPresenter?.getProjectArticle(userId, page) 88 | } 89 | 90 | 91 | override fun onArticleSuccess(data: BaseListData) { 92 | if (data.curPage == 1) { 93 | mAdapter.setNewData(data.datas) 94 | refreshLayout.isRefreshing = false 95 | } else { 96 | mAdapter.addData(data.datas) 97 | mAdapter.loadMoreComplete() 98 | } 99 | page = data.curPage 100 | if (data.over) { 101 | mAdapter.loadMoreEnd() 102 | } 103 | mAdapter.setEnableLoadMore(!data.over) 104 | mLoadingStateView.success() 105 | } 106 | 107 | override fun onArticleFailed(msg: String) { 108 | if (page == 1) { 109 | mAdapter.setNewData(mutableListOf()) 110 | mLoadingStateView.failed(msg) 111 | refreshLayout.isRefreshing = false 112 | } else { 113 | toast(msg) 114 | mAdapter.loadMoreComplete() 115 | } 116 | } 117 | 118 | @Subscribe(threadMode = ThreadMode.MAIN) 119 | fun onEventArticleCollectChange(event: EventArticleCollectChange) { 120 | val id = event.id 121 | val item = mAdapter.data.find { it.id == id } 122 | if (item != null) { 123 | item.collect = event.collect 124 | mAdapter.notifyDataSetChanged() 125 | } 126 | } 127 | 128 | @Subscribe(threadMode = ThreadMode.MAIN) 129 | fun onEventCollectRemove(event: EventRemoveCollectPageArticle) { 130 | val id = event.id 131 | onEventArticleCollectChange(EventArticleCollectChange(id, false)) 132 | } 133 | 134 | override fun onDestroy() { 135 | super.onDestroy() 136 | EventBus.getDefault().unregister(this) 137 | } 138 | } -------------------------------------------------------------------------------- /app/src/main/java/com/githubly/wanandroid/fragment/base/BaseFragment.kt: -------------------------------------------------------------------------------- 1 | package com.githubly.wanandroid.fragment.base 2 | 3 | import android.os.Bundle 4 | import android.support.v4.app.Fragment 5 | import android.view.LayoutInflater 6 | import android.view.View 7 | import android.view.ViewGroup 8 | import com.githubly.wanandroid.presenter.base.BasePresenter 9 | import com.githubly.wanandroid.utils.ILoading 10 | import com.githubly.wanandroid.widget.LoadingStateView 11 | import com.yanzhenjie.loading.dialog.LoadingDialog 12 | import org.jetbrains.anko.support.v4.act 13 | 14 | /** 15 | * 类名:BaseFragment 16 | * 作者:Yun.Lei 17 | * 功能: 18 | * 创建日期:2018-10-18 19:34 19 | * 修改人: 20 | * 修改时间: 21 | * 修改备注: 22 | */ 23 | abstract class BaseFragment> : Fragment(), ILoading { 24 | /** 25 | * 当前页面需要加载的layoutId,等价setContentView 26 | */ 27 | abstract val inflateId: Int 28 | 29 | /** 30 | * 初始化视图操作在这里执行,执行时机为onCreate之后 31 | */ 32 | abstract fun initView(): Unit 33 | 34 | /** 35 | * 数据初始化在这里执行,执行时机为initView之后 36 | */ 37 | abstract fun initData(): Unit 38 | 39 | //kotlin 懒加载,在第一次使用Presenter时初始化,这种设计师针对一个View只针对一个Presenter。 40 | //多个Presenter的情况此处不应该使用泛型 41 | protected val mPresenter: P? by lazy { initPresenter() } 42 | 43 | abstract fun initPresenter(): P? 44 | 45 | private val mWaitDialog by lazy { LoadingDialog(act) } 46 | 47 | protected val mLoadingStateView by lazy { LoadingStateView(act) } 48 | 49 | override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { 50 | return inflater.inflate(inflateId, container, false) 51 | } 52 | 53 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) { 54 | super.onViewCreated(view, savedInstanceState) 55 | initView() 56 | initData() 57 | } 58 | 59 | override fun onDestroyView() { 60 | super.onDestroyView() 61 | //view和presenter解绑 62 | mPresenter?.onDestroy() 63 | dismissLoading() 64 | } 65 | 66 | override fun showLoading(msg: String) { 67 | mWaitDialog.setMessage(msg) 68 | if (!mWaitDialog.isShowing) { 69 | mWaitDialog.show() 70 | } 71 | } 72 | 73 | override fun dismissLoading() { 74 | if (mWaitDialog.isShowing) { 75 | mWaitDialog.dismiss() 76 | } 77 | } 78 | } -------------------------------------------------------------------------------- /app/src/main/java/com/githubly/wanandroid/model/ArticleItem.kt: -------------------------------------------------------------------------------- 1 | package com.githubly.wanandroid.model 2 | 3 | import com.google.gson.annotations.SerializedName 4 | 5 | 6 | /** 7 | * 类名:ArticleItem 8 | * 作者:Yun.Lei 9 | * 功能: 10 | * 创建日期:2018-10-18 17:57 11 | * 修改人: 12 | * 修改时间: 13 | * 修改备注: 14 | */ 15 | 16 | data class ArticleItem( 17 | @SerializedName("apkLink") var apkLink: String = "", 18 | @SerializedName("author") var author: String = "", 19 | @SerializedName("chapterId") var chapterId: Int = 0, 20 | @SerializedName("chapterName") var chapterName: String = "", 21 | @SerializedName("collect") var collect: Boolean = false, 22 | @SerializedName("courseId") var courseId: Int = 0, 23 | @SerializedName("desc") var desc: String = "", 24 | @SerializedName("envelopePic") var envelopePic: String = "", 25 | @SerializedName("fresh") var fresh: Boolean = false, 26 | @SerializedName("id") var id: Int = 0, 27 | @SerializedName("link") var link: String = "", 28 | @SerializedName("niceDate") var niceDate: String = "", 29 | @SerializedName("origin") var origin: String = "", 30 | @SerializedName("projectLink") var projectLink: String = "", 31 | @SerializedName("publishTime") var publishTime: Long = 0, 32 | @SerializedName("superChapterId") var superChapterId: Int = 0, 33 | @SerializedName("superChapterName") var superChapterName: String = "", 34 | @SerializedName("tags") var tags: MutableList = mutableListOf(), 35 | @SerializedName("title") var title: String = "", 36 | @SerializedName("type") var type: Int = 0, 37 | @SerializedName("userId") var userId: Int = 0, 38 | @SerializedName("visible") var visible: Int = 0, 39 | @SerializedName("zan") var zan: Int = 0, 40 | @SerializedName("originId") var originId: Int = 0 41 | ) 42 | 43 | data class WChatArticleTag( 44 | @SerializedName("name") var name: String = "", 45 | @SerializedName("url") var url: String = "" 46 | ) 47 | 48 | data class EventRemoveCollectPageArticle(var id: Int) 49 | 50 | data class EventArticleCollectChange(var id: Int,var collect: Boolean) -------------------------------------------------------------------------------- /app/src/main/java/com/githubly/wanandroid/model/Banner.kt: -------------------------------------------------------------------------------- 1 | package com.githubly.wanandroid.model 2 | import com.google.gson.annotations.SerializedName 3 | 4 | 5 | /** 6 | * 类名:Banner 7 | * 作者:Yun.Lei 8 | * 功能: 9 | * 创建日期:2018-10-19 11:30 10 | * 修改人: 11 | * 修改时间: 12 | * 修改备注: 13 | */ 14 | 15 | data class Banner( 16 | @SerializedName("desc") var desc: String = "", 17 | @SerializedName("id") var id: Int = 0, 18 | @SerializedName("imagePath") var imagePath: String = "", 19 | @SerializedName("isVisible") var isVisible: Int = 0, 20 | @SerializedName("order") var order: Int = 0, 21 | @SerializedName("title") var title: String = "", 22 | @SerializedName("type") var type: Int = 0, 23 | @SerializedName("url") var url: String = "" 24 | ) -------------------------------------------------------------------------------- /app/src/main/java/com/githubly/wanandroid/model/BaseListData.kt: -------------------------------------------------------------------------------- 1 | package com.githubly.wanandroid.model 2 | 3 | /** 4 | * 类名:BaseListData 5 | * 作者:Yun.Lei 6 | * 功能: 7 | * 创建日期:2018-10-18 17:54 8 | * 修改人: 9 | * 修改时间: 10 | * 修改备注: 11 | */ 12 | class BaseListData { 13 | val curPage: Int = 0 14 | val datas: MutableList = mutableListOf() 15 | val offset: Int = 0 16 | val over: Boolean = true 17 | val pageCount: Int = 0 18 | val size: Int = 0 19 | val total: Int = 0 20 | } -------------------------------------------------------------------------------- /app/src/main/java/com/githubly/wanandroid/model/BaseResult.kt: -------------------------------------------------------------------------------- 1 | package com.githubly.wanandroid.model 2 | 3 | /** 4 | * 类名:BaseResult 5 | * 作者:Yun.Lei 6 | * 功能: 7 | * 创建日期:2018-10-18 17:16 8 | * 修改人: 9 | * 修改时间: 10 | * 修改备注: 11 | */ 12 | class BaseResult { 13 | var data: T? = null 14 | var errorCode: Int = -1 15 | var errorMsg: String = "" 16 | 17 | val isSuccess: Boolean 18 | get() = errorCode == 0 19 | } -------------------------------------------------------------------------------- /app/src/main/java/com/githubly/wanandroid/model/Chapter.kt: -------------------------------------------------------------------------------- 1 | package com.githubly.wanandroid.model 2 | import com.google.gson.annotations.SerializedName 3 | 4 | 5 | /** 6 | * 类名:Chapter 7 | * 作者:Yun.Lei 8 | * 功能: 9 | * 创建日期:2018-10-19 16:33 10 | * 修改人: 11 | * 修改时间: 12 | * 修改备注: 13 | */ 14 | 15 | data class Chapter( 16 | @SerializedName("children") var children: List = listOf(), 17 | @SerializedName("courseId") var courseId: Int = 0, 18 | @SerializedName("id") var id: Int = 0, 19 | @SerializedName("name") var name: String = "", 20 | @SerializedName("order") var order: Int = 0, 21 | @SerializedName("parentChapterId") var parentChapterId: Int = 0, 22 | @SerializedName("userControlSetTop") var userControlSetTop: Boolean = false, 23 | @SerializedName("visible") var visible: Int = 0 24 | ) -------------------------------------------------------------------------------- /app/src/main/java/com/githubly/wanandroid/model/User.kt: -------------------------------------------------------------------------------- 1 | package com.githubly.wanandroid.model 2 | import android.os.Parcel 3 | import android.os.Parcelable 4 | import com.google.gson.annotations.SerializedName 5 | 6 | 7 | /** 8 | * 类名:User 9 | * 作者:Yun.Lei 10 | * 功能: 11 | * 创建日期:2018-10-22 12:51 12 | * 修改人: 13 | * 修改时间: 14 | * 修改备注: 15 | */ 16 | 17 | data class User( 18 | @SerializedName("email") var email: String = "", 19 | @SerializedName("icon") var icon: String = "", 20 | @SerializedName("id") var id: Int = 0, 21 | @SerializedName("password") var password: String = "", 22 | @SerializedName("token") var token: String = "", 23 | @SerializedName("type") var type: Int = 0, 24 | @SerializedName("username") var username: String = "" 25 | ) : Parcelable { 26 | constructor(parcel: Parcel) : this( 27 | parcel.readString(), 28 | parcel.readString(), 29 | parcel.readInt(), 30 | parcel.readString(), 31 | parcel.readString(), 32 | parcel.readInt(), 33 | parcel.readString()) { 34 | } 35 | 36 | override fun writeToParcel(parcel: Parcel, flags: Int) { 37 | parcel.writeString(email) 38 | parcel.writeString(icon) 39 | parcel.writeInt(id) 40 | parcel.writeString(password) 41 | parcel.writeString(token) 42 | parcel.writeInt(type) 43 | parcel.writeString(username) 44 | } 45 | 46 | override fun describeContents(): Int { 47 | return 0 48 | } 49 | 50 | companion object CREATOR : Parcelable.Creator { 51 | override fun createFromParcel(parcel: Parcel): User { 52 | return User(parcel) 53 | } 54 | 55 | override fun newArray(size: Int): Array { 56 | return arrayOfNulls(size) 57 | } 58 | } 59 | 60 | } -------------------------------------------------------------------------------- /app/src/main/java/com/githubly/wanandroid/net/ApiCallBack.kt: -------------------------------------------------------------------------------- 1 | package com.githubly.wanandroid.net 2 | 3 | import com.githubly.wanandroid.App 4 | import com.githubly.wanandroid.model.BaseResult 5 | import retrofit2.Call 6 | import retrofit2.Callback 7 | import retrofit2.Response 8 | import java.net.ConnectException 9 | import java.net.SocketTimeoutException 10 | import java.net.UnknownHostException 11 | 12 | /** 13 | * 类名:ApiCallBack 14 | * 作者:Yun.Lei 15 | * 功能: 16 | * 创建日期:2018-10-18 17:14 17 | * 修改人: 18 | * 修改时间: 19 | * 修改备注: 20 | */ 21 | class ApiCallBack(val result: BaseResult.() -> Unit) : Callback> { 22 | 23 | override fun onResponse(call: Call>, response: Response>) { 24 | val code = response.code() 25 | if (code in 200..299) { 26 | val errorCode = response.body()?.errorCode 27 | if (errorCode == -1001) { //需要重新登录 28 | App.instance.user = null 29 | } else { 30 | response.body()!!.result() 31 | } 32 | } else { 33 | onFailure(call, RuntimeException("response error,detail = " + response.raw().toString())) 34 | } 35 | } 36 | 37 | override fun onFailure(call: Call>, throwable: Throwable) { 38 | val error = when (throwable) { 39 | is SocketTimeoutException -> "网络不给力!" 40 | is ConnectException -> "当前的网络不通!" 41 | is UnknownHostException -> "当前的网络不通!" 42 | else -> "当前服务异常!" 43 | //可进一步细分错误类型 44 | } 45 | BaseResult().apply { 46 | errorCode = -1 47 | errorMsg = error 48 | }.result() 49 | } 50 | } -------------------------------------------------------------------------------- /app/src/main/java/com/githubly/wanandroid/net/ApiHelper.kt: -------------------------------------------------------------------------------- 1 | package com.githubly.wanandroid.net 2 | 3 | import com.githubly.wanandroid.BuildConfig 4 | import okhttp3.OkHttpClient 5 | import okhttp3.logging.HttpLoggingInterceptor 6 | import retrofit2.Retrofit 7 | import retrofit2.converter.gson.GsonConverterFactory 8 | import java.util.concurrent.TimeUnit 9 | 10 | /** 11 | * 类名:ApiHelper 12 | * 作者:Yun.Lei 13 | * 功能: 14 | * 创建日期:2018-10-18 16:19 15 | * 修改人: 16 | * 修改时间: 17 | * 修改备注: 18 | */ 19 | object ApiHelper { 20 | 21 | val api: ApiService 22 | 23 | init { 24 | val builder = OkHttpClient.Builder() 25 | builder.apply { 26 | connectTimeout(10, TimeUnit.SECONDS) 27 | readTimeout(10, TimeUnit.SECONDS) 28 | writeTimeout(10, TimeUnit.SECONDS) 29 | retryOnConnectionFailure(true) 30 | addInterceptor(HttpLoggingInterceptor().apply { 31 | level = if (BuildConfig.DEBUG) 32 | HttpLoggingInterceptor.Level.BODY 33 | else 34 | HttpLoggingInterceptor.Level.NONE 35 | }) 36 | addInterceptor(ReadCookiesInterceptor()) 37 | addInterceptor(SaveCookiesInterceptor()) 38 | } 39 | val retrofitBuilder = Retrofit.Builder() 40 | .baseUrl("http://wanandroid.com") 41 | .addConverterFactory(GsonConverterFactory.create()) 42 | .client(builder.build()) 43 | val retrofit = retrofitBuilder.build() 44 | api = retrofit.create(ApiService::class.java) 45 | } 46 | } -------------------------------------------------------------------------------- /app/src/main/java/com/githubly/wanandroid/net/ApiService.kt: -------------------------------------------------------------------------------- 1 | package com.githubly.wanandroid.net 2 | 3 | import com.githubly.wanandroid.model.* 4 | import retrofit2.Call 5 | import retrofit2.http.* 6 | 7 | /** 8 | * 类名:ApiService 9 | * 作者:Yun.Lei 10 | * 功能: 11 | * 创建日期:2018-10-18 16:59 12 | * 修改人: 13 | * 修改时间: 14 | * 修改备注: 15 | */ 16 | interface ApiService { 17 | 18 | //获取最新项目 19 | @GET("/article/listproject/{page}/json") 20 | fun getLatestProjects(@Path("page") page: Int): Call>> 21 | 22 | 23 | //获取项目 24 | @GET("/project/list/{page}/json") 25 | fun getProjects(@Path("page") page: Int, @Query("cid") cid: Int): Call>> 26 | 27 | //首页banner 28 | @GET("/banner/json") 29 | fun getBanner(): Call>> 30 | 31 | //首页文章列表 32 | @GET("/article/list/{page}/json") 33 | fun getHomeArticles(@Path("page") page: Int): Call>> 34 | 35 | //查看某个公众号历史数据 36 | @GET("/wxarticle/list/{userID}/{page}/json") 37 | fun getWXArticle(@Path("userID") userID: Int, @Path("page") page: Int): Call>> 38 | 39 | //登录 40 | @FormUrlEncoded 41 | @POST("/user/login") 42 | fun login(@Field("username") username: String, @Field("password") password: String): Call> 43 | 44 | //注册 45 | @FormUrlEncoded 46 | @POST("/user/register") 47 | fun register(@Field("username") username: String, 48 | @Field("password") password: String, 49 | @Field("repassword") repassword: String): Call> 50 | 51 | //退出登录 52 | @GET("/user/logout/json") 53 | fun logout(): Call> 54 | 55 | //收藏文章列表 56 | @GET("/lg/collect/list/{page}/json") 57 | fun getCollectList(@Path("page") page: Int): Call>> 58 | 59 | //收藏文章 60 | @POST("/lg/collect/{id}/json") 61 | fun collect(@Path("id") id: Int): Call> 62 | 63 | //取消收藏文章 64 | @POST("/lg/uncollect_originId/{id}/json") 65 | fun uncollect(@Path("id") id: Int): Call> 66 | 67 | //取消收藏文章--收藏页面 68 | @FormUrlEncoded 69 | @POST("/lg/uncollect/{id}/json") 70 | fun unCollectPage(@Path("id") id: Int, @Field("originId") originId: Int): Call> 71 | } -------------------------------------------------------------------------------- /app/src/main/java/com/githubly/wanandroid/net/ReadCookiesInterceptor.kt: -------------------------------------------------------------------------------- 1 | package com.githubly.wanandroid.net 2 | 3 | import com.githubly.wanandroid.utils.UserInfoHelper 4 | import okhttp3.Interceptor 5 | import okhttp3.Response 6 | import java.io.IOException 7 | 8 | /** 9 | * 读取cookie并设置 10 | */ 11 | class ReadCookiesInterceptor : Interceptor { 12 | 13 | @Throws(IOException::class) 14 | override fun intercept(chain: Interceptor.Chain): Response { 15 | val builder = chain.request().newBuilder() 16 | val preferences = UserInfoHelper.getCookie() 17 | preferences?.let { 18 | for (cookie in preferences) { 19 | builder.addHeader("Cookie", cookie) 20 | } 21 | } 22 | return chain.proceed(builder.build()) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /app/src/main/java/com/githubly/wanandroid/net/SaveCookiesInterceptor.kt: -------------------------------------------------------------------------------- 1 | package com.githubly.wanandroid.net 2 | 3 | import com.githubly.wanandroid.utils.UserInfoHelper 4 | import okhttp3.Interceptor 5 | import okhttp3.Response 6 | import java.io.IOException 7 | import java.util.* 8 | 9 | /** 10 | * 保存Cookie 11 | */ 12 | class SaveCookiesInterceptor : Interceptor { 13 | @Throws(IOException::class) 14 | override fun intercept(chain: Interceptor.Chain): Response { 15 | val originalResponse = chain.proceed(chain.request()) 16 | if (!originalResponse.headers("Set-Cookie").isEmpty()) { 17 | val cookies = HashSet() 18 | for (header in originalResponse.headers("Set-Cookie")) { 19 | cookies.add(header) 20 | } 21 | UserInfoHelper.saveCookie(cookies) 22 | } 23 | return originalResponse 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /app/src/main/java/com/githubly/wanandroid/presenter/ArticlePagePresenter.kt: -------------------------------------------------------------------------------- 1 | package com.githubly.wanandroid.presenter 2 | 3 | import com.githubly.wanandroid.contract.IArticlePageContract 4 | import com.githubly.wanandroid.net.ApiCallBack 5 | import com.githubly.wanandroid.net.ApiHelper 6 | import com.githubly.wanandroid.presenter.base.BasePresenter 7 | 8 | /** 9 | * 类名:ArticlePagePresenter 10 | * 作者:Yun.Lei 11 | * 功能: 12 | * 创建日期:2018-10-19 17:12 13 | * 修改人: 14 | * 修改时间: 15 | * 修改备注: 16 | */ 17 | class ArticlePagePresenter(view: IArticlePageContract.View) : BasePresenter(view), IArticlePageContract.Presenter { 18 | 19 | override fun getWXArticle(userID: Int, page: Int) { 20 | ApiHelper.api.getWXArticle(userID, page).enqueue(ApiCallBack { 21 | if (isSuccess) { 22 | mView?.onArticleSuccess(data!!) 23 | } else { 24 | mView?.onArticleFailed(errorMsg) 25 | } 26 | }) 27 | } 28 | } -------------------------------------------------------------------------------- /app/src/main/java/com/githubly/wanandroid/presenter/CollectListPresenter.kt: -------------------------------------------------------------------------------- 1 | package com.githubly.wanandroid.presenter 2 | 3 | import com.githubly.wanandroid.contract.ICollectListContract 4 | import com.githubly.wanandroid.net.ApiCallBack 5 | import com.githubly.wanandroid.net.ApiHelper 6 | import com.githubly.wanandroid.presenter.base.BasePresenter 7 | 8 | /** 9 | * 类名:CollectListPresenter 10 | * 作者:Yun.Lei 11 | * 功能: 12 | * 创建日期:2018-10-22 17:48 13 | * 修改人: 14 | * 修改时间: 15 | * 修改备注: 16 | */ 17 | class CollectListPresenter(view: ICollectListContract.View) : BasePresenter(view), ICollectListContract.Presenter { 18 | override fun getCollectList(page: Int) { 19 | ApiHelper.api.getCollectList(page - 1).enqueue(ApiCallBack { 20 | if (isSuccess) { 21 | data?.datas?.forEach { 22 | it.collect = true 23 | } 24 | if (data?.datas?.isEmpty() == true) { 25 | mView?.onListFailed("暂无收藏数据!") 26 | } else { 27 | mView?.onListSuccess(data!!) 28 | } 29 | } else { 30 | mView?.onListFailed(errorMsg) 31 | } 32 | }) 33 | } 34 | } -------------------------------------------------------------------------------- /app/src/main/java/com/githubly/wanandroid/presenter/ContentPresenter.kt: -------------------------------------------------------------------------------- 1 | package com.githubly.wanandroid.presenter 2 | 3 | import com.githubly.wanandroid.contract.IContentContract 4 | import com.githubly.wanandroid.net.ApiCallBack 5 | import com.githubly.wanandroid.net.ApiHelper 6 | import com.githubly.wanandroid.presenter.base.BasePresenter 7 | 8 | /** 9 | * 类名:ContentPresenter 10 | * 作者:Yun.Lei 11 | * 功能: 12 | * 创建日期:2018-10-23 16:16 13 | * 修改人: 14 | * 修改时间: 15 | * 修改备注: 16 | */ 17 | class ContentPresenter(view: IContentContract.View) : 18 | BasePresenter(view), IContentContract.Presenter { 19 | override fun articleCollect(id: Int) { 20 | ApiHelper.api.collect(id).enqueue(ApiCallBack { 21 | if (isSuccess) { 22 | mView?.onCollectSuccess() 23 | } else { 24 | mView?.onCollectFailed(errorMsg) 25 | } 26 | }) 27 | } 28 | 29 | override fun articleUncollect(id: Int) { 30 | ApiHelper.api.uncollect(id).enqueue(ApiCallBack{ 31 | if (isSuccess) { 32 | mView?.onUncollectSuccess() 33 | } else { 34 | mView?.onUncollectFailed(errorMsg) 35 | } 36 | }) 37 | } 38 | 39 | override fun articleUncollectPage(id: Int,originId:Int) { 40 | ApiHelper.api.unCollectPage(id,originId).enqueue(ApiCallBack{ 41 | if (isSuccess) { 42 | mView?.onUncollectPageSuccess() 43 | } else { 44 | mView?.onUncollectPageFailed(errorMsg) 45 | } 46 | }) 47 | } 48 | } -------------------------------------------------------------------------------- /app/src/main/java/com/githubly/wanandroid/presenter/HomePresenter.kt: -------------------------------------------------------------------------------- 1 | package com.githubly.wanandroid.presenter 2 | 3 | import com.githubly.wanandroid.contract.IHomeContract 4 | import com.githubly.wanandroid.net.ApiCallBack 5 | import com.githubly.wanandroid.net.ApiHelper 6 | import com.githubly.wanandroid.presenter.base.BasePresenter 7 | 8 | /** 9 | * 类名:HomePresenter 10 | * 作者:Yun.Lei 11 | * 功能: 12 | * 创建日期:2018-10-19 11:32 13 | * 修改人: 14 | * 修改时间: 15 | * 修改备注: 16 | */ 17 | class HomePresenter(view: IHomeContract.View) : 18 | BasePresenter(view), IHomeContract.Presenter { 19 | override fun getHomeArticle(page: Int) { 20 | //page 从1开始 接口Index 从0开始 21 | ApiHelper.api.getHomeArticles(page-1).enqueue(ApiCallBack { 22 | if (isSuccess) { 23 | mView?.onArticleSuccess(data!!) 24 | } else { 25 | mView?.onArticleFailed(errorMsg) 26 | } 27 | }) 28 | } 29 | 30 | override fun getBanner() { 31 | ApiHelper.api.getBanner().enqueue(ApiCallBack { 32 | if (isSuccess) { 33 | mView?.onBannerSuccess(data ?: mutableListOf()) 34 | } else { 35 | mView?.onBannerFailed(errorMsg) 36 | } 37 | }) 38 | } 39 | 40 | } -------------------------------------------------------------------------------- /app/src/main/java/com/githubly/wanandroid/presenter/LoginPresenter.kt: -------------------------------------------------------------------------------- 1 | package com.githubly.wanandroid.presenter 2 | 3 | import com.githubly.wanandroid.contract.ILoginContract 4 | import com.githubly.wanandroid.net.ApiCallBack 5 | import com.githubly.wanandroid.net.ApiHelper 6 | import com.githubly.wanandroid.presenter.base.BasePresenter 7 | 8 | /** 9 | * 类名:LoginPresenter 10 | * 作者:Yun.Lei 11 | * 功能: 12 | * 创建日期:2018-10-22 14:44 13 | * 修改人: 14 | * 修改时间: 15 | * 修改备注: 16 | */ 17 | class LoginPresenter(view: ILoginContract.View) : 18 | BasePresenter(view), ILoginContract.Presenter { 19 | override fun register(userName: String, password: String, rePassword: String) { 20 | ApiHelper.api.register(userName, password, rePassword).enqueue(ApiCallBack { 21 | if (isSuccess) { 22 | mView?.onRegisterSuccess(data!!) 23 | } else { 24 | mView?.onRegisterFailed(errorMsg) 25 | } 26 | }) 27 | } 28 | 29 | override fun login(userName: String, password: String) { 30 | ApiHelper.api.login(userName, password).enqueue(ApiCallBack { 31 | if (isSuccess) { 32 | mView?.onLoginSuccess(data!!) 33 | } else { 34 | mView?.onLoginFailed(errorMsg) 35 | } 36 | 37 | }) 38 | } 39 | } -------------------------------------------------------------------------------- /app/src/main/java/com/githubly/wanandroid/presenter/LogoutPresenter.kt: -------------------------------------------------------------------------------- 1 | package com.githubly.wanandroid.presenter 2 | 3 | import com.githubly.wanandroid.contract.ILogoutContract 4 | import com.githubly.wanandroid.net.ApiCallBack 5 | import com.githubly.wanandroid.net.ApiHelper 6 | import com.githubly.wanandroid.presenter.base.BasePresenter 7 | 8 | /** 9 | * 类名:LogoutPresenter 10 | * 作者:Yun.Lei 11 | * 功能: 12 | * 创建日期:2018-10-22 16:40 13 | * 修改人: 14 | * 修改时间: 15 | * 修改备注: 16 | */ 17 | class LogoutPresenter(view: ILogoutContract.View) : 18 | BasePresenter(view),ILogoutContract.Presenter { 19 | override fun logout() { 20 | ApiHelper.api.logout().enqueue(ApiCallBack{ 21 | if (isSuccess){ 22 | mView?.onLogoutSuccess() 23 | }else{ 24 | mView?.onLogoutFailed(errorMsg) 25 | } 26 | }) 27 | } 28 | } -------------------------------------------------------------------------------- /app/src/main/java/com/githubly/wanandroid/presenter/ProjectPagePresenter.kt: -------------------------------------------------------------------------------- 1 | package com.githubly.wanandroid.presenter 2 | 3 | import com.githubly.wanandroid.contract.IProjectPageContract 4 | import com.githubly.wanandroid.net.ApiCallBack 5 | import com.githubly.wanandroid.net.ApiHelper 6 | import com.githubly.wanandroid.presenter.base.BasePresenter 7 | 8 | /** 9 | * 类名:ProjectPagePresenter 10 | * 作者:Yun.Lei 11 | * 功能: 12 | * 创建日期:2018-10-19 17:12 13 | * 修改人: 14 | * 修改时间: 15 | * 修改备注: 16 | */ 17 | class ProjectPagePresenter(view: IProjectPageContract.View) : BasePresenter(view), IProjectPageContract.Presenter { 18 | 19 | 20 | override fun getProjectArticle(userID: Int, page: Int) { 21 | if (userID == 99999) { 22 | //接口兼容 page 1 index = 0 23 | ApiHelper.api.getLatestProjects(page-1).enqueue(ApiCallBack { 24 | if (isSuccess) { 25 | mView?.onArticleSuccess(data!!) 26 | } else { 27 | mView?.onArticleFailed(errorMsg) 28 | } 29 | }) 30 | } else { 31 | ApiHelper.api.getProjects(page, userID).enqueue(ApiCallBack { 32 | if (isSuccess) { 33 | mView?.onArticleSuccess(data!!) 34 | } else { 35 | mView?.onArticleFailed(errorMsg) 36 | } 37 | }) 38 | } 39 | } 40 | 41 | 42 | } -------------------------------------------------------------------------------- /app/src/main/java/com/githubly/wanandroid/presenter/base/BasePresenter.kt: -------------------------------------------------------------------------------- 1 | package com.githubly.wanandroid.presenter.base 2 | 3 | /** 4 | * 类名:BasePresenter 5 | * 作者:Yun.Lei 6 | * 功能: 7 | * 创建日期:2018-07-13 10:40 8 | * 修改人: 9 | * 修改时间: 10 | * 修改备注: 11 | */ 12 | abstract class BasePresenter(view: T) { 13 | protected var mView: T? = view 14 | 15 | fun onDestroy() { 16 | mView = null 17 | } 18 | 19 | } -------------------------------------------------------------------------------- /app/src/main/java/com/githubly/wanandroid/presenter/base/IView.kt: -------------------------------------------------------------------------------- 1 | package com.githubly.wanandroid.presenter.base 2 | 3 | /** 4 | * 类名:IView 5 | * 作者:Yun.Lei 6 | * 功能: 7 | * 创建日期:2018-07-13 10:39 8 | * 修改人: 9 | * 修改时间: 10 | * 修改备注: 11 | */ 12 | interface IView -------------------------------------------------------------------------------- /app/src/main/java/com/githubly/wanandroid/utils/AppUtils.kt: -------------------------------------------------------------------------------- 1 | package com.githubly.wanandroid.utils 2 | 3 | import android.content.Context 4 | 5 | /** 6 | * 类名:AppUtils 7 | * 作者:Yun.Lei 8 | * 功能: 9 | * 创建日期:2018-10-24 10:13 10 | * 修改人: 11 | * 修改时间: 12 | * 修改备注: 13 | */ 14 | object AppUtils { 15 | 16 | 17 | /** 18 | * 获取版本名称 19 | * 20 | * @param context 21 | * @return 22 | */ 23 | fun getVersionName(context: Context): String { 24 | var versionName = "" 25 | try { 26 | // 获取软件版本名称 27 | versionName = context.packageManager.getPackageInfo( 28 | context.packageName, 0).versionName 29 | } catch (e: Exception) { 30 | return versionName 31 | } 32 | 33 | return versionName 34 | } 35 | 36 | /** 37 | * 获取版本号 38 | * 39 | * @param context 40 | * @return 41 | */ 42 | fun getVersionCode(context: Context): Int { 43 | // 获取软件版本号 44 | var versionCode = 0L 45 | try { 46 | versionCode = context.packageManager.getPackageInfo(context.packageName, 0).longVersionCode 47 | } catch (e: Exception) { 48 | return versionCode.toInt() 49 | } 50 | 51 | return versionCode.toInt() 52 | } 53 | } -------------------------------------------------------------------------------- /app/src/main/java/com/githubly/wanandroid/utils/BuglyFileProvider.kt: -------------------------------------------------------------------------------- 1 | package com.githubly.wanandroid.utils 2 | 3 | import android.support.v4.content.FileProvider 4 | 5 | /** 6 | * 类名:BuglyFileProvider 7 | * 作者:Yun.Lei 8 | * 功能: 9 | * 创建日期:2018-10-23 19:59 10 | * 修改人: 11 | * 修改时间: 12 | * 修改备注: 13 | */ 14 | class BuglyFileProvider:FileProvider() -------------------------------------------------------------------------------- /app/src/main/java/com/githubly/wanandroid/utils/ContentUtil.kt: -------------------------------------------------------------------------------- 1 | package com.githubly.wanandroid.utils 2 | 3 | import android.app.Activity 4 | import android.content.Context 5 | import android.content.Intent 6 | import android.graphics.Point 7 | import android.net.Uri 8 | import android.provider.Settings 9 | import android.support.v4.app.Fragment 10 | import android.view.View 11 | import android.view.WindowManager 12 | import android.view.inputmethod.InputMethodManager 13 | import org.jetbrains.anko.support.v4.act 14 | 15 | 16 | /** 17 | * 类名:ContentUtil 18 | * 作者:Yun.Lei 19 | * 功能: 20 | * 创建日期:2018-10-22 19:45 21 | * 修改人: 22 | * 修改时间: 23 | * 修改备注: 24 | */ 25 | 26 | fun Activity.hideSoftInput(view: View = window.peekDecorView()) { 27 | val inputManger = getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager 28 | inputManger.hideSoftInputFromWindow(view.windowToken, 0) 29 | } 30 | 31 | fun Activity.showSoftInput(view: View = window.peekDecorView()) { 32 | val inputManger = getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager 33 | inputManger.showSoftInput(view, 0) 34 | } 35 | 36 | fun Fragment.hideSoftInput(view: View? = getView()) { 37 | if (view != null) { 38 | val inputManger = act.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager 39 | inputManger.hideSoftInputFromWindow(view.windowToken, 0) 40 | } 41 | } 42 | 43 | fun Fragment.showSoftInput(view: View? = getView()) { 44 | val inputManger = act.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager 45 | inputManger.showSoftInput(view, 0) 46 | } 47 | 48 | fun Context.toAppDetail(){ 49 | val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS) 50 | intent.addCategory(Intent.CATEGORY_DEFAULT) 51 | intent.data = Uri.fromParts("package", packageName, null) 52 | startActivity(intent) 53 | } 54 | fun Fragment.toAppDetail(requestCode:Int = -1){ 55 | val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS) 56 | intent.addCategory(Intent.CATEGORY_DEFAULT) 57 | intent.data = Uri.fromParts("package", activity?.packageName, null) 58 | startActivityForResult(intent,requestCode) 59 | } 60 | fun Activity.toAppDetail(requestCode:Int = -1){ 61 | val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS) 62 | intent.addCategory(Intent.CATEGORY_DEFAULT) 63 | intent.data = Uri.fromParts("package", packageName, null) 64 | startActivityForResult(intent,requestCode) 65 | } 66 | /** 67 | * 屏幕宽度 68 | */ 69 | fun Context.screenWidth(): Int { 70 | val vm = getSystemService(Context.WINDOW_SERVICE) as WindowManager 71 | val point = Point() 72 | vm.defaultDisplay.getSize(point) 73 | return point.x 74 | } 75 | 76 | /** 77 | * 屏幕高度 78 | */ 79 | fun Context.screenHeight(): Int { 80 | val vm = getSystemService(Context.WINDOW_SERVICE) as WindowManager 81 | val point = Point() 82 | vm.defaultDisplay.getSize(point) 83 | return point.y 84 | } -------------------------------------------------------------------------------- /app/src/main/java/com/githubly/wanandroid/utils/DialogUtil.kt: -------------------------------------------------------------------------------- 1 | package com.githubly.wanandroid.utils 2 | 3 | 4 | 5 | /** 6 | * 类名:DialogUtil 7 | * 作者:Yun.Lei 8 | * 功能: 9 | * 创建日期:2018-10-22 17:11 10 | * 修改人: 11 | * 修改时间: 12 | * 修改备注: 13 | */ 14 | 15 | interface ILoading{ 16 | fun showLoading(msg:String="") 17 | fun dismissLoading() 18 | } 19 | -------------------------------------------------------------------------------- /app/src/main/java/com/githubly/wanandroid/utils/FileUtils.kt: -------------------------------------------------------------------------------- 1 | package com.githubly.wanandroid.utils 2 | 3 | import android.content.Context 4 | import java.io.BufferedReader 5 | import java.io.IOException 6 | import java.io.InputStreamReader 7 | 8 | /** 9 | * 类名:FileUtils 10 | * 作者:Yun.Lei 11 | * 功能: 12 | * 创建日期:2018-10-19 16:29 13 | * 修改人: 14 | * 修改时间: 15 | * 修改备注: 16 | */ 17 | object FileUtils { 18 | 19 | /** 20 | * 从assets读取文本内容 21 | * 22 | * @param context 23 | * @param fileName 24 | * @return 25 | */ 26 | fun getFromAssets(context: Context, fileName: String): String { 27 | val result = StringBuffer() 28 | var inputReader: InputStreamReader? = null 29 | var bufReader: BufferedReader? = null 30 | try { 31 | inputReader = InputStreamReader(context.resources.assets.open(fileName), "UTF-8") 32 | bufReader = BufferedReader(inputReader) 33 | bufReader.readLines().forEach { 34 | result.append(it) 35 | } 36 | 37 | } catch (e: Exception) { 38 | e.printStackTrace() 39 | } finally { 40 | try { 41 | inputReader?.close() 42 | bufReader?.close() 43 | } catch (e: IOException) { 44 | e.printStackTrace() 45 | } 46 | 47 | } 48 | return result.toString().trim() 49 | } 50 | } -------------------------------------------------------------------------------- /app/src/main/java/com/githubly/wanandroid/utils/UserInfoHelper.kt: -------------------------------------------------------------------------------- 1 | package com.githubly.wanandroid.utils 2 | 3 | import android.annotation.SuppressLint 4 | import android.content.Context 5 | import com.githubly.wanandroid.model.User 6 | 7 | @SuppressLint("StaticFieldLeak") 8 | /** 9 | * 类名:UserInfoHelper 10 | * 作者:Yun.Lei 11 | * 功能: 12 | * 创建日期:2018-10-22 12:56 13 | * 修改人: 14 | * 修改时间: 15 | * 修改备注: 16 | */ 17 | object UserInfoHelper { 18 | 19 | private var ctx: Context? = null 20 | 21 | fun init(context: Context) { 22 | ctx = context.applicationContext 23 | } 24 | 25 | /** 26 | * 保存用户信息 27 | */ 28 | fun saveUser(user: User) { 29 | val sp = ctx?.getSharedPreferences("user_info", Context.MODE_PRIVATE) 30 | sp?.edit()?.apply { 31 | putString("email", user.email) 32 | putString("icon", user.icon) 33 | putString("username", user.username) 34 | putString("password", user.password) 35 | putString("token", user.token) 36 | putInt("id", user.id) 37 | putInt("type", user.type) 38 | }?.apply() 39 | } 40 | 41 | /** 42 | * 获取保存的用户信息 43 | */ 44 | fun getUser(): User? { 45 | val sp = ctx?.getSharedPreferences("user_info", Context.MODE_PRIVATE) 46 | val user = User( 47 | sp?.getString("email", "") ?: "", 48 | sp?.getString("icon", "") ?: "", 49 | sp?.getInt("id", -1) ?: -1, 50 | sp?.getString("password", "") ?: "", 51 | sp?.getString("token", "") ?: "", 52 | sp?.getInt("type", -1) ?: -1, 53 | sp?.getString("username", "") ?: "" 54 | 55 | ) 56 | return if (user.id == -1) null else user 57 | } 58 | 59 | /** 60 | * 清除保存的用户信息 61 | */ 62 | fun clearUser() { 63 | val sp = ctx?.getSharedPreferences("user_info", Context.MODE_PRIVATE) 64 | sp?.edit()?.clear()?.apply() 65 | } 66 | 67 | 68 | fun saveCookie(set:HashSet){ 69 | val sp = ctx?.getSharedPreferences("user_info", Context.MODE_PRIVATE) 70 | sp?.edit()?.apply { 71 | putStringSet("cookie",set) 72 | }?.apply() 73 | } 74 | 75 | fun getCookie():HashSet?{ 76 | val sp = ctx?.getSharedPreferences("user_info", Context.MODE_PRIVATE) 77 | return sp?.getStringSet("cookie", hashSetOf()) as HashSet? 78 | } 79 | } -------------------------------------------------------------------------------- /app/src/main/java/com/githubly/wanandroid/utils/ViewUtil.kt: -------------------------------------------------------------------------------- 1 | package com.githubly.wanandroid.utils 2 | 3 | import android.widget.ImageView 4 | import com.bumptech.glide.Glide 5 | import com.bumptech.glide.request.RequestOptions 6 | import com.githubly.wanandroid.R 7 | 8 | /** 9 | * 类名:ImageViewUtil 10 | * 作者:Yun.Lei 11 | * 功能: 12 | * 创建日期:2018-10-19 11:44 13 | * 修改人: 14 | * 修改时间: 15 | * 修改备注: 16 | */ 17 | fun ImageView?.loadImage( 18 | url: String, 19 | placeHolderRes: Int = R.mipmap.ic_empty_banner, 20 | errorRes: Int = R.mipmap.ic_empty_banner, 21 | fallbackRes: Int = R.mipmap.ic_empty_banner 22 | ) { 23 | if (this == null) return 24 | Glide.with(this) 25 | .load(url) 26 | .thumbnail(0.1f) 27 | .apply(RequestOptions().apply { 28 | placeholder(placeHolderRes) 29 | error(errorRes) 30 | fallback(fallbackRes) 31 | }) 32 | .into(this) 33 | } -------------------------------------------------------------------------------- /app/src/main/java/com/githubly/wanandroid/widget/HackyViewPager.kt: -------------------------------------------------------------------------------- 1 | package com.githubly.wanandroid.widget 2 | 3 | import android.content.Context 4 | import android.support.v4.view.ViewPager 5 | import android.util.AttributeSet 6 | import android.view.MotionEvent 7 | import com.githubly.wanandroid.R 8 | 9 | /** 10 | * 类名:HackyViewPager 11 | * 作者:Yun.Lei 12 | * 功能: 13 | * 创建日期:2017-10-24 17:38 14 | * 修改人: 15 | * 修改时间: 16 | * 修改备注: 17 | */ 18 | class HackyViewPager : ViewPager { 19 | 20 | var isLock = false 21 | 22 | constructor(context: Context) : this(context, null) 23 | constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) { 24 | val a = context.obtainStyledAttributes(attrs, R.styleable.HackyViewPager, 0, 0) 25 | isLock = a.getBoolean(R.styleable.HackyViewPager_hvp_is_lock, false) 26 | a.recycle() 27 | } 28 | 29 | override fun onInterceptTouchEvent(ev: MotionEvent): Boolean { 30 | if (!isLock) { 31 | return try { 32 | super.onInterceptTouchEvent(ev) 33 | } catch (e: IllegalArgumentException) { 34 | e.printStackTrace() 35 | false 36 | } 37 | 38 | } 39 | return false 40 | } 41 | 42 | override fun onTouchEvent(event: MotionEvent): Boolean { 43 | return if (!isLock) { 44 | super.onTouchEvent(event) 45 | } else false 46 | } 47 | 48 | fun toggleLock() { 49 | isLock = !isLock 50 | } 51 | 52 | } -------------------------------------------------------------------------------- /app/src/main/java/com/githubly/wanandroid/widget/LoadingStateView.kt: -------------------------------------------------------------------------------- 1 | package com.githubly.wanandroid.widget 2 | 3 | import android.content.Context 4 | import android.util.AttributeSet 5 | import android.view.View 6 | import android.widget.FrameLayout 7 | import com.githubly.wanandroid.R 8 | import kotlinx.android.synthetic.main.layout_page_state.view.* 9 | 10 | /** 11 | * 类名:LoadingStateView 12 | * 作者:Yun.Lei 13 | * 功能: 14 | * 创建日期:2018-10-22 19:07 15 | * 修改人: 16 | * 修改时间: 17 | * 修改备注: 18 | */ 19 | class LoadingStateView : FrameLayout { 20 | 21 | constructor(context: Context) : super(context) 22 | constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) 23 | constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr) 24 | 25 | private var mView: View = View.inflate(context, R.layout.layout_page_state, this) 26 | 27 | 28 | fun loading() { 29 | visibility = View.VISIBLE 30 | mView.loadingView.visibility = View.VISIBLE 31 | mView.errorView.visibility = View.GONE 32 | } 33 | 34 | fun success() { 35 | visibility = View.GONE 36 | } 37 | 38 | fun failed(msg: String = "加载失败") { 39 | visibility = View.VISIBLE 40 | mView.loadingView.visibility = View.GONE 41 | mView.errorView.visibility = View.VISIBLE 42 | mView.errorMsgTv.text = msg 43 | } 44 | 45 | fun setOnReloadClickListener(onClick:View.() -> Unit) { 46 | errorView.setOnClickListener{ 47 | it.onClick() 48 | } 49 | } 50 | } -------------------------------------------------------------------------------- /app/src/main/java/com/githubly/wanandroid/widget/OtherBottomDialog.kt: -------------------------------------------------------------------------------- 1 | package com.githubly.wanandroid.widget 2 | 3 | import android.app.Dialog 4 | import android.graphics.Color 5 | import android.graphics.drawable.ColorDrawable 6 | import android.os.Bundle 7 | import android.support.design.widget.BottomSheetDialogFragment 8 | import android.support.v4.app.DialogFragment 9 | import android.view.LayoutInflater 10 | import android.view.View 11 | import android.view.ViewGroup 12 | import com.githubly.wanandroid.R 13 | import kotlinx.android.synthetic.main.dialog_other_bottom.* 14 | import org.jetbrains.anko.support.v4.act 15 | import org.jetbrains.anko.support.v4.withArguments 16 | 17 | /** 18 | * 类名:OtherBottomDialog 19 | * 作者:Yun.Lei 20 | * 功能: 21 | * 创建日期:2018-10-23 15:05 22 | * 修改人: 23 | * 修改时间: 24 | * 修改备注: 25 | */ 26 | const val TYPE_SHARE = 0 27 | const val TYPE_COLLECT = 1 28 | const val TYPE_COPY = 2 29 | const val TYPE_BROWSER = 3 30 | 31 | class OtherBottomDialog : BottomSheetDialogFragment() { 32 | 33 | companion object { 34 | fun getDialog(collect: Boolean): OtherBottomDialog { 35 | val dialog = OtherBottomDialog() 36 | dialog.withArguments("collect" to collect) 37 | return dialog 38 | } 39 | } 40 | 41 | var onItemClick: (type: Int) -> Unit = {} 42 | private var collect: Boolean = false 43 | 44 | override fun onCreate(savedInstanceState: Bundle?) { 45 | super.onCreate(savedInstanceState) 46 | setStyle(DialogFragment.STYLE_NO_TITLE, R.style.style_common_dialog) 47 | collect = arguments?.getBoolean("collect") ?: false 48 | } 49 | 50 | override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { 51 | val dialog = super.onCreateDialog(savedInstanceState) 52 | dialog.window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT)) 53 | return dialog 54 | } 55 | 56 | override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { 57 | return inflater.inflate(R.layout.dialog_other_bottom, container, false) 58 | } 59 | 60 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) { 61 | super.onViewCreated(view, savedInstanceState) 62 | btnCancel.setOnClickListener { 63 | dismiss() 64 | } 65 | collectImageView.setColorFilter(act.resources.getColor(if (collect) R.color.red else R.color.black)) 66 | collectTV.text = if (collect) "取消收藏" else "收藏" 67 | btnShare.setOnClickListener { 68 | onItemClick(TYPE_SHARE) 69 | } 70 | btnCollect.setOnClickListener { 71 | onItemClick(TYPE_COLLECT) 72 | } 73 | btnCopy.setOnClickListener { 74 | onItemClick(TYPE_COPY) 75 | } 76 | btnBrowser.setOnClickListener { 77 | onItemClick(TYPE_BROWSER) 78 | } 79 | } 80 | } -------------------------------------------------------------------------------- /app/src/main/java/com/githubly/wanandroid/widget/ScrollTextView.kt: -------------------------------------------------------------------------------- 1 | package com.githubly.wanandroid.widget 2 | 3 | import android.content.Context 4 | import android.text.TextUtils 5 | import android.util.AttributeSet 6 | 7 | /** 8 | * 类名:ScrollTextView 9 | * 作者:Yun.Lei 10 | * 功能: 11 | * 创建日期:2018-10-18 19:10 12 | * 修改人: 13 | * 修改时间: 14 | * 修改备注: 15 | */ 16 | class ScrollTextView : android.support.v7.widget.AppCompatTextView { 17 | 18 | constructor(context: Context?) : super(context) 19 | constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs) 20 | constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr) 21 | 22 | init { 23 | ellipsize = TextUtils.TruncateAt.MARQUEE 24 | marqueeRepeatLimit = -1 25 | setSingleLine(true) 26 | } 27 | 28 | override fun isFocused(): Boolean { 29 | return true 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /app/src/main/res/color/color_main_page_bottom_tab.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/color/selector_back.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /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/color_cursor.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 10 | 12 | 14 | 16 | 18 | 20 | 22 | 24 | 26 | 28 | 30 | 32 | 34 | 36 | 38 | 40 | 42 | 44 | 46 | 48 | 50 | 52 | 54 | 56 | 58 | 60 | 62 | 64 | 66 | 68 | 70 | 72 | 74 | 75 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/line_et_bg.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/line_et_focus.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | 13 | 14 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/line_et_normal.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | 13 | 14 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/progress_horizontal.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/selector_banner_point.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/selector_tab_article.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/selector_tab_category.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/selector_tab_home.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/selector_tab_my.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/shape_head_blue.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/shape_head_green.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/shape_head_orange.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/shape_head_red.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/shape_login_btn.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/shape_other_dialog.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/shape_other_item.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/shape_project_collect.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/shape_round_3dp_ebebeb.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/shape_update_bg.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/shape_user_head.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/splash.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /app/src/main/res/font/font_title.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leiyun-studio/WanAndroid/abd7c07203f9e03e40ce436f23c4086913a0b0ec/app/src/main/res/font/font_title.ttf -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_collect_list.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 14 | 15 | 18 | 19 | 26 | 27 | 34 | 35 | 36 | 37 | 42 | 43 | 48 | 49 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_login.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 13 | 14 | 17 | 18 | 25 | 26 | 33 | 34 | 35 | 36 | 41 | 42 | 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 16 | 17 | 25 | 26 | 32 | 33 | 38 | 39 | 40 | 46 | 47 | 52 | 53 | 54 | 55 | 62 | 63 | 68 | 69 | 70 | 76 | 77 | 82 | 83 | 84 | 85 | 90 | 91 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_splash.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 19 | 20 | 31 | 32 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_web.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 13 | 14 | 17 | 18 | 25 | 26 | 35 | 36 | 46 | 47 | 56 | 57 | 67 | 68 | 69 | 70 | 75 | -------------------------------------------------------------------------------- /app/src/main/res/layout/dialog_other_bottom.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 13 | 14 | 21 | 22 | 28 | 29 | 36 | 37 | 38 | 45 | 46 | 53 | 54 | 62 | 63 | 64 | 71 | 72 | 78 | 79 | 86 | 87 | 88 | 95 | 96 | 102 | 103 | 110 | 111 | 112 | 113 | 121 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_article.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 13 | 14 | 26 | 27 | 41 | 42 | 43 | 48 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_article_page.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 11 | 12 | 17 | 18 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_home.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 13 | 14 | 25 | 26 | 27 | 31 | 32 | 37 | 38 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_project.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 13 | 14 | 26 | 27 | 41 | 42 | 43 | 48 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_project_page.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 13 | 14 | 19 | 20 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_home_article.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 10 | 23 | 24 | 25 | 36 | 37 | 49 | 50 | 64 | 65 | 80 | 81 | 90 | 91 | 104 | 105 | 112 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_project.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 15 | 16 | 20 | 21 | 27 | 28 | 39 | 40 | 47 | 48 | 58 | 59 | 60 | 71 | 72 | 81 | 82 | 83 | 92 | 93 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_wx_article.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 14 | 15 | 28 | 29 | 30 | 41 | 42 | 54 | 55 | 71 | 72 | 82 | -------------------------------------------------------------------------------- /app/src/main/res/layout/layout_home_banner.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 23 | 24 | 35 | -------------------------------------------------------------------------------- /app/src/main/res/layout/layout_page_state.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 12 | 13 | 20 | 21 | 25 | 26 | 35 | 36 | -------------------------------------------------------------------------------- /app/src/main/res/layout/upgrade_dialog.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 18 | 19 | 24 | 25 | 29 | 30 | 38 | 39 | 40 | 47 | 48 | 55 | 56 | 64 | 65 | 72 | 73 | 81 | 85 | 88 | 89 | 98 | 102 | 111 | 112 | 113 | -------------------------------------------------------------------------------- /app/src/main/res/layout/upgrade_tips_dialog.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 18 | 19 | 24 | 25 | 29 | 30 | 38 | 39 | 40 | 47 | 48 | 55 | 56 | 57 | 65 | 66 | 70 | 71 | 74 | 75 | 84 | 85 | 89 | 90 | 99 | 100 | 101 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_about.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leiyun-studio/WanAndroid/abd7c07203f9e03e40ce436f23c4086913a0b0ec/app/src/main/res/mipmap-xhdpi/ic_about.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_android.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leiyun-studio/WanAndroid/abd7c07203f9e03e40ce436f23c4086913a0b0ec/app/src/main/res/mipmap-xhdpi/ic_android.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_arrow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leiyun-studio/WanAndroid/abd7c07203f9e03e40ce436f23c4086913a0b0ec/app/src/main/res/mipmap-xhdpi/ic_arrow.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_back_def.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leiyun-studio/WanAndroid/abd7c07203f9e03e40ce436f23c4086913a0b0ec/app/src/main/res/mipmap-xhdpi/ic_back_def.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_banner_point.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leiyun-studio/WanAndroid/abd7c07203f9e03e40ce436f23c4086913a0b0ec/app/src/main/res/mipmap-xhdpi/ic_banner_point.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_banner_point_selected.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leiyun-studio/WanAndroid/abd7c07203f9e03e40ce436f23c4086913a0b0ec/app/src/main/res/mipmap-xhdpi/ic_banner_point_selected.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_browser.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leiyun-studio/WanAndroid/abd7c07203f9e03e40ce436f23c4086913a0b0ec/app/src/main/res/mipmap-xhdpi/ic_browser.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_clear.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leiyun-studio/WanAndroid/abd7c07203f9e03e40ce436f23c4086913a0b0ec/app/src/main/res/mipmap-xhdpi/ic_clear.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_close.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leiyun-studio/WanAndroid/abd7c07203f9e03e40ce436f23c4086913a0b0ec/app/src/main/res/mipmap-xhdpi/ic_close.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_collect.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leiyun-studio/WanAndroid/abd7c07203f9e03e40ce436f23c4086913a0b0ec/app/src/main/res/mipmap-xhdpi/ic_collect.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_collect_tag.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leiyun-studio/WanAndroid/abd7c07203f9e03e40ce436f23c4086913a0b0ec/app/src/main/res/mipmap-xhdpi/ic_collect_tag.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_copy_url.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leiyun-studio/WanAndroid/abd7c07203f9e03e40ce436f23c4086913a0b0ec/app/src/main/res/mipmap-xhdpi/ic_copy_url.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_empty.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leiyun-studio/WanAndroid/abd7c07203f9e03e40ce436f23c4086913a0b0ec/app/src/main/res/mipmap-xhdpi/ic_empty.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_empty_banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leiyun-studio/WanAndroid/abd7c07203f9e03e40ce436f23c4086913a0b0ec/app/src/main/res/mipmap-xhdpi/ic_empty_banner.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_head_default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leiyun-studio/WanAndroid/abd7c07203f9e03e40ce436f23c4086913a0b0ec/app/src/main/res/mipmap-xhdpi/ic_head_default.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_heart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leiyun-studio/WanAndroid/abd7c07203f9e03e40ce436f23c4086913a0b0ec/app/src/main/res/mipmap-xhdpi/ic_heart.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_knowledge_system.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leiyun-studio/WanAndroid/abd7c07203f9e03e40ce436f23c4086913a0b0ec/app/src/main/res/mipmap-xhdpi/ic_knowledge_system.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leiyun-studio/WanAndroid/abd7c07203f9e03e40ce436f23c4086913a0b0ec/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_login_bg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leiyun-studio/WanAndroid/abd7c07203f9e03e40ce436f23c4086913a0b0ec/app/src/main/res/mipmap-xhdpi/ic_login_bg.jpg -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_other.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leiyun-studio/WanAndroid/abd7c07203f9e03e40ce436f23c4086913a0b0ec/app/src/main/res/mipmap-xhdpi/ic_other.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_search_article.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leiyun-studio/WanAndroid/abd7c07203f9e03e40ce436f23c4086913a0b0ec/app/src/main/res/mipmap-xhdpi/ic_search_article.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_share.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leiyun-studio/WanAndroid/abd7c07203f9e03e40ce436f23c4086913a0b0ec/app/src/main/res/mipmap-xhdpi/ic_share.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_tag.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leiyun-studio/WanAndroid/abd7c07203f9e03e40ce436f23c4086913a0b0ec/app/src/main/res/mipmap-xhdpi/ic_tag.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_todo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leiyun-studio/WanAndroid/abd7c07203f9e03e40ce436f23c4086913a0b0ec/app/src/main/res/mipmap-xhdpi/ic_todo.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_update.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leiyun-studio/WanAndroid/abd7c07203f9e03e40ce436f23c4086913a0b0ec/app/src/main/res/mipmap-xhdpi/ic_update.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_article.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leiyun-studio/WanAndroid/abd7c07203f9e03e40ce436f23c4086913a0b0ec/app/src/main/res/mipmap-xxhdpi/ic_article.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_article_fill.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leiyun-studio/WanAndroid/abd7c07203f9e03e40ce436f23c4086913a0b0ec/app/src/main/res/mipmap-xxhdpi/ic_article_fill.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_category.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leiyun-studio/WanAndroid/abd7c07203f9e03e40ce436f23c4086913a0b0ec/app/src/main/res/mipmap-xxhdpi/ic_category.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_category_fill.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leiyun-studio/WanAndroid/abd7c07203f9e03e40ce436f23c4086913a0b0ec/app/src/main/res/mipmap-xxhdpi/ic_category_fill.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_home.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leiyun-studio/WanAndroid/abd7c07203f9e03e40ce436f23c4086913a0b0ec/app/src/main/res/mipmap-xxhdpi/ic_home.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_home_fill.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leiyun-studio/WanAndroid/abd7c07203f9e03e40ce436f23c4086913a0b0ec/app/src/main/res/mipmap-xxhdpi/ic_home_fill.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leiyun-studio/WanAndroid/abd7c07203f9e03e40ce436f23c4086913a0b0ec/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_me.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leiyun-studio/WanAndroid/abd7c07203f9e03e40ce436f23c4086913a0b0ec/app/src/main/res/mipmap-xxhdpi/ic_me.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_me_fill.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leiyun-studio/WanAndroid/abd7c07203f9e03e40ce436f23c4086913a0b0ec/app/src/main/res/mipmap-xxhdpi/ic_me_fill.png -------------------------------------------------------------------------------- /app/src/main/res/values/attrs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #008577 4 | #00574B 5 | #D81B60 6 | #ffffff 7 | #333333 8 | #19000000 9 | #33000000 10 | #66000000 11 | #99000000 12 | #cc000000 13 | #11333333 14 | #222222 15 | #666666 16 | #999999 17 | #cccccc 18 | #D8D8D8 19 | #f8f8f8 20 | #ff4444 21 | #54b3b3 22 | #4d92dc 23 | #ff8635 24 | @android:color/transparent 25 | 26 | -------------------------------------------------------------------------------- /app/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 48dp 5 | 12sp 6 | 14sp 7 | 16sp 8 | 18sp 9 | 20sp 10 | 1px 11 | 1dp 12 | 2dp 13 | 3dp 14 | 4dp 15 | 5dp 16 | 6dp 17 | 7dp 18 | 8dp 19 | 9dp 20 | 10dp 21 | 11dp 22 | 12dp 23 | 13dp 24 | 14dp 25 | 15dp 26 | 16dp 27 | 17dp 28 | 18dp 29 | 19dp 30 | 20dp 31 | 21dp 32 | 22dp 33 | 23dp 34 | 24dp 35 | 25dp 36 | 26dp 37 | 27dp 38 | 28dp 39 | 29dp 40 | 30dp 41 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 玩Android 3 | 我的收藏 4 | 登录/注册 5 | 首页 6 | 文章 7 | 项目 8 | 我的 9 | 分享 10 | 收藏 11 | 复制链接 12 | 浏览器打开 13 | 取消 14 | TODO工具 15 | 知识体系 16 | 更新 17 | 关于 18 | 退出登录 19 | 已收藏 20 | 搜索 21 | 登录 22 | 注册 23 | 用户名 24 | 密码 25 | 确认密码 26 | 加载失败 27 | 确定 28 | 29 | -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | 18 | 19 | 33 | 34 | 47 | 48 | 51 | 52 | 55 | 56 | -------------------------------------------------------------------------------- /app/src/test/java/com/githubly/wanandroid/ExampleUnitTest.kt: -------------------------------------------------------------------------------- 1 | package com.githubly.wanandroid 2 | 3 | import org.junit.Test 4 | 5 | import org.junit.Assert.* 6 | 7 | /** 8 | * Example local unit test, which will execute on the development machine (host). 9 | * 10 | * See [testing documentation](http://d.android.com/tools/testing). 11 | */ 12 | class ExampleUnitTest { 13 | @Test 14 | fun addition_isCorrect() { 15 | assertEquals(4, 2 + 2) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | ext.kotlin_version = '1.2.71' 5 | ext.anko_version='0.10.7' 6 | repositories { 7 | google() 8 | jcenter() 9 | maven { url "https://jitpack.io" } 10 | maven { url 'http://oss.jfrog.org/artifactory/oss-snapshot-local/' } 11 | } 12 | dependencies { 13 | classpath 'com.android.tools.build:gradle:3.2.1' 14 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 15 | classpath "org.jetbrains.kotlin:kotlin-android-extensions:$kotlin_version" 16 | // NOTE: Do not place your application dependencies here; they belong 17 | // in the individual module build.gradle files 18 | } 19 | } 20 | 21 | allprojects { 22 | repositories { 23 | google() 24 | jcenter() 25 | } 26 | } 27 | 28 | task clean(type: Delete) { 29 | delete rootProject.buildDir 30 | } 31 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | # IDE (e.g. Android Studio) users: 3 | # Gradle settings configured through the IDE *will override* 4 | # any settings specified in this file. 5 | # For more details on how to configure your build environment visit 6 | # http://www.gradle.org/docs/current/userguide/build_environment.html 7 | # Specifies the JVM arguments used for the daemon process. 8 | # The setting is particularly useful for tweaking memory settings. 9 | org.gradle.jvmargs=-Xmx1536m 10 | # When configured, Gradle will run in incubating parallel mode. 11 | # This option should only be used with decoupled projects. More details, visit 12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 13 | # org.gradle.parallel=true 14 | # Kotlin code style for this project: "official" or "obsolete": 15 | kotlin.code.style=official 16 | 17 | ALIAS_NAME = wanandroid 18 | ALIAS_PWD = 123456 19 | KEY_PATH = ../wanAndroid.jks 20 | KEY_PWD = 123456 21 | 22 | BUGLY_ID = "aad59a037f" -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leiyun-studio/WanAndroid/abd7c07203f9e03e40ce436f23c4086913a0b0ec/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.6-all.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Attempt to set APP_HOME 10 | # Resolve links: $0 may be a link 11 | PRG="$0" 12 | # Need this for relative symlinks. 13 | while [ -h "$PRG" ] ; do 14 | ls=`ls -ld "$PRG"` 15 | link=`expr "$ls" : '.*-> \(.*\)$'` 16 | if expr "$link" : '/.*' > /dev/null; then 17 | PRG="$link" 18 | else 19 | PRG=`dirname "$PRG"`"/$link" 20 | fi 21 | done 22 | SAVED="`pwd`" 23 | cd "`dirname \"$PRG\"`/" >/dev/null 24 | APP_HOME="`pwd -P`" 25 | cd "$SAVED" >/dev/null 26 | 27 | APP_NAME="Gradle" 28 | APP_BASE_NAME=`basename "$0"` 29 | 30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 31 | DEFAULT_JVM_OPTS="" 32 | 33 | # Use the maximum available, or set MAX_FD != -1 to use that value. 34 | MAX_FD="maximum" 35 | 36 | warn () { 37 | echo "$*" 38 | } 39 | 40 | die () { 41 | echo 42 | echo "$*" 43 | echo 44 | exit 1 45 | } 46 | 47 | # OS specific support (must be 'true' or 'false'). 48 | cygwin=false 49 | msys=false 50 | darwin=false 51 | nonstop=false 52 | case "`uname`" in 53 | CYGWIN* ) 54 | cygwin=true 55 | ;; 56 | Darwin* ) 57 | darwin=true 58 | ;; 59 | MINGW* ) 60 | msys=true 61 | ;; 62 | NONSTOP* ) 63 | nonstop=true 64 | ;; 65 | esac 66 | 67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 68 | 69 | # Determine the Java command to use to start the JVM. 70 | if [ -n "$JAVA_HOME" ] ; then 71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 72 | # IBM's JDK on AIX uses strange locations for the executables 73 | JAVACMD="$JAVA_HOME/jre/sh/java" 74 | else 75 | JAVACMD="$JAVA_HOME/bin/java" 76 | fi 77 | if [ ! -x "$JAVACMD" ] ; then 78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 79 | 80 | Please set the JAVA_HOME variable in your environment to match the 81 | location of your Java installation." 82 | fi 83 | else 84 | JAVACMD="java" 85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 86 | 87 | Please set the JAVA_HOME variable in your environment to match the 88 | location of your Java installation." 89 | fi 90 | 91 | # Increase the maximum file descriptors if we can. 92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 93 | MAX_FD_LIMIT=`ulimit -H -n` 94 | if [ $? -eq 0 ] ; then 95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 96 | MAX_FD="$MAX_FD_LIMIT" 97 | fi 98 | ulimit -n $MAX_FD 99 | if [ $? -ne 0 ] ; then 100 | warn "Could not set maximum file descriptor limit: $MAX_FD" 101 | fi 102 | else 103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 104 | fi 105 | fi 106 | 107 | # For Darwin, add options to specify how the application appears in the dock 108 | if $darwin; then 109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 110 | fi 111 | 112 | # For Cygwin, switch paths to Windows format before running java 113 | if $cygwin ; then 114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 116 | JAVACMD=`cygpath --unix "$JAVACMD"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Escape application args 158 | save () { 159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 160 | echo " " 161 | } 162 | APP_ARGS=$(save "$@") 163 | 164 | # Collect all arguments for the java command, following the shell quoting and substitution rules 165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 166 | 167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong 168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then 169 | cd "$(dirname "$0")" 170 | fi 171 | 172 | exec "$JAVACMD" "$@" 173 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /screenshot/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leiyun-studio/WanAndroid/abd7c07203f9e03e40ce436f23c4086913a0b0ec/screenshot/1.png -------------------------------------------------------------------------------- /screenshot/10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leiyun-studio/WanAndroid/abd7c07203f9e03e40ce436f23c4086913a0b0ec/screenshot/10.png -------------------------------------------------------------------------------- /screenshot/11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leiyun-studio/WanAndroid/abd7c07203f9e03e40ce436f23c4086913a0b0ec/screenshot/11.png -------------------------------------------------------------------------------- /screenshot/12.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leiyun-studio/WanAndroid/abd7c07203f9e03e40ce436f23c4086913a0b0ec/screenshot/12.jpg -------------------------------------------------------------------------------- /screenshot/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leiyun-studio/WanAndroid/abd7c07203f9e03e40ce436f23c4086913a0b0ec/screenshot/2.png -------------------------------------------------------------------------------- /screenshot/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leiyun-studio/WanAndroid/abd7c07203f9e03e40ce436f23c4086913a0b0ec/screenshot/3.png -------------------------------------------------------------------------------- /screenshot/4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leiyun-studio/WanAndroid/abd7c07203f9e03e40ce436f23c4086913a0b0ec/screenshot/4.png -------------------------------------------------------------------------------- /screenshot/5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leiyun-studio/WanAndroid/abd7c07203f9e03e40ce436f23c4086913a0b0ec/screenshot/5.png -------------------------------------------------------------------------------- /screenshot/6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leiyun-studio/WanAndroid/abd7c07203f9e03e40ce436f23c4086913a0b0ec/screenshot/6.png -------------------------------------------------------------------------------- /screenshot/7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leiyun-studio/WanAndroid/abd7c07203f9e03e40ce436f23c4086913a0b0ec/screenshot/7.png -------------------------------------------------------------------------------- /screenshot/8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leiyun-studio/WanAndroid/abd7c07203f9e03e40ce436f23c4086913a0b0ec/screenshot/8.png -------------------------------------------------------------------------------- /screenshot/9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leiyun-studio/WanAndroid/abd7c07203f9e03e40ce436f23c4086913a0b0ec/screenshot/9.png -------------------------------------------------------------------------------- /screenshot/QRCode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leiyun-studio/WanAndroid/abd7c07203f9e03e40ce436f23c4086913a0b0ec/screenshot/QRCode.png -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | -------------------------------------------------------------------------------- /wanAndroid.jks: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leiyun-studio/WanAndroid/abd7c07203f9e03e40ce436f23c4086913a0b0ec/wanAndroid.jks --------------------------------------------------------------------------------