Remove General settings section
This commit is contained in:
parent
405a75438a
commit
34b9c82cd0
@ -3,6 +3,7 @@ package eu.kanade.presentation.more.settings.screen
|
|||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.content.ActivityNotFoundException
|
import android.content.ActivityNotFoundException
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
|
import android.os.Build
|
||||||
import android.provider.Settings
|
import android.provider.Settings
|
||||||
import android.webkit.WebStorage
|
import android.webkit.WebStorage
|
||||||
import android.webkit.WebView
|
import android.webkit.WebView
|
||||||
@ -68,6 +69,7 @@ import uy.kohesive.injekt.api.get
|
|||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
object SettingsAdvancedScreen : SearchableSettings {
|
object SettingsAdvancedScreen : SearchableSettings {
|
||||||
|
|
||||||
@ReadOnlyComposable
|
@ReadOnlyComposable
|
||||||
@Composable
|
@Composable
|
||||||
@StringRes
|
@StringRes
|
||||||
@ -82,41 +84,62 @@ object SettingsAdvancedScreen : SearchableSettings {
|
|||||||
val basePreferences = remember { Injekt.get<BasePreferences>() }
|
val basePreferences = remember { Injekt.get<BasePreferences>() }
|
||||||
val networkPreferences = remember { Injekt.get<NetworkPreferences>() }
|
val networkPreferences = remember { Injekt.get<NetworkPreferences>() }
|
||||||
|
|
||||||
return listOf(
|
return buildList {
|
||||||
Preference.PreferenceItem.SwitchPreference(
|
addAll(
|
||||||
pref = basePreferences.acraEnabled(),
|
listOf(
|
||||||
title = stringResource(R.string.pref_enable_acra),
|
Preference.PreferenceItem.SwitchPreference(
|
||||||
subtitle = stringResource(R.string.pref_acra_summary),
|
pref = basePreferences.acraEnabled(),
|
||||||
enabled = isPreviewBuildType || isReleaseBuildType,
|
title = stringResource(R.string.pref_enable_acra),
|
||||||
),
|
subtitle = stringResource(R.string.pref_acra_summary),
|
||||||
Preference.PreferenceItem.TextPreference(
|
enabled = isPreviewBuildType || isReleaseBuildType,
|
||||||
title = stringResource(R.string.pref_dump_crash_logs),
|
),
|
||||||
subtitle = stringResource(R.string.pref_dump_crash_logs_summary),
|
Preference.PreferenceItem.TextPreference(
|
||||||
onClick = {
|
title = stringResource(R.string.pref_dump_crash_logs),
|
||||||
scope.launch {
|
subtitle = stringResource(R.string.pref_dump_crash_logs_summary),
|
||||||
CrashLogUtil(context).dumpLogs()
|
onClick = {
|
||||||
}
|
scope.launch {
|
||||||
},
|
CrashLogUtil(context).dumpLogs()
|
||||||
),
|
}
|
||||||
Preference.PreferenceItem.SwitchPreference(
|
},
|
||||||
pref = networkPreferences.verboseLogging(),
|
),
|
||||||
title = stringResource(R.string.pref_verbose_logging),
|
Preference.PreferenceItem.SwitchPreference(
|
||||||
subtitle = stringResource(R.string.pref_verbose_logging_summary),
|
pref = networkPreferences.verboseLogging(),
|
||||||
onValueChanged = {
|
title = stringResource(R.string.pref_verbose_logging),
|
||||||
context.toast(R.string.requires_app_restart)
|
subtitle = stringResource(R.string.pref_verbose_logging_summary),
|
||||||
true
|
onValueChanged = {
|
||||||
},
|
context.toast(R.string.requires_app_restart)
|
||||||
),
|
true
|
||||||
Preference.PreferenceItem.TextPreference(
|
},
|
||||||
title = stringResource(R.string.pref_debug_info),
|
),
|
||||||
onClick = { navigator.push(DebugInfoScreen) },
|
Preference.PreferenceItem.TextPreference(
|
||||||
),
|
title = stringResource(R.string.pref_debug_info),
|
||||||
getBackgroundActivityGroup(),
|
onClick = { navigator.push(DebugInfoScreen) },
|
||||||
getDataGroup(),
|
),
|
||||||
getNetworkGroup(networkPreferences = networkPreferences),
|
),
|
||||||
getLibraryGroup(),
|
)
|
||||||
getExtensionsGroup(basePreferences = basePreferences),
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
)
|
add(
|
||||||
|
Preference.PreferenceItem.TextPreference(
|
||||||
|
title = stringResource(R.string.pref_manage_notifications),
|
||||||
|
onClick = {
|
||||||
|
val intent = Intent(Settings.ACTION_APP_NOTIFICATION_SETTINGS).apply {
|
||||||
|
putExtra(Settings.EXTRA_APP_PACKAGE, context.packageName)
|
||||||
|
}
|
||||||
|
context.startActivity(intent)
|
||||||
|
},
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
addAll(
|
||||||
|
listOf(
|
||||||
|
getBackgroundActivityGroup(),
|
||||||
|
getDataGroup(),
|
||||||
|
getNetworkGroup(networkPreferences = networkPreferences),
|
||||||
|
getLibraryGroup(),
|
||||||
|
getExtensionsGroup(basePreferences = basePreferences),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
|
@ -4,14 +4,18 @@ import android.app.Activity
|
|||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import androidx.annotation.StringRes
|
import androidx.annotation.StringRes
|
||||||
|
import androidx.appcompat.app.AppCompatDelegate
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.runtime.ReadOnlyComposable
|
import androidx.compose.runtime.ReadOnlyComposable
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.core.app.ActivityCompat
|
import androidx.core.app.ActivityCompat
|
||||||
|
import androidx.core.os.LocaleListCompat
|
||||||
import eu.kanade.domain.ui.UiPreferences
|
import eu.kanade.domain.ui.UiPreferences
|
||||||
import eu.kanade.domain.ui.model.TabletUiMode
|
import eu.kanade.domain.ui.model.TabletUiMode
|
||||||
import eu.kanade.domain.ui.model.ThemeMode
|
import eu.kanade.domain.ui.model.ThemeMode
|
||||||
@ -19,10 +23,12 @@ import eu.kanade.domain.ui.model.setAppCompatDelegateThemeMode
|
|||||||
import eu.kanade.presentation.more.settings.Preference
|
import eu.kanade.presentation.more.settings.Preference
|
||||||
import eu.kanade.presentation.util.collectAsState
|
import eu.kanade.presentation.util.collectAsState
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
|
import eu.kanade.tachiyomi.util.system.LocaleHelper
|
||||||
import eu.kanade.tachiyomi.util.system.toast
|
import eu.kanade.tachiyomi.util.system.toast
|
||||||
import kotlinx.coroutines.flow.collectLatest
|
import kotlinx.coroutines.flow.collectLatest
|
||||||
import kotlinx.coroutines.flow.drop
|
import kotlinx.coroutines.flow.drop
|
||||||
import kotlinx.coroutines.flow.merge
|
import kotlinx.coroutines.flow.merge
|
||||||
|
import org.xmlpull.v1.XmlPullParser
|
||||||
import uy.kohesive.injekt.Injekt
|
import uy.kohesive.injekt.Injekt
|
||||||
import uy.kohesive.injekt.api.get
|
import uy.kohesive.injekt.api.get
|
||||||
import java.util.Date
|
import java.util.Date
|
||||||
@ -103,9 +109,30 @@ object SettingsAppearanceScreen : SearchableSettings {
|
|||||||
context: Context,
|
context: Context,
|
||||||
uiPreferences: UiPreferences,
|
uiPreferences: UiPreferences,
|
||||||
): Preference.PreferenceGroup {
|
): Preference.PreferenceGroup {
|
||||||
|
val langs = remember { getLangs(context) }
|
||||||
|
var currentLanguage by remember { mutableStateOf(AppCompatDelegate.getApplicationLocales().get(0)?.toLanguageTag() ?: "") }
|
||||||
|
|
||||||
|
LaunchedEffect(currentLanguage) {
|
||||||
|
val locale = if (currentLanguage.isEmpty()) {
|
||||||
|
LocaleListCompat.getEmptyLocaleList()
|
||||||
|
} else {
|
||||||
|
LocaleListCompat.forLanguageTags(currentLanguage)
|
||||||
|
}
|
||||||
|
AppCompatDelegate.setApplicationLocales(locale)
|
||||||
|
}
|
||||||
|
|
||||||
return Preference.PreferenceGroup(
|
return Preference.PreferenceGroup(
|
||||||
title = stringResource(R.string.pref_category_display),
|
title = stringResource(R.string.pref_category_display),
|
||||||
preferenceItems = listOf(
|
preferenceItems = listOf(
|
||||||
|
Preference.PreferenceItem.BasicListPreference(
|
||||||
|
value = currentLanguage,
|
||||||
|
title = stringResource(R.string.pref_app_language),
|
||||||
|
entries = langs,
|
||||||
|
onValueChanged = { newValue ->
|
||||||
|
currentLanguage = newValue
|
||||||
|
true
|
||||||
|
},
|
||||||
|
),
|
||||||
Preference.PreferenceItem.ListPreference(
|
Preference.PreferenceItem.ListPreference(
|
||||||
pref = uiPreferences.tabletUiMode(),
|
pref = uiPreferences.tabletUiMode(),
|
||||||
title = stringResource(R.string.pref_tablet_ui_mode),
|
title = stringResource(R.string.pref_tablet_ui_mode),
|
||||||
@ -146,6 +173,31 @@ object SettingsAppearanceScreen : SearchableSettings {
|
|||||||
),
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun getLangs(context: Context): Map<String, String> {
|
||||||
|
val langs = mutableListOf<Pair<String, String>>()
|
||||||
|
val parser = context.resources.getXml(R.xml.locales_config)
|
||||||
|
var eventType = parser.eventType
|
||||||
|
while (eventType != XmlPullParser.END_DOCUMENT) {
|
||||||
|
if (eventType == XmlPullParser.START_TAG && parser.name == "locale") {
|
||||||
|
for (i in 0 until parser.attributeCount) {
|
||||||
|
if (parser.getAttributeName(i) == "name") {
|
||||||
|
val langTag = parser.getAttributeValue(i)
|
||||||
|
val displayName = LocaleHelper.getDisplayName(langTag)
|
||||||
|
if (displayName.isNotEmpty()) {
|
||||||
|
langs.add(Pair(langTag, displayName))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
eventType = parser.next()
|
||||||
|
}
|
||||||
|
|
||||||
|
langs.sortBy { it.second }
|
||||||
|
langs.add(0, Pair("", context.getString(R.string.label_default)))
|
||||||
|
|
||||||
|
return langs.toMap()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private val DateFormats = listOf(
|
private val DateFormats = listOf(
|
||||||
|
@ -1,111 +0,0 @@
|
|||||||
package eu.kanade.presentation.more.settings.screen
|
|
||||||
|
|
||||||
import android.content.Context
|
|
||||||
import android.content.Intent
|
|
||||||
import android.os.Build
|
|
||||||
import android.provider.Settings
|
|
||||||
import androidx.annotation.StringRes
|
|
||||||
import androidx.appcompat.app.AppCompatDelegate
|
|
||||||
import androidx.compose.runtime.Composable
|
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
|
||||||
import androidx.compose.runtime.ReadOnlyComposable
|
|
||||||
import androidx.compose.runtime.getValue
|
|
||||||
import androidx.compose.runtime.mutableStateOf
|
|
||||||
import androidx.compose.runtime.remember
|
|
||||||
import androidx.compose.runtime.setValue
|
|
||||||
import androidx.compose.ui.platform.LocalContext
|
|
||||||
import androidx.compose.ui.res.stringResource
|
|
||||||
import androidx.core.os.LocaleListCompat
|
|
||||||
import eu.kanade.presentation.more.settings.Preference
|
|
||||||
import eu.kanade.tachiyomi.R
|
|
||||||
import eu.kanade.tachiyomi.util.system.LocaleHelper
|
|
||||||
import org.xmlpull.v1.XmlPullParser
|
|
||||||
import tachiyomi.domain.library.service.LibraryPreferences
|
|
||||||
import uy.kohesive.injekt.Injekt
|
|
||||||
import uy.kohesive.injekt.api.get
|
|
||||||
|
|
||||||
object SettingsGeneralScreen : SearchableSettings {
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
@ReadOnlyComposable
|
|
||||||
@StringRes
|
|
||||||
override fun getTitleRes() = R.string.pref_category_general
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
override fun getPreferences(): List<Preference> {
|
|
||||||
val libraryPrefs = remember { Injekt.get<LibraryPreferences>() }
|
|
||||||
val context = LocalContext.current
|
|
||||||
|
|
||||||
val langs = remember { getLangs(context) }
|
|
||||||
var currentLanguage by remember { mutableStateOf(AppCompatDelegate.getApplicationLocales().get(0)?.toLanguageTag() ?: "") }
|
|
||||||
|
|
||||||
return buildList {
|
|
||||||
add(
|
|
||||||
Preference.PreferenceItem.SwitchPreference(
|
|
||||||
pref = libraryPrefs.newShowUpdatesCount(),
|
|
||||||
title = stringResource(R.string.pref_library_update_show_tab_badge),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
|
||||||
add(
|
|
||||||
Preference.PreferenceItem.TextPreference(
|
|
||||||
title = stringResource(R.string.pref_manage_notifications),
|
|
||||||
onClick = {
|
|
||||||
val intent = Intent(Settings.ACTION_APP_NOTIFICATION_SETTINGS).apply {
|
|
||||||
putExtra(Settings.EXTRA_APP_PACKAGE, context.packageName)
|
|
||||||
}
|
|
||||||
context.startActivity(intent)
|
|
||||||
},
|
|
||||||
),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
add(
|
|
||||||
Preference.PreferenceItem.BasicListPreference(
|
|
||||||
value = currentLanguage,
|
|
||||||
title = stringResource(R.string.pref_app_language),
|
|
||||||
entries = langs,
|
|
||||||
onValueChanged = { newValue ->
|
|
||||||
currentLanguage = newValue
|
|
||||||
true
|
|
||||||
},
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
LaunchedEffect(currentLanguage) {
|
|
||||||
val locale = if (currentLanguage.isEmpty()) {
|
|
||||||
LocaleListCompat.getEmptyLocaleList()
|
|
||||||
} else {
|
|
||||||
LocaleListCompat.forLanguageTags(currentLanguage)
|
|
||||||
}
|
|
||||||
AppCompatDelegate.setApplicationLocales(locale)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getLangs(context: Context): Map<String, String> {
|
|
||||||
val langs = mutableListOf<Pair<String, String>>()
|
|
||||||
val parser = context.resources.getXml(R.xml.locales_config)
|
|
||||||
var eventType = parser.eventType
|
|
||||||
while (eventType != XmlPullParser.END_DOCUMENT) {
|
|
||||||
if (eventType == XmlPullParser.START_TAG && parser.name == "locale") {
|
|
||||||
for (i in 0 until parser.attributeCount) {
|
|
||||||
if (parser.getAttributeName(i) == "name") {
|
|
||||||
val langTag = parser.getAttributeValue(i)
|
|
||||||
val displayName = LocaleHelper.getDisplayName(langTag)
|
|
||||||
if (displayName.isNotEmpty()) {
|
|
||||||
langs.add(Pair(langTag, displayName))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
eventType = parser.next()
|
|
||||||
}
|
|
||||||
|
|
||||||
langs.sortBy { it.second }
|
|
||||||
langs.add(0, Pair("", context.getString(R.string.label_default)))
|
|
||||||
|
|
||||||
return langs.toMap()
|
|
||||||
}
|
|
||||||
}
|
|
@ -265,6 +265,10 @@ object SettingsLibraryScreen : SearchableSettings {
|
|||||||
Preference.PreferenceItem.InfoPreference(
|
Preference.PreferenceItem.InfoPreference(
|
||||||
title = stringResource(R.string.pref_update_release_grace_period_info),
|
title = stringResource(R.string.pref_update_release_grace_period_info),
|
||||||
).takeIf { MANGA_OUTSIDE_RELEASE_PERIOD in libraryUpdateMangaRestriction && isDevFlavor },
|
).takeIf { MANGA_OUTSIDE_RELEASE_PERIOD in libraryUpdateMangaRestriction && isDevFlavor },
|
||||||
|
Preference.PreferenceItem.SwitchPreference(
|
||||||
|
pref = libraryPreferences.newShowUpdatesCount(),
|
||||||
|
title = stringResource(R.string.pref_library_update_show_tab_badge),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,6 @@ import androidx.compose.material.icons.outlined.Search
|
|||||||
import androidx.compose.material.icons.outlined.Security
|
import androidx.compose.material.icons.outlined.Security
|
||||||
import androidx.compose.material.icons.outlined.SettingsBackupRestore
|
import androidx.compose.material.icons.outlined.SettingsBackupRestore
|
||||||
import androidx.compose.material.icons.outlined.Sync
|
import androidx.compose.material.icons.outlined.Sync
|
||||||
import androidx.compose.material.icons.outlined.Tune
|
|
||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
import androidx.compose.material3.IconButton
|
import androidx.compose.material3.IconButton
|
||||||
import androidx.compose.material3.LocalContentColor
|
import androidx.compose.material3.LocalContentColor
|
||||||
@ -187,12 +186,6 @@ object SettingsMainScreen : Screen() {
|
|||||||
)
|
)
|
||||||
|
|
||||||
private val items = listOf(
|
private val items = listOf(
|
||||||
Item(
|
|
||||||
titleRes = R.string.pref_category_general,
|
|
||||||
subtitleRes = R.string.pref_general_summary,
|
|
||||||
icon = Icons.Outlined.Tune,
|
|
||||||
screen = SettingsGeneralScreen,
|
|
||||||
),
|
|
||||||
Item(
|
Item(
|
||||||
titleRes = R.string.pref_category_appearance,
|
titleRes = R.string.pref_category_appearance,
|
||||||
subtitleRes = R.string.pref_appearance_summary,
|
subtitleRes = R.string.pref_appearance_summary,
|
||||||
|
@ -284,7 +284,6 @@ private fun getLocalizedBreadcrumb(path: String, node: String?): String {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private val settingScreens = listOf(
|
private val settingScreens = listOf(
|
||||||
SettingsGeneralScreen,
|
|
||||||
SettingsAppearanceScreen,
|
SettingsAppearanceScreen,
|
||||||
SettingsLibraryScreen,
|
SettingsLibraryScreen,
|
||||||
SettingsReaderScreen,
|
SettingsReaderScreen,
|
||||||
|
@ -32,7 +32,6 @@ object SettingsSecurityScreen : SearchableSettings {
|
|||||||
val authSupported = remember { context.isAuthenticationSupported() }
|
val authSupported = remember { context.isAuthenticationSupported() }
|
||||||
|
|
||||||
val useAuthPref = securityPreferences.useAuthenticator()
|
val useAuthPref = securityPreferences.useAuthenticator()
|
||||||
|
|
||||||
val useAuth by useAuthPref.collectAsState()
|
val useAuth by useAuthPref.collectAsState()
|
||||||
|
|
||||||
return listOf(
|
return listOf(
|
||||||
|
@ -13,8 +13,8 @@ import cafe.adriel.voyager.navigator.LocalNavigator
|
|||||||
import cafe.adriel.voyager.navigator.Navigator
|
import cafe.adriel.voyager.navigator.Navigator
|
||||||
import cafe.adriel.voyager.navigator.currentOrThrow
|
import cafe.adriel.voyager.navigator.currentOrThrow
|
||||||
import eu.kanade.presentation.more.settings.screen.AboutScreen
|
import eu.kanade.presentation.more.settings.screen.AboutScreen
|
||||||
|
import eu.kanade.presentation.more.settings.screen.SettingsAppearanceScreen
|
||||||
import eu.kanade.presentation.more.settings.screen.SettingsBackupScreen
|
import eu.kanade.presentation.more.settings.screen.SettingsBackupScreen
|
||||||
import eu.kanade.presentation.more.settings.screen.SettingsGeneralScreen
|
|
||||||
import eu.kanade.presentation.more.settings.screen.SettingsMainScreen
|
import eu.kanade.presentation.more.settings.screen.SettingsMainScreen
|
||||||
import eu.kanade.presentation.util.DefaultNavigatorScreenTransition
|
import eu.kanade.presentation.util.DefaultNavigatorScreenTransition
|
||||||
import eu.kanade.presentation.util.LocalBackPress
|
import eu.kanade.presentation.util.LocalBackPress
|
||||||
@ -59,7 +59,7 @@ class SettingsScreen private constructor(
|
|||||||
} else if (toAbout) {
|
} else if (toAbout) {
|
||||||
AboutScreen
|
AboutScreen
|
||||||
} else {
|
} else {
|
||||||
SettingsGeneralScreen
|
SettingsAppearanceScreen
|
||||||
},
|
},
|
||||||
) {
|
) {
|
||||||
val insets = WindowInsets.systemBars.only(WindowInsetsSides.Horizontal)
|
val insets = WindowInsets.systemBars.only(WindowInsetsSides.Horizontal)
|
||||||
|
@ -171,7 +171,6 @@
|
|||||||
<string name="pref_category_advanced">Advanced</string>
|
<string name="pref_category_advanced">Advanced</string>
|
||||||
<string name="pref_category_about">About</string>
|
<string name="pref_category_about">About</string>
|
||||||
|
|
||||||
<string name="pref_general_summary">App language, notifications</string>
|
|
||||||
<string name="pref_appearance_summary">Theme, date & time format</string>
|
<string name="pref_appearance_summary">Theme, date & time format</string>
|
||||||
<string name="pref_library_summary">Categories, global update, chapter swipe</string>
|
<string name="pref_library_summary">Categories, global update, chapter swipe</string>
|
||||||
<string name="pref_reader_summary">Reading mode, display, navigation</string>
|
<string name="pref_reader_summary">Reading mode, display, navigation</string>
|
||||||
|
Loading…
Reference in New Issue
Block a user