├── .gitignore ├── .idea ├── codeStyles │ ├── Project.xml │ └── codeStyleConfig.xml ├── dbnavigator.xml ├── encodings.xml ├── gradle.xml ├── jarRepositories.xml ├── misc.xml └── runConfigurations.xml ├── README.md ├── app ├── .gitignore ├── __bus__.json ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── wsg │ │ └── up │ │ └── ExampleInstrumentedTest.kt │ ├── main │ ├── AndroidManifest.xml │ ├── assets │ │ ├── fonts │ │ │ ├── acfun.ttf │ │ │ └── eye.ttf │ │ ├── lamsa-splash-screen.json │ │ ├── logo-animation.json │ │ ├── pride-hard-seltzer.json │ │ └── ramadan-kareem-hello-doc.json │ ├── java │ │ └── com │ │ │ └── wsg │ │ │ └── up │ │ │ ├── MainActivity.kt │ │ │ ├── application │ │ │ └── MyApplication.kt │ │ │ ├── entity │ │ │ ├── BottomResourceData.kt │ │ │ ├── CommunityRecommend.kt │ │ │ └── DataBase.kt │ │ │ ├── ext │ │ │ ├── DialogExt.kt │ │ │ ├── TabLayoutExt.kt │ │ │ ├── TextViewExt.kt │ │ │ └── ViewExt.kt │ │ │ ├── repository │ │ │ ├── EyeRepository.kt │ │ │ └── WanAndroidRepository.kt │ │ │ ├── ui │ │ │ ├── activity │ │ │ │ ├── SplashActivity.kt │ │ │ │ ├── Test2Activity.kt │ │ │ │ ├── TestActivity.kt │ │ │ │ ├── base │ │ │ │ │ └── MyBaseActivity.kt │ │ │ │ ├── common │ │ │ │ │ └── WebActivity.kt │ │ │ │ └── ugc │ │ │ │ │ └── UgcDetailActivity.kt │ │ │ ├── adapter │ │ │ │ ├── ArticleAdapter.kt │ │ │ │ ├── BannerAdapter.kt │ │ │ │ ├── BannerViewHolder.kt │ │ │ │ ├── CommunityAdapter.kt │ │ │ │ ├── HomePagerAdapter.kt │ │ │ │ └── UgcDetailAdapter.kt │ │ │ ├── fragment │ │ │ │ ├── ChannelFragment.kt │ │ │ │ ├── FindFragment.kt │ │ │ │ ├── HomeFragment.kt │ │ │ │ ├── TestFragment.kt │ │ │ │ └── base │ │ │ │ │ └── MyBaseFragment.kt │ │ │ └── view │ │ │ │ ├── MyViewPager.kt │ │ │ │ ├── dialog │ │ │ │ └── MyConfirmDialog.kt │ │ │ │ ├── listener │ │ │ │ ├── AutoPlayPageChangeListener.kt │ │ │ │ └── HomeTabSelectedListener.kt │ │ │ │ └── ugc │ │ │ │ └── UgcDetailVideoPlayer.kt │ │ │ ├── utils │ │ │ ├── Constants.kt │ │ │ ├── EyeConstants.kt │ │ │ ├── TablayoutUtils.kt │ │ │ ├── Tools.kt │ │ │ └── TypeFaceUtil.kt │ │ │ └── viewmodel │ │ │ ├── EyeViewModel.kt │ │ │ └── WanAndroidViewModel.kt │ └── res │ │ ├── anim │ │ ├── anl_push_bottom_in.xml │ │ ├── anl_push_bottom_out.xml │ │ ├── anl_push_top_out.xml │ │ ├── anl_push_up_in.xml │ │ └── anl_push_up_out.xml │ │ ├── drawable-v24 │ │ └── ic_launcher_foreground.xml │ │ ├── drawable │ │ ├── confirm_dialog_box.xml │ │ ├── confirm_dialog_cancel_btn.xml │ │ ├── confirm_dialog_cancel_btn_check.xml │ │ ├── confirm_dialog_cancel_btn_uncheck.xml │ │ ├── confirm_dialog_ok_btn.xml │ │ ├── confirm_dialog_ok_btn_check.xml │ │ ├── confirm_dialog_ok_btn_uncheck.xml │ │ ├── confirm_dialog_single_btn.xml │ │ ├── ic_avatar_gray_76dp.xml │ │ ├── ic_favorite_border_black_20dp.xml │ │ ├── ic_favorite_border_white_20dp.xml │ │ ├── ic_kabi.xml │ │ ├── ic_kabi_uncheck.xml │ │ ├── ic_launcher_background.xml │ │ ├── ic_layers_white_30dp.xml │ │ ├── ic_logo_black_76dp.xml │ │ ├── ic_menghuan.xml │ │ ├── ic_menghuan_uncheck.xml │ │ ├── ic_pause_white_24dp.xml │ │ ├── ic_pikaqiu.xml │ │ ├── ic_pikaqiu_uncheck.xml │ │ ├── ic_play_white_24dp.xml │ │ ├── ic_pull_down_white_30dp.xml │ │ ├── ic_refresh_white_24dp.xml │ │ ├── ic_reply_white_20dp.xml │ │ ├── ic_share_white_20dp.xml │ │ ├── ic_star_white_15dp.xml │ │ ├── ic_star_white_20dp.xml │ │ ├── ic_xiaohuolong.xml │ │ ├── ic_xiaohuolong_uncheck.xml │ │ ├── shape_black_alpha_50_4dp_bg.xml │ │ ├── shape_choiceness_radius_black_2dp_bg.xml │ │ ├── shape_follow_radius_black_2dp_bg.xml │ │ ├── shape_follow_radius_white_4dp_bg.xml │ │ ├── shape_gray_4dp_bg.xml │ │ └── shape_primary_4dp_bg.xml │ │ ├── layout │ │ ├── activity_main.xml │ │ ├── activity_main2.xml │ │ ├── activity_splash.xml │ │ ├── activity_ugc_detail.xml │ │ ├── activity_web.xml │ │ ├── common_confirm_dialog.xml │ │ ├── common_empty.xml │ │ ├── fragment_channel.xml │ │ ├── fragment_find.xml │ │ ├── fragment_home.xml │ │ ├── item_banner.xml │ │ ├── item_find.xml │ │ ├── item_home_article.xml │ │ ├── item_ugc_detail.xml │ │ ├── layout_ugc_detail_video_player.xml │ │ └── tab_home_item.xml │ │ ├── mipmap-hdpi │ │ ├── ac_donghua.png │ │ ├── ac_fanju.png │ │ ├── ac_guichu.png │ │ ├── ac_keji.png │ │ ├── ac_shenghuo.png │ │ ├── ac_tiyu.png │ │ ├── ac_wudao.png │ │ ├── ac_xuniouxiang.png │ │ ├── ac_yingshi.png │ │ ├── ac_yinyue.png │ │ ├── ac_youxi.png │ │ ├── ac_yule.png │ │ ├── ac_yutang.png │ │ ├── ac_zhengyi.png │ │ └── btn_release_normal.png │ │ ├── mipmap-xhdpi │ │ └── ic_launcher.png │ │ ├── values │ │ ├── colors.xml │ │ ├── strings.xml │ │ └── styles.xml │ │ └── xml │ │ └── network_security_config.xml │ └── test │ └── java │ └── com │ └── wsg │ └── up │ └── ExampleUnitTest.kt ├── base ├── .gitignore ├── build.gradle ├── consumer-rules.pro ├── libs │ └── tbs_sdk_thirdapp_v3.6.0.jar ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── wsg │ │ └── base │ │ └── ExampleInstrumentedTest.kt │ ├── main │ ├── AndroidManifest.xml │ ├── assets │ │ ├── halloween_smoothymon.json │ │ └── whale.zip │ ├── java │ │ └── com │ │ │ └── wsg │ │ │ └── base │ │ │ ├── activity │ │ │ └── BaseActivity.kt │ │ │ ├── application │ │ │ └── BaseApplication.kt │ │ │ ├── common │ │ │ └── CommonExt.kt │ │ │ ├── entity │ │ │ └── BaseData.kt │ │ │ ├── exception │ │ │ └── AppException.kt │ │ │ ├── ext │ │ │ ├── ActivityMessengerExt.kt │ │ │ ├── ContextExt.kt │ │ │ ├── DensityExt.kt │ │ │ ├── LiveDataExt.kt │ │ │ ├── MvvmExt.kt │ │ │ └── ViewStateExt.kt │ │ │ ├── fragment │ │ │ └── BaseFragment.kt │ │ │ ├── lifecycle │ │ │ └── ProcessLifecycleObserver.kt │ │ │ ├── model │ │ │ └── BaseViewModel.kt │ │ │ ├── state │ │ │ ├── EBaseViewStatus.kt │ │ │ ├── IBaseUIView.kt │ │ │ └── ViewState.kt │ │ │ └── ui │ │ │ └── dialog │ │ │ └── MyProgressDialog.kt │ └── res │ │ ├── drawable │ │ ├── base_solid_stroke_corner.xml │ │ ├── ic_back.xml │ │ ├── ic_loading_bg.9.png │ │ └── web_progress.xml │ │ ├── layout │ │ ├── activity_base.xml │ │ ├── common_base_error.xml │ │ ├── common_base_loading.xml │ │ ├── common_head_layout.xml │ │ ├── common_progress_dialog.xml │ │ └── fragment_base.xml │ │ └── values │ │ ├── colors.xml │ │ ├── string.xml │ │ └── styles.xml │ └── test │ └── java │ └── com │ └── wsg │ └── base │ └── ExampleUnitTest.kt ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/caches 5 | /.idea/libraries 6 | /.idea/modules.xml 7 | /.idea/workspace.xml 8 | /.idea/navEditor.xml 9 | /.idea/assetWizardSettings.xml 10 | .DS_Store 11 | /build 12 | /captures 13 | .externalNativeBuild 14 | .cxx 15 | -------------------------------------------------------------------------------- /.idea/codeStyles/codeStyleConfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | -------------------------------------------------------------------------------- /.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 22 | 23 | -------------------------------------------------------------------------------- /.idea/jarRepositories.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | 10 | 14 | 15 | 19 | 20 | 24 | 25 | 29 | 30 | 34 | 35 | 39 | 40 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 14 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 纯kotlin+ViewModel+LiveData+协程MVVM 2 | 3 | MVVM大家都了解差不多了,但是我发现MVVM整成架构时,每个人的写法真的是千差万别。
4 | 5 | 除了MVVM必要的ViewModel、LiveData,其它写法也没有统一的标准,看下来写法特别多,jetpack、kotlin、java、databinding、rxjava、协程、操作符等等各种混用,甚至还有把mvp的presenter当vm使用的,有的项目混用的多了看起来真的很不直观,没法用到实际项目中。 6 | 7 | ## 纯kotlin+ViewModel+LiveData+协程 8 | 那就自己写一个简单的纯净版mvvm,不用jetpack、databinding、rxjava、晦涩的操作符等。同时也练习一下kotlin各种高阶函数、扩展、新特性等。git地址[https://github.com/wushaoge/WsgMvvm](https://github.com/wushaoge/WsgMvvm) 9 | 10 | ## 屏幕截图 11 | 12 | 13 | 14 | ## 主要功能 15 | * 封装统一Base基类,加载页、错误页 16 | * ViewModel和LiveData扩展 17 | * 常用各种扩展 18 | * 网络请求+协程回调,封装统一的onAppLoading 、onAppSuccess、onAppError、onAppComplete回调 19 | * 网络框架使用的Rxhttp [https://github.com/liujingxing/okhttp-RxHttp](https://github.com/liujingxing/okhttp-RxHttp) 20 | * 图片框架使用的coli[https://github.com/coil-kt/coil](https://github.com/coil-kt/coil) 21 | * 发现界面拷贝eyepetizer项目 22 | * 新建项目可以以base module作为依赖 23 | 24 | ## 参考项目 25 | [https://github.com/Reginer/MVVMHub](https://github.com/Reginer/MVVMHub) 26 | [https://www.pgyer.com/eyepetizer](https://www.pgyer.com/eyepetizer) 27 | 这两个项目强烈建议多学习 28 | 29 | 30 | 31 | ## License 32 | 33 | **所有数据来源于开眼,仅供学习和交流使用,严禁用于任何商业用途,原作公司拥有所有权利。** 34 | 35 | ``` 36 | Copyright (c) 2020. vipyinzhiwei 37 | 38 | Licensed under the Apache License, Version 2.0 (the "License"); 39 | you may not use this file except in compliance with the License. 40 | You may obtain a copy of the License at 41 | 42 | http://www.apache.org/licenses/LICENSE-2.0 43 | 44 | Unless required by applicable law or agreed to in writing, software 45 | distributed under the License is distributed on an "AS IS" BASIS, 46 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 47 | See the License for the specific language governing permissions and 48 | limitations under the License. 49 | ``` 50 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /app/__bus__.json: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | apply plugin: 'kotlin-android' 3 | apply plugin: 'kotlin-android-extensions' 4 | apply plugin: 'kotlin-kapt' 5 | apply plugin: "com.blankj.bus" 6 | 7 | android { 8 | compileSdkVersion 29 9 | buildToolsVersion "29.0.3" 10 | 11 | defaultConfig { 12 | applicationId "com.wsg.up" 13 | minSdkVersion 26 14 | targetSdkVersion 29 15 | versionCode 1 16 | versionName "1.0" 17 | 18 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 19 | multiDexEnabled true 20 | vectorDrawables.useSupportLibrary = true 21 | javaCompileOptions { 22 | annotationProcessorOptions { 23 | arguments = [ 24 | rxhttp_okhttp: '4.7.2', 25 | // rxhttp_rxjava: 'rxjava2', //告知RxHttp你依赖的rxjava版本,可传入rxjava2、rxjava3 26 | rxhttp_package: 'rxhttp' //指定RxHttp相关类的生成路径,即包名 27 | ] 28 | includeCompileClasspath = true 29 | } 30 | } 31 | } 32 | signingConfigs { 33 | config { 34 | 35 | } 36 | } 37 | 38 | buildTypes { 39 | debug { 40 | minifyEnabled false 41 | // signingConfig signingConfigs.config 42 | debuggable true 43 | } 44 | release { 45 | minifyEnabled true 46 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 47 | } 48 | } 49 | 50 | compileOptions { 51 | sourceCompatibility JavaVersion.VERSION_1_8 52 | targetCompatibility JavaVersion.VERSION_1_8 53 | } 54 | 55 | kotlinOptions { 56 | jvmTarget = "1.8" 57 | } 58 | 59 | androidExtensions { 60 | experimental = true 61 | } 62 | } 63 | 64 | 65 | 66 | dependencies { 67 | implementation fileTree(dir: "libs", include: ["*.jar"]) 68 | testImplementation 'junit:junit:4.12' 69 | androidTestImplementation 'androidx.test.ext:junit:1.1.1' 70 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' 71 | kapt 'com.ljx.rxhttp:rxhttp-compiler:2.2.8' //Rxhttp注解类 72 | implementation project(path: ':base') 73 | 74 | //播放器 75 | implementation 'com.shuyu:GSYVideoPlayer:7.1.5' 76 | //PhotoView 77 | implementation 'com.github.chrisbanes:PhotoView:2.3.0' 78 | } -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | 23 | #手动启用support keep注解 24 | #http://tools.android.com/tech-docs/support-annotations 25 | -dontskipnonpubliclibraryclassmembers 26 | -printconfiguration 27 | -keep,allowobfuscation @interface androidx.annotation.Keep 28 | 29 | -keep @androidx.annotation.Keep class * 30 | -keepclassmembers class * { 31 | @androidx.annotation.Keep *; 32 | } -------------------------------------------------------------------------------- /app/src/androidTest/java/com/wsg/up/ExampleInstrumentedTest.kt: -------------------------------------------------------------------------------- 1 | package com.wsg.up 2 | 3 | import androidx.test.platform.app.InstrumentationRegistry 4 | import androidx.test.ext.junit.runners.AndroidJUnit4 5 | 6 | import org.junit.Test 7 | import org.junit.runner.RunWith 8 | 9 | import org.junit.Assert.* 10 | 11 | /** 12 | * Instrumented test, which will execute on an Android device. 13 | * 14 | * See [testing documentation](http://d.android.com/tools/testing). 15 | */ 16 | @RunWith(AndroidJUnit4::class) 17 | class ExampleInstrumentedTest { 18 | @Test 19 | fun useAppContext() { 20 | // Context of the app under test. 21 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext 22 | assertEquals("com.wsg.up", appContext.packageName) 23 | } 24 | } -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 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 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 61 | 62 | 63 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | -------------------------------------------------------------------------------- /app/src/main/assets/fonts/acfun.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wushaoge/WsgMvvm/d5c8722ecc013f17ae8a7d0419abb6daec8c7def/app/src/main/assets/fonts/acfun.ttf -------------------------------------------------------------------------------- /app/src/main/assets/fonts/eye.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wushaoge/WsgMvvm/d5c8722ecc013f17ae8a7d0419abb6daec8c7def/app/src/main/assets/fonts/eye.ttf -------------------------------------------------------------------------------- /app/src/main/java/com/wsg/up/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.wsg.up 2 | 3 | import android.view.KeyEvent 4 | import android.view.View 5 | import androidx.viewpager.widget.ViewPager 6 | import com.blankj.utilcode.util.ToastUtils 7 | import com.wsg.up.application.MyApplication 8 | import com.wsg.up.entity.BottomResourceData 9 | import com.wsg.up.ui.activity.base.MyBaseActivity 10 | import com.wsg.up.ui.adapter.HomePagerAdapter 11 | import com.wsg.up.ui.fragment.FindFragment 12 | import com.wsg.up.ui.fragment.HomeFragment 13 | import com.wsg.up.ui.fragment.base.MyBaseFragment 14 | import com.wsg.up.utils.TablayoutUtils 15 | import kotlinx.android.synthetic.main.activity_main.* 16 | 17 | class MainActivity : MyBaseActivity() { 18 | 19 | override fun isShowLoading(): Boolean { 20 | return false 21 | } 22 | 23 | override fun getChildTitle(): String? { 24 | return "首页" 25 | } 26 | 27 | override fun getLayoutID(): Int { 28 | return R.layout.activity_main 29 | } 30 | 31 | override fun initViewModel() { 32 | 33 | } 34 | 35 | override fun initView() { 36 | 37 | setBackInVisible() 38 | 39 | var bottomList = ArrayList() 40 | bottomList.add(BottomResourceData("首页", R.drawable.ic_xiaohuolong, R.drawable.ic_xiaohuolong_uncheck)) 41 | bottomList.add(BottomResourceData("发现", R.drawable.ic_pikaqiu, R.drawable.ic_pikaqiu_uncheck)) 42 | // bottomList.add(BottomResourceData("ACFUN", R.drawable.ic_menghuan, R.drawable.ic_menghuan_uncheck)) 43 | // bottomList.add(BottomResourceData("ACFUN", R.drawable.ic_kabi, R.drawable.ic_kabi_uncheck)) 44 | 45 | val mFragmentList = ArrayList() 46 | HomeFragment.newInstance("")?.let { mFragmentList.add(it) } 47 | FindFragment.newInstance("")?.let { mFragmentList.add(it) } 48 | // ChannelFragment.newInstance("")?.let { mFragmentList.add(it) } 49 | // ChannelFragment.newInstance("")?.let { mFragmentList.add(it) } 50 | 51 | vp_content.addOnPageChangeListener(object: ViewPager.OnPageChangeListener{ 52 | override fun onPageScrollStateChanged(state: Int) { 53 | } 54 | 55 | override fun onPageScrolled( 56 | position: Int, 57 | positionOffset: Float, 58 | positionOffsetPixels: Int 59 | ) { 60 | } 61 | 62 | override fun onPageSelected(position: Int) { 63 | setTitle(bottomList[position].getTitle()) 64 | } 65 | }) 66 | 67 | vp_content.adapter = HomePagerAdapter(supportFragmentManager, mFragmentList) 68 | vp_content.offscreenPageLimit = mFragmentList.size 69 | tl_tablayout.setupWithViewPager(vp_content) 70 | //重新设置布局 71 | TablayoutUtils.setHomeTablayoutCustomView(mContext, tl_tablayout, bottomList) 72 | 73 | } 74 | 75 | override fun initData() { 76 | 77 | } 78 | 79 | 80 | override fun initMainNetData() { 81 | 82 | } 83 | 84 | 85 | override fun onClick(v: View?) { 86 | 87 | } 88 | 89 | 90 | /** 91 | * 返回按键点击间隔 92 | */ 93 | private var exitTime = 0L 94 | 95 | override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean { 96 | if (keyCode == KeyEvent.KEYCODE_BACK) { 97 | if (System.currentTimeMillis() - exitTime > 2000) { 98 | exitTime = System.currentTimeMillis() 99 | ToastUtils.showLong("再按一次退出" + getString(R.string.app_name)) 100 | } else { 101 | MyApplication.appExit() 102 | return super.onKeyDown(keyCode, event) 103 | } 104 | return true 105 | } 106 | return super.onKeyDown(keyCode, event) 107 | } 108 | 109 | 110 | } -------------------------------------------------------------------------------- /app/src/main/java/com/wsg/up/entity/BottomResourceData.kt: -------------------------------------------------------------------------------- 1 | package com.wsg.up.entity 2 | 3 | /** 4 | * ================================================ 5 | * 作 者:wushaoge 6 | * 版 本:1.0 7 | * 创建日期:2020-07-27 16:22 8 | * 描 述: 9 | * 修订历史: 10 | * ================================================ 11 | */ 12 | class BottomResourceData(title: String, resouce: Int, uncheckResouce: Int){ 13 | var getTitle: () -> String = { title } 14 | var getResource:() -> Int = { resouce } 15 | var getUnCheckResource:() -> Int = { uncheckResouce } 16 | } -------------------------------------------------------------------------------- /app/src/main/java/com/wsg/up/entity/DataBase.kt: -------------------------------------------------------------------------------- 1 | package com.wsg.up.entity 2 | 3 | import android.os.Parcelable 4 | import androidx.annotation.Keep 5 | import com.wsg.base.common.toJsonString 6 | import kotlinx.android.parcel.Parcelize 7 | 8 | /** 9 | * ================================================ 10 | * 作 者:wushaoge 11 | * 版 本:1.0 12 | * 创建日期:2020-07-23 09:47 13 | * 描 述:玩安卓响应实体类 14 | * 修订历史: 15 | * ================================================ 16 | */ 17 | @Keep 18 | @Parcelize 19 | data class ArticleData( 20 | val `data`: Data, 21 | val errorCode: Int, 22 | val errorMsg: String 23 | ) : Parcelable { 24 | override fun toString(): String { 25 | return this.toJsonString() 26 | } 27 | } 28 | @Keep 29 | @Parcelize 30 | data class Data( 31 | val curPage: Int, 32 | val datas: List, 33 | val offset: Int, 34 | val over: Boolean, 35 | val pageCount: Int, 36 | val size: Int, 37 | val total: Int 38 | ) : Parcelable { 39 | override fun toString(): String { 40 | return this.toJsonString() 41 | } 42 | } 43 | @Keep 44 | @Parcelize 45 | data class Datas( 46 | val apkLink: String, 47 | val audit: Int, 48 | val author: String, 49 | val canEdit: Boolean, 50 | val chapterId: Int, 51 | val chapterName: String, 52 | val collect: Boolean, 53 | val courseId: Int, 54 | val desc: String, 55 | val descMd: String, 56 | val envelopePic: String, 57 | val fresh: Boolean, 58 | val id: Int, 59 | val link: String, 60 | val niceDate: String, 61 | val niceShareDate: String, 62 | val origin: String, 63 | val prefix: String, 64 | val projectLink: String, 65 | val publishTime: Long, 66 | val realSuperChapterId: Int, 67 | val selfVisible: Int, 68 | val shareDate: Long, 69 | val shareUser: String, 70 | val superChapterId: Int, 71 | val superChapterName: String, 72 | val tags: List, 73 | val title: String, 74 | val type: Int, 75 | val userId: Int, 76 | val visible: Int, 77 | val zan: Int 78 | ) : Parcelable { 79 | override fun toString(): String { 80 | return this.toJsonString() 81 | } 82 | } 83 | @Keep 84 | @Parcelize 85 | data class Tag( 86 | val name: String, 87 | val url: String 88 | ) : Parcelable 89 | 90 | @Keep 91 | @Parcelize 92 | data class BannerData( 93 | val `data`: List, 94 | val errorCode: Int, 95 | val errorMsg: String 96 | ) : Parcelable 97 | 98 | @Keep 99 | @Parcelize 100 | data class BannerChildData( 101 | val desc: String, 102 | val id: Int, 103 | val imagePath: String, 104 | val isVisible: Int, 105 | val order: Int, 106 | val title: String, 107 | val type: Int, 108 | val url: String 109 | ) : Parcelable 110 | 111 | 112 | 113 | 114 | 115 | -------------------------------------------------------------------------------- /app/src/main/java/com/wsg/up/ext/DialogExt.kt: -------------------------------------------------------------------------------- 1 | package com.wsg.up.ext 2 | 3 | import android.content.Context 4 | import com.wsg.base.ui.dialog.MyProgressDialog 5 | import com.wsg.up.ui.view.dialog.MyConfirmDialog 6 | 7 | /** 8 | * ================================================ 9 | * 作 者:wushaoge 10 | * 版 本:1.0 11 | * 创建日期:2020-08-06 11:16 12 | * 描 述: 13 | * 修订历史: 14 | * ================================================ 15 | */ 16 | fun Context.showProgressDialog(progressDialog: MyProgressDialog.() -> Unit){ 17 | val myProgressDialog = MyProgressDialog(this) 18 | myProgressDialog.apply(progressDialog) 19 | myProgressDialog.show() 20 | } 21 | 22 | fun Context.showConfirmDialog(setting: ConfirmDialogCallBackClick.() -> Unit){ 23 | val dialog = MyConfirmDialog(this) 24 | ConfirmDialogCallBackClick(dialog).apply(setting) 25 | dialog.show() 26 | } 27 | 28 | class ConfirmDialogCallBackClick(dialog: MyConfirmDialog){ 29 | var dialog = dialog 30 | 31 | var content = "" 32 | set(value) {dialog.setContent(value)} 33 | 34 | fun onOkClick(okClick: () -> Unit){ 35 | dialog.setOkClick(okClick) 36 | } 37 | 38 | fun onCancelClick(cancelClick: () -> Unit){ 39 | dialog.setCancel { cancelClick() } 40 | } 41 | 42 | fun title(title:() -> String){ 43 | dialog.setTitle(title()) 44 | } 45 | 46 | 47 | } -------------------------------------------------------------------------------- /app/src/main/java/com/wsg/up/ext/TabLayoutExt.kt: -------------------------------------------------------------------------------- 1 | package com.wsg.up.ext 2 | 3 | import com.google.android.material.tabs.TabLayout 4 | 5 | /** 6 | * ================================================ 7 | * 作 者:wushaoge 8 | * 版 本:1.0 9 | * 创建日期:2020-07-30 16:07 10 | * 描 述: 11 | * 修订历史: 12 | * ================================================ 13 | */ 14 | //封装 15 | fun TabLayout.onTabSelected(tabSelect: TabSelect.() -> Unit) { 16 | //以下四种方式是等价的 17 | 18 | //第一种 19 | // tabSelect.invoke(TabSelect(this)) 20 | // 21 | // //第二种 22 | // tabSelect(TabSelect(this)) 23 | // 24 | // //第三种 25 | // val mTabSelect = TabSelect(this) 26 | // mTabSelect.apply(tabSelect) //第三种(写法1) 27 | // mTabSelect.tabSelect() //第三种(写法2) 28 | 29 | //第四种 30 | TabSelect(this).tabSelect() 31 | } 32 | 33 | class TabSelect(tab: TabLayout) { 34 | private var tabReselected: ((tab: TabLayout.Tab) -> Unit)? = null 35 | private var tabUnselected: ((tab: TabLayout.Tab) -> Unit)? = null 36 | private var tabSelected: ((tab: TabLayout.Tab) -> Unit)? = null 37 | 38 | fun onTabReselected(tabReselected: (TabLayout.Tab.() -> Unit)) { 39 | this.tabReselected = tabReselected 40 | } 41 | 42 | fun onTabUnselected(tabUnselected: (TabLayout.Tab.() -> Unit)) { 43 | this.tabUnselected = tabUnselected 44 | } 45 | 46 | fun onTabSelected(tabSelected: (TabLayout.Tab.() -> Unit)) { 47 | this.tabSelected = tabSelected 48 | } 49 | 50 | init { 51 | tab.addOnTabSelectedListener(object : TabLayout.OnTabSelectedListener { 52 | override fun onTabReselected(tab: TabLayout.Tab?) { 53 | tab?.apply { tabReselected?.invoke(tab) } 54 | } 55 | override fun onTabUnselected(tab: TabLayout.Tab?) { 56 | tab?.apply { tabUnselected?.invoke(tab) } 57 | } 58 | override fun onTabSelected(tab: TabLayout.Tab?) { 59 | tab?.apply { tabSelected?.invoke(tab) } 60 | } 61 | 62 | }) 63 | } 64 | } -------------------------------------------------------------------------------- /app/src/main/java/com/wsg/up/ext/TextViewExt.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020. vipyinzhiwei 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.wsg.up.ext 18 | 19 | import android.graphics.drawable.Drawable 20 | import android.widget.TextView 21 | import com.wsg.base.ext.dp2px 22 | 23 | /** 24 | * 设置TextView图标 25 | * 26 | * @param drawable 图标 27 | * @param iconWidth 图标宽dp:默认自动根据图标大小 28 | * @param iconHeight 图标高dp:默认自动根据图标大小 29 | * @param direction 图标方向,0左 1上 2右 3下 默认图标位于左侧0 30 | */ 31 | fun TextView.setDrawable(drawable: Drawable?, iconWidth: Float? = null, iconHeight: Float? = null, direction: Int = 0) { 32 | if (iconWidth != null && iconHeight != null) { 33 | //第一个0是距左边距离,第二个0是距上边距离,iconWidth、iconHeight 分别是长宽 34 | drawable?.setBounds(0, 0, dp2px(iconWidth), dp2px(iconHeight)) 35 | } 36 | when (direction) { 37 | 0 -> setCompoundDrawables(drawable, null, null, null) 38 | 1 -> setCompoundDrawables(null, drawable, null, null) 39 | 2 -> setCompoundDrawables(null, null, drawable, null) 40 | 3 -> setCompoundDrawables(null, null, null, drawable) 41 | else -> throw NoSuchMethodError() 42 | } 43 | } 44 | 45 | /** 46 | * 设置TextView图标 47 | * 48 | * @param lDrawable 左边图标 49 | * @param rDrawable 右边图标 50 | * @param lIconWidth 图标宽dp:默认自动根据图标大小 51 | * @param lIconHeight 图标高dp:默认自动根据图标大小 52 | * @param rIconWidth 图标宽dp:默认自动根据图标大小 53 | * @param rIconHeight 图标高dp:默认自动根据图标大小 54 | */ 55 | fun TextView.setDrawables(lDrawable: Drawable?, rDrawable: Drawable?, lIconWidth: Float? = null, lIconHeight: Float? = null, rIconWidth: Float? = null, rIconHeight: Float? = null) { 56 | if (lIconWidth != null && lIconHeight != null) { 57 | lDrawable?.setBounds(0, 0, dp2px(lIconWidth), dp2px(lIconHeight)) 58 | } 59 | if (rIconWidth != null && rIconHeight != null) { 60 | rDrawable?.setBounds(0, 0, dp2px(rIconWidth), dp2px(rIconHeight)) 61 | } 62 | setCompoundDrawables(lDrawable, null, rDrawable, null) 63 | } -------------------------------------------------------------------------------- /app/src/main/java/com/wsg/up/ext/ViewExt.kt: -------------------------------------------------------------------------------- 1 | package com.wsg.up.ext 2 | 3 | import android.view.View 4 | import android.view.animation.AlphaAnimation 5 | 6 | /** 7 | * ================================================ 8 | * 作 者:wushaoge 9 | * 版 本:1.0 10 | * 创建日期:2020-08-18 15:26 11 | * 描 述: 12 | * 修订历史: 13 | * ================================================ 14 | */ 15 | 16 | /** 17 | * 显示view 18 | */ 19 | fun View?.visible() { 20 | this?.visibility = View.VISIBLE 21 | } 22 | 23 | /** 24 | * 占位隐藏view 25 | */ 26 | fun View?.invisible() { 27 | this?.visibility = View.INVISIBLE 28 | } 29 | 30 | /** 31 | * 隐藏view 32 | */ 33 | fun View?.gone() { 34 | this?.visibility = View.GONE 35 | } 36 | 37 | 38 | /** 39 | * 显示view,带有渐显动画效果。 40 | * 41 | * @param duration 毫秒,动画持续时长,默认500毫秒。 42 | */ 43 | fun View?.visibleAlphaAnimation(duration: Long = 500L) { 44 | this?.visibility = View.VISIBLE 45 | this?.startAnimation(AlphaAnimation(0f, 1f).apply { 46 | this.duration = duration 47 | fillAfter = true 48 | }) 49 | } 50 | 51 | /** 52 | * 占位隐藏view,带有渐隐动画效果。 53 | * 54 | * @param duration 毫秒,动画持续时长,默认500毫秒。 55 | */ 56 | fun View?.invisibleAlphaAnimation(duration: Long = 500L) { 57 | this?.visibility = View.INVISIBLE 58 | this?.startAnimation(AlphaAnimation(1f, 0f).apply { 59 | this.duration = duration 60 | fillAfter = true 61 | }) 62 | } -------------------------------------------------------------------------------- /app/src/main/java/com/wsg/up/repository/EyeRepository.kt: -------------------------------------------------------------------------------- 1 | package com.wsg.up.repository 2 | 3 | import com.wsg.base.entity.BaseData 4 | import com.wsg.up.entity.RecommendData 5 | import com.wsg.up.utils.Constants 6 | import rxhttp.RxHttp 7 | import rxhttp.toClass 8 | import java.net.ConnectException 9 | 10 | /** 11 | * ================================================ 12 | * 作 者:wushaoge 13 | * 版 本:1.0 14 | * 创建日期:2020-07-23 09:44 15 | * 描 述: 16 | * 修订历史: 17 | * ================================================ 18 | */ 19 | class EyeRepository { 20 | 21 | suspend fun getCommunityData(url: String): BaseData { 22 | val data = RxHttp.get(url) 23 | .toClass() 24 | .await() 25 | ?: throw ConnectException() 26 | 27 | //为null说明后端错误 28 | return BaseData(200, "", data) 29 | } 30 | 31 | 32 | suspend fun onRefresh(): BaseData = getCommunityData(Constants.EYE_COMMUNITY) 33 | 34 | suspend fun loadMore(url: String): BaseData = getCommunityData(url) 35 | } -------------------------------------------------------------------------------- /app/src/main/java/com/wsg/up/repository/WanAndroidRepository.kt: -------------------------------------------------------------------------------- 1 | package com.wsg.up.repository 2 | 3 | import com.wsg.base.entity.BaseData 4 | import com.wsg.up.entity.ArticleData 5 | import com.wsg.up.entity.BannerData 6 | import com.wsg.up.utils.Constants 7 | import rxhttp.RxHttp 8 | import rxhttp.toClass 9 | import java.net.ConnectException 10 | 11 | /** 12 | * ================================================ 13 | * 作 者:wushaoge 14 | * 版 本:1.0 15 | * 创建日期:2020-07-23 09:44 16 | * 描 述: 17 | * 修订历史: 18 | * ================================================ 19 | */ 20 | class WanAndroidRepository { 21 | 22 | suspend fun getArticle(page: Int): BaseData { 23 | var url = Constants.WAN_ARTICLE + page + "/json" 24 | // url = "http://gank.io/api/random/data/福利/20" 25 | 26 | val data = RxHttp.get(url) 27 | .toClass() 28 | .await() 29 | ?: throw ConnectException() 30 | //为null说明后端错误 31 | return BaseData(200, "", data) 32 | } 33 | 34 | suspend fun getBanner(): BaseData { 35 | var url = Constants.WAN_BANNER + "/json" 36 | 37 | var data = RxHttp.get(url) 38 | .toClass() 39 | .await() 40 | ?: throw ConnectException() 41 | 42 | return BaseData(200, "", data) 43 | } 44 | 45 | } -------------------------------------------------------------------------------- /app/src/main/java/com/wsg/up/ui/activity/SplashActivity.kt: -------------------------------------------------------------------------------- 1 | package com.wsg.up.ui.activity 2 | 3 | import android.Manifest 4 | import android.view.View 5 | import android.view.WindowManager 6 | import com.permissionx.guolindev.PermissionX 7 | import com.wsg.base.ext.setViewsOnClickListener 8 | import com.wsg.base.ext.showToast 9 | import com.wsg.base.ext.startActivity 10 | import com.wsg.up.MainActivity 11 | import com.wsg.up.R 12 | import com.wsg.up.ui.activity.base.MyBaseActivity 13 | import kotlinx.android.synthetic.main.activity_splash.* 14 | 15 | /** 16 | * ================================================ 17 | * 作 者:wushaoge 18 | * 版 本:1.0 19 | * 创建日期:2020-07-29 15:33 20 | * 描 述: 21 | * 修订历史: 22 | * ================================================ 23 | */ 24 | class SplashActivity: MyBaseActivity() { 25 | 26 | 27 | override fun getChildTitle(): String? { 28 | return null 29 | } 30 | 31 | override fun setContentBefore() { 32 | window.setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN) 33 | } 34 | 35 | override fun getLayoutID(): Int { 36 | return R.layout.activity_splash 37 | } 38 | 39 | override fun initViewModel() { 40 | } 41 | 42 | override fun initView() { 43 | setHeadGone() 44 | 45 | setViewsOnClickListener(this, ll_skip) 46 | 47 | //申请权限 48 | checkPermissions() 49 | } 50 | 51 | fun checkPermissions() { 52 | 53 | PermissionX.init(this@SplashActivity).permissions(Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_PHONE_STATE) 54 | .onForwardToSettings { scope, deniedList -> 55 | showToast("请授予相关权限") 56 | } 57 | .request { allGranted, grantedList, deniedList -> 58 | // if (allGranted) { 59 | // showToast("所有申请的权限都已通过") 60 | // } else { 61 | // showToast("您拒绝了如下权限:$deniedList") 62 | // } 63 | lottie_view.playAnimation() 64 | } 65 | } 66 | 67 | override fun initData() { 68 | val list = mutableListOf( 69 | "pride-hard-seltzer.json", 70 | "lamsa-splash-screen.json", 71 | "ramadan-kareem-hello-doc.json", 72 | "logo-animation.json" 73 | ) 74 | 75 | lottie_view.setAnimation(list.random()) 76 | lottie_view.addAnimatorUpdateListener { 77 | if(it.animatedFraction == 1f) startActivity() 78 | } 79 | } 80 | 81 | override fun initMainNetData() { 82 | 83 | } 84 | 85 | override fun onClick(v: View?) { 86 | when (v) { 87 | ll_skip -> { 88 | lottie_view.removeAllUpdateListeners() 89 | startActivity() 90 | } 91 | } 92 | } 93 | } -------------------------------------------------------------------------------- /app/src/main/java/com/wsg/up/ui/activity/Test2Activity.kt: -------------------------------------------------------------------------------- 1 | package com.wsg.up.ui.activity 2 | 3 | import android.view.View 4 | import androidx.lifecycle.ViewModelProvider 5 | import androidx.lifecycle.lifecycleScope 6 | import androidx.lifecycle.rxLifeScope 7 | import com.blankj.utilcode.util.LogUtils 8 | import com.wsg.base.common.toJsonString 9 | import com.wsg.base.ext.setViewsOnClickListener 10 | import com.wsg.base.ext.vmObserverLoading 11 | import com.wsg.base.state.VmResult 12 | import com.wsg.up.R 13 | import com.wsg.up.entity.ArticleData 14 | import com.wsg.up.repository.WanAndroidRepository 15 | import com.wsg.up.ui.activity.base.MyBaseActivity 16 | import com.wsg.up.utils.Constants 17 | import com.wsg.up.viewmodel.WanAndroidViewModel 18 | import kotlinx.android.synthetic.main.activity_main2.* 19 | import kotlinx.coroutines.MainScope 20 | import kotlinx.coroutines.launch 21 | import rxhttp.RxHttp 22 | import rxhttp.toClass 23 | 24 | class MainActivity2 : MyBaseActivity() { 25 | 26 | lateinit var mViewModel: WanAndroidViewModel 27 | 28 | 29 | override fun isShowLoading(): Boolean { 30 | return false 31 | } 32 | 33 | override fun getChildTitle(): String? { 34 | return "首页" 35 | } 36 | 37 | override fun getLayoutID(): Int { 38 | return R.layout.activity_main2 39 | } 40 | 41 | override fun initViewModel() { 42 | } 43 | 44 | override fun initView() { 45 | mViewModel = ViewModelProvider(this).get(WanAndroidViewModel::class.java) 46 | 47 | setViewsOnClickListener(this, tv_test) 48 | 49 | //以下是瞎鸡儿写的 50 | //kotlin internal 关键字使用 51 | lifecycleScope.launch { 52 | 53 | } 54 | MainScope().launch { 55 | 56 | } 57 | 58 | } 59 | 60 | override fun initData() { 61 | } 62 | 63 | override fun initMainNetData() { 64 | val result = VmResult() 65 | result.onAppLoading = { 66 | showLoadingDialog() 67 | LogUtils.e("开始2") 68 | } 69 | 70 | result.onAppSuccess = { 71 | LogUtils.json(it) 72 | } 73 | 74 | result.onAppError = { 75 | LogUtils.e(it.message) 76 | } 77 | 78 | result.onAppComplete = { 79 | dismissLoadingDialog() 80 | LogUtils.e("完成2") 81 | } 82 | 83 | // mViewModel.articleData.vmObserver2(this, result) 84 | // 85 | // mViewModel.articleData.vmObserver(this){ 86 | // onAppLoading = { showLoadingDialog(); LogUtils.e("开始") } 87 | // onAppSuccess = { LogUtils.json(it) } 88 | // onAppError = { 89 | // LogUtils.e(it.parseErrorString()) 90 | // LogUtils.e(it.javaClass.typeName) 91 | // LogUtils.e(it.toString()) 92 | // LogUtils.e(it.errorMsg) 93 | // } 94 | // onAppComplete = { dismissLoadingDialog(); LogUtils.e("完成") } 95 | // } 96 | 97 | mViewModel.articleData.vmObserverLoading(this){ 98 | LogUtils.json(it) 99 | } 100 | 101 | val job = rxLifeScope.launch { 102 | WanAndroidRepository().getArticle(1) 103 | } 104 | 105 | // job.cancel() 106 | 107 | rxLifeScope.launch({ 108 | //协程代码块,运行在UI线程 109 | var url = Constants.WAN_ARTICLE + "1/json" 110 | 111 | url = "http://gank.io/api/random/data/福利/20" 112 | 113 | // url = "http://www.sdf.com" 114 | 115 | val data = RxHttp.get(url) 116 | .toClass() 117 | .await() 118 | //可直接更新UI 119 | LogUtils.e(data.toJsonString()) 120 | // throw JsonSyntaxException("json错误") 121 | }, { 122 | //异常回调,这里可以拿到Throwable对象 123 | LogUtils.e(it.message) 124 | LogUtils.e(it.javaClass.typeName) 125 | // LogUtils.e(it.parseErrorString()) 126 | }, { 127 | //开始回调,可以开启等待弹窗,运行在UI线程 128 | LogUtils.e("开始3") 129 | }, { 130 | //结束回调,可以销毁等待弹窗,运行在UI线程 131 | LogUtils.e("完成3") 132 | }) 133 | 134 | 135 | 136 | test { 137 | v2 = "2333" 138 | } 139 | test2(View2()) 140 | } 141 | 142 | 143 | override fun onClick(v: View?) { 144 | when (v) { 145 | tv_test -> { 146 | mViewModel.getArticleData(1) 147 | } 148 | 149 | } 150 | } 151 | 152 | 153 | fun test(init: View2.() -> Unit){ 154 | init(View2()) 155 | val t = View2() 156 | t.apply(init) 157 | t.a() 158 | } 159 | 160 | fun test2(init: View2){ 161 | init.a() 162 | } 163 | 164 | } 165 | 166 | class View2{ 167 | var v2: String = "" 168 | 169 | public fun a(){ 170 | 171 | } 172 | } -------------------------------------------------------------------------------- /app/src/main/java/com/wsg/up/ui/activity/TestActivity.kt: -------------------------------------------------------------------------------- 1 | package com.wsg.up.ui.activity 2 | 3 | import android.os.Bundle 4 | import android.view.View 5 | import com.blankj.utilcode.util.LogUtils 6 | import com.wsg.up.R 7 | import com.wsg.up.entity.RecommendItem 8 | import com.wsg.up.entity.Tag 9 | import com.wsg.up.ui.activity.base.MyBaseActivity 10 | 11 | /** 12 | * ================================================ 13 | * 作 者:wushaoge 14 | * 版 本:1.0 15 | * 创建日期:2020-08-27 10:24 16 | * 描 述: 17 | * 修订历史: 18 | * ================================================ 19 | */ 20 | class TestActivity: MyBaseActivity() { 21 | 22 | override fun getChildTitle(): String? { 23 | return "" 24 | } 25 | 26 | override fun getBundleExtras(extras: Bundle?) { 27 | val tag: Tag? = extras!!.getParcelable("tag") 28 | val list: ArrayList? = intent.getParcelableArrayListExtra("data") 29 | val item: RecommendItem? = extras!!.getParcelable("item") 30 | LogUtils.e(tag?.name) 31 | LogUtils.e("${item?.id}水电费") 32 | } 33 | 34 | override fun getLayoutID(): Int { 35 | return R.layout.activity_main 36 | } 37 | 38 | override fun initViewModel() { 39 | } 40 | 41 | override fun initView() { 42 | } 43 | 44 | override fun initData() { 45 | } 46 | 47 | override fun initMainNetData() { 48 | } 49 | 50 | override fun onClick(v: View?) { 51 | } 52 | 53 | 54 | } -------------------------------------------------------------------------------- /app/src/main/java/com/wsg/up/ui/activity/base/MyBaseActivity.kt: -------------------------------------------------------------------------------- 1 | package com.wsg.up.ui.activity.base 2 | 3 | import android.content.Context 4 | import android.os.Bundle 5 | import android.util.AttributeSet 6 | import android.view.LayoutInflater 7 | import android.view.View 8 | import android.widget.TextView 9 | import androidx.core.view.LayoutInflaterCompat 10 | import com.wsg.base.activity.BaseActivity 11 | import com.wsg.base.ui.dialog.MyProgressDialog 12 | import com.wsg.up.utils.TypeFaceUtil 13 | 14 | /** 15 | * ================================================ 16 | * 作 者:wushaoge 17 | * 版 本:1.0 18 | * 创建日期:2020-07-22 15:29 19 | * 描 述: 20 | * 修订历史: 21 | * ================================================ 22 | */ 23 | abstract class MyBaseActivity: BaseActivity() { 24 | 25 | var dialog: MyProgressDialog? = null 26 | 27 | //分页使用 28 | var pageNo = 1 29 | var pageSize = 10 30 | var pageCount = 0 31 | 32 | override fun onCreate(savedInstanceState: Bundle?) { 33 | LayoutInflaterCompat.setFactory2(LayoutInflater.from(this), object: LayoutInflater.Factory2{ 34 | override fun onCreateView( 35 | parent: View?, 36 | name: String, 37 | context: Context, 38 | attrs: AttributeSet 39 | ): View? { 40 | 41 | var view = delegate.createView(parent, name, context, attrs) 42 | if(view != null && view is TextView){ 43 | view.typeface = TypeFaceUtil.getEyeTypeFace() 44 | } 45 | return view 46 | } 47 | 48 | override fun onCreateView(name: String, context: Context, attrs: AttributeSet): View? { 49 | return null 50 | } 51 | }) 52 | 53 | super.onCreate(savedInstanceState) 54 | } 55 | 56 | override fun showLoadingDialog(content: String) { 57 | dialog?:let { 58 | dialog = MyProgressDialog(mContext, content) 59 | } 60 | dialog?.show() 61 | } 62 | 63 | override fun dismissLoadingDialog() { 64 | dialog?.dismiss() 65 | } 66 | } -------------------------------------------------------------------------------- /app/src/main/java/com/wsg/up/ui/activity/common/WebActivity.kt: -------------------------------------------------------------------------------- 1 | package com.wsg.up.ui.activity.common 2 | 3 | import android.os.Bundle 4 | import android.text.TextUtils 5 | import android.view.KeyEvent 6 | import android.view.View 7 | import com.blankj.utilcode.util.LogUtils 8 | import com.tencent.smtt.export.external.interfaces.WebResourceError 9 | import com.tencent.smtt.export.external.interfaces.WebResourceRequest 10 | import com.tencent.smtt.sdk.WebChromeClient 11 | import com.tencent.smtt.sdk.WebView 12 | import com.tencent.smtt.sdk.WebViewClient 13 | import com.wsg.base.state.EBaseViewStatus 14 | import com.wsg.up.R 15 | import com.wsg.up.ui.activity.base.MyBaseActivity 16 | import kotlinx.android.synthetic.main.activity_web.* 17 | 18 | 19 | /** 20 | * ================================================ 21 | * 作 者:wushaoge 22 | * 版 本:1.0 23 | * 创建日期:2020-08-27 10:24 24 | * 描 述: 25 | * 修订历史: 26 | * ================================================ 27 | */ 28 | class WebActivity: MyBaseActivity() { 29 | 30 | var webTitle: String? = "" 31 | var url = "https://www.acfun.cn/" 32 | 33 | var isLoadSuccess = true 34 | 35 | override fun getChildTitle(): String? { 36 | return webTitle 37 | } 38 | 39 | override fun getBundleExtras(extras: Bundle?) { 40 | webTitle = intent.getStringExtra("title") 41 | url = intent.getStringExtra("url") 42 | } 43 | 44 | override fun getLayoutID(): Int { 45 | return R.layout.activity_web 46 | } 47 | 48 | override fun initViewModel() { 49 | } 50 | 51 | override fun initView() { 52 | initProgressBar() 53 | 54 | webTitle?.apply { getString(R.string.app_name) } 55 | 56 | webView.webViewClient = object : WebViewClient() { 57 | // 点击超链接的时候重新在原来进程上加载URL 58 | override fun shouldOverrideUrlLoading(view: WebView, url: String?): Boolean { 59 | LogUtils.e(url) 60 | view.loadUrl(url) 61 | return true 62 | } 63 | 64 | override fun onReceivedError( 65 | webView: WebView?, 66 | webResourceRequest: WebResourceRequest, 67 | webResourceError: WebResourceError? 68 | ) { 69 | super.onReceivedError(webView, webResourceRequest, webResourceError) 70 | LogUtils.e("加载出错!!!") 71 | if (webResourceRequest.isForMainFrame) { 72 | isLoadSuccess = false 73 | webView?.stopLoading() 74 | webView?.loadDataWithBaseURL(null, "", "text/html", "utf-8", null) 75 | showWebViewError() 76 | } 77 | } 78 | 79 | // webview加载完成 80 | override fun onPageFinished(view: WebView, url: String?) { 81 | LogUtils.e("加载完成!!!,isLoadSuccess=$isLoadSuccess") 82 | pb_progress.visibility = View.GONE 83 | if (isLoadSuccess) { 84 | val title: String = view.getTitle() 85 | if (title != null && title != "") { 86 | updateTitle(title) 87 | } 88 | setBaseViewStatus(EBaseViewStatus.SUCCESS) 89 | } else { 90 | showWebViewError() 91 | } 92 | } 93 | } 94 | 95 | webView.webChromeClient = object : WebChromeClient() { 96 | override fun onProgressChanged(view: WebView?, newProgress: Int) { 97 | pb_progress.progress = newProgress 98 | if (newProgress >= 100) { 99 | pb_progress.visibility = View.GONE 100 | } 101 | } 102 | 103 | override fun onReceivedTitle(webView: WebView?, s: String?) { 104 | super.onReceivedTitle(webView, s) 105 | if (!TextUtils.isEmpty(s)) { 106 | updateTitle(s) 107 | } 108 | } 109 | } 110 | 111 | webView.loadUrl(url) 112 | } 113 | 114 | override fun initData() { 115 | } 116 | 117 | override fun initMainNetData() { 118 | 119 | } 120 | 121 | override fun onClick(v: View?) { 122 | } 123 | 124 | override fun backClick() { 125 | if (webView.canGoBack()) { 126 | webView.goBack() 127 | } else { 128 | finish() 129 | } 130 | } 131 | 132 | /** 133 | * 初始化进度条 134 | */ 135 | private fun initProgressBar() { 136 | pb_progress.setMax(100) 137 | pb_progress.setProgressDrawable(resources.getDrawable(R.drawable.web_progress)) 138 | } 139 | 140 | fun updateTitle(title: String?) { 141 | if (isLoadSuccess) { 142 | setTitle(title) 143 | } else { 144 | setTitle(title) 145 | } 146 | } 147 | 148 | fun showWebViewError() { 149 | setBaseViewStatus(EBaseViewStatus.ERROR) 150 | setErrorText("加载网页出错") 151 | } 152 | 153 | /** 154 | * 设置回退 155 | * 覆盖Activity类的onKeyDown(int keyCoder,KeyEvent event)方法 156 | */ 157 | override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean { 158 | if (isLoadSuccess) { 159 | if (keyCode == KeyEvent.KEYCODE_BACK && webView.canGoBack()) { 160 | webView.goBack() // goBack()表示返回WebView的上一页面 161 | return true 162 | } 163 | } else { 164 | finish() 165 | } 166 | return super.onKeyDown(keyCode, event) 167 | } 168 | 169 | } -------------------------------------------------------------------------------- /app/src/main/java/com/wsg/up/ui/activity/ugc/UgcDetailActivity.kt: -------------------------------------------------------------------------------- 1 | package com.wsg.up.ui.activity.ugc 2 | 3 | import android.os.Bundle 4 | import android.view.View 5 | import androidx.viewpager2.widget.ViewPager2 6 | import com.jaeger.library.StatusBarUtil 7 | import com.shuyu.gsyvideoplayer.GSYVideoManager 8 | import com.wsg.up.R 9 | import com.wsg.up.entity.RecommendItem 10 | import com.wsg.up.ui.activity.base.MyBaseActivity 11 | import com.wsg.up.ui.adapter.UgcDetailAdapter 12 | import com.wsg.up.ui.view.listener.AutoPlayPageChangeListener 13 | import kotlinx.android.synthetic.main.activity_ugc_detail.* 14 | 15 | /** 16 | * ================================================ 17 | * 作 者:wushaoge 18 | * 版 本:1.0 19 | * 创建日期:2020-08-27 10:24 20 | * 描 述: 21 | * 修订历史: 22 | * ================================================ 23 | */ 24 | class UgcDetailActivity: MyBaseActivity() { 25 | 26 | private lateinit var adapter: UgcDetailAdapter 27 | 28 | var position = -1 29 | var list: List? = null 30 | 31 | override fun getChildTitle(): String? { 32 | return "详情" 33 | } 34 | 35 | override fun getBundleExtras(extras: Bundle?) { 36 | position = extras!!.getInt("position") 37 | list = extras!!.getParcelableArrayList("data") 38 | } 39 | 40 | override fun getLayoutID(): Int { 41 | return R.layout.activity_ugc_detail 42 | } 43 | 44 | override fun initViewModel() { 45 | } 46 | 47 | override fun initView() { 48 | setHeadGone() 49 | StatusBarUtil.setColor(this, getColor(R.color.black)) 50 | } 51 | 52 | override fun initData() { 53 | 54 | adapter = UgcDetailAdapter(this, list!!) 55 | viewPager.adapter = adapter 56 | viewPager.orientation = ViewPager2.ORIENTATION_VERTICAL 57 | viewPager.offscreenPageLimit = 1 58 | viewPager.registerOnPageChangeCallback(AutoPlayPageChangeListener(viewPager, position, R.id.videoPlayer)) 59 | viewPager.setCurrentItem(position, false) 60 | } 61 | 62 | override fun initMainNetData() { 63 | } 64 | 65 | override fun onClick(v: View?) { 66 | 67 | } 68 | 69 | override fun onPause() { 70 | super.onPause() 71 | GSYVideoManager.onPause() 72 | } 73 | 74 | override fun onResume() { 75 | super.onResume() 76 | GSYVideoManager.onResume() 77 | } 78 | 79 | override fun onDestroy() { 80 | super.onDestroy() 81 | GSYVideoManager.releaseAllVideos() 82 | } 83 | 84 | override fun finish() { 85 | super.finish() 86 | overridePendingTransition(0, R.anim.anl_push_bottom_out) 87 | } 88 | 89 | } -------------------------------------------------------------------------------- /app/src/main/java/com/wsg/up/ui/adapter/ArticleAdapter.kt: -------------------------------------------------------------------------------- 1 | package com.wsg.up.ui.adapter 2 | 3 | import android.content.Context 4 | import com.chad.library.adapter.base.BaseQuickAdapter 5 | import com.chad.library.adapter.base.viewholder.BaseViewHolder 6 | import com.wsg.up.R 7 | import com.wsg.up.entity.Datas 8 | 9 | /** 10 | * ================================================ 11 | * 作 者:wushaoge 12 | * 版 本:1.0 13 | * 创建日期:2018-12-13 17:03 14 | * 描 述: 15 | * 修订历史: 16 | * ================================================ 17 | */ 18 | class ArticleAdapter(private val mContext: Context) : BaseQuickAdapter(R.layout.item_home_article) { 19 | override fun convert( 20 | helper: BaseViewHolder, 21 | item: Datas 22 | ) { 23 | helper.setText(R.id.tv_title, item.title) 24 | helper.setText(R.id.tv_create_time, item.niceDate + " " + item.author) 25 | } 26 | 27 | } -------------------------------------------------------------------------------- /app/src/main/java/com/wsg/up/ui/adapter/BannerAdapter.kt: -------------------------------------------------------------------------------- 1 | package com.wsg.up.ui.adapter 2 | 3 | import android.view.View 4 | import com.wsg.up.R 5 | import com.wsg.up.entity.BannerChildData 6 | import com.zhpan.bannerview.BaseBannerAdapter 7 | import com.zhpan.bannerview.BaseViewHolder 8 | 9 | /** 10 | *
11 |  * Created by zhpan on 2020/4/6.
12 |  * Description:
13 | 
* 14 | */ 15 | class BannerAdapter() : BaseBannerAdapter>() { 16 | 17 | override fun onBind( 18 | holder: BaseViewHolder?, 19 | data: BannerChildData?, 20 | position: Int, 21 | pageSize: Int 22 | ) { 23 | holder!!.bindData(data, position, pageSize) 24 | } 25 | 26 | override fun createViewHolder( 27 | itemView: View?, 28 | viewType: Int 29 | ): BannerViewHolder? { 30 | return BannerViewHolder(itemView!!) 31 | } 32 | 33 | override fun getLayoutId(viewType: Int): Int { 34 | return R.layout.item_banner 35 | } 36 | 37 | 38 | } -------------------------------------------------------------------------------- /app/src/main/java/com/wsg/up/ui/adapter/BannerViewHolder.kt: -------------------------------------------------------------------------------- 1 | package com.wsg.up.ui.adapter 2 | 3 | import android.view.View 4 | import android.widget.ImageView 5 | import coil.api.load 6 | import coil.transform.RoundedCornersTransformation 7 | import com.wsg.up.R 8 | import com.wsg.up.entity.BannerChildData 9 | import com.zhpan.bannerview.BaseViewHolder 10 | 11 | /** 12 | * ================================================ 13 | * 作 者:wushaoge 14 | * 版 本:1.0 15 | * 创建日期:2020年07月30日11:08:53 16 | * 描 述: 17 | * 修订历史: 18 | * ================================================ 19 | */ 20 | class BannerViewHolder(itemView: View) : 21 | BaseViewHolder(itemView) { 22 | 23 | override fun bindData(data: BannerChildData?, position: Int, pageSize: Int) { 24 | val imageView = findView(R.id.banner_image) 25 | imageView.load(data?.imagePath) { 26 | crossfade(true) 27 | transformations(RoundedCornersTransformation(5f)) 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /app/src/main/java/com/wsg/up/ui/adapter/HomePagerAdapter.kt: -------------------------------------------------------------------------------- 1 | package com.wsg.up.ui.adapter 2 | 3 | import android.content.Context 4 | import androidx.annotation.Nullable 5 | import androidx.fragment.app.Fragment 6 | import androidx.fragment.app.FragmentManager 7 | import androidx.fragment.app.FragmentPagerAdapter 8 | import com.wsg.up.ui.fragment.base.MyBaseFragment 9 | 10 | /** 11 | * ================================================ 12 | * 作 者:wushaoge 13 | * 版 本:1.0 14 | * 创建日期:2020-07-27 16:48 15 | * 描 述: 16 | * 修订历史: 17 | * ================================================ 18 | */ 19 | class HomePagerAdapter: FragmentPagerAdapter { 20 | 21 | private var mFragmentList: ArrayList? = null 22 | private var mContext: Context? = null 23 | 24 | constructor( 25 | fm: FragmentManager?, 26 | list: ArrayList 27 | ): super(fm!!, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT){ 28 | mFragmentList = list 29 | } 30 | 31 | constructor( 32 | context: Context?, 33 | fm: FragmentManager?, 34 | list: ArrayList? 35 | ) : super(fm!!, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT){ 36 | mFragmentList = list 37 | mContext = context 38 | } 39 | 40 | override fun getItem(position: Int): Fragment { 41 | return mFragmentList!![position] 42 | } 43 | 44 | override fun getCount(): Int { 45 | return mFragmentList!!.size 46 | } 47 | 48 | @Nullable 49 | override fun getPageTitle(position: Int): CharSequence? { 50 | return mFragmentList!![position].getTitle() 51 | } 52 | 53 | 54 | } -------------------------------------------------------------------------------- /app/src/main/java/com/wsg/up/ui/fragment/ChannelFragment.kt: -------------------------------------------------------------------------------- 1 | package com.wsg.up.ui.fragment 2 | import android.os.Bundle 3 | import android.view.View 4 | import com.wsg.base.ext.setViewsOnClickListener 5 | import com.wsg.base.ext.showToast 6 | import com.wsg.up.R 7 | import com.wsg.up.ext.showConfirmDialog 8 | import com.wsg.up.ext.showProgressDialog 9 | import com.wsg.up.ui.fragment.base.MyBaseFragment 10 | import kotlinx.android.synthetic.main.fragment_channel.* 11 | 12 | 13 | /** 14 | * ================================================ 15 | * 作 者:wushaoge 16 | * 版 本:1.0 17 | * 创建日期:2020-07-27 16:33 18 | * 描 述:测试用可以无视 19 | * 修订历史: 20 | * ================================================ 21 | */ 22 | class ChannelFragment: MyBaseFragment(){ 23 | 24 | companion object{ 25 | fun newInstance(title: String?): ChannelFragment { 26 | val fragment = ChannelFragment() 27 | val args = Bundle() 28 | fragment.setTitle(title) 29 | args.putString("", title) 30 | fragment.arguments = args 31 | return fragment 32 | } 33 | } 34 | 35 | override fun getLayoutID(): Int { 36 | return R.layout.fragment_channel 37 | } 38 | 39 | override fun initViewModel() { 40 | 41 | } 42 | 43 | override fun initView() { 44 | setViewsOnClickListener(this, ll_zhengyi, ll_fanju, ll_donghua, ll_yinyue, ll_wudao, ll_youxi, ll_yule, ll_keji, ll_yingshi, ll_tiyu, ll_yutang, ll_shenghuo, ll_guichu, ll_xuniouxiang) 45 | } 46 | 47 | override fun initData() { 48 | } 49 | 50 | override fun initMainNetData() { 51 | } 52 | 53 | override fun initLazyData() { 54 | 55 | } 56 | 57 | override fun onClick(v: View?) { 58 | when (v) { 59 | ll_zhengyi -> { 60 | // MyProgressDialog(mContext, "加载中").show() 61 | mContext.showProgressDialog { 62 | setLoadingMsg("啦啦啦") 63 | } 64 | } 65 | ll_fanju -> { 66 | // MyConfirmDialog(mContext, "拨打电话", "斯蒂芬斯蒂芬", { mContext.showToast("点击了确定") }, ::test ).show() 67 | mContext.showConfirmDialog { 68 | title { 69 | "标题题题" 70 | } 71 | content = "多线程必须从" 72 | onOkClick { 73 | showToast("点击了确认") 74 | } 75 | onCancelClick { 76 | test() 77 | } 78 | } 79 | } 80 | ll_donghua -> { 81 | 82 | } 83 | } 84 | } 85 | 86 | 87 | 88 | fun test(){ 89 | showToast("点击了取消") 90 | } 91 | 92 | } -------------------------------------------------------------------------------- /app/src/main/java/com/wsg/up/ui/fragment/FindFragment.kt: -------------------------------------------------------------------------------- 1 | package com.wsg.up.ui.fragment 2 | import android.os.Bundle 3 | import android.view.View 4 | import androidx.recyclerview.widget.StaggeredGridLayoutManager 5 | import com.scwang.smartrefresh.layout.api.RefreshLayout 6 | import com.scwang.smartrefresh.layout.listener.OnLoadMoreListener 7 | import com.scwang.smartrefresh.layout.listener.OnRefreshListener 8 | import com.wsg.base.ext.getViewModel 9 | import com.wsg.base.ext.showToast 10 | import com.wsg.base.ext.vmObserverDefault 11 | import com.wsg.base.ext.vmObserverMain 12 | import com.wsg.up.R 13 | import com.wsg.up.ui.adapter.CommunityAdapter 14 | import com.wsg.up.ui.fragment.base.MyBaseFragment 15 | import com.wsg.up.utils.Tools 16 | import com.wsg.up.viewmodel.EyeViewModel 17 | import kotlinx.android.synthetic.main.fragment_find.* 18 | 19 | 20 | /** 21 | * ================================================ 22 | * 作 者:wushaoge 23 | * 版 本:1.0 24 | * 创建日期:2020-07-27 16:33 25 | * 描 述: 26 | * 修订历史: 27 | * ================================================ 28 | */ 29 | class FindFragment: MyBaseFragment(), OnRefreshListener, OnLoadMoreListener { 30 | 31 | lateinit var mViewModel: EyeViewModel 32 | 33 | lateinit var adapter: CommunityAdapter 34 | 35 | var nextPage = "" 36 | 37 | companion object{ 38 | fun newInstance(title: String?): FindFragment { 39 | val fragment = FindFragment() 40 | val args = Bundle() 41 | fragment.setTitle(title) 42 | args.putString("", title) 43 | fragment.arguments = args 44 | return fragment 45 | } 46 | } 47 | 48 | override fun isShowLoading(): Boolean { 49 | return true 50 | } 51 | 52 | override fun getLayoutID(): Int { 53 | return R.layout.fragment_find 54 | } 55 | 56 | override fun initViewModel() { 57 | mViewModel = getViewModel() 58 | } 59 | 60 | override fun initView() { 61 | srl_content.setOnRefreshListener(this) 62 | srl_content.setOnLoadMoreListener(this) 63 | 64 | adapter = CommunityAdapter(mContext) 65 | val mainLayoutManager = StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL) 66 | mainLayoutManager.gapStrategy = StaggeredGridLayoutManager.GAP_HANDLING_NONE 67 | rv_content.layoutManager = mainLayoutManager 68 | rv_content.adapter = adapter 69 | rv_content.setHasFixedSize(true) 70 | rv_content.itemAnimator = null 71 | } 72 | 73 | override fun initData() { 74 | mViewModel.refreshData.vmObserverMain(this, 75 | onSuccess = { 76 | nextPage = it.nextPageUrl!! 77 | val data = it.itemList!!.filter { it.type == "communityColumnsCard"} 78 | if (data.isNotEmpty()) { 79 | adapter.setList(data!!) 80 | } else { 81 | adapter.setNewInstance(null) 82 | adapter.setEmptyView(Tools.getEmptyView(mContext)) 83 | } 84 | }, 85 | onComplete = { 86 | stopLoad(srl_content) 87 | } 88 | ) 89 | 90 | mViewModel.loadMoreData.vmObserverDefault(this, 91 | onSuccess = { 92 | nextPage = it.nextPageUrl!! 93 | adapter.removeEmptyView() 94 | val data = it.itemList!!.filter { it.type == "communityColumnsCard"} 95 | if (data.isNotEmpty()) { 96 | adapter.addData(data) 97 | } else { 98 | mContext.showToast("暂无更多数据") 99 | } 100 | }, 101 | onComplete = { 102 | stopLoad(srl_content) 103 | } 104 | ) 105 | } 106 | 107 | override fun initMainNetData() { 108 | mViewModel.onRefresh() 109 | } 110 | 111 | override fun initLazyData() { 112 | 113 | } 114 | 115 | override fun onClick(v: View?) { 116 | 117 | } 118 | 119 | override fun onRefresh(refreshLayout: RefreshLayout) { 120 | mViewModel.onRefresh() 121 | } 122 | 123 | override fun onLoadMore(refreshLayout: RefreshLayout) { 124 | if(nextPage.isNotEmpty()){ 125 | mViewModel.onLoadMore(nextPage) 126 | } 127 | } 128 | 129 | 130 | } 131 | 132 | 133 | -------------------------------------------------------------------------------- /app/src/main/java/com/wsg/up/ui/fragment/HomeFragment.kt: -------------------------------------------------------------------------------- 1 | package com.wsg.up.ui.fragment 2 | import android.os.Bundle 3 | import android.view.View 4 | import com.blankj.utilcode.util.ColorUtils.getColor 5 | import com.blankj.utilcode.util.LogUtils 6 | import com.scwang.smartrefresh.layout.api.RefreshLayout 7 | import com.scwang.smartrefresh.layout.listener.OnLoadMoreListener 8 | import com.scwang.smartrefresh.layout.listener.OnRefreshListener 9 | import com.wsg.base.ext.* 10 | import com.wsg.up.R 11 | import com.wsg.up.entity.ArticleData 12 | import com.wsg.up.entity.BannerChildData 13 | import com.wsg.up.entity.Datas 14 | import com.wsg.up.ui.activity.common.WebActivity 15 | import com.wsg.up.ui.adapter.ArticleAdapter 16 | import com.wsg.up.ui.adapter.BannerAdapter 17 | import com.wsg.up.ui.fragment.base.MyBaseFragment 18 | import com.wsg.up.utils.Tools 19 | import com.wsg.up.viewmodel.WanAndroidViewModel 20 | import com.zhpan.bannerview.BannerViewPager 21 | import com.zhpan.bannerview.BaseViewHolder 22 | import com.zhpan.indicator.enums.IndicatorSlideMode 23 | import com.zhpan.indicator.enums.IndicatorStyle 24 | import kotlinx.android.synthetic.main.fragment_home.* 25 | 26 | 27 | /** 28 | * ================================================ 29 | * 作 者:wushaoge 30 | * 版 本:1.0 31 | * 创建日期:2020-07-27 16:33 32 | * 描 述: 33 | * 修订历史: 34 | * ================================================ 35 | */ 36 | class HomeFragment: MyBaseFragment(), OnRefreshListener, OnLoadMoreListener { 37 | 38 | lateinit var mViewModel: WanAndroidViewModel 39 | 40 | lateinit var mViewPager: BannerViewPager> 41 | 42 | lateinit var articleAdapter: ArticleAdapter 43 | 44 | companion object{ 45 | 46 | fun newInstance(title: String?): HomeFragment { 47 | val fragment = HomeFragment() 48 | val args = Bundle() 49 | fragment.setTitle(title) 50 | args.putString("", title) 51 | fragment.arguments = args 52 | return fragment 53 | } 54 | } 55 | 56 | override fun isShowLoading(): Boolean { 57 | return true 58 | } 59 | 60 | override fun getLayoutID(): Int { 61 | return R.layout.fragment_home 62 | } 63 | 64 | override fun initViewModel() { 65 | mViewModel = getViewModel() 66 | 67 | mViewModel.bannerData.vmObserverMain(this){ 68 | mViewPager.refreshData(it.data) 69 | } 70 | mViewModel.articleData.vmObserverDefault(this, 71 | onSuccess = { 72 | setArticleData(it) 73 | }, 74 | onComplete = { 75 | stopLoad(srl_content) 76 | } 77 | ) 78 | } 79 | 80 | override fun initView() { 81 | srl_content.setOnRefreshListener(this) 82 | srl_content.setOnLoadMoreListener(this) 83 | 84 | mViewPager = baseView!!.findViewById(R.id.banner) 85 | 86 | mViewPager.apply { 87 | adapter = BannerAdapter() 88 | setAutoPlay(true) 89 | setLifecycleRegistry(lifecycle) 90 | setIndicatorStyle(IndicatorStyle.ROUND_RECT) 91 | setIndicatorSliderGap(20) 92 | setIndicatorSlideMode(IndicatorSlideMode.WORM) 93 | setIndicatorSliderRadius(15, 15) 94 | setIndicatorSliderColor(getColor(R.color.red_normal_color), getColor(R.color.red_checked_color)) 95 | setOnPageClickListener { 96 | LogUtils.e("第{$it}个,${(banner.getData()[it] as BannerChildData).url}") 97 | startActivity("url" to (banner.getData()[it] as BannerChildData).url) 98 | } 99 | }.create() 100 | 101 | articleAdapter = ArticleAdapter(mContext) 102 | articleAdapter.setOnItemClickListener { adapter, view, position -> 103 | LogUtils.e((adapter.data[position] as Datas).link) 104 | startActivity("url" to (adapter.data[position] as Datas).link) 105 | } 106 | rv_content.adapter = articleAdapter 107 | 108 | } 109 | 110 | override fun initData() { 111 | } 112 | 113 | override fun initMainNetData() { 114 | mViewModel.getBannerData() 115 | getArticleData() 116 | } 117 | 118 | override fun initLazyData() { 119 | 120 | } 121 | 122 | fun getArticleData(){ 123 | mViewModel.getArticleData(pageNo) 124 | } 125 | 126 | fun setArticleData(articleData: ArticleData){ 127 | val data= articleData?.data?.datas 128 | if (pageNo === 1) { 129 | if (data.isNotEmpty()) { 130 | articleAdapter.setList(data!!) 131 | } else { 132 | articleAdapter.setNewInstance(null) 133 | articleAdapter.setEmptyView(Tools.getEmptyView(mContext)) 134 | } 135 | } else { 136 | articleAdapter.removeEmptyView() 137 | if (data.isNotEmpty()) { 138 | articleAdapter.addData(data) 139 | } else { 140 | mContext.showToast("暂无更多数据") 141 | } 142 | } 143 | } 144 | 145 | override fun onClick(v: View?) { 146 | 147 | } 148 | 149 | override fun onRefresh(refreshLayout: RefreshLayout) { 150 | pageNo = 1 151 | getArticleData() 152 | } 153 | 154 | override fun onLoadMore(refreshLayout: RefreshLayout) { 155 | ++pageNo 156 | getArticleData() 157 | } 158 | } -------------------------------------------------------------------------------- /app/src/main/java/com/wsg/up/ui/fragment/TestFragment.kt: -------------------------------------------------------------------------------- 1 | package com.wsg.up.ui.fragment 2 | import android.os.Bundle 3 | import android.view.View 4 | import com.wsg.up.R 5 | import com.wsg.up.ui.fragment.base.MyBaseFragment 6 | 7 | 8 | /** 9 | * ================================================ 10 | * 作 者:wushaoge 11 | * 版 本:1.0 12 | * 创建日期:2020-07-27 16:33 13 | * 描 述: 14 | * 修订历史: 15 | * ================================================ 16 | */ 17 | class TestFragment: MyBaseFragment(){ 18 | 19 | companion object{ 20 | fun newInstance(title: String?): TestFragment { 21 | val fragment = TestFragment() 22 | val args = Bundle() 23 | fragment.setTitle(title) 24 | args.putString("", title) 25 | fragment.arguments = args 26 | return fragment 27 | } 28 | } 29 | 30 | override fun isShowLoading(): Boolean { 31 | return true 32 | } 33 | 34 | override fun getLayoutID(): Int { 35 | return R.layout.fragment_home 36 | } 37 | 38 | override fun initViewModel() { 39 | 40 | } 41 | 42 | override fun initView() { 43 | 44 | 45 | } 46 | 47 | override fun initData() { 48 | } 49 | 50 | override fun initMainNetData() { 51 | } 52 | 53 | override fun initLazyData() { 54 | 55 | } 56 | 57 | 58 | override fun onClick(v: View?) { 59 | 60 | } 61 | 62 | } -------------------------------------------------------------------------------- /app/src/main/java/com/wsg/up/ui/fragment/base/MyBaseFragment.kt: -------------------------------------------------------------------------------- 1 | package com.wsg.up.ui.fragment.base 2 | 3 | import com.scwang.smartrefresh.layout.SmartRefreshLayout 4 | import com.scwang.smartrefresh.layout.constant.RefreshState 5 | import com.wsg.base.fragment.BaseFragment 6 | import com.wsg.base.ui.dialog.MyProgressDialog 7 | 8 | /** 9 | * ================================================ 10 | * 作 者:wushaoge 11 | * 版 本:1.0 12 | * 创建日期:2020-07-22 15:29 13 | * 描 述: 14 | * 修订历史: 15 | * ================================================ 16 | */ 17 | abstract class MyBaseFragment: BaseFragment() { 18 | 19 | var baseTitle: String? = "" 20 | 21 | var dialog: MyProgressDialog? = null 22 | 23 | //分页使用 24 | var pageNo = 1 25 | var pageSize = 10 26 | var pageCount = 0 27 | 28 | override fun showLoadingDialog(content: String) { 29 | dialog?:let { 30 | dialog = MyProgressDialog(mContext, content) 31 | } 32 | dialog?.show() 33 | } 34 | 35 | override fun dismissLoadingDialog() { 36 | dialog?.dismiss() 37 | } 38 | 39 | open fun getTitle(): String? { 40 | return baseTitle 41 | } 42 | 43 | open fun setTitle(title: String?) { 44 | this.baseTitle = title 45 | } 46 | 47 | /** 48 | * 结束刷新/加载 49 | * 50 | * @param srl 51 | */ 52 | open fun stopLoad(srl: SmartRefreshLayout?) { 53 | if (srl != null) { 54 | if (srl.state == RefreshState.Refreshing) { 55 | srl.finishRefresh() 56 | } else { 57 | srl.finishLoadMore() 58 | } 59 | } 60 | } 61 | } -------------------------------------------------------------------------------- /app/src/main/java/com/wsg/up/ui/view/MyViewPager.kt: -------------------------------------------------------------------------------- 1 | package com.wsg.up.ui.view 2 | 3 | import android.content.Context 4 | import android.util.AttributeSet 5 | import android.view.MotionEvent 6 | import androidx.viewpager.widget.ViewPager 7 | 8 | /** 9 | * ================================================ 10 | * 作 者:wushaoge 11 | * 版 本:1.0 12 | * 创建日期:2020-07-27 15:01 13 | * 描 述: 14 | * 修订历史: 15 | * ================================================ 16 | */ 17 | class MyViewPager: ViewPager { 18 | private var scrollble = false 19 | 20 | constructor(context: Context): super(context) 21 | 22 | constructor( 23 | context: Context, 24 | attrs: AttributeSet? 25 | ): super(context, attrs) 26 | 27 | 28 | override fun onTouchEvent(ev: MotionEvent?): Boolean { 29 | return if (scrollble) { 30 | super.onTouchEvent(ev) 31 | } else scrollble 32 | } 33 | 34 | override fun onInterceptTouchEvent(ev: MotionEvent?): Boolean { 35 | return if (scrollble) { 36 | super.onInterceptTouchEvent(ev) 37 | } else scrollble 38 | } 39 | 40 | fun isScrollble(): Boolean { 41 | return scrollble 42 | } 43 | 44 | fun setScrollble(scrollble: Boolean) { 45 | this.scrollble = scrollble 46 | } 47 | 48 | 49 | } -------------------------------------------------------------------------------- /app/src/main/java/com/wsg/up/ui/view/dialog/MyConfirmDialog.kt: -------------------------------------------------------------------------------- 1 | package com.wsg.up.ui.view.dialog 2 | 3 | import android.app.Dialog 4 | import android.content.Context 5 | import android.view.View 6 | import android.view.Window 7 | import com.wsg.up.R 8 | import kotlinx.android.synthetic.main.common_confirm_dialog.* 9 | 10 | 11 | /** 12 | * ================================================ 13 | * 作 者:wushaoge 14 | * 版 本:1.0 15 | * 创建日期:2020-08-06 15:45 16 | * 描 述: 17 | * 修订历史: 18 | * ================================================ 19 | */ 20 | class MyConfirmDialog : Dialog { 21 | 22 | 23 | constructor(context: Context, title: String = "", content: String = "您确定这么做吗", okClick: () -> Unit = {}, cancleClick: () -> Unit = {} ): super(context, R.style.dialog){ 24 | requestWindowFeature(Window.FEATURE_NO_TITLE) 25 | setContentView(R.layout.common_confirm_dialog) 26 | this.setCanceledOnTouchOutside(true) 27 | 28 | tv_title.visibility = View.GONE 29 | btn_single.visibility = View.GONE 30 | 31 | title.isNotEmpty().let { 32 | setTitle(title) 33 | } 34 | setContent(content) 35 | 36 | btn_confirm.setOnClickListener { okClick();dismiss() } 37 | btn_cancel.setOnClickListener { cancleClick();dismiss() } 38 | btn_single.setOnClickListener { okClick();dismiss() } 39 | } 40 | 41 | 42 | /** 43 | * 设置标题 44 | * @param str 45 | * @return 46 | */ 47 | fun setTitle(str: String?): MyConfirmDialog? { 48 | tv_title.visibility = View.VISIBLE 49 | tv_title.text = str 50 | return this 51 | } 52 | 53 | /** 54 | * 设置内容 55 | * @param str 56 | * @return 57 | */ 58 | fun setContent(str: String?): MyConfirmDialog? { 59 | tv_content.text = str 60 | return this 61 | } 62 | 63 | 64 | /** 65 | * 设置取消按钮文字 66 | * @param str 67 | * @return 68 | */ 69 | fun setCancleBtnText(str: String?): MyConfirmDialog? { 70 | btn_cancel.setText(str) 71 | return this 72 | } 73 | 74 | /** 75 | * 设置确定按钮文字 76 | * @param str 77 | * @return 78 | */ 79 | fun setConfirmBtnText(str: String?): MyConfirmDialog? { 80 | btn_confirm.setText(str) 81 | return this 82 | } 83 | 84 | /** 85 | * 设置单按钮文字 86 | */ 87 | fun setSingleBtnText(str: String?): MyConfirmDialog? { 88 | btn_single.setText(str) 89 | return this 90 | } 91 | 92 | /** 93 | * 设置为单个按钮 94 | */ 95 | fun setSingleBtnVisible(visible: Boolean): MyConfirmDialog? { 96 | btn_single.visibility = if (visible) View.VISIBLE else View.GONE 97 | btn_cancel.visibility = if (!visible) View.VISIBLE else View.GONE 98 | btn_confirm.visibility = if (!visible) View.VISIBLE else View.GONE 99 | v_single_line.visibility = if (!visible) View.VISIBLE else View.GONE 100 | return this 101 | } 102 | 103 | fun setOkClick(click: () -> Unit){ 104 | btn_confirm.setOnClickListener { click();dismiss() } 105 | } 106 | 107 | fun setCancel(click: () -> Unit){ 108 | btn_cancel.setOnClickListener { click();dismiss() } 109 | } 110 | 111 | } -------------------------------------------------------------------------------- /app/src/main/java/com/wsg/up/ui/view/listener/HomeTabSelectedListener.kt: -------------------------------------------------------------------------------- 1 | package com.wsg.up.ui.view.listener 2 | 3 | import android.content.Context 4 | import android.content.res.ColorStateList 5 | import android.view.View 6 | import android.widget.ImageView 7 | import android.widget.TextView 8 | import androidx.core.content.ContextCompat 9 | import androidx.core.graphics.drawable.DrawableCompat 10 | import com.google.android.material.tabs.TabLayout 11 | import com.google.android.material.tabs.TabLayout.OnTabSelectedListener 12 | import com.wsg.up.R 13 | 14 | /** 15 | * ================================================ 16 | * 作 者:wushaoge 17 | * 版 本:1.0 18 | * 创建日期:2018-09-04 19:36 19 | * 描 述: 20 | * 修订历史: 21 | * ================================================ 22 | */ 23 | class HomeTabSelectedListener(private val mContext: Context) : 24 | OnTabSelectedListener { 25 | override fun onTabSelected(tab: TabLayout.Tab) { 26 | val customView = tab.customView 27 | val tvTitle = 28 | customView!!.findViewById(R.id.tv_tab_title) as TextView 29 | val ivImg = 30 | customView.findViewById(R.id.iv_img) as ImageView 31 | tvTitle.setTextColor(mContext.resources.getColor(R.color.colorPrimary)) 32 | 33 | // DrawableCompat.setTint( 34 | // ivImg.drawable, 35 | // ContextCompat.getColor(mContext, R.color.colorPrimary) 36 | // ) 37 | ivImg.setImageDrawable(ivImg.drawable) 38 | } 39 | 40 | override fun onTabUnselected(tab: TabLayout.Tab) { 41 | val customView = tab.customView 42 | val tvTitle = customView!!.findViewById(R.id.tv_tab_title) as TextView 43 | val ivImg = customView.findViewById(R.id.iv_img) as ImageView 44 | tvTitle.setTextColor(mContext.resources.getColor(R.color.font_gray_deep)) 45 | // DrawableCompat.setTint( 46 | // ivImg.drawable, 47 | // ContextCompat.getColor(mContext, R.color.font_black) 48 | // ) 49 | // ivImg.setImageDrawable(ivImg.drawable) 50 | 51 | //通过mutate()复制加载出来的对象 52 | val drawable = ivImg.drawable.mutate() 53 | val wrappedDrawable = 54 | DrawableCompat.wrap(drawable) 55 | DrawableCompat.setTintList( 56 | wrappedDrawable, 57 | ColorStateList.valueOf(ContextCompat.getColor(mContext, R.color.font_black)) 58 | ) 59 | ivImg.setImageDrawable(wrappedDrawable) 60 | } 61 | 62 | override fun onTabReselected(tab: TabLayout.Tab) {} 63 | 64 | } -------------------------------------------------------------------------------- /app/src/main/java/com/wsg/up/ui/view/ugc/UgcDetailVideoPlayer.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020. vipyinzhiwei 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.wsg.up.ui.view.ugc 17 | 18 | import android.content.Context 19 | import android.util.AttributeSet 20 | import android.widget.ImageView 21 | import com.blankj.utilcode.util.LogUtils 22 | import com.shuyu.gsyvideoplayer.video.StandardGSYVideoPlayer 23 | import com.shuyu.gsyvideoplayer.video.base.GSYVideoView 24 | import com.wsg.up.R 25 | import com.wsg.up.ext.gone 26 | import com.wsg.up.ext.visible 27 | 28 | /** 29 | * 社区-推荐详情页面对应的视频播放器。 30 | * 31 | * @author vipyinzhiwei 32 | * @since 2020/5/26 33 | */ 34 | class UgcDetailVideoPlayer : StandardGSYVideoPlayer { 35 | 36 | /** 37 | * 是否第一次加载视频。用于隐藏进度条、播放按钮等UI。播放完成后,重新加载视频,会重置为true。 38 | */ 39 | private var initFirstLoad = true 40 | 41 | constructor(context: Context) : super(context) 42 | 43 | constructor(context: Context, fullFlag: Boolean?) : super(context, fullFlag) 44 | 45 | constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) 46 | 47 | override fun getLayoutId() = R.layout.layout_ugc_detail_video_player 48 | 49 | override fun updateStartImage() { 50 | if (mStartButton is ImageView) { 51 | val imageView = mStartButton as ImageView 52 | when (mCurrentState) { 53 | GSYVideoView.CURRENT_STATE_PLAYING -> imageView.setImageResource(R.drawable.ic_pause_white_24dp) 54 | GSYVideoView.CURRENT_STATE_ERROR -> imageView.setImageResource(R.drawable.ic_play_white_24dp) 55 | GSYVideoView.CURRENT_STATE_AUTO_COMPLETE -> imageView.setImageResource(R.drawable.ic_refresh_white_24dp) 56 | else -> imageView.setImageResource(R.drawable.ic_play_white_24dp) 57 | } 58 | 59 | } else { 60 | super.updateStartImage() 61 | } 62 | } 63 | 64 | //正常 65 | override fun changeUiToNormal() { 66 | super.changeUiToNormal() 67 | LogUtils.e("changeUiToNormal") 68 | initFirstLoad = true 69 | } 70 | 71 | //准备中 72 | override fun changeUiToPreparingShow() { 73 | super.changeUiToPreparingShow() 74 | LogUtils.e("changeUiToPreparingShow") 75 | mBottomContainer.gone() 76 | } 77 | 78 | //播放中 79 | override fun changeUiToPlayingShow() { 80 | super.changeUiToPlayingShow() 81 | LogUtils.e("changeUiToPlayingShow") 82 | if (initFirstLoad) mBottomContainer.gone() 83 | initFirstLoad = false 84 | } 85 | 86 | //开始缓冲 87 | override fun changeUiToPlayingBufferingShow() { 88 | super.changeUiToPlayingBufferingShow() 89 | LogUtils.e("changeUiToPlayingBufferingShow") 90 | if (initFirstLoad) { 91 | mStartButton.gone() 92 | initFirstLoad = false 93 | } else { 94 | mStartButton.visible() 95 | } 96 | } 97 | 98 | //暂停 99 | override fun changeUiToPauseShow() { 100 | super.changeUiToPauseShow() 101 | LogUtils.e("changeUiToPauseShow") 102 | } 103 | 104 | //自动播放结束 105 | override fun changeUiToCompleteShow() { 106 | super.changeUiToCompleteShow() 107 | LogUtils.e("changeUiToCompleteShow") 108 | mBottomContainer.gone() 109 | } 110 | 111 | //错误状态 112 | override fun changeUiToError() { 113 | super.changeUiToError() 114 | LogUtils.e("changeUiToError") 115 | } 116 | 117 | fun getBottomContainer() = mBottomContainer 118 | } -------------------------------------------------------------------------------- /app/src/main/java/com/wsg/up/utils/Constants.kt: -------------------------------------------------------------------------------- 1 | package com.wsg.up.utils 2 | 3 | import rxhttp.wrapper.annotation.DefaultDomain 4 | 5 | /** 6 | * ================================================ 7 | * 作 者:wushaoge 8 | * 版 本:1.0 9 | * 创建日期:2020-07-23 09:41 10 | * 描 述: 11 | * 修订历史: 12 | * ================================================ 13 | */ 14 | class Constants { 15 | 16 | companion object{ 17 | 18 | @DefaultDomain //设置为默认域名 19 | const val WAN_ANDROID_BASEURL = "http://www.wanandroid.com/" 20 | 21 | 22 | /** 23 | * 玩安卓首页文章 24 | */ 25 | const val WAN_ARTICLE = "article/list/" 26 | 27 | /** 28 | * 玩安卓Banner 29 | */ 30 | const val WAN_BANNER = "banner" 31 | 32 | 33 | /** 34 | * 开眼推荐 35 | */ 36 | const val EYE_COMMUNITY = "http://baobab.kaiyanapp.com/api/v7/community/tab/rec" 37 | 38 | } 39 | 40 | } -------------------------------------------------------------------------------- /app/src/main/java/com/wsg/up/utils/EyeConstants.kt: -------------------------------------------------------------------------------- 1 | package com.wsg.up.utils 2 | 3 | /** 4 | * ================================================ 5 | * 作 者:wushaoge 6 | * 版 本:1.0 7 | * 创建日期:2020-08-27 10:56 8 | * 描 述: 9 | * 修订历史: 10 | * ================================================ 11 | */ 12 | object EyeConstants { 13 | 14 | const val STR_HORIZONTAL_SCROLLCARD_TYPE = "horizontalScrollCard" 15 | const val STR_COMMUNITY_COLUMNS_CARD = "communityColumnsCard" 16 | 17 | const val STR_HORIZONTAL_SCROLLCARD_DATA_TYPE = "HorizontalScrollCard" 18 | const val STR_ITEM_COLLECTION_DATA_TYPE = "ItemCollection" 19 | const val STR_FOLLOW_CARD_DATA_TYPE = "FollowCard" 20 | 21 | const val STR_VIDEO_TYPE = "video" 22 | const val STR_UGC_PICTURE_TYPE = "ugcPicture" 23 | 24 | const val HORIZONTAL_SCROLLCARD_ITEM_COLLECTION_TYPE = 1 //type:horizontalScrollCard -> dataType:ItemCollection 25 | const val HORIZONTAL_SCROLLCARD_TYPE = 2 //type:horizontalScrollCard -> dataType:HorizontalScrollCard 26 | const val FOLLOW_CARD_TYPE = 3 //type:communityColumnsCard -> dataType:FollowCard 27 | const val UN_KNOW = 4 28 | } -------------------------------------------------------------------------------- /app/src/main/java/com/wsg/up/utils/TablayoutUtils.kt: -------------------------------------------------------------------------------- 1 | package com.wsg.up.utils 2 | 3 | import android.content.Context 4 | import android.view.LayoutInflater 5 | import android.view.View 6 | import android.widget.ImageView 7 | import android.widget.TextView 8 | import com.google.android.material.tabs.TabLayout 9 | import com.wsg.up.R 10 | import com.wsg.up.entity.BottomResourceData 11 | import com.wsg.up.ext.onTabSelected 12 | import java.util.* 13 | 14 | /** 15 | * ================================================ 16 | * 作 者:wushaoge 17 | * 版 本:1.0 18 | * 创建日期:2018-09-05 10:21 19 | * 描 述: 20 | * 修订历史: 21 | * ================================================ 22 | */ 23 | object TablayoutUtils { 24 | /** 25 | * 首页设置tablayout布局 26 | * @param mContext 27 | * @param tlTablayout 28 | * @param bottomList 29 | */ 30 | fun setHomeTablayoutCustomView(mContext: Context, tlTablayout: TabLayout, bottomList: ArrayList) { 31 | for (i in 0 until tlTablayout.tabCount) { 32 | val itemView: View = LayoutInflater.from(mContext).inflate(R.layout.tab_home_item, tlTablayout, false) 33 | val txtView = itemView.findViewById(R.id.tv_tab_title) as TextView 34 | txtView.text = bottomList[i].getTitle() 35 | val ivImg = itemView.findViewById(R.id.iv_img) as ImageView 36 | 37 | //默认选中第一项 38 | if (i == 0) { 39 | txtView.setTextColor(mContext.getColor(R.color.colorPrimary)) 40 | ivImg.setImageResource(bottomList[i].getResource()) 41 | } else { 42 | txtView.setTextColor(mContext.getColor(R.color.font_gray_deep)) 43 | ivImg.setImageResource(bottomList[i].getUnCheckResource()) 44 | } 45 | tlTablayout.getTabAt(i)!!.customView = itemView 46 | } 47 | 48 | //设置监听 49 | tlTablayout.onTabSelected { 50 | onTabSelected { 51 | for (i in 0 until tlTablayout.tabCount) { 52 | val itemView: View = tlTablayout.getTabAt(i)!!.customView!! 53 | val txtView = itemView.findViewById(R.id.tv_tab_title) as TextView 54 | val ivImg = itemView.findViewById(R.id.iv_img) as ImageView 55 | if(i != tlTablayout.selectedTabPosition){ 56 | txtView.setTextColor(mContext.getColor(R.color.font_gray_deep)) 57 | ivImg.setImageResource(bottomList[i].getUnCheckResource()) 58 | } 59 | } 60 | customView?.let { 61 | (it.findViewById(R.id.tv_tab_title) as TextView).setTextColor(mContext.getColor(R.color.colorPrimary)) 62 | (it.findViewById(R.id.iv_img) as ImageView).setImageResource(bottomList[tlTablayout.selectedTabPosition].getResource()) 63 | } 64 | } 65 | } 66 | 67 | 68 | // tlTablayout.addOnTabSelectedListener(object: TabLayout.OnTabSelectedListener{ 69 | // 70 | // override fun onTabSelected(tab: TabLayout.Tab?) { 71 | // for (i in 0 until tlTablayout.tabCount) { 72 | // val itemView: View = tlTablayout.getTabAt(i)!!.customView!! 73 | // val txtView = itemView.findViewById(R.id.tv_tab_title) as TextView 74 | // val ivImg = itemView.findViewById(R.id.iv_img) as ImageView 75 | // if(i != tlTablayout.selectedTabPosition){ 76 | // txtView.setTextColor(mContext.getColor(R.color.font_gray_deep)) 77 | // ivImg.setImageResource(bottomList[i].getUnCheckResource()) 78 | // } 79 | // } 80 | // tab!!.customView?.let { 81 | // (it.findViewById(R.id.tv_tab_title) as TextView).setTextColor(mContext.getColor(R.color.colorPrimary)) 82 | // (it.findViewById(R.id.iv_img) as ImageView).setImageResource(bottomList[tlTablayout.selectedTabPosition].getResource()) 83 | // } 84 | // } 85 | // override fun onTabUnselected(tab: TabLayout.Tab?) { 86 | // } 87 | // 88 | // override fun onTabReselected(tab: TabLayout.Tab?) { 89 | // } 90 | // 91 | // }) 92 | } 93 | } -------------------------------------------------------------------------------- /app/src/main/java/com/wsg/up/utils/Tools.kt: -------------------------------------------------------------------------------- 1 | package com.wsg.up.utils 2 | 3 | import android.animation.ValueAnimator 4 | import android.content.Context 5 | import android.view.LayoutInflater 6 | import android.view.View 7 | import com.airbnb.lottie.LottieAnimationView 8 | import com.wsg.up.R 9 | 10 | /** 11 | * ================================================ 12 | * 作 者:wushaoge 13 | * 版 本:1.0 14 | * 创建日期:2020-08-03 15:22 15 | * 描 述: 16 | * 修订历史: 17 | * ================================================ 18 | */ 19 | class Tools { 20 | 21 | companion object{ 22 | 23 | /** 24 | * 加载列表的空布局 25 | * @param context 26 | * @return 27 | */ 28 | fun getEmptyView(context: Context): View { 29 | val mLayoutInflater = 30 | context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater 31 | val emptyView: View = 32 | mLayoutInflater.inflate(R.layout.common_empty, null, true) 33 | val lottieLoadingView = 34 | emptyView.findViewById(R.id.lottie_empty_view) as LottieAnimationView 35 | lottieLoadingView.setAnimation("halloween_smoothymon.json") 36 | lottieLoadingView.repeatCount = ValueAnimator.INFINITE 37 | lottieLoadingView.playAnimation() 38 | return emptyView 39 | } 40 | 41 | 42 | 43 | 44 | 45 | } 46 | 47 | } -------------------------------------------------------------------------------- /app/src/main/java/com/wsg/up/utils/TypeFaceUtil.kt: -------------------------------------------------------------------------------- 1 | package com.wsg.up.utils 2 | 3 | import android.graphics.Typeface 4 | import com.wsg.base.application.BaseApplication 5 | 6 | /** 7 | * ================================================ 8 | * 作 者:wushaoge 9 | * 版 本:1.0 10 | * 创建日期:2020-08-11 10:03 11 | * 描 述: 12 | * 修订历史: 13 | * ================================================ 14 | */ 15 | object TypeFaceUtil { 16 | 17 | var typeface: Typeface? = null 18 | 19 | fun getEyeTypeFace(): Typeface { 20 | typeface = if(typeface == null){ 21 | Typeface.createFromAsset(BaseApplication.instance.assets, "fonts/eye.ttf") 22 | }else{ 23 | Typeface.DEFAULT 24 | } 25 | return typeface!! 26 | } 27 | 28 | 29 | fun getAcfunTypeFace(): Typeface { 30 | typeface = if(typeface == null){ 31 | Typeface.createFromAsset(BaseApplication.instance.assets, "fonts/acfun.ttf") 32 | }else{ 33 | Typeface.DEFAULT 34 | } 35 | return typeface!! 36 | } 37 | } -------------------------------------------------------------------------------- /app/src/main/java/com/wsg/up/viewmodel/EyeViewModel.kt: -------------------------------------------------------------------------------- 1 | package com.wsg.up.viewmodel 2 | 3 | import androidx.lifecycle.MutableLiveData 4 | import com.wsg.base.ext.VmLiveData 5 | import com.wsg.base.ext.launchVmRequest 6 | import com.wsg.base.model.BaseViewModel 7 | import com.wsg.up.entity.RecommendData 8 | import com.wsg.up.repository.EyeRepository 9 | 10 | /** 11 | * ================================================ 12 | * 作 者:wushaoge 13 | * 版 本:1.0 14 | * 创建日期:2020-07-23 09:38 15 | * 描 述: 16 | * 修订历史: 17 | * ================================================ 18 | */ 19 | class EyeViewModel: BaseViewModel() { 20 | private val eyeRepository by lazy { EyeRepository() } 21 | 22 | /** 23 | * 刷新和加载更多 24 | * 这里其实可以只用一个data 25 | * 为什么我用两个~~因为懒 26 | */ 27 | val refreshData: VmLiveData = MutableLiveData() 28 | val loadMoreData: VmLiveData = MutableLiveData() 29 | 30 | 31 | fun onRefresh(){ 32 | launchVmRequest({ 33 | eyeRepository.onRefresh() 34 | }, refreshData) 35 | } 36 | 37 | fun onLoadMore(url: String){ 38 | launchVmRequest({ 39 | eyeRepository.loadMore(url) 40 | }, loadMoreData) 41 | } 42 | 43 | } -------------------------------------------------------------------------------- /app/src/main/java/com/wsg/up/viewmodel/WanAndroidViewModel.kt: -------------------------------------------------------------------------------- 1 | package com.wsg.up.viewmodel 2 | 3 | import androidx.lifecycle.MutableLiveData 4 | import com.wsg.base.ext.VmLiveData 5 | import com.wsg.base.ext.launchVmRequest 6 | import com.wsg.base.model.BaseViewModel 7 | import com.wsg.up.entity.ArticleData 8 | import com.wsg.up.entity.BannerData 9 | import com.wsg.up.repository.WanAndroidRepository 10 | 11 | /** 12 | * ================================================ 13 | * 作 者:wushaoge 14 | * 版 本:1.0 15 | * 创建日期:2020-07-23 09:38 16 | * 描 述: 17 | * 修订历史: 18 | * ================================================ 19 | */ 20 | class WanAndroidViewModel: BaseViewModel() { 21 | private val wanAndroidRepository by lazy { WanAndroidRepository() } 22 | 23 | val articleData: VmLiveData = MutableLiveData() 24 | val bannerData: VmLiveData = MutableLiveData() 25 | 26 | 27 | fun getArticleData(page: Int){ 28 | launchVmRequest({ 29 | wanAndroidRepository.getArticle(page) 30 | }, articleData) 31 | } 32 | 33 | fun getBannerData(){ 34 | launchVmRequest({ 35 | wanAndroidRepository.getBanner() 36 | }, bannerData) 37 | } 38 | 39 | 40 | } -------------------------------------------------------------------------------- /app/src/main/res/anim/anl_push_bottom_in.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/anim/anl_push_bottom_out.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/anim/anl_push_top_out.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/anim/anl_push_up_in.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 19 | 20 | 24 | 25 | -------------------------------------------------------------------------------- /app/src/main/res/anim/anl_push_up_out.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 19 | 20 | 24 | 25 | 29 | 30 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 8 | 9 | 15 | 18 | 21 | 22 | 23 | 24 | 30 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/confirm_dialog_box.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/confirm_dialog_cancel_btn.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/confirm_dialog_cancel_btn_check.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/confirm_dialog_cancel_btn_uncheck.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/confirm_dialog_ok_btn.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/confirm_dialog_ok_btn_check.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/confirm_dialog_ok_btn_uncheck.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/confirm_dialog_single_btn.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 12 | 13 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_avatar_gray_76dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_favorite_border_black_20dp.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_favorite_border_white_20dp.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_kabi.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 12 | 15 | 18 | 21 | 24 | 27 | 30 | 33 | 36 | 39 | 42 | 45 | 48 | 51 | 54 | 55 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_kabi_uncheck.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 12 | 15 | 18 | 21 | 24 | 27 | 30 | 33 | 36 | 39 | 42 | 45 | 48 | 51 | 54 | 55 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | 15 | 20 | 25 | 30 | 35 | 40 | 45 | 50 | 55 | 60 | 65 | 70 | 75 | 80 | 85 | 90 | 95 | 100 | 105 | 110 | 115 | 120 | 125 | 130 | 135 | 140 | 145 | 150 | 155 | 160 | 165 | 170 | 171 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_layers_white_30dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 12 | 13 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_logo_black_76dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 12 | 13 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_pause_white_24dp.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_play_white_24dp.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_pull_down_white_30dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_refresh_white_24dp.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_reply_white_20dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 12 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_share_white_20dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_star_white_15dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_star_white_20dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/shape_black_alpha_50_4dp_bg.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/shape_choiceness_radius_black_2dp_bg.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/shape_follow_radius_black_2dp_bg.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/shape_follow_radius_white_4dp_bg.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/shape_gray_4dp_bg.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/shape_primary_4dp_bg.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 11 | 12 | 17 | 18 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main2.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 17 | 18 | 27 | 28 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_splash.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 13 | 14 | 22 | 23 | 34 | 35 | 40 | 41 | 49 | 50 | 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_ugc_detail.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_web.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 12 | 13 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /app/src/main/res/layout/common_confirm_dialog.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 16 | 17 | 24 | 25 | 34 | 35 | 48 | 49 | 50 | 51 | 52 | 56 | 57 | 64 | 65 |