= 0) {
- MainActivity.unlocked = false
+ SecureActivityDelegate.locked = true
}
}
diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferenceKeys.kt b/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferenceKeys.kt
index d735bab70c..ca7ddad342 100644
--- a/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferenceKeys.kt
+++ b/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferenceKeys.kt
@@ -131,6 +131,8 @@ object PreferenceKeys {
const val lastUnlock = "last_unlock"
+ const val secureScreen = "secure_screen"
+
const val removeArticles = "remove_articles"
const val skipPreMigration = "skip_pre_migration"
diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferencesHelper.kt b/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferencesHelper.kt
index 008b7e0905..6e595872b9 100644
--- a/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferencesHelper.kt
+++ b/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferencesHelper.kt
@@ -215,6 +215,8 @@ class PreferencesHelper(val context: Context) {
fun lastUnlock() = rxPrefs.getLong(Keys.lastUnlock, 0)
+ fun secureScreen() = rxPrefs.getBoolean(Keys.secureScreen, false)
+
fun removeArticles() = rxPrefs.getBoolean(Keys.removeArticles, false)
fun migrateFlags() = rxPrefs.getInteger("migrate_flags", Int.MAX_VALUE)
diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/base/activity/BaseActivity.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/base/activity/BaseActivity.kt
index 7ce33c448a..d28dd773a3 100644
--- a/app/src/main/java/eu/kanade/tachiyomi/ui/base/activity/BaseActivity.kt
+++ b/app/src/main/java/eu/kanade/tachiyomi/ui/base/activity/BaseActivity.kt
@@ -5,6 +5,9 @@ import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.app.AppCompatDelegate
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
+import eu.kanade.tachiyomi.ui.main.SearchActivity
+import eu.kanade.tachiyomi.ui.security.BiometricActivity
+import eu.kanade.tachiyomi.ui.security.SecureActivityDelegate
import eu.kanade.tachiyomi.util.system.LocaleHelper
import uy.kohesive.injekt.injectLazy
@@ -32,6 +35,12 @@ abstract class BaseActivity : AppCompatActivity() {
else -> R.style.Theme_Tachiyomi
})
super.onCreate(savedInstanceState)
+ SecureActivityDelegate.setSecure(this)
}
+ override fun onResume() {
+ super.onResume()
+ if (this !is BiometricActivity && this !is SearchActivity)
+ SecureActivityDelegate.promptLockIfNeeded(this)
+ }
}
diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/base/activity/BaseRxActivity.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/base/activity/BaseRxActivity.kt
index 7d120f5cb1..4bfe865053 100644
--- a/app/src/main/java/eu/kanade/tachiyomi/ui/base/activity/BaseRxActivity.kt
+++ b/app/src/main/java/eu/kanade/tachiyomi/ui/base/activity/BaseRxActivity.kt
@@ -1,6 +1,8 @@
package eu.kanade.tachiyomi.ui.base.activity
+import android.os.Bundle
import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter
+import eu.kanade.tachiyomi.ui.security.SecureActivityDelegate
import eu.kanade.tachiyomi.util.system.LocaleHelper
import nucleus.view.NucleusAppCompatActivity
@@ -11,4 +13,14 @@ abstract class BaseRxActivity> : NucleusAppCompatActivity
=
- preferences.lastUnlock().getOrDefault() + 60 * 1000 * preferences.lockAfter().getOrDefault())) {
- val intent = Intent(this, BiometricActivity::class.java)
- startActivity(intent)
- this.overridePendingTransition(0, 0)
- }
- }
- else if (useBiometrics)
- preferences.useBiometrics().set(false)
}
private fun getExtensionUpdates() {
@@ -480,7 +468,7 @@ open class MainActivity : BaseActivity(), DownloadServiceListener {
val baseController = router.backstack.last().controller() as? BaseController
if (if (router.backstackSize == 1) !(baseController?.handleRootBack() ?: false)
else !router.handleBack()) {
- unlocked = false
+ SecureActivityDelegate.locked = true
super.onBackPressed()
}
}
@@ -593,8 +581,6 @@ open class MainActivity : BaseActivity(), DownloadServiceListener {
private const val URL_HELP = "https://tachiyomi.org/help/"
- var unlocked = false
-
var usingBottomNav = true
internal set
}
diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/main/SearchActivity.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/main/SearchActivity.kt
index b06364c40b..b8aeeaeb95 100644
--- a/app/src/main/java/eu/kanade/tachiyomi/ui/main/SearchActivity.kt
+++ b/app/src/main/java/eu/kanade/tachiyomi/ui/main/SearchActivity.kt
@@ -22,6 +22,7 @@ import eu.kanade.tachiyomi.ui.base.controller.NoToolbarElevationController
import eu.kanade.tachiyomi.ui.base.controller.TabbedController
import eu.kanade.tachiyomi.ui.base.controller.withFadeTransaction
import eu.kanade.tachiyomi.ui.catalogue.global_search.CatalogueSearchController
+import eu.kanade.tachiyomi.ui.security.SecureActivityDelegate
import eu.kanade.tachiyomi.util.system.getResourceColor
import eu.kanade.tachiyomi.util.view.updateLayoutParams
import eu.kanade.tachiyomi.util.view.updatePadding
@@ -148,7 +149,7 @@ class SearchActivity: MainActivity() {
override fun onBackPressed() {
if (router.backstack.size <= 1 || !router.handleBack()) {
- unlocked = false
+ SecureActivityDelegate.locked = true
super.onBackPressed()
}
}
diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaController.kt
index 766128365f..a8d97343d2 100644
--- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaController.kt
+++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaController.kt
@@ -1,6 +1,7 @@
package eu.kanade.tachiyomi.ui.manga
import android.Manifest.permission.WRITE_EXTERNAL_STORAGE
+import android.app.Activity
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
@@ -29,10 +30,11 @@ import eu.kanade.tachiyomi.ui.main.SearchActivity
import eu.kanade.tachiyomi.ui.manga.chapter.ChaptersController
import eu.kanade.tachiyomi.ui.manga.info.MangaInfoController
import eu.kanade.tachiyomi.ui.manga.track.TrackController
-import kotlinx.android.synthetic.main.search_activity.sTabs
+import eu.kanade.tachiyomi.ui.security.SecureActivityDelegate
import eu.kanade.tachiyomi.util.system.toast
-import kotlinx.android.synthetic.main.main_activity.tabs
-import kotlinx.android.synthetic.main.manga_controller.manga_pager
+import kotlinx.android.synthetic.main.main_activity.*
+import kotlinx.android.synthetic.main.manga_controller.*
+import kotlinx.android.synthetic.main.search_activity.*
import rx.Subscription
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
@@ -98,6 +100,8 @@ class MangaController : RxController, TabbedController {
var startingChapterYPos:Float? = null
+ var isLockedFromSearch = false
+
private var adapter: MangaDetailAdapter? = null
val fromCatalogue = args.getBoolean(FROM_CATALOGUE_EXTRA, false)
@@ -131,6 +135,9 @@ class MangaController : RxController, TabbedController {
manga_pager.offscreenPageLimit = 3
manga_pager.adapter = adapter
+ isLockedFromSearch = activity is SearchActivity &&
+ SecureActivityDelegate.shouldBeLocked()
+
if (!fromCatalogue)
manga_pager.currentItem = CHAPTERS_CONTROLLER
}
@@ -140,6 +147,12 @@ class MangaController : RxController, TabbedController {
adapter = null
}
+ override fun onActivityResumed(activity: Activity) {
+ super.onActivityResumed(activity)
+ isLockedFromSearch = activity is SearchActivity &&
+ SecureActivityDelegate.shouldBeLocked()
+ }
+
override fun onChangeStarted(handler: ControllerChangeHandler, type: ControllerChangeType) {
super.onChangeStarted(handler, type)
if (type.isEnter) {
diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/ChapterHolder.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/ChapterHolder.kt
index fb91361ef2..c5cc1cfc1e 100644
--- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/ChapterHolder.kt
+++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/ChapterHolder.kt
@@ -8,9 +8,11 @@ import eu.kanade.tachiyomi.data.download.model.Download
import eu.kanade.tachiyomi.ui.base.holder.BaseFlexibleViewHolder
import eu.kanade.tachiyomi.util.system.getResourceColor
import eu.kanade.tachiyomi.util.view.gone
+import eu.kanade.tachiyomi.util.view.invisible
import eu.kanade.tachiyomi.util.view.setVectorCompat
+import eu.kanade.tachiyomi.util.view.visible
import kotlinx.android.synthetic.main.chapters_item.*
-import java.util.*
+import java.util.Date
class ChapterHolder(
private val view: View,
@@ -26,7 +28,7 @@ class ChapterHolder(
fun bind(item: ChapterItem, manga: Manga) {
val chapter = item.chapter
-
+ val isLocked = item.isLocked
chapter_title.text = when (manga.displayMode) {
Manga.DISPLAY_NUMBER -> {
val number = adapter.decimalFormat.format(chapter.chapter_number.toDouble())
@@ -35,12 +37,16 @@ class ChapterHolder(
else -> chapter.name
}
+ chapter_menu.visible()
// Set the correct drawable for dropdown and update the tint to match theme.
chapter_menu.setVectorCompat(R.drawable.ic_more_vert_black_24dp, view.context.getResourceColor(R.attr.icon_color))
+ if (isLocked) chapter_menu.invisible()
+
// Set correct text color
- chapter_title.setTextColor(if (chapter.read) adapter.readColor else adapter.unreadColor)
- if (chapter.bookmark) chapter_title.setTextColor(adapter.bookmarkedColor)
+ chapter_title.setTextColor(if (chapter.read && !isLocked)
+ adapter.readColor else adapter.unreadColor)
+ if (chapter.bookmark && !isLocked) chapter_title.setTextColor(adapter.bookmarkedColor)
if (chapter.date_upload > 0) {
chapter_date.text = adapter.dateFormat.format(Date(chapter.date_upload))
@@ -59,7 +65,7 @@ class ChapterHolder(
chapter_title.maxLines = 1
}
- chapter_pages.text = if (!chapter.read && chapter.last_page_read > 0) {
+ chapter_pages.text = if (!chapter.read && chapter.last_page_read > 0 && !isLocked) {
itemView.context.getString(R.string.chapter_progress, chapter.last_page_read + 1)
} else {
""
@@ -81,6 +87,10 @@ class ChapterHolder(
private fun showPopupMenu(view: View) {
val item = adapter.getItem(adapterPosition) ?: return
+ if (item.isLocked) {
+ adapter.unlock()
+ return
+ }
// Create a PopupMenu, giving it the clicked view for an anchor
val popup = PopupMenu(view.context, view)
diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/ChapterItem.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/ChapterItem.kt
index 141bbdc783..c8b3d768ae 100644
--- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/ChapterItem.kt
+++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/ChapterItem.kt
@@ -14,6 +14,7 @@ class ChapterItem(val chapter: Chapter, val manga: Manga) : AbstractFlexibleItem
Chapter by chapter {
private var _status: Int = 0
+ var isLocked = false
var status: Int
get() = download?.status ?: _status
diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/ChaptersAdapter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/ChaptersAdapter.kt
index 2138a2ba78..2e06f365da 100644
--- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/ChaptersAdapter.kt
+++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/ChaptersAdapter.kt
@@ -2,18 +2,20 @@ package eu.kanade.tachiyomi.ui.manga.chapter
import android.content.Context
import android.view.MenuItem
+import androidx.fragment.app.FragmentActivity
import eu.davidea.flexibleadapter.FlexibleAdapter
import eu.kanade.tachiyomi.R
+import eu.kanade.tachiyomi.data.preference.PreferencesHelper
+import eu.kanade.tachiyomi.data.preference.getOrDefault
+import eu.kanade.tachiyomi.ui.security.SecureActivityDelegate
import eu.kanade.tachiyomi.util.system.getResourceColor
+import uy.kohesive.injekt.injectLazy
import java.text.DateFormat
import java.text.DecimalFormat
import java.text.DecimalFormatSymbols
-import eu.kanade.tachiyomi.data.preference.PreferencesHelper
-import eu.kanade.tachiyomi.data.preference.getOrDefault
-import uy.kohesive.injekt.injectLazy
class ChaptersAdapter(
- controller: ChaptersController,
+ val controller: ChaptersController,
context: Context
) : FlexibleAdapter(null, controller, true) {
@@ -43,8 +45,12 @@ class ChaptersAdapter(
return items.indexOf(item)
}
+ fun unlock() {
+ val activity = controller.activity as? FragmentActivity ?: return
+ SecureActivityDelegate.promptLockIfNeeded(activity)
+ }
+
interface OnMenuItemClickListener {
fun onMenuItemClick(position: Int, item: MenuItem)
}
-
}
diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/ChaptersController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/ChaptersController.kt
index 4b7479ade0..018eb26fb3 100644
--- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/ChaptersController.kt
+++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/ChaptersController.kt
@@ -25,12 +25,12 @@ import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.database.models.Chapter
import eu.kanade.tachiyomi.data.database.models.Manga
import eu.kanade.tachiyomi.data.download.model.Download
-import eu.kanade.tachiyomi.data.preference.getOrDefault
import eu.kanade.tachiyomi.ui.base.controller.NucleusController
import eu.kanade.tachiyomi.ui.main.MainActivity
import eu.kanade.tachiyomi.ui.main.SearchActivity
import eu.kanade.tachiyomi.ui.manga.MangaController
import eu.kanade.tachiyomi.ui.reader.ReaderActivity
+import eu.kanade.tachiyomi.ui.security.SecureActivityDelegate
import eu.kanade.tachiyomi.util.system.toast
import eu.kanade.tachiyomi.util.view.doOnApplyWindowInsets
import eu.kanade.tachiyomi.util.view.getCoordinates
@@ -95,6 +95,7 @@ class ChaptersController() : NucleusController(),
// Init RecyclerView and adapter
adapter = ChaptersAdapter(this, view.context)
+ setReadingDrawable()
recycler.adapter = adapter
recycler.layoutManager = LinearLayoutManager(view.context)
@@ -117,6 +118,10 @@ class ChaptersController() : NucleusController(),
swipe_refresh.refreshes().subscribeUntilDestroy { fetchChaptersFromSource() }
fab.clicks().subscribeUntilDestroy {
+ if (activity is SearchActivity && presenter.isLockedFromSearch) {
+ SecureActivityDelegate.promptLockIfNeeded(activity)
+ return@subscribeUntilDestroy
+ }
val item = presenter.getNextUnreadChapter()
if (item != null) {
// Create animation listener
@@ -149,9 +154,29 @@ class ChaptersController() : NucleusController(),
actionMode = null
super.onDestroyView(view)
}
+ /**
+ * Update FAB with correct drawable.
+ *
+ * @param isFavorite determines if manga is favorite or not.
+ */
+ private fun setReadingDrawable() {
+ // Set the Favorite drawable to the correct one.
+ // Border drawable if false, filled drawable if true.
+ fab.setImageResource(
+ when {
+ (parentController as MangaController).isLockedFromSearch -> R.drawable.ic_lock_white_24dp
+ else -> R.drawable.ic_play_arrow_white_24dp
+ }
+ )
+ }
override fun onActivityResumed(activity: Activity) {
+ super.onActivityResumed(activity)
if (view == null) return
+ if (activity is SearchActivity) {
+ presenter.updateLockStatus()
+ setReadingDrawable()
+ }
// Check if animation view is visible
if (reveal_view.visibility == View.VISIBLE) {
@@ -159,11 +184,11 @@ class ChaptersController() : NucleusController(),
val coordinates = fab.getCoordinates()
reveal_view.hideRevealEffect(coordinates.x, coordinates.y, 1920)
}
- super.onActivityResumed(activity)
}
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
- inflater.inflate(R.menu.chapters, menu)
+ if (!(parentController as MangaController).isLockedFromSearch)
+ inflater.inflate(R.menu.chapters, menu)
}
override fun onPrepareOptionsMenu(menu: Menu) {
diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/ChaptersPresenter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/ChaptersPresenter.kt
index dfc4867972..44b5b078c3 100644
--- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/ChaptersPresenter.kt
+++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/ChaptersPresenter.kt
@@ -12,6 +12,7 @@ import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.source.LocalSource
import eu.kanade.tachiyomi.source.Source
import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter
+import eu.kanade.tachiyomi.ui.security.SecureActivityDelegate
import eu.kanade.tachiyomi.util.chapter.syncChaptersWithSource
import eu.kanade.tachiyomi.util.lang.isNullOrUnsubscribed
import rx.Observable
@@ -65,14 +66,28 @@ class ChaptersPresenter(
*/
private var observeDownloadsSubscription: Subscription? = null
+ var isLockedFromSearch = false
+
+ fun updateLockStatus() {
+ val lastCheck = isLockedFromSearch
+ isLockedFromSearch = SecureActivityDelegate.shouldBeLocked()
+ if (lastCheck && lastCheck != isLockedFromSearch) {
+ chapters.forEach {
+ it.isLocked = false
+ }
+ chaptersRelay.call(chapters)
+ }
+ }
+
override fun onCreate(savedState: Bundle?) {
super.onCreate(savedState)
+ isLockedFromSearch = SecureActivityDelegate.shouldBeLocked()
// Prepare the relay.
chaptersRelay.flatMap { applyChapterFilters(it) }
.observeOn(AndroidSchedulers.mainThread())
- .subscribeLatestCache(ChaptersController::onNextChapters,
- { _, error -> Timber.e(error) })
+ .subscribeLatestCache(ChaptersController::onNextChapters
+ ) { _, error -> Timber.e(error) }
// Add the subscription that retrieves the chapters from the database, keeps subscribed to
// changes, and sends the list of chapters to the relay.
@@ -120,6 +135,7 @@ class ChaptersPresenter(
private fun Chapter.toModel(): ChapterItem {
// Create the model object.
val model = ChapterItem(this, manga)
+ model.isLocked = isLockedFromSearch
// Find an active download for this chapter.
val download = downloadManager.queue.find { it.chapter.id == id }
diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/info/MangaInfoController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/info/MangaInfoController.kt
index 7ef2fec77d..87ba0efea7 100644
--- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/info/MangaInfoController.kt
+++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/info/MangaInfoController.kt
@@ -4,6 +4,7 @@ import android.animation.Animator
import android.animation.AnimatorListenerAdapter
import android.animation.AnimatorSet
import android.animation.ObjectAnimator
+import android.app.Activity
import android.app.Dialog
import android.app.PendingIntent
import android.content.ClipData
@@ -61,26 +62,19 @@ import eu.kanade.tachiyomi.ui.catalogue.global_search.CatalogueSearchController
import eu.kanade.tachiyomi.ui.library.ChangeMangaCategoriesDialog
import eu.kanade.tachiyomi.ui.library.LibraryController
import eu.kanade.tachiyomi.ui.main.MainActivity
-import eu.kanade.tachiyomi.ui.main.SearchActivity
import eu.kanade.tachiyomi.ui.manga.MangaController
+import eu.kanade.tachiyomi.ui.security.SecureActivityDelegate
import eu.kanade.tachiyomi.ui.webview.WebViewActivity
-import eu.kanade.tachiyomi.util.view.doOnApplyWindowInsets
import eu.kanade.tachiyomi.util.storage.getUriCompat
+import eu.kanade.tachiyomi.util.system.toast
+import eu.kanade.tachiyomi.util.view.doOnApplyWindowInsets
import eu.kanade.tachiyomi.util.view.marginBottom
import eu.kanade.tachiyomi.util.view.snack
-import eu.kanade.tachiyomi.util.system.toast
import eu.kanade.tachiyomi.util.view.updateLayoutParams
import eu.kanade.tachiyomi.util.view.updatePaddingRelative
import jp.wasabeef.glide.transformations.CropSquareTransformation
import jp.wasabeef.glide.transformations.MaskTransformation
-import kotlinx.android.synthetic.main.edit_manga_dialog.*
import kotlinx.android.synthetic.main.manga_info_controller.*
-import kotlinx.android.synthetic.main.manga_info_controller.manga_artist
-import kotlinx.android.synthetic.main.manga_info_controller.manga_author
-import kotlinx.android.synthetic.main.manga_info_controller.manga_cover
-import kotlinx.android.synthetic.main.manga_info_controller.manga_genres_tags
-import uy.kohesive.injekt.Injekt
-import uy.kohesive.injekt.api.get
import uy.kohesive.injekt.injectLazy
import java.io.File
import java.text.DateFormat
@@ -238,7 +232,8 @@ class MangaInfoController : NucleusController(),
inflater.inflate(R.menu.manga_info, menu)
val editItem = menu.findItem(R.id.action_edit)
- editItem.isVisible = presenter.manga.favorite
+ editItem.isVisible = presenter.manga.favorite &&
+ !(parentController as MangaController).isLockedFromSearch
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
@@ -365,6 +360,11 @@ class MangaInfoController : NucleusController(),
}
}
+ override fun onActivityResumed(activity: Activity) {
+ super.onActivityResumed(activity)
+ setFavoriteDrawable(presenter.manga.favorite)
+ }
+
override fun onDestroyView(view: View) {
manga_genres_tags.setOnTagClickListener(null)
snack?.dismiss()
@@ -466,10 +466,13 @@ class MangaInfoController : NucleusController(),
private fun setFavoriteDrawable(isFavorite: Boolean) {
// Set the Favorite drawable to the correct one.
// Border drawable if false, filled drawable if true.
- fab_favorite?.setImageResource(if (isFavorite)
- R.drawable.ic_bookmark_white_24dp
- else
- R.drawable.ic_add_to_library_24dp)
+ fab_favorite?.setImageResource(
+ when {
+ (parentController as MangaController).isLockedFromSearch -> R.drawable.ic_lock_white_24dp
+ isFavorite -> R.drawable.ic_bookmark_white_24dp
+ else -> R.drawable.ic_add_to_library_24dp
+ }
+ )
}
/**
@@ -510,6 +513,10 @@ class MangaInfoController : NucleusController(),
* Called when the fab is clicked.
*/
private fun onFabClick() {
+ if ((parentController as MangaController).isLockedFromSearch) {
+ SecureActivityDelegate.promptLockIfNeeded(activity)
+ return
+ }
val manga = presenter.manga
toggleFavorite()
if (manga.favorite) {
@@ -689,6 +696,8 @@ class MangaInfoController : NucleusController(),
* @param query the search query to pass to the search controller
*/
private fun performGlobalSearch(query: String) {
+ if ((parentController as MangaController).isLockedFromSearch)
+ return
val router = parentController?.router ?: return
router.pushController(CatalogueSearchController(query).withFadeTransaction())
}
diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/TrackController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/TrackController.kt
index 84cbc43192..71f89f09c0 100644
--- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/TrackController.kt
+++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/TrackController.kt
@@ -1,5 +1,6 @@
package eu.kanade.tachiyomi.ui.manga.track
+import android.app.Activity
import android.content.Intent
import android.net.Uri
import android.view.LayoutInflater
@@ -11,8 +12,12 @@ import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.track.model.TrackSearch
import eu.kanade.tachiyomi.ui.base.controller.NucleusController
import eu.kanade.tachiyomi.ui.manga.MangaController
+import eu.kanade.tachiyomi.ui.security.SecureActivityDelegate
import eu.kanade.tachiyomi.util.system.toast
import eu.kanade.tachiyomi.util.view.RecyclerWindowInsetsListener
+import eu.kanade.tachiyomi.util.view.gone
+import eu.kanade.tachiyomi.util.view.invisible
+import eu.kanade.tachiyomi.util.view.visible
import kotlinx.android.synthetic.main.track_controller.*
import timber.log.Timber
@@ -41,13 +46,31 @@ class TrackController : NucleusController(),
override fun onViewCreated(view: View) {
super.onViewCreated(view)
+ if ((parentController as MangaController).isLockedFromSearch) {
+ swipe_refresh.invisible()
+ unlock_button.visible()
+ unlock_button.setOnClickListener {
+ SecureActivityDelegate.promptLockIfNeeded(activity)
+ }
+ }
+
adapter = TrackAdapter(this)
- with(view) {
- track_recycler.layoutManager = LinearLayoutManager(context)
- track_recycler.adapter = adapter
- track_recycler.setOnApplyWindowInsetsListener(RecyclerWindowInsetsListener)
- swipe_refresh.isEnabled = false
- swipe_refresh.refreshes().subscribeUntilDestroy { presenter.refresh() }
+ track_recycler.layoutManager = LinearLayoutManager(view.context)
+ track_recycler.adapter = adapter
+ track_recycler.setOnApplyWindowInsetsListener(RecyclerWindowInsetsListener)
+ swipe_refresh.isEnabled = false
+ swipe_refresh.refreshes().subscribeUntilDestroy { presenter.refresh() }
+ }
+
+ private fun showTracking() {
+ swipe_refresh.visible()
+ unlock_button.gone()
+ }
+
+ override fun onActivityResumed(activity: Activity) {
+ super.onActivityResumed(activity)
+ if (!(parentController as MangaController).isLockedFromSearch) {
+ showTracking()
}
}
diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderActivity.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderActivity.kt
index 43e749fef4..58515f665f 100644
--- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderActivity.kt
+++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderActivity.kt
@@ -21,7 +21,6 @@ import android.view.animation.Animation
import android.view.animation.AnimationUtils
import android.widget.SeekBar
import androidx.appcompat.app.AppCompatDelegate
-import androidx.biometric.BiometricManager
import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView
import com.google.android.material.bottomsheet.BottomSheetDialog
import eu.kanade.tachiyomi.R
@@ -32,8 +31,6 @@ import eu.kanade.tachiyomi.data.notification.Notifications
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.data.preference.getOrDefault
import eu.kanade.tachiyomi.ui.base.activity.BaseRxActivity
-import eu.kanade.tachiyomi.ui.main.BiometricActivity
-import eu.kanade.tachiyomi.ui.main.MainActivity
import eu.kanade.tachiyomi.ui.reader.ReaderPresenter.SetAsCoverResult.AddToLibraryFirst
import eu.kanade.tachiyomi.ui.reader.ReaderPresenter.SetAsCoverResult.Error
import eu.kanade.tachiyomi.ui.reader.ReaderPresenter.SetAsCoverResult.Success
@@ -45,11 +42,12 @@ import eu.kanade.tachiyomi.ui.reader.viewer.pager.L2RPagerViewer
import eu.kanade.tachiyomi.ui.reader.viewer.pager.R2LPagerViewer
import eu.kanade.tachiyomi.ui.reader.viewer.pager.VerticalPagerViewer
import eu.kanade.tachiyomi.ui.reader.viewer.webtoon.WebtoonViewer
-import eu.kanade.tachiyomi.util.system.launchUI
+import eu.kanade.tachiyomi.ui.security.SecureActivityDelegate
import eu.kanade.tachiyomi.util.lang.plusAssign
import eu.kanade.tachiyomi.util.storage.getUriCompat
import eu.kanade.tachiyomi.util.system.GLUtil
import eu.kanade.tachiyomi.util.system.getResourceColor
+import eu.kanade.tachiyomi.util.system.launchUI
import eu.kanade.tachiyomi.util.system.toast
import eu.kanade.tachiyomi.util.view.gone
import eu.kanade.tachiyomi.util.view.visible
@@ -67,7 +65,6 @@ import rx.subscriptions.CompositeSubscription
import timber.log.Timber
import uy.kohesive.injekt.injectLazy
import java.io.File
-import java.util.Date
import java.util.concurrent.TimeUnit
import kotlin.math.abs
@@ -527,23 +524,6 @@ class ReaderActivity : BaseRxActivity(),
presenter.shareImage(page)
}
- override fun onResume() {
- super.onResume()
- val useBiometrics = preferences.useBiometrics().getOrDefault()
- if (useBiometrics && BiometricManager.from(this)
- .canAuthenticate() == BiometricManager.BIOMETRIC_SUCCESS) {
- if (!MainActivity.unlocked && (preferences.lockAfter().getOrDefault() <= 0 || Date()
- .time >=
- preferences.lastUnlock().getOrDefault() + 60 * 1000 * preferences.lockAfter().getOrDefault())) {
- val intent = Intent(this, BiometricActivity::class.java)
- startActivity(intent)
- this.overridePendingTransition(0, 0)
- }
- }
- else if (useBiometrics)
- preferences.useBiometrics().set(false)
- }
-
/**
* Called from the presenter when a page is ready to be shared. It shows Android's default
* sharing tool.
diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/main/BiometricActivity.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/security/BiometricActivity.kt
similarity index 74%
rename from app/src/main/java/eu/kanade/tachiyomi/ui/main/BiometricActivity.kt
rename to app/src/main/java/eu/kanade/tachiyomi/ui/security/BiometricActivity.kt
index b630cb849d..067e2e4784 100644
--- a/app/src/main/java/eu/kanade/tachiyomi/ui/main/BiometricActivity.kt
+++ b/app/src/main/java/eu/kanade/tachiyomi/ui/security/BiometricActivity.kt
@@ -1,16 +1,15 @@
-package eu.kanade.tachiyomi.ui.main
+package eu.kanade.tachiyomi.ui.security
import android.os.Bundle
import androidx.biometric.BiometricPrompt
import eu.kanade.tachiyomi.R
-import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.ui.base.activity.BaseActivity
-import uy.kohesive.injekt.injectLazy
import java.util.Date
+import java.util.concurrent.ExecutorService
import java.util.concurrent.Executors
class BiometricActivity : BaseActivity() {
- val executor = Executors.newSingleThreadExecutor()
+ private val executor: ExecutorService = Executors.newSingleThreadExecutor()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@@ -24,15 +23,10 @@ class BiometricActivity : BaseActivity() {
override fun onAuthenticationSucceeded(result: BiometricPrompt.AuthenticationResult) {
super.onAuthenticationSucceeded(result)
- MainActivity.unlocked = true
+ SecureActivityDelegate.locked = false
preferences.lastUnlock().set(Date().time)
finish()
}
-
- override fun onAuthenticationFailed() {
- super.onAuthenticationFailed()
- // TODO("Called when a biometric is valid but not recognized.")
- }
})
val promptInfo = BiometricPrompt.PromptInfo.Builder()
diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/security/SecureActivityDelegate.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/security/SecureActivityDelegate.kt
new file mode 100644
index 0000000000..e13ff2b81f
--- /dev/null
+++ b/app/src/main/java/eu/kanade/tachiyomi/ui/security/SecureActivityDelegate.kt
@@ -0,0 +1,57 @@
+package eu.kanade.tachiyomi.ui.security
+
+import android.app.Activity
+import android.content.Intent
+import android.view.WindowManager
+import androidx.biometric.BiometricManager
+import eu.kanade.tachiyomi.data.preference.PreferencesHelper
+import eu.kanade.tachiyomi.data.preference.getOrDefault
+import uy.kohesive.injekt.injectLazy
+import java.util.Date
+
+object SecureActivityDelegate {
+
+ private val preferences by injectLazy()
+
+ var locked: Boolean = true
+
+ fun setSecure(activity: Activity?, force:Boolean? = null) {
+ val enabled = force ?: preferences.secureScreen().getOrDefault()
+ if (enabled) {
+ activity?.window?.setFlags(
+ WindowManager.LayoutParams.FLAG_SECURE,
+ WindowManager.LayoutParams.FLAG_SECURE
+ )
+ } else {
+ activity?.window?.clearFlags(WindowManager.LayoutParams.FLAG_SECURE)
+ }
+ }
+
+ fun promptLockIfNeeded(activity: Activity?) {
+ if (activity == null) return
+ val lockApp = preferences.useBiometrics().getOrDefault()
+ if (lockApp && BiometricManager.from(activity).canAuthenticate() == BiometricManager.BIOMETRIC_SUCCESS) {
+ if (isAppLocked()) {
+ val intent = Intent(activity, BiometricActivity::class.java)
+ activity.startActivity(intent)
+ activity.overridePendingTransition(0, 0)
+ }
+ } else if (lockApp) {
+ preferences.useBiometrics().set(false)
+ }
+ }
+
+ fun shouldBeLocked(): Boolean {
+ val lockApp = preferences.useBiometrics().getOrDefault()
+ if (lockApp && isAppLocked()) return true
+ return false
+ }
+
+ private fun isAppLocked(): Boolean {
+ return locked &&
+ (preferences.lockAfter().getOrDefault() <= 0
+ || Date().time >= preferences.lastUnlock().getOrDefault() + 60 * 1000 * preferences
+ .lockAfter().getOrDefault())
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsGeneralController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsGeneralController.kt
index ba04203382..c1b7d26a61 100644
--- a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsGeneralController.kt
+++ b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsGeneralController.kt
@@ -1,17 +1,14 @@
package eu.kanade.tachiyomi.ui.setting
-import androidx.appcompat.app.AppCompatDelegate
import androidx.biometric.BiometricManager
import androidx.preference.PreferenceScreen
-import com.afollestad.materialdialogs.MaterialDialog
import eu.kanade.tachiyomi.BuildConfig
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.preference.getOrDefault
import eu.kanade.tachiyomi.data.updater.UpdaterJob
-import eu.kanade.tachiyomi.widget.preference.IntListMatPreference
+import eu.kanade.tachiyomi.ui.security.SecureActivityDelegate
import eu.kanade.tachiyomi.util.system.LocaleHelper
-import eu.kanade.tachiyomi.ui.main.MainActivity
-import kotlinx.android.synthetic.main.main_activity.*
+import eu.kanade.tachiyomi.widget.preference.IntListMatPreference
import eu.kanade.tachiyomi.data.preference.PreferenceKeys as Keys
class SettingsGeneralController : SettingsController() {
@@ -97,35 +94,53 @@ class SettingsGeneralController : SettingsController() {
}
}
- val biometricManager = BiometricManager.from(context)
- if (biometricManager.canAuthenticate() == BiometricManager.BIOMETRIC_SUCCESS) {
- var preference:IntListMatPreference? = null
+ preferenceCategory {
+ titleRes = R.string.pref_category_security
+
+ val biometricManager = BiometricManager.from(context)
+ if (biometricManager.canAuthenticate() == BiometricManager.BIOMETRIC_SUCCESS) {
+ var preference: IntListMatPreference? = null
+ switchPreference {
+ key = Keys.useBiometrics
+ titleRes = R.string.lock_with_biometrics
+ defaultValue = false
+
+ onChange {
+ preference?.isVisible = it as Boolean
+ true
+ }
+ }
+ preference = intListPreference(activity) {
+ key = Keys.lockAfter
+ titleRes = R.string.lock_when_idle
+ isVisible = preferences.useBiometrics().getOrDefault()
+ val values = listOf(0, 2, 5, 10, 20, 30, 60, 90, 120, -1)
+ entries = values.mapNotNull {
+ when (it) {
+ 0 -> context.getString(R.string.lock_always)
+ -1 -> context.getString(R.string.lock_never)
+ else -> resources?.getQuantityString(
+ R.plurals.lock_after_mins, it.toInt(), it
+ )
+ }
+ }
+ entryValues = values
+ defaultValue = 0
+ }
+ }
+
switchPreference {
- key = Keys.useBiometrics
- titleRes = R.string.lock_with_biometrics
+ key = Keys.secureScreen
+ titleRes = R.string.pref_secure_screen
+ summaryRes = R.string.pref_secure_screen_summary
defaultValue = false
onChange {
- preference?.isVisible = it as Boolean
+ it as Boolean
+ SecureActivityDelegate.setSecure(activity, it)
true
}
}
- preference = intListPreference(activity) {
- key = Keys.lockAfter
- titleRes = R.string.lock_when_idle
- isVisible = preferences.useBiometrics().getOrDefault()
- val values = listOf(0, 2, 5, 10, 20, 30, 60, 90, 120, -1)
- entries = values.mapNotNull {
- when (it) {
- 0 -> context.getString(R.string.lock_always)
- -1 -> context.getString(R.string.lock_never)
- else -> resources?.getQuantityString(R.plurals.lock_after_mins, it.toInt(),
- it)
- }
- }
- entryValues = values
- defaultValue = 0
- }
}
}
}
diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsLibraryController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsLibraryController.kt
index e105962436..8d2a13a14d 100644
--- a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsLibraryController.kt
+++ b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsLibraryController.kt
@@ -185,7 +185,8 @@ class SettingsLibraryController : SettingsController() {
intListPreference(activity) {
titleRes = R.string.pref_keep_category_sorting
key = Keys.keepCatSort
- summaryRes = R.string.pref_keep_category_sorting_summary
+
+ customSummary = context.getString(R.string.pref_keep_category_sorting_summary)
entries = listOf(
context.getString(R.string.always_ask),
context.getString(R.string.option_keep_category_sort),
diff --git a/app/src/main/java/eu/kanade/tachiyomi/widget/preference/IntListMatPreference.kt b/app/src/main/java/eu/kanade/tachiyomi/widget/preference/IntListMatPreference.kt
index 0b3b8a37a3..f98bf0966f 100644
--- a/app/src/main/java/eu/kanade/tachiyomi/widget/preference/IntListMatPreference.kt
+++ b/app/src/main/java/eu/kanade/tachiyomi/widget/preference/IntListMatPreference.kt
@@ -27,7 +27,8 @@ AttributeSet? =
defValue = defaultValue as? Int ?: defValue
}
override fun getSummary(): CharSequence {
- if (key == null || useCustomSummary) return super.getSummary()
+ if (customSummary != null) return customSummary!!
+ if (key == null) return super.getSummary()
val index = entryValues.indexOf(prefs.getInt(key, defValue).getOrDefault())
return if (entries.isEmpty() || index == -1) ""
else entries[index]
diff --git a/app/src/main/java/eu/kanade/tachiyomi/widget/preference/ListMatPreference.kt b/app/src/main/java/eu/kanade/tachiyomi/widget/preference/ListMatPreference.kt
index 8fad529a36..56103c5b5a 100644
--- a/app/src/main/java/eu/kanade/tachiyomi/widget/preference/ListMatPreference.kt
+++ b/app/src/main/java/eu/kanade/tachiyomi/widget/preference/ListMatPreference.kt
@@ -3,17 +3,11 @@ package eu.kanade.tachiyomi.widget.preference
import android.annotation.SuppressLint
import android.app.Activity
import android.content.Context
-import android.content.SharedPreferences
import android.util.AttributeSet
import androidx.preference.Preference
-import androidx.preference.PreferenceManager
import com.afollestad.materialdialogs.MaterialDialog
import com.afollestad.materialdialogs.list.listItemsSingleChoice
-import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.data.preference.getOrDefault
-import eu.kanade.tachiyomi.ui.setting.defaultValue
-import uy.kohesive.injekt.Injekt
-import uy.kohesive.injekt.api.get
open class ListMatPreference @JvmOverloads constructor(activity: Activity?, context: Context,
attrs: AttributeSet? =
@@ -34,6 +28,7 @@ open class ListMatPreference @JvmOverloads constructor(activity: Activity?, cont
defValue = defaultValue as? String ?: defValue
}
override fun getSummary(): CharSequence {
+ if (customSummary != null) return customSummary!!
val index = entryValues.indexOf(prefs.getStringPref(key, defValue).getOrDefault())
return if (entries.isEmpty() || index == -1) ""
else entries[index]
diff --git a/app/src/main/java/eu/kanade/tachiyomi/widget/preference/MatPreference.kt b/app/src/main/java/eu/kanade/tachiyomi/widget/preference/MatPreference.kt
index 604620ee87..2763838a7b 100644
--- a/app/src/main/java/eu/kanade/tachiyomi/widget/preference/MatPreference.kt
+++ b/app/src/main/java/eu/kanade/tachiyomi/widget/preference/MatPreference.kt
@@ -16,19 +16,10 @@ open class MatPreference @JvmOverloads constructor(val activity: Activity?, cont
null) :
Preference(context, attrs) {
- protected var useCustomSummary = false
protected val prefs: PreferencesHelper = Injekt.get()
private var isShowing = false
+ var customSummary:String? = null
- override fun setSummary(summaryResId: Int) {
- useCustomSummary = true
- super.setSummary(summaryResId)
- }
-
- override fun setSummary(summary: CharSequence?) {
- useCustomSummary = true
- super.setSummary(summary)
- }
override fun onClick() {
if (!isShowing)
dialog().apply {
@@ -37,6 +28,10 @@ open class MatPreference @JvmOverloads constructor(val activity: Activity?, cont
isShowing = true
}
+ override fun getSummary(): CharSequence {
+ return customSummary ?: super.getSummary()
+ }
+
open fun dialog(): MaterialDialog {
return MaterialDialog(activity ?: context).apply {
if (title != null)
diff --git a/app/src/main/java/eu/kanade/tachiyomi/widget/preference/MultiListMatPreference.kt b/app/src/main/java/eu/kanade/tachiyomi/widget/preference/MultiListMatPreference.kt
index 14ea22b901..406fc0ba0f 100644
--- a/app/src/main/java/eu/kanade/tachiyomi/widget/preference/MultiListMatPreference.kt
+++ b/app/src/main/java/eu/kanade/tachiyomi/widget/preference/MultiListMatPreference.kt
@@ -20,10 +20,15 @@ class MultiListMatPreference @JvmOverloads constructor(activity: Activity?, cont
var customSummaryRes:Int
get() = 0
set(value) { customSummary = context.getString(value) }
- var customSummary:String? = null
override fun getSummary(): CharSequence {
- return customSummary ?: super.getSummary()
+ if (customSummary != null) return customSummary!!
+ return prefs.getStringSet(key, emptySet()).getOrDefault().mapNotNull {
+ if (entryValues.indexOf(it) == -1) null
+ else entryValues.indexOf(it) + if (allSelectionRes != null) 1 else 0
+ }.toIntArray().joinToString(",") {
+ entries[it]
+ }
}
@SuppressLint("CheckResult")
diff --git a/app/src/main/res/drawable/ic_lock_white_24dp.xml b/app/src/main/res/drawable/ic_lock_white_24dp.xml
new file mode 100644
index 0000000000..146c066b5f
--- /dev/null
+++ b/app/src/main/res/drawable/ic_lock_white_24dp.xml
@@ -0,0 +1,5 @@
+
+
+
diff --git a/app/src/main/res/layout/track_controller.xml b/app/src/main/res/layout/track_controller.xml
index b0a35bb1b9..bfff5494c2 100644
--- a/app/src/main/res/layout/track_controller.xml
+++ b/app/src/main/res/layout/track_controller.xml
@@ -1,8 +1,10 @@
-
+ android:layout_height="match_parent"
+ xmlns:app="http://schemas.android.com/apk/res-auto">
+
-
+
+
+
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 28076c7a04..080bef7e0b 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -48,6 +48,7 @@
Hiding categories
Manga only
Manwha only
+ Unlock to access trackers
Sorting by %1$s
Sort by: %1$s
@@ -169,6 +170,9 @@
Date format
Check for updates
Automatically check for new app versions
+ Secure screen
+ Hide Tachiyomi from the overview screen
+ Security
Display