@ -1,2 +1 @@ |
|||||||
<manifest |
<manifest package="com.zwy.opennsfw" /> |
||||||
package="com.zwy.opennsfw"/> |
|
||||||
|
@ -1,15 +1,32 @@ |
|||||||
package com.example.open_nsfw_android |
package com.example.open_nsfw_android |
||||||
|
|
||||||
import android.app.Application |
import android.app.Application |
||||||
|
import com.example.open_nsfw_android.view.mModules |
||||||
import com.zwy.opennsfw.core.Classifier |
import com.zwy.opennsfw.core.Classifier |
||||||
|
import okhttp3.OkHttp |
||||||
|
import okhttp3.OkHttpClient |
||||||
|
import okhttp3.Request |
||||||
|
import org.koin.android.ext.koin.androidContext |
||||||
|
import org.koin.android.ext.koin.androidFileProperties |
||||||
|
import org.koin.android.ext.koin.androidLogger |
||||||
|
import org.koin.core.context.startKoin |
||||||
|
import org.koin.core.logger.PrintLogger |
||||||
|
import org.koin.core.qualifier.qualifier |
||||||
|
import org.koin.dsl.module |
||||||
|
|
||||||
class DemoApplication : Application() { |
class DemoApplication : Application() { |
||||||
override fun onCreate() { |
override fun onCreate() { |
||||||
super.onCreate() |
super.onCreate() |
||||||
|
|
||||||
|
startKoin { |
||||||
|
modules(mModules) |
||||||
|
} |
||||||
Classifier.Build() |
Classifier.Build() |
||||||
.context(this) //必须调用 否则会有异常抛出 |
.context(this) //必须调用 否则会有异常抛出 |
||||||
// .isOpenGPU(true)//默认不开启GPU加速 部分机型开启会奔溃,自行选择,默认false |
// .isOpenGPU(true)//默认不开启GPU加速 部分机型开启会奔溃,自行选择,默认false |
||||||
// .numThreads(10) //分配的线程数 根据手机配置设置,默认1 |
// .numThreads(10) //分配的线程数 根据手机配置设置,默认1 |
||||||
.build() |
.build() |
||||||
|
|
||||||
} |
} |
||||||
|
|
||||||
} |
} |
@ -0,0 +1,32 @@ |
|||||||
|
package com.example.open_nsfw_android.view |
||||||
|
|
||||||
|
import com.google.gson.Gson |
||||||
|
import okhttp3.OkHttpClient |
||||||
|
import okhttp3.Request |
||||||
|
import org.koin.core.qualifier.qualifier |
||||||
|
import org.koin.dsl.module |
||||||
|
|
||||||
|
val BaseUrl = "http://114.116.213.202:7777/" |
||||||
|
val GetImageListURL = "${BaseUrl}imageList.do" |
||||||
|
val UploadImageURL = "${BaseUrl}imageList.do" |
||||||
|
|
||||||
|
|
||||||
|
val mModules = module { |
||||||
|
single<OkHttpClient> { |
||||||
|
OkHttpClient.Builder().build() |
||||||
|
} |
||||||
|
single<Gson> { |
||||||
|
Gson() |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
data class NSFWImage( |
||||||
|
val createTime: String, |
||||||
|
val id: Int, |
||||||
|
val imgUrl: String |
||||||
|
) { |
||||||
|
override fun toString(): String { |
||||||
|
return Gson().toJson(this) |
||||||
|
} |
||||||
|
} |
@ -1,74 +1,170 @@ |
|||||||
<?xml version="1.0" encoding="utf-8"?> |
<?xml version="1.0" encoding="utf-8"?> |
||||||
<vector |
<vector android:height="108dp" |
||||||
android:height="108dp" |
|
||||||
android:width="108dp" |
android:width="108dp" |
||||||
android:viewportHeight="108" |
android:viewportHeight="108" |
||||||
android:viewportWidth="108" |
android:viewportWidth="108" |
||||||
xmlns:android="http://schemas.android.com/apk/res/android"> |
xmlns:android="http://schemas.android.com/apk/res/android"> |
||||||
<path android:fillColor="#3DDC84" |
<path |
||||||
|
android:fillColor="#3DDC84" |
||||||
android:pathData="M0,0h108v108h-108z" /> |
android:pathData="M0,0h108v108h-108z" /> |
||||||
<path android:fillColor="#00000000" android:pathData="M9,0L9,108" |
<path |
||||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/> |
android:fillColor="#00000000" |
||||||
<path android:fillColor="#00000000" android:pathData="M19,0L19,108" |
android:pathData="M9,0L9,108" |
||||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/> |
android:strokeColor="#33FFFFFF" |
||||||
<path android:fillColor="#00000000" android:pathData="M29,0L29,108" |
android:strokeWidth="0.8" /> |
||||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/> |
<path |
||||||
<path android:fillColor="#00000000" android:pathData="M39,0L39,108" |
android:fillColor="#00000000" |
||||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/> |
android:pathData="M19,0L19,108" |
||||||
<path android:fillColor="#00000000" android:pathData="M49,0L49,108" |
android:strokeColor="#33FFFFFF" |
||||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/> |
android:strokeWidth="0.8" /> |
||||||
<path android:fillColor="#00000000" android:pathData="M59,0L59,108" |
<path |
||||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/> |
android:fillColor="#00000000" |
||||||
<path android:fillColor="#00000000" android:pathData="M69,0L69,108" |
android:pathData="M29,0L29,108" |
||||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/> |
android:strokeColor="#33FFFFFF" |
||||||
<path android:fillColor="#00000000" android:pathData="M79,0L79,108" |
android:strokeWidth="0.8" /> |
||||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/> |
<path |
||||||
<path android:fillColor="#00000000" android:pathData="M89,0L89,108" |
android:fillColor="#00000000" |
||||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/> |
android:pathData="M39,0L39,108" |
||||||
<path android:fillColor="#00000000" android:pathData="M99,0L99,108" |
android:strokeColor="#33FFFFFF" |
||||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/> |
android:strokeWidth="0.8" /> |
||||||
<path android:fillColor="#00000000" android:pathData="M0,9L108,9" |
<path |
||||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/> |
android:fillColor="#00000000" |
||||||
<path android:fillColor="#00000000" android:pathData="M0,19L108,19" |
android:pathData="M49,0L49,108" |
||||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/> |
android:strokeColor="#33FFFFFF" |
||||||
<path android:fillColor="#00000000" android:pathData="M0,29L108,29" |
android:strokeWidth="0.8" /> |
||||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/> |
<path |
||||||
<path android:fillColor="#00000000" android:pathData="M0,39L108,39" |
android:fillColor="#00000000" |
||||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/> |
android:pathData="M59,0L59,108" |
||||||
<path android:fillColor="#00000000" android:pathData="M0,49L108,49" |
android:strokeColor="#33FFFFFF" |
||||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/> |
android:strokeWidth="0.8" /> |
||||||
<path android:fillColor="#00000000" android:pathData="M0,59L108,59" |
<path |
||||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/> |
android:fillColor="#00000000" |
||||||
<path android:fillColor="#00000000" android:pathData="M0,69L108,69" |
android:pathData="M69,0L69,108" |
||||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/> |
android:strokeColor="#33FFFFFF" |
||||||
<path android:fillColor="#00000000" android:pathData="M0,79L108,79" |
android:strokeWidth="0.8" /> |
||||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/> |
<path |
||||||
<path android:fillColor="#00000000" android:pathData="M0,89L108,89" |
android:fillColor="#00000000" |
||||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/> |
android:pathData="M79,0L79,108" |
||||||
<path android:fillColor="#00000000" android:pathData="M0,99L108,99" |
android:strokeColor="#33FFFFFF" |
||||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/> |
android:strokeWidth="0.8" /> |
||||||
<path android:fillColor="#00000000" android:pathData="M19,29L89,29" |
<path |
||||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/> |
android:fillColor="#00000000" |
||||||
<path android:fillColor="#00000000" android:pathData="M19,39L89,39" |
android:pathData="M89,0L89,108" |
||||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/> |
android:strokeColor="#33FFFFFF" |
||||||
<path android:fillColor="#00000000" android:pathData="M19,49L89,49" |
android:strokeWidth="0.8" /> |
||||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/> |
<path |
||||||
<path android:fillColor="#00000000" android:pathData="M19,59L89,59" |
android:fillColor="#00000000" |
||||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/> |
android:pathData="M99,0L99,108" |
||||||
<path android:fillColor="#00000000" android:pathData="M19,69L89,69" |
android:strokeColor="#33FFFFFF" |
||||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/> |
android:strokeWidth="0.8" /> |
||||||
<path android:fillColor="#00000000" android:pathData="M19,79L89,79" |
<path |
||||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/> |
android:fillColor="#00000000" |
||||||
<path android:fillColor="#00000000" android:pathData="M29,19L29,89" |
android:pathData="M0,9L108,9" |
||||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/> |
android:strokeColor="#33FFFFFF" |
||||||
<path android:fillColor="#00000000" android:pathData="M39,19L39,89" |
android:strokeWidth="0.8" /> |
||||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/> |
<path |
||||||
<path android:fillColor="#00000000" android:pathData="M49,19L49,89" |
android:fillColor="#00000000" |
||||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/> |
android:pathData="M0,19L108,19" |
||||||
<path android:fillColor="#00000000" android:pathData="M59,19L59,89" |
android:strokeColor="#33FFFFFF" |
||||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/> |
android:strokeWidth="0.8" /> |
||||||
<path android:fillColor="#00000000" android:pathData="M69,19L69,89" |
<path |
||||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/> |
android:fillColor="#00000000" |
||||||
<path android:fillColor="#00000000" android:pathData="M79,19L79,89" |
android:pathData="M0,29L108,29" |
||||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/> |
android:strokeColor="#33FFFFFF" |
||||||
|
android:strokeWidth="0.8" /> |
||||||
|
<path |
||||||
|
android:fillColor="#00000000" |
||||||
|
android:pathData="M0,39L108,39" |
||||||
|
android:strokeColor="#33FFFFFF" |
||||||
|
android:strokeWidth="0.8" /> |
||||||
|
<path |
||||||
|
android:fillColor="#00000000" |
||||||
|
android:pathData="M0,49L108,49" |
||||||
|
android:strokeColor="#33FFFFFF" |
||||||
|
android:strokeWidth="0.8" /> |
||||||
|
<path |
||||||
|
android:fillColor="#00000000" |
||||||
|
android:pathData="M0,59L108,59" |
||||||
|
android:strokeColor="#33FFFFFF" |
||||||
|
android:strokeWidth="0.8" /> |
||||||
|
<path |
||||||
|
android:fillColor="#00000000" |
||||||
|
android:pathData="M0,69L108,69" |
||||||
|
android:strokeColor="#33FFFFFF" |
||||||
|
android:strokeWidth="0.8" /> |
||||||
|
<path |
||||||
|
android:fillColor="#00000000" |
||||||
|
android:pathData="M0,79L108,79" |
||||||
|
android:strokeColor="#33FFFFFF" |
||||||
|
android:strokeWidth="0.8" /> |
||||||
|
<path |
||||||
|
android:fillColor="#00000000" |
||||||
|
android:pathData="M0,89L108,89" |
||||||
|
android:strokeColor="#33FFFFFF" |
||||||
|
android:strokeWidth="0.8" /> |
||||||
|
<path |
||||||
|
android:fillColor="#00000000" |
||||||
|
android:pathData="M0,99L108,99" |
||||||
|
android:strokeColor="#33FFFFFF" |
||||||
|
android:strokeWidth="0.8" /> |
||||||
|
<path |
||||||
|
android:fillColor="#00000000" |
||||||
|
android:pathData="M19,29L89,29" |
||||||
|
android:strokeColor="#33FFFFFF" |
||||||
|
android:strokeWidth="0.8" /> |
||||||
|
<path |
||||||
|
android:fillColor="#00000000" |
||||||
|
android:pathData="M19,39L89,39" |
||||||
|
android:strokeColor="#33FFFFFF" |
||||||
|
android:strokeWidth="0.8" /> |
||||||
|
<path |
||||||
|
android:fillColor="#00000000" |
||||||
|
android:pathData="M19,49L89,49" |
||||||
|
android:strokeColor="#33FFFFFF" |
||||||
|
android:strokeWidth="0.8" /> |
||||||
|
<path |
||||||
|
android:fillColor="#00000000" |
||||||
|
android:pathData="M19,59L89,59" |
||||||
|
android:strokeColor="#33FFFFFF" |
||||||
|
android:strokeWidth="0.8" /> |
||||||
|
<path |
||||||
|
android:fillColor="#00000000" |
||||||
|
android:pathData="M19,69L89,69" |
||||||
|
android:strokeColor="#33FFFFFF" |
||||||
|
android:strokeWidth="0.8" /> |
||||||
|
<path |
||||||
|
android:fillColor="#00000000" |
||||||
|
android:pathData="M19,79L89,79" |
||||||
|
android:strokeColor="#33FFFFFF" |
||||||
|
android:strokeWidth="0.8" /> |
||||||
|
<path |
||||||
|
android:fillColor="#00000000" |
||||||
|
android:pathData="M29,19L29,89" |
||||||
|
android:strokeColor="#33FFFFFF" |
||||||
|
android:strokeWidth="0.8" /> |
||||||
|
<path |
||||||
|
android:fillColor="#00000000" |
||||||
|
android:pathData="M39,19L39,89" |
||||||
|
android:strokeColor="#33FFFFFF" |
||||||
|
android:strokeWidth="0.8" /> |
||||||
|
<path |
||||||
|
android:fillColor="#00000000" |
||||||
|
android:pathData="M49,19L49,89" |
||||||
|
android:strokeColor="#33FFFFFF" |
||||||
|
android:strokeWidth="0.8" /> |
||||||
|
<path |
||||||
|
android:fillColor="#00000000" |
||||||
|
android:pathData="M59,19L59,89" |
||||||
|
android:strokeColor="#33FFFFFF" |
||||||
|
android:strokeWidth="0.8" /> |
||||||
|
<path |
||||||
|
android:fillColor="#00000000" |
||||||
|
android:pathData="M69,19L69,89" |
||||||
|
android:strokeColor="#33FFFFFF" |
||||||
|
android:strokeWidth="0.8" /> |
||||||
|
<path |
||||||
|
android:fillColor="#00000000" |
||||||
|
android:pathData="M79,19L79,89" |
||||||
|
android:strokeColor="#33FFFFFF" |
||||||
|
android:strokeWidth="0.8" /> |
||||||
</vector> |
</vector> |
||||||
|
@ -1,5 +1,11 @@ |
|||||||
<vector android:alpha="0.57" android:height="24dp" |
<vector android:alpha="0.57" |
||||||
android:tint="#0A0033" android:viewportHeight="24.0" |
android:height="24dp" |
||||||
android:viewportWidth="24.0" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android"> |
android:tint="#0A0033" |
||||||
<path android:fillColor="#FF000000" android:pathData="M20,11H7.83l5.59,-5.59L12,4l-8,8 8,8 1.41,-1.41L7.83,13H20v-2z"/> |
android:viewportHeight="24.0" |
||||||
|
android:viewportWidth="24.0" |
||||||
|
android:width="24dp" |
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"> |
||||||
|
<path |
||||||
|
android:fillColor="#FF000000" |
||||||
|
android:pathData="M20,11H7.83l5.59,-5.59L12,4l-8,8 8,8 1.41,-1.41L7.83,13H20v-2z" /> |
||||||
</vector> |
</vector> |
||||||
|
@ -1,5 +1,11 @@ |
|||||||
<vector android:alpha="0.57" android:height="24dp" |
<vector android:alpha="0.57" |
||||||
android:tint="#FB2516" android:viewportHeight="24.0" |
android:height="24dp" |
||||||
android:viewportWidth="24.0" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android"> |
android:tint="#FB2516" |
||||||
<path android:fillColor="#FF000000" android:pathData="M9.4,10.5l4.77,-8.26C13.47,2.09 12.75,2 12,2c-2.4,0 -4.6,0.85 -6.32,2.25l3.66,6.35 0.06,-0.1zM21.54,9c-0.92,-2.92 -3.15,-5.26 -6,-6.34L11.88,9h9.66zM21.8,10h-7.49l0.29,0.5 4.76,8.25C21,16.97 22,14.61 22,12c0,-0.69 -0.07,-1.35 -0.2,-2zM8.54,12l-3.9,-6.75C3.01,7.03 2,9.39 2,12c0,0.69 0.07,1.35 0.2,2h7.49l-1.15,-2zM2.46,15c0.92,2.92 3.15,5.26 6,6.34L12.12,15L2.46,15zM13.73,15l-3.9,6.76c0.7,0.15 1.42,0.24 2.17,0.24 2.4,0 4.6,-0.85 6.32,-2.25l-3.66,-6.35 -0.93,1.6z"/> |
android:viewportHeight="24.0" |
||||||
|
android:viewportWidth="24.0" |
||||||
|
android:width="24dp" |
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"> |
||||||
|
<path |
||||||
|
android:fillColor="#FF000000" |
||||||
|
android:pathData="M9.4,10.5l4.77,-8.26C13.47,2.09 12.75,2 12,2c-2.4,0 -4.6,0.85 -6.32,2.25l3.66,6.35 0.06,-0.1zM21.54,9c-0.92,-2.92 -3.15,-5.26 -6,-6.34L11.88,9h9.66zM21.8,10h-7.49l0.29,0.5 4.76,8.25C21,16.97 22,14.61 22,12c0,-0.69 -0.07,-1.35 -0.2,-2zM8.54,12l-3.9,-6.75C3.01,7.03 2,9.39 2,12c0,0.69 0.07,1.35 0.2,2h7.49l-1.15,-2zM2.46,15c0.92,2.92 3.15,5.26 6,6.34L12.12,15L2.46,15zM13.73,15l-3.9,6.76c0.7,0.15 1.42,0.24 2.17,0.24 2.4,0 4.6,-0.85 6.32,-2.25l-3.66,-6.35 -0.93,1.6z" /> |
||||||
</vector> |
</vector> |
||||||
|
@ -0,0 +1,4 @@ |
|||||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||||
|
<network-security-config> |
||||||
|
<base-config cleartextTrafficPermitted="true" /> |
||||||
|
</network-security-config> |
@ -0,0 +1 @@ |
|||||||
|
/build |
@ -0,0 +1,90 @@ |
|||||||
|
apply plugin: 'com.android.application' |
||||||
|
apply plugin: 'kotlin-android' |
||||||
|
apply plugin: 'kotlin-android-extensions' |
||||||
|
apply plugin: 'kotlin-kapt' |
||||||
|
apply plugin: 'org.greenrobot.greendao' |
||||||
|
android { |
||||||
|
compileSdkVersion 29 |
||||||
|
buildToolsVersion "29.0.3" |
||||||
|
|
||||||
|
defaultConfig { |
||||||
|
applicationId "com.zwy.demo" |
||||||
|
minSdkVersion 19 |
||||||
|
targetSdkVersion 29 |
||||||
|
versionCode 1 |
||||||
|
versionName "1.3.1" |
||||||
|
multiDexEnabled true |
||||||
|
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" |
||||||
|
} |
||||||
|
|
||||||
|
buildTypes { |
||||||
|
release { |
||||||
|
minifyEnabled false |
||||||
|
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
dataBinding { |
||||||
|
enabled = true |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
compileOptions { |
||||||
|
sourceCompatibility JavaVersion.VERSION_1_8 |
||||||
|
targetCompatibility JavaVersion.VERSION_1_8 |
||||||
|
} |
||||||
|
|
||||||
|
greendao { |
||||||
|
schemaVersion 1 |
||||||
|
daoPackage 'com.zwy.demo.db' |
||||||
|
targetGenDir 'src/main/java' |
||||||
|
} |
||||||
|
|
||||||
|
aaptOptions { |
||||||
|
noCompress "tflite" |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
dependencies { |
||||||
|
implementation fileTree(dir: "libs", include: ["*.jar"]) |
||||||
|
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" |
||||||
|
implementation 'androidx.core:core-ktx:1.3.0' |
||||||
|
implementation 'androidx.appcompat:appcompat:1.1.0' |
||||||
|
implementation 'androidx.constraintlayout:constraintlayout:1.1.3' |
||||||
|
implementation 'androidx.recyclerview:recyclerview:1.1.0' |
||||||
|
implementation 'androidx.cardview:cardview:1.0.0' |
||||||
|
testImplementation 'junit:junit:4.13' |
||||||
|
androidTestImplementation 'androidx.test.ext:junit:1.1.1' |
||||||
|
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' |
||||||
|
|
||||||
|
implementation "org.koin:koin-android:2.1.5" |
||||||
|
implementation "org.koin:koin-androidx-viewmodel:2.1.5" |
||||||
|
implementation "org.koin:koin-androidx-ext:2.1.5" |
||||||
|
implementation "com.squareup.okhttp3:logging-interceptor:4.7.2" |
||||||
|
|
||||||
|
//retrofit |
||||||
|
implementation "io.reactivex.rxjava2:rxandroid:2.1.1" |
||||||
|
implementation 'com.squareup.retrofit2:retrofit:2.8.2' |
||||||
|
implementation 'com.squareup.retrofit2:converter-gson:2.7.2' |
||||||
|
implementation 'com.squareup.retrofit2:adapter-rxjava2:2.7.2' |
||||||
|
|
||||||
|
//沉浸式状态栏 |
||||||
|
implementation 'com.gyf.immersionbar:immersionbar:3.0.0' |
||||||
|
//适配器快速实现 |
||||||
|
implementation 'com.github.CymChad:BaseRecyclerViewAdapterHelper:3.0.4' |
||||||
|
//图片加载框架 |
||||||
|
implementation 'com.github.bumptech.glide:glide:4.11.0' |
||||||
|
kapt 'com.github.bumptech.glide:compiler:4.11.0' |
||||||
|
|
||||||
|
implementation 'org.greenrobot:greendao:3.3.0' |
||||||
|
implementation 'org.greenrobot:greendao-generator:3.3.0' |
||||||
|
implementation 'com.android.support:multidex:1.0.3' |
||||||
|
implementation "org.jetbrains.anko:anko:0.10.5" |
||||||
|
|
||||||
|
//NSFW鉴黄库 |
||||||
|
implementation 'com.github.devzwy:open_nsfw_android:1.3.0' |
||||||
|
implementation 'pub.devrel:easypermissions:3.0.0' |
||||||
|
|
||||||
|
implementation 'com.github.LuckSiege.PictureSelector:picture_library:2.2.5' |
||||||
|
} |
@ -0,0 +1,21 @@ |
|||||||
|
# Add project specific ProGuard rules here. |
||||||
|
# You can control the set of applied configuration files using the |
||||||
|
# proguardFiles setting in build.gradle. |
||||||
|
# |
||||||
|
# For more details, see |
||||||
|
# http://developer.android.com/guide/developing/tools/proguard.html |
||||||
|
|
||||||
|
# If your project uses WebView with JS, uncomment the following |
||||||
|
# and specify the fully qualified class name to the JavaScript interface |
||||||
|
# class: |
||||||
|
#-keepclassmembers class fqcn.of.javascript.interface.for.webview { |
||||||
|
# public *; |
||||||
|
#} |
||||||
|
|
||||||
|
# Uncomment this to preserve the line number information for |
||||||
|
# debugging stack traces. |
||||||
|
#-keepattributes SourceFile,LineNumberTable |
||||||
|
|
||||||
|
# If you keep the line number information, uncomment this to |
||||||
|
# hide the original source file name. |
||||||
|
#-renamesourcefileattribute SourceFile |
@ -0,0 +1,22 @@ |
|||||||
|
package com.zwy.demo |
||||||
|
|
||||||
|
import android.support.test.InstrumentationRegistry |
||||||
|
import android.support.test.runner.AndroidJUnit4 |
||||||
|
import org.junit.Assert.assertEquals |
||||||
|
import org.junit.Test |
||||||
|
import org.junit.runner.RunWith |
||||||
|
|
||||||
|
/** |
||||||
|
* Instrumented test, which will execute on an Android device. |
||||||
|
* |
||||||
|
* See [testing documentation](http://d.android.com/tools/testing). |
||||||
|
*/ |
||||||
|
@RunWith(AndroidJUnit4::class) |
||||||
|
class ExampleInstrumentedTest { |
||||||
|
@Test |
||||||
|
fun useAppContext() { |
||||||
|
// Context of the app under test. |
||||||
|
val appContext = InstrumentationRegistry.getInstrumentation().targetContext |
||||||
|
assertEquals("com.zwy.demo", appContext.packageName) |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,34 @@ |
|||||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||||
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android" |
||||||
|
package="com.zwy.demo"> |
||||||
|
|
||||||
|
<uses-permission android:name="android.permission.CAMERA" /> |
||||||
|
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> |
||||||
|
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> |
||||||
|
<uses-permission android:name="android.permission.INTERNET" /> |
||||||
|
|
||||||
|
<application |
||||||
|
android:name=".NSFWApplication" |
||||||
|
android:allowBackup="true" |
||||||
|
android:icon="@mipmap/launch" |
||||||
|
android:label="@string/app_name" |
||||||
|
android:networkSecurityConfig="@xml/network_security_config" |
||||||
|
android:roundIcon="@mipmap/launch" |
||||||
|
android:supportsRtl="true" |
||||||
|
android:theme="@style/AppTheme" |
||||||
|
android:usesCleartextTraffic="true"> |
||||||
|
|
||||||
|
<activity |
||||||
|
android:name=".views.MainActivity" |
||||||
|
android:label="@string/main_aty_name"> |
||||||
|
<intent-filter> |
||||||
|
<action android:name="android.intent.action.MAIN" /> |
||||||
|
|
||||||
|
<category android:name="android.intent.category.LAUNCHER" /> |
||||||
|
</intent-filter> |
||||||
|
</activity> |
||||||
|
<activity android:name=".views.ScanPicActivity" |
||||||
|
android:label="@string/myscan"/> |
||||||
|
</application> |
||||||
|
|
||||||
|
</manifest> |
After Width: | Height: | Size: 70 KiB |
After Width: | Height: | Size: 24 KiB |
After Width: | Height: | Size: 37 KiB |
@ -0,0 +1,50 @@ |
|||||||
|
package com.zwy.demo |
||||||
|
|
||||||
|
import android.content.Context |
||||||
|
import androidx.multidex.MultiDexApplication |
||||||
|
import com.zwy.demo.utils.ActivityLifecycleCallback |
||||||
|
import com.zwy.demo.utils.networkModule |
||||||
|
import com.zwy.demo.utils.repositoryModule |
||||||
|
import com.zwy.demo.utils.viewModelModules |
||||||
|
import com.zwy.opennsfw.core.Classifier |
||||||
|
import org.koin.android.ext.koin.androidContext |
||||||
|
import org.koin.android.ext.koin.androidLogger |
||||||
|
import org.koin.core.context.startKoin |
||||||
|
import java.util.* |
||||||
|
|
||||||
|
class NSFWApplication : MultiDexApplication() { |
||||||
|
|
||||||
|
|
||||||
|
override fun onCreate() { |
||||||
|
super.onCreate() |
||||||
|
|
||||||
|
startTime = Date().time |
||||||
|
|
||||||
|
context = this |
||||||
|
|
||||||
|
//全局配置actionbar title |
||||||
|
registerActivityLifecycleCallbacks(ActivityLifecycleCallback()) |
||||||
|
|
||||||
|
//初始化鉴黄库NSFW |
||||||
|
Classifier.Build() |
||||||
|
.context(this) //必须调用 否则会有异常抛出 |
||||||
|
// .isOpenGPU(true)//默认不开启GPU加速 部分机型开启会奔溃,自行选择,默认false |
||||||
|
// .numThreads(1) //分配的线程数 根据手机配置设置,默认1 |
||||||
|
.build() |
||||||
|
//全局注入对象 |
||||||
|
startKoin { |
||||||
|
androidContext(this@NSFWApplication) |
||||||
|
androidLogger() |
||||||
|
modules(networkModule) |
||||||
|
modules(repositoryModule) |
||||||
|
modules(viewModelModules) |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
companion object { |
||||||
|
lateinit var context: Context |
||||||
|
var startTime: Long = 0 |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,111 @@ |
|||||||
|
package com.zwy.demo.base |
||||||
|
|
||||||
|
import android.app.Dialog |
||||||
|
import android.content.DialogInterface |
||||||
|
import android.os.Bundle |
||||||
|
import android.util.Log |
||||||
|
import androidx.appcompat.app.AppCompatActivity |
||||||
|
import androidx.databinding.DataBindingUtil |
||||||
|
import androidx.databinding.ViewDataBinding |
||||||
|
import androidx.lifecycle.Observer |
||||||
|
import com.gyf.immersionbar.ImmersionBar |
||||||
|
import com.zwy.demo.R |
||||||
|
import org.jetbrains.anko.indeterminateProgressDialog |
||||||
|
import org.koin.java.KoinJavaComponent.get |
||||||
|
import java.lang.reflect.ParameterizedType |
||||||
|
import java.lang.reflect.Type |
||||||
|
|
||||||
|
abstract class BaseActivity<V : ViewDataBinding, VM : BaseViewModel> : AppCompatActivity(), |
||||||
|
DialogInterface.OnCancelListener { |
||||||
|
|
||||||
|
lateinit var binding: V |
||||||
|
lateinit var viewModel: VM |
||||||
|
var dialog: Dialog? = null |
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) { |
||||||
|
super.onCreate(savedInstanceState) |
||||||
|
ImmersionBar.with(this).fitsSystemWindows(true).statusBarColor(R.color.colorPrimary).init() |
||||||
|
initViewDataBinding(savedInstanceState) |
||||||
|
registorUIChangeLiveDataCallBack() |
||||||
|
initData() |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* 注入绑定 |
||||||
|
*/ |
||||||
|
private fun initViewDataBinding(savedInstanceState: Bundle?) { |
||||||
|
binding = DataBindingUtil.setContentView(this, initContentView(savedInstanceState)) |
||||||
|
val type: Type = javaClass.genericSuperclass!! |
||||||
|
viewModel = get((type as ParameterizedType).actualTypeArguments[1] as Class<VM>) |
||||||
|
binding.lifecycleOwner = this |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 注册ViewModel与View的契约UI回调事件 |
||||||
|
*/ |
||||||
|
protected open fun registorUIChangeLiveDataCallBack() { |
||||||
|
|
||||||
|
viewModel.appLiveData.observe(this, Observer { |
||||||
|
|
||||||
|
when (it.type) { |
||||||
|
0 -> { |
||||||
|
//加载进度条 |
||||||
|
if (it.text.isNotBlank()) initDialog(it.text) |
||||||
|
dialog?.show() |
||||||
|
} |
||||||
|
1 -> { |
||||||
|
//取消进度条 |
||||||
|
if (dialog != null && dialog?.isShowing == true) { |
||||||
|
dialog?.dismiss() |
||||||
|
} |
||||||
|
} |
||||||
|
2 -> { |
||||||
|
//关闭页面 |
||||||
|
finish() |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* |
||||||
|
* 父类onCreate执行完成后调用 |
||||||
|
*/ |
||||||
|
abstract fun initData() |
||||||
|
|
||||||
|
/** |
||||||
|
* 初始化根布局 |
||||||
|
* |
||||||
|
* @return 布局layout的id |
||||||
|
*/ |
||||||
|
abstract fun initContentView(savedInstanceState: Bundle?): Int |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* 初始化进度条 |
||||||
|
*/ |
||||||
|
private fun initDialog(msg: String) { |
||||||
|
dialog = indeterminateProgressDialog(msg, "提示") |
||||||
|
dialog?.setCanceledOnTouchOutside(false) |
||||||
|
dialog?.setOnCancelListener(this) |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 页面进度条对话框被取消后的回掉 |
||||||
|
*/ |
||||||
|
override fun onCancel(dialog: DialogInterface?) { |
||||||
|
Log.d(com.zwy.demo.utils.TAG, "进度条销毁回掉") |
||||||
|
} |
||||||
|
|
||||||
|
override fun onDestroy() { |
||||||
|
super.onDestroy() |
||||||
|
binding.unbind() |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
} |
||||||
|
|
@ -0,0 +1,32 @@ |
|||||||
|
package com.zwy.demo.base |
||||||
|
|
||||||
|
import android.util.Log |
||||||
|
import androidx.lifecycle.MutableLiveData |
||||||
|
import androidx.lifecycle.ViewModel |
||||||
|
import com.zwy.demo.utils.AppLiveData |
||||||
|
import com.zwy.demo.utils.TAG |
||||||
|
import io.reactivex.disposables.CompositeDisposable |
||||||
|
import io.reactivex.disposables.Disposable |
||||||
|
|
||||||
|
|
||||||
|
open class BaseViewModel : ViewModel() { |
||||||
|
val appLiveData = MutableLiveData<AppLiveData>() |
||||||
|
|
||||||
|
private var mCompositeDisposable: CompositeDisposable? = null |
||||||
|
|
||||||
|
/** |
||||||
|
* 将所有请求加入集合,页面推出后统一取消 |
||||||
|
*/ |
||||||
|
fun addSubscribe(subscribe: Disposable) { |
||||||
|
if (mCompositeDisposable == null) mCompositeDisposable = CompositeDisposable() |
||||||
|
mCompositeDisposable!!.add(subscribe) |
||||||
|
} |
||||||
|
|
||||||
|
override fun onCleared() { |
||||||
|
super.onCleared() |
||||||
|
Log.d(TAG, "页面销毁,取消全部网络请求") |
||||||
|
if (mCompositeDisposable != null) mCompositeDisposable!!.clear() |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
} |
@ -0,0 +1,99 @@ |
|||||||
|
package com.zwy.demo.db; |
||||||
|
|
||||||
|
import android.content.Context; |
||||||
|
import android.database.sqlite.SQLiteDatabase; |
||||||
|
import android.database.sqlite.SQLiteDatabase.CursorFactory; |
||||||
|
import android.util.Log; |
||||||
|
|
||||||
|
import org.greenrobot.greendao.AbstractDaoMaster; |
||||||
|
import org.greenrobot.greendao.database.StandardDatabase; |
||||||
|
import org.greenrobot.greendao.database.Database; |
||||||
|
import org.greenrobot.greendao.database.DatabaseOpenHelper; |
||||||
|
import org.greenrobot.greendao.identityscope.IdentityScopeType; |
||||||
|
|
||||||
|
|
||||||
|
// THIS CODE IS GENERATED BY greenDAO, DO NOT EDIT.
|
||||||
|
/** |
||||||
|
* Master of DAO (schema version 1): knows all DAOs. |
||||||
|
*/ |
||||||
|
public class DaoMaster extends AbstractDaoMaster { |
||||||
|
public static final int SCHEMA_VERSION = 1; |
||||||
|
|
||||||
|
/** Creates underlying database table using DAOs. */ |
||||||
|
public static void createAllTables(Database db, boolean ifNotExists) { |
||||||
|
HomeTitleDao.createTable(db, ifNotExists); |
||||||
|
ImageBeanDao.createTable(db, ifNotExists); |
||||||
|
} |
||||||
|
|
||||||
|
/** Drops underlying database table using DAOs. */ |
||||||
|
public static void dropAllTables(Database db, boolean ifExists) { |
||||||
|
HomeTitleDao.dropTable(db, ifExists); |
||||||
|
ImageBeanDao.dropTable(db, ifExists); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* WARNING: Drops all table on Upgrade! Use only during development. |
||||||
|
* Convenience method using a {@link DevOpenHelper}. |
||||||
|
*/ |
||||||
|
public static DaoSession newDevSession(Context context, String name) { |
||||||
|
Database db = new DevOpenHelper(context, name).getWritableDb(); |
||||||
|
DaoMaster daoMaster = new DaoMaster(db); |
||||||
|
return daoMaster.newSession(); |
||||||
|
} |
||||||
|
|
||||||
|
public DaoMaster(SQLiteDatabase db) { |
||||||
|
this(new StandardDatabase(db)); |
||||||
|
} |
||||||
|
|
||||||
|
public DaoMaster(Database db) { |
||||||
|
super(db, SCHEMA_VERSION); |
||||||
|
registerDaoClass(HomeTitleDao.class); |
||||||
|
registerDaoClass(ImageBeanDao.class); |
||||||
|
} |
||||||
|
|
||||||
|
public DaoSession newSession() { |
||||||
|
return new DaoSession(db, IdentityScopeType.Session, daoConfigMap); |
||||||
|
} |
||||||
|
|
||||||
|
public DaoSession newSession(IdentityScopeType type) { |
||||||
|
return new DaoSession(db, type, daoConfigMap); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Calls {@link #createAllTables(Database, boolean)} in {@link #onCreate(Database)} - |
||||||
|
*/ |
||||||
|
public static abstract class OpenHelper extends DatabaseOpenHelper { |
||||||
|
public OpenHelper(Context context, String name) { |
||||||
|
super(context, name, SCHEMA_VERSION); |
||||||
|
} |
||||||
|
|
||||||
|
public OpenHelper(Context context, String name, CursorFactory factory) { |
||||||
|
super(context, name, factory, SCHEMA_VERSION); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void onCreate(Database db) { |
||||||
|
Log.i("greenDAO", "Creating tables for schema version " + SCHEMA_VERSION); |
||||||
|
createAllTables(db, false); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** WARNING: Drops all table on Upgrade! Use only during development. */ |
||||||
|
public static class DevOpenHelper extends OpenHelper { |
||||||
|
public DevOpenHelper(Context context, String name) { |
||||||
|
super(context, name); |
||||||
|
} |
||||||
|
|
||||||
|
public DevOpenHelper(Context context, String name, CursorFactory factory) { |
||||||
|
super(context, name, factory); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void onUpgrade(Database db, int oldVersion, int newVersion) { |
||||||
|
Log.i("greenDAO", "Upgrading schema from version " + oldVersion + " to " + newVersion + " by dropping all tables"); |
||||||
|
dropAllTables(db, true); |
||||||
|
onCreate(db); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,62 @@ |
|||||||
|
package com.zwy.demo.db; |
||||||
|
|
||||||
|
import java.util.Map; |
||||||
|
|
||||||
|
import org.greenrobot.greendao.AbstractDao; |
||||||
|
import org.greenrobot.greendao.AbstractDaoSession; |
||||||
|
import org.greenrobot.greendao.database.Database; |
||||||
|
import org.greenrobot.greendao.identityscope.IdentityScopeType; |
||||||
|
import org.greenrobot.greendao.internal.DaoConfig; |
||||||
|
|
||||||
|
import com.zwy.demo.dbbean.HomeTitle; |
||||||
|
import com.zwy.demo.dbbean.ImageBean; |
||||||
|
|
||||||
|
import com.zwy.demo.db.HomeTitleDao; |
||||||
|
import com.zwy.demo.db.ImageBeanDao; |
||||||
|
|
||||||
|
// THIS CODE IS GENERATED BY greenDAO, DO NOT EDIT.
|
||||||
|
|
||||||
|
/** |
||||||
|
* {@inheritDoc} |
||||||
|
* |
||||||
|
* @see org.greenrobot.greendao.AbstractDaoSession |
||||||
|
*/ |
||||||
|
public class DaoSession extends AbstractDaoSession { |
||||||
|
|
||||||
|
private final DaoConfig homeTitleDaoConfig; |
||||||
|
private final DaoConfig imageBeanDaoConfig; |
||||||
|
|
||||||
|
private final HomeTitleDao homeTitleDao; |
||||||
|
private final ImageBeanDao imageBeanDao; |
||||||
|
|
||||||
|
public DaoSession(Database db, IdentityScopeType type, Map<Class<? extends AbstractDao<?, ?>>, DaoConfig> |
||||||
|
daoConfigMap) { |
||||||
|
super(db); |
||||||
|
|
||||||
|
homeTitleDaoConfig = daoConfigMap.get(HomeTitleDao.class).clone(); |
||||||
|
homeTitleDaoConfig.initIdentityScope(type); |
||||||
|
|
||||||
|
imageBeanDaoConfig = daoConfigMap.get(ImageBeanDao.class).clone(); |
||||||
|
imageBeanDaoConfig.initIdentityScope(type); |
||||||
|
|
||||||
|
homeTitleDao = new HomeTitleDao(homeTitleDaoConfig, this); |
||||||
|
imageBeanDao = new ImageBeanDao(imageBeanDaoConfig, this); |
||||||
|
|
||||||
|
registerDao(HomeTitle.class, homeTitleDao); |
||||||
|
registerDao(ImageBean.class, imageBeanDao); |
||||||
|
} |
||||||
|
|
||||||
|
public void clear() { |
||||||
|
homeTitleDaoConfig.clearIdentityScope(); |
||||||
|
imageBeanDaoConfig.clearIdentityScope(); |
||||||
|
} |
||||||
|
|
||||||
|
public HomeTitleDao getHomeTitleDao() { |
||||||
|
return homeTitleDao; |
||||||
|
} |
||||||
|
|
||||||
|
public ImageBeanDao getImageBeanDao() { |
||||||
|
return imageBeanDao; |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,129 @@ |
|||||||
|
package com.zwy.demo.db; |
||||||
|
|
||||||
|
import android.database.Cursor; |
||||||
|
import android.database.sqlite.SQLiteStatement; |
||||||
|
|
||||||
|
import org.greenrobot.greendao.AbstractDao; |
||||||
|
import org.greenrobot.greendao.Property; |
||||||
|
import org.greenrobot.greendao.internal.DaoConfig; |
||||||
|
import org.greenrobot.greendao.database.Database; |
||||||
|
import org.greenrobot.greendao.database.DatabaseStatement; |
||||||
|
|
||||||
|
import com.zwy.demo.dbbean.HomeTitle; |
||||||
|
|
||||||
|
// THIS CODE IS GENERATED BY greenDAO, DO NOT EDIT.
|
||||||
|
/** |
||||||
|
* DAO for table "HOME_TITLE". |
||||||
|
*/ |
||||||
|
public class HomeTitleDao extends AbstractDao<HomeTitle, Long> { |
||||||
|
|
||||||
|
public static final String TABLENAME = "HOME_TITLE"; |
||||||
|
|
||||||
|
/** |
||||||
|
* Properties of entity HomeTitle.<br/> |
||||||
|
* Can be used for QueryBuilder and for referencing column names. |
||||||
|
*/ |
||||||
|
public static class Properties { |
||||||
|
public final static Property Id = new Property(0, Long.class, "id", true, "_id"); |
||||||
|
public final static Property Title = new Property(1, String.class, "title", false, "TITLE"); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
public HomeTitleDao(DaoConfig config) { |
||||||
|
super(config); |
||||||
|
} |
||||||
|
|
||||||
|
public HomeTitleDao(DaoConfig config, DaoSession daoSession) { |
||||||
|
super(config, daoSession); |
||||||
|
} |
||||||
|
|
||||||
|
/** Creates the underlying database table. */ |
||||||
|
public static void createTable(Database db, boolean ifNotExists) { |
||||||
|
String constraint = ifNotExists? "IF NOT EXISTS ": ""; |
||||||
|
db.execSQL("CREATE TABLE " + constraint + "\"HOME_TITLE\" (" + //
|
||||||
|
"\"_id\" INTEGER PRIMARY KEY ," + // 0: id
|
||||||
|
"\"TITLE\" TEXT);"); // 1: title
|
||||||
|
} |
||||||
|
|
||||||
|
/** Drops the underlying database table. */ |
||||||
|
public static void dropTable(Database db, boolean ifExists) { |
||||||
|
String sql = "DROP TABLE " + (ifExists ? "IF EXISTS " : "") + "\"HOME_TITLE\""; |
||||||
|
db.execSQL(sql); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
protected final void bindValues(DatabaseStatement stmt, HomeTitle entity) { |
||||||
|
stmt.clearBindings(); |
||||||
|
|
||||||
|
Long id = entity.getId(); |
||||||
|
if (id != null) { |
||||||
|
stmt.bindLong(1, id); |
||||||
|
} |
||||||
|
|
||||||
|
String title = entity.getTitle(); |
||||||
|
if (title != null) { |
||||||
|
stmt.bindString(2, title); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
protected final void bindValues(SQLiteStatement stmt, HomeTitle entity) { |
||||||
|
stmt.clearBindings(); |
||||||
|
|
||||||
|
Long id = entity.getId(); |
||||||
|
if (id != null) { |
||||||
|
stmt.bindLong(1, id); |
||||||
|
} |
||||||
|
|
||||||
|
String title = entity.getTitle(); |
||||||
|
if (title != null) { |
||||||
|
stmt.bindString(2, title); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Long readKey(Cursor cursor, int offset) { |
||||||
|
return cursor.isNull(offset + 0) ? null : cursor.getLong(offset + 0); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public HomeTitle readEntity(Cursor cursor, int offset) { |
||||||
|
HomeTitle entity = new HomeTitle( //
|
||||||
|
cursor.isNull(offset + 0) ? null : cursor.getLong(offset + 0), // id
|
||||||
|
cursor.isNull(offset + 1) ? null : cursor.getString(offset + 1) // title
|
||||||
|
); |
||||||
|
return entity; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void readEntity(Cursor cursor, HomeTitle entity, int offset) { |
||||||
|
entity.setId(cursor.isNull(offset + 0) ? null : cursor.getLong(offset + 0)); |
||||||
|
entity.setTitle(cursor.isNull(offset + 1) ? null : cursor.getString(offset + 1)); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
protected final Long updateKeyAfterInsert(HomeTitle entity, long rowId) { |
||||||
|
entity.setId(rowId); |
||||||
|
return rowId; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Long getKey(HomeTitle entity) { |
||||||
|
if(entity != null) { |
||||||
|
return entity.getId(); |
||||||
|
} else { |
||||||
|
return null; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean hasKey(HomeTitle entity) { |
||||||
|
return entity.getId() != null; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
protected final boolean isEntityUpdateable() { |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,171 @@ |
|||||||
|
package com.zwy.demo.db; |
||||||
|
|
||||||
|
import android.database.Cursor; |
||||||
|
import android.database.sqlite.SQLiteStatement; |
||||||
|
|
||||||
|
import org.greenrobot.greendao.AbstractDao; |
||||||
|
import org.greenrobot.greendao.Property; |
||||||
|
import org.greenrobot.greendao.internal.DaoConfig; |
||||||
|
import org.greenrobot.greendao.database.Database; |
||||||
|
import org.greenrobot.greendao.database.DatabaseStatement; |
||||||
|
|
||||||
|
import com.zwy.demo.dbbean.ImageBean; |
||||||
|
|
||||||
|
// THIS CODE IS GENERATED BY greenDAO, DO NOT EDIT.
|
||||||
|
/** |
||||||
|
* DAO for table "IMAGE_BEAN". |
||||||
|
*/ |
||||||
|
public class ImageBeanDao extends AbstractDao<ImageBean, Long> { |
||||||
|
|
||||||
|
public static final String TABLENAME = "IMAGE_BEAN"; |
||||||
|
|
||||||
|
/** |
||||||
|
* Properties of entity ImageBean.<br/> |
||||||
|
* Can be used for QueryBuilder and for referencing column names. |
||||||
|
*/ |
||||||
|
public static class Properties { |
||||||
|
public final static Property CreateTime = new Property(0, String.class, "createTime", false, "CREATE_TIME"); |
||||||
|
public final static Property Id = new Property(1, Long.class, "id", true, "_id"); |
||||||
|
public final static Property ImgUrl = new Property(2, String.class, "imgUrl", false, "IMG_URL"); |
||||||
|
public final static Property Nsfw = new Property(3, Float.class, "nsfw", false, "NSFW"); |
||||||
|
public final static Property Sfw = new Property(4, Float.class, "sfw", false, "SFW"); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
public ImageBeanDao(DaoConfig config) { |
||||||
|
super(config); |
||||||
|
} |
||||||
|
|
||||||
|
public ImageBeanDao(DaoConfig config, DaoSession daoSession) { |
||||||
|
super(config, daoSession); |
||||||
|
} |
||||||
|
|
||||||
|
/** Creates the underlying database table. */ |
||||||
|
public static void createTable(Database db, boolean ifNotExists) { |
||||||
|
String constraint = ifNotExists? "IF NOT EXISTS ": ""; |
||||||
|
db.execSQL("CREATE TABLE " + constraint + "\"IMAGE_BEAN\" (" + //
|
||||||
|
"\"CREATE_TIME\" TEXT," + // 0: createTime
|
||||||
|
"\"_id\" INTEGER PRIMARY KEY ," + // 1: id
|
||||||
|
"\"IMG_URL\" TEXT," + // 2: imgUrl
|
||||||
|
"\"NSFW\" REAL," + // 3: nsfw
|
||||||
|
"\"SFW\" REAL);"); // 4: sfw
|
||||||
|
} |
||||||
|
|
||||||
|
/** Drops the underlying database table. */ |
||||||
|
public static void dropTable(Database db, boolean ifExists) { |
||||||
|
String sql = "DROP TABLE " + (ifExists ? "IF EXISTS " : "") + "\"IMAGE_BEAN\""; |
||||||
|
db.execSQL(sql); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
protected final void bindValues(DatabaseStatement stmt, ImageBean entity) { |
||||||
|
stmt.clearBindings(); |
||||||
|
|
||||||
|
String createTime = entity.getCreateTime(); |
||||||
|
if (createTime != null) { |
||||||
|
stmt.bindString(1, createTime); |
||||||
|
} |
||||||
|
|
||||||
|
Long id = entity.getId(); |
||||||
|
if (id != null) { |
||||||
|
stmt.bindLong(2, id); |
||||||
|
} |
||||||
|
|
||||||
|
String imgUrl = entity.getImgUrl(); |
||||||
|
if (imgUrl != null) { |
||||||
|
stmt.bindString(3, imgUrl); |
||||||
|
} |
||||||
|
|
||||||
|
Float nsfw = entity.getNsfw(); |
||||||
|
if (nsfw != null) { |
||||||
|
stmt.bindDouble(4, nsfw); |
||||||
|
} |
||||||
|
|
||||||
|
Float sfw = entity.getSfw(); |
||||||
|
if (sfw != null) { |
||||||
|
stmt.bindDouble(5, sfw); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
protected final void bindValues(SQLiteStatement stmt, ImageBean entity) { |
||||||
|
stmt.clearBindings(); |
||||||
|
|
||||||
|
String createTime = entity.getCreateTime(); |
||||||
|
if (createTime != null) { |
||||||
|
stmt.bindString(1, createTime); |
||||||
|
} |
||||||
|
|
||||||
|
Long id = entity.getId(); |
||||||
|
if (id != null) { |
||||||
|
stmt.bindLong(2, id); |
||||||
|
} |
||||||
|
|
||||||
|
String imgUrl = entity.getImgUrl(); |
||||||
|
if (imgUrl != null) { |
||||||
|
stmt.bindString(3, imgUrl); |
||||||
|
} |
||||||
|
|
||||||
|
Float nsfw = entity.getNsfw(); |
||||||
|
if (nsfw != null) { |
||||||
|
stmt.bindDouble(4, nsfw); |
||||||
|
} |
||||||
|
|
||||||
|
Float sfw = entity.getSfw(); |
||||||
|
if (sfw != null) { |
||||||
|
stmt.bindDouble(5, sfw); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Long readKey(Cursor cursor, int offset) { |
||||||
|
return cursor.isNull(offset + 1) ? null : cursor.getLong(offset + 1); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public ImageBean readEntity(Cursor cursor, int offset) { |
||||||
|
ImageBean entity = new ImageBean( //
|
||||||
|
cursor.isNull(offset + 0) ? null : cursor.getString(offset + 0), // createTime
|
||||||
|
cursor.isNull(offset + 1) ? null : cursor.getLong(offset + 1), // id
|
||||||
|
cursor.isNull(offset + 2) ? null : cursor.getString(offset + 2), // imgUrl
|
||||||
|
cursor.isNull(offset + 3) ? null : cursor.getFloat(offset + 3), // nsfw
|
||||||
|
cursor.isNull(offset + 4) ? null : cursor.getFloat(offset + 4) // sfw
|
||||||
|
); |
||||||
|
return entity; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void readEntity(Cursor cursor, ImageBean entity, int offset) { |
||||||
|
entity.setCreateTime(cursor.isNull(offset + 0) ? null : cursor.getString(offset + 0)); |
||||||
|
entity.setId(cursor.isNull(offset + 1) ? null : cursor.getLong(offset + 1)); |
||||||
|
entity.setImgUrl(cursor.isNull(offset + 2) ? null : cursor.getString(offset + 2)); |
||||||
|
entity.setNsfw(cursor.isNull(offset + 3) ? null : cursor.getFloat(offset + 3)); |
||||||
|
entity.setSfw(cursor.isNull(offset + 4) ? null : cursor.getFloat(offset + 4)); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
protected final Long updateKeyAfterInsert(ImageBean entity, long rowId) { |
||||||
|
entity.setId(rowId); |
||||||
|
return rowId; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Long getKey(ImageBean entity) { |
||||||
|
if(entity != null) { |
||||||
|
return entity.getId(); |
||||||
|
} else { |
||||||
|
return null; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean hasKey(ImageBean entity) { |
||||||
|
return entity.getId() != null; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
protected final boolean isEntityUpdateable() { |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,42 @@ |
|||||||
|
package com.zwy.demo.dbbean; |
||||||
|
|
||||||
|
import org.greenrobot.greendao.annotation.Entity; |
||||||
|
import org.greenrobot.greendao.annotation.Generated; |
||||||
|
import org.greenrobot.greendao.annotation.Id; |
||||||
|
|
||||||
|
@Entity |
||||||
|
public class HomeTitle { |
||||||
|
@Id |
||||||
|
private Long id; |
||||||
|
private String title; |
||||||
|
|
||||||
|
@Generated(hash = 2016918462) |
||||||
|
public HomeTitle(Long id, String title) { |
||||||
|
this.id = id; |
||||||
|
this.title = title; |
||||||
|
} |
||||||
|
|
||||||
|
@Generated(hash = 869810785) |
||||||
|
public HomeTitle() { |
||||||
|
} |
||||||
|
|
||||||
|
public HomeTitle(String title) { |
||||||
|
this.title = title; |
||||||
|
} |
||||||
|
|
||||||
|
public Long getId() { |
||||||
|
return this.id; |
||||||
|
} |
||||||
|
|
||||||
|
public void setId(Long id) { |
||||||
|
this.id = id; |
||||||
|
} |
||||||
|
|
||||||
|
public String getTitle() { |
||||||
|
return this.title; |
||||||
|
} |
||||||
|
|
||||||
|
public void setTitle(String title) { |
||||||
|
this.title = title; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,78 @@ |
|||||||
|
package com.zwy.demo.dbbean; |
||||||
|
|
||||||
|
import org.greenrobot.greendao.annotation.Entity; |
||||||
|
import org.greenrobot.greendao.annotation.Generated; |
||||||
|
import org.greenrobot.greendao.annotation.Id; |
||||||
|
|
||||||
|
@Entity |
||||||
|
public class ImageBean { |
||||||
|
private String createTime; |
||||||
|
@Id |
||||||
|
private Long id; |
||||||
|
private String imgUrl = ""; |
||||||
|
private Float nsfw = 0.0f; |
||||||
|
private Float sfw = 0.0f; |
||||||
|
|
||||||
|
|
||||||
|
@Generated(hash = 716432991) |
||||||
|
public ImageBean(String createTime, Long id, String imgUrl, Float nsfw, |
||||||
|
Float sfw) { |
||||||
|
this.createTime = createTime; |
||||||
|
this.id = id; |
||||||
|
this.imgUrl = imgUrl; |
||||||
|
this.nsfw = nsfw; |
||||||
|
this.sfw = sfw; |
||||||
|
} |
||||||
|
|
||||||
|
public ImageBean(String imgUrl, Float nsfw, |
||||||
|
Float sfw) { |
||||||
|
this.imgUrl = imgUrl; |
||||||
|
this.nsfw = nsfw; |
||||||
|
this.sfw = sfw; |
||||||
|
} |
||||||
|
|
||||||
|
@Generated(hash = 645668394) |
||||||
|
public ImageBean() { |
||||||
|
} |
||||||
|
|
||||||
|
public String getCreateTime() { |
||||||
|
return this.createTime; |
||||||
|
} |
||||||
|
|
||||||
|
public void setCreateTime(String createTime) { |
||||||
|
this.createTime = createTime; |
||||||
|
} |
||||||
|
|
||||||
|
public Long getId() { |
||||||
|
return this.id; |
||||||
|
} |
||||||
|
|
||||||
|
public void setId(Long id) { |
||||||
|
this.id = id; |
||||||
|
} |
||||||
|
|
||||||
|
public String getImgUrl() { |
||||||
|
return this.imgUrl; |
||||||
|
} |
||||||
|
|
||||||
|
public void setImgUrl(String imgUrl) { |
||||||
|
this.imgUrl = imgUrl; |
||||||
|
} |
||||||
|
|
||||||
|
public Float getNsfw() { |
||||||
|
return this.nsfw; |
||||||
|
} |
||||||
|
|
||||||
|
public void setNsfw(Float nsfw) { |
||||||
|
this.nsfw = nsfw; |
||||||
|
} |
||||||
|
|
||||||
|
public Float getSfw() { |
||||||
|
return this.sfw; |
||||||
|
} |
||||||
|
|
||||||
|
public void setSfw(Float sfw) { |
||||||
|
this.sfw = sfw; |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,19 @@ |
|||||||
|
package com.zwy.demo.models |
||||||
|
|
||||||
|
import androidx.lifecycle.MutableLiveData |
||||||
|
import com.zwy.demo.base.BaseViewModel |
||||||
|
import com.zwy.demo.dbbean.HomeTitle |
||||||
|
import com.zwy.demo.repositorys.AppRepository |
||||||
|
|
||||||
|
class MainViewModel constructor(val mAppRepository: AppRepository) : |
||||||
|
BaseViewModel() { |
||||||
|
|
||||||
|
var titles = MutableLiveData<List<HomeTitle>>() |
||||||
|
|
||||||
|
|
||||||
|
fun getTitles() { |
||||||
|
this.titles.value = mAppRepository.getHomeTitles() |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
@ -0,0 +1,87 @@ |
|||||||
|
package com.zwy.demo.models |
||||||
|
|
||||||
|
import android.annotation.SuppressLint |
||||||
|
import android.app.Application |
||||||
|
import android.content.Context |
||||||
|
import android.graphics.BitmapFactory |
||||||
|
import androidx.lifecycle.MutableLiveData |
||||||
|
import com.bumptech.glide.Glide |
||||||
|
import com.zwy.demo.NSFWApplication |
||||||
|
import com.zwy.demo.base.BaseViewModel |
||||||
|
import com.zwy.demo.dbbean.ImageBean |
||||||
|
import com.zwy.demo.repositorys.AppRepository |
||||||
|
import com.zwy.demo.utils.AppLiveData |
||||||
|
import getNsfwScore |
||||||
|
import io.reactivex.android.schedulers.AndroidSchedulers |
||||||
|
import io.reactivex.schedulers.Schedulers |
||||||
|
import org.koin.java.KoinJavaComponent.inject |
||||||
|
|
||||||
|
class ScanPicViewModel constructor(val mAppRepository: AppRepository) : |
||||||
|
BaseViewModel() { |
||||||
|
|
||||||
|
|
||||||
|
var imgData = MutableLiveData<List<ImageBean>>() |
||||||
|
|
||||||
|
val context: Context by inject(Application::class.java) |
||||||
|
|
||||||
|
|
||||||
|
@SuppressLint("CheckResult") |
||||||
|
fun startScann(pageIndex: Int) { |
||||||
|
mAppRepository.startScann(pageIndex) |
||||||
|
.subscribeOn(Schedulers.io()) |
||||||
|
.doOnSubscribe { |
||||||
|
addSubscribe(it) |
||||||
|
appLiveData.value = |
||||||
|
AppLiveData(0, if (pageIndex == 0x03) "多图下载较慢,请耐心等待......." else "描中请稍后.......") |
||||||
|
} |
||||||
|
.map { |
||||||
|
return@map when (pageIndex) { |
||||||
|
0x01 -> { |
||||||
|
it.filter { |
||||||
|
val bitmap = |
||||||
|
BitmapFactory.decodeStream(context.resources.assets.open(it.imgUrl)) |
||||||
|
val nsfwScore = bitmap.getNsfwScore() |
||||||
|
it.nsfw = nsfwScore.nsfw |
||||||
|
it.sfw = nsfwScore.sfw |
||||||
|
bitmap.recycle() |
||||||
|
true |
||||||
|
} |
||||||
|
} |
||||||
|
0x02 -> { |
||||||
|
it |
||||||
|
} |
||||||
|
0x03 -> { |
||||||
|
it.filter { |
||||||
|
val nsfwBean = |
||||||
|
Glide.with(NSFWApplication.context).asBitmap().load(it.imgUrl) |
||||||
|
.submit().get().getNsfwScore() |
||||||
|
it.sfw = nsfwBean.sfw |
||||||
|
it.nsfw = nsfwBean.nsfw |
||||||
|
true |
||||||
|
} |
||||||
|
if (it.size > 10) it.subList(it.size - 10, it.size) |
||||||
|
else it |
||||||
|
|
||||||
|
} |
||||||
|
else -> { |
||||||
|
it |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
.observeOn(AndroidSchedulers.mainThread()) |
||||||
|
.subscribe({ |
||||||
|
appLiveData.value = AppLiveData(1, "") |
||||||
|
imgData.value = it |
||||||
|
}, { |
||||||
|
appLiveData.value = AppLiveData(1, "") |
||||||
|
print(it) |
||||||
|
}) |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
|
@ -0,0 +1,16 @@ |
|||||||
|
package com.zwy.demo.repositorys |
||||||
|
|
||||||
|
import com.zwy.demo.dbbean.ImageBean |
||||||
|
import io.reactivex.Observable |
||||||
|
import retrofit2.http.GET |
||||||
|
|
||||||
|
/** |
||||||
|
* 网络请求类 |
||||||
|
*/ |
||||||
|
interface ApiService { |
||||||
|
|
||||||
|
@GET("/imageList.do") |
||||||
|
fun getImageList(): Observable<List<ImageBean>> |
||||||
|
|
||||||
|
|
||||||
|
} |
@ -0,0 +1,56 @@ |
|||||||
|
package com.zwy.demo.repositorys |
||||||
|
|
||||||
|
import android.annotation.SuppressLint |
||||||
|
import android.app.Application |
||||||
|
import com.google.gson.Gson |
||||||
|
import com.zwy.demo.dbbean.HomeTitle |
||||||
|
import com.zwy.demo.dbbean.ImageBean |
||||||
|
import com.zwy.demo.utils.DBHelper |
||||||
|
import io.reactivex.Observable |
||||||
|
import org.koin.java.KoinJavaComponent.inject |
||||||
|
|
||||||
|
/** |
||||||
|
* 数据源 这里决定是从缓存获取还是从网络获取 |
||||||
|
*/ |
||||||
|
class AppRepository constructor( |
||||||
|
private val mApiService: ApiService, |
||||||
|
private val mDBHelper: DBHelper, |
||||||
|
val mGson: Gson |
||||||
|
) : |
||||||
|
Repository { |
||||||
|
|
||||||
|
val context: Application by inject(Application::class.java) |
||||||
|
|
||||||
|
/** |
||||||
|
* 获取首页list标题 |
||||||
|
*/ |
||||||
|
override fun getHomeTitles(): List<HomeTitle> = mDBHelper.getTitles() |
||||||
|
|
||||||
|
/** |
||||||
|
* 扫描图片 |
||||||
|
*/ |
||||||
|
@SuppressLint("CheckResult") |
||||||
|
override fun startScann(index: Int): Observable<List<ImageBean>> { |
||||||
|
|
||||||
|
return when (index) { |
||||||
|
0x01 -> { |
||||||
|
val list = arrayListOf<ImageBean>() |
||||||
|
context.resources.assets.list("img")!!.forEach { |
||||||
|
list.add(ImageBean("img/$it", 0.0f, 0.0f)) |
||||||
|
} |
||||||
|
Observable.just(list) |
||||||
|
} |
||||||
|
0x02 -> { |
||||||
|
Observable.just(emptyList()) |
||||||
|
} |
||||||
|
0x03 -> { |
||||||
|
mApiService.getImageList() |
||||||
|
} |
||||||
|
else -> { |
||||||
|
Observable.just(emptyList()) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
@ -0,0 +1,17 @@ |
|||||||
|
package com.zwy.demo.repositorys |
||||||
|
|
||||||
|
import com.zwy.demo.dbbean.HomeTitle |
||||||
|
import com.zwy.demo.dbbean.ImageBean |
||||||
|
import io.reactivex.Observable |
||||||
|
|
||||||
|
interface Repository { |
||||||
|
/** |
||||||
|
* 获取首页list标题 |
||||||
|
*/ |
||||||
|
fun getHomeTitles(): List<HomeTitle> |
||||||
|
|
||||||
|
/** |
||||||
|
* 扫描图片 |
||||||
|
*/ |
||||||
|
fun startScann(index: Int): Observable<List<ImageBean>> |
||||||
|
} |
@ -0,0 +1,40 @@ |
|||||||
|
package com.zwy.demo.utils |
||||||
|
|
||||||
|
import android.app.Activity |
||||||
|
import android.app.Application |
||||||
|
import android.os.Bundle |
||||||
|
import android.view.View |
||||||
|
import androidx.appcompat.widget.AppCompatImageView |
||||||
|
import androidx.appcompat.widget.AppCompatTextView |
||||||
|
import com.zwy.demo.R |
||||||
|
|
||||||
|
class ActivityLifecycleCallback : Application.ActivityLifecycleCallbacks { |
||||||
|
override fun onActivityPaused(activity: Activity) { |
||||||
|
} |
||||||
|
|
||||||
|
override fun onActivityStarted(activity: Activity) { |
||||||
|
} |
||||||
|
|
||||||
|
override fun onActivityDestroyed(activity: Activity) { |
||||||
|
} |
||||||
|
|
||||||
|
override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) { |
||||||
|
} |
||||||
|
|
||||||
|
override fun onActivityStopped(activity: Activity) { |
||||||
|
} |
||||||
|
|
||||||
|
override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) { |
||||||
|
} |
||||||
|
|
||||||
|
override fun onActivityResumed(activity: Activity) { |
||||||
|
activity.findViewById<AppCompatTextView>(R.id.actionBarTitle)?.text = activity.title |
||||||
|
|
||||||
|
activity.findViewById<AppCompatImageView>(R.id.iv_back).also { |
||||||
|
if (activity.title == "离线鉴黄") it?.visibility = View.GONE |
||||||
|
it?.setOnClickListener { |
||||||
|
activity.finish() |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,17 @@ |
|||||||
|
package com.zwy.demo.utils |
||||||
|
|
||||||
|
/** |
||||||
|
* 常量 请求超时时间 |
||||||
|
*/ |
||||||
|
const val NETWORK_TIMEOUT = 60L |
||||||
|
|
||||||
|
/** |
||||||
|
* 常量 baseurl |
||||||
|
*/ |
||||||
|
const val BASE_URL = "http://114.116.213.202:7777" |
||||||
|
|
||||||
|
|
||||||
|
const val TAG = "鉴黄Demo日志" |
||||||
|
|
||||||
|
|
||||||
|
const val ParmKey2ScanPicAty = "ParmKey2ScanPicAty" |
@ -0,0 +1,64 @@ |
|||||||
|
package com.zwy.demo.utils |
||||||
|
|
||||||
|
import com.zwy.demo.NSFWApplication |
||||||
|
import com.zwy.demo.db.DaoMaster |
||||||
|
import com.zwy.demo.db.DaoSession |
||||||
|
import com.zwy.demo.dbbean.HomeTitle |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* 数据库操作类 |
||||||
|
*/ |
||||||
|
class DBHelper private constructor(val mDaoSession: DaoSession) { |
||||||
|
|
||||||
|
/** |
||||||
|
* 获取全部已缓存的图片列表 |
||||||
|
*/ |
||||||
|
fun getImageListFromDB() = mDaoSession.imageBeanDao.queryBuilder().list() |
||||||
|
|
||||||
|
/** |
||||||
|
* 获取首页列表数据 |
||||||
|
*/ |
||||||
|
fun getTitles() = mDaoSession.homeTitleDao.queryBuilder().list() |
||||||
|
|
||||||
|
companion object { |
||||||
|
private var instance: DBHelper? = null |
||||||
|
get() { |
||||||
|
if (field == null) { |
||||||
|
field = DBHelper(initDB()) |
||||||
|
} |
||||||
|
return field |
||||||
|
} |
||||||
|
|
||||||
|
private fun initDB(): DaoSession { |
||||||
|
return DaoMaster( |
||||||
|
DaoMaster.DevOpenHelper( |
||||||
|
NSFWApplication.context, |
||||||
|
"nsfw_db" |
||||||
|
).writableDatabase |
||||||
|
).newSession().apply { |
||||||
|
//插入默认数据 |
||||||
|
if (this.homeTitleDao.queryBuilder().list().size == 0) { |
||||||
|
arrayListOf( |
||||||
|
"识别Assets目录图片", |
||||||
|
"识别相册图片", |
||||||
|
"实时扫描识别", |
||||||
|
"测试网络图片库中的大尺度资源", |
||||||
|
"我有资源贡献", |
||||||
|
"如果项目对您有帮助", |
||||||
|
"请给我一个Star吧" |
||||||
|
).forEach { |
||||||
|
System.out.println("数据写入成功") |
||||||
|
this.homeTitleDao.insert(HomeTitle(it)) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Synchronized |
||||||
|
fun get(): DBHelper { |
||||||
|
return instance!! |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,144 @@ |
|||||||
|
package com.zwy.demo.utils |
||||||
|
|
||||||
|
import android.content.Intent |
||||||
|
import android.net.Uri |
||||||
|
import android.view.LayoutInflater |
||||||
|
import android.widget.ImageView |
||||||
|
import android.widget.LinearLayout |
||||||
|
import android.widget.TextView |
||||||
|
import androidx.cardview.widget.CardView |
||||||
|
import androidx.databinding.BindingAdapter |
||||||
|
import androidx.recyclerview.widget.LinearLayoutManager |
||||||
|
import androidx.recyclerview.widget.RecyclerView |
||||||
|
import com.bumptech.glide.Glide |
||||||
|
import com.chad.library.adapter.base.BaseQuickAdapter |
||||||
|
import com.chad.library.adapter.base.animation.ScaleInAnimation |
||||||
|
import com.chad.library.adapter.base.viewholder.BaseViewHolder |
||||||
|
import com.zwy.demo.R |
||||||
|
import com.zwy.demo.dbbean.HomeTitle |
||||||
|
import com.zwy.demo.dbbean.ImageBean |
||||||
|
import com.zwy.demo.views.ScanPicActivity |
||||||
|
import org.jetbrains.anko.startActivity |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* 首页列表适配器填充 |
||||||
|
*/ |
||||||
|
@BindingAdapter("bindHomeData") |
||||||
|
fun RecyclerView.bindData(data: List<HomeTitle>?) { |
||||||
|
|
||||||
|
val mContext = this.context |
||||||
|
|
||||||
|
val homeAdapter = |
||||||
|
object : |
||||||
|
BaseQuickAdapter<HomeTitle, BaseViewHolder>(R.layout.tem_home, data?.toMutableList()) { |
||||||
|
override fun convert(holder: BaseViewHolder, item: HomeTitle) { |
||||||
|
holder.setText(R.id.tv_title, item.title) |
||||||
|
} |
||||||
|
} |
||||||
|
homeAdapter.animationEnable = true |
||||||
|
homeAdapter.isAnimationFirstOnly = false |
||||||
|
homeAdapter.adapterAnimation = ScaleInAnimation() |
||||||
|
|
||||||
|
homeAdapter.addHeaderView(LayoutInflater.from(mContext) |
||||||
|
.inflate(R.layout.item_home_head, LinearLayout(mContext)).apply { |
||||||
|
findViewById<TextView>(R.id.tv_info).text = |
||||||
|
mContext.getString(R.string.versionstr, PackageUtils.getVersionName(mContext)) |
||||||
|
}) |
||||||
|
|
||||||
|
homeAdapter.addFooterView(LayoutInflater.from(mContext) |
||||||
|
.inflate(R.layout.item_home_head, LinearLayout(mContext)).apply { |
||||||
|
this.setPadding(20, 0, 20, 0) |
||||||
|
findViewById<TextView>(R.id.tv_info).apply { |
||||||
|
setTextColor(mContext.resources.getColor(R.color.red)) |
||||||
|
text = context.getString(R.string.nsfw_info) |
||||||
|
} |
||||||
|
}) |
||||||
|
|
||||||
|
this.layoutManager = LinearLayoutManager(mContext) |
||||||
|
this.adapter = homeAdapter |
||||||
|
|
||||||
|
homeAdapter.setOnItemClickListener { adapter, view, position -> |
||||||
|
when (position) { |
||||||
|
0 -> { |
||||||
|
//识别Assets目录 |
||||||
|
mContext.startActivity<ScanPicActivity>(ParmKey2ScanPicAty to 0x01) |
||||||
|
} |
||||||
|
1 -> { |
||||||
|
//识别相册 |
||||||
|
mContext.startActivity<ScanPicActivity>(ParmKey2ScanPicAty to 0x02) |
||||||
|
} |
||||||
|
2 -> { |
||||||
|
//实时扫描 |
||||||
|
} |
||||||
|
3 -> { |
||||||
|
//Api获取图片测试 |
||||||
|
mContext.startActivity<ScanPicActivity>(ParmKey2ScanPicAty to 0x03) |
||||||
|
} |
||||||
|
4 -> { |
||||||
|
//上传文件 |
||||||
|
} |
||||||
|
5 -> { |
||||||
|
//跳转GitHub首页 |
||||||
|
mContext.startActivity( |
||||||
|
Intent( |
||||||
|
Intent.ACTION_VIEW, |
||||||
|
Uri.parse("https://github.com/devzwy/open_nsfw_android") |
||||||
|
) |
||||||
|
) |
||||||
|
} |
||||||
|
6 -> { |
||||||
|
//跳转GitHub首页 |
||||||
|
mContext.startActivity( |
||||||
|
Intent( |
||||||
|
Intent.ACTION_VIEW, |
||||||
|
Uri.parse("https://github.com/devzwy/open_nsfw_android") |
||||||
|
) |
||||||
|
) |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* 首页列表适配器填充 |
||||||
|
*/ |
||||||
|
@BindingAdapter("bindScanPicListData") |
||||||
|
fun RecyclerView.bindData2(data: List<ImageBean>?) { |
||||||
|
|
||||||
|
val mContext = this.context |
||||||
|
|
||||||
|
val pathBase = "file:///android_asset/" |
||||||
|
val scannAdapter = |
||||||
|
object : |
||||||
|
BaseQuickAdapter<ImageBean, BaseViewHolder>( |
||||||
|
R.layout.item_scann, |
||||||
|
data?.toMutableList() |
||||||
|
) { |
||||||
|
override fun convert(holder: BaseViewHolder, item: ImageBean) { |
||||||
|
holder.getView<TextView>(R.id.tv_sss).apply { |
||||||
|
text = "NSFW 分值:${item.nsfw} \nSFW 分值:${item.sfw}" |
||||||
|
// textColorResource = if (item.nsfw > 0.5) R.color.white else R.color.colorPrimary |
||||||
|
} |
||||||
|
holder.getView<CardView>(R.id.cardview) |
||||||
|
.setBackgroundResource(if (item.nsfw > 0.5) R.color.nsfw else R.color.colorPrimary) |
||||||
|
val imageView = holder.getView<ImageView>(R.id.iv_item) |
||||||
|
if (item.imgUrl.contains("http")) { |
||||||
|
Glide.with(imageView).load(item.imgUrl).into(imageView) |
||||||
|
} else { |
||||||
|
Glide.with(imageView).load("${pathBase}${item.imgUrl}").into(imageView) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
scannAdapter.animationEnable = true |
||||||
|
scannAdapter.isAnimationFirstOnly = false |
||||||
|
scannAdapter.adapterAnimation = ScaleInAnimation() |
||||||
|
|
||||||
|
|
||||||
|
this.layoutManager = LinearLayoutManager(mContext) |
||||||
|
this.adapter = scannAdapter |
||||||
|
|
||||||
|
} |
||||||
|
|
@ -0,0 +1,77 @@ |
|||||||
|
package com.zwy.demo.utils |
||||||
|
|
||||||
|
import android.content.Context |
||||||
|
import android.content.pm.PackageManager |
||||||
|
|
||||||
|
object PackageUtils { |
||||||
|
/** |
||||||
|
* 获取版本名称 |
||||||
|
* |
||||||
|
* @param context 上下文 |
||||||
|
* |
||||||
|
* @return 版本名称 |
||||||
|
*/ |
||||||
|
fun getVersionName(context: Context): String? { |
||||||
|
|
||||||
|
//获取包管理器 |
||||||
|
val pm = context.packageManager |
||||||
|
//获取包信息 |
||||||
|
try { |
||||||
|
val packageInfo = |
||||||
|
pm.getPackageInfo(context.packageName, 0) |
||||||
|
//返回版本号 |
||||||
|
return packageInfo.versionName |
||||||
|
} catch (e: PackageManager.NameNotFoundException) { |
||||||
|
e.printStackTrace() |
||||||
|
} |
||||||
|
return null |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 获取版本号 |
||||||
|
* |
||||||
|
* @param context 上下文 |
||||||
|
* |
||||||
|
* @return 版本号 |
||||||
|
*/ |
||||||
|
fun getVersionCode(context: Context): Int { |
||||||
|
|
||||||
|
//获取包管理器 |
||||||
|
val pm = context.packageManager |
||||||
|
//获取包信息 |
||||||
|
try { |
||||||
|
val packageInfo = |
||||||
|
pm.getPackageInfo(context.packageName, 0) |
||||||
|
//返回版本号 |
||||||
|
return packageInfo.versionCode |
||||||
|
} catch (e: PackageManager.NameNotFoundException) { |
||||||
|
e.printStackTrace() |
||||||
|
} |
||||||
|
return 0 |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 获取App的名称 |
||||||
|
* |
||||||
|
* @param context 上下文 |
||||||
|
* |
||||||
|
* @return 名称 |
||||||
|
*/ |
||||||
|
fun getAppName(context: Context): String? { |
||||||
|
val pm = context.packageManager |
||||||
|
//获取包信息 |
||||||
|
try { |
||||||
|
val packageInfo = |
||||||
|
pm.getPackageInfo(context.packageName, 0) |
||||||
|
//获取应用 信息 |
||||||
|
val applicationInfo = packageInfo.applicationInfo |
||||||
|
//获取albelRes |
||||||
|
val labelRes = applicationInfo.labelRes |
||||||
|
//返回App的名称 |
||||||
|
return context.resources.getString(labelRes) |
||||||
|
} catch (e: PackageManager.NameNotFoundException) { |
||||||
|
e.printStackTrace() |
||||||
|
} |
||||||
|
return null |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,4 @@ |
|||||||
|
package com.zwy.demo.utils |
||||||
|
|
||||||
|
|
||||||
|
data class AppLiveData(var type: Int = -1, var text: String = "") |
@ -0,0 +1,25 @@ |
|||||||
|
package com.zwy.demo.utils |
||||||
|
|
||||||
|
import android.app.Activity |
||||||
|
import com.luck.picture.lib.PictureSelector |
||||||
|
import com.luck.picture.lib.config.PictureConfig |
||||||
|
import com.luck.picture.lib.config.PictureMimeType |
||||||
|
|
||||||
|
/** |
||||||
|
* 相册选择 |
||||||
|
*/ |
||||||
|
fun Activity.selectImgFromD(requestCode: Int) { |
||||||
|
PictureSelector.create(this) |
||||||
|
.openGallery(PictureMimeType.ofImage())//全部.ofAll()、图片.、视频.ofVideo()、音频.ofAudio() |
||||||
|
.maxSelectNum(if (requestCode == 0) 20 else 1)// 最大图片选择数量 int |
||||||
|
.minSelectNum(1)// 最小选择数量 int |
||||||
|
.imageSpanCount(3)// 每行显示个数 int |
||||||
|
.selectionMode(PictureConfig.MULTIPLE)// 多选 or 单选 or PictureConfig.SINGLE |
||||||
|
.previewImage(true)// 是否可预览图片 true or false |
||||||
|
.isCamera(false)// 是否显示拍照按钮 true or false |
||||||
|
.isZoomAnim(true)// 图片列表点击 缩放效果 默认true |
||||||
|
// .selectionMedia(selectList) |
||||||
|
.sizeMultiplier(0.5f)// glide 加载图片大小 0~1之间 如设置 .glideOverride()无效 |
||||||
|
.previewEggs(true)// 预览图片时 是否增强左右滑动图片体验(图片滑动一半即可看到上一张是否选中) true or false |
||||||
|
.forResult(requestCode);//结果回调onActivityResult code } |
||||||
|
} |
@ -0,0 +1,64 @@ |
|||||||
|
package com.zwy.demo.utils |
||||||
|
|
||||||
|
import com.google.gson.Gson |
||||||
|
import com.zwy.demo.models.MainViewModel |
||||||
|
import com.zwy.demo.models.ScanPicViewModel |
||||||
|
import com.zwy.demo.repositorys.ApiService |
||||||
|
import com.zwy.demo.repositorys.AppRepository |
||||||
|
import io.reactivex.schedulers.Schedulers |
||||||
|
import okhttp3.OkHttpClient |
||||||
|
import okhttp3.logging.HttpLoggingInterceptor |
||||||
|
import org.koin.androidx.viewmodel.dsl.viewModel |
||||||
|
import org.koin.dsl.module |
||||||
|
import retrofit2.Retrofit |
||||||
|
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory |
||||||
|
import retrofit2.converter.gson.GsonConverterFactory |
||||||
|
import java.util.concurrent.TimeUnit |
||||||
|
|
||||||
|
|
||||||
|
val networkModule = module { |
||||||
|
single { |
||||||
|
OkHttpClient().newBuilder() |
||||||
|
.connectTimeout(NETWORK_TIMEOUT, TimeUnit.SECONDS) |
||||||
|
.readTimeout(NETWORK_TIMEOUT, TimeUnit.SECONDS) |
||||||
|
.writeTimeout(NETWORK_TIMEOUT, TimeUnit.SECONDS) |
||||||
|
.addInterceptor( |
||||||
|
HttpLoggingInterceptor() |
||||||
|
.setLevel(HttpLoggingInterceptor.Level.BODY) |
||||||
|
) |
||||||
|
.build() |
||||||
|
} |
||||||
|
|
||||||
|
single { |
||||||
|
Retrofit.Builder() |
||||||
|
.baseUrl(BASE_URL) |
||||||
|
.client(get<OkHttpClient>()) |
||||||
|
.addCallAdapterFactory(RxJava2CallAdapterFactory.createWithScheduler(Schedulers.io())) |
||||||
|
.addConverterFactory(GsonConverterFactory.create()) |
||||||
|
.build() |
||||||
|
} |
||||||
|
|
||||||
|
single { |
||||||
|
get<Retrofit>().create(ApiService::class.java) |
||||||
|
} |
||||||
|
|
||||||
|
single { |
||||||
|
Gson() |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
val repositoryModule = module { |
||||||
|
single { |
||||||
|
AppRepository(get(), DBHelper.get(), get()) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
val viewModelModules = module { |
||||||
|
viewModel { |
||||||
|
ScanPicViewModel(get()) |
||||||
|
} |
||||||
|
viewModel { |
||||||
|
MainViewModel(get()) |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,36 @@ |
|||||||
|
package com.zwy.demo.views |
||||||
|
|
||||||
|
import android.os.Bundle |
||||||
|
import com.zwy.demo.R |
||||||
|
import com.zwy.demo.base.BaseActivity |
||||||
|
import com.zwy.demo.databinding.MainLayoutBinding |
||||||
|
import com.zwy.demo.models.MainViewModel |
||||||
|
import org.jetbrains.anko.toast |
||||||
|
|
||||||
|
class MainActivity : BaseActivity<MainLayoutBinding, MainViewModel>() { |
||||||
|
/** |
||||||
|
* 初始化根布局 |
||||||
|
* |
||||||
|
* @return 布局layout的id |
||||||
|
*/ |
||||||
|
override fun initContentView(savedInstanceState: Bundle?): Int = R.layout.activity_main |
||||||
|
|
||||||
|
|
||||||
|
override fun initData() { |
||||||
|
binding.titles = viewModel.titles |
||||||
|
viewModel.getTitles() |
||||||
|
} |
||||||
|
|
||||||
|
private var mExitTime: Long = 0 |
||||||
|
|
||||||
|
override fun onBackPressed() { |
||||||
|
if (System.currentTimeMillis() - mExitTime < 2000) { |
||||||
|
super.onBackPressed(); |
||||||
|
} else { |
||||||
|
mExitTime = System.currentTimeMillis(); |
||||||
|
toast("再按一次返回键退出应用") |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
} |
@ -0,0 +1,77 @@ |
|||||||
|
package com.zwy.demo.views |
||||||
|
|
||||||
|
import android.Manifest |
||||||
|
import android.os.Bundle |
||||||
|
import com.zwy.demo.R |
||||||
|
import com.zwy.demo.base.BaseActivity |
||||||
|
import com.zwy.demo.databinding.ScanPicBindingView |
||||||
|
import com.zwy.demo.models.ScanPicViewModel |
||||||
|
import com.zwy.demo.utils.ParmKey2ScanPicAty |
||||||
|
import com.zwy.demo.utils.selectImgFromD |
||||||
|
import pub.devrel.easypermissions.EasyPermissions |
||||||
|
import pub.devrel.easypermissions.PermissionRequest |
||||||
|
|
||||||
|
class ScanPicActivity : BaseActivity<ScanPicBindingView, ScanPicViewModel>() { |
||||||
|
|
||||||
|
val requestCode = 0x01 |
||||||
|
private fun _requestPermissions() { |
||||||
|
if (!EasyPermissions.hasPermissions( |
||||||
|
this, |
||||||
|
Manifest.permission.WRITE_EXTERNAL_STORAGE |
||||||
|
) |
||||||
|
) { |
||||||
|
EasyPermissions.requestPermissions( |
||||||
|
PermissionRequest.Builder( |
||||||
|
this, |
||||||
|
0x01, |
||||||
|
Manifest.permission.WRITE_EXTERNAL_STORAGE |
||||||
|
).build() |
||||||
|
) |
||||||
|
return |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
override fun initData() { |
||||||
|
_requestPermissions() |
||||||
|
binding.dataList = viewModel.imgData |
||||||
|
intent.getIntExtra(ParmKey2ScanPicAty, 0x00).let { |
||||||
|
if (it == 1 || it == 3) |
||||||
|
viewModel.startScann(it) |
||||||
|
else selectImgFromD(requestCode) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 初始化根布局 |
||||||
|
* |
||||||
|
* @return 布局layout的id |
||||||
|
*/ |
||||||
|
override fun initContentView(savedInstanceState: Bundle?): Int = R.layout.activity_scan_pic |
||||||
|
|
||||||
|
|
||||||
|
// override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { |
||||||
|
// super.onActivityResult(requestCode, resultCode, data) |
||||||
|
// if (requestCode == 0x01 && resultCode == RESULT_OK) { |
||||||
|
// PictureSelector.obtainMultipleResult(data)?.let { |
||||||
|
// mMainAdapter.setNewData(null) |
||||||
|
// Toast.makeText(this, "请稍等...", Toast.LENGTH_LONG).show() |
||||||
|
// } |
||||||
|
// Thread(Runnable { |
||||||
|
// selectList?.forEach { |
||||||
|
// val file = File(it.path) |
||||||
|
// val nsfwScore = file.getNsfwScore() |
||||||
|
// addDataToAdapter( |
||||||
|
// MyNsfwBean( |
||||||
|
// nsfwScore.sfw, |
||||||
|
// nsfwScore.nsfw, |
||||||
|
// it.path, |
||||||
|
// BitmapFactory.decodeStream(file.inputStream()) |
||||||
|
// ) |
||||||
|
// ) |
||||||
|
// } |
||||||
|
// }).start() |
||||||
|
// |
||||||
|
// } |
||||||
|
// } |
||||||
|
} |
||||||
|
|
@ -0,0 +1,11 @@ |
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android" |
||||||
|
android:width="24dp" |
||||||
|
android:height="24dp" |
||||||
|
android:viewportWidth="24" |
||||||
|
android:viewportHeight="24" |
||||||
|
android:tint="#FFFFFF" |
||||||
|
android:alpha="0.8"> |
||||||
|
<path |
||||||
|
android:fillColor="@android:color/white" |
||||||
|
android:pathData="M11.67,3.87L9.9,2.1 0,12l9.9,9.9 1.77,-1.77L3.54,12z"/> |
||||||
|
</vector> |
After Width: | Height: | Size: 163 B |
After Width: | Height: | Size: 121 B |
After Width: | Height: | Size: 201 B |
After Width: | Height: | Size: 291 B |
@ -0,0 +1,45 @@ |
|||||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||||
|
<layout xmlns:android="http://schemas.android.com/apk/res/android"> |
||||||
|
|
||||||
|
<data class="MainLayoutBinding"> |
||||||
|
|
||||||
|
<import type="com.zwy.demo.dbbean.HomeTitle" /> |
||||||
|
|
||||||
|
<import type="java.util.List" /> |
||||||
|
|
||||||
|
<import type="androidx.lifecycle.MutableLiveData" /> |
||||||
|
|
||||||
|
<variable |
||||||
|
name="titles" |
||||||
|
type="MutableLiveData<List<HomeTitle>>" /> |
||||||
|
</data> |
||||||
|
|
||||||
|
<RelativeLayout xmlns:tools="http://schemas.android.com/tools" |
||||||
|
android:layout_width="match_parent" |
||||||
|
android:layout_height="match_parent" |
||||||
|
tools:context=".views.MainActivity"> |
||||||
|
|
||||||
|
|
||||||
|
<include layout="@layout/include_actionbar" /> |
||||||
|
|
||||||
|
<androidx.recyclerview.widget.RecyclerView |
||||||
|
bindHomeData="@{titles}" |
||||||
|
android:layout_width="match_parent" |
||||||
|
android:layout_height="match_parent" |
||||||
|
android:layout_above="@+id/tv_b" |
||||||
|
android:layout_below="@+id/mActionBar" |
||||||
|
android:background="@color/bgmain" /> |
||||||
|
|
||||||
|
<TextView |
||||||
|
android:id="@+id/tv_b" |
||||||
|
android:layout_width="match_parent" |
||||||
|
android:background="@color/blackT" |
||||||
|
android:layout_height="wrap_content" |
||||||
|
android:layout_alignParentBottom="true" |
||||||
|
android:gravity="center" |
||||||
|
android:padding="5dp" |
||||||
|
android:text="@string/info" |
||||||
|
android:textColor="@color/black" |
||||||
|
android:textSize="12sp" /> |
||||||
|
</RelativeLayout> |
||||||
|
</layout> |
@ -0,0 +1,30 @@ |
|||||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||||
|
<layout xmlns:android="http://schemas.android.com/apk/res/android"> |
||||||
|
|
||||||
|
<data class="ScanPicBindingView"> |
||||||
|
|
||||||
|
<import type="com.zwy.demo.dbbean.ImageBean" /> |
||||||
|
|
||||||
|
<import type="java.util.List" /> |
||||||
|
|
||||||
|
<import type="androidx.lifecycle.MutableLiveData" /> |
||||||
|
|
||||||
|
<variable |
||||||
|
name="dataList" |
||||||
|
type="MutableLiveData<List<ImageBean>>" /> |
||||||
|
</data> |
||||||
|
|
||||||
|
<RelativeLayout |
||||||
|
android:layout_width="match_parent" |
||||||
|
android:layout_height="match_parent"> |
||||||
|
|
||||||
|
<include layout="@layout/include_actionbar" /> |
||||||
|
|
||||||
|
<androidx.recyclerview.widget.RecyclerView |
||||||
|
android:background="@color/bgmain" |
||||||
|
bindScanPicListData="@{dataList}" |
||||||
|
android:layout_width="match_parent" |
||||||
|
android:layout_height="match_parent" |
||||||
|
android:layout_below="@+id/mActionBar" /> |
||||||
|
</RelativeLayout> |
||||||
|
</layout> |
@ -0,0 +1,23 @@ |
|||||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||||
|
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" |
||||||
|
android:id="@+id/mActionBar" |
||||||
|
android:layout_width="match_parent" |
||||||
|
android:layout_height="?attr/actionBarSize" |
||||||
|
android:layout_alignParentTop="true" |
||||||
|
android:background="@color/colorPrimary"> |
||||||
|
|
||||||
|
<androidx.appcompat.widget.AppCompatImageView |
||||||
|
android:id="@+id/iv_back" |
||||||
|
android:layout_width="wrap_content" |
||||||
|
android:layout_height="wrap_content" |
||||||
|
android:layout_centerVertical="true" |
||||||
|
android:layout_marginLeft="15dp" |
||||||
|
android:background="@drawable/ic_back" /> |
||||||
|
|
||||||
|
<androidx.appcompat.widget.AppCompatTextView |
||||||
|
android:id="@+id/actionBarTitle" |
||||||
|
android:layout_width="wrap_content" |
||||||
|
android:layout_height="wrap_content" |
||||||
|
android:layout_centerInParent="true" |
||||||
|
android:textColor="#ffffff" /> |
||||||
|
</RelativeLayout> |
@ -0,0 +1,16 @@ |
|||||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||||
|
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" |
||||||
|
android:layout_width="match_parent" |
||||||
|
android:layout_height="wrap_content" |
||||||
|
android:layout_margin="10dp" |
||||||
|
android:layout_marginTop="5dp"> |
||||||
|
|
||||||
|
<TextView |
||||||
|
android:id="@+id/tv_info" |
||||||
|
android:layout_width="wrap_content" |
||||||
|
android:layout_height="wrap_content" |
||||||
|
android:layout_centerInParent="true" |
||||||
|
android:text="当前版本号:1.0.0" |
||||||
|
android:lineSpacingExtra="10dp" |
||||||
|
android:textColor="@color/colorPrimary" /> |
||||||
|
</RelativeLayout> |
@ -0,0 +1,35 @@ |
|||||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||||
|
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android" |
||||||
|
android:layout_width="match_parent" |
||||||
|
android:layout_height="wrap_content" |
||||||
|
android:layout_marginLeft="5dp" |
||||||
|
android:id="@+id/cardview" |
||||||
|
android:layout_marginRight="5dp" |
||||||
|
android:layout_marginTop="5dp" |
||||||
|
android:background="@color/white"> |
||||||
|
|
||||||
|
<LinearLayout |
||||||
|
android:layout_width="match_parent" |
||||||
|
android:layout_height="wrap_content" |
||||||
|
android:orientation="horizontal"> |
||||||
|
|
||||||
|
<ImageView |
||||||
|
android:id="@+id/iv_item" |
||||||
|
android:layout_width="120dp" |
||||||
|
android:layout_height="wrap_content" |
||||||
|
android:scaleType="centerCrop" |
||||||
|
android:layout_alignParentLeft="true" |
||||||
|
android:minHeight="120dp" |
||||||
|
android:padding="10dp" |
||||||
|
android:src="@mipmap/launch" /> |
||||||
|
|
||||||
|
<TextView |
||||||
|
android:id="@+id/tv_sss" |
||||||
|
android:layout_width="match_parent" |
||||||
|
android:layout_height="wrap_content" |
||||||
|
android:textColor="@color/white" |
||||||
|
android:layout_gravity="center" |
||||||
|
android:gravity="left" /> |
||||||
|
</LinearLayout> |
||||||
|
|
||||||
|
</androidx.cardview.widget.CardView> |
@ -0,0 +1,15 @@ |
|||||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||||
|
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android" |
||||||
|
android:layout_width="match_parent" |
||||||
|
android:background="@color/white" |
||||||
|
android:layout_marginLeft="5dp" |
||||||
|
android:layout_marginRight="5dp" |
||||||
|
android:layout_marginBottom="5dp" |
||||||
|
android:layout_height="50dp"> |
||||||
|
|
||||||
|
<TextView |
||||||
|
android:id="@+id/tv_title" |
||||||
|
android:layout_width="match_parent" |
||||||
|
android:layout_height="match_parent" |
||||||
|
android:gravity="center" /> |
||||||
|
</androidx.cardview.widget.CardView> |
After Width: | Height: | Size: 83 KiB |
@ -0,0 +1,14 @@ |
|||||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||||
|
<resources> |
||||||
|
<color name="colorPrimary">#2196F3</color> |
||||||
|
<color name="colorPrimaryDark">#00B0FF</color> |
||||||
|
<color name="colorAccent">#03DAC5</color> |
||||||
|
<color name="bgmain">#FAFAFA</color> |
||||||
|
<color name="white">#FAFAFA</color> |
||||||
|
<color name="black">#202020</color> |
||||||
|
<color name="red">#F30606</color> |
||||||
|
<color name="blackT">#50202020</color> |
||||||
|
|
||||||
|
<color name="nsfw">#F33D03</color> |
||||||
|
|
||||||
|
</resources> |
@ -0,0 +1,9 @@ |
|||||||
|
<resources> |
||||||
|
<string name="app_name">Demo</string> |
||||||
|
<string name="main_aty_name">离线鉴黄</string> |
||||||
|
<string name="info">所有图片均来源百度,如有侵权请联系我删除</string> |
||||||
|
<string name="nsfw_info">网络接收图像并给出输出概率(分数在0-1之间),该概率可用于过滤不适合工作图像的图像。得分小于 0.2表示该图像很可能是安全的。得分大于 0.8表示该图像很有可能是NSFW。中间范围的分数可以针对不同的NSFW级别进行分类。 |
||||||
|
根据数据集,用例和图像类型,我们建议开发人员选择合适的阈值。由于问题的困难性质,会出现错误,具体取决于NSFW的用例/定义/容忍度。理想情况下,开发人员应根据对他们的应用程序安全的定义来创建评估集,然后按原样使用模型拟合ROC曲线以选择合适的阈值。</string> |
||||||
|
<string name="versionstr">当前最新版本:%s</string> |
||||||
|
<string name="myscan">自定义扫描</string> |
||||||
|
</resources> |
@ -0,0 +1,12 @@ |
|||||||
|
<resources> |
||||||
|
|
||||||
|
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar"> |
||||||
|
<!-- Customize your theme here. --> |
||||||
|
<item name="colorPrimary">@color/colorPrimary</item> |
||||||
|
<item name="colorPrimaryDark">@color/colorPrimaryDark</item> |
||||||
|
<item name="colorAccent">@color/colorAccent</item> |
||||||
|
<item name="android:windowContentOverlay">@null</item> |
||||||
|
<item name="android:windowBackground">@android:color/white</item> |
||||||
|
</style> |
||||||
|
|
||||||
|
</resources> |
@ -0,0 +1,4 @@ |
|||||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||||
|
<network-security-config> |
||||||
|
<base-config cleartextTrafficPermitted="true" /> |
||||||
|
</network-security-config> |
@ -0,0 +1,16 @@ |
|||||||
|
package com.zwy.demo |
||||||
|
|
||||||
|
import org.junit.Assert.assertEquals |
||||||
|
import org.junit.Test |
||||||
|
|
||||||
|
/** |
||||||
|
* Example local unit test, which will execute on the development machine (host). |
||||||
|
* |
||||||
|
* See [testing documentation](http://d.android.com/tools/testing). |
||||||
|
*/ |
||||||
|
class ExampleUnitTest { |
||||||
|
@Test |
||||||
|
fun addition_isCorrect() { |
||||||
|
assertEquals(4, 2 + 2) |
||||||
|
} |
||||||
|
} |
@ -1,16 +1,5 @@ |
|||||||
# Project-wide Gradle settings. |
|
||||||
# IDE (e.g. Android Studio) users: |
|
||||||
# Gradle settings configured through the IDE *will override* |
|
||||||
# any settings specified in this file. |
|
||||||
# For more details on how to configure your build environment visit |
|
||||||
# http://www.gradle.org/docs/current/userguide/build_environment.html |
|
||||||
# Specifies the JVM arguments used for the daemon process. |
|
||||||
# The setting is particularly useful for tweaking memory settings. |
|
||||||
org.gradle.jvmargs=-Xmx1536m |
org.gradle.jvmargs=-Xmx1536m |
||||||
# When configured, Gradle will run in incubating parallel mode. |
|
||||||
# This option should only be used with decoupled projects. More details, visit |
|
||||||
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects |
|
||||||
# org.gradle.parallel=true |
|
||||||
# Kotlin code style for this project: "official" or "obsolete": |
|
||||||
kotlin.code.style=official |
kotlin.code.style=official |
||||||
kotlin.coroutines=enable |
kotlin.coroutines=enable |
||||||
|
#android.useAndroidX=true |
||||||
|
#android.enableJetifier=true |
@ -1,6 +1,6 @@ |
|||||||
#Sun Apr 19 20:19:15 CST 2020 |
#Thu Jun 04 08:01:30 CST 2020 |
||||||
distributionBase=GRADLE_USER_HOME |
distributionBase=GRADLE_USER_HOME |
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.4-all.zip |
|
||||||
distributionPath=wrapper/dists |
distributionPath=wrapper/dists |
||||||
zipStorePath=wrapper/dists |
|
||||||
zipStoreBase=GRADLE_USER_HOME |
zipStoreBase=GRADLE_USER_HOME |
||||||
|
zipStorePath=wrapper/dists |
||||||
|
distributionUrl=https\://services.gradle.org/distributions/gradle-6.1.1-all.zip |
||||||
|
After Width: | Height: | Size: 2.5 MiB |
@ -1 +1,3 @@ |
|||||||
include ':app', ':OpenNSFW' |
//include ':demo' //开启新demo必须注释 include ':app' 并打开gradle.properties中 注释的两行代码 因为新demo使用了androidx与app模块冲突 demo模块完成:Assets目录识别、网络图片识别 |
||||||
|
include ':app' |
||||||
|
include ':OpenNSFW' |
||||||
|