Dantotsu/app/src/main/java/ani/dantotsu/settings/SettingsActivity.kt
2024-03-01 17:47:41 -06:00

989 lines
No EOL
40 KiB
Kotlin

package ani.dantotsu.settings
import android.annotation.SuppressLint
import android.app.AlertDialog
import android.content.Intent
import android.graphics.drawable.Animatable
import android.os.Build.BRAND
import android.os.Build.DEVICE
import android.os.Build.SUPPORTED_ABIS
import android.os.Build.VERSION.CODENAME
import android.os.Build.VERSION.RELEASE
import android.os.Build.VERSION.SDK_INT
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.animation.AnimationUtils
import android.view.inputmethod.EditorInfo
import android.widget.ArrayAdapter
import android.widget.ImageView
import android.widget.TextView
import android.widget.Toast
import androidx.activity.OnBackPressedCallback
import androidx.activity.result.contract.ActivityResultContracts
import androidx.annotation.OptIn
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import androidx.core.view.updateLayoutParams
import androidx.documentfile.provider.DocumentFile
import androidx.lifecycle.lifecycleScope
import androidx.media3.common.util.UnstableApi
import androidx.media3.exoplayer.offline.DownloadService
import ani.dantotsu.BuildConfig
import ani.dantotsu.R
import ani.dantotsu.Refresh
import ani.dantotsu.connections.anilist.Anilist
import ani.dantotsu.connections.discord.Discord
import ani.dantotsu.connections.mal.MAL
import ani.dantotsu.copyToClipboard
import ani.dantotsu.currContext
import ani.dantotsu.databinding.ActivitySettingsBinding
import ani.dantotsu.download.DownloadedType
import ani.dantotsu.download.DownloadsManager
import ani.dantotsu.download.video.ExoplayerDownloadService
import ani.dantotsu.downloadsPermission
import ani.dantotsu.initActivity
import ani.dantotsu.loadImage
import ani.dantotsu.logger
import ani.dantotsu.navBarHeight
import ani.dantotsu.openLinkInBrowser
import ani.dantotsu.others.AppUpdater
import ani.dantotsu.others.CustomBottomDialog
import ani.dantotsu.pop
import ani.dantotsu.savePrefsToDownloads
import ani.dantotsu.setSafeOnClickListener
import ani.dantotsu.settings.saving.PrefManager
import ani.dantotsu.settings.saving.PrefName
import ani.dantotsu.settings.saving.internal.Location
import ani.dantotsu.settings.saving.internal.PreferenceKeystore
import ani.dantotsu.settings.saving.internal.PreferencePackager
import ani.dantotsu.snackString
import ani.dantotsu.startMainActivity
import ani.dantotsu.statusBarHeight
import ani.dantotsu.subcriptions.Notifications
import ani.dantotsu.subcriptions.Notifications.Companion.openSettings
import ani.dantotsu.subcriptions.Subscription.Companion.defaultTime
import ani.dantotsu.subcriptions.Subscription.Companion.startSubscription
import ani.dantotsu.subcriptions.Subscription.Companion.timeMinutes
import ani.dantotsu.themes.ThemeManager
import ani.dantotsu.toast
import com.google.android.material.snackbar.Snackbar
import com.google.android.material.textfield.TextInputEditText
import eltos.simpledialogfragment.SimpleDialog
import eltos.simpledialogfragment.SimpleDialog.OnDialogResultListener.BUTTON_POSITIVE
import eltos.simpledialogfragment.color.SimpleColorDialog
import eu.kanade.domain.base.BasePreferences
import io.noties.markwon.Markwon
import io.noties.markwon.SoftBreakAddsNewLinePlugin
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
import kotlin.random.Random
class SettingsActivity : AppCompatActivity(), SimpleDialog.OnDialogResultListener {
private val restartMainActivity = object : OnBackPressedCallback(false) {
override fun handleOnBackPressed() = startMainActivity(this@SettingsActivity)
}
lateinit var binding: ActivitySettingsBinding
private val extensionInstaller = Injekt.get<BasePreferences>().extensionInstaller()
private var cursedCounter = 0
@OptIn(UnstableApi::class)
@SuppressLint("SetTextI18n", "Recycle")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
ThemeManager(this).applyTheme()
binding = ActivitySettingsBinding.inflate(layoutInflater)
setContentView(binding.root)
initActivity(this)
val openDocumentLauncher =
registerForActivityResult(ActivityResultContracts.OpenDocument()) { uri ->
if (uri != null) {
try {
val jsonString = contentResolver.openInputStream(uri)?.readBytes()
?: throw Exception("Error reading file")
val name = DocumentFile.fromSingleUri(this, uri)?.name ?: "settings"
//.sani is encrypted, .ani is not
if (name.endsWith(".sani")) {
passwordAlertDialog(false) { password ->
if (password != null) {
val salt = jsonString.copyOfRange(0, 16)
val encrypted = jsonString.copyOfRange(16, jsonString.size)
val decryptedJson = try {
PreferenceKeystore.decryptWithPassword(
password,
encrypted,
salt
)
} catch (e: Exception) {
toast("Incorrect password")
return@passwordAlertDialog
}
if (PreferencePackager.unpack(decryptedJson))
restartApp()
} else {
toast("Password cannot be empty")
}
}
} else if (name.endsWith(".ani")) {
val decryptedJson = jsonString.toString(Charsets.UTF_8)
if (PreferencePackager.unpack(decryptedJson))
restartApp()
} else {
toast("Unknown file type")
}
} catch (e: Exception) {
e.printStackTrace()
toast("Error importing settings")
}
}
}
binding.settingsVersion.text = getString(R.string.version_current, BuildConfig.VERSION_NAME)
binding.settingsVersion.setOnLongClickListener {
copyToClipboard(getDeviceInfo(), false)
toast(getString(R.string.copied_device_info))
return@setOnLongClickListener true
}
binding.settingsContainer.updateLayoutParams<ViewGroup.MarginLayoutParams> {
topMargin = statusBarHeight
bottomMargin = navBarHeight
}
onBackPressedDispatcher.addCallback(this, restartMainActivity)
binding.settingsBack.setOnClickListener {
onBackPressedDispatcher.onBackPressed()
}
binding.settingsUseMaterialYou.isChecked = PrefManager.getVal(PrefName.UseMaterialYou)
binding.settingsUseMaterialYou.setOnCheckedChangeListener { _, isChecked ->
PrefManager.setVal(PrefName.UseMaterialYou, isChecked)
if (isChecked) binding.settingsUseCustomTheme.isChecked = false
restartApp()
}
binding.settingsUseCustomTheme.isChecked = PrefManager.getVal(PrefName.UseCustomTheme)
binding.settingsUseCustomTheme.setOnCheckedChangeListener { _, isChecked ->
PrefManager.setVal(PrefName.UseCustomTheme, isChecked)
if (isChecked) {
binding.settingsUseMaterialYou.isChecked = false
}
restartApp()
}
binding.settingsUseSourceTheme.isChecked = PrefManager.getVal(PrefName.UseSourceTheme)
binding.settingsUseSourceTheme.setOnCheckedChangeListener { _, isChecked ->
PrefManager.setVal(PrefName.UseSourceTheme, isChecked)
restartApp()
}
binding.settingsUseOLED.isChecked = PrefManager.getVal(PrefName.UseOLED)
binding.settingsUseOLED.setOnCheckedChangeListener { _, isChecked ->
PrefManager.setVal(PrefName.UseOLED, isChecked)
restartApp()
}
val themeString: String = PrefManager.getVal(PrefName.Theme)
binding.themeSwitcher.setText(
themeString.substring(0, 1) + themeString.substring(1).lowercase()
)
binding.themeSwitcher.setAdapter(
ArrayAdapter(
this,
R.layout.item_dropdown,
ThemeManager.Companion.Theme.entries
.map { it.theme.substring(0, 1) + it.theme.substring(1).lowercase() })
)
binding.themeSwitcher.setOnItemClickListener { _, _, i, _ ->
PrefManager.setVal(PrefName.Theme, ThemeManager.Companion.Theme.entries[i].theme)
//ActivityHelper.shouldRefreshMainActivity = true
binding.themeSwitcher.clearFocus()
restartApp()
}
binding.customTheme.setOnClickListener {
val originalColor: Int = PrefManager.getVal(PrefName.CustomThemeInt)
class CustomColorDialog : SimpleColorDialog() { //idk where to put it
override fun onPositiveButtonClick() {
restartApp()
super.onPositiveButtonClick()
}
}
val tag = "colorPicker"
CustomColorDialog().title("Custom Theme")
.colorPreset(originalColor)
.colors(this, SimpleColorDialog.MATERIAL_COLOR_PALLET)
.allowCustom(true)
.showOutline(0x46000000)
.gridNumColumn(5)
.choiceMode(SimpleColorDialog.SINGLE_CHOICE)
.neg()
.show(this, tag)
}
binding.settingsPlayer.setOnClickListener {
startActivity(Intent(this, PlayerSettingsActivity::class.java))
}
val managers = arrayOf("Default", "1DM", "ADM")
val downloadManagerDialog =
AlertDialog.Builder(this, R.style.MyPopup).setTitle("Download Manager")
var downloadManager: Int = PrefManager.getVal(PrefName.DownloadManager)
binding.settingsDownloadManager.setOnClickListener {
val dialog = downloadManagerDialog.setSingleChoiceItems(
managers,
downloadManager
) { dialog, count ->
downloadManager = count
PrefManager.setVal(PrefName.DownloadManager, downloadManager)
dialog.dismiss()
}.show()
dialog.window?.setDimAmount(0.8f)
}
binding.importExportSettings.setOnClickListener {
downloadsPermission(this)
val selectedArray = mutableListOf(false)
val filteredLocations = Location.entries.filter { it.exportable }
selectedArray.addAll(List(filteredLocations.size - 1) { false })
val dialog = AlertDialog.Builder(this, R.style.MyPopup)
.setTitle("Import/Export Settings")
.setMultiChoiceItems(
filteredLocations.map { it.name }.toTypedArray(),
selectedArray.toBooleanArray()
) { _, which, isChecked ->
selectedArray[which] = isChecked
}
.setPositiveButton("Import...") { dialog, _ ->
openDocumentLauncher.launch(arrayOf("*/*"))
dialog.dismiss()
}
.setNegativeButton("Export...") { dialog, _ ->
if (!selectedArray.contains(true)) {
toast("No location selected")
return@setNegativeButton
}
dialog.dismiss()
val selected =
filteredLocations.filterIndexed { index, _ -> selectedArray[index] }
if (selected.contains(Location.Protected)) {
passwordAlertDialog(true) { password ->
if (password != null) {
savePrefsToDownloads(
"DantotsuSettings",
PrefManager.exportAllPrefs(selected),
this@SettingsActivity,
password
)
} else {
toast("Password cannot be empty")
}
}
} else {
savePrefsToDownloads(
"DantotsuSettings",
PrefManager.exportAllPrefs(selected),
this@SettingsActivity,
null
)
}
}
.setNeutralButton("Cancel") { dialog, _ ->
dialog.dismiss()
}
.create()
dialog.window?.setDimAmount(0.8f)
dialog.show()
}
binding.purgeAnimeDownloads.setOnClickListener {
val dialog = AlertDialog.Builder(this, R.style.MyPopup)
.setTitle("Purge Anime Downloads")
.setMessage("Are you sure you want to purge all anime downloads?")
.setPositiveButton("Yes") { dialog, _ ->
val downloadsManager = Injekt.get<DownloadsManager>()
downloadsManager.purgeDownloads(DownloadedType.Type.ANIME)
DownloadService.sendRemoveAllDownloads(
this,
ExoplayerDownloadService::class.java,
false
)
dialog.dismiss()
}
.setNegativeButton("No") { dialog, _ ->
dialog.dismiss()
}
.create()
dialog.window?.setDimAmount(0.8f)
dialog.show()
}
binding.purgeMangaDownloads.setOnClickListener {
val dialog = AlertDialog.Builder(this, R.style.MyPopup)
.setTitle("Purge Manga Downloads")
.setMessage("Are you sure you want to purge all manga downloads?")
.setPositiveButton("Yes") { dialog, _ ->
val downloadsManager = Injekt.get<DownloadsManager>()
downloadsManager.purgeDownloads(DownloadedType.Type.MANGA)
dialog.dismiss()
}
.setNegativeButton("No") { dialog, _ ->
dialog.dismiss()
}
.create()
dialog.window?.setDimAmount(0.8f)
dialog.show()
}
binding.purgeNovelDownloads.setOnClickListener {
val dialog = AlertDialog.Builder(this, R.style.MyPopup)
.setTitle("Purge Novel Downloads")
.setMessage("Are you sure you want to purge all novel downloads?")
.setPositiveButton("Yes") { dialog, _ ->
val downloadsManager = Injekt.get<DownloadsManager>()
downloadsManager.purgeDownloads(DownloadedType.Type.NOVEL)
dialog.dismiss()
}
.setNegativeButton("No") { dialog, _ ->
dialog.dismiss()
}
.create()
dialog.window?.setDimAmount(0.8f)
dialog.show()
}
binding.settingsForceLegacyInstall.isChecked =
extensionInstaller.get() == BasePreferences.ExtensionInstaller.LEGACY
binding.settingsForceLegacyInstall.setOnCheckedChangeListener { _, isChecked ->
if (isChecked) {
extensionInstaller.set(BasePreferences.ExtensionInstaller.LEGACY)
} else {
extensionInstaller.set(BasePreferences.ExtensionInstaller.PACKAGEINSTALLER)
}
}
binding.skipExtensionIcons.isChecked = PrefManager.getVal(PrefName.SkipExtensionIcons)
binding.skipExtensionIcons.setOnCheckedChangeListener { _, isChecked ->
PrefManager.getVal(PrefName.SkipExtensionIcons, isChecked)
}
binding.NSFWExtension.isChecked = PrefManager.getVal(PrefName.NSFWExtension)
binding.NSFWExtension.setOnCheckedChangeListener { _, isChecked ->
PrefManager.setVal(PrefName.NSFWExtension, isChecked)
}
binding.userAgent.setOnClickListener {
val dialogView = layoutInflater.inflate(R.layout.dialog_user_agent, null)
val editText = dialogView.findViewById<TextInputEditText>(R.id.userAgentTextBox)
editText.setText(PrefManager.getVal<String>(PrefName.DefaultUserAgent))
val alertDialog = AlertDialog.Builder(this, R.style.MyPopup)
.setTitle("User Agent")
.setView(dialogView)
.setPositiveButton("OK") { dialog, _ ->
PrefManager.setVal(PrefName.DefaultUserAgent, editText.text.toString())
dialog.dismiss()
}
.setNeutralButton("Reset") { dialog, _ ->
PrefManager.removeVal(PrefName.DefaultUserAgent)
editText.setText("")
dialog.dismiss()
}
.setNegativeButton("Cancel") { dialog, _ ->
dialog.dismiss()
}
.create()
alertDialog.show()
alertDialog.window?.setDimAmount(0.8f)
}
val exDns = listOf(
"None",
"Cloudflare",
"Google",
"AdGuard",
"Quad9",
"AliDNS",
"DNSPod",
"360",
"Quad101",
"Mullvad",
"Controld",
"Njalla",
"Shecan",
"Libre"
)
binding.settingsExtensionDns.setText(exDns[PrefManager.getVal(PrefName.DohProvider)])
binding.settingsExtensionDns.setAdapter(ArrayAdapter(this, R.layout.item_dropdown, exDns))
binding.settingsExtensionDns.setOnItemClickListener { _, _, i, _ ->
PrefManager.setVal(PrefName.DohProvider, i)
binding.settingsExtensionDns.clearFocus()
Toast.makeText(this, "Restart app to apply changes", Toast.LENGTH_LONG).show()
}
binding.settingsDownloadInSd.isChecked = PrefManager.getVal(PrefName.SdDl)
binding.settingsDownloadInSd.setOnCheckedChangeListener { _, isChecked ->
if (isChecked) {
val arrayOfFiles = ContextCompat.getExternalFilesDirs(this, null)
if (arrayOfFiles.size > 1 && arrayOfFiles[1] != null) {
PrefManager.setVal(PrefName.SdDl, true)
} else {
binding.settingsDownloadInSd.isChecked = false
PrefManager.setVal(PrefName.SdDl, true)
snackString(getString(R.string.noSdFound))
}
} else PrefManager.setVal(PrefName.SdDl, true)
}
binding.settingsContinueMedia.isChecked = PrefManager.getVal(PrefName.ContinueMedia)
binding.settingsContinueMedia.setOnCheckedChangeListener { _, isChecked ->
PrefManager.setVal(PrefName.ContinueMedia, isChecked)
}
binding.settingsRecentlyListOnly.isChecked = PrefManager.getVal(PrefName.RecentlyListOnly)
binding.settingsRecentlyListOnly.setOnCheckedChangeListener { _, isChecked ->
PrefManager.setVal(PrefName.RecentlyListOnly, isChecked)
}
binding.settingsPreferDub.isChecked = PrefManager.getVal(PrefName.SettingsPreferDub)
binding.settingsPreferDub.setOnCheckedChangeListener { _, isChecked ->
PrefManager.setVal(PrefName.SettingsPreferDub, isChecked)
}
binding.settingsReader.setOnClickListener {
startActivity(Intent(this, ReaderSettingsActivity::class.java))
}
var previous: View = when (PrefManager.getVal<Int>(PrefName.DarkMode)) {
0 -> binding.settingsUiAuto
1 -> binding.settingsUiLight
2 -> binding.settingsUiDark
else -> binding.settingsUiAuto
}
previous.alpha = 1f
fun uiTheme(mode: Int, current: View) {
previous.alpha = 0.33f
previous = current
current.alpha = 1f
PrefManager.setVal(PrefName.DarkMode, mode)
Refresh.all()
finish()
startActivity(Intent(this, SettingsActivity::class.java))
initActivity(this)
}
binding.settingsUiAuto.setOnClickListener {
uiTheme(0, it)
}
binding.settingsUiLight.setOnClickListener {
binding.settingsUseOLED.isChecked = false
uiTheme(1, it)
}
binding.settingsUiDark.setOnClickListener {
uiTheme(2, it)
}
var previousStart: View = when (PrefManager.getVal<Int>(PrefName.DefaultStartUpTab)) {
0 -> binding.uiSettingsAnime
1 -> binding.uiSettingsHome
2 -> binding.uiSettingsManga
else -> binding.uiSettingsHome
}
previousStart.alpha = 1f
fun uiDefault(mode: Int, current: View) {
previousStart.alpha = 0.33f
previousStart = current
current.alpha = 1f
PrefManager.setVal(PrefName.DefaultStartUpTab, mode)
initActivity(this)
}
binding.uiSettingsAnime.setOnClickListener {
uiDefault(0, it)
}
binding.uiSettingsHome.setOnClickListener {
uiDefault(1, it)
}
binding.uiSettingsManga.setOnClickListener {
uiDefault(2, it)
}
binding.settingsShowYt.isChecked = PrefManager.getVal(PrefName.ShowYtButton)
binding.settingsShowYt.setOnCheckedChangeListener { _, isChecked ->
PrefManager.setVal(PrefName.ShowYtButton, isChecked)
}
var previousEp: View = when (PrefManager.getVal<Int>(PrefName.AnimeDefaultView)) {
0 -> binding.settingsEpList
1 -> binding.settingsEpGrid
2 -> binding.settingsEpCompact
else -> binding.settingsEpList
}
previousEp.alpha = 1f
fun uiEp(mode: Int, current: View) {
previousEp.alpha = 0.33f
previousEp = current
current.alpha = 1f
PrefManager.setVal(PrefName.AnimeDefaultView, mode)
}
binding.settingsEpList.setOnClickListener {
uiEp(0, it)
}
binding.settingsEpGrid.setOnClickListener {
uiEp(1, it)
}
binding.settingsEpCompact.setOnClickListener {
uiEp(2, it)
}
var previousChp: View = when (PrefManager.getVal<Int>(PrefName.MangaDefaultView)) {
0 -> binding.settingsChpList
1 -> binding.settingsChpCompact
else -> binding.settingsChpList
}
previousChp.alpha = 1f
fun uiChp(mode: Int, current: View) {
previousChp.alpha = 0.33f
previousChp = current
current.alpha = 1f
PrefManager.setVal(PrefName.MangaDefaultView, mode)
}
binding.settingsChpList.setOnClickListener {
uiChp(0, it)
}
binding.settingsChpCompact.setOnClickListener {
uiChp(1, it)
}
binding.settingBuyMeCoffee.setOnClickListener {
lifecycleScope.launch {
it.pop()
}
openLinkInBrowser("https://www.buymeacoffee.com/rebelonion")
}
lifecycleScope.launch {
binding.settingBuyMeCoffee.pop()
}
binding.loginDiscord.setOnClickListener {
openLinkInBrowser(getString(R.string.discord))
}
binding.loginGithub.setOnClickListener {
openLinkInBrowser(getString(R.string.github))
}
binding.loginTelegram.setOnClickListener {
openLinkInBrowser(getString(R.string.telegram))
}
binding.settingsUi.setOnClickListener {
startActivity(Intent(this, UserInterfaceSettingsActivity::class.java))
}
binding.settingsFAQ.setOnClickListener {
startActivity(Intent(this, FAQActivity::class.java))
}
(binding.settingsLogo.drawable as Animatable).start()
val array = resources.getStringArray(R.array.tips)
binding.settingsLogo.setSafeOnClickListener {
cursedCounter++
(binding.settingsLogo.drawable as Animatable).start()
if (cursedCounter % 7 == 0) {
Toast.makeText(this, "youwu have been cuwsed :pwayge:", Toast.LENGTH_LONG).show()
val url = "https://www.youtube.com/watch?v=dQw4w9WgXcQ"
openLinkInBrowser(url)
//PrefManager.setVal(PrefName.SomethingSpecial, !PrefManager.getVal(PrefName.SomethingSpecial, false))
} else {
snackString(array[(Math.random() * array.size).toInt()], this)
}
}
binding.settingsDev.setOnClickListener {
DevelopersDialogFragment().show(supportFragmentManager, "dialog")
}
binding.settingsForks.setOnClickListener {
ForksDialogFragment().show(supportFragmentManager, "dialog")
}
binding.settingsDisclaimer.setOnClickListener {
val title = getString(R.string.disclaimer)
val text = TextView(this)
text.setText(R.string.full_disclaimer)
CustomBottomDialog.newInstance().apply {
setTitleText(title)
addView(text)
setNegativeButton(currContext()!!.getString(R.string.close)) {
dismiss()
}
show(supportFragmentManager, "dialog")
}
}
var curTime = PrefManager.getVal(PrefName.SubscriptionsTimeS, defaultTime)
val timeNames = timeMinutes.map {
val mins = it % 60
val hours = it / 60
if (it > 0) "${if (hours > 0) "$hours hrs " else ""}${if (mins > 0) "$mins mins" else ""}"
else getString(R.string.do_not_update)
}.toTypedArray()
binding.settingsSubscriptionsTime.text =
getString(R.string.subscriptions_checking_time_s, timeNames[curTime])
val speedDialog = AlertDialog.Builder(this, R.style.MyPopup)
.setTitle(R.string.subscriptions_checking_time)
binding.settingsSubscriptionsTime.setOnClickListener {
val dialog = speedDialog.setSingleChoiceItems(timeNames, curTime) { dialog, i ->
curTime = i
binding.settingsSubscriptionsTime.text =
getString(R.string.subscriptions_checking_time_s, timeNames[i])
PrefManager.setVal(PrefName.SubscriptionsTimeS, curTime)
dialog.dismiss()
startSubscription(true)
}.show()
dialog.window?.setDimAmount(0.8f)
}
binding.settingsSubscriptionsTime.setOnLongClickListener {
startSubscription(true)
true
}
binding.settingsNotificationsCheckingSubscriptions.isChecked =
PrefManager.getVal(PrefName.SubscriptionCheckingNotifications)
binding.settingsNotificationsCheckingSubscriptions.setOnCheckedChangeListener { _, isChecked ->
PrefManager.setVal(PrefName.SubscriptionCheckingNotifications, isChecked)
if (isChecked)
Notifications.createChannel(
this,
null,
"subscription_checking",
getString(R.string.checking_subscriptions),
false
)
else
Notifications.deleteChannel(this, "subscription_checking")
}
binding.settingsNotificationsCheckingSubscriptions.setOnLongClickListener {
openSettings(this, null)
}
if (!BuildConfig.FLAVOR.contains("fdroid")) {
binding.settingsLogo.setOnLongClickListener {
lifecycleScope.launch(Dispatchers.IO) {
AppUpdater.check(this@SettingsActivity, true)
}
true
}
binding.settingsCheckUpdate.isChecked = PrefManager.getVal(PrefName.CheckUpdate)
binding.settingsCheckUpdate.setOnCheckedChangeListener { _, isChecked ->
PrefManager.setVal(PrefName.CheckUpdate, isChecked)
if (!isChecked) {
snackString(getString(R.string.long_click_to_check_update))
}
}
binding.settingsCheckUpdate.setOnLongClickListener {
lifecycleScope.launch(Dispatchers.IO) {
AppUpdater.check(this@SettingsActivity, true)
}
true
}
binding.settingsShareUsername.isChecked = PrefManager.getVal(PrefName.SharedUserID)
binding.settingsShareUsername.setOnCheckedChangeListener { _, isChecked ->
PrefManager.setVal(PrefName.SharedUserID, isChecked)
}
} else {
binding.settingsCheckUpdate.visibility = View.GONE
binding.settingsShareUsername.visibility = View.GONE
binding.settingsCheckUpdate.isEnabled = false
binding.settingsShareUsername.isEnabled = false
binding.settingsCheckUpdate.isChecked = false
binding.settingsShareUsername.isChecked = false
}
binding.settingsAccountHelp.setOnClickListener {
val title = getString(R.string.account_help)
val full = getString(R.string.full_account_help)
CustomBottomDialog.newInstance().apply {
setTitleText(title)
addView(
TextView(it.context).apply {
val markWon = Markwon.builder(it.context)
.usePlugin(SoftBreakAddsNewLinePlugin.create()).build()
markWon.setMarkdown(this, full)
}
)
}.show(supportFragmentManager, "dialog")
}
fun reload() {
if (Anilist.token != null) {
binding.settingsAnilistLogin.setText(R.string.logout)
binding.settingsAnilistLogin.setOnClickListener {
Anilist.removeSavedToken()
restartMainActivity.isEnabled = true
reload()
}
binding.settingsAnilistUsername.visibility = View.VISIBLE
binding.settingsAnilistUsername.text = Anilist.username
binding.settingsAnilistAvatar.loadImage(Anilist.avatar)
binding.settingsMALLoginRequired.visibility = View.GONE
binding.settingsMALLogin.visibility = View.VISIBLE
binding.settingsMALUsername.visibility = View.VISIBLE
if (MAL.token != null) {
binding.settingsMALLogin.setText(R.string.logout)
binding.settingsMALLogin.setOnClickListener {
MAL.removeSavedToken(it.context)
restartMainActivity.isEnabled = true
reload()
}
binding.settingsMALUsername.visibility = View.VISIBLE
binding.settingsMALUsername.text = MAL.username
binding.settingsMALAvatar.loadImage(MAL.avatar)
} else {
binding.settingsMALAvatar.setImageResource(R.drawable.ic_round_person_24)
binding.settingsMALUsername.visibility = View.GONE
binding.settingsMALLogin.setText(R.string.login)
binding.settingsMALLogin.setOnClickListener {
MAL.loginIntent(this)
}
}
} else {
binding.settingsAnilistAvatar.setImageResource(R.drawable.ic_round_person_24)
binding.settingsAnilistUsername.visibility = View.GONE
binding.settingsAnilistLogin.setText(R.string.login)
binding.settingsAnilistLogin.setOnClickListener {
Anilist.loginIntent(this)
}
binding.settingsMALLoginRequired.visibility = View.VISIBLE
binding.settingsMALLogin.visibility = View.GONE
binding.settingsMALUsername.visibility = View.GONE
}
if (Discord.token != null) {
val id = PrefManager.getVal(PrefName.DiscordId, null as String?)
val avatar = PrefManager.getVal(PrefName.DiscordAvatar, null as String?)
val username = PrefManager.getVal(PrefName.DiscordUserName, null as String?)
if (id != null && avatar != null) {
binding.settingsDiscordAvatar.loadImage("https://cdn.discordapp.com/avatars/$id/$avatar.png")
}
binding.settingsDiscordUsername.visibility = View.VISIBLE
binding.settingsDiscordUsername.text =
username ?: Discord.token?.replace(Regex("."), "*")
binding.settingsDiscordLogin.setText(R.string.logout)
binding.settingsDiscordLogin.setOnClickListener {
Discord.removeSavedToken(this)
restartMainActivity.isEnabled = true
reload()
}
binding.imageSwitcher.visibility = View.VISIBLE
var initialStatus = when (PrefManager.getVal<String>(PrefName.DiscordStatus)) {
"online" -> R.drawable.discord_status_online
"idle" -> R.drawable.discord_status_idle
"dnd" -> R.drawable.discord_status_dnd
else -> R.drawable.discord_status_online
}
binding.imageSwitcher.setImageResource(initialStatus)
val zoomInAnimation = AnimationUtils.loadAnimation(this, R.anim.bounce_zoom)
binding.imageSwitcher.setOnClickListener {
var status = "online"
initialStatus = when (initialStatus) {
R.drawable.discord_status_online -> {
status = "idle"
R.drawable.discord_status_idle
}
R.drawable.discord_status_idle -> {
status = "dnd"
R.drawable.discord_status_dnd
}
R.drawable.discord_status_dnd -> {
status = "online"
R.drawable.discord_status_online
}
else -> R.drawable.discord_status_online
}
PrefManager.setVal(PrefName.DiscordStatus, status)
binding.imageSwitcher.setImageResource(initialStatus)
binding.imageSwitcher.startAnimation(zoomInAnimation)
}
} else {
binding.imageSwitcher.visibility = View.GONE
binding.settingsDiscordAvatar.setImageResource(R.drawable.ic_round_person_24)
binding.settingsDiscordUsername.visibility = View.GONE
binding.settingsDiscordLogin.setText(R.string.login)
binding.settingsDiscordLogin.setOnClickListener {
Discord.warning(this).show(supportFragmentManager, "dialog")
}
}
}
reload()
lifecycleScope.launch(Dispatchers.IO) {
delay(2000)
runOnUiThread {
if (Random.nextInt(0, 100) > 69) {
CustomBottomDialog.newInstance().apply {
title = "Enjoying the App?"
addView(TextView(this@SettingsActivity).apply {
text =
"Consider donating!"
})
setNegativeButton("no moners :(") {
snackString("That's alright, you'll be a rich man soon :prayge:")
dismiss()
}
setPositiveButton("denote :)") {
binding.settingBuyMeCoffee.performClick()
dismiss()
}
show(supportFragmentManager, "dialog")
}
}
}
}
}
override fun onResult(dialogTag: String, which: Int, extras: Bundle): Boolean {
if (which == BUTTON_POSITIVE) {
if (dialogTag == "colorPicker") {
val color = extras.getInt(SimpleColorDialog.COLOR)
PrefManager.setVal(PrefName.CustomThemeInt, color)
logger("Custom Theme: $color")
}
}
return true
}
private fun restartApp() {
Snackbar.make(
binding.root,
R.string.restart_app, Snackbar.LENGTH_SHORT
).apply {
val mainIntent =
Intent.makeRestartActivityTask(
context.packageManager.getLaunchIntentForPackage(
context.packageName
)!!.component
)
setAction("Do it!") {
context.startActivity(mainIntent)
Runtime.getRuntime().exit(0)
}
show()
}
}
private fun passwordAlertDialog(isExporting: Boolean, callback: (CharArray?) -> Unit) {
val password = CharArray(16).apply { fill('0') }
// Inflate the dialog layout
val dialogView = LayoutInflater.from(this).inflate(R.layout.dialog_user_agent, null)
val box = dialogView.findViewById<TextInputEditText>(R.id.userAgentTextBox)
box?.hint = "Password"
box?.setSingleLine()
val dialog = AlertDialog.Builder(this, R.style.MyPopup)
.setTitle("Enter Password")
.setView(dialogView)
.setPositiveButton("OK", null)
.setNegativeButton("Cancel") { dialog, _ ->
password.fill('0')
dialog.dismiss()
callback(null)
}
.create()
fun handleOkAction() {
val editText = dialog.findViewById<TextInputEditText>(R.id.userAgentTextBox)
if (editText?.text?.isNotBlank() == true) {
editText.text?.toString()?.trim()?.toCharArray(password)
dialog.dismiss()
callback(password)
} else {
toast("Password cannot be empty")
}
}
box?.setOnEditorActionListener { _, actionId, _ ->
if (actionId == EditorInfo.IME_ACTION_DONE) {
handleOkAction()
true
} else {
false
}
}
val subtitleTextView = dialogView.findViewById<TextView>(R.id.subtitle)
subtitleTextView?.visibility = View.VISIBLE
if (!isExporting)
subtitleTextView?.text = "Enter your password to decrypt the file"
dialog.window?.setDimAmount(0.8f)
dialog.show()
// Override the positive button here
dialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener {
handleOkAction()
}
}
companion object {
fun getDeviceInfo(): String {
return """
dantotsu Version: ${BuildConfig.VERSION_NAME}
Device: $BRAND $DEVICE
Architecture: ${getArch()}
OS Version: $CODENAME $RELEASE ($SDK_INT)
""".trimIndent()
}
private fun getArch(): String {
SUPPORTED_ABIS.forEach {
when (it) {
"arm64-v8a" -> return "aarch64"
"armeabi-v7a" -> return "arm"
"x86_64" -> return "x86_64"
"x86" -> return "i686"
}
}
return System.getProperty("os.arch") ?: System.getProperty("os.product.cpu.abi")
?: "Unknown Architecture"
}
}
}