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 c72a9b9e..00000000 Binary files a/app/src/main/res/drawable-hdpi/ic_fullscreen.png and /dev/null differ 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 f3b20dfb..00000000 Binary files a/app/src/main/res/drawable-hdpi/ic_notification.png and /dev/null differ diff --git a/app/src/main/res/drawable-mdpi/ic_fullscreen.png b/app/src/main/res/drawable-mdpi/ic_fullscreen.png deleted file mode 100644 index f19ccbfa..00000000 Binary files a/app/src/main/res/drawable-mdpi/ic_fullscreen.png and /dev/null differ diff --git a/app/src/main/res/drawable-mdpi/ic_notification.png b/app/src/main/res/drawable-mdpi/ic_notification.png deleted file mode 100644 index ad62327f..00000000 Binary files a/app/src/main/res/drawable-mdpi/ic_notification.png and /dev/null differ 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 6caba05d..00000000 Binary files a/app/src/main/res/drawable-xhdpi/ic_fullscreen.png and /dev/null differ 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 35d6cbc1..00000000 Binary files a/app/src/main/res/drawable-xhdpi/ic_notification.png and /dev/null differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_fullscreen.png b/app/src/main/res/drawable-xxhdpi/ic_fullscreen.png deleted file mode 100644 index 4712c6c1..00000000 Binary files a/app/src/main/res/drawable-xxhdpi/ic_fullscreen.png and /dev/null differ 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 bf017e1a..00000000 Binary files a/app/src/main/res/drawable-xxhdpi/ic_notification.png and /dev/null differ diff --git a/app/src/main/res/drawable-xxxhdpi/ic_notification.png b/app/src/main/res/drawable-xxxhdpi/ic_notification.png deleted file mode 100644 index 8552f319..00000000 Binary files a/app/src/main/res/drawable-xxxhdpi/ic_notification.png and /dev/null differ 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 82270729..00000000 Binary files a/app/src/main/res/drawable/hitomi.png and /dev/null differ 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 b8ea5312..00000000 Binary files a/app/src/main/res/drawable/thumbnail.webp and /dev/null differ diff --git a/app/src/main/res/drawable/translate.xml b/app/src/main/res/drawable/translate.xml deleted file mode 100644 index 8507868c..00000000 --- a/app/src/main/res/drawable/translate.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - - 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 @@ - - - - - - - - - -