From 4028739e70c29f4f2b74b2805ac307e0c5e59af5 Mon Sep 17 00:00:00 2001 From: tom5079 <7948651+tom5079@users.noreply.github.com> Date: Mon, 1 Jul 2024 11:18:30 -0700 Subject: [PATCH] complete migration to compose --- app/build.gradle | 151 --------- app/build.gradle.kts | 165 ++++++++++ app/proguard-rules.pro | 2 +- app/src/main/AndroidManifest.xml | 23 +- app/src/main/java/xyz/quaver/pupil/Pupil.kt | 109 +----- .../xyz/quaver/pupil/di/SingletonModule.kt | 2 +- .../pupil/networking/HitomiHttpClient.kt | 1 + .../pupil/receiver/UpdateBroadcastReceiver.kt | 96 ------ .../java/xyz/quaver/pupil/ui/BaseActivity.kt | 67 ---- .../java/xyz/quaver/pupil/ui/LockActivity.kt | 280 ---------------- .../java/xyz/quaver/pupil/ui/MainActivity.kt | 3 +- .../xyz/quaver/pupil/ui/SettingsActivity.kt | 45 --- .../xyz/quaver/pupil/ui/composable/Gallery.kt | 13 +- .../xyz/quaver/pupil/ui/composable/MainApp.kt | 9 +- .../pupil/ui/dialog/DefaultQueryDialog.kt | 171 ---------- .../DownloadFolderNameDialogFragment.kt | 85 ----- .../dialog/DownloadLocationDialogFragment.kt | 157 --------- .../pupil/ui/dialog/ProxyDialogFragment.kt | 133 -------- .../pupil/ui/fragment/LockSettingsFragment.kt | 146 --------- .../ui/fragment/ManageFavoritesFragment.kt | 140 -------- .../pupil/ui/fragment/PINLockFragment.kt | 57 ---- .../pupil/ui/fragment/PatternLockFragment.kt | 61 ---- .../pupil/ui/fragment/SettingsFragment.kt | 309 ------------------ .../xyz/quaver/pupil/ui/reader/ImageViewer.kt | 2 - .../xyz/quaver/pupil/util/ItemClickSupport.kt | 69 ---- .../java/xyz/quaver/pupil/util/Preferences.kt | 48 --- .../java/xyz/quaver/pupil/util/SavedSet.kt | 93 ------ .../main/java/xyz/quaver/pupil/util/camera.kt | 119 ------- .../main/java/xyz/quaver/pupil/util/file.kt | 67 ---- .../main/java/xyz/quaver/pupil/util/lock.kt | 124 ------- .../main/java/xyz/quaver/pupil/util/misc.kt | 172 ---------- .../main/java/xyz/quaver/pupil/util/proxy.kt | 58 ---- .../java/xyz/quaver/pupil/util/translation.kt | 68 ---- .../main/java/xyz/quaver/pupil/util/update.kt | 214 ------------ app/src/main/res/anim/shake.xml | 24 -- app/src/main/res/anim/shake_cycle.xml | 21 -- app/src/main/res/color/lock_fab.xml | 23 -- .../main/res/drawable-hdpi/ic_fullscreen.png | Bin 145 -> 0 bytes .../res/drawable-hdpi/ic_notification.png | Bin 255 -> 0 bytes .../main/res/drawable-mdpi/ic_fullscreen.png | Bin 99 -> 0 bytes .../res/drawable-mdpi/ic_notification.png | Bin 183 -> 0 bytes .../main/res/drawable-xhdpi/ic_fullscreen.png | Bin 125 -> 0 bytes .../res/drawable-xhdpi/ic_notification.png | Bin 311 -> 0 bytes .../res/drawable-xxhdpi/ic_fullscreen.png | Bin 149 -> 0 bytes .../res/drawable-xxhdpi/ic_notification.png | Bin 432 -> 0 bytes .../res/drawable-xxxhdpi/ic_notification.png | Bin 605 -> 0 bytes app/src/main/res/drawable/account_group.xml | 4 - app/src/main/res/drawable/account_star.xml | 4 - app/src/main/res/drawable/avd_star.xml | 14 - .../main/res/drawable/backspace_outline.xml | 4 - app/src/main/res/drawable/book_open.xml | 4 - app/src/main/res/drawable/brush.xml | 4 - app/src/main/res/drawable/close.xml | 4 - app/src/main/res/drawable/delete.xml | 4 - app/src/main/res/drawable/dot.xml | 30 -- app/src/main/res/drawable/eye.xml | 8 - app/src/main/res/drawable/eye_closed.xml | 44 --- app/src/main/res/drawable/eye_off.xml | 8 - app/src/main/res/drawable/eye_off_white.xml | 8 - app/src/main/res/drawable/eye_white.xml | 8 - app/src/main/res/drawable/fingerprint.xml | 4 - app/src/main/res/drawable/gender_female.xml | 4 - .../main/res/drawable/gender_female_white.xml | 4 - app/src/main/res/drawable/gender_male.xml | 4 - .../main/res/drawable/gender_male_white.xml | 4 - app/src/main/res/drawable/history.xml | 4 - app/src/main/res/drawable/hitomi.png | Bin 3768 -> 0 bytes app/src/main/res/drawable/ic_download.xml | 3 - app/src/main/res/drawable/ic_downloading.xml | 19 -- app/src/main/res/drawable/ic_star_empty.xml | 3 - app/src/main/res/drawable/ic_star_filled.xml | 3 - .../res/drawable/image_broken_variant.xml | 4 - app/src/main/res/drawable/lastpass.xml | 4 - app/src/main/res/drawable/lock_pattern.xml | 4 - app/src/main/res/drawable/navigate_next.xml | 3 - app/src/main/res/drawable/navigate_prev.xml | 6 - app/src/main/res/drawable/numeric.xml | 4 - app/src/main/res/drawable/pin_filled.xml | 5 - .../res/drawable/reader_item_boundary.xml | 10 - app/src/main/res/drawable/refresh.xml | 4 - app/src/main/res/drawable/swap_horizontal.xml | 4 - app/src/main/res/drawable/tag.xml | 4 - app/src/main/res/drawable/thumb.xml | 5 - .../main/res/drawable/thumb_horizontal.xml | 5 - app/src/main/res/drawable/thumbnail.webp | Bin 81790 -> 0 bytes app/src/main/res/drawable/translate.xml | 4 - .../main/res/layout/default_query_dialog.xml | 135 -------- .../layout/download_folder_name_dialog.xml | 59 ---- .../res/layout/download_location_dialog.xml | 25 -- .../res/layout/download_location_item.xml | 51 --- app/src/main/res/layout/lock_activity.xml | 97 ------ .../main/res/layout/numberpicker_dialog.xml | 53 --- .../main/res/layout/pattern_lock_fragment.xml | 37 --- app/src/main/res/layout/pin_lock_fragment.xml | 42 --- app/src/main/res/layout/proxy_dialog.xml | 123 ------- app/src/main/res/layout/settings_activity.xml | 27 -- app/src/main/res/menu/reader.xml | 36 -- app/src/main/res/values-ja/arrays.xml | 26 -- app/src/main/res/values-ko/arrays.xml | 26 -- app/src/main/res/values/arrays.xml | 97 ------ app/src/main/res/values/attrs.xml | 31 -- app/src/main/res/values/colors.xml | 13 - app/src/main/res/values/dimen.xml | 7 - app/src/main/res/values/ids.xml | 10 - app/src/main/res/values/styles.xml | 18 - app/src/main/res/xml/lock_preferences.xml | 26 -- .../res/xml/manage_favorites_preferences.xml | 30 -- .../res/xml/manage_storage_preferences.xml | 39 --- app/src/main/res/xml/root_preferences.xml | 124 ------- build.gradle | 39 --- build.gradle.kts | 10 + gradle.properties | 2 +- gradle/libs.versions.toml | 73 +++++ gradle/wrapper/gradle-wrapper.properties | 2 +- settings.gradle | 1 - settings.gradle.kts | 20 ++ 116 files changed, 290 insertions(+), 4582 deletions(-) delete mode 100644 app/build.gradle create mode 100644 app/build.gradle.kts delete mode 100644 app/src/main/java/xyz/quaver/pupil/receiver/UpdateBroadcastReceiver.kt delete mode 100644 app/src/main/java/xyz/quaver/pupil/ui/BaseActivity.kt delete mode 100644 app/src/main/java/xyz/quaver/pupil/ui/LockActivity.kt delete mode 100644 app/src/main/java/xyz/quaver/pupil/ui/SettingsActivity.kt delete mode 100644 app/src/main/java/xyz/quaver/pupil/ui/dialog/DefaultQueryDialog.kt delete mode 100644 app/src/main/java/xyz/quaver/pupil/ui/dialog/DownloadFolderNameDialogFragment.kt delete mode 100644 app/src/main/java/xyz/quaver/pupil/ui/dialog/DownloadLocationDialogFragment.kt delete mode 100644 app/src/main/java/xyz/quaver/pupil/ui/dialog/ProxyDialogFragment.kt delete mode 100644 app/src/main/java/xyz/quaver/pupil/ui/fragment/LockSettingsFragment.kt delete mode 100644 app/src/main/java/xyz/quaver/pupil/ui/fragment/ManageFavoritesFragment.kt delete mode 100644 app/src/main/java/xyz/quaver/pupil/ui/fragment/PINLockFragment.kt delete mode 100644 app/src/main/java/xyz/quaver/pupil/ui/fragment/PatternLockFragment.kt delete mode 100644 app/src/main/java/xyz/quaver/pupil/ui/fragment/SettingsFragment.kt delete mode 100644 app/src/main/java/xyz/quaver/pupil/ui/reader/ImageViewer.kt delete mode 100644 app/src/main/java/xyz/quaver/pupil/util/ItemClickSupport.kt delete mode 100644 app/src/main/java/xyz/quaver/pupil/util/Preferences.kt delete mode 100644 app/src/main/java/xyz/quaver/pupil/util/SavedSet.kt delete mode 100644 app/src/main/java/xyz/quaver/pupil/util/camera.kt delete mode 100644 app/src/main/java/xyz/quaver/pupil/util/file.kt delete mode 100644 app/src/main/java/xyz/quaver/pupil/util/lock.kt delete mode 100644 app/src/main/java/xyz/quaver/pupil/util/misc.kt delete mode 100644 app/src/main/java/xyz/quaver/pupil/util/proxy.kt delete mode 100644 app/src/main/java/xyz/quaver/pupil/util/translation.kt delete mode 100644 app/src/main/java/xyz/quaver/pupil/util/update.kt delete mode 100644 app/src/main/res/anim/shake.xml delete mode 100644 app/src/main/res/anim/shake_cycle.xml delete mode 100644 app/src/main/res/color/lock_fab.xml delete mode 100644 app/src/main/res/drawable-hdpi/ic_fullscreen.png delete mode 100644 app/src/main/res/drawable-hdpi/ic_notification.png delete mode 100644 app/src/main/res/drawable-mdpi/ic_fullscreen.png delete mode 100644 app/src/main/res/drawable-mdpi/ic_notification.png delete mode 100644 app/src/main/res/drawable-xhdpi/ic_fullscreen.png delete mode 100644 app/src/main/res/drawable-xhdpi/ic_notification.png delete mode 100644 app/src/main/res/drawable-xxhdpi/ic_fullscreen.png delete mode 100644 app/src/main/res/drawable-xxhdpi/ic_notification.png delete mode 100644 app/src/main/res/drawable-xxxhdpi/ic_notification.png delete mode 100644 app/src/main/res/drawable/account_group.xml delete mode 100644 app/src/main/res/drawable/account_star.xml delete mode 100644 app/src/main/res/drawable/avd_star.xml delete mode 100644 app/src/main/res/drawable/backspace_outline.xml delete mode 100644 app/src/main/res/drawable/book_open.xml delete mode 100644 app/src/main/res/drawable/brush.xml delete mode 100644 app/src/main/res/drawable/close.xml delete mode 100644 app/src/main/res/drawable/delete.xml delete mode 100644 app/src/main/res/drawable/dot.xml delete mode 100644 app/src/main/res/drawable/eye.xml delete mode 100644 app/src/main/res/drawable/eye_closed.xml delete mode 100644 app/src/main/res/drawable/eye_off.xml delete mode 100644 app/src/main/res/drawable/eye_off_white.xml delete mode 100644 app/src/main/res/drawable/eye_white.xml delete mode 100644 app/src/main/res/drawable/fingerprint.xml delete mode 100644 app/src/main/res/drawable/gender_female.xml delete mode 100644 app/src/main/res/drawable/gender_female_white.xml delete mode 100644 app/src/main/res/drawable/gender_male.xml delete mode 100644 app/src/main/res/drawable/gender_male_white.xml delete mode 100644 app/src/main/res/drawable/history.xml delete mode 100644 app/src/main/res/drawable/hitomi.png delete mode 100644 app/src/main/res/drawable/ic_download.xml delete mode 100644 app/src/main/res/drawable/ic_downloading.xml delete mode 100644 app/src/main/res/drawable/ic_star_empty.xml delete mode 100644 app/src/main/res/drawable/ic_star_filled.xml delete mode 100644 app/src/main/res/drawable/image_broken_variant.xml delete mode 100644 app/src/main/res/drawable/lastpass.xml delete mode 100644 app/src/main/res/drawable/lock_pattern.xml delete mode 100644 app/src/main/res/drawable/navigate_next.xml delete mode 100644 app/src/main/res/drawable/navigate_prev.xml delete mode 100644 app/src/main/res/drawable/numeric.xml delete mode 100644 app/src/main/res/drawable/pin_filled.xml delete mode 100644 app/src/main/res/drawable/reader_item_boundary.xml delete mode 100644 app/src/main/res/drawable/refresh.xml delete mode 100644 app/src/main/res/drawable/swap_horizontal.xml delete mode 100644 app/src/main/res/drawable/tag.xml delete mode 100644 app/src/main/res/drawable/thumb.xml delete mode 100644 app/src/main/res/drawable/thumb_horizontal.xml delete mode 100644 app/src/main/res/drawable/thumbnail.webp delete mode 100644 app/src/main/res/drawable/translate.xml delete mode 100644 app/src/main/res/layout/default_query_dialog.xml delete mode 100644 app/src/main/res/layout/download_folder_name_dialog.xml delete mode 100644 app/src/main/res/layout/download_location_dialog.xml delete mode 100644 app/src/main/res/layout/download_location_item.xml delete mode 100644 app/src/main/res/layout/lock_activity.xml delete mode 100644 app/src/main/res/layout/numberpicker_dialog.xml delete mode 100644 app/src/main/res/layout/pattern_lock_fragment.xml delete mode 100644 app/src/main/res/layout/pin_lock_fragment.xml delete mode 100644 app/src/main/res/layout/proxy_dialog.xml delete mode 100644 app/src/main/res/layout/settings_activity.xml delete mode 100644 app/src/main/res/menu/reader.xml delete mode 100644 app/src/main/res/values-ja/arrays.xml delete mode 100644 app/src/main/res/values-ko/arrays.xml delete mode 100644 app/src/main/res/values/arrays.xml delete mode 100644 app/src/main/res/values/attrs.xml delete mode 100644 app/src/main/res/values/colors.xml delete mode 100644 app/src/main/res/values/dimen.xml delete mode 100644 app/src/main/res/values/ids.xml delete mode 100644 app/src/main/res/values/styles.xml delete mode 100644 app/src/main/res/xml/lock_preferences.xml delete mode 100644 app/src/main/res/xml/manage_favorites_preferences.xml delete mode 100644 app/src/main/res/xml/manage_storage_preferences.xml delete mode 100644 app/src/main/res/xml/root_preferences.xml delete mode 100644 build.gradle create mode 100644 build.gradle.kts create mode 100644 gradle/libs.versions.toml delete mode 100644 settings.gradle create mode 100644 settings.gradle.kts diff --git a/app/build.gradle b/app/build.gradle deleted file mode 100644 index 07ff5e6b..00000000 --- a/app/build.gradle +++ /dev/null @@ -1,151 +0,0 @@ -apply plugin: "com.android.application" -apply plugin: "kotlin-android" -apply plugin: "kotlin-parcelize" -apply plugin: "kotlinx-serialization" -apply plugin: "com.google.android.gms.oss-licenses-plugin" -apply plugin: "com.google.devtools.ksp" -apply plugin: "com.google.dagger.hilt.android" - -if (file("google-services.json").exists()) { - logger.lifecycle("Firebase Enabled") - apply plugin: "com.google.gms.google-services" - apply plugin: "com.google.firebase.crashlytics" - apply plugin: "com.google.firebase.firebase-perf" -} else { - logger.lifecycle("Firebase Disabled") -} - -android { - namespace 'xyz.quaver.pupil' - defaultConfig { - applicationId "xyz.quaver.pupil" - minSdkVersion 21 - compileSdk 34 - targetSdkVersion 34 - versionCode 69 - versionName "6.0.0" - testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" - } - buildTypes { - debug { - minifyEnabled false - shrinkResources false - - debuggable true - applicationIdSuffix ".debug" - versionNameSuffix "-DEBUG" - - ext.enableCrashlytics = false - ext.alwaysUpdateBuildId = false - } - release { - minifyEnabled true - shrinkResources true - - proguardFiles getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro" - } - } - buildFeatures { - viewBinding true - compose true - buildConfig true - } - compileOptions { - coreLibraryDesugaringEnabled true - sourceCompatibility JavaVersion.VERSION_17 - targetCompatibility JavaVersion.VERSION_17 - } - kotlinOptions { - jvmTarget = "17" - } - composeOptions { - kotlinCompilerExtensionVersion = "1.5.9" - } -} - -dependencies { - coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.0.4' - - implementation fileTree(dir: "libs", include: ["*.jar", "*.aar"]) - implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8" - implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.8.0" - implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.3" - implementation "org.jetbrains.kotlinx:kotlinx-datetime:0.5.0" - - implementation "androidx.appcompat:appcompat:1.6.1" - implementation "androidx.activity:activity-ktx:1.8.2" - implementation "androidx.fragment:fragment-ktx:1.6.2" - implementation "androidx.preference:preference-ktx:1.2.1" - implementation "androidx.recyclerview:recyclerview:1.3.2" - implementation "androidx.constraintlayout:constraintlayout:2.1.4" - implementation "androidx.gridlayout:gridlayout:1.0.0" - implementation "androidx.biometric:biometric:1.1.0" - implementation "androidx.work:work-runtime-ktx:2.9.0" - - implementation platform("androidx.compose:compose-bom:2024.03.00") - - implementation "androidx.compose.material3:material3" - implementation "androidx.compose.material3:material3-window-size-class" - implementation 'androidx.compose.foundation:foundation' - implementation 'androidx.compose.ui:ui' - implementation 'androidx.compose.ui:ui-tooling-preview' - debugImplementation 'androidx.compose.ui:ui-tooling' - androidTestImplementation 'androidx.compose.ui:ui-test-junit4:1.6.4' - debugImplementation 'androidx.compose.ui:ui-test-manifest' - implementation 'androidx.compose.material:material-icons-extended' - implementation 'androidx.activity:activity-compose:1.8.2' - implementation 'androidx.lifecycle:lifecycle-viewmodel-compose:2.7.0' - implementation 'androidx.lifecycle:lifecycle-runtime-compose:2.7.0' - implementation "com.google.accompanist:accompanist-adaptive:0.34.0" - implementation "androidx.navigation:navigation-compose:2.7.7" - - ksp 'androidx.lifecycle:lifecycle-compiler:2.7.0' - - def room_version = "2.6.1" - - implementation "androidx.room:room-runtime:$room_version" - annotationProcessor "androidx.room:room-compiler:$room_version" - ksp "androidx.room:room-compiler:$room_version" - - implementation "io.ktor:ktor-client-core:2.3.8" - implementation "io.ktor:ktor-client-okhttp:2.3.8" - - implementation "io.coil-kt:coil-compose:2.6.0" - - implementation "com.google.dagger:hilt-android:2.44" - ksp "com.google.dagger:hilt-compiler:2.44" - - implementation "com.google.android.material:material:1.11.0" - - implementation platform('com.google.firebase:firebase-bom:32.8.0') - implementation "com.google.firebase:firebase-analytics-ktx" - implementation "com.google.firebase:firebase-crashlytics-ktx" - implementation "com.google.firebase:firebase-perf-ktx" - - implementation "com.google.android.gms:play-services-oss-licenses:17.0.1" - implementation "com.google.android.gms:play-services-mlkit-face-detection:17.1.0" - - implementation "com.github.clans:fab:1.6.4" - - implementation 'com.github.piasy:BigImageViewer:1.8.1' - implementation 'com.github.piasy:FrescoImageLoader:1.8.1' - implementation 'com.github.piasy:FrescoImageViewFactory:1.8.1' - implementation 'com.facebook.fresco:imagepipeline-okhttp3:3.1.3' - - //noinspection GradleDependency - implementation "com.squareup.okhttp3:okhttp:4.12.0" - - implementation "com.andrognito.patternlockview:patternlockview:1.0.0" - - implementation "ru.noties.markwon:core:3.1.0" - - implementation "xyz.quaver:documentfilex:0.7.2" - implementation "xyz.quaver:floatingsearchview:1.1.7" - - testImplementation "junit:junit:4.13.2" - testImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:1.8.0" - androidTestImplementation "androidx.test.ext:junit:1.1.5" - androidTestImplementation "androidx.test:rules:1.5.0" - androidTestImplementation "androidx.test:runner:1.5.2" - androidTestImplementation "androidx.test.espresso:espresso-core:3.5.1" -} \ No newline at end of file diff --git a/app/build.gradle.kts b/app/build.gradle.kts new file mode 100644 index 00000000..a7721cc2 --- /dev/null +++ b/app/build.gradle.kts @@ -0,0 +1,165 @@ +import org.jetbrains.kotlin.ir.util.toIrConst + +plugins { + alias(libs.plugins.org.jetbrains.kotlin.android) + alias(libs.plugins.android.application) + alias(libs.plugins.compose.compiler) + alias(libs.plugins.googleServices) + alias(libs.plugins.ksp) + alias(libs.plugins.hilt) + alias(libs.plugins.kotlinx.serialization) + alias(libs.plugins.crashlytics) +} + +android { + namespace = "xyz.quaver.pupil" + defaultConfig { + applicationId = "xyz.quaver.pupil" + minSdk = libs.versions.android.minSdk.get().toInt() + compileSdk = libs.versions.android.compileSdk.get().toInt() + targetSdk = libs.versions.android.targetSdk.get().toInt() + versionCode = 69 + versionName = "6.0.0" + testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" + } + buildTypes { + getByName("debug") { + isMinifyEnabled = false + isShrinkResources = false + isDebuggable = true + applicationIdSuffix = ".debug" + versionNameSuffix = "-DEBUG" + ext.set("enableCrashlytics", false) + ext.set("alwaysUpdateBuildId", false) + } + getByName("release") { + isMinifyEnabled = true + isShrinkResources = true + proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro") + } + } + buildFeatures { + compose = true + } + compileOptions { + isCoreLibraryDesugaringEnabled = true + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 + } +} + +dependencies { + coreLibraryDesugaring(libs.android.desugaring) + + implementation(libs.kotlinx.serialization) + implementation(libs.kotlinx.coroutines) + implementation(libs.kotlinx.datetime) + + implementation(libs.androidx.core) + implementation(libs.androidx.activity) + implementation(libs.androidx.activity.compose) + implementation(libs.androidx.lifecycle.runtime.compose) + implementation(libs.androidx.navigation.compose) + + implementation(platform(libs.androidx.compose.bom)) + implementation(libs.androidx.compose.material3) + implementation(libs.androidx.compose.material3.windowSizeClass) + implementation(libs.androidx.compose.foundation) + debugImplementation(libs.androidx.compose.ui.tooling) + implementation(libs.androidx.compose.ui.tooling.preview) + implementation(libs.androidx.compose.material.icons.extended) + + implementation(libs.accompanist.adaptive) + + implementation(libs.coil) + + implementation(platform(libs.firebase.bom)) + implementation(libs.firebase.analytics) + implementation(libs.firebase.crashlytics) + implementation(libs.firebase.perf) + + implementation(libs.hilt.android) + ksp(libs.hilt.compiler) + + implementation(libs.ktor.client) + implementation(libs.ktor.client.okhttp) + + implementation(libs.documentFileX) +} + +//dependencies { +// implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8" +// implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.8.0" +// implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.3" +// implementation "org.jetbrains.kotlinx:kotlinx-datetime:0.5.0" +// +// implementation "androidx.appcompat:appcompat:1.7.0" +// implementation "androidx.activity:activity-ktx:1.9.0" +// implementation "androidx.fragment:fragment-ktx:1.8.1" +// implementation "androidx.preference:preference-ktx:1.2.1" +// implementation "androidx.recyclerview:recyclerview:1.3.2" +// implementation "androidx.constraintlayout:constraintlayout:2.1.4" +// implementation "androidx.gridlayout:gridlayout:1.0.0" +// implementation "androidx.biometric:biometric:1.1.0" +// implementation "androidx.work:work-runtime-ktx:2.9.0" +// +// implementation platform("androidx.compose:compose-bom:2024.06.00") +// +// implementation "androidx.compose.material3:material3" +// implementation "androidx.compose.material3:material3-window-size-class" +// implementation 'androidx.compose.foundation:foundation' +// implementation 'androidx.compose.ui:ui' +// implementation 'androidx.compose.ui:ui-tooling-preview' +// debugImplementation 'androidx.compose.ui:ui-tooling' +// androidTestImplementation 'androidx.compose.ui:ui-test-junit4:1.6.8' +// debugImplementation 'androidx.compose.ui:ui-test-manifest' +// implementation 'androidx.compose.material:material-icons-extended' +// implementation 'androidx.activity:activity-compose:1.9.0' +// implementation 'androidx.lifecycle:lifecycle-viewmodel-compose:2.8.2' +// implementation 'androidx.lifecycle:lifecycle-runtime-compose:2.8.2' +// implementation "com.google.accompanist:accompanist-adaptive:0.34.0" +// implementation "androidx.navigation:navigation-compose:2.7.7" +// +// ksp 'androidx.lifecycle:lifecycle-compiler:2.8.2' +// +// def room_version = "2.6.1" +// +// implementation "androidx.room:room-runtime:$room_version" +// annotationProcessor "androidx.room:room-compiler:$room_version" +// ksp "androidx.room:room-compiler:$room_version" +// +// implementation "io.ktor:ktor-client-core:2.3.8" +// implementation "io.ktor:ktor-client-okhttp:2.3.8" +// +// implementation "io.coil-kt:coil-compose:2.6.0" +// +// implementation "com.google.dagger:hilt-android:2.51.1" +// ksp "com.google.dagger:hilt-compiler:2.51.1" +// +// implementation "com.google.android.material:material:1.12.0" +// +// implementation platform('com.google.firebase:firebase-bom:33.1.1') +// implementation "com.google.firebase:firebase-analytics-ktx" +// implementation "com.google.firebase:firebase-crashlytics-ktx" +// implementation "com.google.firebase:firebase-perf-ktx" +// +// implementation "com.google.android.gms:play-services-oss-licenses:17.1.0" +// implementation "com.google.android.gms:play-services-mlkit-face-detection:17.1.0" +// +// implementation "com.github.clans:fab:1.6.4" +// +// //noinspection GradleDependency +// implementation "com.squareup.okhttp3:okhttp:4.12.0" +// +// implementation "ru.noties.markwon:core:3.1.0" +// +// implementation "xyz.quaver:documentfilex:0.7.2" +// implementation "xyz.quaver:floatingsearchview:1.1.7" +// +// testImplementation "junit:junit:4.13.2" +// testImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:1.8.0" +// androidTestImplementation "androidx.test.ext:junit:1.2.1" +// androidTestImplementation "androidx.test:rules:1.6.1" +// androidTestImplementation "androidx.test:runner:1.6.1" +// androidTestImplementation "androidx.test.espresso:espresso-core:3.6.1" +//} \ No newline at end of file diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro index d2a01ae9..97f980cd 100644 --- a/app/proguard-rules.pro +++ b/app/proguard-rules.pro @@ -1,6 +1,6 @@ # Add project specific ProGuard rules here. # You can control the set of applied configuration files using the -# proguardFiles setting in build.gradle. +# proguardFiles setting in build.gradle.kts. # # For more details, see # http://developer.android.com/guide/developing/tools/proguard.html diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index d54999b4..eea9b391 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -1,7 +1,6 @@ + xmlns:tools="http://schemas.android.com/tools" > @@ -25,11 +24,8 @@ android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" - android:theme="@style/AppTheme" android:networkSecurityConfig="@xml/network_security_config" - tools:replace="android:theme" - tools:ignore="UnusedAttribute" - android:dataExtractionRules="@xml/data_extraction_rules"> + tools:ignore="UnusedAttribute" > - - - - - - - - - diff --git a/app/src/main/java/xyz/quaver/pupil/Pupil.kt b/app/src/main/java/xyz/quaver/pupil/Pupil.kt index 8a764239..c9e8c12f 100644 --- a/app/src/main/java/xyz/quaver/pupil/Pupil.kt +++ b/app/src/main/java/xyz/quaver/pupil/Pupil.kt @@ -26,118 +26,16 @@ import android.content.Context import android.content.Intent import android.net.Uri import android.os.Build -import android.util.Log -import androidx.appcompat.app.AppCompatDelegate -import androidx.core.content.ContextCompat -import androidx.preference.PreferenceManager -import coil.ImageLoader -import coil.ImageLoaderFactory -import com.facebook.imagepipeline.backends.okhttp3.OkHttpImagePipelineConfigFactory -import com.github.piasy.biv.BigImageViewer -import com.github.piasy.biv.loader.fresco.FrescoImageLoader -import com.google.android.gms.common.GooglePlayServicesNotAvailableException -import com.google.android.gms.common.GooglePlayServicesRepairableException -import com.google.android.gms.security.ProviderInstaller import com.google.firebase.FirebaseApp import com.google.firebase.crashlytics.FirebaseCrashlytics import dagger.hilt.android.HiltAndroidApp -import kotlinx.coroutines.* -import okhttp3.Dispatcher -import okhttp3.Interceptor -import okhttp3.OkHttpClient -import okhttp3.Response import xyz.quaver.io.FileX -import xyz.quaver.pupil.networking.SSLSettings -import xyz.quaver.pupil.types.Tag -import xyz.quaver.pupil.util.* -import java.io.File -import java.net.URL -import java.util.* -import java.util.concurrent.Executors -import java.util.concurrent.TimeUnit -import kotlin.reflect.KClass - -typealias PupilInterceptor = (Interceptor.Chain) -> Response - -val interceptors = mutableMapOf, PupilInterceptor>() - -lateinit var clientBuilder: OkHttpClient.Builder - -var clientHolder: OkHttpClient? = null -val client: OkHttpClient - get() = clientHolder ?: clientBuilder.build().also { - clientHolder = it - } +import java.util.UUID @HiltAndroidApp class Pupil : Application() { override fun onCreate() { - preferences = PreferenceManager.getDefaultSharedPreferences(this) - - val userID = Preferences["user_id", ""].let { userID -> - userID.ifEmpty { UUID.randomUUID().toString().also { Preferences["user_id"] = it } } - } - FirebaseApp.initializeApp(this) - FirebaseCrashlytics.getInstance().setUserId(userID) - - val proxyInfo = getProxyInfo() - - clientBuilder = OkHttpClient.Builder() - .readTimeout(0, TimeUnit.SECONDS) - .proxyInfo(proxyInfo) - .addInterceptor { chain -> - val request = chain.request().newBuilder() - .addHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.81 Safari/537.36") - .header("Referer", "https://hitomi.la/") - .build() - - val tag = request.tag() ?: return@addInterceptor chain.proceed(request) - - interceptors[tag::class]?.invoke(chain) ?: chain.proceed(request) - }.apply { - (Preferences.get("max_concurrent_download").toIntOrNull() ?: 0).let { - if (it != 0) - dispatcher(Dispatcher(Executors.newFixedThreadPool(it))) - } - } - - try { - Preferences.get("download_folder").also { - if (it.startsWith("content://")) - contentResolver.takePersistableUriPermission( - Uri.parse(it), - Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION - ) - - if (!FileX(this, it).canWrite()) - throw Exception() - } - } catch (e: Exception) { - Preferences.remove("download_folder") - } - - if (!Preferences["reset_secure", false]) { - Preferences["security_mode"] = false - Preferences["reset_secure"] = true - } - - try { - ProviderInstaller.installIfNeeded(this) - } catch (e: GooglePlayServicesRepairableException) { - e.printStackTrace() - } catch (e: GooglePlayServicesNotAvailableException) { - e.printStackTrace() - } - - BigImageViewer.initialize( - FrescoImageLoader.with( - this, - OkHttpImagePipelineConfigFactory - .newBuilder(this, client) - .build() - ) - ) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { val manager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager @@ -171,11 +69,6 @@ class Pupil : Application() { }) } - AppCompatDelegate.setDefaultNightMode(when (Preferences.get("dark_mode")) { - true -> AppCompatDelegate.MODE_NIGHT_YES - false -> AppCompatDelegate.MODE_NIGHT_NO - }) - super.onCreate() } } \ No newline at end of file diff --git a/app/src/main/java/xyz/quaver/pupil/di/SingletonModule.kt b/app/src/main/java/xyz/quaver/pupil/di/SingletonModule.kt index 86284f5c..a4d4607b 100644 --- a/app/src/main/java/xyz/quaver/pupil/di/SingletonModule.kt +++ b/app/src/main/java/xyz/quaver/pupil/di/SingletonModule.kt @@ -1,8 +1,8 @@ package xyz.quaver.pupil.di import android.content.Context -import com.google.android.datatransport.runtime.dagger.Provides import dagger.Module +import dagger.Provides import dagger.hilt.InstallIn import dagger.hilt.android.qualifiers.ApplicationContext import dagger.hilt.components.SingletonComponent diff --git a/app/src/main/java/xyz/quaver/pupil/networking/HitomiHttpClient.kt b/app/src/main/java/xyz/quaver/pupil/networking/HitomiHttpClient.kt index 835dad68..7e578730 100644 --- a/app/src/main/java/xyz/quaver/pupil/networking/HitomiHttpClient.kt +++ b/app/src/main/java/xyz/quaver/pupil/networking/HitomiHttpClient.kt @@ -17,6 +17,7 @@ import kotlinx.coroutines.sync.withLock import kotlinx.coroutines.withContext import kotlinx.datetime.Clock.System.now import kotlinx.datetime.Instant +import kotlinx.serialization.decodeFromString import kotlinx.serialization.json.Json import java.nio.ByteBuffer import java.nio.ByteOrder diff --git a/app/src/main/java/xyz/quaver/pupil/receiver/UpdateBroadcastReceiver.kt b/app/src/main/java/xyz/quaver/pupil/receiver/UpdateBroadcastReceiver.kt deleted file mode 100644 index 95a7dde4..00000000 --- a/app/src/main/java/xyz/quaver/pupil/receiver/UpdateBroadcastReceiver.kt +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Pupil, Hitomi.la viewer for Android - * Copyright (C) 2020 tom5079 - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package xyz.quaver.pupil.receiver - -import android.app.DownloadManager -import android.app.PendingIntent -import android.content.BroadcastReceiver -import android.content.Context -import android.content.Intent -import android.net.Uri -import android.os.Build -import android.webkit.MimeTypeMap -import androidx.core.app.NotificationCompat -import androidx.core.app.NotificationManagerCompat -import androidx.core.content.FileProvider -import xyz.quaver.pupil.R -import xyz.quaver.pupil.util.Preferences -import java.io.File - -class UpdateBroadcastReceiver : BroadcastReceiver() { - - override fun onReceive(context: Context?, intent: Intent?) { - context ?: return - - when (intent?.action) { - DownloadManager.ACTION_DOWNLOAD_COMPLETE -> { - - // Validate download - val downloadID: Long = Preferences["update_download_id"] - val downloadManager = context.getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager - - if (intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -2) != downloadID) - return - - // Get target uri - - val query = DownloadManager.Query() - .setFilterById(downloadID) - - val uri = downloadManager.query(query).use { cursor -> - if (cursor.moveToFirst()) { - cursor.getString(cursor.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI))?.let { - val uri = Uri.parse(it) - - when (uri.scheme) { - "file" -> - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) - FileProvider.getUriForFile(context, context.applicationContext.packageName + ".provider", File(uri.path!!)) - else - uri - "content" -> uri - else -> null - } - } - } else - null - } ?: return - - // Build Notification - - val notificationManager = NotificationManagerCompat.from(context) - - val pendingIntent = PendingIntent.getActivity(context, System.currentTimeMillis().toInt(), Intent(Intent.ACTION_VIEW).apply { - flags = Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_ACTIVITY_NEW_TASK - setDataAndType(uri, MimeTypeMap.getSingleton().getMimeTypeFromExtension("apk")) - }, if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) PendingIntent.FLAG_IMMUTABLE else 0) - - val notification = NotificationCompat.Builder(context, "update") - .setSmallIcon(android.R.drawable.stat_sys_download_done) - .setContentTitle(context.getText(R.string.update_download_completed)) - .setContentText(context.getText(R.string.update_download_completed_description)) - .setContentIntent(pendingIntent) - .build() - - notificationManager.notify(R.id.notification_id_update, notification) - } - } - } - -} \ No newline at end of file diff --git a/app/src/main/java/xyz/quaver/pupil/ui/BaseActivity.kt b/app/src/main/java/xyz/quaver/pupil/ui/BaseActivity.kt deleted file mode 100644 index 96d8b3b3..00000000 --- a/app/src/main/java/xyz/quaver/pupil/ui/BaseActivity.kt +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Pupil, Hitomi.la viewer for Android - * Copyright (C) 2020 tom5079 - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package xyz.quaver.pupil.ui - -import android.app.Activity -import android.content.Intent -import android.os.Bundle -import android.os.PersistableBundle -import android.view.WindowManager -import androidx.activity.result.contract.ActivityResultContracts -import androidx.annotation.CallSuper -import androidx.appcompat.app.AppCompatActivity -import xyz.quaver.pupil.R -import xyz.quaver.pupil.util.LockManager -import xyz.quaver.pupil.util.Preferences -import xyz.quaver.pupil.util.normalizeID - -open class BaseActivity : AppCompatActivity() { - - private var locked: Boolean = true - - private val lockLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { - if (it.resultCode == Activity.RESULT_OK) - locked = false - else - finish() - } - - @CallSuper - override fun onCreate(savedInstanceState: Bundle?, persistentState: PersistableBundle?) { - super.onCreate(savedInstanceState, persistentState) - - locked = !LockManager(this).locks.isNullOrEmpty() - } - - @CallSuper - override fun onResume() { - super.onResume() - - if (Preferences["security_mode"]) - window.setFlags( - WindowManager.LayoutParams.FLAG_SECURE, - WindowManager.LayoutParams.FLAG_SECURE) - else - window.clearFlags(WindowManager.LayoutParams.FLAG_SECURE) - - if (locked) - lockLauncher.launch(Intent(this, LockActivity::class.java)) - } - -} \ No newline at end of file diff --git a/app/src/main/java/xyz/quaver/pupil/ui/LockActivity.kt b/app/src/main/java/xyz/quaver/pupil/ui/LockActivity.kt deleted file mode 100644 index 33e678f6..00000000 --- a/app/src/main/java/xyz/quaver/pupil/ui/LockActivity.kt +++ /dev/null @@ -1,280 +0,0 @@ -/* - * Pupil, Hitomi.la viewer for Android - * Copyright (C) 2019 tom5079 - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package xyz.quaver.pupil.ui - -import android.app.Activity -import android.app.AlertDialog -import android.os.Bundle -import android.view.animation.Animation -import android.view.animation.AnimationUtils -import androidx.appcompat.app.AppCompatActivity -import androidx.biometric.BiometricManager -import androidx.biometric.BiometricPrompt -import androidx.core.content.ContextCompat -import com.andrognito.patternlockview.PatternLockView -import com.google.android.material.snackbar.Snackbar -import xyz.quaver.pupil.R -import xyz.quaver.pupil.databinding.LockActivityBinding -import xyz.quaver.pupil.ui.fragment.PINLockFragment -import xyz.quaver.pupil.ui.fragment.PatternLockFragment -import xyz.quaver.pupil.util.Lock -import xyz.quaver.pupil.util.LockManager -import xyz.quaver.pupil.util.Preferences - -private var lastUnlocked = 0L -class LockActivity : AppCompatActivity() { - - private lateinit var lockManager: LockManager - private var mode: String? = null - - private lateinit var binding: LockActivityBinding - - private val patternLockFragment = PatternLockFragment().apply { - var lastPass = "" - onPatternDrawn = { - when(mode) { - null -> { - val result = lockManager.check(it) - - if (result == true) { - lastUnlocked = System.currentTimeMillis() - setResult(Activity.RESULT_OK) - finish() - } else - binding.patternLockView.setViewMode(PatternLockView.PatternViewMode.WRONG) - } - "add_lock" -> { - if (lastPass.isEmpty()) { - lastPass = it - - Snackbar.make(view!!, R.string.settings_lock_confirm, Snackbar.LENGTH_LONG).show() - } else { - if (lastPass == it) { - LockManager(context!!).add(Lock.generate(Lock.Type.PATTERN, it)) - finish() - } else { - binding.patternLockView.setViewMode(PatternLockView.PatternViewMode.WRONG) - lastPass = "" - - Snackbar.make(view!!, R.string.settings_lock_wrong_confirm, Snackbar.LENGTH_LONG).show() - } - } - } - } - } - } - - private val pinLockFragment = PINLockFragment().apply { - var lastPass = "" - onPINEntered = { - when(mode) { - null -> { - val result = lockManager.check(it) - - if (result == true) { - lastUnlocked = System.currentTimeMillis() - setResult(Activity.RESULT_OK) - finish() - } else { - binding.indicatorDots.startAnimation(AnimationUtils.loadAnimation(context, R.anim.shake).apply { - setAnimationListener(object: Animation.AnimationListener { - override fun onAnimationEnd(animation: Animation?) { - binding.pinLockView.resetPinLockView() - binding.pinLockView.isEnabled = true - } - - override fun onAnimationStart(animation: Animation?) { - binding.pinLockView.isEnabled = false - } - - override fun onAnimationRepeat(animation: Animation?) { - // Do Nothing - } - }) - }) - } - } - "add_lock" -> { - if (lastPass.isEmpty()) { - lastPass = it - - binding.pinLockView.resetPinLockView() - Snackbar.make(view!!, R.string.settings_lock_confirm, Snackbar.LENGTH_LONG).show() - } else { - if (lastPass == it) { - LockManager(context!!).add(Lock.generate(Lock.Type.PIN, it)) - finish() - } else { - binding.indicatorDots.startAnimation(AnimationUtils.loadAnimation(context, R.anim.shake).apply { - setAnimationListener(object: Animation.AnimationListener { - override fun onAnimationEnd(animation: Animation?) { - binding.pinLockView.resetPinLockView() - binding.pinLockView.isEnabled = true - } - - override fun onAnimationStart(animation: Animation?) { - binding.pinLockView.isEnabled = false - } - - override fun onAnimationRepeat(animation: Animation?) { - // Do Nothing - } - }) - }) - lastPass = "" - - Snackbar.make(view!!, R.string.settings_lock_wrong_confirm, Snackbar.LENGTH_LONG).show() - } - } - } - } - } - } - - private fun showBiometricPrompt() { - val promptInfo = BiometricPrompt.PromptInfo.Builder() - .setTitle(getText(R.string.settings_lock_fingerprint_prompt)) - .setSubtitle(getText(R.string.settings_lock_fingerprint_prompt_subtitle)) - .setNegativeButtonText(getText(android.R.string.cancel)) - .setConfirmationRequired(false) - .build() - - val biometricPrompt = BiometricPrompt(this, ContextCompat.getMainExecutor(this), - object : BiometricPrompt.AuthenticationCallback() { - override fun onAuthenticationSucceeded( - result: BiometricPrompt.AuthenticationResult) { - super.onAuthenticationSucceeded(result) - lastUnlocked = System.currentTimeMillis() - setResult(RESULT_OK) - finish() - return - } - }) - - // Displays the "log in" prompt. - biometricPrompt.authenticate(promptInfo) - } - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - binding = LockActivityBinding.inflate(layoutInflater) - setContentView(binding.root) - - lockManager = try { - LockManager(this) - } catch (e: Exception) { - AlertDialog.Builder(this).apply { - setTitle(R.string.warning) - setMessage(R.string.lock_corrupted) - setPositiveButton(android.R.string.ok) { _, _ -> - finish() - } - }.show() - return - } - - mode = intent.getStringExtra("mode") - val force = intent.getBooleanExtra("force", false) - - when(mode) { - null -> { - if (lockManager.isEmpty()) { - setResult(RESULT_OK) - finish() - return - } - - if (System.currentTimeMillis() - lastUnlocked < 5*60*1000 && !force) { - lastUnlocked = System.currentTimeMillis() - setResult(RESULT_OK) - finish() - return - } - - if ( - Preferences["lock_fingerprint"] - && BiometricManager.from(this).canAuthenticate() == BiometricManager.BIOMETRIC_SUCCESS - ) { - binding.fingerprintBtn.apply { - isEnabled = true - setOnClickListener { - showBiometricPrompt() - } - } - showBiometricPrompt() - } - - binding.patternBtn.apply { - isEnabled = lockManager.contains(Lock.Type.PATTERN) - setOnClickListener { - supportFragmentManager.beginTransaction().replace( - R.id.lock_content, patternLockFragment - ).commit() - } - } - binding.pinBtn.apply { - isEnabled = lockManager.contains(Lock.Type.PIN) - setOnClickListener { - supportFragmentManager.beginTransaction().replace( - R.id.lock_content, pinLockFragment - ).commit() - } - } - binding.passwordBtn.isEnabled = false - - when (lockManager.locks!!.first().type) { - Lock.Type.PIN -> { - - supportFragmentManager.beginTransaction().add( - R.id.lock_content, pinLockFragment - ).commit() - } - Lock.Type.PATTERN -> { - supportFragmentManager.beginTransaction().add( - R.id.lock_content, patternLockFragment - ).commit() - } - else -> return - } - } - "add_lock" -> { - binding.patternBtn.isEnabled = false - binding.pinBtn.isEnabled = false - binding.fingerprintBtn.isEnabled = false - binding.passwordBtn.isEnabled = false - - when(intent.getStringExtra("type")!!) { - "pattern" -> { - binding.patternBtn.isEnabled = true - supportFragmentManager.beginTransaction().add( - R.id.lock_content, patternLockFragment - ).commit() - } - "pin" -> { - binding.pinBtn.isEnabled = true - supportFragmentManager.beginTransaction().add( - R.id.lock_content, pinLockFragment - ).commit() - } - } - } - } - } - -} diff --git a/app/src/main/java/xyz/quaver/pupil/ui/MainActivity.kt b/app/src/main/java/xyz/quaver/pupil/ui/MainActivity.kt index 7e32a32c..aaf83795 100644 --- a/app/src/main/java/xyz/quaver/pupil/ui/MainActivity.kt +++ b/app/src/main/java/xyz/quaver/pupil/ui/MainActivity.kt @@ -19,6 +19,7 @@ package xyz.quaver.pupil.ui import android.os.Bundle +import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.activity.enableEdgeToEdge import androidx.activity.viewModels @@ -33,7 +34,7 @@ import xyz.quaver.pupil.ui.composable.MainApp import xyz.quaver.pupil.ui.theme.AppTheme import xyz.quaver.pupil.ui.viewmodel.MainViewModel -class MainActivity : BaseActivity() { +class MainActivity : ComponentActivity() { @OptIn(ExperimentalMaterial3WindowSizeClassApi::class) override fun onCreate(savedInstanceState: Bundle?) { enableEdgeToEdge() diff --git a/app/src/main/java/xyz/quaver/pupil/ui/SettingsActivity.kt b/app/src/main/java/xyz/quaver/pupil/ui/SettingsActivity.kt deleted file mode 100644 index 38685e4f..00000000 --- a/app/src/main/java/xyz/quaver/pupil/ui/SettingsActivity.kt +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Pupil, Hitomi.la viewer for Android - * Copyright (C) 2019 tom5079 - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package xyz.quaver.pupil.ui - -import android.os.Bundle -import android.view.MenuItem -import xyz.quaver.pupil.R -import xyz.quaver.pupil.ui.fragment.SettingsFragment - -class SettingsActivity : BaseActivity() { - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - setContentView(R.layout.settings_activity) - supportFragmentManager - .beginTransaction() - .replace(R.id.settings, SettingsFragment()) - .commit() - supportActionBar?.setDisplayHomeAsUpEnabled(true) - } - - override fun onOptionsItemSelected(item: MenuItem): Boolean { - when (item.itemId) { - android.R.id.home -> onBackPressed() - } - - return true - } -} \ No newline at end of file diff --git a/app/src/main/java/xyz/quaver/pupil/ui/composable/Gallery.kt b/app/src/main/java/xyz/quaver/pupil/ui/composable/Gallery.kt index 51bb3886..a2a811c1 100644 --- a/app/src/main/java/xyz/quaver/pupil/ui/composable/Gallery.kt +++ b/app/src/main/java/xyz/quaver/pupil/ui/composable/Gallery.kt @@ -21,6 +21,7 @@ import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.text.InlineTextContent import androidx.compose.foundation.text.appendInlineContent import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.BrokenImage import androidx.compose.material.icons.filled.QuestionMark import androidx.compose.material.icons.filled.StarOutline import androidx.compose.material3.Card @@ -352,9 +353,9 @@ fun DetailedGalleryInfoHeader(galleryInfo: GalleryInfo, thumbnailUrl: String?) { .clip(RoundedCornerShape(8.dp)), loading = { CircularProgressIndicator(Modifier.align(Alignment.Center)) }, error = { - Image( - painter = painterResource(R.drawable.thumbnail), - contentDescription = null + Icon( + Icons.Default.BrokenImage, + contentDescription = null, ) }, contentDescription = "Thumbnail" @@ -408,9 +409,9 @@ fun DetailedGalleryInfoHeader(galleryInfo: GalleryInfo, thumbnailUrl: String?) { .clip(RoundedCornerShape(8.dp)), loading = { CircularProgressIndicator(Modifier.align(Alignment.Center)) }, error = { - Image( - painter = painterResource(R.drawable.thumbnail), - contentDescription = null + Icon( + Icons.Default.BrokenImage, + contentDescription = null, ) }, contentDescription = "Thumbnail" diff --git a/app/src/main/java/xyz/quaver/pupil/ui/composable/MainApp.kt b/app/src/main/java/xyz/quaver/pupil/ui/composable/MainApp.kt index 0878b345..00eba225 100644 --- a/app/src/main/java/xyz/quaver/pupil/ui/composable/MainApp.kt +++ b/app/src/main/java/xyz/quaver/pupil/ui/composable/MainApp.kt @@ -40,7 +40,6 @@ import kotlinx.coroutines.launch import xyz.quaver.pupil.R import xyz.quaver.pupil.networking.GalleryInfo import xyz.quaver.pupil.networking.SearchQuery -import xyz.quaver.pupil.ui.SettingsActivity import xyz.quaver.pupil.ui.viewmodel.SearchState @Composable @@ -286,11 +285,11 @@ fun MainContent( composable(MainDestination.Favorites.route) { NotImplemented() } - activity(MainDestination.Settings.route) { - activityClass = SettingsActivity::class + composable(MainDestination.Settings.route) { + NotImplemented() } - activity(MainDestination.ImageViewer.commonRoute) { -// argument("galleryID") { type = NavType.IntType } + composable(MainDestination.ImageViewer.commonRoute) { + NotImplemented() } } } diff --git a/app/src/main/java/xyz/quaver/pupil/ui/dialog/DefaultQueryDialog.kt b/app/src/main/java/xyz/quaver/pupil/ui/dialog/DefaultQueryDialog.kt deleted file mode 100644 index c0883922..00000000 --- a/app/src/main/java/xyz/quaver/pupil/ui/dialog/DefaultQueryDialog.kt +++ /dev/null @@ -1,171 +0,0 @@ -/* - * Pupil, Hitomi.la viewer for Android - * Copyright (C) 2020 tom5079 - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package xyz.quaver.pupil.ui.dialog - -import android.app.Dialog -import android.os.Bundle -import android.text.Editable -import android.text.TextWatcher -import android.widget.ArrayAdapter -import androidx.appcompat.app.AlertDialog -import androidx.fragment.app.DialogFragment -import xyz.quaver.pupil.R -import xyz.quaver.pupil.databinding.DefaultQueryDialogBinding -import xyz.quaver.pupil.types.Tags -import xyz.quaver.pupil.util.Preferences - -class DefaultQueryDialog : DialogFragment() { - - private val languages: Map by lazy { - requireContext().resources.getStringArray(R.array.languages).map { - it.split("|").let { split -> - Pair(split[0], split[1]) - } - }.toMap() - } - private val reverseLanguages: Map by lazy { - languages.entries.associate { (k, v) -> v to k } - } - - private val excludeBL = "-male:yaoi" - private val excludeGuro = listOf("-female:guro", "-male:guro") - private val excludeLoli = listOf("-female:loli", "-male:shota") - - var onPositiveButtonClickListener : ((Tags) -> (Unit))? = null - - private var _binding: DefaultQueryDialogBinding? = null - private val binding get() = _binding!! - - private fun initView() { - val tags = Tags.parse( - Preferences["default_query"] - ) - - with(binding.languageSelector) { - adapter = - ArrayAdapter( - context, - android.R.layout.simple_spinner_dropdown_item, - arrayListOf( - context.getString(R.string.default_query_dialog_language_selector_none) - ).apply { - addAll(languages.values) - } - ) - if (tags.any { it.area == "language" && !it.isNegative }) { - val tag = languages[tags.first { it.area == "language" }.tag] - if (tag != null) { - setSelection( - @Suppress("UNCHECKED_CAST") - (adapter as ArrayAdapter).getPosition(tag) - ) - tags.removeByArea("language", false) - } - } - } - - with(binding.BLCheckbox) { - isChecked = tags.contains(excludeBL) - if (tags.contains(excludeBL)) - tags.remove(excludeBL) - } - - with(binding.guroCheckbox) { - isChecked = excludeGuro.all { tags.contains(it) } - if (excludeGuro.all { tags.contains(it) }) - excludeGuro.forEach { - tags.remove(it) - } - } - - with(binding.loliCheckbox) { - isChecked = excludeLoli.all { tags.contains(it) } - if (excludeLoli.all { tags.contains(it) }) - excludeLoli.forEach { - tags.remove(it) - } - } - - with(binding.edittext) { - setText(tags.toString(), android.widget.TextView.BufferType.EDITABLE) - addTextChangedListener(object : TextWatcher { - override fun beforeTextChanged( - s: CharSequence?, - start: Int, - count: Int, - after: Int - ) { - } - - override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {} - - override fun afterTextChanged(s: Editable?) { - s ?: return - - if (s.any { it.isUpperCase() }) - s.replace( - 0, - s.length, - s.toString().toLowerCase(java.util.Locale.getDefault()) - ) - } - }) - } - } - - override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { - _binding = DefaultQueryDialogBinding.inflate(layoutInflater) - - initView() - - return AlertDialog.Builder(requireContext()).apply { - setTitle(R.string.default_query_dialog_title) - setView(binding.root) - setPositiveButton(android.R.string.ok) { _, _ -> - val newTags = Tags.parse(binding.edittext.text.toString()) - - with(binding.languageSelector) { - if (selectedItemPosition != 0) - newTags.add("language:${reverseLanguages[selectedItem]}") - } - - if (binding.BLCheckbox.isChecked) - newTags.add(excludeBL) - - if (binding.guroCheckbox.isChecked) - excludeGuro.forEach { tag -> - newTags.add(tag) - } - - if (binding.loliCheckbox.isChecked) - excludeLoli.forEach { tag -> - newTags.add(tag) - } - - onPositiveButtonClickListener?.invoke(newTags) - } - }.create() - } - - override fun onDestroy() { - super.onDestroy() - _binding = null - } - -} \ No newline at end of file diff --git a/app/src/main/java/xyz/quaver/pupil/ui/dialog/DownloadFolderNameDialogFragment.kt b/app/src/main/java/xyz/quaver/pupil/ui/dialog/DownloadFolderNameDialogFragment.kt deleted file mode 100644 index 86af6cc9..00000000 --- a/app/src/main/java/xyz/quaver/pupil/ui/dialog/DownloadFolderNameDialogFragment.kt +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Pupil, Hitomi.la viewer for Android - * Copyright (C) 2020 tom5079 - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package xyz.quaver.pupil.ui.dialog - -import android.app.Dialog -import android.os.Bundle -import android.view.ViewGroup -import androidx.core.widget.addTextChangedListener -import androidx.fragment.app.DialogFragment -import com.google.android.material.snackbar.Snackbar -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.launch -import xyz.quaver.pupil.R -import xyz.quaver.pupil.databinding.DownloadFolderNameDialogBinding -import xyz.quaver.pupil.util.Preferences -import xyz.quaver.pupil.util.downloader.Cache -import xyz.quaver.pupil.util.formatDownloadFolder -import xyz.quaver.pupil.util.formatDownloadFolderTest -import xyz.quaver.pupil.util.formatMap - -class DownloadFolderNameDialogFragment : DialogFragment() { - - private var _binding: DownloadFolderNameDialogBinding? = null - private val binding get() = _binding!! - - override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { - _binding = DownloadFolderNameDialogBinding.inflate(layoutInflater) - - initView() - - return Dialog(requireContext()).apply { - setContentView(binding.root) - window?.attributes?.width = ViewGroup.LayoutParams.MATCH_PARENT - } - } - - override fun onDestroy() { - super.onDestroy() - _binding = null - } - - private fun initView() { - val galleryID = Cache.instances.let { if (it.size == 0) 1199708 else it.keys.elementAt((0 until it.size).random()) } - CoroutineScope(Dispatchers.IO).launch { - val galleryBlock = Cache.getInstance(requireContext(), galleryID).getGalleryBlock() - - binding.message.text = getString(R.string.settings_download_folder_name_message, formatMap.keys.toString(), galleryBlock?.formatDownloadFolder() ?: "") - binding.edittext.addTextChangedListener { - binding.message.text = requireContext().getString(R.string.settings_download_folder_name_message, formatMap.keys.toString(), galleryBlock?.formatDownloadFolderTest(it.toString()) ?: "") - } - } - - binding.edittext.setText(Preferences["download_folder_name", "[-id-] -title-"]) - binding.okButton.setOnClickListener { - val newValue = binding.edittext.text.toString() - - if ((newValue as? String)?.contains("/") != false) { - Snackbar.make(binding.root, R.string.settings_invalid_download_folder_name, Snackbar.LENGTH_SHORT).show() - return@setOnClickListener - } - - Preferences["download_folder_name"] = binding.edittext.text.toString() - - dismiss() - } - } - -} \ No newline at end of file diff --git a/app/src/main/java/xyz/quaver/pupil/ui/dialog/DownloadLocationDialogFragment.kt b/app/src/main/java/xyz/quaver/pupil/ui/dialog/DownloadLocationDialogFragment.kt deleted file mode 100644 index c2f59642..00000000 --- a/app/src/main/java/xyz/quaver/pupil/ui/dialog/DownloadLocationDialogFragment.kt +++ /dev/null @@ -1,157 +0,0 @@ -/* - * Pupil, Hitomi.la viewer for Android - * Copyright (C) 2020 tom5079 - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package xyz.quaver.pupil.ui.dialog - -import android.app.Activity -import android.app.Dialog -import android.content.Intent -import android.os.Build -import android.os.Bundle -import androidx.activity.result.contract.ActivityResultContracts -import androidx.appcompat.app.AlertDialog -import androidx.core.content.ContextCompat -import androidx.core.net.toUri -import androidx.fragment.app.DialogFragment -import com.google.android.material.snackbar.Snackbar -import xyz.quaver.io.FileX -import xyz.quaver.io.util.toFile -import xyz.quaver.pupil.R -import xyz.quaver.pupil.databinding.DownloadLocationDialogBinding -import xyz.quaver.pupil.databinding.DownloadLocationItemBinding -import xyz.quaver.pupil.util.Preferences -import xyz.quaver.pupil.util.byteToString -import xyz.quaver.pupil.util.downloader.DownloadManager -import java.io.File - -class DownloadLocationDialogFragment : DialogFragment() { - - private var _binding: DownloadLocationDialogBinding? = null - private val binding get() = _binding!! - - private val entries = mutableMapOf() - - private val requestDownloadFolderLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { - if (it.resultCode == Activity.RESULT_OK) { - val context = context ?: return@registerForActivityResult - val dialog = dialog ?: return@registerForActivityResult - - it.data?.data?.also { uri -> - val takeFlags: Int = Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION - - context.contentResolver.takePersistableUriPermission(uri, takeFlags) - - if (kotlin.runCatching { FileX(context, uri).canWrite() }.getOrDefault(false)) { - entries[null]?.locationAvailable?.text = uri.toFile(context)?.canonicalPath - Preferences["download_folder"] = uri.toString() - } else { - Snackbar.make( - dialog.window!!.decorView.rootView, - R.string.settings_download_folder_not_writable, - Snackbar.LENGTH_LONG - ).show() - - val downloadFolder = DownloadManager.getInstance(context).downloadFolder.canonicalPath - val key = entries.keys.firstOrNull { it?.canonicalPath == downloadFolder } - entries[key]!!.button.isChecked = true - if (key == null) entries[null]!!.locationAvailable.text = downloadFolder - } - } - } else { - val downloadFolder = DownloadManager.getInstance(context ?: return@registerForActivityResult).downloadFolder.canonicalPath - val key = entries.keys.firstOrNull { it?.canonicalPath == downloadFolder } - if (key == null) - entries[null]!!.locationAvailable.text = downloadFolder - else { - entries[null]!!.button.isChecked = false - entries[key]!!.button.isChecked = true - } - } - } - - private fun initView() { - val externalFilesDirs = ContextCompat.getExternalFilesDirs(requireContext(), null) - - externalFilesDirs.forEachIndexed { index, dir -> - dir ?: return@forEachIndexed - - DownloadLocationItemBinding.inflate(layoutInflater, binding.root, true).apply { - locationType.text = requireContext().getString(when (index) { - 0 -> R.string.settings_download_folder_internal - else -> R.string.settings_download_folder_removable - }) - locationAvailable.text = requireContext().getString( - R.string.settings_download_folder_available, - byteToString(dir.freeSpace) - ) - root.setOnClickListener { - entries.values.forEach { entry -> - entry.button.isChecked = false - } - button.performClick() - Preferences["download_folder"] = dir.toUri().toString() - } - entries[dir] = this - } - } - - DownloadLocationItemBinding.inflate(layoutInflater, binding.root, true).apply { - locationType.text = requireContext().getString(R.string.settings_download_folder_custom) - root.setOnClickListener { - entries.values.forEach { entry -> - entry.button.isChecked = false - } - button.performClick() - - val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE).apply { - putExtra("android.content.extra.SHOW_ADVANCED", true) - } - - requestDownloadFolderLauncher.launch(intent) - } - entries[null] = this - } - - val downloadFolder = DownloadManager.getInstance(requireContext()).downloadFolder.canonicalPath - val key = entries.keys.firstOrNull { it?.canonicalPath == downloadFolder } - entries[key]!!.button.isChecked = true - if (key == null) entries[key]!!.locationAvailable.text = downloadFolder - } - - override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { - _binding = DownloadLocationDialogBinding.inflate(layoutInflater) - - initView() - - return AlertDialog.Builder(requireContext()).apply { - setTitle(R.string.settings_download_folder) - setView(binding.root) - setPositiveButton(requireContext().getText(android.R.string.ok)) { _, _ -> - if (Preferences["download_folder", ""].isEmpty()) - Preferences["download_folder"] = context.getExternalFilesDir(null)?.toUri()?.toString() ?: "" - } - - isCancelable = false - }.create() - } - - override fun onDestroy() { - super.onDestroy() - _binding = null - } -} \ No newline at end of file diff --git a/app/src/main/java/xyz/quaver/pupil/ui/dialog/ProxyDialogFragment.kt b/app/src/main/java/xyz/quaver/pupil/ui/dialog/ProxyDialogFragment.kt deleted file mode 100644 index 8cce55ea..00000000 --- a/app/src/main/java/xyz/quaver/pupil/ui/dialog/ProxyDialogFragment.kt +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Pupil, Hitomi.la viewer for Android - * Copyright (C) 2020 tom5079 - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package xyz.quaver.pupil.ui.dialog - -import android.app.Dialog -import android.content.Context -import android.os.Bundle -import android.view.View -import android.widget.AdapterView -import android.widget.ArrayAdapter -import androidx.appcompat.app.AlertDialog -import androidx.fragment.app.DialogFragment -import kotlinx.serialization.encodeToString -import kotlinx.serialization.json.Json -import xyz.quaver.pupil.R -import xyz.quaver.pupil.client -import xyz.quaver.pupil.clientBuilder -import xyz.quaver.pupil.clientHolder -import xyz.quaver.pupil.databinding.ProxyDialogBinding -import xyz.quaver.pupil.util.Preferences -import xyz.quaver.pupil.util.ProxyInfo -import xyz.quaver.pupil.util.getProxyInfo -import xyz.quaver.pupil.util.proxyInfo -import java.net.Proxy - -class ProxyDialogFragment : DialogFragment() { - - private var _binding: ProxyDialogBinding? = null - private val binding get() = _binding!! - - override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { - _binding = ProxyDialogBinding.inflate(layoutInflater) - - initView() - - return AlertDialog.Builder(requireContext()).apply { - setView(binding.root) - }.create() - } - - private fun initView() { - val proxyInfo = getProxyInfo() - - val enabler = { enable: Boolean -> - binding.addr.isEnabled = enable - binding.port.isEnabled = enable - binding.username.isEnabled = enable - binding.password.isEnabled = enable - - if (!enable) { - binding.addr.text = null - binding.port.text = null - binding.username.text = null - binding.password.text = null - } - } - - with(binding.typeSelector) { - adapter = ArrayAdapter( - context, - android.R.layout.simple_spinner_dropdown_item, - context.resources.getStringArray(R.array.proxy_type) - ) - - setSelection(proxyInfo.type.ordinal) - - onItemSelectedListener = object: AdapterView.OnItemSelectedListener { - override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) { - enabler.invoke(position != 0) - } - - override fun onNothingSelected(parent: AdapterView<*>?) {} - } - } - - binding.addr.setText(proxyInfo.host) - binding.port.setText(proxyInfo.port?.toString()) - binding.username.setText(proxyInfo.username) - binding.password.setText(proxyInfo.password) - - enabler.invoke(proxyInfo.type != Proxy.Type.DIRECT) - - binding.cancelButton.setOnClickListener { - dismiss() - } - - binding.okButton.setOnClickListener { - val type = Proxy.Type.values()[binding.typeSelector.selectedItemPosition] - val addr = binding.addr.text?.toString() - val port = binding.port.text?.toString()?.toIntOrNull() - val username = binding.username.text?.toString() - val password = binding.password.text?.toString() - - if (type != Proxy.Type.DIRECT) { - if (addr == null || addr.isEmpty()) - binding.addr.error = requireContext().getText(R.string.proxy_dialog_error) - if (port == null) - binding.port.error = requireContext().getText(R.string.proxy_dialog_error) - - if (addr == null || addr.isEmpty() || port == null) - return@setOnClickListener - } - - ProxyInfo(type, addr, port, username, password).let { - Preferences["proxy"] = Json.encodeToString(it) - - clientBuilder - .proxyInfo(it) - clientHolder = null - client - } - - dismiss() - } - } - -} \ No newline at end of file diff --git a/app/src/main/java/xyz/quaver/pupil/ui/fragment/LockSettingsFragment.kt b/app/src/main/java/xyz/quaver/pupil/ui/fragment/LockSettingsFragment.kt deleted file mode 100644 index 8dce8389..00000000 --- a/app/src/main/java/xyz/quaver/pupil/ui/fragment/LockSettingsFragment.kt +++ /dev/null @@ -1,146 +0,0 @@ -/* - * Pupil, Hitomi.la viewer for Android - * Copyright (C) 2020 tom5079 - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package xyz.quaver.pupil.ui.fragment - -import android.content.Intent -import android.os.Bundle -import android.widget.Toast -import androidx.appcompat.app.AlertDialog -import androidx.preference.Preference -import androidx.preference.PreferenceFragmentCompat -import androidx.preference.SwitchPreferenceCompat -import xyz.quaver.pupil.R -import xyz.quaver.pupil.ui.LockActivity -import xyz.quaver.pupil.util.Lock -import xyz.quaver.pupil.util.LockManager -import xyz.quaver.pupil.util.Preferences - -class LockSettingsFragment : PreferenceFragmentCompat() { - - override fun onResume() { - super.onResume() - - val lockManager = LockManager(requireContext()) - - findPreference("lock_pattern")?.summary = - if (lockManager.contains(Lock.Type.PATTERN)) - getString(R.string.settings_lock_enabled) - else - "" - - findPreference("lock_pin")?.summary = - if (lockManager.contains(Lock.Type.PIN)) - getString(R.string.settings_lock_enabled) - else - "" - - if (lockManager.isEmpty()) { - (findPreference("lock_fingerprint") as SwitchPreferenceCompat).isChecked = false - - Preferences["lock_fingerprint"] = false - } - } - - override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { - setPreferencesFromResource(R.xml.lock_preferences, rootKey) - - with(findPreference("lock_pattern")) { - this!! - - if (LockManager(requireContext()).contains(Lock.Type.PATTERN)) - summary = getString(R.string.settings_lock_enabled) - - onPreferenceClickListener = Preference.OnPreferenceClickListener { - val lockManager = LockManager(requireContext()) - - if (lockManager.contains(Lock.Type.PATTERN)) { - AlertDialog.Builder(requireContext()).apply { - setTitle(R.string.warning) - setMessage(R.string.settings_lock_remove_message) - - setPositiveButton(android.R.string.ok) { _, _ -> - lockManager.remove(Lock.Type.PATTERN) - onResume() - } - setNegativeButton(android.R.string.cancel) { _, _ -> } - }.show() - } else { - val intent = Intent(requireContext(), LockActivity::class.java).apply { - putExtra("mode", "add_lock") - putExtra("type", "pattern") - } - - startActivity(intent) - } - - true - } - } - - with(findPreference("lock_pin")) { - this!! - - if (LockManager(requireContext()).contains(Lock.Type.PIN)) - summary = getString(R.string.settings_lock_enabled) - - onPreferenceClickListener = Preference.OnPreferenceClickListener { - val lockManager = LockManager(requireContext()) - - if (lockManager.contains(Lock.Type.PIN)) { - AlertDialog.Builder(requireContext()).apply { - setTitle(R.string.warning) - setMessage(R.string.settings_lock_remove_message) - - setPositiveButton(android.R.string.ok) { _, _ -> - lockManager.remove(Lock.Type.PIN) - onResume() - } - setNegativeButton(android.R.string.cancel) { _, _ -> } - }.show() - } else { - val intent = Intent(requireContext(), LockActivity::class.java).apply { - putExtra("mode", "add_lock") - putExtra("type", "pin") - } - - startActivity(intent) - } - - true - } - } - - with(findPreference("lock_fingerprint")) { - this!! - - setOnPreferenceChangeListener { _, newValue -> - this as SwitchPreferenceCompat - - if (newValue == true && LockManager(requireContext()).isEmpty()) { - isChecked = false - - Toast.makeText(requireContext(), R.string.settings_lock_fingerprint_without_lock, Toast.LENGTH_SHORT).show() - } else - isChecked = newValue as Boolean - - false - } - } - } -} \ No newline at end of file diff --git a/app/src/main/java/xyz/quaver/pupil/ui/fragment/ManageFavoritesFragment.kt b/app/src/main/java/xyz/quaver/pupil/ui/fragment/ManageFavoritesFragment.kt deleted file mode 100644 index 7e479890..00000000 --- a/app/src/main/java/xyz/quaver/pupil/ui/fragment/ManageFavoritesFragment.kt +++ /dev/null @@ -1,140 +0,0 @@ -/* - * Pupil, Hitomi.la viewer for Android - * Copyright (C) 2020 tom5079 - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package xyz.quaver.pupil.ui.fragment - -import android.app.Activity -import android.content.Intent -import android.content.res.Resources -import android.graphics.PorterDuff -import android.graphics.PorterDuffColorFilter -import android.os.Bundle -import android.util.Log -import android.widget.EditText -import android.widget.TextView -import android.widget.Toast -import androidx.activity.result.contract.ActivityResultContracts -import androidx.appcompat.app.AlertDialog -import androidx.core.content.ContextCompat -import androidx.core.content.FileProvider -import androidx.core.graphics.drawable.DrawableCompat -import androidx.preference.Preference -import androidx.preference.PreferenceFragmentCompat -import androidx.swiperefreshlayout.widget.CircularProgressDrawable -import com.google.android.material.snackbar.Snackbar -import kotlinx.coroutines.MainScope -import kotlinx.coroutines.launch -import kotlinx.datetime.LocalDate -import kotlinx.serialization.json.Json -import kotlinx.serialization.json.buildJsonObject -import kotlinx.serialization.json.decodeFromJsonElement -import okhttp3.* -import xyz.quaver.io.FileX -import xyz.quaver.io.util.readText -import xyz.quaver.pupil.R -import xyz.quaver.pupil.client -import xyz.quaver.pupil.favoriteTags -import xyz.quaver.pupil.favorites -import xyz.quaver.pupil.types.Tag -import xyz.quaver.pupil.util.get -import xyz.quaver.pupil.util.restore -import java.io.File -import java.io.IOException -import kotlin.math.roundToInt - -class ManageFavoritesFragment : PreferenceFragmentCompat() { - - private val requestBackupFileLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result -> - if (result.resultCode != Activity.RESULT_OK) { - return@registerForActivityResult - } - - val uri = result.data?.data ?: return@registerForActivityResult - val context = context ?: return@registerForActivityResult - val view = view ?: return@registerForActivityResult - - val backupData = runCatching { - FileX(context, uri).readText()?.let { Json.parseToJsonElement(it) } - }.getOrNull() ?: run{ - Snackbar.make(view, context.getString(R.string.error), Toast.LENGTH_LONG).show() - return@registerForActivityResult - } - - val newFavorites = backupData["favorites"]?.let { Json.decodeFromJsonElement>(it) }.orEmpty() - val newFavoriteTags = backupData["favorite_tags"]?.let { Json.decodeFromJsonElement>(it) }.orEmpty() - - favorites.addAll(newFavorites) - favoriteTags.addAll(newFavoriteTags) - - Snackbar.make(view, context.getString(R.string.settings_restore_success, newFavorites.size + newFavoriteTags.size), Snackbar.LENGTH_LONG).show() - } - - override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { - setPreferencesFromResource(R.xml.manage_favorites_preferences, rootKey) - - initPreferences() - } - - private fun initPreferences() { - val context = context ?: return - - findPreference("backup")?.setOnPreferenceClickListener { - val favorites = runCatching { - Json.parseToJsonElement(File(ContextCompat.getDataDir(context), "favorites.json").readText()) - }.getOrNull() - val favoriteTags = kotlin.runCatching { - Json.parseToJsonElement(File(ContextCompat.getDataDir(context), "favorites_tags.json").readText()) - }.getOrNull() - - val favoriteJson = buildJsonObject { - favorites?.let { - put("favorites", it) - } - favoriteTags?.let { - put("favorite_tags", it) - } - } - - val backupFile = File(context.filesDir, "pupil-backup.json").also { - it.writeText(favoriteJson.toString()) - } - - Intent(Intent.ACTION_SEND).apply { - val uri = FileProvider.getUriForFile(context, "${context.packageName}.provider", backupFile) - setDataAndType(uri, "application/json") - addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) - putExtra(Intent.EXTRA_STREAM, uri) - }.let { - context.startActivity(Intent.createChooser(it, getString(R.string.settings_backup_share))) - } - - true - } - findPreference("restore")?.setOnPreferenceClickListener { - val intent = Intent(Intent.ACTION_OPEN_DOCUMENT).apply { - addCategory(Intent.CATEGORY_OPENABLE) - type = "*/*" - } - - requestBackupFileLauncher.launch(intent) - - true - } - } - -} \ No newline at end of file diff --git a/app/src/main/java/xyz/quaver/pupil/ui/fragment/PINLockFragment.kt b/app/src/main/java/xyz/quaver/pupil/ui/fragment/PINLockFragment.kt deleted file mode 100644 index 5a8d3a7f..00000000 --- a/app/src/main/java/xyz/quaver/pupil/ui/fragment/PINLockFragment.kt +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Pupil, Hitomi.la viewer for Android - * Copyright (C) 2020 tom5079 - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package xyz.quaver.pupil.ui.fragment - -import android.os.Bundle -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import androidx.fragment.app.Fragment -import com.andrognito.pinlockview.PinLockListener -import xyz.quaver.pupil.databinding.PinLockFragmentBinding - -class PINLockFragment : Fragment() { - - private var _binding: PinLockFragmentBinding? = null - val binding get() = _binding!! - - var onPINEntered: ((String) -> Unit)? = null - - override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { - _binding = PinLockFragmentBinding.inflate(inflater, container, false) - - binding.pinLockView.attachIndicatorDots(binding.indicatorDots) - binding.pinLockView.setPinLockListener(object: PinLockListener { - override fun onComplete(p0: String?) { - onPINEntered?.invoke(p0 ?: "") - } - - override fun onEmpty() {} - override fun onPinChange(p0: Int, p1: String?) {} - }) - - return binding.root - } - - override fun onDestroy() { - super.onDestroy() - _binding = null - } - -} \ No newline at end of file diff --git a/app/src/main/java/xyz/quaver/pupil/ui/fragment/PatternLockFragment.kt b/app/src/main/java/xyz/quaver/pupil/ui/fragment/PatternLockFragment.kt deleted file mode 100644 index 69d48f4a..00000000 --- a/app/src/main/java/xyz/quaver/pupil/ui/fragment/PatternLockFragment.kt +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Pupil, Hitomi.la viewer for Android - * Copyright (C) 2019 tom5079 - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package xyz.quaver.pupil.ui.fragment - -import android.os.Bundle -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import androidx.fragment.app.Fragment -import com.andrognito.patternlockview.PatternLockView -import com.andrognito.patternlockview.listener.PatternLockViewListener -import com.andrognito.patternlockview.utils.PatternLockUtils -import xyz.quaver.pupil.databinding.PatternLockFragmentBinding - -class PatternLockFragment : Fragment() { - - private var _binding: PatternLockFragmentBinding? = null - val binding get() = _binding!! - - var onPatternDrawn: ((String) -> Unit)? = null - - override fun onCreateView( - inflater: LayoutInflater, container: ViewGroup?, - savedInstanceState: Bundle? - ): View { - _binding = PatternLockFragmentBinding.inflate(inflater, container, false) - binding.patternLockView.addPatternLockListener(object: PatternLockViewListener { - override fun onComplete(pattern: MutableList?) { - val password = PatternLockUtils.patternToMD5(binding.patternLockView, pattern) - onPatternDrawn?.invoke(password) - } - - override fun onCleared() {} - override fun onProgress(progressPattern: MutableList?) {} - override fun onStarted() {} - }) - return binding.root - } - - override fun onDestroy() { - super.onDestroy() - _binding = null - } - -} diff --git a/app/src/main/java/xyz/quaver/pupil/ui/fragment/SettingsFragment.kt b/app/src/main/java/xyz/quaver/pupil/ui/fragment/SettingsFragment.kt deleted file mode 100644 index 97706f8b..00000000 --- a/app/src/main/java/xyz/quaver/pupil/ui/fragment/SettingsFragment.kt +++ /dev/null @@ -1,309 +0,0 @@ -/* - * Pupil, Hitomi.la viewer for Android - * Copyright (C) 2020 tom5079 - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package xyz.quaver.pupil.ui.fragment - -import android.app.Activity -import android.content.* -import android.os.Bundle -import android.widget.Toast -import androidx.activity.result.contract.ActivityResultContracts -import androidx.appcompat.app.AppCompatDelegate -import androidx.preference.* -import com.google.android.gms.oss.licenses.OssLicensesMenuActivity -import com.google.firebase.crashlytics.FirebaseCrashlytics -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.launch -import okhttp3.Dispatcher -import xyz.quaver.io.FileX -import xyz.quaver.io.util.getChild -import xyz.quaver.pupil.R -import xyz.quaver.pupil.client -import xyz.quaver.pupil.clientBuilder -import xyz.quaver.pupil.clientHolder -import xyz.quaver.pupil.types.SendLogException -import xyz.quaver.pupil.ui.LockActivity -import xyz.quaver.pupil.ui.SettingsActivity -import xyz.quaver.pupil.ui.dialog.* -import xyz.quaver.pupil.util.* -import xyz.quaver.pupil.util.downloader.DownloadManager -import java.util.* -import java.util.concurrent.Executors - -class SettingsFragment : - PreferenceFragmentCompat(), - Preference.OnPreferenceClickListener, - Preference.OnPreferenceChangeListener, - SharedPreferences.OnSharedPreferenceChangeListener { - - private val lockLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { - if (it.resultCode == Activity.RESULT_OK) { - parentFragmentManager - .beginTransaction() - .replace(R.id.settings, LockSettingsFragment()) - .addToBackStack("Lock") - .commitAllowingStateLoss() - } - } - - override fun onResume() { - super.onResume() - - val lockManager = LockManager(requireContext()) - - findPreference("app_lock")?.summary = if (lockManager.locks.isNullOrEmpty()) { - getString(R.string.settings_lock_none) - } else { - lockManager.locks?.joinToString(", ") { - when(it.type) { - Lock.Type.PATTERN -> getString(R.string.settings_lock_pattern) - Lock.Type.PIN -> getString(R.string.settings_lock_pin) - Lock.Type.PASSWORD -> getString(R.string.settings_lock_password) - } - } - } - } - - override fun onPreferenceClick(preference: Preference): Boolean { - with (preference) { - when (key) { - "app_version" -> { - checkUpdate(activity as SettingsActivity, true) - } - "download_folder" -> { - DownloadLocationDialogFragment().show(parentFragmentManager, "Download Location Dialog") - } - "default_query" -> { - DefaultQueryDialog().apply { - onPositiveButtonClickListener = { newTags -> - Preferences["default_query"] = newTags.toString() - summary = newTags.toString() - } - }.show(parentFragmentManager, "Default Query Dialog") - } - "app_lock" -> { - val intent = Intent(requireContext(), LockActivity::class.java).apply { - putExtra("force", true) - } - lockLauncher.launch(intent) - } - "proxy" -> { - ProxyDialogFragment().show(parentFragmentManager, "Proxy Dialog") - } - "user_id" -> { - FirebaseCrashlytics.getInstance().recordException(SendLogException()) - (context.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager).setPrimaryClip( - ClipData.newPlainText("user_id", Preferences.get("user_id")) - ) - Toast.makeText(context, R.string.copied_to_clipboard, Toast.LENGTH_SHORT).show() - } - else -> return false - } - } - - return true - } - - override fun onPreferenceChange(preference: Preference, newValue: Any?): Boolean { - with (preference) { - when (key) { - "tag_translation" -> { - updateTranslations() - } - "nomedia" -> { - val create = (newValue as? Boolean) ?: return false - - return kotlin.runCatching { - val nomedia = DownloadManager.getInstance(context).downloadFolder.getChild(".nomedia") - - if (create) - nomedia.createNewFile() - else - nomedia.delete() - }.getOrDefault(false) - } - "dark_mode" -> { - AppCompatDelegate.setDefaultNightMode(when (newValue as Boolean) { - true -> AppCompatDelegate.MODE_NIGHT_YES - false -> AppCompatDelegate.MODE_NIGHT_NO - }) - } - else -> return false - } - } - - return true - } - - override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, key: String?) { - key ?: return - - with(findPreference(key)) { - this ?: return - - when (key) { - "proxy" -> { - summary = context.let { getProxyInfo().type.name } - } - "download_folder" -> { - summary = FileX(context, Preferences.get("download_folder")).canonicalPath - } - "download_folder_name" -> { - summary = Preferences["download_folder_name", "[-id-] -title-"] - } - "max_concurrent_download" -> { - val newValue = Preferences.get(key).toIntOrNull() ?: 0 - - if (newValue == 0) - clientBuilder.dispatcher(Dispatcher()) - else - clientBuilder.dispatcher((Dispatcher(Executors.newFixedThreadPool(newValue)))) - - clientHolder = null - client - } - else -> return - } - } - } - - override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { - setPreferencesFromResource(R.xml.root_preferences, rootKey) - - Preferences.registerOnSharedPreferenceChangeListener(this) - - initPreferences() - } - - override fun onDestroy() { - Preferences.unregisterOnSharedPreferenceChangeListener(this) - super.onDestroy() - } - - private fun initPreferences() { - for (i in 0 until preferenceScreen.preferenceCount) { - - preferenceScreen.getPreference(i).run { - if (this is PreferenceCategory) - (0 until preferenceCount).map { getPreference(it) } - else - listOf(this) - }.forEach { preference -> - with (preference) with@{ - - when (key) { - "app_version" -> { - val manager = requireContext().packageManager - val info = manager.getPackageInfo(requireContext().packageName, 0) - summary = requireContext().getString(R.string.settings_app_version_description, info.versionName) - - onPreferenceClickListener = this@SettingsFragment - } - "download_folder_name" -> { - summary = Preferences["download_folder_name", "[-id-] -title-"] - - setOnPreferenceClickListener { - DownloadFolderNameDialogFragment().show(requireActivity().supportFragmentManager, "Download Location Dialog") - - true - } - } - "download_folder" -> { - summary = FileX(context, Preferences.get("download_folder")).canonicalPath - - onPreferenceClickListener = this@SettingsFragment - } - "nomedia" -> { - (this as SwitchPreferenceCompat).isChecked = kotlin.runCatching { - DownloadManager.getInstance(context).downloadFolder.getChild(".nomedia").exists() - }.getOrDefault(false) - - onPreferenceChangeListener = this@SettingsFragment - } - "default_query" -> { - summary = Preferences.get("default_query") - - onPreferenceClickListener = this@SettingsFragment - } - "app_lock" -> { - val lockManager = LockManager(requireContext()) - summary = - if (lockManager.locks.isNullOrEmpty()) { - getString(R.string.settings_lock_none) - } else { - lockManager.locks?.joinToString(", ") { - when (it.type) { - Lock.Type.PATTERN -> getString(R.string.settings_lock_pattern) - Lock.Type.PIN -> getString(R.string.settings_lock_pin) - Lock.Type.PASSWORD -> getString(R.string.settings_lock_password) - } - } - } - - onPreferenceClickListener = this@SettingsFragment - } - "proxy" -> { - summary = getProxyInfo().type.name - - onPreferenceClickListener = this@SettingsFragment - } - "tag_translation" -> { - this as ListPreference - - isEnabled = false - - CoroutineScope(Dispatchers.IO).launch { - kotlin.runCatching { - val languages = getAvailableLanguages().distinct().toTypedArray() - - entries = languages.map { Locale(it).let { loc -> loc.getDisplayLanguage(loc) } }.toTypedArray() - entryValues = languages - - launch(Dispatchers.Main) { - isEnabled = true - } - } - } - - onPreferenceChangeListener = this@SettingsFragment - - } - "dark_mode" -> { - onPreferenceChangeListener = this@SettingsFragment - } - "old_import_galleries" -> { - onPreferenceClickListener = this@SettingsFragment - } - "user_id" -> { - summary = Preferences.get("user_id") - onPreferenceClickListener = this@SettingsFragment - } - "oss" -> { - setOnPreferenceClickListener { - context.startActivity(Intent(context, OssLicensesMenuActivity::class.java)) - true - } - } - } - - } - } - } - } -} \ No newline at end of file diff --git a/app/src/main/java/xyz/quaver/pupil/ui/reader/ImageViewer.kt b/app/src/main/java/xyz/quaver/pupil/ui/reader/ImageViewer.kt deleted file mode 100644 index b7a8a540..00000000 --- a/app/src/main/java/xyz/quaver/pupil/ui/reader/ImageViewer.kt +++ /dev/null @@ -1,2 +0,0 @@ -package xyz.quaver.pupil.ui.reader - diff --git a/app/src/main/java/xyz/quaver/pupil/util/ItemClickSupport.kt b/app/src/main/java/xyz/quaver/pupil/util/ItemClickSupport.kt deleted file mode 100644 index 1b4ce3ba..00000000 --- a/app/src/main/java/xyz/quaver/pupil/util/ItemClickSupport.kt +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Pupil, Hitomi.la viewer for Android - * Copyright (C) 2020 tom5079 - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package xyz.quaver.pupil.util - -import android.view.View -import androidx.recyclerview.widget.RecyclerView -import xyz.quaver.pupil.R - -class ItemClickSupport(private val recyclerView: RecyclerView) { - - var onItemClickListener: ((RecyclerView, Int, View) -> Unit)? = null - var onItemLongClickListener: ((RecyclerView, Int, View) -> Boolean)? = null - - init { - recyclerView.apply { - setTag(R.id.item_click_support, this) - addOnChildAttachStateChangeListener(object: RecyclerView.OnChildAttachStateChangeListener { - override fun onChildViewAttachedToWindow(view: View) { - onItemClickListener?.let { listener -> - view.setOnClickListener { - recyclerView.getChildViewHolder(view).let { holder -> - listener.invoke(recyclerView, holder.adapterPosition, view) - } - } - } - onItemLongClickListener?.let { listener -> - view.setOnLongClickListener { - recyclerView.getChildViewHolder(view).let { holder -> - listener.invoke(recyclerView, holder.adapterPosition, view) - } - } - } - } - - override fun onChildViewDetachedFromWindow(view: View) { - // Do Nothing - } - }) - } - } - - fun detach() { - recyclerView.apply { - clearOnChildAttachStateChangeListeners() - setTag(R.id.item_click_support, null) - } - } - - companion object { - fun addTo(view: RecyclerView) = view.let { removeFrom(it); ItemClickSupport(it) } - fun removeFrom(view: RecyclerView) = (view.tag as? ItemClickSupport)?.detach() - } -} \ No newline at end of file diff --git a/app/src/main/java/xyz/quaver/pupil/util/Preferences.kt b/app/src/main/java/xyz/quaver/pupil/util/Preferences.kt deleted file mode 100644 index 1fce3dff..00000000 --- a/app/src/main/java/xyz/quaver/pupil/util/Preferences.kt +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Pupil, Hitomi.la viewer for Android - * Copyright (C) 2020 tom5079 - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package xyz.quaver.pupil.util - -import android.content.SharedPreferences -import kotlin.reflect.KClass - -lateinit var preferences: SharedPreferences - -object Preferences: SharedPreferences by preferences { - - val defMap = mapOf( - String::class to "", - Int::class to -1, - Long::class to -1L, - Boolean::class to false, - Set::class to emptySet() - ) - - operator fun set(key: String, value: String) = edit().putString(key, value).apply() - operator fun set(key: String, value: Int) = edit().putInt(key, value).apply() - operator fun set(key: String, value: Long) = edit().putLong(key, value).apply() - operator fun set(key: String, value: Boolean) = edit().putBoolean(key, value).apply() - operator fun set(key: String, value: Set) = edit().putStringSet(key, value).apply() - - @Suppress("UNCHECKED_CAST") - inline operator fun get(key: String, defaultVal: T = defMap[T::class] as T): T = (all[key] as? T) ?: defaultVal - - fun remove(key: String) { - edit().remove(key).apply() - } -} \ No newline at end of file diff --git a/app/src/main/java/xyz/quaver/pupil/util/SavedSet.kt b/app/src/main/java/xyz/quaver/pupil/util/SavedSet.kt deleted file mode 100644 index 710fe184..00000000 --- a/app/src/main/java/xyz/quaver/pupil/util/SavedSet.kt +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Pupil, Hitomi.la viewer for Android - * Copyright (C) 2020 tom5079 - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package xyz.quaver.pupil.util - -import com.google.firebase.crashlytics.FirebaseCrashlytics -import kotlinx.serialization.ExperimentalSerializationApi -import kotlinx.serialization.KSerializer -import kotlinx.serialization.builtins.ListSerializer -import kotlinx.serialization.json.Json -import kotlinx.serialization.serializer -import java.io.File - -class SavedSet (private val file: File, private val any: T, private val set: MutableSet = mutableSetOf()) : MutableSet by set { - - @Suppress("UNCHECKED_CAST") - @OptIn(ExperimentalSerializationApi::class) - val serializer: KSerializer> - get() = ListSerializer(serializer(any::class.java) as KSerializer) - - init { - if (!file.exists()) { - file.parentFile?.mkdirs() - save() - } - load() - } - - @Synchronized - fun load() { - set.clear() - kotlin.runCatching { - Json.decodeFromString(serializer, file.readText()) - }.onSuccess { - set.addAll(it) - }.onFailure { - FirebaseCrashlytics.getInstance().recordException(it) - } - } - - @Synchronized - @OptIn(ExperimentalSerializationApi::class) - fun save() { - file.writeText(Json.encodeToString(serializer, set.toList())) - } - - @Synchronized - override fun add(element: T): Boolean { - set.remove(element) - - return set.add(element).also { - save() - } - } - - @Synchronized - override fun addAll(elements: Collection): Boolean { - set.removeAll(elements) - - return set.addAll(elements).also { - save() - } - } - - @Synchronized - override fun remove(element: T): Boolean { - return set.remove(element).also { - save() - } - } - - @Synchronized - override fun clear() { - set.clear() - save() - } - -} \ No newline at end of file diff --git a/app/src/main/java/xyz/quaver/pupil/util/camera.kt b/app/src/main/java/xyz/quaver/pupil/util/camera.kt deleted file mode 100644 index 1b2e5652..00000000 --- a/app/src/main/java/xyz/quaver/pupil/util/camera.kt +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Pupil, Hitomi.la viewer for Android - * Copyright (C) 2020 tom5079 - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -@file:Suppress("DEPRECATION", "Recycle") - -package xyz.quaver.pupil.util - -import android.content.Context -import android.content.pm.PackageManager -import android.graphics.ImageFormat -import android.graphics.SurfaceTexture -import android.hardware.Camera -import android.view.Surface -import android.view.WindowManager -import com.google.android.gms.tasks.Task -import com.google.mlkit.vision.common.InputImage -import com.google.mlkit.vision.face.Face -import com.google.mlkit.vision.face.FaceDetection -import com.google.mlkit.vision.face.FaceDetectorOptions - -/** Check if this device has a camera */ -private fun Context.checkCameraHardware() = - this.packageManager.hasSystemFeature(PackageManager.FEATURE_CAMERA) - -private fun openFrontCamera() : Pair { - var camera: Camera? = null - var cameraID: Int = -1 - - val cameraInfo = Camera.CameraInfo() - - for (i in 0 until Camera.getNumberOfCameras()) { - Camera.getCameraInfo(i, cameraInfo) - if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) - runCatching { Camera.open(i) }.getOrNull()?.let { camera = it; cameraID = i } - - if (camera != null) break - } - - return Pair(camera, cameraID) -} - -val orientations = mapOf( - Surface.ROTATION_0 to 0, - Surface.ROTATION_90 to 90, - Surface.ROTATION_180 to 180, - Surface.ROTATION_270 to 270, -) - -private fun getRotation(context: Context, cameraID: Int): Int { - val cameraRotation = Camera.CameraInfo().also { Camera.getCameraInfo(cameraID, it) }.orientation - val rotation = orientations[(context.getSystemService(Context.WINDOW_SERVICE) as WindowManager).defaultDisplay.rotation] ?: error("") - - return (cameraRotation + rotation) % 360 -} - -var camera: Camera? = null -var surfaceTexture: SurfaceTexture? = null -private val detector = FaceDetection.getClient( - FaceDetectorOptions.Builder() - .setClassificationMode(FaceDetectorOptions.CLASSIFICATION_MODE_ALL) - .build() -) -private var process: Task>? = null - -fun startCamera(context: Context, callback: (List) -> Unit) { - if (camera != null) closeCamera() - - val cameraID = openFrontCamera().let { (cam, cameraID) -> - cam ?: return - camera = cam - cameraID - } - - with (camera!!) { - parameters = parameters.apply { - setPreviewSize(640, 480) - previewFormat = ImageFormat.NV21 - } - - setPreviewTexture(surfaceTexture ?: SurfaceTexture(0).also { - surfaceTexture = it - }) - startPreview() - setPreviewCallback { bytes, _ -> - if (process?.isComplete == false) - return@setPreviewCallback - - val rotation = getRotation(context, cameraID) - - val image = InputImage.fromByteArray(bytes, 640, 480, rotation, InputImage.IMAGE_FORMAT_NV21) - process = detector.process(image) - .addOnSuccessListener(callback) - } - } -} - -fun closeCamera() { - camera?.setPreviewCallback(null) - camera?.stopPreview() - surfaceTexture?.release() - surfaceTexture = null - camera?.release() - camera = null -} \ No newline at end of file diff --git a/app/src/main/java/xyz/quaver/pupil/util/file.kt b/app/src/main/java/xyz/quaver/pupil/util/file.kt deleted file mode 100644 index d889b3a1..00000000 --- a/app/src/main/java/xyz/quaver/pupil/util/file.kt +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Pupil, Hitomi.la viewer for Android - * Copyright (C) 2019 tom5079 - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package xyz.quaver.pupil.util - -import android.content.Context -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.launch -import kotlinx.coroutines.sync.Mutex -import kotlinx.coroutines.sync.withLock -import xyz.quaver.pupil.histories -import xyz.quaver.pupil.util.downloader.Cache -import xyz.quaver.pupil.util.downloader.DownloadManager -import java.io.File - -val mutex = Mutex() -fun cleanCache(context: Context) = CoroutineScope(Dispatchers.IO).launch { - if (mutex.isLocked) return@launch - - mutex.withLock { - val cacheFolder = File(context.cacheDir, "imageCache") - val downloadManager = DownloadManager.getInstance(context) - - val limit = (Preferences.get("cache_limit").toLongOrNull() ?: 0L)*1024*1024*1024 - - if (limit == 0L) return@withLock - - val cacheSize = { - var size = 0L - - cacheFolder.walk().forEach { - size += it.length() - } - - size - } - - if (cacheSize.invoke() > limit) - while (cacheSize.invoke() > limit/2) { - val caches = cacheFolder.list() ?: return@withLock - - synchronized(histories) { - (histories.firstOrNull { - caches.contains(it.toString()) && !downloadManager.isDownloading(it) - } ?: return@withLock).let { - Cache.delete(context, it) - } - } - } - } -} \ No newline at end of file diff --git a/app/src/main/java/xyz/quaver/pupil/util/lock.kt b/app/src/main/java/xyz/quaver/pupil/util/lock.kt deleted file mode 100644 index cf5da4cb..00000000 --- a/app/src/main/java/xyz/quaver/pupil/util/lock.kt +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Pupil, Hitomi.la viewer for Android - * Copyright (C) 2019 tom5079 - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package xyz.quaver.pupil.util - -import android.content.Context -import android.content.ContextWrapper -import androidx.core.content.ContextCompat -import kotlinx.serialization.Serializable -import kotlinx.serialization.decodeFromString -import kotlinx.serialization.encodeToString -import kotlinx.serialization.json.Json -import java.io.File -import java.security.MessageDigest - -fun hash(password: String): String { - val bytes = password.toByteArray() - val md = MessageDigest.getInstance("SHA-256") - - return md.digest(bytes).fold("") { str, it -> str + "%02x".format(it) } -} - -// Ret1: SHA-256 Hash -// Ret2: Hash salt -fun hashWithSalt(password: String): Pair { - val salt = (0 until 12).map { source.random() }.joinToString() - - return Pair(hash(password+salt), salt) -} - -const val source = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" - -@Serializable -data class Lock(val type: Type, val hash: String, val salt: String) { - - enum class Type { - PATTERN, - PIN, - PASSWORD - } - - companion object { - fun generate(type: Type, password: String): Lock { - val (hash, salt) = hashWithSalt(password) - return Lock(type, hash, salt) - } - } - - fun match(password: String): Boolean { - return hash(password+salt) == hash - } -} - -class LockManager(base: Context): ContextWrapper(base) { - - var locks: ArrayList? = null - - init { - load() - } - - private fun load() { - val lock = File(ContextCompat.getDataDir(this), "lock.json") - - if (!lock.exists()) { - lock.createNewFile() - lock.writeText("[]") - } - - locks = Json.decodeFromString(lock.readText()) - } - - private fun save() { - val lock = File(ContextCompat.getDataDir(this), "lock.json") - - if (!lock.exists()) - lock.createNewFile() - - lock.writeText(Json.encodeToString(locks?.toList() ?: listOf())) - } - - fun add(lock: Lock) { - remove(lock.type) - locks?.add(lock) - save() - } - - fun remove(type: Lock.Type) { - locks?.removeAll { it.type == type } - save() - } - - fun check(password: String): Boolean? { - return locks?.any { - it.match(password) - } - } - - fun isEmpty(): Boolean { - return locks.isNullOrEmpty() - } - - fun isNotEmpty(): Boolean = !isEmpty() - - fun contains(type: Lock.Type): Boolean { - return locks?.any { it.type == type } ?: false - } - -} \ No newline at end of file diff --git a/app/src/main/java/xyz/quaver/pupil/util/misc.kt b/app/src/main/java/xyz/quaver/pupil/util/misc.kt deleted file mode 100644 index 9e666680..00000000 --- a/app/src/main/java/xyz/quaver/pupil/util/misc.kt +++ /dev/null @@ -1,172 +0,0 @@ -/* - * Pupil, Hitomi.la viewer for Android - * Copyright (C) 2019 tom5079 - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package xyz.quaver.pupil.util - -import android.Manifest -import android.annotation.SuppressLint -import android.app.Activity -import android.content.Context -import android.content.pm.PackageManager -import android.os.Build -import androidx.activity.result.ActivityResultLauncher -import androidx.appcompat.app.AlertDialog -import androidx.core.app.ActivityCompat -import androidx.core.content.ContextCompat -import com.google.firebase.crashlytics.FirebaseCrashlytics -import kotlinx.serialization.json.* -import okhttp3.OkHttpClient -import okhttp3.Request -import xyz.quaver.pupil.R -import xyz.quaver.pupil.hitomi.GalleryBlock -import xyz.quaver.pupil.hitomi.GalleryInfo -import xyz.quaver.pupil.hitomi.imageUrlFromImage -import java.util.* -import kotlin.collections.ArrayList - -@OptIn(ExperimentalStdlibApi::class) -fun String.wordCapitalize() : String { - val result = ArrayList() - - @SuppressLint("DefaultLocale") - for (word in this.split(" ")) - result.add(word.replaceFirstChar { if (it.isLowerCase()) it.titlecase(Locale.US) else it.toString() }) - - return result.joinToString(" ") -} - -private val suffix = listOf( - "B", - "kB", - "MB", - "GB", - "TB" //really? -) - -fun byteToString(byte: Long, precision : Int = 1) : String { - var size = byte.toDouble(); var suffixIndex = 0 - - while (size >= 1024) { - size /= 1024 - suffixIndex++ - } - - return "%.${precision}f ${suffix[suffixIndex]}".format(size) -} - -/** - * Convert android generated ID to requestCode - * to prevent java.lang.IllegalArgumentException: Can only use lower 16 bits for requestCode - * - * https://stackoverflow.com/questions/38072322/generate-16-bit-unique-ids-in-android-for-startactivityforresult - */ -fun Int.normalizeID() = this.and(0xFFFF) - -fun OkHttpClient.Builder.proxyInfo(proxyInfo: ProxyInfo) = this.apply { - proxy(proxyInfo.proxy()) - proxyInfo.authenticator()?.let { - proxyAuthenticator(it) - } -} - -val formatMap = mapOf (String)>( - "-id-" to { id.toString() }, - "-title-" to { title }, - "-artist-" to { if (artists.isNotEmpty()) artists.joinToString() else "N/A" }, - "-group-" to { if (groups.isNotEmpty()) groups.joinToString() else "N/A" } - // TODO -) -/** - * Formats download folder name with given Metadata - */ -fun GalleryBlock.formatDownloadFolder(): String = - Preferences["download_folder_name", "[-id-] -title-"].let { - formatMap.entries.fold(it) { str, (k, v) -> - str.replace(k, v.invoke(this), true) - } - }.replace(Regex("""[*\\|"?><:/]"""), "").ellipsize(127) - -fun GalleryBlock.formatDownloadFolderTest(format: String): String = - format.let { - formatMap.entries.fold(it) { str, (k, v) -> - str.replace(k, v.invoke(this), true) - } - }.replace(Regex("""[*\\|"?><:/]"""), "").ellipsize(127) - -suspend fun GalleryInfo.getRequestBuilders(): List { - val galleryID = this.id.toIntOrNull() ?: 0 - return this.files.map { - Request.Builder() - .url( - runCatching { - imageUrlFromImage(galleryID, it, false) - } - .onFailure { - FirebaseCrashlytics.getInstance().recordException(it) - } - .getOrDefault("https://a/") - ) - .header("Referer", "https://hitomi.la/") - } -} - -fun String.ellipsize(n: Int): String = - if (this.length > n) - this.slice(0 until n) + "…" - else - this - -operator fun JsonElement.get(index: Int) = - this.jsonArray[index] - -operator fun JsonElement.get(tag: String) = - this.jsonObject[tag] - -fun JsonElement.getOrNull(tag: String) = kotlin.runCatching { - this.jsonObject.getOrDefault(tag, null) -}.getOrNull() - -val JsonElement.content - get() = this.jsonPrimitive.contentOrNull - -fun checkNotificationEnabled(context: Context) = - Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU || - ContextCompat.checkSelfPermission(context, Manifest.permission.POST_NOTIFICATIONS) == PackageManager.PERMISSION_GRANTED - -fun showNotificationPermissionExplanationDialog(context: Context) { - AlertDialog.Builder(context) - .setTitle(R.string.warning) - .setMessage(R.string.notification_denied) - .setPositiveButton(android.R.string.ok) { _, _ -> } - .show() -} - -fun requestNotificationPermission( - activity: Activity, - requestPermissionLauncher: ActivityResultLauncher, - showRationale: Boolean = true, - ifGranted: () -> Unit, -) { - when { - checkNotificationEnabled(activity) -> ifGranted() - showRationale && ActivityCompat.shouldShowRequestPermissionRationale(activity, Manifest.permission.POST_NOTIFICATIONS) -> - showNotificationPermissionExplanationDialog(activity) - else -> - requestPermissionLauncher.launch(Manifest.permission.POST_NOTIFICATIONS) - } -} \ No newline at end of file diff --git a/app/src/main/java/xyz/quaver/pupil/util/proxy.kt b/app/src/main/java/xyz/quaver/pupil/util/proxy.kt deleted file mode 100644 index 20947d3c..00000000 --- a/app/src/main/java/xyz/quaver/pupil/util/proxy.kt +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Pupil, Hitomi.la viewer for Android - * Copyright (C) 2020 tom5079 - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package xyz.quaver.pupil.util - -import android.content.Context -import kotlinx.serialization.Serializable -import kotlinx.serialization.decodeFromString -import kotlinx.serialization.encodeToString -import kotlinx.serialization.json.Json -import okhttp3.Authenticator -import okhttp3.Credentials -import java.net.InetSocketAddress -import java.net.Proxy - -@Serializable -data class ProxyInfo( - val type: Proxy.Type, - val host: String? = null, - val port: Int? = null, - val username: String? = null, - val password: String? = null -) { - fun proxy() : Proxy { - return if (host.isNullOrBlank() || port == null) - return Proxy.NO_PROXY - else - Proxy(type, InetSocketAddress.createUnresolved(host, port)) - } - - fun authenticator(): Authenticator? = if (username.isNullOrBlank() || password.isNullOrBlank()) null else - Authenticator { _, response -> - val credential = Credentials.basic(username, password) - - response.request.newBuilder() - .header("Proxy-Authorization", credential) - .build() - } - -} - -fun getProxyInfo(): ProxyInfo = - Json.decodeFromString(Preferences["proxy", Json.encodeToString(ProxyInfo(Proxy.Type.DIRECT))]) \ No newline at end of file diff --git a/app/src/main/java/xyz/quaver/pupil/util/translation.kt b/app/src/main/java/xyz/quaver/pupil/util/translation.kt deleted file mode 100644 index 61b92990..00000000 --- a/app/src/main/java/xyz/quaver/pupil/util/translation.kt +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Pupil, Hitomi.la viewer for Android - * Copyright (C) 2020 tom5079 - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package xyz.quaver.pupil.util - -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.launch -import kotlinx.serialization.decodeFromString -import kotlinx.serialization.json.Json -import kotlinx.serialization.json.jsonArray -import kotlinx.serialization.json.jsonPrimitive -import okhttp3.Request -import xyz.quaver.pupil.client -import java.io.IOException -import java.util.* - -private val filesURL = "https://api.github.com/repos/tom5079/Pupil/git/trees/tags" -private val contentURL = "https://raw.githubusercontent.com/tom5079/Pupil/tags/" - -var translations: Map = run { - updateTranslations() - emptyMap() -} - private set - -@Suppress("BlockingMethodInNonBlockingContext") -fun updateTranslations() = CoroutineScope(Dispatchers.IO).launch { - translations = emptyMap() - kotlin.runCatching { - translations = Json.decodeFromString>(client.newCall( - Request.Builder() - .url(contentURL + "${Preferences["tag_translation", ""].let { if (it.isEmpty()) Locale.getDefault().language else it }}.json") - .build() - ).execute().also { if (it.code != 200) return@launch }.body?.use { it.string() } ?: return@launch).filterValues { it.isNotEmpty() } - } -} - -fun getAvailableLanguages(): List { - val languages = Locale.getISOLanguages() - - val json = Json.parseToJsonElement(client.newCall( - Request.Builder() - .url(filesURL) - .build() - ).execute().also { if (it.code != 200) throw IOException() }.body?.use { it.string() } ?: return emptyList()) - - return listOf("en") + (json["tree"]?.jsonArray?.mapNotNull { - val name = it["path"]?.jsonPrimitive?.content?.takeWhile { c -> c != '.' } - - languages.firstOrNull { code -> code.equals(name, ignoreCase = true) } - } ?: emptyList()) -} \ No newline at end of file diff --git a/app/src/main/java/xyz/quaver/pupil/util/update.kt b/app/src/main/java/xyz/quaver/pupil/util/update.kt deleted file mode 100644 index e8b817aa..00000000 --- a/app/src/main/java/xyz/quaver/pupil/util/update.kt +++ /dev/null @@ -1,214 +0,0 @@ -/* - * Pupil, Hitomi.la viewer for Android - * Copyright (C) 2019 tom5079 - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package xyz.quaver.pupil.util - -import android.app.DownloadManager -import android.content.Context -import android.net.Uri -import android.webkit.URLUtil -import androidx.appcompat.app.AlertDialog -import androidx.preference.PreferenceManager -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.launch -import kotlinx.serialization.json.* -import okhttp3.Call -import okhttp3.Callback -import okhttp3.Request -import okhttp3.Response -import ru.noties.markwon.Markwon -import xyz.quaver.pupil.* -import xyz.quaver.pupil.types.Tag -import java.io.File -import java.io.IOException -import java.net.URL -import java.util.* - -fun getReleases(url: String) : JsonArray { - return try { - URL(url).readText().let { - Json.parseToJsonElement(it).jsonArray - } - } catch (e: Exception) { - JsonArray(emptyList()) - } -} - -fun checkUpdate(url: String) : JsonObject? { - val releases = getReleases(url) - - if (releases.isEmpty()) - return null - - return releases.firstOrNull { - Preferences["beta"] || it.jsonObject["prerelease"]?.jsonPrimitive?.booleanOrNull == false - }?.let { - if (it.jsonObject["tag_name"]?.jsonPrimitive?.contentOrNull == BuildConfig.VERSION_NAME) - null - else - it.jsonObject - } -} - -fun getApkUrl(releases: JsonObject) : String? { - return releases["assets"]?.jsonArray?.firstOrNull { - Regex("Pupil-v.+\\.apk").matches(it.jsonObject["name"]?.jsonPrimitive?.contentOrNull ?: "") - }.let { - it?.jsonObject?.get("browser_download_url")?.jsonPrimitive?.contentOrNull - } -} - -fun checkUpdate(context: Context, force: Boolean = false) { - - val preferences = PreferenceManager.getDefaultSharedPreferences(context) - val ignoreUpdateUntil = preferences.getLong("ignore_update_until", 0) - - if (!force && ignoreUpdateUntil > System.currentTimeMillis()) - return - - fun extractReleaseNote(update: JsonObject, locale: Locale) : String { - val markdown = update["body"]!!.jsonPrimitive.content - - val target = when(locale.language) { - "ko" -> "한국어" - "ja" -> "日本語" - else -> "English" - } - - val releaseNote = Regex("^# Release Note.+$") - val language = Regex("^## $target$") - val end = Regex("^#.+$") - - var releaseNoteFlag = false - var languageFlag = false - - val result = StringBuilder() - - for(line in markdown.lines()) { - if (releaseNote.matches(line)) { - releaseNoteFlag = true - continue - } - - if (releaseNoteFlag) { - if (language.matches(line)) { - languageFlag = true - continue - } - } - - if (languageFlag) { - if (end.matches(line)) - break - - result.append(line+"\n") - } - } - - return context.getString(R.string.update_release_note, update["tag_name"]?.jsonPrimitive?.contentOrNull, result.toString()) - } - - CoroutineScope(Dispatchers.Default).launch { - val update = - checkUpdate(context.getString(R.string.release_url)) ?: return@launch - - val url = getApkUrl(update) ?: return@launch - - val dialog = AlertDialog.Builder(context).apply { - setTitle(R.string.update_title) - val msg = extractReleaseNote(update, Locale.getDefault()) - setMessage(Markwon.create(context).toMarkdown(msg)) - setPositiveButton(android.R.string.ok) { _, _ -> - if (!checkNotificationEnabled(context)) { - showNotificationPermissionExplanationDialog(context) - return@setPositiveButton - } - - val downloadManager = context.getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager - - //Cancel any download queued before - - val id: Long = Preferences["update_download_id"] - - if (id != -1L) - downloadManager.remove(id) - - val target = File(context.getExternalFilesDir(null), "Pupil.apk").also { - it.delete() - } - - val request = DownloadManager.Request(Uri.parse(url)) - .setTitle(context.getText(R.string.update_notification_description)) - .setDestinationUri(Uri.fromFile(target)) - - downloadManager.enqueue(request).also { - Preferences["update_download_id"] = it - } - } - setNegativeButton(if (force) android.R.string.cancel else R.string.ignore) { _, _ -> - if (!force) - preferences.edit() - .putLong("ignore_update_until", System.currentTimeMillis() + 86400000) - .apply() - } - } - - launch(Dispatchers.Main) { - dialog.show() - } - } -} - -fun restore(url: String, onFailure: ((Throwable) -> Unit)? = null, onSuccess: ((Int) -> Unit)? = null) { - if (!URLUtil.isValidUrl(url)) { - onFailure?.invoke(IllegalArgumentException()) - return - } - - val request = Request.Builder() - .url(url) - .get() - .build() - - client.newCall(request).enqueue(object: Callback { - override fun onFailure(call: Call, e: IOException) { - onFailure?.invoke(e) - } - - override fun onResponse(call: Call, response: Response) { - kotlin.runCatching { - val data = Json.parseToJsonElement(response.also { if (it.code != 200) throw IOException() }.body.use { it?.string() } ?: "[]") - - when (data) { - is JsonArray -> favorites.addAll(data.map { it.jsonPrimitive.int }) - is JsonObject -> { - val newFavorites = data["favorites"]?.let { Json.decodeFromJsonElement>(it) }.orEmpty() - val newFavoriteTags = data["favorite_tags"]?.let { Json.decodeFromJsonElement>(it) }.orEmpty() - - favorites.addAll(newFavorites) - favoriteTags.addAll(newFavoriteTags) - - onSuccess?.invoke(favorites.size + favoriteTags.size) - } - else -> error("data is neither JsonArray or JsonObject") - } - }.onFailure { onFailure?.invoke(it) } - } - }) -} \ No newline at end of file diff --git a/app/src/main/res/anim/shake.xml b/app/src/main/res/anim/shake.xml deleted file mode 100644 index 323768dd..00000000 --- a/app/src/main/res/anim/shake.xml +++ /dev/null @@ -1,24 +0,0 @@ - - - - \ No newline at end of file diff --git a/app/src/main/res/anim/shake_cycle.xml b/app/src/main/res/anim/shake_cycle.xml deleted file mode 100644 index 13dcab54..00000000 --- a/app/src/main/res/anim/shake_cycle.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - \ No newline at end of file diff --git a/app/src/main/res/color/lock_fab.xml b/app/src/main/res/color/lock_fab.xml deleted file mode 100644 index 197313e3..00000000 --- a/app/src/main/res/color/lock_fab.xml +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/drawable-hdpi/ic_fullscreen.png b/app/src/main/res/drawable-hdpi/ic_fullscreen.png deleted file mode 100644 index c72a9b9eb59f52f566d83fa5c178bc9b92094282..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 145 zcmeAS@N?(olHy`uVBq!ia0vp^Dj>|k1|%Oc%$NbBB0OCjLn>~)z2?oupupjJaoV+W zF;U)|rA#k%ewkc-VBseP4{yc>*U;A*8&ACyUY@0LK_;Q-m(3)z0B)Pe+kzf>=M^v1 tH!{fF`1Z${#jCciz;Ivv6Xp{un60OsRSur8gB558gQu&X%Q~loCIBDAGwc8W diff --git a/app/src/main/res/drawable-hdpi/ic_notification.png b/app/src/main/res/drawable-hdpi/ic_notification.png deleted file mode 100644 index f3b20dfbcdba99b18b2c53b59dd8195705bce3e6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 255 zcmV{aME{ddmEWhE9!u24*EZ}HZr1SRD%CVG=FSmW`TPw)lJb#OPFitOe!>#s^t_V zD9471^yOG}a7*}d2FvnyvF@`z5(8^H!5f^(K zdTfWp<&dl@6L$}Zys5>#Wg=gDas80Uj!|q+ttiTy`2gQz}rHT&8*hbhfeRR_J z*P*(D$7ACH#_oq&9-p)#bTSo=HZ9GVC7u+xS-|(~CC608v&|jbCi;9%@tWS__IXj0 gUh7>A2{{G^BXN7_KNgDWK$kFhy85}Sb4q9e06nHaM*si- diff --git a/app/src/main/res/drawable-xhdpi/ic_fullscreen.png b/app/src/main/res/drawable-xhdpi/ic_fullscreen.png deleted file mode 100644 index 6caba05d64fd25fc7858e6992c5925b88fcfa24f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 125 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA1|-9oezpTC7f%<*kcwMxZye-hP~c#3{FN^i z{h_(4a2dm-TEP`e3`}2^1sAh$?2w&c7T>_Y_>z%f$BCRIMkba$!Vk0+A8cn}NI1as X_vjxzO$PaRpm_|Qu6{1-oD!M<3#}yT diff --git a/app/src/main/res/drawable-xhdpi/ic_notification.png b/app/src/main/res/drawable-xhdpi/ic_notification.png deleted file mode 100644 index 35d6cbc19338225375e68c52b1abb6704b092256..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 311 zcmV-70m%M|P)*ny6khB=VvG6ieg4vfGiH%6wQN^$ZT$;Ih(KNd#_@x4!aO(4b&iQ}Xw z00000U z4qRB(i~f~7`-YFQV@oNZ8TsmijY|0^niv7}iVr)59jCCsM zm8rL2JHt;uB_^PJ!!+jE>6|JP9GE!2SWc*A5%N%I1QYYvfzk&GU(6DRiLiY7_sAZ~ c0qHE}dfxlJQsScWS|E?X)78&qol`;+03Hb{3jhEB diff --git a/app/src/main/res/drawable-xxhdpi/ic_notification.png b/app/src/main/res/drawable-xxhdpi/ic_notification.png deleted file mode 100644 index bf017e1a3981ac0a75e38183aa274669a8d8c32a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 432 zcmV;h0Z;ykP)5xq=ia7jPNsi}zh;V&rDo1v^cEh+6lsZk+;>RKH&OdVx1|Z&Q{&kg zf5cT(it=yf&GoaZaqiAVgR7mkg?CXAF@K?BEu1_U^kUpO#f%t*aVJ$C40<&zyfnlq z4RIO|2K9!7oEzfghQ!^cXi&Q#R*OLxgh3cYlAgElhR6Kx3$G{?X*Fn8Iqu-V%<+L4 zN3I;&^V)|OhmK6*)pLYNTwaLWNnC%4$VptFiYx)Rf)`nFbBQyu!Q~n-0000000000 axZ?voOBcEMStjlP0000U{djPaSW-r^>&VZ-XQ~#_LWDv zEF6p&%uk9+Ot>*Y>Z#aGtAl4$cW|dBy=0xVkvS=0#c!p`Ow|yk^+(SCw0mj(@wonb z^_v^#zdZ;v5(W;Ko!dFxEoIT-CzDx$V!xSxd6)=3UG!G|)ZcRVly@7K_`4Qg^xIPY z_U7;VX8#RU7jIXuQ;X`>TJHYzf3aKJdUZR|T$ioC?X&K?ovL~M+*xFi|96{N+q&+} zR%q;ZeZS6n*0$rdZ;QkhHNT#x*5-PD(teS-u@)v9b$(CzGnu0<)yytHYJ(bBV zf5LvJnR~wT6z1aN`POUi_a%APJ$w^*WYV86CnxKiJsBm{%qX2c-Is?udut+d)@AOB zI@U{8*{5IsoLXe0w`lPSk+pRzzs!%Fa(j)>HQ^dXm&yErWzM^2{$Hn7+|BkzMEHZ6 zSJaldKkjF2+&t~i#kr|RvQNt26FeMnv1RW{sm=Ob^_r#DCz%UXy6#>)GKq1$7jxb+ z0q8ZIt}$R>2B8K=3FZpk+Ac;*;f?R6 zD{TpLi0n!*Ja;2W=JZ986pa%BlXwoZbbXSQKCo>HgHJ+o*m1TEriKi{H|9t;aOU{G zzrnzl!IHq_K84Ak(YdN|#sR~t47-&1ve*p_ibEY0KC^6|UV0>{>E!FIB$FoY*-Wd{ m3sNH$(h4%=VbKVsw>*}P*m}e6!G}9yAQ4YjKbLh*2~7a8b^>q! diff --git a/app/src/main/res/drawable/account_group.xml b/app/src/main/res/drawable/account_group.xml deleted file mode 100644 index 4680128b..00000000 --- a/app/src/main/res/drawable/account_group.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/app/src/main/res/drawable/account_star.xml b/app/src/main/res/drawable/account_star.xml deleted file mode 100644 index 5797e282..00000000 --- a/app/src/main/res/drawable/account_star.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/app/src/main/res/drawable/avd_star.xml b/app/src/main/res/drawable/avd_star.xml deleted file mode 100644 index 4ec5915e..00000000 --- a/app/src/main/res/drawable/avd_star.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - - - - - - diff --git a/app/src/main/res/drawable/backspace_outline.xml b/app/src/main/res/drawable/backspace_outline.xml deleted file mode 100644 index aea682c7..00000000 --- a/app/src/main/res/drawable/backspace_outline.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/app/src/main/res/drawable/book_open.xml b/app/src/main/res/drawable/book_open.xml deleted file mode 100644 index f676d847..00000000 --- a/app/src/main/res/drawable/book_open.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/app/src/main/res/drawable/brush.xml b/app/src/main/res/drawable/brush.xml deleted file mode 100644 index cedc1a3a..00000000 --- a/app/src/main/res/drawable/brush.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/app/src/main/res/drawable/close.xml b/app/src/main/res/drawable/close.xml deleted file mode 100644 index 5de405fe..00000000 --- a/app/src/main/res/drawable/close.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/app/src/main/res/drawable/delete.xml b/app/src/main/res/drawable/delete.xml deleted file mode 100644 index b174be80..00000000 --- a/app/src/main/res/drawable/delete.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/app/src/main/res/drawable/dot.xml b/app/src/main/res/drawable/dot.xml deleted file mode 100644 index f75e450c..00000000 --- a/app/src/main/res/drawable/dot.xml +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/drawable/eye.xml b/app/src/main/res/drawable/eye.xml deleted file mode 100644 index c5853f1e..00000000 --- a/app/src/main/res/drawable/eye.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - \ No newline at end of file diff --git a/app/src/main/res/drawable/eye_closed.xml b/app/src/main/res/drawable/eye_closed.xml deleted file mode 100644 index cb8e83fd..00000000 --- a/app/src/main/res/drawable/eye_closed.xml +++ /dev/null @@ -1,44 +0,0 @@ - - - - - - - - - diff --git a/app/src/main/res/drawable/eye_off.xml b/app/src/main/res/drawable/eye_off.xml deleted file mode 100644 index 2f1a1e82..00000000 --- a/app/src/main/res/drawable/eye_off.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - \ No newline at end of file diff --git a/app/src/main/res/drawable/eye_off_white.xml b/app/src/main/res/drawable/eye_off_white.xml deleted file mode 100644 index 15afd4cd..00000000 --- a/app/src/main/res/drawable/eye_off_white.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - \ No newline at end of file diff --git a/app/src/main/res/drawable/eye_white.xml b/app/src/main/res/drawable/eye_white.xml deleted file mode 100644 index c1f3d205..00000000 --- a/app/src/main/res/drawable/eye_white.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - \ No newline at end of file diff --git a/app/src/main/res/drawable/fingerprint.xml b/app/src/main/res/drawable/fingerprint.xml deleted file mode 100644 index 7c14a715..00000000 --- a/app/src/main/res/drawable/fingerprint.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/app/src/main/res/drawable/gender_female.xml b/app/src/main/res/drawable/gender_female.xml deleted file mode 100644 index 74729734..00000000 --- a/app/src/main/res/drawable/gender_female.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/app/src/main/res/drawable/gender_female_white.xml b/app/src/main/res/drawable/gender_female_white.xml deleted file mode 100644 index 7dbc415f..00000000 --- a/app/src/main/res/drawable/gender_female_white.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/app/src/main/res/drawable/gender_male.xml b/app/src/main/res/drawable/gender_male.xml deleted file mode 100644 index d58538ae..00000000 --- a/app/src/main/res/drawable/gender_male.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/app/src/main/res/drawable/gender_male_white.xml b/app/src/main/res/drawable/gender_male_white.xml deleted file mode 100644 index fddbc6ff..00000000 --- a/app/src/main/res/drawable/gender_male_white.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/app/src/main/res/drawable/history.xml b/app/src/main/res/drawable/history.xml deleted file mode 100644 index 448a3497..00000000 --- a/app/src/main/res/drawable/history.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/app/src/main/res/drawable/hitomi.png b/app/src/main/res/drawable/hitomi.png deleted file mode 100644 index 82270729604405c3148a14a327313f7586959a3c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3768 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 diff --git a/app/src/main/res/drawable/ic_download.xml b/app/src/main/res/drawable/ic_download.xml deleted file mode 100644 index e611a677..00000000 --- a/app/src/main/res/drawable/ic_download.xml +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/app/src/main/res/drawable/ic_downloading.xml b/app/src/main/res/drawable/ic_downloading.xml deleted file mode 100644 index bc694e22..00000000 --- a/app/src/main/res/drawable/ic_downloading.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - - - - - - - - - - - - - diff --git a/app/src/main/res/drawable/ic_star_empty.xml b/app/src/main/res/drawable/ic_star_empty.xml deleted file mode 100644 index ddec4480..00000000 --- a/app/src/main/res/drawable/ic_star_empty.xml +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/app/src/main/res/drawable/ic_star_filled.xml b/app/src/main/res/drawable/ic_star_filled.xml deleted file mode 100644 index a46ce175..00000000 --- a/app/src/main/res/drawable/ic_star_filled.xml +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/app/src/main/res/drawable/image_broken_variant.xml b/app/src/main/res/drawable/image_broken_variant.xml deleted file mode 100644 index 43e243e7..00000000 --- a/app/src/main/res/drawable/image_broken_variant.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/app/src/main/res/drawable/lastpass.xml b/app/src/main/res/drawable/lastpass.xml deleted file mode 100644 index b6b8a41a..00000000 --- a/app/src/main/res/drawable/lastpass.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/app/src/main/res/drawable/lock_pattern.xml b/app/src/main/res/drawable/lock_pattern.xml deleted file mode 100644 index 543da1c5..00000000 --- a/app/src/main/res/drawable/lock_pattern.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/app/src/main/res/drawable/navigate_next.xml b/app/src/main/res/drawable/navigate_next.xml deleted file mode 100644 index c25983c7..00000000 --- a/app/src/main/res/drawable/navigate_next.xml +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/app/src/main/res/drawable/navigate_prev.xml b/app/src/main/res/drawable/navigate_prev.xml deleted file mode 100644 index a3081f14..00000000 --- a/app/src/main/res/drawable/navigate_prev.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/app/src/main/res/drawable/numeric.xml b/app/src/main/res/drawable/numeric.xml deleted file mode 100644 index 1bcf9285..00000000 --- a/app/src/main/res/drawable/numeric.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/app/src/main/res/drawable/pin_filled.xml b/app/src/main/res/drawable/pin_filled.xml deleted file mode 100644 index d2c2323c..00000000 --- a/app/src/main/res/drawable/pin_filled.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/app/src/main/res/drawable/reader_item_boundary.xml b/app/src/main/res/drawable/reader_item_boundary.xml deleted file mode 100644 index 18006135..00000000 --- a/app/src/main/res/drawable/reader_item_boundary.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/app/src/main/res/drawable/refresh.xml b/app/src/main/res/drawable/refresh.xml deleted file mode 100644 index 150addb8..00000000 --- a/app/src/main/res/drawable/refresh.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/app/src/main/res/drawable/swap_horizontal.xml b/app/src/main/res/drawable/swap_horizontal.xml deleted file mode 100644 index 90d142ac..00000000 --- a/app/src/main/res/drawable/swap_horizontal.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/app/src/main/res/drawable/tag.xml b/app/src/main/res/drawable/tag.xml deleted file mode 100644 index e152a6d9..00000000 --- a/app/src/main/res/drawable/tag.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/app/src/main/res/drawable/thumb.xml b/app/src/main/res/drawable/thumb.xml deleted file mode 100644 index 4541d8a9..00000000 --- a/app/src/main/res/drawable/thumb.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/app/src/main/res/drawable/thumb_horizontal.xml b/app/src/main/res/drawable/thumb_horizontal.xml deleted file mode 100644 index 0de6aece..00000000 --- a/app/src/main/res/drawable/thumb_horizontal.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/app/src/main/res/drawable/thumbnail.webp b/app/src/main/res/drawable/thumbnail.webp deleted file mode 100644 index b8ea5312366edceea1c1530d86e2b339fff01b46..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 81790 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 - - - diff --git a/app/src/main/res/layout/default_query_dialog.xml b/app/src/main/res/layout/default_query_dialog.xml deleted file mode 100644 index 968fde0b..00000000 --- a/app/src/main/res/layout/default_query_dialog.xml +++ /dev/null @@ -1,135 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/download_folder_name_dialog.xml b/app/src/main/res/layout/download_folder_name_dialog.xml deleted file mode 100644 index 4104aace..00000000 --- a/app/src/main/res/layout/download_folder_name_dialog.xml +++ /dev/null @@ -1,59 +0,0 @@ - - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/download_location_dialog.xml b/app/src/main/res/layout/download_location_dialog.xml deleted file mode 100644 index fde6c7d9..00000000 --- a/app/src/main/res/layout/download_location_dialog.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/download_location_item.xml b/app/src/main/res/layout/download_location_item.xml deleted file mode 100644 index 50335e91..00000000 --- a/app/src/main/res/layout/download_location_item.xml +++ /dev/null @@ -1,51 +0,0 @@ - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/lock_activity.xml b/app/src/main/res/layout/lock_activity.xml deleted file mode 100644 index a19341ad..00000000 --- a/app/src/main/res/layout/lock_activity.xml +++ /dev/null @@ -1,97 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/numberpicker_dialog.xml b/app/src/main/res/layout/numberpicker_dialog.xml deleted file mode 100644 index e5687cb5..00000000 --- a/app/src/main/res/layout/numberpicker_dialog.xml +++ /dev/null @@ -1,53 +0,0 @@ - - - - - - - - - -