mirror of
https://github.com/tachiyomiorg/tachiyomi.git
synced 2024-12-23 05:21:47 +01:00
Merge pull request #3 from lmj0011/dev-settings-search-highlighter
implement preference highlighting after settings search
This commit is contained in:
commit
f10fe8bf02
@ -165,6 +165,48 @@ object PreferenceKeys {
|
|||||||
|
|
||||||
const val enableDoh = "enable_doh"
|
const val enableDoh = "enable_doh"
|
||||||
|
|
||||||
|
const val disableBatteryOptimization = "pref_disable_battery_optimization"
|
||||||
|
|
||||||
|
const val clearDatabase = "pref_clear_database"
|
||||||
|
|
||||||
|
const val clearCookies = "pref_clear_cookies"
|
||||||
|
|
||||||
|
const val refreshLibraryCovers = "pref_refresh_library_covers"
|
||||||
|
|
||||||
|
const val refreshLibraryTracking = "pref_refresh_library_tracking"
|
||||||
|
|
||||||
|
const val createBackup = "pref_create_backup"
|
||||||
|
|
||||||
|
const val restoreBackup = "pref_restore_backup"
|
||||||
|
|
||||||
|
const val manageNotifications = "pref_manage_notifications"
|
||||||
|
|
||||||
|
const val libraryColumns = "pref_library_columns"
|
||||||
|
|
||||||
|
const val actionEditCategories = "pref_action_edit_categories"
|
||||||
|
|
||||||
|
const val parentalControlsInfo = "pref_parental_controls_info"
|
||||||
|
|
||||||
|
const val aboutVersion = "pref_about_version"
|
||||||
|
|
||||||
|
const val aboutBuildTime = "pref_about_build_time"
|
||||||
|
|
||||||
|
const val aboutCheckForUpdates = "pref_about_check_for_updates"
|
||||||
|
|
||||||
|
const val aboutWhatsNew = "pref_about_whats_new"
|
||||||
|
|
||||||
|
const val aboutNotices = "pref_about_notices"
|
||||||
|
|
||||||
|
const val aboutWebsite = "pref_about_website"
|
||||||
|
|
||||||
|
const val aboutDiscord = "pref_about_discord"
|
||||||
|
|
||||||
|
const val aboutGitHub = "pref_about_github"
|
||||||
|
|
||||||
|
const val aboutLabelExtensions = "pref_about_label_extensions"
|
||||||
|
|
||||||
|
const val aboutLicenses = "pref_about_licenses"
|
||||||
|
|
||||||
fun trackUsername(syncId: Int) = "pref_mangasync_username_$syncId"
|
fun trackUsername(syncId: Int) = "pref_mangasync_username_$syncId"
|
||||||
|
|
||||||
fun trackPassword(syncId: Int) = "pref_mangasync_password_$syncId"
|
fun trackPassword(syncId: Int) = "pref_mangasync_password_$syncId"
|
||||||
|
@ -10,6 +10,7 @@ import com.afollestad.materialdialogs.MaterialDialog
|
|||||||
import com.mikepenz.aboutlibraries.LibsBuilder
|
import com.mikepenz.aboutlibraries.LibsBuilder
|
||||||
import eu.kanade.tachiyomi.BuildConfig
|
import eu.kanade.tachiyomi.BuildConfig
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
|
import eu.kanade.tachiyomi.data.preference.PreferenceKeys as Keys
|
||||||
import eu.kanade.tachiyomi.data.updater.UpdateChecker
|
import eu.kanade.tachiyomi.data.updater.UpdateChecker
|
||||||
import eu.kanade.tachiyomi.data.updater.UpdateResult
|
import eu.kanade.tachiyomi.data.updater.UpdateResult
|
||||||
import eu.kanade.tachiyomi.data.updater.UpdaterService
|
import eu.kanade.tachiyomi.data.updater.UpdaterService
|
||||||
@ -45,6 +46,7 @@ class AboutController : SettingsController() {
|
|||||||
titleRes = R.string.pref_category_about
|
titleRes = R.string.pref_category_about
|
||||||
|
|
||||||
preference {
|
preference {
|
||||||
|
key = Keys.aboutVersion
|
||||||
titleRes = R.string.version
|
titleRes = R.string.version
|
||||||
summary = if (BuildConfig.DEBUG) {
|
summary = if (BuildConfig.DEBUG) {
|
||||||
"Preview r${BuildConfig.COMMIT_COUNT} (${BuildConfig.COMMIT_SHA})"
|
"Preview r${BuildConfig.COMMIT_COUNT} (${BuildConfig.COMMIT_SHA})"
|
||||||
@ -55,17 +57,20 @@ class AboutController : SettingsController() {
|
|||||||
onClick { copyDebugInfo() }
|
onClick { copyDebugInfo() }
|
||||||
}
|
}
|
||||||
preference {
|
preference {
|
||||||
|
key = Keys.aboutBuildTime
|
||||||
titleRes = R.string.build_time
|
titleRes = R.string.build_time
|
||||||
summary = getFormattedBuildTime()
|
summary = getFormattedBuildTime()
|
||||||
}
|
}
|
||||||
if (isUpdaterEnabled) {
|
if (isUpdaterEnabled) {
|
||||||
preference {
|
preference {
|
||||||
|
key = Keys.aboutCheckForUpdates
|
||||||
titleRes = R.string.check_for_updates
|
titleRes = R.string.check_for_updates
|
||||||
|
|
||||||
onClick { checkVersion() }
|
onClick { checkVersion() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
preference {
|
preference {
|
||||||
|
key = Keys.aboutWhatsNew
|
||||||
titleRes = R.string.whats_new
|
titleRes = R.string.whats_new
|
||||||
|
|
||||||
onClick {
|
onClick {
|
||||||
@ -81,6 +86,7 @@ class AboutController : SettingsController() {
|
|||||||
}
|
}
|
||||||
if (BuildConfig.DEBUG) {
|
if (BuildConfig.DEBUG) {
|
||||||
preference {
|
preference {
|
||||||
|
key = Keys.aboutNotices
|
||||||
titleRes = R.string.notices
|
titleRes = R.string.notices
|
||||||
|
|
||||||
onClick {
|
onClick {
|
||||||
@ -91,7 +97,10 @@ class AboutController : SettingsController() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
preferenceCategory {
|
preferenceCategory {
|
||||||
|
titleRes = R.string.about_resources
|
||||||
|
|
||||||
preference {
|
preference {
|
||||||
|
key = Keys.aboutWebsite
|
||||||
titleRes = R.string.website
|
titleRes = R.string.website
|
||||||
val url = "https://tachiyomi.org"
|
val url = "https://tachiyomi.org"
|
||||||
summary = url
|
summary = url
|
||||||
@ -101,6 +110,7 @@ class AboutController : SettingsController() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
preference {
|
preference {
|
||||||
|
key = Keys.aboutDiscord
|
||||||
title = "Discord"
|
title = "Discord"
|
||||||
val url = "https://discord.gg/tachiyomi"
|
val url = "https://discord.gg/tachiyomi"
|
||||||
summary = url
|
summary = url
|
||||||
@ -110,6 +120,7 @@ class AboutController : SettingsController() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
preference {
|
preference {
|
||||||
|
key = Keys.aboutGitHub
|
||||||
title = "GitHub"
|
title = "GitHub"
|
||||||
val url = "https://github.com/inorichi/tachiyomi"
|
val url = "https://github.com/inorichi/tachiyomi"
|
||||||
summary = url
|
summary = url
|
||||||
@ -119,6 +130,7 @@ class AboutController : SettingsController() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
preference {
|
preference {
|
||||||
|
key = Keys.aboutLabelExtensions
|
||||||
titleRes = R.string.label_extensions
|
titleRes = R.string.label_extensions
|
||||||
val url = "https://github.com/inorichi/tachiyomi-extensions"
|
val url = "https://github.com/inorichi/tachiyomi-extensions"
|
||||||
summary = url
|
summary = url
|
||||||
@ -128,6 +140,7 @@ class AboutController : SettingsController() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
preference {
|
preference {
|
||||||
|
key = Keys.aboutLicenses
|
||||||
titleRes = R.string.licenses
|
titleRes = R.string.licenses
|
||||||
|
|
||||||
onClick {
|
onClick {
|
||||||
|
@ -33,7 +33,6 @@ import rx.schedulers.Schedulers
|
|||||||
import uy.kohesive.injekt.injectLazy
|
import uy.kohesive.injekt.injectLazy
|
||||||
|
|
||||||
class SettingsAdvancedController : SettingsController() {
|
class SettingsAdvancedController : SettingsController() {
|
||||||
|
|
||||||
private val network: NetworkHelper by injectLazy()
|
private val network: NetworkHelper by injectLazy()
|
||||||
|
|
||||||
private val chapterCache: ChapterCache by injectLazy()
|
private val chapterCache: ChapterCache by injectLazy()
|
||||||
@ -43,7 +42,6 @@ class SettingsAdvancedController : SettingsController() {
|
|||||||
@SuppressLint("BatteryLife")
|
@SuppressLint("BatteryLife")
|
||||||
override fun setupPreferenceScreen(screen: PreferenceScreen) = screen.apply {
|
override fun setupPreferenceScreen(screen: PreferenceScreen) = screen.apply {
|
||||||
titleRes = R.string.pref_category_advanced
|
titleRes = R.string.pref_category_advanced
|
||||||
|
|
||||||
switchPreference {
|
switchPreference {
|
||||||
key = "acra.enable"
|
key = "acra.enable"
|
||||||
titleRes = R.string.pref_enable_acra
|
titleRes = R.string.pref_enable_acra
|
||||||
@ -53,6 +51,7 @@ class SettingsAdvancedController : SettingsController() {
|
|||||||
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||||
preference {
|
preference {
|
||||||
|
key = Keys.disableBatteryOptimization
|
||||||
titleRes = R.string.pref_disable_battery_optimization
|
titleRes = R.string.pref_disable_battery_optimization
|
||||||
summaryRes = R.string.pref_disable_battery_optimization_summary
|
summaryRes = R.string.pref_disable_battery_optimization_summary
|
||||||
|
|
||||||
@ -86,6 +85,7 @@ class SettingsAdvancedController : SettingsController() {
|
|||||||
onClick { clearChapterCache() }
|
onClick { clearChapterCache() }
|
||||||
}
|
}
|
||||||
preference {
|
preference {
|
||||||
|
key = Keys.clearDatabase
|
||||||
titleRes = R.string.pref_clear_database
|
titleRes = R.string.pref_clear_database
|
||||||
summaryRes = R.string.pref_clear_database_summary
|
summaryRes = R.string.pref_clear_database_summary
|
||||||
|
|
||||||
@ -101,6 +101,7 @@ class SettingsAdvancedController : SettingsController() {
|
|||||||
titleRes = R.string.label_network
|
titleRes = R.string.label_network
|
||||||
|
|
||||||
preference {
|
preference {
|
||||||
|
key = Keys.clearCookies
|
||||||
titleRes = R.string.pref_clear_cookies
|
titleRes = R.string.pref_clear_cookies
|
||||||
|
|
||||||
onClick {
|
onClick {
|
||||||
@ -120,11 +121,13 @@ class SettingsAdvancedController : SettingsController() {
|
|||||||
titleRes = R.string.label_library
|
titleRes = R.string.label_library
|
||||||
|
|
||||||
preference {
|
preference {
|
||||||
|
key = Keys.refreshLibraryCovers
|
||||||
titleRes = R.string.pref_refresh_library_covers
|
titleRes = R.string.pref_refresh_library_covers
|
||||||
|
|
||||||
onClick { LibraryUpdateService.start(context, target = Target.COVERS) }
|
onClick { LibraryUpdateService.start(context, target = Target.COVERS) }
|
||||||
}
|
}
|
||||||
preference {
|
preference {
|
||||||
|
key = Keys.refreshLibraryTracking
|
||||||
titleRes = R.string.pref_refresh_library_tracking
|
titleRes = R.string.pref_refresh_library_tracking
|
||||||
summaryRes = R.string.pref_refresh_library_tracking_summary
|
summaryRes = R.string.pref_refresh_library_tracking_summary
|
||||||
|
|
||||||
|
@ -53,6 +53,7 @@ class SettingsBackupController : SettingsController() {
|
|||||||
titleRes = R.string.backup
|
titleRes = R.string.backup
|
||||||
|
|
||||||
preference {
|
preference {
|
||||||
|
key = Keys.createBackup
|
||||||
titleRes = R.string.pref_create_backup
|
titleRes = R.string.pref_create_backup
|
||||||
summaryRes = R.string.pref_create_backup_summ
|
summaryRes = R.string.pref_create_backup_summ
|
||||||
|
|
||||||
@ -67,6 +68,7 @@ class SettingsBackupController : SettingsController() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
preference {
|
preference {
|
||||||
|
key = Keys.restoreBackup
|
||||||
titleRes = R.string.pref_restore_backup
|
titleRes = R.string.pref_restore_backup
|
||||||
summaryRes = R.string.pref_restore_backup_summ
|
summaryRes = R.string.pref_restore_backup_summ
|
||||||
|
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
package eu.kanade.tachiyomi.ui.setting
|
package eu.kanade.tachiyomi.ui.setting
|
||||||
|
|
||||||
|
import android.animation.ArgbEvaluator
|
||||||
|
import android.animation.ValueAnimator
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import android.graphics.Color
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.util.TypedValue
|
import android.util.TypedValue
|
||||||
import android.view.ContextThemeWrapper
|
import android.view.ContextThemeWrapper
|
||||||
@ -9,6 +12,7 @@ import android.view.View
|
|||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.preference.PreferenceController
|
import androidx.preference.PreferenceController
|
||||||
|
import androidx.preference.PreferenceGroup
|
||||||
import androidx.preference.PreferenceScreen
|
import androidx.preference.PreferenceScreen
|
||||||
import com.bluelinelabs.conductor.ControllerChangeHandler
|
import com.bluelinelabs.conductor.ControllerChangeHandler
|
||||||
import com.bluelinelabs.conductor.ControllerChangeType
|
import com.bluelinelabs.conductor.ControllerChangeType
|
||||||
@ -26,6 +30,7 @@ import uy.kohesive.injekt.api.get
|
|||||||
|
|
||||||
abstract class SettingsController : PreferenceController() {
|
abstract class SettingsController : PreferenceController() {
|
||||||
|
|
||||||
|
var preferenceKey: String? = null
|
||||||
val preferences: PreferencesHelper = Injekt.get()
|
val preferences: PreferencesHelper = Injekt.get()
|
||||||
val scope = CoroutineScope(Job() + Dispatchers.Main)
|
val scope = CoroutineScope(Job() + Dispatchers.Main)
|
||||||
|
|
||||||
@ -39,6 +44,24 @@ abstract class SettingsController : PreferenceController() {
|
|||||||
return super.onCreateView(inflater, container, savedInstanceState)
|
return super.onCreateView(inflater, container, savedInstanceState)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onAttach(view: View) {
|
||||||
|
super.onAttach(view)
|
||||||
|
|
||||||
|
preferenceKey?.let { prefKey ->
|
||||||
|
val adapter = listView.adapter
|
||||||
|
scrollToPreference(prefKey)
|
||||||
|
|
||||||
|
listView.post {
|
||||||
|
if (adapter is PreferenceGroup.PreferencePositionCallback) {
|
||||||
|
val pos = adapter.getPreferenceAdapterPosition(prefKey)
|
||||||
|
listView.findViewHolderForAdapterPosition(pos)?.let {
|
||||||
|
animatePreferenceHighlight(it.itemView)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun onDestroyView(view: View) {
|
override fun onDestroyView(view: View) {
|
||||||
super.onDestroyView(view)
|
super.onDestroyView(view)
|
||||||
untilDestroySubscriptions.unsubscribe()
|
untilDestroySubscriptions.unsubscribe()
|
||||||
@ -58,6 +81,17 @@ abstract class SettingsController : PreferenceController() {
|
|||||||
return ContextThemeWrapper(activity, tv.resourceId)
|
return ContextThemeWrapper(activity, tv.resourceId)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun animatePreferenceHighlight(view: View) {
|
||||||
|
val duration = 500L
|
||||||
|
val repeat = 2
|
||||||
|
|
||||||
|
val colorAnimation = ValueAnimator.ofObject(ArgbEvaluator(), Color.TRANSPARENT, Color.WHITE)
|
||||||
|
colorAnimation.duration = duration
|
||||||
|
colorAnimation.repeatCount = repeat
|
||||||
|
colorAnimation.addUpdateListener { animator -> view.setBackgroundColor(animator.animatedValue as Int) }
|
||||||
|
colorAnimation.reverse()
|
||||||
|
}
|
||||||
|
|
||||||
open fun getTitle(): String? {
|
open fun getTitle(): String? {
|
||||||
return preferenceScreen?.title?.toString()
|
return preferenceScreen?.title?.toString()
|
||||||
}
|
}
|
||||||
|
@ -47,6 +47,7 @@ class SettingsGeneralController : SettingsController() {
|
|||||||
}
|
}
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
preference {
|
preference {
|
||||||
|
key = Keys.manageNotifications
|
||||||
titleRes = R.string.pref_manage_notifications
|
titleRes = R.string.pref_manage_notifications
|
||||||
onClick {
|
onClick {
|
||||||
val intent = Intent(Settings.ACTION_APP_NOTIFICATION_SETTINGS).apply {
|
val intent = Intent(Settings.ACTION_APP_NOTIFICATION_SETTINGS).apply {
|
||||||
|
@ -50,6 +50,7 @@ class SettingsLibraryController : SettingsController() {
|
|||||||
titleRes = R.string.pref_category_display
|
titleRes = R.string.pref_category_display
|
||||||
|
|
||||||
preference {
|
preference {
|
||||||
|
key = Keys.libraryColumns
|
||||||
titleRes = R.string.pref_library_columns
|
titleRes = R.string.pref_library_columns
|
||||||
onClick {
|
onClick {
|
||||||
LibraryColumnsDialog().showDialog(router)
|
LibraryColumnsDialog().showDialog(router)
|
||||||
@ -83,6 +84,7 @@ class SettingsLibraryController : SettingsController() {
|
|||||||
titleRes = R.string.pref_category_library_categories
|
titleRes = R.string.pref_category_library_categories
|
||||||
|
|
||||||
preference {
|
preference {
|
||||||
|
key = Keys.actionEditCategories
|
||||||
titleRes = R.string.action_edit_categories
|
titleRes = R.string.action_edit_categories
|
||||||
|
|
||||||
val catCount = dbCategories.size
|
val catCount = dbCategories.size
|
||||||
|
@ -6,8 +6,6 @@ import androidx.preference.Preference
|
|||||||
import androidx.preference.PreferenceCategory
|
import androidx.preference.PreferenceCategory
|
||||||
import androidx.preference.PreferenceGroup
|
import androidx.preference.PreferenceGroup
|
||||||
import androidx.preference.PreferenceManager
|
import androidx.preference.PreferenceManager
|
||||||
import eu.kanade.tachiyomi.ui.browse.extension.ExtensionFilterController
|
|
||||||
import eu.kanade.tachiyomi.ui.browse.source.SourceFilterController
|
|
||||||
import eu.kanade.tachiyomi.ui.more.AboutController
|
import eu.kanade.tachiyomi.ui.more.AboutController
|
||||||
import eu.kanade.tachiyomi.ui.setting.SettingsAdvancedController
|
import eu.kanade.tachiyomi.ui.setting.SettingsAdvancedController
|
||||||
import eu.kanade.tachiyomi.ui.setting.SettingsBackupController
|
import eu.kanade.tachiyomi.ui.setting.SettingsBackupController
|
||||||
@ -41,8 +39,6 @@ object SettingsSearchHelper {
|
|||||||
SettingsReaderController::class,
|
SettingsReaderController::class,
|
||||||
SettingsSecurityController::class,
|
SettingsSecurityController::class,
|
||||||
SettingsTrackingController::class,
|
SettingsTrackingController::class,
|
||||||
ExtensionFilterController::class,
|
|
||||||
SourceFilterController::class,
|
|
||||||
AboutController::class
|
AboutController::class
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -94,12 +90,21 @@ object SettingsSearchHelper {
|
|||||||
val summary = if (pref.summary != null) pref.summary.toString() else ""
|
val summary = if (pref.summary != null) pref.summary.toString() else ""
|
||||||
val breadcrumbsStr = breadcrumbs + " > ${pref.title}"
|
val breadcrumbsStr = breadcrumbs + " > ${pref.title}"
|
||||||
|
|
||||||
prefSearchResultList.add(SettingsSearchResult(title, summary, breadcrumbsStr, ctrl))
|
prefSearchResultList.add(
|
||||||
|
SettingsSearchResult(
|
||||||
|
key = pref.key,
|
||||||
|
title = title,
|
||||||
|
summary = summary,
|
||||||
|
breadcrumb = breadcrumbsStr,
|
||||||
|
searchController = ctrl
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
data class SettingsSearchResult(
|
data class SettingsSearchResult(
|
||||||
|
val key: String?,
|
||||||
val title: String,
|
val title: String,
|
||||||
val summary: String,
|
val summary: String,
|
||||||
val breadcrumb: String,
|
val breadcrumb: String,
|
||||||
|
@ -17,9 +17,11 @@ class SettingsSearchHolder(view: View, val adapter: SettingsSearchAdapter) :
|
|||||||
init {
|
init {
|
||||||
title_wrapper.setOnClickListener {
|
title_wrapper.setOnClickListener {
|
||||||
adapter.getItem(bindingAdapterPosition)?.let {
|
adapter.getItem(bindingAdapterPosition)?.let {
|
||||||
val ctrl = it.settingsSearchResult.searchController
|
val ctrl = it.settingsSearchResult.searchController::class.createInstance()
|
||||||
// needs to be a new instance to avoid this error https://github.com/bluelinelabs/Conductor/issues/446
|
ctrl.preferenceKey = it.settingsSearchResult.key
|
||||||
adapter.titleClickListener.onTitleClick(ctrl::class.createInstance())
|
|
||||||
|
// must pass a new Controller instance to avoid this error https://github.com/bluelinelabs/Conductor/issues/446
|
||||||
|
adapter.titleClickListener.onTitleClick(ctrl)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -411,6 +411,7 @@
|
|||||||
<string name="licenses">Open source licenses</string>
|
<string name="licenses">Open source licenses</string>
|
||||||
<string name="check_for_updates">Check for updates</string>
|
<string name="check_for_updates">Check for updates</string>
|
||||||
<string name="updated_version">Updated to v%1$s</string>
|
<string name="updated_version">Updated to v%1$s</string>
|
||||||
|
<string name="about_resources">Resources</string>
|
||||||
|
|
||||||
<!-- ACRA -->
|
<!-- ACRA -->
|
||||||
<string name="pref_enable_acra">Send crash reports</string>
|
<string name="pref_enable_acra">Send crash reports</string>
|
||||||
|
Loading…
Reference in New Issue
Block a user