├── .github ├── dependabot.yml └── workflows │ └── android.yml ├── .gitignore ├── LICENSE ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro ├── schemas │ └── com.github.yueeng.moebooru.Db │ │ └── 1.json └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── github │ │ └── yueeng │ │ └── moebooru │ │ └── ExampleInstrumentedTest.kt │ ├── debug │ └── res │ │ └── values │ │ └── ic_launcher_background.xml │ ├── konachan │ ├── assets │ │ ├── database.db │ │ ├── summary.etag │ │ └── summary.json │ ├── ic_launcher-playstore.png │ └── res │ │ ├── drawable-hdpi │ │ └── ic_stat_name.png │ │ ├── drawable-mdpi │ │ └── ic_stat_name.png │ │ ├── drawable-xhdpi │ │ └── ic_stat_name.png │ │ ├── drawable-xxhdpi │ │ └── ic_stat_name.png │ │ ├── drawable-xxxhdpi │ │ └── ic_stat_name.png │ │ ├── mipmap-anydpi-v26 │ │ ├── ic_launcher.xml │ │ └── ic_launcher_round.xml │ │ ├── mipmap-hdpi │ │ ├── ic_launcher.png │ │ ├── ic_launcher_foreground.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-mdpi │ │ ├── ic_launcher.png │ │ ├── ic_launcher_foreground.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xhdpi │ │ ├── ic_launcher.png │ │ ├── ic_launcher_foreground.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxhdpi │ │ ├── ic_launcher.png │ │ ├── ic_launcher_foreground.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxxhdpi │ │ ├── ic_launcher.png │ │ ├── ic_launcher_foreground.png │ │ └── ic_launcher_round.png │ │ └── values │ │ ├── ic_launcher_background.xml │ │ └── values.xml │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── github │ │ │ └── yueeng │ │ │ └── moebooru │ │ │ ├── Common.kt │ │ │ ├── CropActivity.kt │ │ │ ├── Db.kt │ │ │ ├── MainActivity.kt │ │ │ ├── MainApplication.kt │ │ │ ├── Model.kt │ │ │ ├── PopularActivity.kt │ │ │ ├── PreviewActivity.kt │ │ │ ├── QueryActivity.kt │ │ │ ├── SavedActivity.kt │ │ │ ├── SettingsActivity.kt │ │ │ ├── SimilarActivity.kt │ │ │ └── UserActivity.kt │ └── res │ │ ├── drawable-night │ │ └── background_toolbar_translucent.xml │ │ ├── drawable │ │ ├── background_toolbar_translucent.xml │ │ ├── fab_title_background.xml │ │ ├── ic_about.xml │ │ ├── ic_add.xml │ │ ├── ic_all.xml │ │ ├── ic_anim.xml │ │ ├── ic_avatar.xml │ │ ├── ic_column.xml │ │ ├── ic_crop_rotate.xml │ │ ├── ic_date.xml │ │ ├── ic_day.xml │ │ ├── ic_daynight.xml │ │ ├── ic_done.xml │ │ ├── ic_edit.xml │ │ ├── ic_expand_less.xml │ │ ├── ic_github.xml │ │ ├── ic_high_quality.xml │ │ ├── ic_host.xml │ │ ├── ic_host_ip.xml │ │ ├── ic_image_search.xml │ │ ├── ic_jump.xml │ │ ├── ic_list_info.xml │ │ ├── ic_list_page.xml │ │ ├── ic_list_quality.xml │ │ ├── ic_month.xml │ │ ├── ic_notification.xml │ │ ├── ic_open.xml │ │ ├── ic_person.xml │ │ ├── ic_photo_children.xml │ │ ├── ic_photo_library.xml │ │ ├── ic_preview_color.xml │ │ ├── ic_reg.xml │ │ ├── ic_remove.xml │ │ ├── ic_safe.xml │ │ ├── ic_save.xml │ │ ├── ic_save_alt.xml │ │ ├── ic_search.xml │ │ ├── ic_settings.xml │ │ ├── ic_star.xml │ │ ├── ic_storage.xml │ │ ├── ic_undo.xml │ │ ├── ic_update.xml │ │ ├── ic_wallpaper.xml │ │ ├── ic_week.xml │ │ ├── ic_year.xml │ │ └── image_tag_background.xml │ │ ├── layout-v23 │ │ └── image_item.xml │ │ ├── layout │ │ ├── activity_container.xml │ │ ├── activity_crash.xml │ │ ├── activity_main.xml │ │ ├── fragment_image.xml │ │ ├── fragment_list.xml │ │ ├── fragment_main.xml │ │ ├── fragment_popular.xml │ │ ├── fragment_preview.xml │ │ ├── fragment_query.xml │ │ ├── fragment_saved.xml │ │ ├── fragment_settings.xml │ │ ├── fragment_similar.xml │ │ ├── fragment_star.xml │ │ ├── fragment_user.xml │ │ ├── image_item.xml │ │ ├── list_menu_header.xml │ │ ├── list_string_item.xml │ │ ├── popular_tab_item.xml │ │ ├── preview_item.xml │ │ ├── preview_tag_item.xml │ │ ├── query_item.xml │ │ ├── query_saved.xml │ │ ├── query_sheet_date.xml │ │ ├── query_sheet_int.xml │ │ ├── query_sheet_string.xml │ │ ├── query_sheet_vote.xml │ │ ├── query_suggestion_item.xml │ │ ├── query_tag_item.xml │ │ ├── settings_ip_address.xml │ │ ├── simple_input.xml │ │ ├── simple_list_item_2.xml │ │ ├── simple_list_item_2_single_choice.xml │ │ ├── state_item.xml │ │ ├── user_change_email.xml │ │ ├── user_change_pwd.xml │ │ ├── user_image_item.xml │ │ ├── user_login.xml │ │ ├── user_register.xml │ │ ├── user_reset.xml │ │ ├── user_tag_item.xml │ │ ├── user_title_item.xml │ │ ├── vote_title_item.xml │ │ └── vote_user_item.xml │ │ ├── menu │ │ ├── app.xml │ │ ├── main.xml │ │ ├── popular.xml │ │ ├── query.xml │ │ ├── saved.xml │ │ └── user.xml │ │ ├── values-night │ │ └── colors.xml │ │ ├── values-v35 │ │ └── styles.xml │ │ ├── values-w600dp │ │ └── values.xml │ │ ├── values-w720dp │ │ └── values.xml │ │ ├── values-zh │ │ └── strings.xml │ │ ├── values │ │ ├── colors.xml │ │ ├── strings.xml │ │ ├── styles.xml │ │ └── values.xml │ │ └── xml │ │ ├── filepaths.xml │ │ └── preferences.xml │ ├── test │ └── java │ │ └── com │ │ └── github │ │ └── yueeng │ │ └── moebooru │ │ └── ExampleUnitTest.kt │ └── yande │ ├── assets │ ├── database.db │ ├── summary.etag │ └── summary.json │ ├── ic_launcher-playstore.png │ └── res │ ├── drawable-hdpi │ └── ic_stat_name.png │ ├── drawable-mdpi │ └── ic_stat_name.png │ ├── drawable-xhdpi │ └── ic_stat_name.png │ ├── drawable-xxhdpi │ └── ic_stat_name.png │ ├── drawable-xxxhdpi │ └── ic_stat_name.png │ ├── mipmap-anydpi-v26 │ ├── ic_launcher.xml │ └── ic_launcher_round.xml │ ├── mipmap-hdpi │ ├── ic_launcher.png │ ├── ic_launcher_foreground.png │ └── ic_launcher_round.png │ ├── mipmap-mdpi │ ├── ic_launcher.png │ ├── ic_launcher_foreground.png │ └── ic_launcher_round.png │ ├── mipmap-xhdpi │ ├── ic_launcher.png │ ├── ic_launcher_foreground.png │ └── ic_launcher_round.png │ ├── mipmap-xxhdpi │ ├── ic_launcher.png │ ├── ic_launcher_foreground.png │ └── ic_launcher_round.png │ ├── mipmap-xxxhdpi │ ├── ic_launcher.png │ ├── ic_launcher_foreground.png │ └── ic_launcher_round.png │ └── values │ └── ic_launcher_background.xml ├── build.gradle ├── gradle.properties ├── gradle ├── libs.versions.toml └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # To get started with Dependabot version updates, you'll need to specify which 2 | # package ecosystems to update and where the package manifests are located. 3 | # Please see the documentation for all configuration options: 4 | # https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates 5 | 6 | version: 2 7 | updates: 8 | - package-ecosystem: "github-actions" 9 | directory: "/" 10 | schedule: 11 | interval: "weekly" 12 | - package-ecosystem: "gradle" # See documentation for possible values 13 | directory: "/" # Location of package manifests 14 | schedule: 15 | interval: "daily" 16 | open-pull-requests-limit: 16 17 | -------------------------------------------------------------------------------- /.github/workflows/android.yml: -------------------------------------------------------------------------------- 1 | name: Android CI 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | paths-ignore: 7 | - '.github/**' 8 | - '.idea/**' 9 | - 'README.md' 10 | - 'LICENSE' 11 | workflow_dispatch: 12 | jobs: 13 | build: 14 | runs-on: ubuntu-latest 15 | concurrency: 16 | group: build 17 | cancel-in-progress: true 18 | 19 | steps: 20 | - uses: actions/checkout@v4 21 | - name: Set up JDK 17 22 | uses: actions/setup-java@v4 23 | with: 24 | distribution: 'temurin' 25 | java-version: '17' 26 | - name: Cache Gradle 27 | uses: actions/cache@v4.2.3 28 | with: 29 | path: | 30 | ~/.gradle/caches 31 | ~/.gradle/wrapper 32 | key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }} 33 | restore-keys: | 34 | ${{ runner.os }}-gradle- 35 | - name: Time tick 36 | run: echo "time_tick=$(date '+%Y%m%d%H%M')" >> $GITHUB_ENV 37 | - name: Signing Apk 38 | run: | 39 | echo '${{ secrets.ANDROID_JKS }}'|base64 -d > android.jks 40 | echo 'storeFile=../android.jks' >> local.properties 41 | echo 'storePassword=${{ secrets.STORE_PASSWORD }}' >> local.properties 42 | echo 'keyAlias=${{ secrets.KEY_ALIAS }}' >> local.properties 43 | echo 'keyPassword=${{ secrets.KEY_PASSWORD }}' >> local.properties 44 | echo 'buildTime=${{ env.time_tick }}' >> local.properties 45 | - name: Update summary.json 46 | run: ./gradlew summary 47 | - name: Build with Gradle 48 | run: ./gradlew publish 49 | - name: Move Apk 50 | run: | 51 | cd ${{ github.workspace }}/app/build/outputs/apk 52 | mv konachan/release/* konachan/ 53 | rm -fr konachan/release 54 | mv yande/release/* yande/ 55 | rm -fr yande/release 56 | - name: Artifact Apk 57 | uses: actions/upload-artifact@v4 58 | with: 59 | name: outputs 60 | path: ${{ github.workspace }}/app/build/outputs/** 61 | - name: Zip Outputs 62 | run: | 63 | cd ${{ github.workspace }}/app/build/outputs 64 | zip -r build.outputs.zip . -x "apk/*" 65 | - name: Create Release 66 | id: create_release 67 | uses: softprops/action-gh-release@v2 68 | env: 69 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # This token is provided by Actions, you do not need to create your own token 70 | with: 71 | tag_name: ${{ env.time_tick }} 72 | name: pre-release ${{ env.time_tick }} 73 | body: | 74 | - ${{ github.event.head_commit.message }} 75 | - ${{ github.sha }} 76 | - ${{ github.ref }} 77 | draft: false 78 | prerelease: true 79 | files: | 80 | ${{ github.workspace }}/app/build/outputs/apk/konachan/app-konachan-release.apk 81 | ${{ github.workspace }}/app/build/outputs/apk/yande/app-yande-release.apk 82 | ${{ github.workspace }}/app/build/outputs/build.outputs.zip -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea 5 | /.kotlin 6 | .DS_Store 7 | /build 8 | /captures 9 | .externalNativeBuild 10 | .cxx 11 | /konachan/ 12 | /yande/ 13 | *.log -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Moebooru 2 | An Android application for konachan.com and yande.re. This application is used for learning and personal use, so updates are sporadic. 3 | 4 | | [](https://github.com/yueeng/moebooru/releases/latest/download/app-konachan-release.apk) | [](https://github.com/yueeng/moebooru/releases/latest/download/app-yande-release.apk) | 5 | |---|---| 6 | 7 | | | | 8 | |---|---| 9 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | alias(libs.plugins.androidApplication) 3 | alias(libs.plugins.jetbrainsKotlinAndroid) 4 | alias(libs.plugins.googleDevtoolsKsp) 5 | alias(libs.plugins.kotlinParcelize) 6 | } 7 | 8 | android { 9 | def config = new File("local.properties").withInputStream { stream -> 10 | new Properties().tap { load(stream) } 11 | } 12 | compileSdk 35 13 | buildToolsVersion = '35.0.1' 14 | 15 | namespace 'com.github.yueeng.moebooru' 16 | defaultConfig { 17 | applicationId "com.github.yueeng.moebooru" 18 | minSdkVersion 21 19 | targetSdkVersion 35 20 | versionCode 9 21 | versionName "1.0.9.1" 22 | resourceConfigurations += ['zh'] 23 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 24 | 25 | ksp { 26 | arg("room.schemaLocation", "$projectDir/schemas".toString()) 27 | } 28 | buildConfigField "String", "BUILD_TIME", "\"${config["buildTime"] ?: new Date().format("YYYYMMddHHmm")}\"" 29 | } 30 | 31 | signingConfigs { 32 | release { 33 | storeFile file(config['storeFile']) 34 | storePassword config['storePassword'] 35 | keyAlias config['keyAlias'] 36 | keyPassword config['keyPassword'] 37 | v1SigningEnabled true 38 | v2SigningEnabled true 39 | } 40 | } 41 | buildTypes { 42 | debug { 43 | applicationIdSuffix '.debug' 44 | versionNameSuffix '.debug' 45 | } 46 | release { 47 | // ndk.abiFilters 'armeabi-v7a', 'arm64-v8a' 48 | minifyEnabled true 49 | shrinkResources true 50 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 51 | signingConfig signingConfigs.release 52 | } 53 | } 54 | flavorDimensions = ['moe'] 55 | productFlavors { 56 | yande { 57 | dimension 'moe' 58 | applicationIdSuffix '.yande' 59 | resValue 'string', 'app_name', 'Yande' 60 | resValue 'string', 'app_host', 'yande.re' 61 | resValue 'string', 'app_ip', '198.251.89.183' 62 | resValue 'string', 'app_create_time', '2006-8-13' 63 | manifestPlaceholders.host = "yande.re" 64 | } 65 | konachan { 66 | dimension 'moe' 67 | applicationIdSuffix '.konachan' 68 | resValue "string", "app_name", "Konachan" 69 | resValue 'string', 'app_host', 'konachan.com' 70 | resValue 'string', 'app_ip', '104.21.4.105' 71 | resValue 'string', 'app_create_time', '2008-1-13' 72 | manifestPlaceholders.host = "konachan.com" 73 | } 74 | } 75 | buildFeatures { 76 | viewBinding true 77 | buildConfig true 78 | } 79 | compileOptions { 80 | sourceCompatibility JavaVersion.VERSION_17 81 | targetCompatibility JavaVersion.VERSION_17 82 | } 83 | kotlinOptions { 84 | jvmTarget = "17" 85 | } 86 | ksp { 87 | useKsp2 = false 88 | } 89 | packagingOptions { 90 | resources { 91 | excludes += ['DebugProbesKt.bin'] 92 | } 93 | } 94 | } 95 | 96 | dependencies { 97 | implementation libs.kotlinx.coroutines.core 98 | implementation libs.kotlinx.coroutines.android 99 | implementation libs.androidx.core.ktx 100 | implementation libs.androidx.preference.ktx 101 | implementation libs.androidx.appcompat 102 | implementation libs.androidx.constraintlayout 103 | implementation libs.androidx.lifecycle.livedata.ktx 104 | implementation libs.androidx.lifecycle.viewmodel.ktx 105 | implementation libs.androidx.lifecycle.process 106 | implementation libs.androidx.swiperefreshlayout 107 | implementation libs.androidx.paging.runtime.ktx 108 | implementation libs.androidx.activity.ktx 109 | implementation libs.androidx.fragment.ktx 110 | implementation libs.androidx.work.runtime.ktx 111 | implementation libs.androidx.palette.ktx 112 | implementation libs.androidx.room.runtime 113 | ksp libs.androidx.room.compiler 114 | implementation libs.androidx.room.ktx 115 | implementation libs.androidx.room.paging 116 | implementation libs.androidx.material 117 | implementation libs.androidx.flexbox 118 | implementation libs.gson 119 | implementation libs.okhttp 120 | implementation libs.okhttp.logging.interceptor 121 | implementation libs.retrofit 122 | implementation libs.retrofit.converter.gson 123 | implementation libs.retrofit.converter.scalars 124 | implementation libs.glide 125 | implementation libs.glide.okhttp3.integration 126 | ksp libs.glide.ksp 127 | implementation libs.glide.transformations 128 | implementation libs.persistentCookieJar 129 | implementation libs.gesture.views 130 | implementation libs.jsoup 131 | implementation libs.ucrop 132 | implementation libs.github.api 133 | testImplementation libs.junit 134 | androidTestImplementation libs.androidx.test.ext.junit 135 | androidTestImplementation libs.androidx.test.espresso 136 | } -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | 23 | -keepclassmembers,allowobfuscation class * { 24 | @com.google.gson.annotations.SerializedName ; 25 | } 26 | -keep class com.github.yueeng.moebooru.BuildConfig{*;} 27 | -keep class org.kohsuke.github.GH*{*;} 28 | -keep class com.yalantis.ucrop.util.RectUtils{*;} 29 | 30 | -dontwarn org.conscrypt.Conscrypt$Version 31 | -dontwarn org.conscrypt.Conscrypt 32 | -dontwarn org.conscrypt.ConscryptHostnameVerifier 33 | -dontwarn com.android.org.conscrypt.SSLParametersImpl 34 | -dontwarn org.apache.harmony.xnet.provider.jsse.SSLParametersImpl 35 | -dontwarn org.bouncycastle.jsse.BCSSLParameters 36 | -dontwarn org.bouncycastle.jsse.BCSSLSocket 37 | -dontwarn org.bouncycastle.jsse.provider.BouncyCastleJsseProvider 38 | -dontwarn org.openjsse.javax.net.ssl.SSLParameters 39 | -dontwarn org.openjsse.javax.net.ssl.SSLSocket 40 | -dontwarn org.openjsse.net.ssl.OpenJSSE 41 | 42 | -dontwarn com.infradna.tool.bridge_method_injector.BridgeMethodsAdded 43 | -dontwarn com.infradna.tool.bridge_method_injector.WithBridgeMethods 44 | -dontwarn edu.umd.cs.findbugs.annotations.NonNull 45 | -dontwarn edu.umd.cs.findbugs.annotations.CheckForNull 46 | -dontwarn edu.umd.cs.findbugs.annotations.SuppressFBWarnings 47 | -dontwarn java.beans.ConstructorProperties 48 | -dontwarn java.beans.Transient 49 | 50 | # https://github.com/square/retrofit/blob/master/retrofit/src/main/resources/META-INF/proguard/retrofit2.pro 51 | # Retrofit does reflection on generic parameters. InnerClasses is required to use Signature and 52 | # EnclosingMethod is required to use InnerClasses. 53 | -keepattributes Signature, InnerClasses, EnclosingMethod 54 | 55 | # Retrofit does reflection on method and parameter annotations. 56 | -keepattributes RuntimeVisibleAnnotations, RuntimeVisibleParameterAnnotations 57 | 58 | # Keep annotation default values (e.g., retrofit2.http.Field.encoded). 59 | -keepattributes AnnotationDefault 60 | 61 | # Retain service method parameters when optimizing. 62 | -keepclassmembers,allowshrinking,allowobfuscation interface * { 63 | @retrofit2.http.* ; 64 | } 65 | 66 | # Ignore annotation used for build tooling. 67 | -dontwarn org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement 68 | 69 | # Ignore JSR 305 annotations for embedding nullability information. 70 | -dontwarn javax.annotation.** 71 | 72 | # Guarded by a NoClassDefFoundError try/catch and only used when on the classpath. 73 | -dontwarn kotlin.Unit 74 | 75 | # Top-level functions that can only be used by Kotlin. 76 | -dontwarn retrofit2.KotlinExtensions 77 | -dontwarn retrofit2.KotlinExtensions$* 78 | 79 | # With R8 full mode, it sees no subtypes of Retrofit interfaces since they are created with a Proxy 80 | # and replaces all potential values with null. Explicitly keeping the interfaces prevents this. 81 | -if interface * { @retrofit2.http.* ; } 82 | -keep,allowobfuscation interface <1> 83 | 84 | # Keep inherited services. 85 | -if interface * { @retrofit2.http.* ; } 86 | -keep,allowobfuscation interface * extends <1> 87 | 88 | # Keep generic signature of Call, Response (R8 full mode strips signatures from non-kept items). 89 | -keep,allowobfuscation,allowshrinking interface retrofit2.Call 90 | -keep,allowobfuscation,allowshrinking class retrofit2.Response 91 | 92 | # With R8 full mode generic signatures are stripped for classes that are not 93 | # kept. Suspend functions are wrapped in continuations where the type argument 94 | # is used. 95 | -keep,allowobfuscation,allowshrinking class kotlin.coroutines.Continuation 96 | 97 | -------------------------------------------------------------------------------- /app/schemas/com.github.yueeng.moebooru.Db/1.json: -------------------------------------------------------------------------------- 1 | { 2 | "formatVersion": 1, 3 | "database": { 4 | "version": 1, 5 | "identityHash": "84941ee73d8453ec36b7f1b065fe099b", 6 | "entities": [ 7 | { 8 | "tableName": "tags", 9 | "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `tag` TEXT NOT NULL, `name` TEXT NOT NULL, `pin` INTEGER NOT NULL, `create` INTEGER NOT NULL)", 10 | "fields": [ 11 | { 12 | "fieldPath": "id", 13 | "columnName": "id", 14 | "affinity": "INTEGER", 15 | "notNull": true 16 | }, 17 | { 18 | "fieldPath": "tag", 19 | "columnName": "tag", 20 | "affinity": "TEXT", 21 | "notNull": true 22 | }, 23 | { 24 | "fieldPath": "name", 25 | "columnName": "name", 26 | "affinity": "TEXT", 27 | "notNull": true 28 | }, 29 | { 30 | "fieldPath": "pin", 31 | "columnName": "pin", 32 | "affinity": "INTEGER", 33 | "notNull": true 34 | }, 35 | { 36 | "fieldPath": "create", 37 | "columnName": "create", 38 | "affinity": "INTEGER", 39 | "notNull": true 40 | } 41 | ], 42 | "primaryKey": { 43 | "columnNames": [ 44 | "id" 45 | ], 46 | "autoGenerate": true 47 | }, 48 | "indices": [ 49 | { 50 | "name": "index_tags_tag", 51 | "unique": true, 52 | "columnNames": [ 53 | "tag" 54 | ], 55 | "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_tags_tag` ON `${TABLE_NAME}` (`tag`)" 56 | } 57 | ], 58 | "foreignKeys": [] 59 | }, 60 | { 61 | "tableName": "order", 62 | "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`tag` TEXT NOT NULL, `index` INTEGER NOT NULL, PRIMARY KEY(`tag`))", 63 | "fields": [ 64 | { 65 | "fieldPath": "tag", 66 | "columnName": "tag", 67 | "affinity": "TEXT", 68 | "notNull": true 69 | }, 70 | { 71 | "fieldPath": "index", 72 | "columnName": "index", 73 | "affinity": "INTEGER", 74 | "notNull": true 75 | } 76 | ], 77 | "primaryKey": { 78 | "columnNames": [ 79 | "tag" 80 | ], 81 | "autoGenerate": false 82 | }, 83 | "indices": [ 84 | { 85 | "name": "index_order_tag", 86 | "unique": true, 87 | "columnNames": [ 88 | "tag" 89 | ], 90 | "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_order_tag` ON `${TABLE_NAME}` (`tag`)" 91 | }, 92 | { 93 | "name": "index_order_index", 94 | "unique": false, 95 | "columnNames": [ 96 | "index" 97 | ], 98 | "createSql": "CREATE INDEX IF NOT EXISTS `index_order_index` ON `${TABLE_NAME}` (`index`)" 99 | } 100 | ], 101 | "foreignKeys": [] 102 | } 103 | ], 104 | "views": [], 105 | "setupQueries": [ 106 | "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", 107 | "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '84941ee73d8453ec36b7f1b065fe099b')" 108 | ] 109 | } 110 | } -------------------------------------------------------------------------------- /app/src/androidTest/java/com/github/yueeng/moebooru/ExampleInstrumentedTest.kt: -------------------------------------------------------------------------------- 1 | package com.github.yueeng.moebooru 2 | 3 | import androidx.test.ext.junit.runners.AndroidJUnit4 4 | import androidx.test.platform.app.InstrumentationRegistry 5 | import org.junit.Assert.assertEquals 6 | import org.junit.Test 7 | import org.junit.runner.RunWith 8 | 9 | /** 10 | * Instrumented test, which will execute on an Android device. 11 | * 12 | * See [testing documentation](http://d.android.com/tools/testing). 13 | */ 14 | @RunWith(AndroidJUnit4::class) 15 | class ExampleInstrumentedTest { 16 | @Test 17 | fun useAppContext() { 18 | // Context of the app under test. 19 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext 20 | assertEquals("com.github.yueeng.moebooru", appContext.packageName) 21 | } 22 | } -------------------------------------------------------------------------------- /app/src/debug/res/values/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #000000 4 | -------------------------------------------------------------------------------- /app/src/konachan/assets/database.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yueeng/moebooru/23bf58e44a3c3ad58e8c550012cf7e9f7302d2c7/app/src/konachan/assets/database.db -------------------------------------------------------------------------------- /app/src/konachan/assets/summary.etag: -------------------------------------------------------------------------------- 1 | "8de057ed4ad08dab1d686dc089a5af5b" -------------------------------------------------------------------------------- /app/src/konachan/ic_launcher-playstore.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yueeng/moebooru/23bf58e44a3c3ad58e8c550012cf7e9f7302d2c7/app/src/konachan/ic_launcher-playstore.png -------------------------------------------------------------------------------- /app/src/konachan/res/drawable-hdpi/ic_stat_name.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yueeng/moebooru/23bf58e44a3c3ad58e8c550012cf7e9f7302d2c7/app/src/konachan/res/drawable-hdpi/ic_stat_name.png -------------------------------------------------------------------------------- /app/src/konachan/res/drawable-mdpi/ic_stat_name.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yueeng/moebooru/23bf58e44a3c3ad58e8c550012cf7e9f7302d2c7/app/src/konachan/res/drawable-mdpi/ic_stat_name.png -------------------------------------------------------------------------------- /app/src/konachan/res/drawable-xhdpi/ic_stat_name.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yueeng/moebooru/23bf58e44a3c3ad58e8c550012cf7e9f7302d2c7/app/src/konachan/res/drawable-xhdpi/ic_stat_name.png -------------------------------------------------------------------------------- /app/src/konachan/res/drawable-xxhdpi/ic_stat_name.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yueeng/moebooru/23bf58e44a3c3ad58e8c550012cf7e9f7302d2c7/app/src/konachan/res/drawable-xxhdpi/ic_stat_name.png -------------------------------------------------------------------------------- /app/src/konachan/res/drawable-xxxhdpi/ic_stat_name.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yueeng/moebooru/23bf58e44a3c3ad58e8c550012cf7e9f7302d2c7/app/src/konachan/res/drawable-xxxhdpi/ic_stat_name.png -------------------------------------------------------------------------------- /app/src/konachan/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/konachan/res/mipmap-anydpi-v26/ic_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/konachan/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yueeng/moebooru/23bf58e44a3c3ad58e8c550012cf7e9f7302d2c7/app/src/konachan/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/konachan/res/mipmap-hdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yueeng/moebooru/23bf58e44a3c3ad58e8c550012cf7e9f7302d2c7/app/src/konachan/res/mipmap-hdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /app/src/konachan/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yueeng/moebooru/23bf58e44a3c3ad58e8c550012cf7e9f7302d2c7/app/src/konachan/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/konachan/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yueeng/moebooru/23bf58e44a3c3ad58e8c550012cf7e9f7302d2c7/app/src/konachan/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/konachan/res/mipmap-mdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yueeng/moebooru/23bf58e44a3c3ad58e8c550012cf7e9f7302d2c7/app/src/konachan/res/mipmap-mdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /app/src/konachan/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yueeng/moebooru/23bf58e44a3c3ad58e8c550012cf7e9f7302d2c7/app/src/konachan/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/konachan/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yueeng/moebooru/23bf58e44a3c3ad58e8c550012cf7e9f7302d2c7/app/src/konachan/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/konachan/res/mipmap-xhdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yueeng/moebooru/23bf58e44a3c3ad58e8c550012cf7e9f7302d2c7/app/src/konachan/res/mipmap-xhdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /app/src/konachan/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yueeng/moebooru/23bf58e44a3c3ad58e8c550012cf7e9f7302d2c7/app/src/konachan/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/konachan/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yueeng/moebooru/23bf58e44a3c3ad58e8c550012cf7e9f7302d2c7/app/src/konachan/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/konachan/res/mipmap-xxhdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yueeng/moebooru/23bf58e44a3c3ad58e8c550012cf7e9f7302d2c7/app/src/konachan/res/mipmap-xxhdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /app/src/konachan/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yueeng/moebooru/23bf58e44a3c3ad58e8c550012cf7e9f7302d2c7/app/src/konachan/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/konachan/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yueeng/moebooru/23bf58e44a3c3ad58e8c550012cf7e9f7302d2c7/app/src/konachan/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/konachan/res/mipmap-xxxhdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yueeng/moebooru/23bf58e44a3c3ad58e8c550012cf7e9f7302d2c7/app/src/konachan/res/mipmap-xxxhdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /app/src/konachan/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yueeng/moebooru/23bf58e44a3c3ad58e8c550012cf7e9f7302d2c7/app/src/konachan/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/konachan/res/values/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #FFFFFF 4 | -------------------------------------------------------------------------------- /app/src/konachan/res/values/values.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 90dp 4 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 13 | 14 | 22 | 25 | 26 | 27 | 28 | 29 | 30 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 79 | 80 | 81 | 84 | 85 | 90 | 93 | 94 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | -------------------------------------------------------------------------------- /app/src/main/java/com/github/yueeng/moebooru/CropActivity.kt: -------------------------------------------------------------------------------- 1 | package com.github.yueeng.moebooru 2 | 3 | import android.Manifest 4 | import android.app.PendingIntent 5 | import android.content.Intent 6 | import android.content.pm.PackageManager 7 | import android.graphics.Bitmap 8 | import android.graphics.drawable.Drawable 9 | import android.net.Uri 10 | import android.os.Bundle 11 | import android.webkit.MimeTypeMap 12 | import android.widget.Toast 13 | import androidx.appcompat.app.AppCompatActivity 14 | import androidx.core.app.ActivityCompat 15 | import androidx.core.app.NotificationCompat 16 | import androidx.core.app.NotificationManagerCompat 17 | import androidx.core.content.FileProvider 18 | import com.bumptech.glide.Glide 19 | import com.bumptech.glide.load.engine.DiskCacheStrategy 20 | import com.bumptech.glide.request.target.CustomTarget 21 | import com.bumptech.glide.request.transition.Transition 22 | import com.yalantis.ucrop.UCrop 23 | import com.yalantis.ucrop.UCropActivity 24 | import java.io.File 25 | import java.util.UUID 26 | 27 | class CropActivity : AppCompatActivity() { 28 | companion object { 29 | const val OPTION_SHARE = 1 30 | const val OPTION_AVATAR = 2 31 | } 32 | 33 | private val op: Int by lazy { intent.getIntExtra("op", 0) } 34 | private val id: Int by lazy { intent.getIntExtra("id", 0) } 35 | private val name: String by lazy { intent.getStringExtra("name") ?: getString(R.string.app_name) } 36 | private val source: Uri by lazy { intent.getParcelableExtraCompat("source")!! } 37 | private val cropShare = registerForActivityResult(CropImage()) { result -> 38 | try { 39 | if (result == null) return@registerForActivityResult 40 | val extension = MimeTypeMap.getFileExtensionFromUrl(result.output.path!!) 41 | val mime = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension) 42 | val uri = FileProvider.getUriForFile(this, "${BuildConfig.APPLICATION_ID}.fileprovider", File(result.output.path!!)) 43 | startActivity(Intent.createChooser(Intent(Intent.ACTION_VIEW).apply { 44 | type = mime ?: "image/$extension" 45 | data = uri 46 | addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) 47 | addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) 48 | }, getString(R.string.app_share))) 49 | notifyImageComplete(uri, id, getString(R.string.app_name), name) 50 | } finally { 51 | finish() 52 | } 53 | } 54 | 55 | private val cropAvatar = registerForActivityResult(CropImage()) { data -> 56 | try { 57 | if (data == null) return@registerForActivityResult 58 | OAuth.avatar(this, OAuth.user.value!!, id, 1F * data.offsetX / data.originWidth, 1F * (data.offsetX + data.imageWidth) / data.originWidth, 1F * data.offsetY / data.originHeight, 1F * (data.offsetY + data.imageHeight) / data.originHeight) { 59 | Toast.makeText(this, R.string.app_complete, Toast.LENGTH_SHORT).show() 60 | } 61 | } finally { 62 | finish() 63 | } 64 | } 65 | 66 | override fun onCreate(savedInstanceState: Bundle?) { 67 | super.onCreate(savedInstanceState) 68 | when (op) { 69 | OPTION_SHARE -> { 70 | val dest = File(File(cacheDir, "shared").apply { mkdirs() }, name) 71 | cropShare.launch(UCrop.of(source, Uri.fromFile(dest))) 72 | } 73 | 74 | OPTION_AVATAR -> { 75 | val dest = File(cacheDir, UUID.randomUUID().toString()) 76 | val option = UCrop.Options().apply { 77 | setAllowedGestures(UCropActivity.SCALE, UCropActivity.NONE, UCropActivity.SCALE) 78 | setHideBottomControls(true) 79 | } 80 | val crop = UCrop.of(source, Uri.fromFile(dest)) 81 | .withAspectRatio(1F, 1F).withOptions(option) 82 | cropAvatar.launch(crop) 83 | } 84 | 85 | else -> finish() 86 | } 87 | } 88 | 89 | private fun notifyImageComplete(uri: Uri, id: Int, title: String, content: String) { 90 | val extension = MimeTypeMap.getFileExtensionFromUrl(uri.toString()) 91 | val mime = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension) 92 | val intent = Intent(Intent.ACTION_VIEW).apply { 93 | setDataAndType(uri, mime ?: "image/$extension") 94 | addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) 95 | addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) 96 | } 97 | 98 | val builder = NotificationCompat.Builder(this, moeHost) 99 | .setContentTitle(title) 100 | .setContentText(content) 101 | .setAutoCancel(true) 102 | .setSmallIcon(R.drawable.ic_stat_name) 103 | .setContentIntent(PendingIntent.getActivity(this, id, Intent.createChooser(intent, getString(R.string.app_share)), PendingIntentCompat.FLAG_IMMUTABLE)) 104 | Glide.with(this).asBitmap().load(uri) 105 | .diskCacheStrategy(DiskCacheStrategy.NONE) 106 | .skipMemoryCache(true) 107 | .override(500, 500) 108 | .into(object : CustomTarget() { 109 | override fun onResourceReady(resource: Bitmap, transition: Transition?) { 110 | builder.setStyle(NotificationCompat.BigPictureStyle().bigPicture(resource)) 111 | .setLargeIcon(resource) 112 | if (ActivityCompat.checkSelfPermission(this@CropActivity, Manifest.permission.POST_NOTIFICATIONS) == PackageManager.PERMISSION_GRANTED) { 113 | NotificationManagerCompat.from(this@CropActivity).notify(id, builder.build()) 114 | } 115 | } 116 | 117 | override fun onLoadFailed(errorDrawable: Drawable?) { 118 | if (ActivityCompat.checkSelfPermission(this@CropActivity, Manifest.permission.POST_NOTIFICATIONS) == PackageManager.PERMISSION_GRANTED) { 119 | NotificationManagerCompat.from(this@CropActivity).notify(id, builder.build()) 120 | } 121 | } 122 | 123 | override fun onLoadCleared(placeholder: Drawable?) = Unit 124 | }) 125 | } 126 | } -------------------------------------------------------------------------------- /app/src/main/java/com/github/yueeng/moebooru/Db.kt: -------------------------------------------------------------------------------- 1 | package com.github.yueeng.moebooru 2 | 3 | import android.content.Context 4 | import androidx.paging.PagingSource 5 | import androidx.room.ColumnInfo 6 | import androidx.room.Dao 7 | import androidx.room.Database 8 | import androidx.room.Delete 9 | import androidx.room.Entity 10 | import androidx.room.Index 11 | import androidx.room.Insert 12 | import androidx.room.OnConflictStrategy 13 | import androidx.room.PrimaryKey 14 | import androidx.room.Query 15 | import androidx.room.Room 16 | import androidx.room.RoomDatabase 17 | import androidx.room.TypeConverter 18 | import androidx.room.TypeConverters 19 | import androidx.room.Update 20 | import kotlinx.coroutines.flow.Flow 21 | import java.util.Date 22 | 23 | @Entity( 24 | tableName = "tags", 25 | indices = [Index("tag", unique = true)] 26 | ) 27 | data class DbTag( 28 | @PrimaryKey(autoGenerate = true) val id: Long, 29 | @ColumnInfo(name = "tag") var tag: String, 30 | @ColumnInfo(name = "name") var name: String, 31 | @ColumnInfo(name = "pin") var pin: Boolean = false, 32 | @ColumnInfo(name = "create") var create: Date = Date() 33 | ) { 34 | fun update(tag: String, name: String, pin: Boolean) = apply { 35 | this.tag = tag 36 | this.name = name 37 | this.pin = pin 38 | this.create = Date() 39 | } 40 | } 41 | 42 | @Entity( 43 | tableName = "order", 44 | indices = [Index("tag", unique = true), Index("index")] 45 | ) 46 | data class DbTagOrder( 47 | @PrimaryKey @ColumnInfo(name = "tag") var tag: String, 48 | @ColumnInfo(name = "index") var index: Int 49 | ) 50 | 51 | @Dao 52 | interface DbDao { 53 | @Query("SELECT * FROM tags WHERE pin = :pin ORDER BY `create` DESC") 54 | suspend fun tags(pin: Boolean): List 55 | 56 | @Query("SELECT tags.* FROM tags LEFT JOIN `order` ON tags.tag = `order`.tag WHERE pin = :pin ORDER BY `order`.`index`, `create` DESC") 57 | fun tagsWithIndex(pin: Boolean): Flow> 58 | 59 | @Query("SELECT * FROM tags ORDER BY `pin` DESC, `create` DESC") 60 | suspend fun tags(): List 61 | 62 | @Query("SELECT tags.* FROM tags LEFT JOIN `order` ON tags.tag = `order`.tag WHERE pin = :pin ORDER BY `order`.`index`, `create` DESC") 63 | fun pagingTagsWithIndex(pin: Boolean): PagingSource 64 | 65 | @Query("SELECT * FROM tags WHERE pin = :pin ORDER BY `create` DESC") 66 | fun pagingTags(pin: Boolean): PagingSource 67 | 68 | @Query("SELECT * FROM tags ORDER BY `pin` DESC, `create` DESC") 69 | fun pagingTags(): PagingSource 70 | 71 | @Query("SELECT * FROM tags WHERE tag = :tag LIMIT 1") 72 | suspend fun tag(tag: String): DbTag? 73 | 74 | @Query("SELECT * FROM tags WHERE id = :id LIMIT 1") 75 | suspend fun tag(id: Long): DbTag? 76 | 77 | @Insert(onConflict = OnConflictStrategy.REPLACE) 78 | suspend fun insertTag(tag: DbTag): Long 79 | 80 | @Update 81 | suspend fun updateTag(tag: DbTag) 82 | 83 | @Delete 84 | suspend fun deleteTag(tag: DbTag) 85 | 86 | @Query("DELETE FROM `order` WHERE `order`.tag = :tag") 87 | suspend fun deleteOrder(tag: String) 88 | 89 | @Insert(onConflict = OnConflictStrategy.REPLACE) 90 | suspend fun insertOrder(order: DbTagOrder): Long 91 | } 92 | 93 | class DaoConverter { 94 | 95 | @TypeConverter 96 | fun dataFromTimestamp(value: Long?): Date? = value?.let { Date(it) } 97 | 98 | @TypeConverter 99 | fun dateToTimestamp(date: Date?): Long? = date?.time 100 | } 101 | 102 | @Database( 103 | entities = [DbTag::class, DbTagOrder::class], 104 | version = 1, 105 | exportSchema = true 106 | ) 107 | @TypeConverters(DaoConverter::class) 108 | abstract class Db : RoomDatabase() { 109 | companion object { 110 | private fun create(context: Context): Db = Room.databaseBuilder(context, Db::class.java, "database.db") 111 | .createFromAsset("database.db") 112 | .fallbackToDestructiveMigration(false) 113 | .build() 114 | 115 | val db: Db by lazy { create(MainApplication.instance()) } 116 | val tags: DbDao get() = db.tags() 117 | } 118 | 119 | abstract fun tags(): DbDao 120 | } -------------------------------------------------------------------------------- /app/src/main/res/drawable-night/background_toolbar_translucent.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/background_toolbar_translucent.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/fab_title_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_about.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_add.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_all.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_anim.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_avatar.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_column.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_crop_rotate.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_date.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_day.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_daynight.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_done.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_edit.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_expand_less.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_github.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_high_quality.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_host.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_host_ip.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_image_search.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_jump.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_list_info.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 13 | 16 | 17 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_list_page.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 13 | 16 | 19 | 20 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_list_quality.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_month.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_notification.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_open.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_person.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_photo_children.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_photo_library.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_preview_color.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_reg.xml: -------------------------------------------------------------------------------- 1 | 7 | 11 | 15 | 16 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_remove.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_safe.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_save.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_save_alt.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_search.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_settings.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_star.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_storage.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_undo.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_update.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_wallpaper.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_week.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_year.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/image_tag_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/layout-v23/image_item.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 13 | 14 | 26 | 27 | 37 | 38 | 50 | 51 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_container.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_crash.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 10 | 11 | 17 | 18 | 19 | 20 | 24 | 25 | 29 | 30 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 13 | 14 | 23 | 24 | 33 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_image.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 13 | 14 | 22 | 23 | 24 | 31 | 32 | 43 | 44 | 55 | 56 | 67 | 68 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_list.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 13 | 14 | 20 | 21 | 22 | 23 | 28 | 29 | 35 | 36 | 45 | 46 | 58 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 13 | 14 | 21 | 22 | 27 | 28 | 29 | 34 | 35 | 41 | 42 | 51 | 52 | 64 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_popular.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 13 | 14 | 20 | 21 | 29 | 30 | 31 | 36 | 37 | 46 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_query.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 13 | 14 | 20 | 21 | 22 | 23 | 30 | 31 | 40 | 41 | 54 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_saved.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 11 | 12 | 17 | 18 | 19 | 20 | 25 | 26 | 34 | 35 | 36 | 45 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 10 | 11 | 15 | 16 | 17 | 18 | 27 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_similar.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 13 | 14 | 20 | 21 | 29 | 30 | 31 | 36 | 37 | 45 | 46 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_star.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 13 | 14 | 21 | 22 | 25 | 26 | 37 | 38 | 49 | 50 | 51 | 52 | 57 | 58 | 66 | 67 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_user.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 13 | 14 | 19 | 20 | 27 | 28 | 35 | 36 | 37 | 38 | 43 | 44 | 50 | 51 | -------------------------------------------------------------------------------- /app/src/main/res/layout/image_item.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 13 | 14 | 26 | 27 | 37 | 38 | 50 | 51 | -------------------------------------------------------------------------------- /app/src/main/res/layout/list_menu_header.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 22 | -------------------------------------------------------------------------------- /app/src/main/res/layout/list_string_item.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 18 | 19 | 30 | -------------------------------------------------------------------------------- /app/src/main/res/layout/popular_tab_item.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 19 | 20 | 30 | -------------------------------------------------------------------------------- /app/src/main/res/layout/preview_item.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 13 | 14 | 21 | 22 | -------------------------------------------------------------------------------- /app/src/main/res/layout/preview_tag_item.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 13 | 14 | 29 | 30 | 41 | 42 | 50 | 51 | -------------------------------------------------------------------------------- /app/src/main/res/layout/query_item.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 12 | 13 | 27 | 28 | 43 | 44 | -------------------------------------------------------------------------------- /app/src/main/res/layout/query_saved.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 11 | 12 | 19 | 20 | 24 | 25 | 26 | 34 | 35 | -------------------------------------------------------------------------------- /app/src/main/res/layout/query_sheet_date.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 11 | 12 | 20 | 21 | 27 | 28 | 34 | 35 | 41 | 42 | 48 | 49 | 55 | 56 | 62 | 63 | 64 | 72 | 73 | 84 | 85 | 90 | 91 | 92 | 103 | 104 | 109 | 110 | 111 | -------------------------------------------------------------------------------- /app/src/main/res/layout/query_sheet_int.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 11 | 12 | 20 | 21 | 27 | 28 | 34 | 35 | 41 | 42 | 48 | 49 | 55 | 56 | 62 | 63 | 64 | 72 | 73 | 78 | 79 | 80 | 88 | 89 | 94 | 95 | 96 | -------------------------------------------------------------------------------- /app/src/main/res/layout/query_sheet_string.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 19 | 20 | 24 | 25 | -------------------------------------------------------------------------------- /app/src/main/res/layout/query_suggestion_item.xml: -------------------------------------------------------------------------------- 1 | 15 | 16 | 26 | 27 | 36 | 37 | 47 | 48 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /app/src/main/res/layout/query_tag_item.xml: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 15 | 16 | 29 | 30 | 41 | 42 | -------------------------------------------------------------------------------- /app/src/main/res/layout/settings_ip_address.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 16 | 17 | 23 | 24 | -------------------------------------------------------------------------------- /app/src/main/res/layout/simple_input.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 12 | 13 | 18 | 19 | -------------------------------------------------------------------------------- /app/src/main/res/layout/simple_list_item_2.xml: -------------------------------------------------------------------------------- 1 | 15 | 16 | 25 | 26 | 35 | 36 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /app/src/main/res/layout/simple_list_item_2_single_choice.xml: -------------------------------------------------------------------------------- 1 | 15 | 16 | 24 | 25 | 40 | 41 | 53 | 54 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /app/src/main/res/layout/state_item.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 14 | 15 | 22 | 23 |