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