├── README.md
├── app
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── nightssky
│ │ └── gankforkotlin
│ │ └── ExampleInstrumentedTest.kt
│ ├── main
│ ├── AndroidManifest.xml
│ ├── java
│ │ └── com
│ │ │ └── nightssky
│ │ │ └── gankforkotlin
│ │ │ ├── Model
│ │ │ ├── Constants.kt
│ │ │ ├── Entity
│ │ │ │ └── GankData.kt
│ │ │ ├── GankDataModel.kt
│ │ │ ├── GankService.kt
│ │ │ ├── HttpManager.kt
│ │ │ └── OnGetDataListener.kt
│ │ │ ├── Presenter
│ │ │ ├── GankDataPresenter.kt
│ │ │ └── SearchPresenter.kt
│ │ │ ├── View
│ │ │ ├── Activity
│ │ │ │ ├── ImageActivity.kt
│ │ │ │ ├── LabelActivity.kt
│ │ │ │ ├── MainActivity.kt
│ │ │ │ ├── SearchActivity.kt
│ │ │ │ ├── SplashActivity.kt
│ │ │ │ └── WebActivity.kt
│ │ │ ├── Adapter
│ │ │ │ ├── BaseRecycleViewAdapter.kt
│ │ │ │ ├── GankAdapter.kt
│ │ │ │ ├── LabelAdapter.kt
│ │ │ │ ├── MeiziAdapter.kt
│ │ │ │ └── SearchAdapter.kt
│ │ │ ├── Common
│ │ │ │ ├── BasePresenter.kt
│ │ │ │ ├── BaseView.kt
│ │ │ │ ├── DividerItemDecoration.kt
│ │ │ │ └── MyApplication.kt
│ │ │ ├── Contract
│ │ │ │ ├── GankDataContract.kt
│ │ │ │ ├── MainContract.kt
│ │ │ │ └── SearchContract.kt
│ │ │ ├── Fragment
│ │ │ │ ├── BaseFragment.kt
│ │ │ │ ├── MeiziFragment.kt
│ │ │ │ ├── RecommendFragment.kt
│ │ │ │ └── TypeFragment.kt
│ │ │ └── Widget
│ │ │ │ ├── DragHelper
│ │ │ │ ├── ItemTouchHelperAdapter.java
│ │ │ │ ├── ItemTouchHelperViewHolder.java
│ │ │ │ ├── OnStartDragListener.java
│ │ │ │ └── SimpleItemTouchHelperCallback.java
│ │ │ │ └── ScaleImageView.java
│ │ │ └── utils
│ │ │ ├── FileUtils.kt
│ │ │ ├── PreUtils.kt
│ │ │ └── ToastUtils.kt
│ └── res
│ │ ├── drawable
│ │ ├── ic_arrow_right.xml
│ │ ├── ic_back.xml
│ │ ├── ic_down.xml
│ │ ├── ic_label.xml
│ │ ├── ic_label_list.xml
│ │ ├── ic_night.xml
│ │ ├── ic_search.xml
│ │ ├── ic_settings.xml
│ │ ├── ic_share.xml
│ │ ├── ic_whatshot_black_24dp.xml
│ │ ├── progress_bar_states.xml
│ │ ├── shape_progress_shadow.xml
│ │ └── shape_search_bg.xml
│ │ ├── layout
│ │ ├── activity_image.xml
│ │ ├── activity_label.xml
│ │ ├── activity_main.xml
│ │ ├── activity_search.xml
│ │ ├── activity_splash.xml
│ │ ├── activity_web.xml
│ │ ├── fragment_base.xml
│ │ ├── fragment_blank.xml
│ │ ├── item_gank_recycle_view.xml
│ │ ├── item_girls_recycle.xml
│ │ ├── item_label_recycle_view.xml
│ │ └── layout_empty_view.xml
│ │ ├── menu
│ │ └── web_menu.xml
│ │ ├── mipmap
│ │ ├── ic_launcher.png
│ │ └── start.jpg
│ │ ├── values-w820dp
│ │ └── dimens.xml
│ │ └── values
│ │ ├── attrs.xml
│ │ ├── colors.xml
│ │ ├── dimens.xml
│ │ ├── strings.xml
│ │ └── styles.xml
│ └── test
│ └── java
│ └── com
│ └── nightssky
│ └── gankforkotlin
│ └── ExampleUnitTest.kt
├── build.gradle
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
└── settings.gradle
/README.md:
--------------------------------------------------------------------------------
1 |
2 | #### 自从Kotlin成了Google爸爸的干儿子后,是越来越火啦,作为一个Android开发者怎么能不会kotlin,那不然就落后啦,于是自己边学边敲撸了一个kotlin的干货客户端分享给大家,有什么不足之处或者建议欢迎提出。
3 |
4 | 
5 |
6 | ## 项目所运用到的一些第三方库
7 |
8 |
9 | ```
10 |
11 | //Retroit 相关包
12 | compile 'com.squareup.retrofit2:retrofit:2.3.0'
13 | compile 'com.squareup.retrofit2:converter-gson:2.3.0'
14 | compile 'com.squareup.retrofit2:adapter-rxjava2:2.3.0'
15 | //Rxjava 相关包
16 | compile 'io.reactivex.rxjava2:rxjava:2.1.0'
17 | compile 'io.reactivex.rxjava2:rxandroid:2.0.1'
18 |
19 | // Retrofit 生命周期管理框架
20 | compile 'com.trello.rxlifecycle2:rxlifecycle-kotlin:2.1.0'
21 | compile 'com.trello.rxlifecycle2:rxlifecycle-android-lifecycle-kotlin:2.1.0'
22 | compile 'com.trello.rxlifecycle2:rxlifecycle-components:2.1.0'
23 |
24 | // 基于rxjava 的6.0权限请求框架
25 | compile 'com.tbruyelle.rxpermissions2:rxpermissions:0.9.4@aar'
26 |
27 | //下拉刷新框架
28 | compile 'in.srain.cube:ultra-ptr:1.0.11'
29 | //图片加载框架
30 | compile 'com.github.bumptech.glide:glide:4.0.0-RC0'
31 |
32 | //图片查看库
33 | compile 'com.github.chrisbanes:PhotoView:2.1.2'
34 |
35 | ```
36 |
37 | ## 项目所运用到的一些知识
38 |
39 | - Kotlin
40 | - MVP + Retrofit + RxJava
41 | - RecycleView瀑布流
42 | - M D 风格
43 | - 抱歉,我编不出来了.....
44 |
45 |
46 | ## 项目截图
47 |
48 |  
49 |
50 |  
51 |
52 | 
53 |
54 | ## 感谢
55 |
56 | - 数据来源:[干货集中营](http://gank.io/)
57 | - 掘金客户端,没错我就是借(chao)鉴(xi)了部分UI
58 | - 当然还有大佬的[kotlin中文站](https://www.kotlincn.net/)
59 | - 感谢所有开源大佬
60 | - 还有感谢啥来着?
61 |
62 |
63 |
64 | 
65 |
66 | APK下载地址[GankForKotlin](https://fir.im/58qb?release_id=59671792959d696af40001d6)
67 |
68 |
69 |
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | apply plugin: 'kotlin-android'
4 | apply plugin: 'kotlin-android-extensions'
5 | android {
6 | compileSdkVersion 25
7 | buildToolsVersion "25.0.2"
8 | defaultConfig {
9 | applicationId "com.nightssky.gankforkotlin"
10 | minSdkVersion 21
11 | targetSdkVersion 25
12 | versionCode 1
13 | versionName "1.0"
14 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
15 | }
16 |
17 | buildTypes {
18 | release {
19 | minifyEnabled false
20 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
21 | }
22 | }
23 | }
24 |
25 | dependencies {
26 | compile fileTree(include: ['*.jar'], dir: 'libs')
27 | androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
28 | exclude group: 'com.android.support', module: 'support-annotations'
29 | })
30 | compile "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version"
31 | compile 'com.android.support:appcompat-v7:25.3.1'
32 | testCompile 'junit:junit:4.12'
33 | compile 'com.android.support:design:25.3.1'
34 | compile 'com.android.support.constraint:constraint-layout:1.0.2'
35 | compile 'com.android.support:support-v4:25.3.1'
36 | compile 'com.squareup.retrofit2:retrofit:2.3.0'
37 | compile 'com.squareup.retrofit2:converter-gson:2.3.0'
38 | compile 'com.squareup.retrofit2:adapter-rxjava2:2.3.0'
39 | compile 'io.reactivex.rxjava2:rxjava:2.1.0'
40 | compile 'io.reactivex.rxjava2:rxandroid:2.0.1'
41 | compile 'in.srain.cube:ultra-ptr:1.0.11'
42 | compile 'com.github.bumptech.glide:glide:4.0.0-RC0'
43 | compile 'com.android.support:cardview-v7:25.1.1'
44 | compile 'com.trello.rxlifecycle2:rxlifecycle-kotlin:2.1.0'
45 | compile 'com.trello.rxlifecycle2:rxlifecycle-android-lifecycle-kotlin:2.1.0'
46 | compile 'com.trello.rxlifecycle2:rxlifecycle-components:2.1.0'
47 |
48 | implementation 'com.android.support.constraint:constraint-layout:1.0.2'
49 | implementation 'com.android.support:support-v4:25.4.0'
50 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version"
51 | compile 'com.github.chrisbanes:PhotoView:2.1.2'
52 | compile 'com.tbruyelle.rxpermissions2:rxpermissions:0.9.4@aar'
53 | }
54 |
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in D:\studio\android-sdk-windows/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
19 | # Uncomment this to preserve the line number information for
20 | # debugging stack traces.
21 | #-keepattributes SourceFile,LineNumberTable
22 |
23 | # If you keep the line number information, uncomment this to
24 | # hide the original source file name.
25 | #-renamesourcefileattribute SourceFile
26 |
--------------------------------------------------------------------------------
/app/src/androidTest/java/com/nightssky/gankforkotlin/ExampleInstrumentedTest.kt:
--------------------------------------------------------------------------------
1 | package com.nightssky.gankforkotlin
2 |
3 | import android.support.test.InstrumentationRegistry
4 | import android.support.test.runner.AndroidJUnit4
5 |
6 | import org.junit.Test
7 | import org.junit.runner.RunWith
8 |
9 | import org.junit.Assert.*
10 |
11 | /**
12 | * Instrumentation 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 | @Throws(Exception::class)
20 | fun useAppContext() {
21 | // Context of the app under test.
22 | val appContext = InstrumentationRegistry.getTargetContext()
23 | assertEquals("com.nightssky.gankforkotlin", appContext.packageName)
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
16 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/app/src/main/java/com/nightssky/gankforkotlin/Model/Constants.kt:
--------------------------------------------------------------------------------
1 | package com.nightssky.gankforkotlin.Model
2 |
3 | import android.os.Environment
4 |
5 |
6 | /**
7 | * Created by user on 2017/6/15.
8 | */
9 | object Constants {
10 | var TYPELIST = mutableListOf("Android_T","iOS_T","休息视频_T","拓展资源_T","前端_T","福利_T")
11 |
12 | //记录是否改变
13 | var TABISCHANGED = false
14 |
15 | var dir = Environment.getExternalStorageDirectory().absolutePath + "/Gank/"
16 |
17 | }
18 |
19 | //扩展
20 | fun MutableList.getAllList():MutableList {
21 | var list:MutableList = mutableListOf()
22 | this.forEach {
23 | list.add( it.substring(0,it.length-2))
24 | }
25 | return list
26 | }
27 |
28 | /**
29 | * 只获取显示的类型
30 | */
31 | fun MutableList.getList():MutableList {
32 | var list:MutableList = mutableListOf()
33 | this.forEach {
34 | if (it[it.length-1].toString().equals("T")){
35 | list.add( it.substring(0,it.length-2))
36 | }
37 | }
38 | return list
39 | }
40 |
41 | /**
42 | * 设置是否显示
43 | */
44 | fun MutableList.setShow(position:Int,isChecked:Boolean) {
45 | var type = this[position]
46 | type = "${type.substring(0,type.length-1)}${if (isChecked)"T" else "F"}"
47 | this[position] = type
48 | }
49 | fun MutableList.getShow(position:Int):Boolean {
50 | var type = this[position]
51 | //不得不说这提示功能就是TMD强大
52 | //TMD巨坑
53 | return type[type.length-1].toString().equals("T")
54 | }
55 | //重新排序
56 | fun MutableList.swap(fromPosition: Int, toPosition: Int) {
57 | val tmp = this[fromPosition]
58 | this[fromPosition] = this[toPosition]
59 | this[toPosition] = tmp
60 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/nightssky/gankforkotlin/Model/Entity/GankData.kt:
--------------------------------------------------------------------------------
1 | package com.nightssky.gankforkotlin.Model.Entity
2 |
3 | import com.google.gson.annotations.SerializedName
4 | import java.util.*
5 |
6 | /**
7 | * Created by user on 2017/6/14.
8 | */
9 |
10 | data class historyData(var isError: Boolean,
11 | var results: List)
12 |
13 | data class DayData(var isError: Boolean,
14 | var results: ResultData,
15 | var category: List)
16 |
17 | data class ResultData(
18 | @SerializedName("Android")
19 | var android: List,
20 | @SerializedName("iOS")
21 | var ios: List,
22 | @SerializedName("休息视频")
23 | var video: List,
24 | @SerializedName("前端")
25 | var js: List,
26 | @SerializedName("拓展资源")
27 | var rec: List,
28 | @SerializedName("福利")
29 | var bonus: List)
30 |
31 | data class typeData(var isError: Boolean,
32 | var results: List)
33 | data class DetailsData(
34 | var desc: String,
35 | var publishedAt: Date,
36 | var type: String,
37 | var url: String,
38 | var who: String,
39 | var images: List,
40 | var width:Int,
41 | var height:Int)
42 |
43 | data class MeiziData(
44 | var url: String,
45 | var width:Int,
46 | var height:Int
47 | )
48 |
49 | data class SearchData(
50 | @SerializedName("count")
51 | var count: Int,
52 | var error: Boolean,
53 | var results: List)
54 |
55 | data class CategoryData(var desc: String,
56 | var publishedAt: String,
57 | var type: String,
58 | var url: String,
59 | var who: String)
60 |
61 |
62 |
63 |
--------------------------------------------------------------------------------
/app/src/main/java/com/nightssky/gankforkotlin/Model/GankDataModel.kt:
--------------------------------------------------------------------------------
1 | package com.nightssky.gankforkotlin.Model
2 |
3 | import android.Manifest
4 | import android.app.Activity
5 | import android.os.Environment
6 | import android.util.Log
7 | import com.bumptech.glide.Glide
8 | import com.bumptech.glide.request.target.Target
9 | import com.nightssky.gankforkotlin.Model.Entity.DayData
10 | import com.nightssky.gankforkotlin.Model.Entity.SearchData
11 | import com.nightssky.gankforkotlin.Model.Entity.typeData
12 | import com.nightssky.gankforkotlin.View.Common.MyApplication
13 | import com.nightssky.gankforkotlin.utils.FileUtils
14 | import com.nightssky.gankforkotlin.utils.toast
15 | import com.tbruyelle.rxpermissions2.RxPermissions
16 | import com.trello.rxlifecycle2.LifecycleProvider
17 | import com.trello.rxlifecycle2.android.ActivityEvent
18 | import com.trello.rxlifecycle2.android.FragmentEvent
19 | import io.reactivex.Observable
20 | import io.reactivex.Observer
21 | import io.reactivex.android.schedulers.AndroidSchedulers
22 | import io.reactivex.disposables.Disposable
23 | import io.reactivex.schedulers.Schedulers
24 | import java.io.File
25 | import java.util.*
26 |
27 |
28 |
29 |
30 |
31 |
32 | /**
33 | * Created by user on 2017/6/14.
34 | */
35 | class GankDataModel {
36 | val calendar:Calendar by lazy {
37 | Calendar.getInstance()
38 |
39 | }
40 |
41 | fun getHistoryDate(life: LifecycleProvider, listener: OnGetDataListener) {
42 | var observer = object : Observer {
43 | override fun onError(e: Throwable) {
44 | e.message?.let {
45 | }
46 | }
47 |
48 | override fun onSubscribe(d: Disposable) {
49 |
50 | }
51 |
52 | override fun onComplete() {
53 |
54 | }
55 |
56 | override fun onNext(t: Date) {
57 | t.let {
58 | calendar.time = t
59 | listener.success(calendar)
60 | }
61 | Log.d("msg", t.toString())
62 | }
63 |
64 |
65 | }
66 | HttpManager.getInstence.getHistoryDate(observer,life)
67 | }
68 |
69 |
70 | fun getDayData(year: Int, month: Int, day: Int, life: LifecycleProvider ,listener: OnGetDataListener) {
71 | val observer = object : Observer {
72 | override fun onNext(t: DayData) {
73 | t.let {
74 | listener.success(t)
75 | }
76 | Log.d("msg", t.toString())
77 | }
78 |
79 | override fun onSubscribe(d: Disposable) {
80 | }
81 |
82 | override fun onError(e: Throwable) {
83 |
84 | e.message?.let {
85 | listener.fail(e.message as String)
86 | }
87 |
88 | }
89 |
90 |
91 |
92 | override fun onComplete() {
93 | Log.d("msg", "onComplete")
94 |
95 | }
96 |
97 |
98 |
99 | }
100 | HttpManager.getInstence.getDayData(observer,year,month,day,life)
101 | }
102 | fun getTypeData(type:String, num:Int, page:Int, life: LifecycleProvider, TypeListener: OnGetDataListener){
103 | var observer = object :Observer{
104 | override fun onError(e: Throwable) {
105 | e.message?.let {
106 | TypeListener.fail(e.message as String)
107 | }
108 | }
109 |
110 | override fun onComplete() {
111 | }
112 |
113 | override fun onNext(t: typeData) {
114 | t?.let {
115 | TypeListener.success(t)
116 | }
117 | Log.d("msg", t.toString())
118 | }
119 |
120 | override fun onSubscribe(d: Disposable) {
121 | }
122 |
123 | }
124 | if (type.equals("福利")) {
125 | HttpManager.getInstence.getTypeData(observer, num, page, life)
126 | } else {
127 | HttpManager.getInstence.getTypeData(observer,type,num,page,life)
128 |
129 | }
130 |
131 | }
132 |
133 |
134 |
135 | fun getSearchData(query:String,category: String,page:Int, life: LifecycleProvider, TypeListener: OnGetDataListener){
136 | var observer = object :Observer{
137 | override fun onError(e: Throwable) {
138 | e.printStackTrace()
139 | e.message?.let {
140 | TypeListener.fail(e.message as String)
141 | }
142 | }
143 |
144 | override fun onComplete() {
145 | }
146 |
147 | override fun onNext(t: SearchData) {
148 | t?.let {
149 | TypeListener.success(t)
150 | }
151 | Log.d("msg", t.toString())
152 | }
153 |
154 | override fun onSubscribe(d: Disposable) {
155 | }
156 |
157 | }
158 | HttpManager.getInstence.getSearchData(observer,query,category,page,life)
159 |
160 | }
161 |
162 | /**
163 | * 保存图片
164 | *
165 | */
166 | fun downImage(rxPermissions:RxPermissions,activity: Activity,url:String) {
167 | rxPermissions.let {
168 | rxPermissions
169 | .request(Manifest.permission.WRITE_EXTERNAL_STORAGE )
170 | .subscribe { granted ->
171 | if (granted) { // Always true pre-M
172 | // I can control the camera now
173 | Observable.just(url)
174 | .subscribeOn(Schedulers.io())
175 | .map {
176 | val bitmap = Glide.with(MyApplication.context())
177 | .asBitmap()
178 | .load(url)
179 | .into(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL)
180 | .get()
181 | try {
182 |
183 | FileUtils.saveBitmap(bitmap,
184 | Environment
185 | .getExternalStorageDirectory().absolutePath
186 | +File.separator+Math.random())
187 |
188 | true
189 | } catch(e: Exception) {
190 | e.printStackTrace()
191 | false
192 | }finally {
193 | bitmap.recycle()
194 | }
195 | }
196 | .observeOn(AndroidSchedulers.mainThread())
197 | .subscribe(object :Observer{
198 | override fun onComplete() {
199 | }
200 | override fun onNext(t: Boolean) {
201 | if (t) {
202 | activity.toast("下载成功啦")
203 | } else {
204 | activity.toast("下载失败")
205 | }
206 | }
207 | override fun onSubscribe(d: Disposable) {
208 | }
209 | override fun onError(e: Throwable) {
210 | }
211 |
212 | })
213 | } else {
214 | // Oups permission denied
215 | activity.toast("下载失败,请在权限设置中打开所需权限")
216 | }
217 | }
218 | }
219 | }
220 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/nightssky/gankforkotlin/Model/GankService.kt:
--------------------------------------------------------------------------------
1 | package com.nightssky.gankforkotlin.Model
2 |
3 | import com.nightssky.gankforkotlin.Model.Entity.DayData
4 | import com.nightssky.gankforkotlin.Model.Entity.SearchData
5 | import com.nightssky.gankforkotlin.Model.Entity.historyData
6 | import com.nightssky.gankforkotlin.Model.Entity.typeData
7 | import io.reactivex.Observable
8 | import retrofit2.http.GET
9 | import retrofit2.http.Path
10 |
11 | /**
12 | * Created by 追寻何意?又往何处 on 2017/6/13.
13 | */
14 | interface GankService {
15 |
16 | /**
17 | * 获取发过干货日期接口:
18 | * http://gank.io/api/day/history
19 | */
20 | @GET("day/history")
21 | fun getHistoryDate():Observable
22 |
23 |
24 |
25 | /**
26 | * 每日推荐
27 | */
28 | @GET("day/{year}/{month}/{day}")
29 | fun getDayGanHuo(@Path("year") year: Int, @Path("month") month: Int
30 | , @Path("day") day: Int): Observable
31 |
32 | /**
33 | * 数据类型: 福利 | Android | iOS | 休息视频 | 拓展资源 | 前端 | all
34 | * 请求个数: 数字,大于0
35 | * 第几页:数字,大于0
36 | */
37 | @GET("data/{type}/{num}/{page}")
38 | fun getTypeData(@Path("type") type: String,@Path("num") num:Int
39 | ,@Path("page") page:Int): Observable
40 |
41 | /**
42 | * 搜索 API
43 | * http://gank.io/api/search/query/listview/category/Android/count/10/page/1
44 | * 注:
45 | * category 后面可接受参数 all | Android | iOS | 休息视频 | 福利 | 拓展资源 | 前端 | 瞎推荐 | App
46 | * count 最大 50
47 | */
48 | @GET("search/query/{query}/category/{category}/count/10/page/{page}")
49 | fun getSearchData(@Path("query") query: String,@Path("category") category:String
50 | ,@Path("page") page:Int): Observable
51 |
52 |
53 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/nightssky/gankforkotlin/Model/HttpManager.kt:
--------------------------------------------------------------------------------
1 | package com.nightssky.gankforkotlin.Model
2 |
3 | import com.bumptech.glide.Glide
4 | import com.bumptech.glide.request.target.Target
5 | import com.nightssky.gankforkotlin.Model.Entity.DayData
6 | import com.nightssky.gankforkotlin.Model.Entity.SearchData
7 | import com.nightssky.gankforkotlin.Model.Entity.typeData
8 | import com.nightssky.gankforkotlin.View.Common.MyApplication
9 | import com.trello.rxlifecycle2.LifecycleProvider
10 | import com.trello.rxlifecycle2.android.ActivityEvent
11 | import com.trello.rxlifecycle2.android.FragmentEvent
12 | import com.trello.rxlifecycle2.kotlin.bindToLifecycle
13 | import io.reactivex.Observer
14 | import io.reactivex.android.schedulers.AndroidSchedulers
15 | import io.reactivex.schedulers.Schedulers
16 | import okhttp3.OkHttpClient
17 | import retrofit2.Retrofit
18 | import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory
19 | import retrofit2.converter.gson.GsonConverterFactory
20 | import java.text.SimpleDateFormat
21 | import java.util.*
22 | import java.util.concurrent.TimeUnit
23 |
24 |
25 | /**
26 | * Created by 追寻何意?又往何处 on 2017/6/13.
27 | */
28 | class HttpManager
29 | private constructor() {
30 |
31 | private val retrofit: Retrofit
32 | private val contentService: GankService
33 | private val mOkHttpClient: OkHttpClient
34 |
35 | init {
36 | //手动创建一个OkHttpClient并设置超时时间和调试日志
37 |
38 | val httpClientBuilder = OkHttpClient.Builder()
39 | httpClientBuilder.connectTimeout(DEFAULT_TIMEOUT.toLong(), TimeUnit.SECONDS)
40 | mOkHttpClient = httpClientBuilder.build()
41 |
42 |
43 |
44 | retrofit = Retrofit.Builder().client(mOkHttpClient)
45 | .addConverterFactory(GsonConverterFactory.create())
46 | .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
47 | .baseUrl(GankUrl)
48 | .build()
49 |
50 | contentService = retrofit.create(GankService::class.java)
51 | }
52 |
53 | /**
54 | * 获取发布过干货的日期
55 | */
56 | fun getHistoryDate(subscriber: Observer, provider: LifecycleProvider) {
57 | contentService.getHistoryDate()
58 | .subscribeOn(Schedulers.io())
59 | .observeOn(AndroidSchedulers.mainThread())
60 | .bindToLifecycle(provider)
61 | .map {
62 | val list = it.results
63 | val str = list[0]
64 | val format1 = SimpleDateFormat("yyyy-MM-dd")
65 | val date = format1.parse(str)
66 | date
67 | }
68 | .subscribe(subscriber)
69 |
70 | }
71 |
72 | /**
73 | * 每日数据
74 | */
75 | fun getDayData(subscriber: Observer, year: Int, month: Int, day: Int,provider:LifecycleProvider) {
76 | contentService.getDayGanHuo(year, month, day)
77 | .subscribeOn(Schedulers.io())
78 | .unsubscribeOn(Schedulers.io())
79 | .observeOn(AndroidSchedulers.mainThread())
80 | .bindToLifecycle(provider)
81 | .subscribe(subscriber)
82 |
83 | }
84 |
85 | /**
86 | * 分类数据
87 | */
88 | fun getTypeData(subscriber: Observer,type:String,num:Int,page:Int,provider:LifecycleProvider){
89 | contentService.getTypeData(type,num,page)
90 | .subscribeOn(Schedulers.io())
91 | .observeOn(AndroidSchedulers.mainThread())
92 | .bindToLifecycle(provider)
93 | .subscribe(subscriber)
94 |
95 | }
96 |
97 | /**
98 | * 福利
99 | */
100 | fun getTypeData(subscriber: Observer,num:Int,page:Int,provider:LifecycleProvider){
101 | contentService.getTypeData("福利",num,page)
102 | .subscribeOn(Schedulers.io())
103 |
104 | .bindToLifecycle(provider)
105 | .map { typeData ->
106 | typeData.results.forEach {
107 | val bitmap = Glide.with(MyApplication.context())
108 | .asBitmap()
109 | .load(it.url)
110 | .into(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL)
111 | .get()
112 | it.width = bitmap.width
113 | it.height = bitmap.height
114 | bitmap.recycle()
115 | }
116 | typeData
117 | }
118 | .observeOn(AndroidSchedulers.mainThread())
119 | .subscribe(subscriber)
120 |
121 | }
122 | /**
123 | * 搜索数据
124 | */
125 | fun getSearchData(subscriber: Observer,query:String,category: String,page:Int,provider:LifecycleProvider) {
126 | contentService.getSearchData(query,category,page)
127 | .subscribeOn(Schedulers.io())
128 | .observeOn(AndroidSchedulers.mainThread())
129 | .bindToLifecycle(provider)
130 |
131 | .subscribe(subscriber)
132 | }
133 |
134 |
135 |
136 | //在访问HttpMethods时创建单例
137 | private object SingletonHolder {
138 | val INSTANCE = HttpManager()
139 | }
140 | companion object {
141 | private val DEFAULT_TIMEOUT = 5
142 | val GankUrl = "http://gank.io/api/"
143 | val getInstence: HttpManager
144 | get() = SingletonHolder.INSTANCE
145 |
146 | }
147 | }
148 |
149 |
--------------------------------------------------------------------------------
/app/src/main/java/com/nightssky/gankforkotlin/Model/OnGetDataListener.kt:
--------------------------------------------------------------------------------
1 | package com.nightssky.gankforkotlin.Model
2 |
3 | /**
4 | * Created by 追寻何意?又往何处 on 2017/5/29.
5 | */
6 |
7 | interface OnGetDataListener {
8 | fun success(response: T?)
9 | fun fail(msg: String)
10 | }
11 |
--------------------------------------------------------------------------------
/app/src/main/java/com/nightssky/gankforkotlin/Presenter/GankDataPresenter.kt:
--------------------------------------------------------------------------------
1 | package com.nightssky.gankforkotlin.Presenter
2 |
3 | import android.util.Log
4 | import com.nightssky.gankforkotlin.Model.Entity.DayData
5 | import com.nightssky.gankforkotlin.Model.Entity.DetailsData
6 | import com.nightssky.gankforkotlin.Model.Entity.typeData
7 | import com.nightssky.gankforkotlin.Model.GankDataModel
8 | import com.nightssky.gankforkotlin.Model.OnGetDataListener
9 | import com.nightssky.gankforkotlin.View.Contract.GankDataContract
10 | import com.trello.rxlifecycle2.components.support.RxFragment
11 | import java.util.*
12 |
13 | /**
14 | * Created by 追寻何意?又往何处 on 2017/6/14.
15 | */
16 | class GankDataPresenter(val View:GankDataContract.View) :GankDataContract.Presenter{
17 |
18 | val model: GankDataModel = GankDataModel()
19 |
20 | override fun start() {
21 | getHistoryDate()
22 | View.showProgress()
23 | }
24 | override fun getHistoryDate() {
25 | model.getHistoryDate(View as RxFragment,object : OnGetDataListener{
26 | override fun success(response: Calendar?) {
27 | response.let {
28 | getDayData(response!!)
29 | }
30 | }
31 | override fun fail(msg: String) {
32 |
33 | }
34 | })
35 | }
36 |
37 | override fun getDayData(calendar: Calendar) {
38 | model.getDayData(calendar.get(Calendar.YEAR),calendar.get(Calendar.MONTH)+1,calendar.get(Calendar.DAY_OF_MONTH)
39 | ,View as RxFragment,object :OnGetDataListener{
40 | override fun success(response: DayData?) {
41 | response?.let {
42 | var list = mutableListOf()
43 | response.category.forEach {
44 | when (it) {
45 | "Android" -> list.addAll(response.results.android)
46 | "休息视频" -> list.addAll(response.results.video)
47 | "福利" -> list.addAll(response.results.bonus)
48 | "iOS" -> list.addAll(response.results.ios)
49 | "前端" -> list.addAll(response.results.js )
50 | }
51 | }
52 | View.setData(list)
53 | }
54 | }
55 |
56 | override fun fail(msg: String) {
57 | View.setEmpty()
58 | }
59 |
60 | })
61 | }
62 | override fun getTypeData(type: String, num: Int, page: Int) {
63 | model.getTypeData(type,num,page,View as RxFragment,object :OnGetDataListener{
64 | override fun success(response: typeData?) {
65 |
66 | response?.let{
67 | View.setData(response.results)
68 | }
69 |
70 |
71 | }
72 |
73 | override fun fail(msg: String) {
74 | Log.e("msg", msg)
75 | View.setEmpty()
76 | }
77 |
78 | })
79 | }
80 |
81 | /**
82 | * 加载更多
83 | */
84 | override fun loadMore(type: String, num: Int, page: Int) {
85 | model.getTypeData(type,num,page,View as RxFragment,object :OnGetDataListener{
86 | override fun success(response: typeData?) {
87 |
88 | response?.let{
89 | if (response.results.size > 0) {
90 | View.addData(response.results)
91 | }
92 | }
93 |
94 | }
95 |
96 | override fun fail(msg: String) {
97 |
98 | }
99 |
100 | })
101 | }
102 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/nightssky/gankforkotlin/Presenter/SearchPresenter.kt:
--------------------------------------------------------------------------------
1 | package com.nightssky.gankforkotlin.Presenter
2 |
3 | import com.nightssky.gankforkotlin.Model.Entity.SearchData
4 | import com.nightssky.gankforkotlin.Model.GankDataModel
5 | import com.nightssky.gankforkotlin.Model.OnGetDataListener
6 | import com.nightssky.gankforkotlin.View.Contract.SearchContract
7 | import com.trello.rxlifecycle2.components.support.RxAppCompatActivity
8 |
9 | /**
10 | * Created by user on 2017/7/3.
11 | */
12 | class SearchPresenter (val View: SearchContract.View) :SearchContract.Presenter {
13 |
14 | val model: GankDataModel = GankDataModel()
15 | override fun getSearchData(query: String, category: String, page: Int) {
16 | model.getSearchData(query,category,page,View as RxAppCompatActivity,object :OnGetDataListener{
17 | override fun success(response: SearchData?) {
18 | response?.let{
19 | View.setData(response.results)
20 | }
21 | }
22 |
23 | override fun fail(msg: String) {
24 | View.hideProgress()
25 | View.setEmpty()
26 | }
27 |
28 | })
29 | }
30 |
31 | override fun loadMore(query: String, category: String, page: Int) {
32 | model.getSearchData(query,category,page,View as RxAppCompatActivity,object :OnGetDataListener{
33 | override fun success(response: SearchData?) {
34 | response?.let{
35 |
36 | View.addData(response.results)
37 | }
38 | }
39 |
40 | override fun fail(msg: String) {
41 | View.hideProgress()
42 | }
43 |
44 | })
45 | }
46 |
47 | override fun start() {
48 |
49 | }
50 |
51 |
52 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/nightssky/gankforkotlin/View/Activity/ImageActivity.kt:
--------------------------------------------------------------------------------
1 | package com.nightssky.gankforkotlin.View.Activity
2 |
3 | import android.graphics.Color
4 | import android.os.Build.VERSION
5 | import android.os.Build.VERSION_CODES
6 | import android.os.Bundle
7 | import android.support.v7.app.AppCompatActivity
8 | import android.view.View
9 | import android.view.WindowManager
10 | import com.bumptech.glide.Glide
11 | import com.bumptech.glide.load.engine.DiskCacheStrategy
12 | import com.bumptech.glide.request.RequestOptions
13 | import com.nightssky.gankforkotlin.Model.GankDataModel
14 | import com.nightssky.gankforkotlin.R
15 | import com.tbruyelle.rxpermissions2.RxPermissions
16 | import kotlinx.android.synthetic.main.activity_image.*
17 |
18 |
19 | class ImageActivity : AppCompatActivity() {
20 |
21 | val rxPermissions:RxPermissions by lazy {
22 | RxPermissions(this)
23 | }
24 | override fun onCreate(savedInstanceState: Bundle?) {
25 | super.onCreate(savedInstanceState)
26 | if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
27 | val window = window
28 | window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS or WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION)
29 | window.decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION or View.SYSTEM_UI_FLAG_LAYOUT_STABLE
30 | window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS)
31 | window.statusBarColor = Color.TRANSPARENT
32 | window.navigationBarColor = Color.TRANSPARENT
33 | }
34 | setContentView(R.layout.activity_image)
35 | initView()
36 | }
37 |
38 | private fun initView() {
39 | toolbar.setNavigationIcon(R.drawable.ic_back)
40 | toolbar.setNavigationOnClickListener {
41 | finish()
42 | }
43 | val url = intent.getStringExtra("url")
44 | url.let {
45 | val options = RequestOptions()
46 | .centerCrop()
47 | .diskCacheStrategy(DiskCacheStrategy.ALL)
48 | Glide.with(this)
49 | .load(url)
50 | .apply (options)
51 | .into(photo_view)
52 | }
53 |
54 | down.setOnClickListener {
55 | val model = GankDataModel()
56 | model.downImage(rxPermissions,this,url)
57 | }
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/app/src/main/java/com/nightssky/gankforkotlin/View/Activity/LabelActivity.kt:
--------------------------------------------------------------------------------
1 | package com.nightssky.gankforkotlin.View.Activity
2 |
3 | import android.os.Bundle
4 | import android.support.v7.app.AppCompatActivity
5 | import android.support.v7.widget.DividerItemDecoration
6 | import android.support.v7.widget.LinearLayoutManager
7 | import android.support.v7.widget.RecyclerView
8 | import android.support.v7.widget.helper.ItemTouchHelper
9 | import com.nightssky.gankforkotlin.R
10 | import com.nightssky.gankforkotlin.View.Adapter.LabelAdapter
11 | import com.nightssky.gankforkotlin.View.Widget.DragHelper.OnStartDragListener
12 | import com.nightssky.gankforkotlin.View.Widget.DragHelper.SimpleItemTouchHelperCallback
13 | import kotlinx.android.synthetic.main.activity_label.*
14 |
15 |
16 | class LabelActivity : AppCompatActivity(),OnStartDragListener {
17 |
18 | private var mItemTouchHelper:ItemTouchHelper?= null
19 |
20 | override fun onCreate(savedInstanceState: Bundle?) {
21 | super.onCreate(savedInstanceState)
22 | setContentView(R.layout.activity_label)
23 | toolbar.setNavigationIcon(R.drawable.ic_back)
24 | toolbar.setNavigationOnClickListener {
25 | finish()
26 | }
27 | recyclerView.layoutManager = LinearLayoutManager(this)
28 | recyclerView.setHasFixedSize(true)
29 | recyclerView.addItemDecoration(DividerItemDecoration(this,DividerItemDecoration.VERTICAL))
30 | val adapter = LabelAdapter(this)
31 | recyclerView.adapter = adapter
32 | val callback = SimpleItemTouchHelperCallback(adapter)
33 | mItemTouchHelper = ItemTouchHelper(callback)
34 | mItemTouchHelper!!.attachToRecyclerView(recyclerView)
35 | }
36 |
37 | override fun onStartDrag(viewHolder: RecyclerView.ViewHolder?) {
38 | mItemTouchHelper?.startDrag(viewHolder)
39 | }
40 |
41 | }
42 |
--------------------------------------------------------------------------------
/app/src/main/java/com/nightssky/gankforkotlin/View/Activity/MainActivity.kt:
--------------------------------------------------------------------------------
1 | package com.nightssky.gankforkotlin.View.Activity
2 |
3 | import android.content.Intent
4 | import android.os.Bundle
5 | import android.support.design.widget.TabLayout
6 | import android.support.v4.app.Fragment
7 | import android.support.v4.app.FragmentManager
8 | import android.support.v4.app.FragmentStatePagerAdapter
9 | import android.support.v4.view.PagerAdapter
10 | import android.support.v7.app.AppCompatActivity
11 | import com.nightssky.gankforkotlin.Model.Constants
12 | import com.nightssky.gankforkotlin.Model.getList
13 | import com.nightssky.gankforkotlin.R
14 | import com.nightssky.gankforkotlin.View.Contract.MainContract
15 | import com.nightssky.gankforkotlin.View.Fragment.MeiziFragment
16 | import com.nightssky.gankforkotlin.View.Fragment.RecommendFragment
17 | import com.nightssky.gankforkotlin.View.Fragment.TypeFragment
18 | import kotlinx.android.synthetic.main.activity_main.*
19 |
20 |
21 |
22 | class MainActivity : AppCompatActivity(),MainContract.View {
23 |
24 |
25 | private lateinit var list: MutableList
26 |
27 |
28 | override fun onCreate(savedInstanceState: Bundle?) {
29 | super.onCreate(savedInstanceState)
30 | setContentView(R.layout.activity_main)
31 | setView()
32 | setViewPager()
33 | }
34 |
35 | override fun setView() {
36 | toolbar.title = "GankForKotlin"
37 | setTabLayout()
38 | label.setOnClickListener({
39 | startActivity(Intent(MainActivity@this,LabelActivity::class.java ))
40 | })
41 | search.setOnClickListener({ startActivity(Intent(MainActivity@this,SearchActivity::class.java ))})
42 |
43 | }
44 |
45 | fun setTabLayout() {
46 | tablayout.addTab(tablayout.newTab().setText("每日推荐"))
47 | Constants.TYPELIST.getList().forEach {
48 |
49 | tablayout.addTab(tablayout.newTab().setText(it))
50 | }
51 | }
52 | override fun setViewPager() {
53 | tablayout.addOnTabSelectedListener(object : TabLayout.OnTabSelectedListener {
54 | override fun onTabReselected(tab: TabLayout.Tab?) {}
55 | override fun onTabUnselected(p0: TabLayout.Tab?) {}
56 | override fun onTabSelected(tab: TabLayout.Tab?) {
57 | container.currentItem = tab!!.position;
58 |
59 | }
60 |
61 | })
62 | container.addOnPageChangeListener(object : TabLayout.TabLayoutOnPageChangeListener(tablayout) {})
63 | setFAdapter()
64 | }
65 |
66 | fun setFAdapter() {
67 | list = mutableListOf()
68 | list.add(RecommendFragment())
69 | Constants.TYPELIST.getList().forEach {
70 | when {
71 | it.equals("福利") -> list.add(MeiziFragment())
72 | else -> list.add(TypeFragment().setType(it))
73 | }
74 | }
75 | //ViewPager的适配器
76 | var adapter: MyAdapter = MyAdapter(supportFragmentManager);
77 | container.adapter = adapter;
78 | }
79 |
80 | override fun onResume() {
81 | super.onResume()
82 | if (Constants.TABISCHANGED) {
83 | tablayout.removeAllTabs()
84 | setTabLayout()
85 | container.removeAllViews()
86 | setFAdapter()
87 | Constants.TABISCHANGED = false
88 | }
89 |
90 | }
91 |
92 | internal inner class MyAdapter(fm: FragmentManager) : FragmentStatePagerAdapter(fm) {
93 | override fun getItem(position: Int): Fragment {
94 | return list[position]
95 | }
96 |
97 | override fun getCount(): Int {
98 | return list.size
99 | }
100 | override fun getPageTitle(position: Int): CharSequence = Constants.TYPELIST[position]
101 |
102 |
103 | override fun getItemPosition(`object`: Any?): Int = PagerAdapter.POSITION_NONE
104 |
105 | }
106 |
107 | }
108 |
--------------------------------------------------------------------------------
/app/src/main/java/com/nightssky/gankforkotlin/View/Activity/SearchActivity.kt:
--------------------------------------------------------------------------------
1 | package com.nightssky.gankforkotlin.View.Activity
2 |
3 | import android.animation.AnimatorSet
4 | import android.animation.ObjectAnimator
5 | import android.content.Context
6 | import android.content.Intent
7 | import android.os.Bundle
8 | import android.support.v4.view.ViewCompat
9 | import android.support.v7.widget.LinearLayoutManager
10 | import android.support.v7.widget.RecyclerView
11 | import android.text.Editable
12 | import android.text.TextUtils
13 | import android.text.TextWatcher
14 | import android.view.MotionEvent
15 | import android.view.View
16 | import android.view.inputmethod.InputMethodManager
17 | import android.widget.EditText
18 | import com.nightssky.gankforkotlin.Model.Entity.CategoryData
19 | import com.nightssky.gankforkotlin.Presenter.SearchPresenter
20 | import com.nightssky.gankforkotlin.R
21 | import com.nightssky.gankforkotlin.View.Adapter.BaseRecycleViewAdapter
22 | import com.nightssky.gankforkotlin.View.Adapter.SearchAdapter
23 | import com.nightssky.gankforkotlin.View.Contract.SearchContract
24 | import com.trello.rxlifecycle2.components.support.RxAppCompatActivity
25 | import kotlinx.android.synthetic.main.activity_search.*
26 |
27 |
28 |
29 | class SearchActivity : RxAppCompatActivity(),SearchContract.View {
30 |
31 | private val presenter = SearchPresenter(this)
32 | lateinit var adapter:SearchAdapter
33 | private var pageIndex = 2
34 | override fun onCreate(savedInstanceState: Bundle?) {
35 | super.onCreate(savedInstanceState)
36 | setContentView(R.layout.activity_search)
37 | setView()
38 |
39 | }
40 | override fun setView() {
41 | toolbar.setNavigationIcon(R.drawable.ic_back)
42 | toolbar.setNavigationOnClickListener {
43 | finish()
44 | }
45 | search_view.addTextChangedListener(object:TextWatcher{
46 | override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
47 |
48 | override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {}
49 |
50 | override fun afterTextChanged(s: Editable?) {
51 | showProgress()
52 | if (!TextUtils.isEmpty(search_view.text.toString())) {
53 | presenter.getSearchData(search_view.text.toString(),category.text.toString(),1)
54 | }
55 | }
56 |
57 | })
58 | search_recycler.setHasFixedSize(true)
59 | search_recycler.layoutManager = LinearLayoutManager(this) as RecyclerView.LayoutManager?
60 | adapter = SearchAdapter(R.layout.item_gank_recycle_view)
61 | search_recycler.adapter = adapter
62 | adapter.setItemClickListener(object : BaseRecycleViewAdapter.onItemClickListener{
63 | override fun onItemClick(position: Int, v: View) {
64 | val data = adapter.getItem(position)
65 | if (data?.type.equals("福利")) {
66 | startActivity(Intent(this@SearchActivity, ImageActivity::class.java)
67 | .putExtra("url",data?.url))
68 | } else {
69 | startActivity(Intent(this@SearchActivity, WebActivity::class.java)
70 | .putExtra("URL",data?.url))
71 | }
72 |
73 |
74 | }
75 |
76 | })
77 | search_recycler.addOnScrollListener(object : RecyclerView.OnScrollListener() {
78 | override fun onScrollStateChanged(recyclerView: RecyclerView?, newState: Int) {
79 | super.onScrollStateChanged(recyclerView, newState)
80 | if (newState == RecyclerView.SCROLL_STATE_IDLE) {
81 | if (!ViewCompat.canScrollVertically(recyclerView, 1)){
82 | if (anim_layout.visibility == View.GONE) {
83 | loadMore()
84 | }
85 |
86 | }
87 | }
88 | }
89 | })
90 |
91 | }
92 |
93 | override fun setData(list: List) {
94 | adapter.setData(list)
95 | hideProgress()
96 | }
97 |
98 | override fun addData(list: List) {
99 | adapter.addData(list)
100 | hideProgress()
101 | }
102 |
103 | override fun setEmpty() {
104 | empty_view.visibility = View.VISIBLE
105 | }
106 |
107 | override fun showProgress() {
108 | anim_layout.visibility = View.VISIBLE
109 | val animatorx = ObjectAnimator.ofFloat(anim_layout,"scaleX",0f,1f)
110 | val animatory = ObjectAnimator.ofFloat(anim_layout,"scaleY",0f,1f)
111 | val animSet = AnimatorSet()
112 | animSet.duration = 1000
113 | animSet.play(animatorx).with(animatory)
114 | animSet.start()
115 | }
116 |
117 | override fun hideProgress() {
118 | anim_layout.visibility = View.GONE
119 | }
120 | override fun loadMore() {
121 | showProgress()
122 | presenter.loadMore(search_view.text.toString(),category.text.toString(),pageIndex++)
123 | }
124 |
125 |
126 |
127 | val imm:InputMethodManager by lazy {
128 | getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
129 | }
130 |
131 | /**
132 | * 判断点击按下是否在EditText上
133 |
134 | * @param v
135 | * *
136 | * @param event
137 | * *
138 | * @return
139 | */
140 | private fun isShouldHideInput(v: View?, event: MotionEvent): Boolean {
141 | if (v != null && v is EditText) {
142 | val leftTop = intArrayOf(0, 0)
143 | //获取输入框当前的location位置
144 | v.getLocationInWindow(leftTop)
145 | val left = leftTop[0]
146 | val top = leftTop[1]
147 | val bottom = top + v.height
148 | val right = left + v.width
149 | return !(event.x > left && event.x < right && event.y > top && event.y < bottom)
150 | }
151 | return false
152 | }
153 |
154 | override fun dispatchTouchEvent(ev: MotionEvent): Boolean {
155 | if (ev.action == MotionEvent.ACTION_DOWN) {
156 | val v = currentFocus
157 | if (isShouldHideInput(v, ev)) {
158 | if (imm != null) {
159 | imm.hideSoftInputFromWindow(v!!.windowToken, 0)
160 | }
161 | }
162 | return super.dispatchTouchEvent(ev)
163 | }
164 | // 必不可少,否则所有的组件都不会有TouchEvent了
165 | if (window.superDispatchTouchEvent(ev)) {
166 | return true
167 | }
168 | return onTouchEvent(ev)
169 | }
170 | }
171 |
--------------------------------------------------------------------------------
/app/src/main/java/com/nightssky/gankforkotlin/View/Activity/SplashActivity.kt:
--------------------------------------------------------------------------------
1 | package com.nightssky.gankforkotlin.View.Activity
2 |
3 | import android.content.Intent
4 | import android.graphics.Color
5 | import android.os.Build
6 | import android.os.Bundle
7 | import android.os.Handler
8 | import android.support.v7.app.AppCompatActivity
9 | import android.view.View
10 | import android.view.WindowManager
11 |
12 | class SplashActivity : AppCompatActivity() {
13 | private val SPLASH_LENGTH: Long = 2000
14 | var handler = Handler()
15 | override fun onCreate(savedInstanceState: Bundle?) {
16 | super.onCreate(savedInstanceState)
17 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
18 | val window = window
19 | window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS or WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION)
20 | window.decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION or View.SYSTEM_UI_FLAG_LAYOUT_STABLE
21 | window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS)
22 | window.statusBarColor = Color.TRANSPARENT
23 | window.navigationBarColor = Color.TRANSPARENT
24 | }
25 | handler.postDelayed({
26 | val intent = Intent(this@SplashActivity, MainActivity::class.java)
27 | startActivity(intent)
28 | finish()
29 | }, SPLASH_LENGTH)
30 | }
31 |
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/app/src/main/java/com/nightssky/gankforkotlin/View/Activity/WebActivity.kt:
--------------------------------------------------------------------------------
1 | package com.nightssky.gankforkotlin.View.Activity
2 |
3 | import android.content.ActivityNotFoundException
4 | import android.content.ClipboardManager
5 | import android.content.Context
6 | import android.content.Intent
7 | import android.net.Uri
8 | import android.os.Bundle
9 | import android.support.design.widget.Snackbar
10 | import android.support.v7.app.AppCompatActivity
11 | import android.view.Menu
12 | import android.view.MenuItem
13 | import android.view.View
14 | import android.webkit.WebChromeClient
15 | import android.webkit.WebSettings
16 | import android.webkit.WebView
17 | import android.webkit.WebViewClient
18 | import com.nightssky.gankforkotlin.R
19 | import kotlinx.android.synthetic.main.activity_web.*
20 |
21 |
22 |
23 | class WebActivity : AppCompatActivity() {
24 |
25 | private var URL: String? = null
26 |
27 | override fun onCreate(savedInstanceState: Bundle?) {
28 | super.onCreate(savedInstanceState)
29 | setContentView(R.layout.activity_web)
30 |
31 | val intent = intent
32 | val bundle = intent.extras
33 | if (bundle != null) {
34 | URL = bundle.getString("URL")
35 | }
36 |
37 | setSupportActionBar(tl_web)
38 | tl_web.setNavigationIcon(R.drawable.ic_back)
39 | initWebViewSettings()
40 |
41 | wv_content.removeJavascriptInterface("searchBoxJavaBridge_")
42 | wv_content.removeJavascriptInterface("accessibilityTraversal")
43 | wv_content.removeJavascriptInterface("accessibility")
44 | wv_content.loadUrl(URL)
45 | }
46 |
47 | public override fun onPause() {
48 | super.onPause()
49 | wv_content?.let { it.onPause() }
50 | }
51 |
52 | public override fun onResume() {
53 | super.onResume()
54 | wv_content?.let { it.onResume() }
55 | }
56 |
57 | public override fun onDestroy() {
58 | super.onDestroy()
59 | wv_content?.let { it.destroy() }
60 | }
61 |
62 | override fun onCreateOptionsMenu(menu: Menu): Boolean {
63 | menuInflater.inflate(R.menu.web_menu, menu)
64 | return true
65 | }
66 |
67 | override fun onOptionsItemSelected(item: MenuItem): Boolean {
68 | when (item.itemId) {
69 | android.R.id.home -> {
70 | finish()
71 | }
72 | R.id.share -> {//share url with system share windows
73 | URL?.let { share(it) }
74 | }
75 | R.id.openinbrowse -> {
76 | URL?.let { browse(it) }
77 | }
78 | R.id.copyurl -> {
79 | val clipboardManager = getSystemService(
80 | Context.CLIPBOARD_SERVICE) as ClipboardManager
81 | clipboardManager.text = URL
82 | Snackbar.make(tl_web, "已复制到剪切板", Snackbar.LENGTH_SHORT).show()
83 | }
84 | R.id.refresh -> {
85 | wv_content.reload()
86 | }
87 | else -> {
88 | }
89 | }
90 | return true
91 | }
92 |
93 | private fun initWebViewSettings() {
94 | val settings = wv_content.settings
95 | settings.javaScriptEnabled = true
96 | settings.loadWithOverviewMode = true
97 | settings.setAppCacheEnabled(true)
98 | settings.layoutAlgorithm = WebSettings.LayoutAlgorithm.SINGLE_COLUMN
99 | settings.setSupportZoom(true)
100 | settings.savePassword = false
101 | wv_content.setWebChromeClient(object : WebChromeClient() {
102 | override fun onProgressChanged(view: WebView, newProgress: Int) {
103 | super.onProgressChanged(view, newProgress)
104 | progressbar.progress = newProgress
105 | if (newProgress == 100) {
106 | progressbar.visibility = View.GONE
107 | } else {
108 | progressbar.visibility = View.VISIBLE
109 | }
110 | }
111 |
112 |
113 | override fun onReceivedTitle(view: WebView, title: String) {
114 | super.onReceivedTitle(view, title)
115 | setTitle(title)
116 | }
117 | })
118 | wv_content.setWebViewClient(object : WebViewClient() {
119 | override fun shouldOverrideUrlLoading(view: WebView, url: String?): Boolean {
120 | url?.let { view.loadUrl(it) }
121 | return true
122 | }
123 | })
124 | }
125 | }
126 |
127 | fun Context.share(text: String, subject: String = ""): Boolean {
128 | try {
129 | val intent = Intent(Intent.ACTION_SEND)
130 | intent.type = "text/plain"
131 | intent.putExtra(android.content.Intent.EXTRA_SUBJECT, subject)
132 | intent.putExtra(android.content.Intent.EXTRA_TEXT, text)
133 | startActivity(Intent.createChooser(intent, null))
134 | return true
135 | } catch (e: ActivityNotFoundException) {
136 | e.printStackTrace()
137 | return false
138 | }
139 | }
140 |
141 | fun Context.browse(url: String, newTask: Boolean = false): Boolean {
142 | try {
143 | val intent = Intent(Intent.ACTION_VIEW)
144 | intent.data = Uri.parse(url)
145 | if (newTask) {
146 | intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
147 | }
148 | startActivity(intent)
149 | return true
150 | } catch (e: ActivityNotFoundException) {
151 | e.printStackTrace()
152 | return false
153 | }
154 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/nightssky/gankforkotlin/View/Adapter/BaseRecycleViewAdapter.kt:
--------------------------------------------------------------------------------
1 | package com.nightssky.gankforkotlin.View.Adapter
2 |
3 | import android.support.v7.widget.RecyclerView
4 | import android.util.SparseArray
5 | import android.view.LayoutInflater
6 | import android.view.View
7 | import android.view.ViewGroup
8 | import android.widget.TextView
9 | import java.util.*
10 |
11 | /**
12 | * Created by user on 2017/3/31.
13 | */
14 | //D(实体类)和VH分别代表了的 数据源、ViewHold
15 | abstract class BaseRecycleViewAdapter : RecyclerView.Adapter, View.OnClickListener {
16 | private var mList: MutableList? = null
17 | private var layoutResId: Int = 0
18 | private var clickListener: onItemClickListener? = null
19 |
20 | constructor(list: MutableList, layoutResId: Int) {
21 | mList = list
22 |
23 | if (layoutResId != 0) {
24 | this.layoutResId = layoutResId
25 | } else {
26 | throw NullPointerException("请设置Item资源id")
27 | }
28 | }
29 |
30 | constructor(layoutResId: Int) {
31 | mList = ArrayList()
32 | if (layoutResId != 0) {
33 | this.layoutResId = layoutResId
34 | } else {
35 | throw NullPointerException("请设置Item资源id")
36 | }
37 | }
38 |
39 | override fun getItemViewType(position: Int): Int {
40 | return super.getItemViewType(position)
41 | }
42 |
43 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): VH {
44 | val view = LayoutInflater.from(parent.context).inflate(layoutResId, parent, false)
45 | return BaseViewHolder(view) as VH
46 | }
47 |
48 | //添加数据
49 | fun addData(list: List) {
50 | val size = this.mList!!.size
51 | this.mList!!.addAll(list)
52 | notifyItemInserted(size + 1)
53 | }
54 |
55 | //更新数据
56 | fun setData(list: List) {
57 | if (mList!!.size > 0) {
58 | mList!!.clear()
59 | }
60 | mList!!.addAll(list)
61 | notifyDataSetChanged()
62 | }
63 |
64 | override fun onBindViewHolder(holder: VH, position: Int) {
65 | holder.itemView.setOnClickListener(this)
66 | holder.itemView.tag = position
67 | bindTheData(holder, mList!![position], position)
68 | }
69 |
70 | /**
71 | * 绑定数据
72 |
73 | * @param holder 视图管理者
74 | * *
75 | * @param data 数据源
76 | */
77 | protected abstract fun bindTheData(holder: VH, data: D, position: Int)
78 |
79 | // override fun getItemCount(): Int {
80 | // return mList!!.size
81 | // }
82 | override fun getItemCount()= mList!!.size
83 |
84 | override fun onClick(v: View) {
85 | //点击回调
86 | if (clickListener != null) {
87 | clickListener!!.onItemClick(v.tag as Int, v)
88 | }
89 | }
90 |
91 | fun getItem(position: Int): D? {
92 | if (position < mList!!.size) {
93 | return mList!![position]
94 | }
95 | return null
96 | }
97 |
98 | /**
99 | * 自定义ViewHolder
100 | */
101 | class BaseViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
102 | private val views: SparseArray = SparseArray()
103 |
104 | fun findViewById(resId: Int): T {
105 | var view: View? = views.get(resId)
106 | if (view == null) {
107 | view = itemView.findViewById(resId)
108 | views.put(resId, view)
109 | }
110 | return view as T
111 | }
112 |
113 | /**
114 | * 设置文本资源
115 |
116 | * @param viewId view id
117 | * *
118 | * @param s 字符
119 | */
120 | fun setText(viewId: Int, s: CharSequence): TextView {
121 | val view = findViewById(viewId)
122 | view.text = s
123 | return view
124 | }
125 |
126 | // /**
127 | // * 设置图片
128 | // * @param viewId
129 | // * *
130 | // * @param url
131 | // * *
132 | // * @return
133 | // */
134 | // fun setImg(viewId: Int, url: CharSequence): ImageView {
135 | // val view = findViewById(viewId)
136 | // // Glide.with(MyApplication.getInstance())
137 | // // .load(url)
138 | // // .placeholder(R.mipmap.image_loading)
139 | // // .crossFade(100)
140 | // // .diskCacheStrategy(DiskCacheStrategy.SOURCE)
141 | // // .centerCrop()
142 | // // .into(view);
143 | // return view
144 | // }
145 |
146 | fun getView(viewId: Int): View {
147 | val view = findViewById(viewId)
148 | return view
149 | }
150 | }
151 |
152 | /**
153 | * 设置点击监听
154 |
155 | * @param clickListener 监听器
156 | */
157 | fun setItemClickListener(clickListener: onItemClickListener) {
158 | this.clickListener = clickListener
159 | }
160 |
161 | interface onItemClickListener {
162 | fun onItemClick(position: Int, v: View)
163 | }
164 |
165 | interface onItemLongClickListener {
166 | fun onItemLonClick(position: Int, v: View): Boolean
167 | }
168 | }
169 |
--------------------------------------------------------------------------------
/app/src/main/java/com/nightssky/gankforkotlin/View/Adapter/GankAdapter.kt:
--------------------------------------------------------------------------------
1 | package com.nightssky.gankforkotlin.View.Adapter
2 |
3 | import android.view.View
4 | import android.widget.ImageView
5 | import com.bumptech.glide.Glide
6 | import com.nightssky.gankforkotlin.Model.Entity.DetailsData
7 | import com.nightssky.gankforkotlin.R
8 | import com.nightssky.gankforkotlin.View.Common.MyApplication
9 | import java.text.SimpleDateFormat
10 |
11 | /**
12 | * Created by user on 2017/6/14.
13 | */
14 | class GankAdapter : BaseRecycleViewAdapter {
15 | constructor(layoutResId: Int) : super(layoutResId)
16 |
17 |
18 |
19 | override fun bindTheData(holder: BaseViewHolder, data: DetailsData, position: Int) {
20 | holder.setText(R.id.gank_title, data.desc)
21 | data.who?.let {
22 |
23 | holder.setText(R.id.who, data.who)
24 | }
25 | val image = holder.getView(R.id.image) as ImageView
26 |
27 | if (data.type.equals("福利")) {
28 | image.visibility = View.VISIBLE
29 | Glide.with(MyApplication.context())
30 | .load(data.url)
31 | .into(image)
32 | } else if (data.images == null) {
33 | image.visibility = View.GONE
34 | } else {
35 | image.visibility = View.VISIBLE
36 |
37 | Glide.with(MyApplication.context())
38 | .load(data.images[0])
39 | .into(image)
40 | }
41 |
42 |
43 | holder.setText(R.id.type, data.type)
44 | // 初始化时设置 日期和时间模式
45 | var sdf = SimpleDateFormat("yyyy/MM/dd HH:mm:ss.SSS");
46 | // 修改日期和时间模式
47 | sdf.applyPattern("yyyy-MM-dd ")
48 | var dateStr = sdf.format(data.publishedAt);
49 | holder.setText(R.id.time, dateStr)
50 |
51 | }
52 |
53 |
54 |
55 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/nightssky/gankforkotlin/View/Adapter/LabelAdapter.kt:
--------------------------------------------------------------------------------
1 | package com.nightssky.gankforkotlin.View.Adapter
2 |
3 | import android.graphics.Color
4 | import android.support.v4.view.MotionEventCompat
5 | import android.support.v7.widget.RecyclerView
6 | import android.view.LayoutInflater
7 | import android.view.MotionEvent
8 | import android.view.View
9 | import android.view.ViewGroup
10 | import android.widget.ImageView
11 | import android.widget.Switch
12 | import android.widget.TextView
13 | import com.nightssky.gankforkotlin.Model.*
14 | import com.nightssky.gankforkotlin.R
15 | import com.nightssky.gankforkotlin.View.Widget.DragHelper.ItemTouchHelperAdapter
16 | import com.nightssky.gankforkotlin.View.Widget.DragHelper.ItemTouchHelperViewHolder
17 | import com.nightssky.gankforkotlin.View.Widget.DragHelper.OnStartDragListener
18 |
19 | /**
20 | * Created by 追寻何意?又往何处 on 2017/6/15.
21 | */
22 | class LabelAdapter : RecyclerView.Adapter,ItemTouchHelperAdapter {
23 |
24 | private var mDragStartListener: OnStartDragListener? = null
25 |
26 | constructor(mDragStartListener: OnStartDragListener){
27 | this.mDragStartListener = mDragStartListener
28 |
29 | }
30 |
31 | override fun onCreateViewHolder(parent: ViewGroup?, p1: Int): ItemViewHolder? {
32 | val view = LayoutInflater.from(parent?.context).inflate(R.layout.item_label_recycle_view, parent, false)
33 | val itemViewHolder = ItemViewHolder(view)
34 | return itemViewHolder
35 | }
36 |
37 | override fun getItemCount(): Int {
38 |
39 | return Constants.TYPELIST.size
40 | }
41 |
42 | override fun onBindViewHolder(holder: ItemViewHolder, position: Int) {
43 |
44 |
45 | holder.textView.text = Constants.TYPELIST.getAllList()[position]
46 | holder.switch_btn.isChecked = Constants.TYPELIST.getShow(position)
47 | holder.label.setOnTouchListener(View.OnTouchListener { _, event ->
48 | if (MotionEventCompat.getActionMasked(event) == MotionEvent.ACTION_DOWN) {
49 | mDragStartListener?.onStartDrag(holder)
50 | }
51 | false
52 | })
53 | holder.switch_btn.setOnCheckedChangeListener { _, isChecked ->
54 | Constants.TABISCHANGED = true
55 | Constants.TYPELIST.setShow(position,isChecked)
56 | }
57 | }
58 |
59 |
60 |
61 |
62 |
63 |
64 | override fun onItemMove(fromPosition: Int, toPosition: Int): Boolean {
65 | // Collections.swap(data, fromPosition, toPosition)
66 | Constants.TYPELIST?.swap(fromPosition, toPosition)
67 | Constants.TABISCHANGED = true
68 | notifyItemMoved(fromPosition, toPosition)
69 | return true
70 |
71 | }
72 |
73 | override fun onItemDismiss(position: Int) {
74 |
75 | }
76 |
77 | class ItemViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView), ItemTouchHelperViewHolder {
78 |
79 | val textView: TextView
80 | val switch_btn: Switch
81 | val label: ImageView
82 |
83 | init {
84 | textView = itemView.findViewById(R.id.type) as TextView
85 | switch_btn = itemView.findViewById(R.id.switch_btn) as Switch
86 | label = itemView.findViewById(R.id.label_image) as ImageView
87 | }
88 |
89 | override fun onItemSelected() {
90 | itemView.setBackgroundColor(Color.LTGRAY)
91 | }
92 |
93 | override fun onItemClear() {
94 | itemView.setBackgroundColor(0)
95 | }
96 | }
97 |
98 |
99 |
100 |
101 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/nightssky/gankforkotlin/View/Adapter/MeiziAdapter.kt:
--------------------------------------------------------------------------------
1 | package com.nightssky.gankforkotlin.View.Adapter
2 |
3 | import com.bumptech.glide.Glide
4 | import com.bumptech.glide.load.engine.DiskCacheStrategy
5 | import com.bumptech.glide.request.RequestOptions
6 | import com.nightssky.gankforkotlin.Model.Entity.DetailsData
7 | import com.nightssky.gankforkotlin.R
8 | import com.nightssky.gankforkotlin.View.Common.MyApplication
9 | import com.nightssky.gankforkotlin.View.Widget.ScaleImageView
10 |
11 |
12 | /**
13 | * Created by user on 2017/6/14.
14 | */
15 | class MeiziAdapter : BaseRecycleViewAdapter {
16 | constructor(layoutResId: Int) : super(layoutResId)
17 |
18 | override fun bindTheData(holder: BaseViewHolder, data: DetailsData, position: Int) {
19 |
20 | val imageView = holder.getView(R.id.img_girls) as ScaleImageView
21 |
22 | val options = RequestOptions()
23 | .centerCrop()
24 | .diskCacheStrategy(DiskCacheStrategy.ALL)
25 | if (data.width!=null||data.height!=null) {
26 | imageView.setInitSize(data.width,data.height)
27 | }
28 | Glide.with(MyApplication.context())
29 | .load(data.url)
30 | .apply(options)
31 | .into(imageView)
32 |
33 | }
34 |
35 |
36 |
37 |
38 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/nightssky/gankforkotlin/View/Adapter/SearchAdapter.kt:
--------------------------------------------------------------------------------
1 | package com.nightssky.gankforkotlin.View.Adapter
2 |
3 | import android.view.View
4 | import android.widget.ImageView
5 | import com.bumptech.glide.Glide
6 | import com.nightssky.gankforkotlin.Model.Entity.CategoryData
7 | import com.nightssky.gankforkotlin.R
8 | import com.nightssky.gankforkotlin.View.Common.MyApplication
9 |
10 | /**
11 | * Created by user on 2017/6/14.
12 | */
13 | class SearchAdapter : BaseRecycleViewAdapter {
14 | constructor(layoutResId: Int) : super(layoutResId)
15 |
16 |
17 |
18 | override fun bindTheData(holder: BaseViewHolder, data: CategoryData, position: Int) {
19 | holder.setText(R.id.gank_title,data.desc)
20 | data.who?.let {
21 |
22 | holder.setText(R.id.who,data.who)
23 | }
24 | val image = holder.getView(R.id.image) as ImageView
25 | if (data.type.equals("福利")) {
26 | image.visibility = View.VISIBLE
27 | Glide.with(MyApplication.context())
28 | .load(data.url)
29 | .into(image)
30 | } else {
31 | image.visibility = View.GONE
32 | }
33 | holder.setText(R.id.type,data.type)
34 | holder.setText(R.id.time,data.publishedAt.substring(0,10))
35 |
36 | }
37 |
38 |
39 |
40 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/nightssky/gankforkotlin/View/Common/BasePresenter.kt:
--------------------------------------------------------------------------------
1 | package com.nightssky.gankforkotlin.View.Common
2 |
3 | interface BasePresenter {
4 | fun start()
5 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/nightssky/gankforkotlin/View/Common/BaseView.kt:
--------------------------------------------------------------------------------
1 | package com.nightssky.gankforkotlin.View.Common
2 |
3 | /**
4 | * Created by user on 2017/5/18.
5 | */
6 |
7 | interface BaseView {
8 | fun setView()
9 |
10 | }
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/java/com/nightssky/gankforkotlin/View/Common/DividerItemDecoration.kt:
--------------------------------------------------------------------------------
1 | package com.nightssky.gankforkotlin.View.Common
2 |
3 | import android.content.Context
4 | import android.graphics.Canvas
5 | import android.graphics.Rect
6 | import android.graphics.drawable.Drawable
7 | import android.support.v7.widget.LinearLayoutManager
8 | import android.support.v7.widget.RecyclerView
9 |
10 |
11 | /**
12 | * Created by user on 2017/7/3.
13 | */
14 | class DividerItemDecoration(context: Context, orientation: Int) : RecyclerView.ItemDecoration() {
15 |
16 | private val mDivider: Drawable
17 |
18 | private var mOrientation: Int = 0
19 |
20 | init {
21 | val a = context.obtainStyledAttributes(ATTRS)
22 | mDivider = a.getDrawable(0)
23 | a.recycle()
24 | setOrientation(orientation)
25 | }
26 |
27 | fun setOrientation(orientation: Int) {
28 | if (orientation != HORIZONTAL_LIST && orientation != VERTICAL_LIST) {
29 | throw IllegalArgumentException("invalid orientation")
30 | }
31 | mOrientation = orientation
32 | }
33 |
34 | override fun onDraw(c: Canvas, parent: RecyclerView) {
35 |
36 | if (mOrientation == VERTICAL_LIST) {
37 | drawVertical(c, parent)
38 | } else {
39 | drawHorizontal(c, parent)
40 | }
41 |
42 | }
43 |
44 |
45 | fun drawVertical(c: Canvas, parent: RecyclerView) {
46 | val left = parent.paddingLeft
47 | val right = parent.width - parent.paddingRight
48 |
49 | val childCount = parent.childCount
50 | for (i in 0..childCount - 1) {
51 | val child = parent.getChildAt(i)
52 | val v = android.support.v7.widget.RecyclerView(parent.context)
53 | val params = child
54 | .layoutParams as RecyclerView.LayoutParams
55 | val top = child.bottom + params.bottomMargin
56 | val bottom = top + mDivider.intrinsicHeight
57 | mDivider.setBounds(left, top, right, bottom)
58 | mDivider.draw(c)
59 | }
60 | }
61 |
62 | fun drawHorizontal(c: Canvas, parent: RecyclerView) {
63 | val top = parent.paddingTop
64 | val bottom = parent.height - parent.paddingBottom
65 |
66 | val childCount = parent.childCount
67 | for (i in 0..childCount - 1) {
68 | val child = parent.getChildAt(i)
69 | val params = child
70 | .layoutParams as RecyclerView.LayoutParams
71 | val left = child.right + params.rightMargin
72 | val right = left + mDivider.intrinsicHeight
73 | mDivider.setBounds(left, top, right, bottom)
74 | mDivider.draw(c)
75 | }
76 | }
77 |
78 | override fun getItemOffsets(outRect: Rect, itemPosition: Int, parent: RecyclerView) {
79 | if (mOrientation == VERTICAL_LIST) {
80 | outRect.set(0, 0, 0, mDivider.intrinsicHeight)
81 | } else {
82 | outRect.set(0, 0, mDivider.intrinsicWidth, 0)
83 | }
84 | }
85 |
86 | companion object {
87 |
88 | private val ATTRS = intArrayOf(android.R.attr.listDivider)
89 |
90 | val HORIZONTAL_LIST = LinearLayoutManager.HORIZONTAL
91 |
92 | val VERTICAL_LIST = LinearLayoutManager.VERTICAL
93 | }
94 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/nightssky/gankforkotlin/View/Common/MyApplication.kt:
--------------------------------------------------------------------------------
1 | package com.nightssky.gankforkotlin.View.Common
2 |
3 | import android.app.Application
4 |
5 | /**
6 | * Created by 追寻何意?又往何处 on 2017/6/15.
7 | */
8 | class MyApplication : Application() {
9 |
10 | companion object {
11 | private var instance: Application? = null
12 | fun context() = instance!!
13 | }
14 | override fun onCreate() {
15 | super.onCreate()
16 | instance = this
17 | }
18 |
19 |
20 | }
21 |
--------------------------------------------------------------------------------
/app/src/main/java/com/nightssky/gankforkotlin/View/Contract/GankDataContract.kt:
--------------------------------------------------------------------------------
1 | package com.nightssky.gankforkotlin.View.Contract
2 |
3 | import com.nightssky.gankforkotlin.Model.Entity.DetailsData
4 | import com.nightssky.gankforkotlin.View.Common.BasePresenter
5 | import com.nightssky.gankforkotlin.View.Common.BaseView
6 | import java.util.*
7 |
8 | /**
9 | * Created by 追寻何意?又往何处 on 2017/6/13.
10 | */
11 | interface GankDataContract {
12 | interface View : BaseView {
13 | fun setData(list:List)
14 | fun addData(list:List)
15 | fun setEmpty()
16 | fun showProgress()
17 | fun hideProgress()
18 | }
19 |
20 | interface Presenter: BasePresenter {
21 | fun getHistoryDate()
22 | fun getDayData(calendar: Calendar)
23 | fun getTypeData(type:String, num:Int = 10, page:Int = 1)
24 | fun loadMore(type:String, num:Int = 10, page:Int = 2)
25 | }
26 |
27 | }
28 |
--------------------------------------------------------------------------------
/app/src/main/java/com/nightssky/gankforkotlin/View/Contract/MainContract.kt:
--------------------------------------------------------------------------------
1 | package com.nightssky.gankforkotlin.View.Contract
2 |
3 | import com.nightssky.gankforkotlin.View.Common.BasePresenter
4 | import com.nightssky.gankforkotlin.View.Common.BaseView
5 |
6 | /**
7 | * Created by 追寻何意?又往何处 on 2017/6/13.
8 | */
9 | interface MainContract {
10 | interface View : BaseView {
11 | fun setViewPager()
12 | }
13 |
14 | interface Presenter: BasePresenter
15 |
16 | }
17 |
--------------------------------------------------------------------------------
/app/src/main/java/com/nightssky/gankforkotlin/View/Contract/SearchContract.kt:
--------------------------------------------------------------------------------
1 | package com.nightssky.gankforkotlin.View.Contract
2 |
3 | import com.nightssky.gankforkotlin.Model.Entity.CategoryData
4 | import com.nightssky.gankforkotlin.View.Common.BasePresenter
5 | import com.nightssky.gankforkotlin.View.Common.BaseView
6 |
7 | /**
8 | * Created by 追寻何意?又往何处 on 2017/6/13.
9 | */
10 | interface SearchContract {
11 | interface View : BaseView {
12 | fun setData(list:List)
13 | fun addData(list:List)
14 | fun setEmpty()
15 | fun showProgress()
16 | fun hideProgress()
17 | fun loadMore()
18 | }
19 |
20 | interface Presenter: BasePresenter {
21 | fun getSearchData(query:String, category:String , page:Int = 1)
22 | fun loadMore(query:String, category:String , page:Int = 1)
23 | }
24 |
25 | }
26 |
--------------------------------------------------------------------------------
/app/src/main/java/com/nightssky/gankforkotlin/View/Fragment/BaseFragment.kt:
--------------------------------------------------------------------------------
1 | package com.nightssky.gankforkotlin.View.Fragment
2 |
3 |
4 | import `in`.srain.cube.views.ptr.PtrDefaultHandler
5 | import `in`.srain.cube.views.ptr.PtrFrameLayout
6 | import `in`.srain.cube.views.ptr.PtrHandler
7 | import android.content.Intent
8 | import android.os.Bundle
9 | import android.support.v4.app.Fragment
10 | import android.support.v4.view.ViewCompat
11 | import android.support.v7.widget.LinearLayoutManager
12 | import android.support.v7.widget.RecyclerView
13 | import android.view.LayoutInflater
14 | import android.view.View
15 | import android.view.ViewGroup
16 | import com.nightssky.gankforkotlin.R
17 | import com.nightssky.gankforkotlin.View.Activity.ImageActivity
18 | import com.nightssky.gankforkotlin.View.Activity.WebActivity
19 | import com.nightssky.gankforkotlin.View.Adapter.BaseRecycleViewAdapter
20 | import com.nightssky.gankforkotlin.View.Adapter.GankAdapter
21 | import com.trello.rxlifecycle2.components.support.RxFragment
22 | import kotlinx.android.synthetic.main.fragment_base.*
23 |
24 |
25 | /**
26 | * A simple [Fragment] subclass.
27 | */
28 | abstract class BaseFragment : RxFragment() {
29 |
30 | lateinit var adapter:GankAdapter
31 | override fun onCreateView(inflater: LayoutInflater?, container: ViewGroup?,
32 | savedInstanceState: Bundle?): View? {
33 | return inflater!!.inflate(R.layout.fragment_base, container, false)
34 |
35 | }
36 |
37 | override fun onActivityCreated(savedInstanceState: Bundle?) {
38 | super.onActivityCreated(savedInstanceState)
39 | initView()
40 | //自动刷新
41 | // PtrFrameLayout.postDelayed(Runnable { PtrFrameLayout.autoRefresh(false) }, 50)
42 | PtrFrameLayout.autoRefresh(true,500)
43 | }
44 |
45 |
46 | private fun initView() {
47 | PtrFrameLayout.setPtrHandler(object : PtrHandler {
48 | override fun onRefreshBegin(frame: PtrFrameLayout) {
49 | refresh()
50 | }
51 |
52 | override fun checkCanDoRefresh(frame: PtrFrameLayout, content: View, header: View): Boolean {
53 | // 默认实现,根据实际情况做改动
54 | return PtrDefaultHandler.checkContentCanBePulledDown(frame, content, header)
55 | }
56 | })
57 | val layoutManager = LinearLayoutManager(activity) as RecyclerView.LayoutManager?
58 | recyclerView.layoutManager = layoutManager
59 | recyclerView.setHasFixedSize(true)
60 | adapter = GankAdapter(R.layout.item_gank_recycle_view)
61 | recyclerView.adapter = adapter
62 | adapter.setItemClickListener(object :BaseRecycleViewAdapter.onItemClickListener{
63 | override fun onItemClick(position: Int, v: View) {
64 | val data = adapter.getItem(position)
65 | if (data?.type.equals("福利")) {
66 | startActivity(Intent(activity, ImageActivity::class.java)
67 | .putExtra("url",data?.url))
68 | } else {
69 | startActivity(Intent(activity, WebActivity::class.java)
70 | .putExtra("URL",data?.url))
71 | }
72 | }
73 |
74 | })
75 | recyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener() {
76 | override fun onScrollStateChanged(recyclerView: RecyclerView?, newState: Int) {
77 | super.onScrollStateChanged(recyclerView, newState)
78 | if (newState == RecyclerView.SCROLL_STATE_IDLE) {
79 | if (!ViewCompat.canScrollVertically(recyclerView, 1)){
80 | loadMore()
81 | }
82 | }
83 | }
84 | })
85 |
86 | }
87 |
88 | abstract fun refresh()
89 |
90 | open fun loadMore(){
91 |
92 | }
93 |
94 | }
95 |
--------------------------------------------------------------------------------
/app/src/main/java/com/nightssky/gankforkotlin/View/Fragment/MeiziFragment.kt:
--------------------------------------------------------------------------------
1 | package com.nightssky.gankforkotlin.View.Fragment
2 |
3 |
4 | import android.animation.AnimatorSet
5 | import android.animation.ObjectAnimator
6 | import android.app.ActivityOptions
7 | import android.content.Intent
8 | import android.os.Bundle
9 | import android.support.v4.app.Fragment
10 | import android.support.v4.view.ViewCompat
11 | import android.support.v7.widget.DefaultItemAnimator
12 | import android.support.v7.widget.RecyclerView
13 | import android.support.v7.widget.StaggeredGridLayoutManager
14 | import android.view.LayoutInflater
15 | import android.view.View
16 | import android.view.ViewGroup
17 | import android.widget.ImageView
18 | import com.nightssky.gankforkotlin.Model.Entity.DetailsData
19 | import com.nightssky.gankforkotlin.Presenter.GankDataPresenter
20 | import com.nightssky.gankforkotlin.R
21 | import com.nightssky.gankforkotlin.View.Activity.ImageActivity
22 | import com.nightssky.gankforkotlin.View.Adapter.BaseRecycleViewAdapter
23 | import com.nightssky.gankforkotlin.View.Adapter.MeiziAdapter
24 | import com.nightssky.gankforkotlin.View.Contract.GankDataContract
25 | import com.trello.rxlifecycle2.components.support.RxFragment
26 | import kotlinx.android.synthetic.main.fragment_blank.*
27 |
28 |
29 |
30 |
31 | /**
32 | * A simple [Fragment] subclass.
33 | */
34 | class MeiziFragment : RxFragment(),GankDataContract.View {
35 |
36 |
37 | lateinit var adapter :MeiziAdapter
38 | lateinit var presenter:GankDataPresenter
39 | var pageIndex = 2
40 |
41 | override fun onCreateView(inflater: LayoutInflater?, container: ViewGroup?,
42 | savedInstanceState: Bundle?): View? {
43 | // Inflate the layout for this fragment
44 | return inflater!!.inflate(R.layout.fragment_blank, container, false)
45 | }
46 |
47 | override fun onActivityCreated(savedInstanceState: Bundle?) {
48 | super.onActivityCreated(savedInstanceState)
49 | setView()
50 | showProgress()
51 |
52 | }
53 |
54 |
55 | override fun setView() {
56 |
57 | val layoutManager = StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL)
58 | layoutManager.gapStrategy = StaggeredGridLayoutManager.GAP_HANDLING_NONE
59 | adapter = MeiziAdapter(R.layout.item_girls_recycle)
60 | meizi_recycle.layoutManager = layoutManager
61 | meizi_recycle.adapter = adapter
62 | meizi_recycle.setHasFixedSize(true)
63 | meizi_recycle.setPadding(0, 0, 0, 0);
64 | meizi_recycle.itemAnimator = DefaultItemAnimator()
65 |
66 | presenter = GankDataPresenter(this)
67 | presenter.getTypeData("福利",10,1)
68 | meizi_recycle.addOnScrollListener(object : RecyclerView.OnScrollListener() {
69 | override fun onScrollStateChanged(recyclerView: RecyclerView?, newState: Int) {
70 | super.onScrollStateChanged(recyclerView, newState)
71 | layoutManager.invalidateSpanAssignments();
72 | if (newState == RecyclerView.SCROLL_STATE_IDLE) {
73 | if (!ViewCompat.canScrollVertically(recyclerView, 1)){
74 | if (anim_layout.visibility == View.GONE) {
75 | loadMore()
76 | }
77 | }
78 | }
79 | }
80 | })
81 |
82 | adapter.setItemClickListener(object :BaseRecycleViewAdapter.onItemClickListener{
83 | override fun onItemClick(position: Int, v: View) {
84 | // startActivity(Intent(activity,ImageActivity::class.java)
85 | // .putExtra("url",adapter.getItem(position)?.url))
86 | startActivity(Intent(activity,ImageActivity::class.java)
87 | .putExtra("url",adapter.getItem(position)?.url),
88 | ActivityOptions.makeSceneTransitionAnimation(activity,v.findViewById(R.id.img_girls) as ImageView,"image").toBundle())
89 | }
90 |
91 | })
92 | }
93 |
94 | override fun setData(list: List) {
95 | adapter.setData(list)
96 | hideProgress()
97 | }
98 |
99 | override fun addData(list: List) {
100 | adapter.addData(list)
101 | hideProgress()
102 | }
103 | override fun hideProgress() {
104 | anim_layout.visibility = View.GONE
105 | }
106 |
107 | override fun showProgress() {
108 | anim_layout.visibility = View.VISIBLE
109 | val animatorx = ObjectAnimator.ofFloat(anim_layout,"scaleX",0f,1f)
110 | val animatory = ObjectAnimator.ofFloat(anim_layout,"scaleY",0f,1f)
111 | val animSet = AnimatorSet()
112 | animSet.duration = 1000
113 | animSet.play(animatorx).with(animatory)
114 | animSet.start()
115 | }
116 | override fun setEmpty() {
117 | empty_view.visibility = View.VISIBLE
118 | }
119 |
120 |
121 |
122 | fun loadMore() {
123 | presenter.loadMore("福利",10,pageIndex++)
124 | showProgress()
125 | }
126 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/nightssky/gankforkotlin/View/Fragment/RecommendFragment.kt:
--------------------------------------------------------------------------------
1 | package com.nightssky.gankforkotlin.View.Fragment
2 |
3 |
4 | import android.animation.AnimatorSet
5 | import android.animation.ObjectAnimator
6 | import android.os.Bundle
7 | import android.support.v4.app.Fragment
8 | import android.view.View
9 | import com.nightssky.gankforkotlin.Model.Entity.DetailsData
10 | import com.nightssky.gankforkotlin.Presenter.GankDataPresenter
11 | import com.nightssky.gankforkotlin.View.Contract.GankDataContract
12 | import kotlinx.android.synthetic.main.fragment_base.*
13 |
14 |
15 | /**
16 | * A simple [Fragment] subclass.
17 | */
18 | class RecommendFragment : BaseFragment(),GankDataContract.View {
19 |
20 |
21 |
22 | private val presenter = GankDataPresenter(this)
23 | override fun onActivityCreated(savedInstanceState: Bundle?) {
24 | super.onActivityCreated(savedInstanceState)
25 | presenter.start()
26 |
27 | }
28 | override fun setView() {
29 |
30 | }
31 |
32 | override fun setData(list: List) {
33 | if (list.size > 0) {
34 | adapter.setData(list)
35 | PtrFrameLayout.refreshComplete()
36 |
37 | } else {
38 | setEmpty()
39 | }
40 | hideProgress()
41 |
42 | }
43 |
44 | override fun showProgress() {
45 | anim_layout.visibility = View.VISIBLE
46 | val animatorx = ObjectAnimator.ofFloat(anim_layout,"scaleX",0f,1f)
47 | val animatory = ObjectAnimator.ofFloat(anim_layout,"scaleY",0f,1f)
48 | val animSet = AnimatorSet()
49 | animSet.duration = 1000
50 | animSet.play(animatorx).with(animatory)
51 | animSet.start()
52 | }
53 |
54 | override fun hideProgress() {
55 | anim_layout.visibility = View.GONE
56 | }
57 |
58 | override fun setEmpty() {
59 | PtrFrameLayout.refreshComplete()
60 | empty_view.visibility = View.VISIBLE
61 |
62 | }
63 |
64 | override fun refresh() {
65 | presenter.getHistoryDate()
66 | }
67 |
68 | override fun addData(list: List) {
69 |
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/app/src/main/java/com/nightssky/gankforkotlin/View/Fragment/TypeFragment.kt:
--------------------------------------------------------------------------------
1 | package com.nightssky.gankforkotlin.View.Fragment
2 |
3 |
4 | import android.animation.AnimatorSet
5 | import android.animation.ObjectAnimator
6 | import android.os.Bundle
7 | import android.support.v4.app.Fragment
8 | import android.view.View
9 | import com.nightssky.gankforkotlin.Model.Entity.DetailsData
10 | import com.nightssky.gankforkotlin.Presenter.GankDataPresenter
11 | import com.nightssky.gankforkotlin.View.Contract.GankDataContract
12 | import kotlinx.android.synthetic.main.fragment_base.*
13 |
14 |
15 | /**
16 | * A simple [Fragment] subclass.
17 | */
18 | class TypeFragment : BaseFragment(), GankDataContract.View {
19 |
20 |
21 |
22 | private val presenter = GankDataPresenter(this)
23 | private var pageIndex = 2
24 | override fun setView() {
25 |
26 | }
27 |
28 | override fun onActivityCreated(savedInstanceState: Bundle?) {
29 | super.onActivityCreated(savedInstanceState)
30 | showProgress()
31 | }
32 | override fun setData(list: List) {
33 | adapter.setData(list)
34 | if (list.size==0) setEmpty()
35 | PtrFrameLayout.refreshComplete()
36 | hideProgress()
37 | }
38 | override fun addData(list: List) {
39 | adapter.addData(list)
40 | hideProgress()
41 | }
42 | override fun showProgress() {
43 | anim_layout.visibility = View.VISIBLE
44 | val animatorx = ObjectAnimator.ofFloat(anim_layout,"scaleX",0f,1f)
45 | val animatory = ObjectAnimator.ofFloat(anim_layout,"scaleY",0f,1f)
46 | val animSet = AnimatorSet()
47 | animSet.duration = 1000
48 | animSet.play(animatorx).with(animatory)
49 | animSet.start()
50 | }
51 |
52 | override fun hideProgress() {
53 | anim_layout.visibility = View.GONE
54 |
55 | }
56 |
57 | override fun setEmpty() {
58 | empty_view.visibility = View.VISIBLE
59 | }
60 | override fun refresh() {
61 | pageIndex=2
62 | presenter.getTypeData(typeStr,10,1)
63 |
64 | }
65 | var typeStr:String="Android"
66 |
67 | fun setType(type:String):BaseFragment{
68 |
69 | typeStr = type
70 | return this
71 |
72 | }
73 | override fun loadMore() {
74 |
75 | presenter.loadMore(typeStr,10,pageIndex++)
76 | showProgress()
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/app/src/main/java/com/nightssky/gankforkotlin/View/Widget/DragHelper/ItemTouchHelperAdapter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2015 Paul Burke
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.nightssky.gankforkotlin.View.Widget.DragHelper;
18 |
19 | import android.support.v7.widget.RecyclerView;
20 | import android.support.v7.widget.helper.ItemTouchHelper;
21 |
22 | /**
23 | * Interface to listen for a move or dismissal event from a {@link ItemTouchHelper.Callback}.
24 | *
25 | * @author Paul Burke (ipaulpro)
26 | */
27 | public interface ItemTouchHelperAdapter {
28 |
29 | /**
30 | * Called when an item has been dragged far enough to trigger a move. This is called every time
31 | * an item is shifted, and not at the end of a "drop" event.
32 | *
33 | * Implementations should call {@link RecyclerView.Adapter#notifyItemMoved(int, int)} after
34 | * adjusting the underlying data to reflect this move.
35 | *
36 | * @param fromPosition The start position of the moved item.
37 | * @param toPosition Then resolved position of the moved item.
38 | * @return True if the item was moved to the new adapter position.
39 | *
40 | * @see RecyclerView#getAdapterPositionFor(RecyclerView.ViewHolder)
41 | * @see RecyclerView.ViewHolder#getAdapterPosition()
42 | */
43 | boolean onItemMove(int fromPosition, int toPosition);
44 |
45 |
46 | /**
47 | * Called when an item has been dismissed by a swipe.
48 | *
49 | * Implementations should call {@link RecyclerView.Adapter#notifyItemRemoved(int)} after
50 | * adjusting the underlying data to reflect this removal.
51 | *
52 | * @param position The position of the item dismissed.
53 | *
54 | * @see RecyclerView#getAdapterPositionFor(RecyclerView.ViewHolder)
55 | * @see RecyclerView.ViewHolder#getAdapterPosition()
56 | */
57 | void onItemDismiss(int position);
58 | }
59 |
--------------------------------------------------------------------------------
/app/src/main/java/com/nightssky/gankforkotlin/View/Widget/DragHelper/ItemTouchHelperViewHolder.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2015 Paul Burke
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.nightssky.gankforkotlin.View.Widget.DragHelper;
18 |
19 | import android.support.v7.widget.helper.ItemTouchHelper;
20 |
21 | /**
22 | * Interface to notify an item ViewHolder of relevant callbacks from {@link
23 | * android.support.v7.widget.helper.ItemTouchHelper.Callback}.
24 | *
25 | * @author Paul Burke (ipaulpro)
26 | */
27 | public interface ItemTouchHelperViewHolder {
28 |
29 | /**
30 | * Called when the {@link ItemTouchHelper} first registers an item as being moved or swiped.
31 | * Implementations should update the item view to indicate it's active state.
32 | */
33 | void onItemSelected();
34 |
35 |
36 | /**
37 | * Called when the {@link ItemTouchHelper} has completed the move or swipe, and the active item
38 | * state should be cleared.
39 | */
40 | void onItemClear();
41 | }
42 |
--------------------------------------------------------------------------------
/app/src/main/java/com/nightssky/gankforkotlin/View/Widget/DragHelper/OnStartDragListener.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2015 Paul Burke
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.nightssky.gankforkotlin.View.Widget.DragHelper;
18 |
19 | import android.support.v7.widget.RecyclerView;
20 |
21 | /**
22 | * Listener for manual initiation of a drag.
23 | */
24 | public interface OnStartDragListener {
25 |
26 | /**
27 | * Called when a view is requesting a start of a drag.
28 | *
29 | * @param viewHolder The holder of the view to drag.
30 | */
31 | void onStartDrag(RecyclerView.ViewHolder viewHolder);
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/app/src/main/java/com/nightssky/gankforkotlin/View/Widget/DragHelper/SimpleItemTouchHelperCallback.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2015 Paul Burke
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.nightssky.gankforkotlin.View.Widget.DragHelper;
18 |
19 | import android.graphics.Canvas;
20 | import android.support.v7.widget.GridLayoutManager;
21 | import android.support.v7.widget.RecyclerView;
22 | import android.support.v7.widget.helper.ItemTouchHelper;
23 |
24 | /**
25 | * An implementation of {@link ItemTouchHelper.Callback} that enables basic drag & drop and
26 | * swipe-to-dismiss. Drag events are automatically started by an item long-press.
27 | *
28 | * Expects the RecyclerView.Adapter
to listen for {@link
29 | * ItemTouchHelperAdapter} callbacks and the RecyclerView.ViewHolder
to implement
30 | * {@link ItemTouchHelperViewHolder}.
31 | *
32 | * @author Paul Burke (ipaulpro)
33 | */
34 | public class SimpleItemTouchHelperCallback extends ItemTouchHelper.Callback {
35 |
36 | public static final float ALPHA_FULL = 1.0f;
37 |
38 | private final ItemTouchHelperAdapter mAdapter;
39 |
40 | public SimpleItemTouchHelperCallback(ItemTouchHelperAdapter adapter) {
41 | mAdapter = adapter;
42 | }
43 |
44 | @Override
45 | public boolean isLongPressDragEnabled() {
46 | return true;
47 | }
48 |
49 | @Override
50 | public boolean isItemViewSwipeEnabled() {
51 | return false;
52 | }
53 |
54 | @Override
55 | public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
56 | // Set movement flags based on the layout manager
57 | if (recyclerView.getLayoutManager() instanceof GridLayoutManager) {
58 | final int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN | ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;
59 | final int swipeFlags = 0;
60 | return makeMovementFlags(dragFlags, swipeFlags);
61 | } else {
62 | final int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
63 | final int swipeFlags = ItemTouchHelper.START | ItemTouchHelper.END;
64 | return makeMovementFlags(dragFlags, swipeFlags);
65 | }
66 | }
67 |
68 | @Override
69 | public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder source, RecyclerView.ViewHolder target) {
70 | if (source.getItemViewType() != target.getItemViewType()) {
71 | return false;
72 | }
73 |
74 | // Notify the adapter of the move
75 | mAdapter.onItemMove(source.getAdapterPosition(), target.getAdapterPosition());
76 | return true;
77 | }
78 |
79 | @Override
80 | public void onSwiped(RecyclerView.ViewHolder viewHolder, int i) {
81 | // Notify the adapter of the dismissal
82 | mAdapter.onItemDismiss(viewHolder.getAdapterPosition());
83 | }
84 |
85 | @Override
86 | public void onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {
87 | if (actionState == ItemTouchHelper.ACTION_STATE_SWIPE) {
88 | // Fade out the view as it is swiped out of the parent's bounds
89 | final float alpha = ALPHA_FULL - Math.abs(dX) / (float) viewHolder.itemView.getWidth();
90 | viewHolder.itemView.setAlpha(alpha);
91 | viewHolder.itemView.setTranslationX(dX);
92 | } else {
93 | super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
94 | }
95 | }
96 |
97 | @Override
98 | public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) {
99 | // We only want the active item to change
100 | if (actionState != ItemTouchHelper.ACTION_STATE_IDLE) {
101 | if (viewHolder instanceof ItemTouchHelperViewHolder) {
102 | // Let the view holder know that this item is being moved or dragged
103 | ItemTouchHelperViewHolder itemViewHolder = (ItemTouchHelperViewHolder) viewHolder;
104 | itemViewHolder.onItemSelected();
105 | }
106 | }
107 |
108 | super.onSelectedChanged(viewHolder, actionState);
109 | }
110 |
111 | @Override
112 | public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
113 | super.clearView(recyclerView, viewHolder);
114 |
115 | viewHolder.itemView.setAlpha(ALPHA_FULL);
116 |
117 | if (viewHolder instanceof ItemTouchHelperViewHolder) {
118 | // Tell the view holder it's time to restore the idle state
119 | ItemTouchHelperViewHolder itemViewHolder = (ItemTouchHelperViewHolder) viewHolder;
120 | itemViewHolder.onItemClear();
121 | }
122 | }
123 | }
124 |
--------------------------------------------------------------------------------
/app/src/main/java/com/nightssky/gankforkotlin/View/Widget/ScaleImageView.java:
--------------------------------------------------------------------------------
1 | package com.nightssky.gankforkotlin.View.Widget;
2 |
3 | import android.content.Context;
4 | import android.support.v7.widget.AppCompatImageView;
5 | import android.util.AttributeSet;
6 |
7 | /**
8 | * Author: Othershe
9 | * Time: 2016/8/18 10:55
10 | */
11 | public class ScaleImageView extends AppCompatImageView {
12 | private int initWidth;
13 | private int initHeight;
14 |
15 | public ScaleImageView(Context context) {
16 | this(context, null);
17 | }
18 |
19 | public ScaleImageView(Context context, AttributeSet attrs) {
20 | super(context, attrs);
21 | }
22 |
23 | public void setInitSize(int initWidth, int initHeight) {
24 | this.initWidth = initWidth;
25 | this.initHeight = initHeight;
26 | }
27 |
28 | @Override
29 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
30 | if (initWidth > 0 && initHeight > 0) {
31 | int width = MeasureSpec.getSize(widthMeasureSpec);
32 | int height = MeasureSpec.getSize(heightMeasureSpec);
33 |
34 | float scale = (float) initHeight / (float) initWidth;
35 | if (width > 0){
36 | height = (int) ((float)width * scale);
37 | }
38 | setMeasuredDimension(width, height);
39 | } else {
40 | super.onMeasure(widthMeasureSpec, heightMeasureSpec);
41 | }
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/app/src/main/java/com/nightssky/gankforkotlin/utils/FileUtils.kt:
--------------------------------------------------------------------------------
1 | package com.nightssky.gankforkotlin.utils
2 |
3 | import android.graphics.Bitmap
4 | import java.io.File
5 | import java.io.FileNotFoundException
6 | import java.io.FileOutputStream
7 | import java.io.IOException
8 |
9 |
10 | /**
11 | * Created by user on 2017/7/6.
12 | */
13 | object FileUtils {
14 |
15 | /**
16 | * 保存Bitmap为图片
17 | */
18 | @Throws(Exception::class)
19 | fun saveBitmap(bitmap: Bitmap, picPath: String) {
20 | val f = File(picPath + ".jpg")
21 | if (f.exists()) {
22 | f.delete()
23 | }
24 | println(f.absolutePath)
25 | try {
26 | val out = FileOutputStream(f)
27 | bitmap.compress(Bitmap.CompressFormat.JPEG, 90, out)
28 | out.flush()
29 | out.close()
30 | println("下载成功")
31 | } catch (e: FileNotFoundException) {
32 | // TODO Auto-generated catch block
33 | e.printStackTrace()
34 | throw FileNotFoundException()
35 | } catch (e: IOException) {
36 | // TODO Auto-generated catch block
37 | e.printStackTrace()
38 | throw IOException()
39 | }
40 | }
41 |
42 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/nightssky/gankforkotlin/utils/PreUtils.kt:
--------------------------------------------------------------------------------
1 | package com.nightssky.gankforkotlin.utils
2 |
3 | import android.content.Context
4 | import android.content.SharedPreferences
5 | import com.nightssky.gankforkotlin.View.Common.MyApplication
6 |
7 |
8 | /**
9 | * Created by user on 2017/6/28.
10 | */
11 | object PreUtils {
12 | private val SP_NAME = "GANK"
13 | private val sp: SharedPreferences by lazy {
14 | MyApplication.context().getSharedPreferences(SP_NAME, 0)
15 | }
16 |
17 | fun saveBoolean(key: String, value: Boolean) {
18 |
19 | sp!!.edit().putBoolean(key, value).commit()
20 | }
21 |
22 | fun saveString( key: String, value: String) {
23 |
24 | sp!!.edit().putString(key, value).commit()
25 |
26 | }
27 |
28 | fun clear(context: Context) {
29 |
30 | sp!!.edit().clear().commit()
31 | }
32 |
33 |
34 | fun saveLong( key: String, value: Long) {
35 |
36 | sp!!.edit().putLong(key, value).commit()
37 | }
38 |
39 |
40 | fun saveInt(key: String, value: Int) {
41 |
42 | sp!!.edit().putInt(key, value).commit()
43 | }
44 |
45 |
46 | fun getString(context: Context, key: String, defValue: String): String {
47 |
48 | return sp!!.getString(key, defValue)
49 | }
50 |
51 |
52 | fun getInt( key: String, defValue: Int): Int {
53 |
54 | return sp!!.getInt(key, defValue)
55 | }
56 |
57 |
58 | fun getBoolean(key: String, defValue: Boolean): Boolean {
59 |
60 | return sp!!.getBoolean(key, defValue)
61 | }
62 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/nightssky/gankforkotlin/utils/ToastUtils.kt:
--------------------------------------------------------------------------------
1 | package com.nightssky.gankforkotlin.utils
2 |
3 | import android.app.Fragment
4 | import android.content.Context
5 | import android.widget.Toast
6 |
7 | /**
8 | * Created by user on 2017/7/6.
9 | */
10 |
11 |
12 |
13 |
14 | /**
15 | * Display the simple Toast message with the [Toast.LENGTH_SHORT] duration.
16 | *
17 | * @param message the message text resource.
18 | */
19 | inline fun Fragment.toast(message: Int): Unit = activity.toast(message)
20 |
21 | /**
22 | * Display the simple Toast message with the [Toast.LENGTH_SHORT] duration.
23 | *
24 | * @param message the message text resource.
25 | */
26 | fun Context.toast(message: Int) = Toast.makeText(this, message, Toast.LENGTH_SHORT).show()
27 |
28 |
29 |
30 | /**
31 | * Display the simple Toast message with the [Toast.LENGTH_SHORT] duration.
32 | *
33 | * @param message the message text.
34 | */
35 | inline fun Fragment.toast(message: CharSequence): Unit = activity.toast(message)
36 |
37 | /**
38 | * Display the simple Toast message with the [Toast.LENGTH_SHORT] duration.
39 | *
40 | * @param message the message text.
41 | */
42 | fun Context.toast(message: CharSequence) = Toast.makeText(this, message, Toast.LENGTH_SHORT).show()
43 |
44 |
45 |
46 | /**
47 | * Display the simple Toast message with the [Toast.LENGTH_LONG] duration.
48 | *
49 | * @param message the message text resource.
50 | */
51 | inline fun Fragment.longToast(message: Int): Unit = activity.longToast(message)
52 |
53 | /**
54 | * Display the simple Toast message with the [Toast.LENGTH_LONG] duration.
55 | *
56 | * @param message the message text resource.
57 | */
58 | inline fun Context.longToast(message: Int) = Toast.makeText(this, message, Toast.LENGTH_LONG).show()
59 |
60 |
61 | /**
62 | * Display the simple Toast message with the [Toast.LENGTH_LONG] duration.
63 | *
64 | * @param message the message text.
65 | */
66 | inline fun Fragment.longToast(message: CharSequence): Unit = activity.longToast(message)
67 |
68 | /**
69 | * Display the simple Toast message with the [Toast.LENGTH_LONG] duration.
70 | *
71 | * @param message the message text.
72 | */
73 | inline fun Context.longToast(message: CharSequence) = Toast.makeText(this, message, Toast.LENGTH_LONG).show()
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_arrow_right.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_back.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_down.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_label.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_label_list.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_night.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_search.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_settings.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_share.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_whatshot_black_24dp.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/progress_bar_states.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | -
4 |
5 |
8 |
9 |
10 |
11 | -
12 |
13 |
14 |
18 |
19 |
20 |
21 |
22 | -
23 |
24 |
25 |
29 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/shape_progress_shadow.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/shape_search_bg.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_image.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
20 |
27 |
28 |
37 |
38 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_label.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
15 |
23 |
24 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
11 |
20 |
25 |
32 |
39 |
46 |
47 |
48 |
49 |
50 |
51 |
62 |
63 |
64 |
65 |
73 |
74 |
75 |
76 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_search.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
16 |
17 |
23 |
24 |
34 |
35 |
49 |
50 |
51 |
52 |
53 |
54 |
57 |
58 |
62 |
63 |
64 |
68 |
69 |
79 |
80 |
85 |
86 |
87 |
88 |
89 |
90 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_splash.xml:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_web.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
20 |
21 |
31 |
32 |
33 |
38 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_base.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
19 |
20 |
24 |
25 |
26 |
27 |
28 |
32 |
42 |
43 |
48 |
49 |
50 |
51 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_blank.xml:
--------------------------------------------------------------------------------
1 |
6 |
11 |
12 |
16 |
26 |
27 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_gank_recycle_view.xml:
--------------------------------------------------------------------------------
1 |
2 |
13 |
14 |
17 |
24 |
36 |
45 |
54 |
62 |
63 |
64 |
65 |
66 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_girls_recycle.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
15 |
22 |
23 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_label_recycle_view.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
16 |
24 |
31 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/layout_empty_view.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
16 |
17 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/web_menu.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NightsSky/GankForKotlin/dd66325316e68662579e43ab960d28bc9dcf1340/app/src/main/res/mipmap/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap/start.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NightsSky/GankForKotlin/dd66325316e68662579e43ab960d28bc9dcf1340/app/src/main/res/mipmap/start.jpg
--------------------------------------------------------------------------------
/app/src/main/res/values-w820dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 64dp
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/attrs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #007FFF
4 | #0072E5
5 | #FF4081
6 | #FFF
7 | #F00
8 | #000
9 | #f9f9f9
10 | #e6e6e6
11 | #333333
12 | #3399FF
13 |
14 |
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 16dp
4 | 16dp
5 | 16dp
6 | 8dp
7 |
8 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | GankForKotlin
3 |
4 |
5 | Hello blank fragment
6 | SplashActivity
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
12 |
15 |
16 |
17 |
18 |
19 |
25 |
26 |
29 |
30 |
--------------------------------------------------------------------------------
/app/src/test/java/com/nightssky/gankforkotlin/ExampleUnitTest.kt:
--------------------------------------------------------------------------------
1 | package com.nightssky.gankforkotlin
2 |
3 | import org.junit.Test
4 |
5 | import org.junit.Assert.*
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see [Testing documentation](http://d.android.com/tools/testing)
11 | */
12 | class ExampleUnitTest {
13 | @Test
14 | @Throws(Exception::class)
15 | fun addition_isCorrect() {
16 | assertEquals(4, (2 + 2).toLong())
17 | }
18 | }
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 | ext.kotlin_version = '1.1.2-4'
5 | repositories {
6 | maven { url 'https://maven.google.com' }
7 | jcenter()
8 | }
9 | dependencies {
10 | classpath 'com.android.tools.build:gradle:3.0.0-alpha5'
11 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
12 |
13 | // NOTE: Do not place your application dependencies here; they belong
14 | // in the individual module build.gradle files
15 | }
16 | }
17 |
18 | allprojects {
19 | repositories {
20 | maven { url 'https://maven.google.com' }
21 | maven { url "https://jitpack.io" }
22 | jcenter()
23 | mavenCentral()
24 | }
25 | }
26 |
27 | task clean(type: Delete) {
28 | delete rootProject.buildDir
29 | }
30 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Gradle settings configured through the IDE *will override*
5 | # any settings specified in this file.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | org.gradle.jvmargs=-Xmx1536m
13 |
14 | # When configured, Gradle will run in incubating parallel mode.
15 | # This option should only be used with decoupled projects. More details, visit
16 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
17 | # org.gradle.parallel=true
18 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NightsSky/GankForKotlin/dd66325316e68662579e43ab960d28bc9dcf1340/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Tue Jun 13 15:20:57 CST 2017
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-milestone-1-all.zip
7 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # Attempt to set APP_HOME
46 | # Resolve links: $0 may be a link
47 | PRG="$0"
48 | # Need this for relative symlinks.
49 | while [ -h "$PRG" ] ; do
50 | ls=`ls -ld "$PRG"`
51 | link=`expr "$ls" : '.*-> \(.*\)$'`
52 | if expr "$link" : '/.*' > /dev/null; then
53 | PRG="$link"
54 | else
55 | PRG=`dirname "$PRG"`"/$link"
56 | fi
57 | done
58 | SAVED="`pwd`"
59 | cd "`dirname \"$PRG\"`/" >/dev/null
60 | APP_HOME="`pwd -P`"
61 | cd "$SAVED" >/dev/null
62 |
63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
64 |
65 | # Determine the Java command to use to start the JVM.
66 | if [ -n "$JAVA_HOME" ] ; then
67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
68 | # IBM's JDK on AIX uses strange locations for the executables
69 | JAVACMD="$JAVA_HOME/jre/sh/java"
70 | else
71 | JAVACMD="$JAVA_HOME/bin/java"
72 | fi
73 | if [ ! -x "$JAVACMD" ] ; then
74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
75 |
76 | Please set the JAVA_HOME variable in your environment to match the
77 | location of your Java installation."
78 | fi
79 | else
80 | JAVACMD="java"
81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
82 |
83 | Please set the JAVA_HOME variable in your environment to match the
84 | location of your Java installation."
85 | fi
86 |
87 | # Increase the maximum file descriptors if we can.
88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
89 | MAX_FD_LIMIT=`ulimit -H -n`
90 | if [ $? -eq 0 ] ; then
91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
92 | MAX_FD="$MAX_FD_LIMIT"
93 | fi
94 | ulimit -n $MAX_FD
95 | if [ $? -ne 0 ] ; then
96 | warn "Could not set maximum file descriptor limit: $MAX_FD"
97 | fi
98 | else
99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
100 | fi
101 | fi
102 |
103 | # For Darwin, add options to specify how the application appears in the dock
104 | if $darwin; then
105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
106 | fi
107 |
108 | # For Cygwin, switch paths to Windows format before running java
109 | if $cygwin ; then
110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
112 | JAVACMD=`cygpath --unix "$JAVACMD"`
113 |
114 | # We build the pattern for arguments to be converted via cygpath
115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
116 | SEP=""
117 | for dir in $ROOTDIRSRAW ; do
118 | ROOTDIRS="$ROOTDIRS$SEP$dir"
119 | SEP="|"
120 | done
121 | OURCYGPATTERN="(^($ROOTDIRS))"
122 | # Add a user-defined pattern to the cygpath arguments
123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
125 | fi
126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
127 | i=0
128 | for arg in "$@" ; do
129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
131 |
132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
134 | else
135 | eval `echo args$i`="\"$arg\""
136 | fi
137 | i=$((i+1))
138 | done
139 | case $i in
140 | (0) set -- ;;
141 | (1) set -- "$args0" ;;
142 | (2) set -- "$args0" "$args1" ;;
143 | (3) set -- "$args0" "$args1" "$args2" ;;
144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
150 | esac
151 | fi
152 |
153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
154 | function splitJvmOpts() {
155 | JVM_OPTS=("$@")
156 | }
157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
159 |
160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
161 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
--------------------------------------------------------------------------------