更新Demo(未完待续..)

pull/34/head
Jason 5 years ago
parent 211609bba5
commit 6dca4d4bc5
  1. 3
      OpenNSFW/src/main/AndroidManifest.xml
  2. 6
      README.md
  3. 4
      app/build.gradle
  4. 22
      app/src/main/AndroidManifest.xml
  5. 19
      app/src/main/java/com/example/open_nsfw_android/DemoApplication.kt
  6. 19
      app/src/main/java/com/example/open_nsfw_android/util/MainAdapter.kt
  7. 8
      app/src/main/java/com/example/open_nsfw_android/util/kt.kt
  8. 22
      app/src/main/java/com/example/open_nsfw_android/view/CameraActivity.kt
  9. 101
      app/src/main/java/com/example/open_nsfw_android/view/MainAty.kt
  10. 32
      app/src/main/java/com/example/open_nsfw_android/view/kt.kt
  11. 6
      app/src/main/res/drawable-v24/ic_launcher_foreground.xml
  12. 44
      app/src/main/res/drawable/ch.xml
  13. 240
      app/src/main/res/drawable/change_background.xml
  14. 14
      app/src/main/res/drawable/ic_arrow_back_black_24dp.xml
  15. 14
      app/src/main/res/drawable/ic_camera_black_24dp.xml
  16. 66
      app/src/main/res/drawable/ic_launcher_background.xml
  17. 224
      app/src/main/res/layout/activity_main.xml
  18. 20
      app/src/main/res/layout/activity_main2.xml
  19. 14
      app/src/main/res/layout/main_item.xml
  20. 4
      app/src/main/res/mipmap-anydpi-v26/change.xml
  21. 4
      app/src/main/res/mipmap-anydpi-v26/change_round.xml
  22. 4
      app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
  23. 4
      app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
  24. 4
      app/src/main/res/values/styles.xml
  25. 4
      app/src/main/res/xml/network_security_config.xml
  26. 4
      build.gradle
  27. 1
      demo/.gitignore
  28. 90
      demo/build.gradle
  29. 21
      demo/proguard-rules.pro
  30. 22
      demo/src/androidTest/java/com/zwy/demo/ExampleInstrumentedTest.kt
  31. 34
      demo/src/main/AndroidManifest.xml
  32. BIN
      demo/src/main/assets/img/test_img1.jpeg
  33. BIN
      demo/src/main/assets/img/test_img2.jpeg
  34. BIN
      demo/src/main/assets/img/test_img3.jpg
  35. 50
      demo/src/main/java/com/zwy/demo/NSFWApplication.kt
  36. 111
      demo/src/main/java/com/zwy/demo/base/BaseActivity.kt
  37. 32
      demo/src/main/java/com/zwy/demo/base/BaseViewModel.kt
  38. 99
      demo/src/main/java/com/zwy/demo/db/DaoMaster.java
  39. 62
      demo/src/main/java/com/zwy/demo/db/DaoSession.java
  40. 129
      demo/src/main/java/com/zwy/demo/db/HomeTitleDao.java
  41. 171
      demo/src/main/java/com/zwy/demo/db/ImageBeanDao.java
  42. 42
      demo/src/main/java/com/zwy/demo/dbbean/HomeTitle.java
  43. 78
      demo/src/main/java/com/zwy/demo/dbbean/ImageBean.java
  44. 19
      demo/src/main/java/com/zwy/demo/models/MainViewModel.kt
  45. 87
      demo/src/main/java/com/zwy/demo/models/ScanPicModel.kt
  46. 16
      demo/src/main/java/com/zwy/demo/repositorys/ApiService.kt
  47. 56
      demo/src/main/java/com/zwy/demo/repositorys/AppRepository.kt
  48. 17
      demo/src/main/java/com/zwy/demo/repositorys/Repository.kt
  49. 40
      demo/src/main/java/com/zwy/demo/utils/ActivityLifecycleCallback.kt
  50. 17
      demo/src/main/java/com/zwy/demo/utils/Constant.kt
  51. 64
      demo/src/main/java/com/zwy/demo/utils/DBHelper.kt
  52. 144
      demo/src/main/java/com/zwy/demo/utils/DataBindingAdapter.kt
  53. 77
      demo/src/main/java/com/zwy/demo/utils/PackageUtils.kt
  54. 4
      demo/src/main/java/com/zwy/demo/utils/bean.kt
  55. 25
      demo/src/main/java/com/zwy/demo/utils/kt.kt
  56. 64
      demo/src/main/java/com/zwy/demo/utils/modules.kt
  57. 36
      demo/src/main/java/com/zwy/demo/views/MainActivity.kt
  58. 77
      demo/src/main/java/com/zwy/demo/views/ScanPicActivity.kt
  59. 11
      demo/src/main/res/drawable-anydpi/ic_back.xml
  60. BIN
      demo/src/main/res/drawable-hdpi/ic_back.png
  61. BIN
      demo/src/main/res/drawable-mdpi/ic_back.png
  62. BIN
      demo/src/main/res/drawable-xhdpi/ic_back.png
  63. BIN
      demo/src/main/res/drawable-xxhdpi/ic_back.png
  64. 45
      demo/src/main/res/layout/activity_main.xml
  65. 30
      demo/src/main/res/layout/activity_scan_pic.xml
  66. 23
      demo/src/main/res/layout/include_actionbar.xml
  67. 16
      demo/src/main/res/layout/item_home_head.xml
  68. 35
      demo/src/main/res/layout/item_scann.xml
  69. 15
      demo/src/main/res/layout/tem_home.xml
  70. BIN
      demo/src/main/res/mipmap-xhdpi/launch.png
  71. 14
      demo/src/main/res/values/colors.xml
  72. 9
      demo/src/main/res/values/strings.xml
  73. 12
      demo/src/main/res/values/styles.xml
  74. 4
      demo/src/main/res/xml/network_security_config.xml
  75. 16
      demo/src/test/java/com/zwy/demo/ExampleUnitTest.kt
  76. 17
      gradle.properties
  77. 6
      gradle/wrapper/gradle-wrapper.properties
  78. BIN
      img/3.jpeg
  79. 4
      settings.gradle

@ -1,2 +1 @@
<manifest
package="com.zwy.opennsfw"/>
<manifest package="com.zwy.opennsfw" />

@ -10,7 +10,11 @@
### JavaScript参考[JS相关文档](https://js.tensorflow.org/api/latest/)
>>> 其中Python、C++均有两种数据喂入的方式,可根据需求选择pb模型或tfLite文件,详细请参考上面的链接.Java的目前只能加载pb模型。其他的平台可自行[百度](https://www.baidu.com)
### [pb模型下载](https://github.com/devzwy/NSFW-Python/tree/master/model)
### 本项目移除测试图片,请下载Demo后自行配图测试
### 本项目移除测试图片,请下载Demo后自行配图测试
#### 即将优化Demo使用MVVM模式,可用作开发脚手架使用
`Kotlin+okhttp3+rxjava2+retrofit2+koin+glide+greendao+databinding+Livedata`
![MVVM](https://github.com/devzwy/open_nsfw_android/blob/dev/img/3.jpeg)
### 使用
- Add it in your root build.gradle at the end of repositories:

@ -58,4 +58,8 @@ dependencies {
// implementation project(path: ':nsfw')
// implementation project(path: ':OpenNSFW')
implementation 'com.github.devzwy:open_nsfw_android:1.3.0'
implementation 'com.squareup.okhttp3:okhttp:4.7.2'
implementation "org.koin:koin-android:2.1.5"
implementation 'com.google.code.gson:gson:2.8.6'
}

@ -1,32 +1,34 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.open_nsfw_android">
package="com.example.open_nsfw_android">
<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"/>
<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:allowBackup="true"
android:icon="@mipmap/a"
android:label="@string/app_name"
android:roundIcon="@mipmap/a"
android:networkSecurityConfig="@xml/network_security_config"
android:name=".DemoApplication"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity
android:name=".view.Main2Activity"
android:label="@string/title_activity_main2"/>
android:label="@string/title_activity_main2" />
<activity android:name=".view.MainAty">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER"/>
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".view.CameraActivity"
android:theme="@style/Theme.AppCompat.Light.NoActionBar"/>
<activity
android:name=".view.CameraActivity"
android:theme="@style/Theme.AppCompat.Light.NoActionBar" />
</application>
</manifest>

@ -1,15 +1,32 @@
package com.example.open_nsfw_android
import android.app.Application
import com.example.open_nsfw_android.view.mModules
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() {
override fun onCreate() {
super.onCreate()
startKoin {
modules(mModules)
}
Classifier.Build()
.context(this) //必须调用 否则会有异常抛出
// .isOpenGPU(true)//默认不开启GPU加速 部分机型开启会奔溃,自行选择,默认false
// .numThreads(10) //分配的线程数 根据手机配置设置,默认1
.build()
}
}
}

@ -5,9 +5,12 @@ import android.support.v4.content.ContextCompat
import android.widget.ImageView
import android.widget.RelativeLayout
import android.widget.TextView
import com.bumptech.glide.Glide
import com.chad.library.adapter.base.BaseQuickAdapter
import com.chad.library.adapter.base.BaseViewHolder
import com.example.open_nsfw_android.R
import getNsfwScore
import kotlinx.android.synthetic.main.activity_main2.*
import java.math.RoundingMode
import java.text.DecimalFormat
@ -15,12 +18,14 @@ class MainAdapter(nsfwList: List<MyNsfwBean>?) :
BaseQuickAdapter<MyNsfwBean, BaseViewHolder>(R.layout.main_item, nsfwList) {
@SuppressLint("SetTextI18n")
override fun convert(helper: BaseViewHolder, item: MyNsfwBean) {
override fun convert(helper: BaseViewHolder, item2: MyNsfwBean) {
val textView = helper.getView<TextView>(R.id.tv_text)
val imageView = helper.getView<ImageView>(R.id.iv)
val view = helper.getView<RelativeLayout>(R.id.view)
var color = ContextCompat.getColor(mContext, R.color.nsfw1)
when (item.nsfw) {
when (item2.nsfw) {
in 0.0..0.2 -> {
color = ContextCompat.getColor(mContext, R.color.nsfw3)
}
@ -33,8 +38,14 @@ class MainAdapter(nsfwList: List<MyNsfwBean>?) :
floatFormat.roundingMode = RoundingMode.HALF_UP
textView.text =
"\n适宜度(非色情程度):${floatFormat.format(item.sfw * 100)}%\n\n不适宜度(涉黄程度):${floatFormat.format(item.nsfw * 100)}%"
imageView.setImageBitmap(item.bitmap)
"\n适宜度(非色情程度):${floatFormat.format(item2.sfw * 100)}%\n\n不适宜度(涉黄程度):${floatFormat.format(
item2.nsfw * 100
)}%"
if (item2.imgUrl != null && item2.imgUrl.isNotBlank()) {
Glide.with(imageView).load(item2.imgUrl).into(imageView)
} else {
imageView.setImageBitmap(item2.bitmap)
}
view.setBackgroundColor(color)
}
}

@ -2,4 +2,10 @@ package com.example.open_nsfw_android.util
import android.graphics.Bitmap
data class MyNsfwBean(var sfw: Float, var nsfw: Float, val path: String, val bitmap: Bitmap)
data class MyNsfwBean(
var sfw: Float,
var nsfw: Float,
val path: String,
val bitmap: Bitmap?,
val imgUrl: String? = ""
)

@ -182,17 +182,17 @@ class CameraActivity : AppCompatActivity(), SurfaceHolder.Callback, Camera.Previ
@SuppressLint("SetTextI18n")
override fun onPreviewFrame(data: ByteArray?, camera: Camera?) {
mCamera.addCallbackBuffer(data)
val size = mCamera.parameters.previewSize;
val image = YuvImage(data, ImageFormat.NV21, size.width, size.height, null);
val stream = ByteArrayOutputStream()
image.compressToJpeg(Rect(0, 0, size.width, size.height), 80, stream)
val bmp = BitmapFactory.decodeByteArray(stream.toByteArray(), 0, stream.size())
bmp.getNsfwScore()
val spText = bmp.getNsfwScore().toString().split(",")
textView.text = spText[0] + "\n" + spText[1]
stream.close()
mCamera.addCallbackBuffer(data)
val size = mCamera.parameters.previewSize;
val image = YuvImage(data, ImageFormat.NV21, size.width, size.height, null);
val stream = ByteArrayOutputStream()
image.compressToJpeg(Rect(0, 0, size.width, size.height), 80, stream)
val bmp = BitmapFactory.decodeByteArray(stream.toByteArray(), 0, stream.size())
bmp.getNsfwScore()
val spText = bmp.getNsfwScore().toString().split(",")
textView.text = spText[0] + "\n" + spText[1]
stream.close()
}
}

@ -5,24 +5,30 @@ import android.annotation.SuppressLint
import android.content.Intent
import android.content.pm.PackageManager
import android.graphics.BitmapFactory
import android.graphics.Camera
import android.os.Bundle
import android.support.v4.app.ActivityCompat
import android.support.v4.content.ContextCompat
import android.support.v7.app.AppCompatActivity
import android.support.v7.widget.LinearLayoutManager
import android.widget.Toast
import com.bumptech.glide.Glide
import com.example.open_nsfw_android.R
import com.example.open_nsfw_android.util.MainAdapter
import com.example.open_nsfw_android.util.MyNsfwBean
import com.example.open_nsfw_android.util.PackageUtils
import com.google.gson.Gson
import com.google.gson.reflect.TypeToken
import com.luck.picture.lib.PictureSelector
import com.luck.picture.lib.config.PictureConfig
import com.luck.picture.lib.config.PictureMimeType
import com.luck.picture.lib.entity.LocalMedia
import getNsfwScore
import kotlinx.android.synthetic.main.activity_main.*
import okhttp3.*
import org.koin.android.ext.android.inject
import java.io.File
import java.io.IOException
import java.lang.reflect.Type
class MainAty : AppCompatActivity() {
@ -30,6 +36,11 @@ class MainAty : AppCompatActivity() {
lateinit var mMainAdapter: MainAdapter
val httpClient: OkHttpClient by inject()
val gson: Gson by inject()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
@ -48,11 +59,62 @@ class MainAty : AppCompatActivity() {
//识别assets目录
bt_sc_assets.setOnClickListener { assetsListSc() }
//选择相册进行扫描
bt_sc_from_other.setOnClickListener { selectImgFromD() }
bt_sc_from_other.setOnClickListener { selectImgFromD(0x01) }
//跳转网络图片识别页面
bt_sc_from_internet.setOnClickListener { startActivity(Intent(this, Main2Activity::class.java)) }
bt_sc_from_internet.setOnClickListener {
startActivity(
Intent(
this,
Main2Activity::class.java
)
)
}
//实时扫描
bt_sc_from_cam.setOnClickListener { scCamera() }
//调用Api获取测试图片
bt_sc_from_api.setOnClickListener {
httpClient.newCall(Request.Builder().get().url(GetImageListURL).build())
.enqueue(object : Callback {
override fun onFailure(call: Call, e: IOException) {
runOnUiThread {
Toast.makeText(this@MainAty, "请求失败,请重试", Toast.LENGTH_SHORT).show()
}
}
override fun onResponse(call: Call, response: Response) {
val str = response.body?.string()
val type: Type? = object : TypeToken<List<NSFWImage>>() {}.type
val list = gson.fromJson<List<NSFWImage>>(str, type)
val l = ArrayList<MyNsfwBean>()
//迭代数据并获取涉黄程度
list.forEach {
System.out.println(it)
val file = Glide.with(this@MainAty)
.load(it.imgUrl)
.downloadOnly(120, 120).get()
val nsfwBean = file.getNsfwScore()
//填充数据到适配器
l.add(
MyNsfwBean(
sfw = nsfwBean.sfw,
nsfw = nsfwBean.nsfw,
path = it.createTime,
imgUrl = it.imgUrl,
bitmap = null
)
)
}
runOnUiThread {
mMainAdapter.setNewData(null)
mMainAdapter.setNewData(l)
}
}
})
}
bt_upload.setOnClickListener {
selectImgFromD(0x02)
}
tv_version.text = "当前版本号:${PackageUtils.getVersionName(this)}"
}
@ -75,7 +137,7 @@ class MainAty : AppCompatActivity() {
/**
* 相册选择
*/
private fun selectImgFromD() {
private fun selectImgFromD(requestCode: Int) {
PictureSelector.create(this)
.openGallery(PictureMimeType.ofImage())//全部.ofAll()、图片.、视频.ofVideo()、音频.ofAudio()
.maxSelectNum(20)// 最大图片选择数量 int
@ -88,7 +150,7 @@ class MainAty : AppCompatActivity() {
.selectionMedia(selectList)
.sizeMultiplier(0.5f)// glide 加载图片大小 0~1之间 如设置 .glideOverride()无效
.previewEggs(true)// 预览图片时 是否增强左右滑动图片体验(图片滑动一半即可看到上一张是否选中) true or false
.forResult(0x01);//结果回调onActivityResult code }
.forResult(requestCode);//结果回调onActivityResult code }
}
/**
@ -127,7 +189,11 @@ class MainAty : AppCompatActivity() {
Manifest.permission.WRITE_EXTERNAL_STORAGE
) != PackageManager.PERMISSION_GRANTED
) {
ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE), 1);
ActivityCompat.requestPermissions(
this,
arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE),
1
);
}
if (ContextCompat.checkSelfPermission(
@ -164,6 +230,29 @@ class MainAty : AppCompatActivity() {
}).start()
}
if (requestCode == 0x02 && resultCode == RESULT_OK) {
selectList = PictureSelector.obtainMultipleResult(data)
val builder = MultipartBody.Builder().setType(MultipartBody.FORM)
// selectList?.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,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)
}
}

@ -18,10 +18,10 @@
android:type="linear">
<item
android:color="#44000000"
android:offset="0.0"/>
android:offset="0.0" />
<item
android:color="#00000000"
android:offset="1.0"/>
android:offset="1.0" />
</gradient>
</aapt:attr>
</path>
@ -30,5 +30,5 @@
android:fillType="nonZero"
android:pathData="M66.94,46.02L66.94,46.02C72.44,50.07 76,56.61 76,64L32,64C32,56.61 35.56,50.11 40.98,46.06L36.18,41.19C35.45,40.45 35.45,39.3 36.18,38.56C36.91,37.81 38.05,37.81 38.78,38.56L44.25,44.05C47.18,42.57 50.48,41.71 54,41.71C57.48,41.71 60.78,42.57 63.68,44.05L69.11,38.56C69.84,37.81 70.98,37.81 71.71,38.56C72.44,39.3 72.44,40.45 71.71,41.19L66.94,46.02ZM62.94,56.92C64.08,56.92 65,56.01 65,54.88C65,53.76 64.08,52.85 62.94,52.85C61.8,52.85 60.88,53.76 60.88,54.88C60.88,56.01 61.8,56.92 62.94,56.92ZM45.06,56.92C46.2,56.92 47.13,56.01 47.13,54.88C47.13,53.76 46.2,52.85 45.06,52.85C43.92,52.85 43,53.76 43,54.88C43,56.01 43.92,56.92 45.06,56.92Z"
android:strokeWidth="1"
android:strokeColor="#00000000"/>
android:strokeColor="#00000000" />
</vector>

@ -1,23 +1,29 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="108dp"
android:height="108dp"
android:viewportWidth="1148.6849"
android:viewportHeight="1148.6849"
android:tint="#4749FF">
<group android:translateX="219.66045"
android:translateY="484.58157">
<group android:translateY="147.79688">
<path android:pathData="M86.4,-98.208L86.4,-83.52C85.968,-41.616,71.424,-11.232,42.768,7.776L51.264,15.408C80.928,-5.472,96.048,-38.448,96.624,-83.52L96.624,-98.208L123.12,-98.208C122.832,-54.72,122.256,-28.8,121.392,-20.16C119.952,-5.76,114.624,1.584,105.552,1.584C100.944,1.584,95.328,1.296,88.992,1.008L91.584,10.512C98.784,10.8,103.968,11.088,107.136,11.088C121.536,11.088,129.744,2.016,131.472,-16.128C132.768,-27.792,133.488,-58.464,133.488,-108.144L58.32,-108.144L58.32,-98.208L86.4,-98.208ZM64.8,-85.248L34.704,-79.2L34.704,-115.632L24.048,-115.632L24.048,-77.04L5.04,-73.296L6.624,-63.216L24.048,-66.672L24.048,-25.056C24.048,-21.6,22.176,-19.152,18.432,-17.712L21.456,-7.632C37.872,-13.248,51.408,-19.584,62.352,-26.496L59.76,-35.856C51.408,-30.96,43.056,-26.784,34.704,-23.328L34.704,-68.832L66.528,-75.168L64.8,-85.248Z"
android:fillColor="#000000"/>
<path android:pathData="M273.168,-77.904L247.68,-77.904C252,-83.808,256.32,-91.008,260.496,-99.36L260.496,-106.848L229.968,-106.848C231.696,-110.16,233.136,-113.616,234.432,-117.216L224.352,-118.512C219.168,-104.832,209.376,-93.168,194.976,-83.664L201.024,-75.6C210.528,-82.08,218.448,-89.568,224.496,-97.92L249.552,-97.92C245.52,-90.288,241.344,-83.664,237.168,-77.904L204.336,-77.904L204.336,-38.736L194.112,-38.736L194.112,-29.232L227.664,-29.232C221.904,-14.832,209.232,-3.024,189.648,6.192L196.416,14.832C217.728,3.6,231.408,-10.368,237.456,-27.072C245.52,-9.792,259.2,4.32,278.208,14.976L282.96,5.184C265.968,-3.168,253.584,-14.544,245.952,-29.232L282.24,-29.232L282.24,-38.736L273.168,-38.736L273.168,-77.904ZM213.552,-38.736L213.552,-68.832L233.568,-68.832C233.28,-57.168,232.272,-47.088,230.544,-38.736L213.552,-38.736ZM240.48,-38.736C241.92,-46.8,242.784,-56.88,243.072,-68.832L263.952,-68.832L263.952,-38.736L240.48,-38.736ZM166.608,12.816C174.96,12.816,179.136,8.496,179.136,0L179.136,-41.616C184.32,-43.92,189.36,-46.512,194.4,-49.104L194.4,-59.616C189.36,-56.736,184.32,-54.144,179.136,-51.84L179.136,-81.216L193.824,-81.216L193.824,-91.152L179.136,-91.152L179.136,-117.504L168.768,-117.504L168.768,-91.152L151.632,-91.152L151.632,-81.216L168.768,-81.216L168.768,-47.664C162.288,-45.216,155.664,-43.2,148.896,-41.472L151.488,-31.104C157.248,-32.976,163.008,-34.992,168.768,-37.296L168.768,-2.592C168.768,1.44,166.752,3.6,163.008,3.6C159.552,3.6,155.952,3.312,152.208,2.88L154.368,12.816L166.608,12.816Z"
android:fillColor="#000000"/>
<path android:pathData="M310.032,13.104C318.24,13.104,322.416,8.928,322.416,0.864L322.416,-41.328C326.736,-43.344,330.912,-45.648,335.088,-47.952L335.088,-58.176C330.912,-55.728,326.736,-53.424,322.416,-51.408L322.416,-80.208L336.096,-80.208L336.096,-89.856L322.416,-89.856L322.416,-117.216L312.048,-117.216L312.048,-89.856L295.92,-89.856L295.92,-80.208L312.048,-80.208L312.048,-46.8C306,-44.352,299.664,-42.336,293.328,-40.608L295.92,-30.672C301.392,-32.4,306.72,-34.416,312.048,-36.72L312.048,-1.872C312.048,1.872,310.176,3.888,306.432,3.888C303.408,3.888,300.24,3.6,296.784,3.168L298.944,13.104L310.032,13.104ZM339.12,-112.608L339.12,-104.256L351.216,-104.256L351.216,-60.48C346.896,-60.48,342.432,-60.336,337.824,-60.048L339.84,-52.128C360.288,-52.992,379.728,-53.856,398.448,-54.864L398.448,-48.24L408.384,-48.24L408.384,-55.44L421.92,-56.304L421.92,-64.368C417.456,-64.08,412.992,-63.792,408.384,-63.36L408.384,-104.256L420.048,-104.256L420.048,-112.608L339.12,-112.608ZM361.008,-60.912L361.008,-71.28L398.448,-71.28L398.448,-62.784C386.208,-62.064,373.68,-61.488,361.008,-60.912ZM361.008,-78.192L361.008,-87.552L398.448,-87.552L398.448,-78.192L361.008,-78.192ZM361.008,-94.608L361.008,-104.256L398.448,-104.256L398.448,-94.608L361.008,-94.608ZM343.584,-30.096L337.248,-23.904C342.72,-19.152,347.616,-14.4,352.224,-9.792C347.04,-3.168,340.272,2.304,331.92,6.768L337.392,15.12C345.888,10.512,353.088,4.608,358.992,-2.592C362.448,1.296,365.472,5.184,368.208,8.928L375.264,1.728C371.952,-2.304,368.352,-6.336,364.464,-10.512C368.496,-17.712,371.52,-25.92,373.392,-35.28L373.392,-43.776L337.392,-43.776L337.392,-34.848L364.32,-34.848C362.736,-28.512,360.432,-22.752,357.552,-17.568C353.232,-21.744,348.48,-25.92,343.584,-30.096ZM379.152,-43.776L379.152,-34.848L382.752,-34.848C385.056,-24.624,389.232,-15.408,395.568,-7.2C390.096,-1.728,383.472,3.024,375.552,6.912L380.88,15.12C388.944,11.088,396,6.048,402.048,0.144C407.232,5.328,413.424,9.936,420.912,14.256L426.096,6.048C419.04,2.304,412.992,-1.872,407.808,-6.624C413.856,-14.688,418.032,-24.336,420.48,-35.28L420.48,-43.776L379.152,-43.776ZM391.248,-34.848L410.976,-34.848C408.816,-27.072,405.504,-20.16,401.184,-13.968C396.432,-20.16,393.12,-27.072,391.248,-34.848Z"
android:fillColor="#000000"/>
<path android:pathData="M482.256,-83.376L482.256,-57.456L505.872,-57.456C498.384,-50.4,487.872,-45.36,474.192,-42.48L478.08,-33.84C492.192,-37.008,503.712,-42.624,512.352,-50.544C514.368,-48.24,516.384,-45.792,518.112,-43.2C507.744,-34.272,493.056,-26.928,474.048,-21.168L479.088,-12.672C497.232,-18.72,511.632,-26.64,522.288,-36.144C523.584,-33.408,524.736,-30.384,525.744,-27.216C513.36,-15.696,496.08,-6.192,473.616,1.008L478.8,9.936C498.96,2.736,515.232,-6.624,527.616,-17.856C527.76,-16.128,527.904,-14.4,527.904,-12.528C527.904,-5.616,526.896,-1.008,525.168,1.296C523.152,3.6,520.56,4.752,517.392,5.04C514.512,5.184,511.056,5.328,506.88,5.328L509.904,14.688C513.072,14.688,515.952,14.544,518.544,14.256C525.744,13.392,530.784,11.232,533.52,8.064C536.688,4.176,538.272,-2.736,538.272,-12.528C537.984,-18,537.12,-23.184,535.68,-28.368C537.552,-29.232,539.424,-30.096,541.44,-30.96C546.048,-16.704,553.536,-3.744,564.048,8.064L570.816,-0.432C560.448,-10.512,553.248,-22.032,549.216,-34.992C554.688,-38.016,559.584,-41.472,564.048,-45.36L557.28,-53.136C550.656,-46.8,542.304,-41.472,532.512,-37.152C529.344,-44.352,524.592,-50.976,518.4,-57.312L518.544,-57.456L561.6,-57.456L561.6,-88.848L534.816,-88.848C538.56,-92.448,542.304,-96.624,546.048,-101.52L546.048,-108.288L509.904,-108.288C511.92,-110.736,513.792,-113.328,515.808,-116.208L505.152,-118.656C496.224,-105.84,484.56,-95.472,470.448,-87.696L476.784,-79.92C478.512,-81.072,480.24,-82.224,482.256,-83.376ZM521.712,-88.848L489.888,-88.848C494.208,-92.304,498.528,-96.048,502.704,-100.224L533.952,-100.224C529.92,-96.192,525.888,-92.304,521.712,-88.848ZM551.52,-65.952L523.728,-65.952C525.744,-70.272,527.472,-75.168,528.624,-80.352L551.52,-80.352L551.52,-65.952ZM512.784,-65.952L492.336,-65.952L492.336,-80.352L518.544,-80.352C517.392,-75.168,515.376,-70.416,512.784,-65.952ZM454.32,-66.816L454.32,14.256L464.832,14.256L464.832,-85.392C469.152,-94.32,472.896,-103.824,475.776,-113.76L466.128,-118.368C460.08,-96.192,450.576,-76.464,437.328,-59.328L440.64,-48.384C445.536,-54.288,450.144,-60.48,454.32,-66.816Z"
android:fillColor="#000000"/>
<path android:pathData="M585.936,-50.112L585.936,-40.032L646.848,-40.032C644.544,-34.272,641.664,-28.944,638.208,-24.048C628.416,-11.808,610.848,-2.016,585.792,5.472L591.408,14.256C616.464,6.768,634.464,-3.456,645.552,-16.704C647.136,-18.864,648.72,-21.168,650.16,-23.472C672.336,-10.224,689.76,2.448,702.72,14.256L710.208,6.912C695.088,-5.76,676.512,-18.576,654.48,-31.392C655.776,-34.128,656.928,-37.008,657.936,-40.032L710.928,-40.032L710.928,-50.112L660.672,-50.112C662.256,-57.312,663.264,-65.088,663.552,-73.728L663.552,-117.36L653.04,-117.36L653.04,-73.728C652.752,-65.376,651.744,-57.456,650.016,-50.112L585.936,-50.112ZM597.6,-86.544L592.128,-78.48C603.216,-73.728,614.016,-67.248,624.528,-59.184L630.144,-67.68C620.352,-75.168,609.408,-81.36,597.6,-86.544ZM613.44,-109.728L607.968,-101.664C617.472,-97.632,626.688,-92.16,635.76,-84.96L641.232,-93.312C632.88,-99.648,623.52,-105.12,613.44,-109.728Z"
android:fillColor="#000000"/>
android:width="108dp"
android:height="108dp"
android:viewportWidth="1148.6849"
android:viewportHeight="1148.6849"
android:tint="#4749FF">
<group
android:translateX="219.66045"
android:translateY="484.58157">
<group android:translateY="147.79688">
<path
android:pathData="M86.4,-98.208L86.4,-83.52C85.968,-41.616,71.424,-11.232,42.768,7.776L51.264,15.408C80.928,-5.472,96.048,-38.448,96.624,-83.52L96.624,-98.208L123.12,-98.208C122.832,-54.72,122.256,-28.8,121.392,-20.16C119.952,-5.76,114.624,1.584,105.552,1.584C100.944,1.584,95.328,1.296,88.992,1.008L91.584,10.512C98.784,10.8,103.968,11.088,107.136,11.088C121.536,11.088,129.744,2.016,131.472,-16.128C132.768,-27.792,133.488,-58.464,133.488,-108.144L58.32,-108.144L58.32,-98.208L86.4,-98.208ZM64.8,-85.248L34.704,-79.2L34.704,-115.632L24.048,-115.632L24.048,-77.04L5.04,-73.296L6.624,-63.216L24.048,-66.672L24.048,-25.056C24.048,-21.6,22.176,-19.152,18.432,-17.712L21.456,-7.632C37.872,-13.248,51.408,-19.584,62.352,-26.496L59.76,-35.856C51.408,-30.96,43.056,-26.784,34.704,-23.328L34.704,-68.832L66.528,-75.168L64.8,-85.248Z"
android:fillColor="#000000" />
<path
android:pathData="M273.168,-77.904L247.68,-77.904C252,-83.808,256.32,-91.008,260.496,-99.36L260.496,-106.848L229.968,-106.848C231.696,-110.16,233.136,-113.616,234.432,-117.216L224.352,-118.512C219.168,-104.832,209.376,-93.168,194.976,-83.664L201.024,-75.6C210.528,-82.08,218.448,-89.568,224.496,-97.92L249.552,-97.92C245.52,-90.288,241.344,-83.664,237.168,-77.904L204.336,-77.904L204.336,-38.736L194.112,-38.736L194.112,-29.232L227.664,-29.232C221.904,-14.832,209.232,-3.024,189.648,6.192L196.416,14.832C217.728,3.6,231.408,-10.368,237.456,-27.072C245.52,-9.792,259.2,4.32,278.208,14.976L282.96,5.184C265.968,-3.168,253.584,-14.544,245.952,-29.232L282.24,-29.232L282.24,-38.736L273.168,-38.736L273.168,-77.904ZM213.552,-38.736L213.552,-68.832L233.568,-68.832C233.28,-57.168,232.272,-47.088,230.544,-38.736L213.552,-38.736ZM240.48,-38.736C241.92,-46.8,242.784,-56.88,243.072,-68.832L263.952,-68.832L263.952,-38.736L240.48,-38.736ZM166.608,12.816C174.96,12.816,179.136,8.496,179.136,0L179.136,-41.616C184.32,-43.92,189.36,-46.512,194.4,-49.104L194.4,-59.616C189.36,-56.736,184.32,-54.144,179.136,-51.84L179.136,-81.216L193.824,-81.216L193.824,-91.152L179.136,-91.152L179.136,-117.504L168.768,-117.504L168.768,-91.152L151.632,-91.152L151.632,-81.216L168.768,-81.216L168.768,-47.664C162.288,-45.216,155.664,-43.2,148.896,-41.472L151.488,-31.104C157.248,-32.976,163.008,-34.992,168.768,-37.296L168.768,-2.592C168.768,1.44,166.752,3.6,163.008,3.6C159.552,3.6,155.952,3.312,152.208,2.88L154.368,12.816L166.608,12.816Z"
android:fillColor="#000000" />
<path
android:pathData="M310.032,13.104C318.24,13.104,322.416,8.928,322.416,0.864L322.416,-41.328C326.736,-43.344,330.912,-45.648,335.088,-47.952L335.088,-58.176C330.912,-55.728,326.736,-53.424,322.416,-51.408L322.416,-80.208L336.096,-80.208L336.096,-89.856L322.416,-89.856L322.416,-117.216L312.048,-117.216L312.048,-89.856L295.92,-89.856L295.92,-80.208L312.048,-80.208L312.048,-46.8C306,-44.352,299.664,-42.336,293.328,-40.608L295.92,-30.672C301.392,-32.4,306.72,-34.416,312.048,-36.72L312.048,-1.872C312.048,1.872,310.176,3.888,306.432,3.888C303.408,3.888,300.24,3.6,296.784,3.168L298.944,13.104L310.032,13.104ZM339.12,-112.608L339.12,-104.256L351.216,-104.256L351.216,-60.48C346.896,-60.48,342.432,-60.336,337.824,-60.048L339.84,-52.128C360.288,-52.992,379.728,-53.856,398.448,-54.864L398.448,-48.24L408.384,-48.24L408.384,-55.44L421.92,-56.304L421.92,-64.368C417.456,-64.08,412.992,-63.792,408.384,-63.36L408.384,-104.256L420.048,-104.256L420.048,-112.608L339.12,-112.608ZM361.008,-60.912L361.008,-71.28L398.448,-71.28L398.448,-62.784C386.208,-62.064,373.68,-61.488,361.008,-60.912ZM361.008,-78.192L361.008,-87.552L398.448,-87.552L398.448,-78.192L361.008,-78.192ZM361.008,-94.608L361.008,-104.256L398.448,-104.256L398.448,-94.608L361.008,-94.608ZM343.584,-30.096L337.248,-23.904C342.72,-19.152,347.616,-14.4,352.224,-9.792C347.04,-3.168,340.272,2.304,331.92,6.768L337.392,15.12C345.888,10.512,353.088,4.608,358.992,-2.592C362.448,1.296,365.472,5.184,368.208,8.928L375.264,1.728C371.952,-2.304,368.352,-6.336,364.464,-10.512C368.496,-17.712,371.52,-25.92,373.392,-35.28L373.392,-43.776L337.392,-43.776L337.392,-34.848L364.32,-34.848C362.736,-28.512,360.432,-22.752,357.552,-17.568C353.232,-21.744,348.48,-25.92,343.584,-30.096ZM379.152,-43.776L379.152,-34.848L382.752,-34.848C385.056,-24.624,389.232,-15.408,395.568,-7.2C390.096,-1.728,383.472,3.024,375.552,6.912L380.88,15.12C388.944,11.088,396,6.048,402.048,0.144C407.232,5.328,413.424,9.936,420.912,14.256L426.096,6.048C419.04,2.304,412.992,-1.872,407.808,-6.624C413.856,-14.688,418.032,-24.336,420.48,-35.28L420.48,-43.776L379.152,-43.776ZM391.248,-34.848L410.976,-34.848C408.816,-27.072,405.504,-20.16,401.184,-13.968C396.432,-20.16,393.12,-27.072,391.248,-34.848Z"
android:fillColor="#000000" />
<path
android:pathData="M482.256,-83.376L482.256,-57.456L505.872,-57.456C498.384,-50.4,487.872,-45.36,474.192,-42.48L478.08,-33.84C492.192,-37.008,503.712,-42.624,512.352,-50.544C514.368,-48.24,516.384,-45.792,518.112,-43.2C507.744,-34.272,493.056,-26.928,474.048,-21.168L479.088,-12.672C497.232,-18.72,511.632,-26.64,522.288,-36.144C523.584,-33.408,524.736,-30.384,525.744,-27.216C513.36,-15.696,496.08,-6.192,473.616,1.008L478.8,9.936C498.96,2.736,515.232,-6.624,527.616,-17.856C527.76,-16.128,527.904,-14.4,527.904,-12.528C527.904,-5.616,526.896,-1.008,525.168,1.296C523.152,3.6,520.56,4.752,517.392,5.04C514.512,5.184,511.056,5.328,506.88,5.328L509.904,14.688C513.072,14.688,515.952,14.544,518.544,14.256C525.744,13.392,530.784,11.232,533.52,8.064C536.688,4.176,538.272,-2.736,538.272,-12.528C537.984,-18,537.12,-23.184,535.68,-28.368C537.552,-29.232,539.424,-30.096,541.44,-30.96C546.048,-16.704,553.536,-3.744,564.048,8.064L570.816,-0.432C560.448,-10.512,553.248,-22.032,549.216,-34.992C554.688,-38.016,559.584,-41.472,564.048,-45.36L557.28,-53.136C550.656,-46.8,542.304,-41.472,532.512,-37.152C529.344,-44.352,524.592,-50.976,518.4,-57.312L518.544,-57.456L561.6,-57.456L561.6,-88.848L534.816,-88.848C538.56,-92.448,542.304,-96.624,546.048,-101.52L546.048,-108.288L509.904,-108.288C511.92,-110.736,513.792,-113.328,515.808,-116.208L505.152,-118.656C496.224,-105.84,484.56,-95.472,470.448,-87.696L476.784,-79.92C478.512,-81.072,480.24,-82.224,482.256,-83.376ZM521.712,-88.848L489.888,-88.848C494.208,-92.304,498.528,-96.048,502.704,-100.224L533.952,-100.224C529.92,-96.192,525.888,-92.304,521.712,-88.848ZM551.52,-65.952L523.728,-65.952C525.744,-70.272,527.472,-75.168,528.624,-80.352L551.52,-80.352L551.52,-65.952ZM512.784,-65.952L492.336,-65.952L492.336,-80.352L518.544,-80.352C517.392,-75.168,515.376,-70.416,512.784,-65.952ZM454.32,-66.816L454.32,14.256L464.832,14.256L464.832,-85.392C469.152,-94.32,472.896,-103.824,475.776,-113.76L466.128,-118.368C460.08,-96.192,450.576,-76.464,437.328,-59.328L440.64,-48.384C445.536,-54.288,450.144,-60.48,454.32,-66.816Z"
android:fillColor="#000000" />
<path
android:pathData="M585.936,-50.112L585.936,-40.032L646.848,-40.032C644.544,-34.272,641.664,-28.944,638.208,-24.048C628.416,-11.808,610.848,-2.016,585.792,5.472L591.408,14.256C616.464,6.768,634.464,-3.456,645.552,-16.704C647.136,-18.864,648.72,-21.168,650.16,-23.472C672.336,-10.224,689.76,2.448,702.72,14.256L710.208,6.912C695.088,-5.76,676.512,-18.576,654.48,-31.392C655.776,-34.128,656.928,-37.008,657.936,-40.032L710.928,-40.032L710.928,-50.112L660.672,-50.112C662.256,-57.312,663.264,-65.088,663.552,-73.728L663.552,-117.36L653.04,-117.36L653.04,-73.728C652.752,-65.376,651.744,-57.456,650.016,-50.112L585.936,-50.112ZM597.6,-86.544L592.128,-78.48C603.216,-73.728,614.016,-67.248,624.528,-59.184L630.144,-67.68C620.352,-75.168,609.408,-81.36,597.6,-86.544ZM613.44,-109.728L607.968,-101.664C617.472,-97.632,626.688,-92.16,635.76,-84.96L641.232,-93.312C632.88,-99.648,623.52,-105.12,613.44,-109.728Z"
android:fillColor="#000000" />
</group>
</group>
</group>
</vector>

@ -1,74 +1,170 @@
<?xml version="1.0" encoding="utf-8"?>
<vector
android:height="108dp"
android:width="108dp"
android:viewportHeight="108"
android:viewportWidth="108"
xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#3DDC84"
android:pathData="M0,0h108v108h-108z"/>
<path android:fillColor="#00000000" android:pathData="M9,0L9,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M19,0L19,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M29,0L29,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M39,0L39,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M49,0L49,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M59,0L59,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M69,0L69,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M79,0L79,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M89,0L89,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M99,0L99,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,9L108,9"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,19L108,19"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,29L108,29"
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 android:height="108dp"
android:width="108dp"
android:viewportHeight="108"
android:viewportWidth="108"
xmlns:android="http://schemas.android.com/apk/res/android">
<path
android:fillColor="#3DDC84"
android:pathData="M0,0h108v108h-108z" />
<path
android:fillColor="#00000000"
android:pathData="M9,0L9,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M19,0L19,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M29,0L29,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M39,0L39,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M49,0L49,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M59,0L59,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M69,0L69,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M79,0L79,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M89,0L89,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M99,0L99,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,9L108,9"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,19L108,19"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,29L108,29"
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>

@ -1,5 +1,11 @@
<vector android:alpha="0.57" android:height="24dp"
android:tint="#0A0033" 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 android:alpha="0.57"
android:height="24dp"
android:tint="#0A0033"
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>

@ -1,5 +1,11 @@
<vector android:alpha="0.57" android:height="24dp"
android:tint="#FB2516" 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 android:alpha="0.57"
android:height="24dp"
android:tint="#FB2516"
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>

@ -6,165 +6,165 @@
android:viewportHeight="108">
<path
android:fillColor="#008577"
android:pathData="M0,0h108v108h-108z"/>
android:pathData="M0,0h108v108h-108z" />
<path
android:fillColor="#00000000"
android:pathData="M9,0L9,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF"/>
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,0L19,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF"/>
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M29,0L29,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF"/>
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M39,0L39,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF"/>
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M49,0L49,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF"/>
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M59,0L59,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF"/>
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M69,0L69,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF"/>
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M79,0L79,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF"/>
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M89,0L89,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF"/>
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M99,0L99,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF"/>
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,9L108,9"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF"/>
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,19L108,19"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF"/>
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,29L108,29"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF"/>
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,39L108,39"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF"/>
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,49L108,49"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF"/>
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,59L108,59"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF"/>
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,69L108,69"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF"/>
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,79L108,79"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF"/>
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,89L108,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF"/>
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,99L108,99"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF"/>
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,29L89,29"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF"/>
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,39L89,39"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF"/>
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,49L89,49"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF"/>
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,59L89,59"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF"/>
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,69L89,69"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF"/>
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,79L89,79"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF"/>
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M29,19L29,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF"/>
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M39,19L39,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF"/>
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M49,19L49,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF"/>
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M59,19L59,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF"/>
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M69,19L69,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF"/>
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M79,19L79,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF"/>
android:strokeColor="#33FFFFFF" />
</vector>

@ -1,96 +1,136 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
<android.support.v4.widget.NestedScrollView
android:layout_width="match_parent"
android:orientation="horizontal"
android:layout_height="wrap_content">
<Button
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:textSize="12sp"
android:id="@+id/bt_sc_assets"
android:gravity="center"
android:layout_gravity="center"
android:padding="15dp"
android:text="@string/str_bt1"/>
<Button
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:textSize="14sp"
android:id="@+id/bt_sc_from_other"
android:gravity="center"
android:layout_gravity="center"
android:padding="15dp"
android:text="从相册选取"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:orientation="horizontal"
android:layout_height="wrap_content">
<Button
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:textSize="14sp"
android:id="@+id/bt_sc_from_cam"
android:gravity="center"
android:layout_gravity="center"
android:padding="15dp"
android:text="实时扫描"/>
<Button
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:textSize="14sp"
android:id="@+id/bt_sc_from_internet"
android:gravity="center"
android:layout_gravity="center"
android:padding="15dp"
android:text="识别网络图片"/>
</LinearLayout>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:id="@+id/tv_version"
android:textSize="15sp"
android:textColor="@color/blue"
android:padding="5dp"
android:text="版本号:"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="sfw:适宜在公共场所浏览,nsfw:不适宜在公共场所浏览,两者都是0-1中间的浮点型值,nsfw数值越大表示色情程度越高,sfw反之"
android:padding="15dp"
android:textSize="14sp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="所有图片均来源百度,如有侵权请联系我删除。大尺度图片请自行google来测试"
android:textColor="#FF0404"
android:padding="15dp"
android:textSize="12sp"/>
<android.support.v7.widget.RecyclerView
android:id="@+id/rv"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</LinearLayout>
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<Button
android:id="@+id/bt_sc_assets"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_weight="1"
android:gravity="center"
android:padding="15dp"
android:text="@string/str_bt1"
android:textSize="12sp" />
<Button
android:id="@+id/bt_sc_from_other"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_weight="1"
android:gravity="center"
android:padding="15dp"
android:text="从相册选取"
android:textSize="14sp" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<Button
android:id="@+id/bt_sc_from_cam"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_weight="1"
android:gravity="center"
android:padding="15dp"
android:text="实时扫描"
android:textSize="14sp" />
<Button
android:id="@+id/bt_sc_from_internet"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_weight="1"
android:gravity="center"
android:padding="15dp"
android:text="识别网络图片"
android:textSize="14sp" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<Button
android:id="@+id/bt_sc_from_api"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_weight="1"
android:gravity="center"
android:padding="15dp"
android:text="测试狼友上传的图片"
android:textSize="14sp" />
<Button
android:id="@+id/bt_upload"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_weight="1"
android:gravity="center"
android:padding="15dp"
android:text="我有资源可以提供"
android:textSize="14sp" />
</LinearLayout>
<TextView
android:id="@+id/tv_version"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:padding="5dp"
android:text="版本号:"
android:textColor="@color/blue"
android:textSize="15sp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="15dp"
android:text="sfw:适宜在公共场所浏览,nsfw:不适宜在公共场所浏览,两者都是0-1中间的浮点型值,nsfw数值越大表示色情程度越高,sfw反之"
android:textSize="14sp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="15dp"
android:text="所有图片均来源百度,如有侵权请联系我删除。大尺度图片请自行google来测试"
android:textColor="#FF0404"
android:textSize="12sp" />
<android.support.v7.widget.RecyclerView
android:id="@+id/rv"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
</android.support.v4.widget.NestedScrollView>
</LinearLayout>

@ -1,10 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".Main2Activity">
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".Main2Activity">
<LinearLayout
android:layout_width="match_parent"
@ -18,20 +18,20 @@
android:layout_weight="1"
android:background="@null"
android:hint="粘贴网络图片路径"
android:padding="15dp"/>
android:padding="15dp" />
<Button
android:id="@+id/bt"
android:layout_width="0dp"
android:layout_height="50dp"
android:layout_weight="0.3"
android:text="识别"/>
android:text="识别" />
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="#504d4d4d"/>
android:background="#504d4d4d" />
<TextView
android:id="@+id/tv"
@ -40,11 +40,11 @@
android:gravity="center"
android:textColor="#FA3C00"
android:padding="20dp"
android:text="这里显示检测结果"/>
android:text="这里显示检测结果" />
<ImageView
android:id="@+id/iv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="15dp"/>
android:padding="15dp" />
</LinearLayout>

@ -1,22 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:id="@+id/view"
android:layout_marginTop="5dp"
android:padding="20dp"
android:layout_width="match_parent"
android:id="@+id/view"
android:layout_marginTop="5dp"
android:padding="20dp"
android:layout_height="wrap_content">
android:layout_height="wrap_content">
<TextView
android:layout_width="match_parent"
android:id="@+id/tv_text"
android:layout_toLeftOf="@+id/iv"
android:layout_height="wrap_content"/>
android:layout_height="wrap_content" />
<ImageView
android:layout_width="100dp"
android:layout_height="100dp"
android:id="@+id/iv"
android:scaleType="centerCrop"
android:layout_alignParentRight="true"/>
android:layout_alignParentRight="true" />
</RelativeLayout>

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/change_background"/>
<foreground android:drawable="@drawable/ch"/>
<background android:drawable="@drawable/change_background" />
<foreground android:drawable="@drawable/ch" />
</adaptive-icon>

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/change_background"/>
<foreground android:drawable="@drawable/ch"/>
<background android:drawable="@drawable/change_background" />
<foreground android:drawable="@drawable/ch" />
</adaptive-icon>

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background"/>
<foreground android:drawable="@drawable/ic_launcher_foreground"/>
<background android:drawable="@drawable/ic_launcher_background" />
<foreground android:drawable="@drawable/ic_launcher_foreground" />
</adaptive-icon>

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background"/>
<foreground android:drawable="@drawable/ic_launcher_foreground"/>
<background android:drawable="@drawable/ic_launcher_background" />
<foreground android:drawable="@drawable/ic_launcher_foreground" />
</adaptive-icon>

@ -13,8 +13,8 @@
<item name="windowNoTitle">true</item>
</style>
<style name="AppTheme.AppBarOverlay" parent="ThemeOverlay.AppCompat.Dark.ActionBar"/>
<style name="AppTheme.AppBarOverlay" parent="ThemeOverlay.AppCompat.Dark.ActionBar" />
<style name="AppTheme.PopupOverlay" parent="ThemeOverlay.AppCompat.Light"/>
<style name="AppTheme.PopupOverlay" parent="ThemeOverlay.AppCompat.Light" />
</resources>

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<base-config cleartextTrafficPermitted="true" />
</network-security-config>

@ -3,10 +3,12 @@ buildscript {
repositories {
google()
jcenter()
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.6.3'
classpath 'com.android.tools.build:gradle:4.0.0'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath 'org.greenrobot:greendao-gradle-plugin:3.3.0'
}
}

1
demo/.gitignore vendored

@ -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>

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

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>

Binary file not shown.

After

Width:  |  Height:  |  Size: 163 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 121 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 201 B

Binary file not shown.

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&lt;List&lt;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&lt;List&lt;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>

Binary file not shown.

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
# 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.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
distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.4-all.zip
distributionPath=wrapper/dists
zipStorePath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.1.1-all.zip

Binary file not shown.

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'

Loading…
Cancel
Save