diff --git a/app/build.gradle b/app/build.gradle index cccb7ec9..a9fbf7d9 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -20,7 +20,7 @@ android { minSdkVersion 16 targetSdkVersion 29 versionCode 53 - versionName "4.18-beta1" + versionName "4.18-alpha1" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" multiDexEnabled true vectorDrawables.useSupportLibrary = true @@ -52,7 +52,7 @@ android { dependencies { def markwonVersion = '3.1.0' - implementation fileTree(dir: 'libs', include: ['*.jar']) + implementation fileTree(dir: 'libs', include: ['*.jar', '*.aar']) implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.7" implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.7" @@ -80,6 +80,7 @@ dependencies { implementation 'net.rdrei.android.dirchooser:library:3.2@aar' implementation 'com.github.chrisbanes:PhotoView:2.3.0' implementation 'com.andrognito.patternlockview:patternlockview:1.0.0' + //implementation 'com.andrognito.pinlockview:pinlockview:2.1.0' implementation "ru.noties.markwon:core:${markwonVersion}" testImplementation 'junit:junit:4.13' androidTestImplementation 'androidx.test.ext:junit:1.1.1' diff --git a/app/libs/pinlockview-release.aar b/app/libs/pinlockview-release.aar new file mode 100644 index 00000000..646f97a4 Binary files /dev/null and b/app/libs/pinlockview-release.aar differ diff --git a/app/release/output.json b/app/release/output.json index 41aaa36f..246862e8 100644 --- a/app/release/output.json +++ b/app/release/output.json @@ -1 +1,20 @@ -[{"outputType":{"type":"APK"},"apkData":{"type":"MAIN","splits":[],"versionCode":52,"versionName":"4.17","enabled":true,"outputFile":"app-release.apk","fullName":"release","baseName":"release","dirName":""},"path":"app-release.apk","properties":{}}] \ No newline at end of file +{ + "version": 1, + "artifactType": { + "type": "APK", + "kind": "Directory" + }, + "applicationId": "xyz.quaver.pupil", + "variantName": "release", + "elements": [ + { + "type": "SINGLE", + "filters": [], + "properties": [], + "versionCode": 53, + "versionName": "53", + "enabled": true, + "outputFile": "app-release.apk" + } + ] +} \ 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 index f8d77d95..5c11e63d 100644 --- a/app/src/main/java/xyz/quaver/pupil/ui/LockActivity.kt +++ b/app/src/main/java/xyz/quaver/pupil/ui/LockActivity.kt @@ -21,23 +21,157 @@ 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 androidx.preference.PreferenceManager import com.andrognito.patternlockview.PatternLockView import com.google.android.material.snackbar.Snackbar import kotlinx.android.synthetic.main.activity_lock.* import kotlinx.android.synthetic.main.fragment_pattern_lock.* +import kotlinx.android.synthetic.main.fragment_pin_lock.* import xyz.quaver.pupil.R +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 class LockActivity : AppCompatActivity() { + private lateinit var lockManager: LockManager + private var mode: String? = null + + private val patternLockFragment = PatternLockFragment().apply { + var lastPass = "" + onPatternDrawn = { + when(mode) { + null -> { + val result = lockManager.check(it) + + if (result == true) { + setResult(Activity.RESULT_OK) + finish() + } else + lock_pattern_view.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 { + lock_pattern_view.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) { + setResult(Activity.RESULT_OK) + finish() + } else { + indicator_dots.startAnimation(AnimationUtils.loadAnimation(context, R.anim.shake).apply { + setAnimationListener(object: Animation.AnimationListener { + override fun onAnimationEnd(animation: Animation?) { + pin_lock_view.resetPinLockView() + pin_lock_view.isEnabled = true + } + + override fun onAnimationStart(animation: Animation?) { + pin_lock_view.isEnabled = false + } + + override fun onAnimationRepeat(animation: Animation?) { + // Do Nothing + } + }) + }) + } + } + "add_lock" -> { + if (lastPass.isEmpty()) { + lastPass = it + + pin_lock_view.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 { + indicator_dots.startAnimation(AnimationUtils.loadAnimation(context, R.anim.shake).apply { + setAnimationListener(object: Animation.AnimationListener { + override fun onAnimationEnd(animation: Animation?) { + pin_lock_view.resetPinLockView() + pin_lock_view.isEnabled = true + } + + override fun onAnimationStart(animation: Animation?) { + pin_lock_view.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("Cancel") + .setConfirmationRequired(false) + .build() + + val biometricPrompt = BiometricPrompt(this, ContextCompat.getMainExecutor(this), + object : BiometricPrompt.AuthenticationCallback() { + override fun onAuthenticationSucceeded( + result: BiometricPrompt.AuthenticationResult) { + super.onAuthenticationSucceeded(result) + setResult(RESULT_OK) + finish() + return + } + }) + + // Displays the "log in" prompt. + biometricPrompt.authenticate(promptInfo) + } + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_lock) - val lockManager = try { + lockManager = try { LockManager(this) } catch (e: Exception) { AlertDialog.Builder(this).apply { @@ -50,12 +184,7 @@ class LockActivity : AppCompatActivity() { return } - val mode = intent.getStringExtra("mode") - - lock_pattern.isEnabled = false - lock_pin.isEnabled = false - lock_fingerprint.isEnabled = false - lock_password.isEnabled = false + mode = intent.getStringExtra("mode") when(mode) { null -> { @@ -64,52 +193,75 @@ class LockActivity : AppCompatActivity() { finish() return } + + if ( + PreferenceManager.getDefaultSharedPreferences(this).getBoolean("lock_fingerprint", false) + && BiometricManager.from(this).canAuthenticate() == BiometricManager.BIOMETRIC_SUCCESS + ) { + lock_fingerprint.apply { + isEnabled = true + setOnClickListener { + showBiometricPrompt() + } + } + showBiometricPrompt() + } + + lock_pattern.apply { + isEnabled = lockManager.contains(Lock.Type.PATTERN) + setOnClickListener { + supportFragmentManager.beginTransaction().replace( + R.id.lock_content, patternLockFragment + ).commit() + } + } + lock_pin.apply { + isEnabled = lockManager.contains(Lock.Type.PIN) + setOnClickListener { + supportFragmentManager.beginTransaction().replace( + R.id.lock_content, pinLockFragment + ).commit() + } + } + lock_password.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" -> { + lock_pattern.isEnabled = false + lock_pin.isEnabled = false + lock_fingerprint.isEnabled = false + lock_password.isEnabled = false + when(intent.getStringExtra("type")!!) { "pattern" -> { - + lock_pattern.isEnabled = true + supportFragmentManager.beginTransaction().add( + R.id.lock_content, patternLockFragment + ).commit() + } + "pin" -> { + lock_pin.isEnabled = true + supportFragmentManager.beginTransaction().add( + R.id.lock_content, pinLockFragment + ).commit() } } } } - - supportFragmentManager.beginTransaction().add( - R.id.lock_content, - PatternLockFragment().apply { - var lastPass = "" - onPatternDrawn = { - when(mode) { - null -> { - val result = lockManager.check(it) - - if (result == true) { - setResult(Activity.RESULT_OK) - finish() - } else - lock_pattern_view.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 { - lock_pattern_view.setViewMode(PatternLockView.PatternViewMode.WRONG) - lastPass = "" - - Snackbar.make(view!!, R.string.settings_lock_wrong_confirm, Snackbar.LENGTH_LONG).show() - } - } - } - } - } - } - ).commit() } } diff --git a/app/src/main/java/xyz/quaver/pupil/ui/SettingsActivity.kt b/app/src/main/java/xyz/quaver/pupil/ui/SettingsActivity.kt index 20621e38..7bc79d66 100644 --- a/app/src/main/java/xyz/quaver/pupil/ui/SettingsActivity.kt +++ b/app/src/main/java/xyz/quaver/pupil/ui/SettingsActivity.kt @@ -35,7 +35,7 @@ import kotlinx.serialization.builtins.serializer import net.rdrei.android.dirchooser.DirectoryChooserActivity import xyz.quaver.pupil.Pupil import xyz.quaver.pupil.R -import xyz.quaver.pupil.ui.fragment.LockFragment +import xyz.quaver.pupil.ui.fragment.LockSettingsFragment import xyz.quaver.pupil.ui.fragment.SettingsFragment import xyz.quaver.pupil.util.* import java.io.File @@ -84,7 +84,7 @@ class SettingsActivity : AppCompatActivity() { if (resultCode == Activity.RESULT_OK) { supportFragmentManager .beginTransaction() - .replace(R.id.settings, LockFragment()) + .replace(R.id.settings, LockSettingsFragment()) .addToBackStack("Lock") .commitAllowingStateLoss() } diff --git a/app/src/main/java/xyz/quaver/pupil/ui/fragment/LockFragment.kt b/app/src/main/java/xyz/quaver/pupil/ui/fragment/LockFragment.kt deleted file mode 100644 index b95900c1..00000000 --- a/app/src/main/java/xyz/quaver/pupil/ui/fragment/LockFragment.kt +++ /dev/null @@ -1,81 +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 androidx.appcompat.app.AlertDialog -import androidx.preference.Preference -import androidx.preference.PreferenceFragmentCompat -import xyz.quaver.pupil.R -import xyz.quaver.pupil.ui.LockActivity -import xyz.quaver.pupil.util.Lock -import xyz.quaver.pupil.util.LockManager - -class LockFragment : PreferenceFragmentCompat() { - - override fun onResume() { - super.onResume() - - val lockManager = LockManager(context!!) - - findPreference("lock_pattern")?.summary = - if (lockManager.contains(Lock.Type.PATTERN)) - getString(R.string.settings_lock_enabled) - else - "" - } - - override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { - setPreferencesFromResource(R.xml.lock_preferences, rootKey) - - with(findPreference("lock_pattern")) { - this!! - - if (LockManager(context!!).contains(Lock.Type.PATTERN)) - summary = getString(R.string.settings_lock_enabled) - - onPreferenceClickListener = Preference.OnPreferenceClickListener { - val lockManager = LockManager(context!!) - - if (lockManager.contains(Lock.Type.PATTERN)) { - AlertDialog.Builder(context).apply { - setTitle(R.string.warning) - setMessage(R.string.settings_lock_remove_message) - - setPositiveButton(android.R.string.yes) { _, _ -> - lockManager.remove(Lock.Type.PATTERN) - onResume() - } - setNegativeButton(android.R.string.no) { _, _ -> } - }.show() - } else { - val intent = Intent(context, LockActivity::class.java).apply { - putExtra("mode", "add_lock") - putExtra("type", "pattern") - } - - startActivity(intent) - } - - true - } - } - } -} \ 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 new file mode 100644 index 00000000..c4a76ee0 --- /dev/null +++ b/app/src/main/java/xyz/quaver/pupil/ui/fragment/LockSettingsFragment.kt @@ -0,0 +1,147 @@ +/* + * 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.PreferenceManager +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 + +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 + + PreferenceManager.getDefaultSharedPreferences(context).edit().putBoolean("lock_fingerprint", false).apply() + } + } + + 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.yes) { _, _ -> + lockManager.remove(Lock.Type.PATTERN) + onResume() + } + setNegativeButton(android.R.string.no) { _, _ -> } + }.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.yes) { _, _ -> + lockManager.remove(Lock.Type.PIN) + onResume() + } + setNegativeButton(android.R.string.no) { _, _ -> } + }.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/PINLockFragment.kt b/app/src/main/java/xyz/quaver/pupil/ui/fragment/PINLockFragment.kt new file mode 100644 index 00000000..b058840d --- /dev/null +++ b/app/src/main/java/xyz/quaver/pupil/ui/fragment/PINLockFragment.kt @@ -0,0 +1,53 @@ +/* + * 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 kotlinx.android.synthetic.main.fragment_pin_lock.view.* +import xyz.quaver.pupil.R + +class PINLockFragment : Fragment(), PinLockListener { + + var onPINEntered: ((String) -> Unit)? = null + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { + return inflater.inflate(R.layout.fragment_pin_lock, container, false).apply { + pin_lock_view.attachIndicatorDots(indicator_dots) + pin_lock_view.setPinLockListener(this@PINLockFragment) + } + } + + override fun onComplete(pin: String?) { + onPINEntered?.invoke(pin!!) + } + + override fun onEmpty() { + + } + + override fun onPinChange(pinLength: Int, intermediatePin: String?) { + + } + +} \ No newline at end of file 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 index 7f6b8004..a3dec70e 100644 --- a/app/src/main/java/xyz/quaver/pupil/ui/fragment/SettingsFragment.kt +++ b/app/src/main/java/xyz/quaver/pupil/ui/fragment/SettingsFragment.kt @@ -56,13 +56,13 @@ class SettingsFragment : override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - PreferenceManager.getDefaultSharedPreferences(context).registerOnSharedPreferenceChangeListener(this) + PreferenceManager.getDefaultSharedPreferences(requireContext()).registerOnSharedPreferenceChangeListener(this) } override fun onResume() { super.onResume() - val lockManager = LockManager(context!!) + val lockManager = LockManager(requireContext()) findPreference("app_lock")?.summary = if (lockManager.locks.isNullOrEmpty()) { getString(R.string.settings_lock_none) @@ -92,9 +92,9 @@ class SettingsFragment : checkUpdate(activity as SettingsActivity, true) } "delete_cache" -> { - val dir = File(context.cacheDir, "imageCache") + val dir = File(requireContext().cacheDir, "imageCache") - AlertDialog.Builder(context).apply { + AlertDialog.Builder(requireContext()).apply { setTitle(R.string.warning) setMessage(R.string.settings_clear_cache_alert_message) setPositiveButton(android.R.string.yes) { _, _ -> @@ -107,9 +107,9 @@ class SettingsFragment : }.show() } "delete_downloads" -> { - val dir = getDownloadDirectory(context) + val dir = getDownloadDirectory(requireContext()) - AlertDialog.Builder(context).apply { + AlertDialog.Builder(requireContext()).apply { setTitle(R.string.warning) setMessage(R.string.settings_clear_downloads_alert_message) setPositiveButton(android.R.string.yes) { _, _ -> @@ -122,9 +122,9 @@ class SettingsFragment : }.show() } "clear_history" -> { - val histories = (context.applicationContext as Pupil).histories + val histories = (requireContext().applicationContext as Pupil).histories - AlertDialog.Builder(context).apply { + AlertDialog.Builder(requireContext()).apply { setTitle(R.string.warning) setMessage(R.string.settings_clear_history_alert_message) setPositiveButton(android.R.string.yes) { _, _ -> @@ -135,10 +135,10 @@ class SettingsFragment : }.show() } "dl_location" -> { - DownloadLocationDialog(activity!!).show() + DownloadLocationDialog(requireActivity()).show() } "default_query" -> { - DefaultQueryDialog(context).apply { + DefaultQueryDialog(requireContext()).apply { onPositiveButtonClickListener = { newTags -> sharedPreferences.edit().putString("default_query", newTags.toString()).apply() summary = newTags.toString() @@ -146,20 +146,20 @@ class SettingsFragment : }.show() } "app_lock" -> { - val intent = Intent(context, LockActivity::class.java) + val intent = Intent(requireContext(), LockActivity::class.java) activity?.startActivityForResult(intent, REQUEST_LOCK) } "mirrors" -> { - MirrorDialog(context) + MirrorDialog(requireContext()) .show() } "proxy" -> { - ProxyDialog(context) + ProxyDialog(requireContext()) .show() } "backup" -> { - File(ContextCompat.getDataDir(context), "favorites.json").copyTo( - File(getDownloadDirectory(context), "favorites.json"), + File(ContextCompat.getDataDir(requireContext()), "favorites.json").copyTo( + File(getDownloadDirectory(requireContext()), "favorites.json"), true ) @@ -177,8 +177,8 @@ class SettingsFragment : "old_import_galleries" -> { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - if (ContextCompat.checkSelfPermission(context, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) - ActivityCompat.requestPermissions(activity!!, arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE), REQUEST_WRITE_PERMISSION_AND_SAF) + if (ContextCompat.checkSelfPermission(requireContext(), Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) + ActivityCompat.requestPermissions(requireActivity(), arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE), REQUEST_WRITE_PERMISSION_AND_SAF) else { val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE).apply { putExtra("android.content.extra.SHOW_ADVANCED", true) @@ -192,7 +192,7 @@ class SettingsFragment : .allowNewDirectoryNameModification(true) .build() - val intent = Intent(context, DirectoryChooserActivity::class.java).apply { + val intent = Intent(requireContext(), DirectoryChooserActivity::class.java).apply { putExtra(DirectoryChooserActivity.EXTRA_CONFIG, config) } @@ -232,10 +232,10 @@ class SettingsFragment : when (key) { "proxy" -> { - summary = getProxyInfo(context).type.name + summary = getProxyInfo(requireContext()).type.name } "dl_location" -> { - summary = getDownloadDirectory(context!!).canonicalPath + summary = getDownloadDirectory(requireContext()).canonicalPath } } } @@ -260,42 +260,42 @@ class SettingsFragment : when (key) { "app_version" -> { - val manager = context.packageManager - val info = manager.getPackageInfo(context.packageName, 0) - summary = context.getString(R.string.settings_app_version_description, info.versionName) + 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 } "delete_cache" -> { - val dir = File(context.cacheDir, "imageCache") + val dir = File(requireContext().cacheDir, "imageCache") summary = getDirSize(dir) onPreferenceClickListener = this@SettingsFragment } "delete_downloads" -> { - val dir = getDownloadDirectory(context) + val dir = getDownloadDirectory(requireContext()) summary = getDirSize(dir) onPreferenceClickListener = this@SettingsFragment } "clear_history" -> { - val histories = (activity!!.application as Pupil).histories + val histories = (requireActivity().application as Pupil).histories summary = getString(R.string.settings_clear_history_summary, histories.size) onPreferenceClickListener = this@SettingsFragment } "dl_location" -> { - summary = getDownloadDirectory(context).canonicalPath + summary = getDownloadDirectory(requireContext()).canonicalPath onPreferenceClickListener = this@SettingsFragment } "default_query" -> { - summary = PreferenceManager.getDefaultSharedPreferences(context).getString("default_query", "") ?: "" + summary = PreferenceManager.getDefaultSharedPreferences(requireContext()).getString("default_query", "") ?: "" onPreferenceClickListener = this@SettingsFragment } "app_lock" -> { - val lockManager = LockManager(context) + val lockManager = LockManager(requireContext()) summary = if (lockManager.locks.isNullOrEmpty()) { getString(R.string.settings_lock_none) @@ -315,7 +315,7 @@ class SettingsFragment : onPreferenceClickListener = this@SettingsFragment } "proxy" -> { - summary = getProxyInfo(context).type.name + summary = getProxyInfo(requireContext()).type.name onPreferenceClickListener = this@SettingsFragment } diff --git a/app/src/main/res/anim/shake.xml b/app/src/main/res/anim/shake.xml new file mode 100644 index 00000000..323768dd --- /dev/null +++ b/app/src/main/res/anim/shake.xml @@ -0,0 +1,24 @@ + + + + \ 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 new file mode 100644 index 00000000..13dcab54 --- /dev/null +++ b/app/src/main/res/anim/shake_cycle.xml @@ -0,0 +1,21 @@ + + + + \ 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 new file mode 100644 index 00000000..197313e3 --- /dev/null +++ b/app/src/main/res/color/lock_fab.xml @@ -0,0 +1,23 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/backspace_outline.xml b/app/src/main/res/drawable/backspace_outline.xml new file mode 100644 index 00000000..201e2e9b --- /dev/null +++ b/app/src/main/res/drawable/backspace_outline.xml @@ -0,0 +1,8 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/fingerprint.xml b/app/src/main/res/drawable/fingerprint.xml index ffa8a34b..bfc10e9f 100644 --- a/app/src/main/res/drawable/fingerprint.xml +++ b/app/src/main/res/drawable/fingerprint.xml @@ -4,5 +4,5 @@ android:width="24dp" android:viewportWidth="24" android:viewportHeight="24"> - + \ No newline at end of file diff --git a/app/src/main/res/drawable/lastpass.xml b/app/src/main/res/drawable/lastpass.xml index 9dbf638b..40265510 100644 --- a/app/src/main/res/drawable/lastpass.xml +++ b/app/src/main/res/drawable/lastpass.xml @@ -4,5 +4,5 @@ android:width="24dp" android:viewportWidth="24" android:viewportHeight="24"> - + \ No newline at end of file diff --git a/app/src/main/res/drawable/lock_pattern.xml b/app/src/main/res/drawable/lock_pattern.xml index f1be51c2..f88355fb 100644 --- a/app/src/main/res/drawable/lock_pattern.xml +++ b/app/src/main/res/drawable/lock_pattern.xml @@ -4,5 +4,5 @@ android:width="24dp" android:viewportWidth="24" android:viewportHeight="24"> - + \ No newline at end of file diff --git a/app/src/main/res/drawable/pin_filled.xml b/app/src/main/res/drawable/pin_filled.xml new file mode 100644 index 00000000..98fe185c --- /dev/null +++ b/app/src/main/res/drawable/pin_filled.xml @@ -0,0 +1,23 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_lock.xml b/app/src/main/res/layout/activity_lock.xml index 00cd2898..db5b51be 100644 --- a/app/src/main/res/layout/activity_lock.xml +++ b/app/src/main/res/layout/activity_lock.xml @@ -36,7 +36,6 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="16dp" - android:layout_marginBottom="32dp" android:gravity="center" app:layout_constraintTop_toBottomOf="@id/lock_content" app:layout_constraintBottom_toTopOf="@id/lock_button_layout"> @@ -46,9 +45,10 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" app:srcCompat="@drawable/fingerprint" + app:backgroundTint="@color/lock_fab" android:layout_marginLeft="8dp" android:layout_marginRight="8dp" - app:backgroundTint="@color/dark_gray" + app:tint="@null" app:fabSize="mini"/> @@ -67,26 +67,29 @@ android:id="@+id/lock_pattern" android:layout_width="wrap_content" android:layout_height="wrap_content" + app:tint="@null" app:srcCompat="@drawable/lock_pattern" - app:backgroundTint="@color/colorPrimary" + app:backgroundTint="@color/lock_fab" app:fabSize="mini"/> diff --git a/app/src/main/res/layout/fragment_pin_lock.xml b/app/src/main/res/layout/fragment_pin_lock.xml new file mode 100644 index 00000000..7099e499 --- /dev/null +++ b/app/src/main/res/layout/fragment_pin_lock.xml @@ -0,0 +1,42 @@ + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml index 710540e2..ee6ea54d 100644 --- a/app/src/main/res/values-ja/strings.xml +++ b/app/src/main/res/values-ja/strings.xml @@ -141,4 +141,7 @@ 旧ギャラリーインポート中… インポート完了 ランダムギャラリーを開く + 予備のロックが設定されていないと指紋ロックは使用できません + Pupil指紋ロック™ + こうかはばつぐんだ! \ No newline at end of file diff --git a/app/src/main/res/values-ko/strings.xml b/app/src/main/res/values-ko/strings.xml index 598da2cc..9c6fe9ab 100644 --- a/app/src/main/res/values-ko/strings.xml +++ b/app/src/main/res/values-ko/strings.xml @@ -141,4 +141,7 @@ 이전 버전 갤러리 가져오는 중… 가져오기 완료 무작위 갤러리 열기 + 지문 잠금은 다른 잠금 방식이 활성화 되어 있을 때만 사용 가능합니다 + Pupil 지문 인식™ + 힘세고 강한 지문 인식 \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index e43da536..874a083c 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -188,6 +188,8 @@ Password Biometrics Fingerprint + Fingerprint can be only enabled if one of the other locks are enabled + Pupil Fingerprint Lock™ Enabled Input same lock once more to confirm Lock Do you want to remove lock? @@ -216,5 +218,6 @@ Importing old galleries… %1$d/%2$d Importing completed + Ah Shit, Here we go again diff --git a/app/src/main/res/xml/lock_preferences.xml b/app/src/main/res/xml/lock_preferences.xml index 3c3baab3..f17e5c01 100644 --- a/app/src/main/res/xml/lock_preferences.xml +++ b/app/src/main/res/xml/lock_preferences.xml @@ -17,7 +17,7 @@ -