Added PIN Lock

This commit is contained in:
tom5079
2020-06-20 22:48:47 +09:00
parent 0d0f2bd827
commit 293ca5b31d
16 changed files with 441 additions and 90 deletions

View File

@@ -52,7 +52,7 @@ android {
dependencies { dependencies {
def markwonVersion = '3.1.0' 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.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.7" implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.7"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android: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 'net.rdrei.android.dirchooser:library:3.2@aar'
implementation 'com.github.chrisbanes:PhotoView:2.3.0' implementation 'com.github.chrisbanes:PhotoView:2.3.0'
implementation 'com.andrognito.patternlockview:patternlockview:1.0.0' implementation 'com.andrognito.patternlockview:patternlockview:1.0.0'
//implementation 'com.andrognito.pinlockview:pinlockview:2.1.0'
implementation "ru.noties.markwon:core:${markwonVersion}" implementation "ru.noties.markwon:core:${markwonVersion}"
testImplementation 'junit:junit:4.13' testImplementation 'junit:junit:4.13'
androidTestImplementation 'androidx.test.ext:junit:1.1.1' androidTestImplementation 'androidx.test.ext:junit:1.1.1'

Binary file not shown.

View File

@@ -21,62 +21,26 @@ package xyz.quaver.pupil.ui
import android.app.Activity import android.app.Activity
import android.app.AlertDialog import android.app.AlertDialog
import android.os.Bundle import android.os.Bundle
import android.view.animation.Animation
import android.view.animation.AnimationUtils
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import com.andrognito.patternlockview.PatternLockView import com.andrognito.patternlockview.PatternLockView
import com.google.android.material.snackbar.Snackbar import com.google.android.material.snackbar.Snackbar
import kotlinx.android.synthetic.main.activity_lock.* import kotlinx.android.synthetic.main.activity_lock.*
import kotlinx.android.synthetic.main.fragment_pattern_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.R
import xyz.quaver.pupil.ui.fragment.PINLockFragment
import xyz.quaver.pupil.ui.fragment.PatternLockFragment import xyz.quaver.pupil.ui.fragment.PatternLockFragment
import xyz.quaver.pupil.util.Lock import xyz.quaver.pupil.util.Lock
import xyz.quaver.pupil.util.LockManager import xyz.quaver.pupil.util.LockManager
class LockActivity : AppCompatActivity() { class LockActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) { private lateinit var lockManager: LockManager
super.onCreate(savedInstanceState) private var mode: String? = null
setContentView(R.layout.activity_lock)
val lockManager = try { private val patternLockFragment = PatternLockFragment().apply {
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
}
val mode = intent.getStringExtra("mode")
lock_pattern.isEnabled = false
lock_pin.isEnabled = false
lock_fingerprint.isEnabled = false
lock_password.isEnabled = false
when(mode) {
null -> {
if (lockManager.isEmpty()) {
setResult(RESULT_OK)
finish()
return
}
}
"add_lock" -> {
when(intent.getStringExtra("type")!!) {
"pattern" -> {
}
}
}
}
supportFragmentManager.beginTransaction().add(
R.id.lock_content,
PatternLockFragment().apply {
var lastPass = "" var lastPass = ""
onPatternDrawn = { onPatternDrawn = {
when(mode) { when(mode) {
@@ -109,7 +73,156 @@ class LockActivity : AppCompatActivity() {
} }
} }
} }
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()
}
}
}
}
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_lock)
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")
when(mode) {
null -> {
if (lockManager.isEmpty()) {
setResult(RESULT_OK)
finish()
return
}
lock_pattern.apply {
isEnabled = lockManager.contains(Lock.Type.PATTERN)
setOnClickListener {
supportFragmentManager.beginTransaction().replace(
R.id.lock_content, patternLockFragment
).commit() ).commit()
} }
}
lock_pin.apply {
isEnabled = lockManager.contains(Lock.Type.PIN)
setOnClickListener {
supportFragmentManager.beginTransaction().replace(
R.id.lock_content, pinLockFragment
).commit()
}
}
lock_fingerprint.isEnabled = false
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()
}
}
}
}
}
} }

View File

@@ -28,18 +28,25 @@ import xyz.quaver.pupil.ui.LockActivity
import xyz.quaver.pupil.util.Lock import xyz.quaver.pupil.util.Lock
import xyz.quaver.pupil.util.LockManager import xyz.quaver.pupil.util.LockManager
class LockFragment : PreferenceFragmentCompat() { class LockFragment :
PreferenceFragmentCompat() {
override fun onResume() { override fun onResume() {
super.onResume() super.onResume()
val lockManager = LockManager(context!!) val lockManager = LockManager(requireContext())
findPreference<Preference>("lock_pattern")?.summary = findPreference<Preference>("lock_pattern")?.summary =
if (lockManager.contains(Lock.Type.PATTERN)) if (lockManager.contains(Lock.Type.PATTERN))
getString(R.string.settings_lock_enabled) getString(R.string.settings_lock_enabled)
else else
"" ""
findPreference<Preference>("lock_pin")?.summary =
if (lockManager.contains(Lock.Type.PIN))
getString(R.string.settings_lock_enabled)
else
""
} }
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
@@ -48,14 +55,14 @@ class LockFragment : PreferenceFragmentCompat() {
with(findPreference<Preference>("lock_pattern")) { with(findPreference<Preference>("lock_pattern")) {
this!! this!!
if (LockManager(context!!).contains(Lock.Type.PATTERN)) if (LockManager(requireContext()).contains(Lock.Type.PATTERN))
summary = getString(R.string.settings_lock_enabled) summary = getString(R.string.settings_lock_enabled)
onPreferenceClickListener = Preference.OnPreferenceClickListener { onPreferenceClickListener = Preference.OnPreferenceClickListener {
val lockManager = LockManager(context!!) val lockManager = LockManager(requireContext())
if (lockManager.contains(Lock.Type.PATTERN)) { if (lockManager.contains(Lock.Type.PATTERN)) {
AlertDialog.Builder(context).apply { AlertDialog.Builder(requireContext()).apply {
setTitle(R.string.warning) setTitle(R.string.warning)
setMessage(R.string.settings_lock_remove_message) setMessage(R.string.settings_lock_remove_message)
@@ -66,7 +73,7 @@ class LockFragment : PreferenceFragmentCompat() {
setNegativeButton(android.R.string.no) { _, _ -> } setNegativeButton(android.R.string.no) { _, _ -> }
}.show() }.show()
} else { } else {
val intent = Intent(context, LockActivity::class.java).apply { val intent = Intent(requireContext(), LockActivity::class.java).apply {
putExtra("mode", "add_lock") putExtra("mode", "add_lock")
putExtra("type", "pattern") putExtra("type", "pattern")
} }
@@ -77,5 +84,38 @@ class LockFragment : PreferenceFragmentCompat() {
true true
} }
} }
with(findPreference<Preference>("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
}
}
} }
} }

View File

@@ -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 <http://www.gnu.org/licenses/>.
*/
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?) {
}
}

View File

@@ -56,13 +56,13 @@ class SettingsFragment :
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
PreferenceManager.getDefaultSharedPreferences(context).registerOnSharedPreferenceChangeListener(this) PreferenceManager.getDefaultSharedPreferences(requireContext()).registerOnSharedPreferenceChangeListener(this)
} }
override fun onResume() { override fun onResume() {
super.onResume() super.onResume()
val lockManager = LockManager(context!!) val lockManager = LockManager(requireContext())
findPreference<Preference>("app_lock")?.summary = if (lockManager.locks.isNullOrEmpty()) { findPreference<Preference>("app_lock")?.summary = if (lockManager.locks.isNullOrEmpty()) {
getString(R.string.settings_lock_none) getString(R.string.settings_lock_none)
@@ -92,9 +92,9 @@ class SettingsFragment :
checkUpdate(activity as SettingsActivity, true) checkUpdate(activity as SettingsActivity, true)
} }
"delete_cache" -> { "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) setTitle(R.string.warning)
setMessage(R.string.settings_clear_cache_alert_message) setMessage(R.string.settings_clear_cache_alert_message)
setPositiveButton(android.R.string.yes) { _, _ -> setPositiveButton(android.R.string.yes) { _, _ ->
@@ -107,9 +107,9 @@ class SettingsFragment :
}.show() }.show()
} }
"delete_downloads" -> { "delete_downloads" -> {
val dir = getDownloadDirectory(context) val dir = getDownloadDirectory(requireContext())
AlertDialog.Builder(context).apply { AlertDialog.Builder(requireContext()).apply {
setTitle(R.string.warning) setTitle(R.string.warning)
setMessage(R.string.settings_clear_downloads_alert_message) setMessage(R.string.settings_clear_downloads_alert_message)
setPositiveButton(android.R.string.yes) { _, _ -> setPositiveButton(android.R.string.yes) { _, _ ->
@@ -122,9 +122,9 @@ class SettingsFragment :
}.show() }.show()
} }
"clear_history" -> { "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) setTitle(R.string.warning)
setMessage(R.string.settings_clear_history_alert_message) setMessage(R.string.settings_clear_history_alert_message)
setPositiveButton(android.R.string.yes) { _, _ -> setPositiveButton(android.R.string.yes) { _, _ ->
@@ -135,10 +135,10 @@ class SettingsFragment :
}.show() }.show()
} }
"dl_location" -> { "dl_location" -> {
DownloadLocationDialog(activity!!).show() DownloadLocationDialog(requireActivity()).show()
} }
"default_query" -> { "default_query" -> {
DefaultQueryDialog(context).apply { DefaultQueryDialog(requireContext()).apply {
onPositiveButtonClickListener = { newTags -> onPositiveButtonClickListener = { newTags ->
sharedPreferences.edit().putString("default_query", newTags.toString()).apply() sharedPreferences.edit().putString("default_query", newTags.toString()).apply()
summary = newTags.toString() summary = newTags.toString()
@@ -146,20 +146,20 @@ class SettingsFragment :
}.show() }.show()
} }
"app_lock" -> { "app_lock" -> {
val intent = Intent(context, LockActivity::class.java) val intent = Intent(requireContext(), LockActivity::class.java)
activity?.startActivityForResult(intent, REQUEST_LOCK) activity?.startActivityForResult(intent, REQUEST_LOCK)
} }
"mirrors" -> { "mirrors" -> {
MirrorDialog(context) MirrorDialog(requireContext())
.show() .show()
} }
"proxy" -> { "proxy" -> {
ProxyDialog(context) ProxyDialog(requireContext())
.show() .show()
} }
"backup" -> { "backup" -> {
File(ContextCompat.getDataDir(context), "favorites.json").copyTo( File(ContextCompat.getDataDir(requireContext()), "favorites.json").copyTo(
File(getDownloadDirectory(context), "favorites.json"), File(getDownloadDirectory(requireContext()), "favorites.json"),
true true
) )
@@ -177,8 +177,8 @@ class SettingsFragment :
"old_import_galleries" -> { "old_import_galleries" -> {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
if (ContextCompat.checkSelfPermission(context, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) if (ContextCompat.checkSelfPermission(requireContext(), Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED)
ActivityCompat.requestPermissions(activity!!, arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE), REQUEST_WRITE_PERMISSION_AND_SAF) ActivityCompat.requestPermissions(requireActivity(), arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE), REQUEST_WRITE_PERMISSION_AND_SAF)
else { else {
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE).apply { val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE).apply {
putExtra("android.content.extra.SHOW_ADVANCED", true) putExtra("android.content.extra.SHOW_ADVANCED", true)
@@ -192,7 +192,7 @@ class SettingsFragment :
.allowNewDirectoryNameModification(true) .allowNewDirectoryNameModification(true)
.build() .build()
val intent = Intent(context, DirectoryChooserActivity::class.java).apply { val intent = Intent(requireContext(), DirectoryChooserActivity::class.java).apply {
putExtra(DirectoryChooserActivity.EXTRA_CONFIG, config) putExtra(DirectoryChooserActivity.EXTRA_CONFIG, config)
} }
@@ -232,10 +232,10 @@ class SettingsFragment :
when (key) { when (key) {
"proxy" -> { "proxy" -> {
summary = getProxyInfo(context).type.name summary = getProxyInfo(requireContext()).type.name
} }
"dl_location" -> { "dl_location" -> {
summary = getDownloadDirectory(context!!).canonicalPath summary = getDownloadDirectory(requireContext()).canonicalPath
} }
} }
} }
@@ -260,42 +260,42 @@ class SettingsFragment :
when (key) { when (key) {
"app_version" -> { "app_version" -> {
val manager = context.packageManager val manager = requireContext().packageManager
val info = manager.getPackageInfo(context.packageName, 0) val info = manager.getPackageInfo(requireContext().packageName, 0)
summary = context.getString(R.string.settings_app_version_description, info.versionName) summary = requireContext().getString(R.string.settings_app_version_description, info.versionName)
onPreferenceClickListener = this@SettingsFragment onPreferenceClickListener = this@SettingsFragment
} }
"delete_cache" -> { "delete_cache" -> {
val dir = File(context.cacheDir, "imageCache") val dir = File(requireContext().cacheDir, "imageCache")
summary = getDirSize(dir) summary = getDirSize(dir)
onPreferenceClickListener = this@SettingsFragment onPreferenceClickListener = this@SettingsFragment
} }
"delete_downloads" -> { "delete_downloads" -> {
val dir = getDownloadDirectory(context) val dir = getDownloadDirectory(requireContext())
summary = getDirSize(dir) summary = getDirSize(dir)
onPreferenceClickListener = this@SettingsFragment onPreferenceClickListener = this@SettingsFragment
} }
"clear_history" -> { "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) summary = getString(R.string.settings_clear_history_summary, histories.size)
onPreferenceClickListener = this@SettingsFragment onPreferenceClickListener = this@SettingsFragment
} }
"dl_location" -> { "dl_location" -> {
summary = getDownloadDirectory(context).canonicalPath summary = getDownloadDirectory(requireContext()).canonicalPath
onPreferenceClickListener = this@SettingsFragment onPreferenceClickListener = this@SettingsFragment
} }
"default_query" -> { "default_query" -> {
summary = PreferenceManager.getDefaultSharedPreferences(context).getString("default_query", "") ?: "" summary = PreferenceManager.getDefaultSharedPreferences(requireContext()).getString("default_query", "") ?: ""
onPreferenceClickListener = this@SettingsFragment onPreferenceClickListener = this@SettingsFragment
} }
"app_lock" -> { "app_lock" -> {
val lockManager = LockManager(context) val lockManager = LockManager(requireContext())
summary = summary =
if (lockManager.locks.isNullOrEmpty()) { if (lockManager.locks.isNullOrEmpty()) {
getString(R.string.settings_lock_none) getString(R.string.settings_lock_none)
@@ -315,7 +315,7 @@ class SettingsFragment :
onPreferenceClickListener = this@SettingsFragment onPreferenceClickListener = this@SettingsFragment
} }
"proxy" -> { "proxy" -> {
summary = getProxyInfo(context).type.name summary = getProxyInfo(requireContext()).type.name
onPreferenceClickListener = this@SettingsFragment onPreferenceClickListener = this@SettingsFragment
} }

View File

@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ 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 <http://www.gnu.org/licenses/>.
-->
<translate xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="300"
android:fromXDelta="0"
android:interpolator="@anim/shake_cycle"
android:toXDelta="10" />

View File

@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ 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 <http://www.gnu.org/licenses/>.
-->
<cycleInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
android:cycles="3" />

View File

@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ 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 <http://www.gnu.org/licenses/>.
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_enabled="false" android:color="@android:color/darker_gray"/>
<item android:color="@color/colorPrimary"/>
</selector>

View File

@@ -0,0 +1,8 @@
<!-- drawable/backspace_outline.xml -->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:height="24dp"
android:width="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path android:fillColor="#000" android:pathData="M19,15.59L17.59,17L14,13.41L10.41,17L9,15.59L12.59,12L9,8.41L10.41,7L14,10.59L17.59,7L19,8.41L15.41,12L19,15.59M22,3A2,2 0 0,1 24,5V19A2,2 0 0,1 22,21H7C6.31,21 5.77,20.64 5.41,20.11L0,12L5.41,3.88C5.77,3.35 6.31,3 7,3H22M22,5H7L2.28,12L7,19H22V5Z" />
</vector>

View File

@@ -4,5 +4,5 @@
android:width="24dp" android:width="24dp"
android:viewportWidth="24" android:viewportWidth="24"
android:viewportHeight="24"> android:viewportHeight="24">
<path android:fillColor="#000" android:pathData="M17.81,4.47C17.73,4.47 17.65,4.45 17.58,4.41C15.66,3.42 14,3 12,3C10.03,3 8.15,3.47 6.44,4.41C6.2,4.54 5.9,4.45 5.76,4.21C5.63,3.97 5.72,3.66 5.96,3.53C7.82,2.5 9.86,2 12,2C14.14,2 16,2.47 18.04,3.5C18.29,3.65 18.38,3.95 18.25,4.19C18.16,4.37 18,4.47 17.81,4.47M3.5,9.72C3.4,9.72 3.3,9.69 3.21,9.63C3,9.47 2.93,9.16 3.09,8.93C4.08,7.53 5.34,6.43 6.84,5.66C10,4.04 14,4.03 17.15,5.65C18.65,6.42 19.91,7.5 20.9,8.9C21.06,9.12 21,9.44 20.78,9.6C20.55,9.76 20.24,9.71 20.08,9.5C19.18,8.22 18.04,7.23 16.69,6.54C13.82,5.07 10.15,5.07 7.29,6.55C5.93,7.25 4.79,8.25 3.89,9.5C3.81,9.65 3.66,9.72 3.5,9.72M9.75,21.79C9.62,21.79 9.5,21.74 9.4,21.64C8.53,20.77 8.06,20.21 7.39,19C6.7,17.77 6.34,16.27 6.34,14.66C6.34,11.69 8.88,9.27 12,9.27C15.12,9.27 17.66,11.69 17.66,14.66A0.5,0.5 0 0,1 17.16,15.16A0.5,0.5 0 0,1 16.66,14.66C16.66,12.24 14.57,10.27 12,10.27C9.43,10.27 7.34,12.24 7.34,14.66C7.34,16.1 7.66,17.43 8.27,18.5C8.91,19.66 9.35,20.15 10.12,20.93C10.31,21.13 10.31,21.44 10.12,21.64C10,21.74 9.88,21.79 9.75,21.79M16.92,19.94C15.73,19.94 14.68,19.64 13.82,19.05C12.33,18.04 11.44,16.4 11.44,14.66A0.5,0.5 0 0,1 11.94,14.16A0.5,0.5 0 0,1 12.44,14.66C12.44,16.07 13.16,17.4 14.38,18.22C15.09,18.7 15.92,18.93 16.92,18.93C17.16,18.93 17.56,18.9 17.96,18.83C18.23,18.78 18.5,18.96 18.54,19.24C18.59,19.5 18.41,19.77 18.13,19.82C17.56,19.93 17.06,19.94 16.92,19.94M14.91,22C14.87,22 14.82,22 14.78,22C13.19,21.54 12.15,20.95 11.06,19.88C9.66,18.5 8.89,16.64 8.89,14.66C8.89,13.04 10.27,11.72 11.97,11.72C13.67,11.72 15.05,13.04 15.05,14.66C15.05,15.73 16,16.6 17.13,16.6C18.28,16.6 19.21,15.73 19.21,14.66C19.21,10.89 15.96,7.83 11.96,7.83C9.12,7.83 6.5,9.41 5.35,11.86C4.96,12.67 4.76,13.62 4.76,14.66C4.76,15.44 4.83,16.67 5.43,18.27C5.53,18.53 5.4,18.82 5.14,18.91C4.88,19 4.59,18.87 4.5,18.62C4,17.31 3.77,16 3.77,14.66C3.77,13.46 4,12.37 4.45,11.42C5.78,8.63 8.73,6.82 11.96,6.82C16.5,6.82 20.21,10.33 20.21,14.65C20.21,16.27 18.83,17.59 17.13,17.59C15.43,17.59 14.05,16.27 14.05,14.65C14.05,13.58 13.12,12.71 11.97,12.71C10.82,12.71 9.89,13.58 9.89,14.65C9.89,16.36 10.55,17.96 11.76,19.16C12.71,20.1 13.62,20.62 15.03,21C15.3,21.08 15.45,21.36 15.38,21.62C15.33,21.85 15.12,22 14.91,22Z" /> <path android:fillColor="#fff" android:pathData="M17.81,4.47C17.73,4.47 17.65,4.45 17.58,4.41C15.66,3.42 14,3 12,3C10.03,3 8.15,3.47 6.44,4.41C6.2,4.54 5.9,4.45 5.76,4.21C5.63,3.97 5.72,3.66 5.96,3.53C7.82,2.5 9.86,2 12,2C14.14,2 16,2.47 18.04,3.5C18.29,3.65 18.38,3.95 18.25,4.19C18.16,4.37 18,4.47 17.81,4.47M3.5,9.72C3.4,9.72 3.3,9.69 3.21,9.63C3,9.47 2.93,9.16 3.09,8.93C4.08,7.53 5.34,6.43 6.84,5.66C10,4.04 14,4.03 17.15,5.65C18.65,6.42 19.91,7.5 20.9,8.9C21.06,9.12 21,9.44 20.78,9.6C20.55,9.76 20.24,9.71 20.08,9.5C19.18,8.22 18.04,7.23 16.69,6.54C13.82,5.07 10.15,5.07 7.29,6.55C5.93,7.25 4.79,8.25 3.89,9.5C3.81,9.65 3.66,9.72 3.5,9.72M9.75,21.79C9.62,21.79 9.5,21.74 9.4,21.64C8.53,20.77 8.06,20.21 7.39,19C6.7,17.77 6.34,16.27 6.34,14.66C6.34,11.69 8.88,9.27 12,9.27C15.12,9.27 17.66,11.69 17.66,14.66A0.5,0.5 0 0,1 17.16,15.16A0.5,0.5 0 0,1 16.66,14.66C16.66,12.24 14.57,10.27 12,10.27C9.43,10.27 7.34,12.24 7.34,14.66C7.34,16.1 7.66,17.43 8.27,18.5C8.91,19.66 9.35,20.15 10.12,20.93C10.31,21.13 10.31,21.44 10.12,21.64C10,21.74 9.88,21.79 9.75,21.79M16.92,19.94C15.73,19.94 14.68,19.64 13.82,19.05C12.33,18.04 11.44,16.4 11.44,14.66A0.5,0.5 0 0,1 11.94,14.16A0.5,0.5 0 0,1 12.44,14.66C12.44,16.07 13.16,17.4 14.38,18.22C15.09,18.7 15.92,18.93 16.92,18.93C17.16,18.93 17.56,18.9 17.96,18.83C18.23,18.78 18.5,18.96 18.54,19.24C18.59,19.5 18.41,19.77 18.13,19.82C17.56,19.93 17.06,19.94 16.92,19.94M14.91,22C14.87,22 14.82,22 14.78,22C13.19,21.54 12.15,20.95 11.06,19.88C9.66,18.5 8.89,16.64 8.89,14.66C8.89,13.04 10.27,11.72 11.97,11.72C13.67,11.72 15.05,13.04 15.05,14.66C15.05,15.73 16,16.6 17.13,16.6C18.28,16.6 19.21,15.73 19.21,14.66C19.21,10.89 15.96,7.83 11.96,7.83C9.12,7.83 6.5,9.41 5.35,11.86C4.96,12.67 4.76,13.62 4.76,14.66C4.76,15.44 4.83,16.67 5.43,18.27C5.53,18.53 5.4,18.82 5.14,18.91C4.88,19 4.59,18.87 4.5,18.62C4,17.31 3.77,16 3.77,14.66C3.77,13.46 4,12.37 4.45,11.42C5.78,8.63 8.73,6.82 11.96,6.82C16.5,6.82 20.21,10.33 20.21,14.65C20.21,16.27 18.83,17.59 17.13,17.59C15.43,17.59 14.05,16.27 14.05,14.65C14.05,13.58 13.12,12.71 11.97,12.71C10.82,12.71 9.89,13.58 9.89,14.65C9.89,16.36 10.55,17.96 11.76,19.16C12.71,20.1 13.62,20.62 15.03,21C15.3,21.08 15.45,21.36 15.38,21.62C15.33,21.85 15.12,22 14.91,22Z" />
</vector> </vector>

View File

@@ -4,5 +4,5 @@
android:width="24dp" android:width="24dp"
android:viewportWidth="24" android:viewportWidth="24"
android:viewportHeight="24"> android:viewportHeight="24">
<path android:fillColor="#000" android:pathData="M14,12A2,2 0 0,1 16,10A2,2 0 0,1 18,12A2,2 0 0,1 16,14A2,2 0 0,1 14,12M8,12A2,2 0 0,1 10,10A2,2 0 0,1 12,12A2,2 0 0,1 10,14A2,2 0 0,1 8,12M2,12A2,2 0 0,1 4,10A2,2 0 0,1 6,12A2,2 0 0,1 4,14A2,2 0 0,1 2,12M22,5H20V19H22V5Z" /> <path android:fillColor="#fff" android:pathData="M14,12A2,2 0 0,1 16,10A2,2 0 0,1 18,12A2,2 0 0,1 16,14A2,2 0 0,1 14,12M8,12A2,2 0 0,1 10,10A2,2 0 0,1 12,12A2,2 0 0,1 10,14A2,2 0 0,1 8,12M2,12A2,2 0 0,1 4,10A2,2 0 0,1 6,12A2,2 0 0,1 4,14A2,2 0 0,1 2,12M22,5H20V19H22V5Z" />
</vector> </vector>

View File

@@ -4,5 +4,5 @@
android:width="24dp" android:width="24dp"
android:viewportWidth="24" android:viewportWidth="24"
android:viewportHeight="24"> android:viewportHeight="24">
<path android:fillColor="#000" android:pathData="M7,3A4,4 0 0,1 11,7C11,8.86 9.73,10.43 8,10.87V13.13C8.37,13.22 8.72,13.37 9.04,13.56L13.56,9.04C13.2,8.44 13,7.75 13,7A4,4 0 0,1 17,3A4,4 0 0,1 21,7A4,4 0 0,1 17,11C16.26,11 15.57,10.8 15,10.45L10.45,15C10.8,15.57 11,16.26 11,17A4,4 0 0,1 7,21A4,4 0 0,1 3,17C3,15.14 4.27,13.57 6,13.13V10.87C4.27,10.43 3,8.86 3,7A4,4 0 0,1 7,3M17,13A4,4 0 0,1 21,17A4,4 0 0,1 17,21A4,4 0 0,1 13,17A4,4 0 0,1 17,13M17,15A2,2 0 0,0 15,17A2,2 0 0,0 17,19A2,2 0 0,0 19,17A2,2 0 0,0 17,15Z" /> <path android:fillColor="#fff" android:pathData="M7,3A4,4 0 0,1 11,7C11,8.86 9.73,10.43 8,10.87V13.13C8.37,13.22 8.72,13.37 9.04,13.56L13.56,9.04C13.2,8.44 13,7.75 13,7A4,4 0 0,1 17,3A4,4 0 0,1 21,7A4,4 0 0,1 17,11C16.26,11 15.57,10.8 15,10.45L10.45,15C10.8,15.57 11,16.26 11,17A4,4 0 0,1 7,21A4,4 0 0,1 3,17C3,15.14 4.27,13.57 6,13.13V10.87C4.27,10.43 3,8.86 3,7A4,4 0 0,1 7,3M17,13A4,4 0 0,1 21,17A4,4 0 0,1 17,21A4,4 0 0,1 13,17A4,4 0 0,1 17,13M17,15A2,2 0 0,0 15,17A2,2 0 0,0 17,19A2,2 0 0,0 19,17A2,2 0 0,0 17,15Z" />
</vector> </vector>

View File

@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ 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 <http://www.gnu.org/licenses/>.
-->
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<solid android:color="@color/colorAccent" />
</shape>

View File

@@ -36,7 +36,6 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="16dp" android:layout_marginTop="16dp"
android:layout_marginBottom="32dp"
android:gravity="center" android:gravity="center"
app:layout_constraintTop_toBottomOf="@id/lock_content" app:layout_constraintTop_toBottomOf="@id/lock_content"
app:layout_constraintBottom_toTopOf="@id/lock_button_layout"> app:layout_constraintBottom_toTopOf="@id/lock_button_layout">
@@ -46,9 +45,10 @@
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
app:srcCompat="@drawable/fingerprint" app:srcCompat="@drawable/fingerprint"
app:backgroundTint="@color/lock_fab"
android:layout_marginLeft="8dp" android:layout_marginLeft="8dp"
android:layout_marginRight="8dp" android:layout_marginRight="8dp"
app:backgroundTint="@color/dark_gray" app:tint="@null"
app:fabSize="mini"/> app:fabSize="mini"/>
</LinearLayout> </LinearLayout>
@@ -67,26 +67,29 @@
android:id="@+id/lock_pattern" android:id="@+id/lock_pattern"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
app:tint="@null"
app:srcCompat="@drawable/lock_pattern" app:srcCompat="@drawable/lock_pattern"
app:backgroundTint="@color/colorPrimary" app:backgroundTint="@color/lock_fab"
app:fabSize="mini"/> app:fabSize="mini"/>
<com.google.android.material.floatingactionbutton.FloatingActionButton <com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/lock_pin" android:id="@+id/lock_pin"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
app:tint="@null"
app:srcCompat="@drawable/numeric" app:srcCompat="@drawable/numeric"
app:backgroundTint="@color/lock_fab"
android:layout_marginLeft="8dp" android:layout_marginLeft="8dp"
android:layout_marginRight="8dp" android:layout_marginRight="8dp"
app:backgroundTint="@color/dark_gray"
app:fabSize="mini"/> app:fabSize="mini"/>
<com.google.android.material.floatingactionbutton.FloatingActionButton <com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/lock_password" android:id="@+id/lock_password"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
app:tint="@null"
app:srcCompat="@drawable/lastpass" app:srcCompat="@drawable/lastpass"
app:backgroundTint="@color/dark_gray" app:backgroundTint="@color/lock_fab"
app:fabSize="mini"/> app:fabSize="mini"/>
</LinearLayout> </LinearLayout>

View File

@@ -0,0 +1,42 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ 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 <http://www.gnu.org/licenses/>.
-->
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:paddingTop="100dp">
<com.andrognito.pinlockview.IndicatorDots
android:id="@+id/indicator_dots"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal|top"
app:dotFilledBackground="@drawable/pin_filled"/>
<com.andrognito.pinlockview.PinLockView
android:id="@+id/pin_lock_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:keypadTextColor="?android:attr/textColorPrimary"
android:layout_gravity="center_horizontal|bottom"
app:keypadDeleteButtonDrawable="@drawable/backspace_outline"
app:keypadShowDeleteButton="true"/>
</FrameLayout>