Initial commit
This commit is contained in:
commit
21bfbfb139
520 changed files with 47819 additions and 0 deletions
|
@ -0,0 +1,30 @@
|
|||
package ani.dantotsu.settings
|
||||
|
||||
import java.io.Serializable
|
||||
|
||||
data class CurrentNovelReaderSettings(
|
||||
var currentThemeName: String = "Default",
|
||||
var layout: Layouts = Layouts.PAGED,
|
||||
var dualPageMode: CurrentReaderSettings.DualPageModes = CurrentReaderSettings.DualPageModes.Automatic,
|
||||
var lineHeight: Float = 1.4f,
|
||||
var margin: Float = 0.06f,
|
||||
var justify: Boolean = true,
|
||||
var hyphenation: Boolean = true,
|
||||
var useDarkTheme: Boolean = false,
|
||||
var invert: Boolean = false,
|
||||
var maxInlineSize: Int = 720,
|
||||
var maxBlockSize: Int = 1440,
|
||||
var horizontalScrollBar: Boolean = true,
|
||||
var keepScreenOn: Boolean = false,
|
||||
var volumeButtons: Boolean = false,
|
||||
) : Serializable {
|
||||
|
||||
enum class Layouts(val string: String) {
|
||||
PAGED("Paged"),
|
||||
SCROLLED("Scrolled");
|
||||
|
||||
companion object {
|
||||
operator fun get(value: Int) = values().firstOrNull { it.ordinal == value }
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
package ani.dantotsu.settings
|
||||
|
||||
import java.io.Serializable
|
||||
|
||||
data class CurrentReaderSettings(
|
||||
var direction: Directions = Directions.TOP_TO_BOTTOM,
|
||||
var layout: Layouts = Layouts.CONTINUOUS,
|
||||
var dualPageMode: DualPageModes = DualPageModes.Automatic,
|
||||
var overScrollMode: Boolean = true,
|
||||
var trueColors: Boolean = false,
|
||||
var rotation: Boolean = true,
|
||||
var padding: Boolean = true,
|
||||
var hidePageNumbers: Boolean = false,
|
||||
var horizontalScrollBar: Boolean = true,
|
||||
var keepScreenOn: Boolean = false,
|
||||
var volumeButtons: Boolean = false,
|
||||
var wrapImages: Boolean = false,
|
||||
var longClickImage: Boolean = true,
|
||||
var cropBorders: Boolean = false,
|
||||
var cropBorderThreshold: Int = 10,
|
||||
) : Serializable {
|
||||
|
||||
enum class Directions {
|
||||
TOP_TO_BOTTOM,
|
||||
RIGHT_TO_LEFT,
|
||||
BOTTOM_TO_TOP,
|
||||
LEFT_TO_RIGHT;
|
||||
|
||||
companion object {
|
||||
operator fun get(value: Int) = values().firstOrNull { it.ordinal == value }
|
||||
}
|
||||
}
|
||||
|
||||
enum class Layouts {
|
||||
PAGED,
|
||||
CONTINUOUS_PAGED,
|
||||
CONTINUOUS;
|
||||
|
||||
companion object {
|
||||
operator fun get(value: Int) = values().firstOrNull { it.ordinal == value }
|
||||
}
|
||||
}
|
||||
|
||||
enum class DualPageModes {
|
||||
No, Automatic, Force;
|
||||
|
||||
companion object {
|
||||
operator fun get(value: Int) = values().firstOrNull { it.ordinal == value }
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun applyWebtoon(settings: CurrentReaderSettings) {
|
||||
settings.apply {
|
||||
layout = Layouts.CONTINUOUS
|
||||
direction = Directions.TOP_TO_BOTTOM
|
||||
dualPageMode = DualPageModes.No
|
||||
padding = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
8
app/src/main/java/ani/dantotsu/settings/Developer.kt
Normal file
8
app/src/main/java/ani/dantotsu/settings/Developer.kt
Normal file
|
@ -0,0 +1,8 @@
|
|||
package ani.dantotsu.settings
|
||||
|
||||
data class Developer(
|
||||
val name: String,
|
||||
val pfp: String,
|
||||
val role: String,
|
||||
val url: String
|
||||
)
|
38
app/src/main/java/ani/dantotsu/settings/DevelopersAdapter.kt
Normal file
38
app/src/main/java/ani/dantotsu/settings/DevelopersAdapter.kt
Normal file
|
@ -0,0 +1,38 @@
|
|||
package ani.dantotsu.settings
|
||||
|
||||
import android.view.LayoutInflater
|
||||
import android.view.ViewGroup
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import ani.dantotsu.databinding.ItemDeveloperBinding
|
||||
import ani.dantotsu.loadData
|
||||
import ani.dantotsu.loadImage
|
||||
import ani.dantotsu.openLinkInBrowser
|
||||
import ani.dantotsu.setAnimation
|
||||
|
||||
class DevelopersAdapter(private val developers: Array<Developer>) :
|
||||
RecyclerView.Adapter<DevelopersAdapter.DeveloperViewHolder>() {
|
||||
private val uiSettings = loadData<UserInterfaceSettings>("ui_settings") ?: UserInterfaceSettings()
|
||||
|
||||
inner class DeveloperViewHolder(val binding: ItemDeveloperBinding) : RecyclerView.ViewHolder(binding.root) {
|
||||
init {
|
||||
itemView.setOnClickListener {
|
||||
openLinkInBrowser(developers[bindingAdapterPosition].url)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): DeveloperViewHolder {
|
||||
return DeveloperViewHolder(ItemDeveloperBinding.inflate(LayoutInflater.from(parent.context), parent, false))
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: DeveloperViewHolder, position: Int) {
|
||||
val b = holder.binding
|
||||
setAnimation(b.root.context, b.root, uiSettings)
|
||||
val dev = developers[position]
|
||||
b.devName.text = dev.name
|
||||
b.devProfile.loadImage(dev.pfp)
|
||||
b.devRole.text = dev.role
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int = developers.size
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
package ani.dantotsu.settings
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import ani.dantotsu.BottomSheetDialogFragment
|
||||
import ani.dantotsu.databinding.BottomSheetDevelopersBinding
|
||||
|
||||
class DevelopersDialogFragment : BottomSheetDialogFragment() {
|
||||
private var _binding: BottomSheetDevelopersBinding? = null
|
||||
private val binding get() = _binding!!
|
||||
|
||||
private val developers = arrayOf(
|
||||
Developer("vorobyovgabriel","https://avatars.githubusercontent.com/u/99561687?s=120&v=4","Owner","https://github.com/vorobyovgabriel"),
|
||||
Developer("brahmkshtriya","https://avatars.githubusercontent.com/u/69040506?s=120&v=4","Maintainer","https://github.com/brahmkshatriya"),
|
||||
Developer("jeelpatel231","https://avatars.githubusercontent.com/u/33726155?s=120&v=4","Contributor","https://github.com/jeelpatel231"),
|
||||
Developer("blatzar","https://avatars.githubusercontent.com/u/46196380?s=120&v=4","Contributor","https://github.com/Blatzar"),
|
||||
Developer("bilibox","https://avatars.githubusercontent.com/u/1800580?s=120&v=4","Contributor","https://github.com/Bilibox"),
|
||||
Developer("sutslec","https://avatars.githubusercontent.com/u/27722281?s=120&v=4","Contributor","https://github.com/Sutslec"),
|
||||
Developer("4jx","https://avatars.githubusercontent.com/u/79868816?s=120&v=4","Contributor","https://github.com/4JX"),
|
||||
Developer("xtrm-en","https://avatars.githubusercontent.com/u/26600206?s=120&v=4","Contributor","https://github.com/xtrm-en"),
|
||||
Developer("scrazzz","https://avatars.githubusercontent.com/u/70033559?s=120&v=4","Contributor","https://github.com/scrazzz"),
|
||||
Developer("defcoding","https://avatars.githubusercontent.com/u/39608887?s=120&v=4","Contributor","https://github.com/defcoding"),
|
||||
Developer("adolar0042","https://avatars.githubusercontent.com/u/39769465?s=120&v=4","Contributor","https://github.com/adolar0042"),
|
||||
Developer("diegopyl1209","https://avatars.githubusercontent.com/u/80992641?s=120&v=4","Contributor","https://github.com/diegopyl1209"),
|
||||
Developer("sreekrishna2001","https://avatars.githubusercontent.com/u/67505103?s=120&v=4","Contributor","https://github.com/Sreekrishna2001"),
|
||||
Developer("riimuru","https://avatars.githubusercontent.com/u/57333995?s=120&v=4","Contributor","https://github.com/riimuru"),
|
||||
Developer("vu nguyen","https://avatars.githubusercontent.com/u/68330291?s=120&v=4","Contributor","https://github.com/hoangvu12"),
|
||||
Developer("animejeff","https://avatars.githubusercontent.com/u/101831300?s=120&v=4","Contributor","https://github.com/AnimeJeff"),
|
||||
Developer("antonydp","https://avatars.githubusercontent.com/u/38143733?s=120&v=4","Contributor","https://github.com/antonydp"),
|
||||
Developer("tobybridle","https://avatars.githubusercontent.com/u/52335751?s=120&v=4","Contributor","https://github.com/TobyBridle"),
|
||||
Developer("enimax","https://avatars.githubusercontent.com/u/107899019?s=120&v=4","Contributor","https://github.com/enimax-anime"),
|
||||
Developer("vipulog","https://avatars.githubusercontent.com/u/90324465?s=120&v=4","Contributor","https://github.com/VipulOG")
|
||||
)
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
|
||||
_binding = BottomSheetDevelopersBinding.inflate(inflater, container, false)
|
||||
return binding.root
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
binding.devsRecyclerView.adapter = DevelopersAdapter(developers)
|
||||
binding.devsRecyclerView.layoutManager = LinearLayoutManager(requireContext())
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
_binding = null
|
||||
super.onDestroy()
|
||||
}
|
||||
}
|
231
app/src/main/java/ani/dantotsu/settings/ExtensionsActivity.kt
Normal file
231
app/src/main/java/ani/dantotsu/settings/ExtensionsActivity.kt
Normal file
|
@ -0,0 +1,231 @@
|
|||
package ani.dantotsu.settings
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.NotificationManager
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.net.Uri
|
||||
import android.os.Build.*
|
||||
import android.os.Build.VERSION.*
|
||||
import android.os.Bundle
|
||||
import android.provider.Settings
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.ImageView
|
||||
import android.widget.TextView
|
||||
import androidx.activity.OnBackPressedCallback
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.app.NotificationCompat
|
||||
import androidx.core.view.updateLayoutParams
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import ani.dantotsu.*
|
||||
import ani.dantotsu.aniyomi.anime.AnimeExtensionManager
|
||||
import ani.dantotsu.aniyomi.anime.model.AnimeExtension
|
||||
import ani.dantotsu.databinding.ActivityExtensionsBinding
|
||||
import com.bumptech.glide.Glide
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import rx.android.schedulers.AndroidSchedulers
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
|
||||
|
||||
class ExtensionsActivity : AppCompatActivity() {
|
||||
private val restartMainActivity = object : OnBackPressedCallback(false) {
|
||||
override fun handleOnBackPressed() = startMainActivity(this@ExtensionsActivity)
|
||||
}
|
||||
lateinit var binding: ActivityExtensionsBinding
|
||||
private lateinit var extensionsRecyclerView: RecyclerView
|
||||
private lateinit var allextenstionsRecyclerView: RecyclerView
|
||||
private val animeExtensionManager: AnimeExtensionManager by injectLazy()
|
||||
private val extensionsAdapter = ExtensionsAdapter { pkgName ->
|
||||
animeExtensionManager.uninstallExtension(pkgName)
|
||||
}
|
||||
private val allExtensionsAdapter = AllExtensionsAdapter(lifecycleScope) { pkgName ->
|
||||
if (SDK_INT >= VERSION_CODES.O) {
|
||||
// If we don't have permission to install unknown apps, request it
|
||||
if (!packageManager.canRequestPackageInstalls()) {
|
||||
startActivityForResult(
|
||||
Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES).setData(
|
||||
Uri.parse("package:$packageName")
|
||||
), 1
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
val notificationManager =
|
||||
getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
||||
|
||||
// Start the installation process
|
||||
animeExtensionManager.installExtension(pkgName)
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(
|
||||
{ installStep ->
|
||||
val builder = NotificationCompat.Builder(this,
|
||||
ani.dantotsu.aniyomi.data.Notifications.CHANNEL_DOWNLOADER_PROGRESS
|
||||
)
|
||||
.setSmallIcon(R.drawable.ic_round_sync_24)
|
||||
.setContentTitle("Installing extension")
|
||||
.setContentText("Step: $installStep")
|
||||
.setPriority(NotificationCompat.PRIORITY_LOW)
|
||||
notificationManager.notify(1, builder.build())
|
||||
},
|
||||
{ error ->
|
||||
val builder = NotificationCompat.Builder(this,
|
||||
ani.dantotsu.aniyomi.data.Notifications.CHANNEL_DOWNLOADER_ERROR
|
||||
)
|
||||
.setSmallIcon(R.drawable.ic_round_info_24)
|
||||
.setContentTitle("Installation failed")
|
||||
.setContentText("Error: ${error.message}")
|
||||
.setPriority(NotificationCompat.PRIORITY_HIGH)
|
||||
notificationManager.notify(1, builder.build())
|
||||
},
|
||||
{
|
||||
val builder = NotificationCompat.Builder(this,
|
||||
ani.dantotsu.aniyomi.data.Notifications.CHANNEL_DOWNLOADER_PROGRESS)
|
||||
.setSmallIcon(androidx.media3.ui.R.drawable.exo_ic_check)
|
||||
.setContentTitle("Installation complete")
|
||||
.setContentText("The extension has been successfully installed.")
|
||||
.setPriority(NotificationCompat.PRIORITY_LOW)
|
||||
notificationManager.notify(1, builder.build())
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
|
||||
@SuppressLint("SetTextI18n")
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
binding = ActivityExtensionsBinding.inflate(layoutInflater)
|
||||
setContentView(binding.root)
|
||||
|
||||
extensionsRecyclerView = findViewById(R.id.extensionsRecyclerView)
|
||||
extensionsRecyclerView.layoutManager = LinearLayoutManager(this)
|
||||
extensionsRecyclerView.adapter = extensionsAdapter
|
||||
|
||||
allextenstionsRecyclerView = findViewById(R.id.allExtensionsRecyclerView)
|
||||
allextenstionsRecyclerView.layoutManager = LinearLayoutManager(this)
|
||||
allextenstionsRecyclerView.adapter = allExtensionsAdapter
|
||||
|
||||
lifecycleScope.launch {
|
||||
animeExtensionManager.installedExtensionsFlow.collect { extensions ->
|
||||
extensionsAdapter.updateData(extensions)
|
||||
}
|
||||
}
|
||||
lifecycleScope.launch {
|
||||
animeExtensionManager.availableExtensionsFlow.collect { extensions ->
|
||||
allExtensionsAdapter.updateData(extensions)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
initActivity(this)
|
||||
|
||||
|
||||
|
||||
binding.settingsContainer.updateLayoutParams<ViewGroup.MarginLayoutParams> {
|
||||
topMargin = statusBarHeight
|
||||
bottomMargin = navBarHeight
|
||||
}
|
||||
|
||||
onBackPressedDispatcher.addCallback(this, restartMainActivity)
|
||||
|
||||
binding.settingsBack.setOnClickListener {
|
||||
onBackPressedDispatcher.onBackPressed()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private class ExtensionsAdapter(private val onUninstallClicked: (String) -> Unit) : RecyclerView.Adapter<ExtensionsAdapter.ViewHolder>() {
|
||||
|
||||
private var extensions: List<AnimeExtension.Installed> = emptyList()
|
||||
|
||||
fun updateData(newExtensions: List<AnimeExtension.Installed>) {
|
||||
extensions = newExtensions
|
||||
notifyDataSetChanged()
|
||||
}
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
||||
val view = LayoutInflater.from(parent.context)
|
||||
.inflate(R.layout.item_extension, parent, false)
|
||||
return ViewHolder(view)
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
||||
val extension = extensions[position]
|
||||
holder.extensionNameTextView.text = extension.name
|
||||
holder.extensionIconImageView.setImageDrawable(extension.icon)
|
||||
holder.closeTextView.text = "Uninstall"
|
||||
holder.closeTextView.setOnClickListener {
|
||||
onUninstallClicked(extension.pkgName)
|
||||
}
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int = extensions.size
|
||||
|
||||
inner class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
|
||||
val extensionNameTextView: TextView = view.findViewById(R.id.extensionNameTextView)
|
||||
val extensionIconImageView: ImageView = view.findViewById(R.id.extensionIconImageView)
|
||||
val closeTextView: TextView = view.findViewById(R.id.closeTextView)
|
||||
}
|
||||
}
|
||||
|
||||
private class AllExtensionsAdapter(private val coroutineScope: CoroutineScope,
|
||||
private val onButtonClicked: (AnimeExtension.Available) -> Unit) : RecyclerView.Adapter<AllExtensionsAdapter.ViewHolder>() {
|
||||
private var extensions: List<AnimeExtension.Available> = emptyList()
|
||||
|
||||
fun updateData(newExtensions: List<AnimeExtension.Available>) {
|
||||
extensions = newExtensions
|
||||
println("Extensions update: $extensions")
|
||||
notifyDataSetChanged()
|
||||
}
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): AllExtensionsAdapter.ViewHolder {
|
||||
val view = LayoutInflater.from(parent.context)
|
||||
.inflate(R.layout.item_extension_all, parent, false)
|
||||
return ViewHolder(view)
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
||||
val extension = extensions[position]
|
||||
holder.extensionNameTextView.text = extension.name
|
||||
coroutineScope.launch {
|
||||
val drawable = urlToDrawable(holder.itemView.context, extension.iconUrl)
|
||||
holder.extensionIconImageView.setImageDrawable(drawable)
|
||||
}
|
||||
holder.closeTextView.text = "Install"
|
||||
holder.closeTextView.setOnClickListener {
|
||||
onButtonClicked(extension)
|
||||
}
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int = extensions.size
|
||||
|
||||
inner class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
|
||||
val extensionNameTextView: TextView = view.findViewById(R.id.extensionNameTextView)
|
||||
val extensionIconImageView: ImageView = view.findViewById(R.id.extensionIconImageView)
|
||||
val closeTextView: TextView = view.findViewById(R.id.closeTextView)
|
||||
}
|
||||
|
||||
suspend fun urlToDrawable(context: Context, url: String): Drawable? {
|
||||
return withContext(Dispatchers.IO) {
|
||||
try {
|
||||
return@withContext Glide.with(context)
|
||||
.load(url)
|
||||
.submit()
|
||||
.get()
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
return@withContext null
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
49
app/src/main/java/ani/dantotsu/settings/FAQActivity.kt
Normal file
49
app/src/main/java/ani/dantotsu/settings/FAQActivity.kt
Normal file
|
@ -0,0 +1,49 @@
|
|||
package ani.dantotsu.settings
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import ani.dantotsu.R
|
||||
import ani.dantotsu.currContext
|
||||
import ani.dantotsu.databinding.ActivityFaqBinding
|
||||
import ani.dantotsu.initActivity
|
||||
|
||||
class FAQActivity : AppCompatActivity() {
|
||||
private lateinit var binding: ActivityFaqBinding
|
||||
|
||||
private val faqs = listOf(
|
||||
|
||||
Triple(R.drawable.ic_round_help_24, currContext()!!.getString(R.string.question_1), currContext()!!.getString(R.string.answer_1)),
|
||||
Triple(R.drawable.ic_round_auto_awesome_24, currContext()!!.getString(R.string.question_2), currContext()!!.getString(R.string.answer_2)),
|
||||
Triple(R.drawable.ic_round_auto_awesome_24, currContext()!!.getString(R.string.question_17), currContext()!!.getString(R.string.answer_17)),
|
||||
Triple(R.drawable.ic_round_download_24, currContext()!!.getString(R.string.question_3), currContext()!!.getString(R.string.answer_3)),
|
||||
Triple(R.drawable.ic_round_help_24, currContext()!!.getString(R.string.question_16), currContext()!!.getString(R.string.answer_16)),
|
||||
Triple(R.drawable.ic_round_dns_24, currContext()!!.getString(R.string.question_4), currContext()!!.getString(R.string.answer_4)),
|
||||
Triple(R.drawable.ic_baseline_screen_lock_portrait_24, currContext()!!.getString(R.string.question_5), currContext()!!.getString(R.string.answer_5)),
|
||||
Triple(R.drawable.ic_anilist, currContext()!!.getString(R.string.question_6), currContext()!!.getString(R.string.answer_6)),
|
||||
Triple(R.drawable.ic_round_movie_filter_24, currContext()!!.getString(R.string.question_7), currContext()!!.getString(R.string.answer_7)),
|
||||
Triple(R.drawable.ic_round_menu_book_24, currContext()!!.getString(R.string.question_8), currContext()!!.getString(R.string.answer_8)),
|
||||
Triple(R.drawable.ic_round_lock_open_24, currContext()!!.getString(R.string.question_9), currContext()!!.getString(R.string.answer_9)),
|
||||
Triple(R.drawable.ic_round_smart_button_24, currContext()!!.getString(R.string.question_10), currContext()!!.getString(R.string.answer_10)),
|
||||
Triple(R.drawable.ic_round_smart_button_24, currContext()!!.getString(R.string.question_11), currContext()!!.getString(R.string.answer_11)),
|
||||
Triple(R.drawable.ic_round_info_24, currContext()!!.getString(R.string.question_12), currContext()!!.getString(R.string.answer_12)),
|
||||
Triple(R.drawable.ic_round_help_24, currContext()!!.getString(R.string.question_13), currContext()!!.getString(R.string.answer_13)),
|
||||
Triple(R.drawable.ic_round_art_track_24, currContext()!!.getString(R.string.question_14), currContext()!!.getString(R.string.answer_14)),
|
||||
Triple(R.drawable.ic_round_video_settings_24, currContext()!!.getString(R.string.question_15), currContext()!!.getString(R.string.answer_15))
|
||||
)
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
binding = ActivityFaqBinding.inflate(layoutInflater)
|
||||
setContentView(binding.root)
|
||||
|
||||
initActivity(this)
|
||||
|
||||
binding.devsTitle2.setOnClickListener {
|
||||
onBackPressedDispatcher.onBackPressed()
|
||||
}
|
||||
|
||||
binding.devsRecyclerView.adapter = FAQAdapter(faqs, supportFragmentManager)
|
||||
binding.devsRecyclerView.layoutManager = LinearLayoutManager(this)
|
||||
}
|
||||
}
|
45
app/src/main/java/ani/dantotsu/settings/FAQAdapter.kt
Normal file
45
app/src/main/java/ani/dantotsu/settings/FAQAdapter.kt
Normal file
|
@ -0,0 +1,45 @@
|
|||
package ani.dantotsu.settings
|
||||
|
||||
import android.view.LayoutInflater
|
||||
import android.view.ViewGroup
|
||||
import android.widget.TextView
|
||||
import androidx.fragment.app.FragmentManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import ani.dantotsu.databinding.ItemQuestionBinding
|
||||
import ani.dantotsu.loadData
|
||||
import ani.dantotsu.others.CustomBottomDialog
|
||||
import ani.dantotsu.setAnimation
|
||||
import io.noties.markwon.Markwon
|
||||
import io.noties.markwon.SoftBreakAddsNewLinePlugin
|
||||
|
||||
class FAQAdapter(private val questions: List<Triple<Int, String, String>>, private val manager: FragmentManager) :
|
||||
RecyclerView.Adapter<FAQAdapter.FAQViewHolder>() {
|
||||
private val uiSettings = loadData<UserInterfaceSettings>("ui_settings") ?: UserInterfaceSettings()
|
||||
|
||||
inner class FAQViewHolder(val binding: ItemQuestionBinding) : RecyclerView.ViewHolder(binding.root)
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): FAQViewHolder {
|
||||
return FAQViewHolder(ItemQuestionBinding.inflate(LayoutInflater.from(parent.context), parent, false))
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: FAQViewHolder, position: Int) {
|
||||
val b = holder.binding.root
|
||||
setAnimation(b.context, b, uiSettings)
|
||||
val faq = questions[position]
|
||||
b.text = faq.second
|
||||
b.setCompoundDrawablesWithIntrinsicBounds(faq.first, 0, 0, 0)
|
||||
b.setOnClickListener {
|
||||
CustomBottomDialog.newInstance().apply {
|
||||
setTitleText(faq.second)
|
||||
addView(
|
||||
TextView(b.context).apply {
|
||||
val markWon = Markwon.builder(b.context).usePlugin(SoftBreakAddsNewLinePlugin.create()).build()
|
||||
markWon.setMarkdown(this, faq.third)
|
||||
}
|
||||
)
|
||||
}.show(manager, "dialog")
|
||||
}
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int = questions.size
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
package ani.dantotsu.settings
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import ani.dantotsu.BottomSheetDialogFragment
|
||||
import ani.dantotsu.R
|
||||
import ani.dantotsu.databinding.BottomSheetDevelopersBinding
|
||||
|
||||
class ForksDialogFragment : BottomSheetDialogFragment() {
|
||||
private var _binding: BottomSheetDevelopersBinding? = null
|
||||
private val binding get() = _binding!!
|
||||
|
||||
private val developers = arrayOf(
|
||||
Developer("Dantotsu","https://avatars.githubusercontent.com/u/87634197?v=4","rebelonion","https://github.com/rebelonion/Dantotsu"),
|
||||
)
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
|
||||
_binding = BottomSheetDevelopersBinding.inflate(inflater, container, false)
|
||||
return binding.root
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
binding.devsTitle.setText(R.string.forks)
|
||||
binding.devsRecyclerView.adapter = DevelopersAdapter(developers)
|
||||
binding.devsRecyclerView.layoutManager = LinearLayoutManager(requireContext())
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
_binding = null
|
||||
super.onDestroy()
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
package ani.dantotsu.settings
|
||||
|
||||
import java.io.Serializable
|
||||
|
||||
data class NovelReaderSettings(
|
||||
var showSource: Boolean = true,
|
||||
var showSystemBars: Boolean = false,
|
||||
var default: CurrentNovelReaderSettings = CurrentNovelReaderSettings(),
|
||||
var askIndividual: Boolean = true,
|
||||
) : Serializable
|
49
app/src/main/java/ani/dantotsu/settings/PlayerSettings.kt
Normal file
49
app/src/main/java/ani/dantotsu/settings/PlayerSettings.kt
Normal file
|
@ -0,0 +1,49 @@
|
|||
package ani.dantotsu.settings
|
||||
|
||||
import java.io.Serializable
|
||||
|
||||
data class PlayerSettings(
|
||||
//Video
|
||||
var videoInfo: Boolean = true,
|
||||
var defaultSpeed: Int = 5,
|
||||
var cursedSpeeds: Boolean = false,
|
||||
var resize: Int = 0,
|
||||
|
||||
//Subtitles
|
||||
var subtitles: Boolean = true,
|
||||
var primaryColor: Int = 4,
|
||||
var secondaryColor: Int = 0,
|
||||
var outline: Int = 0,
|
||||
var subBackground: Int = 0,
|
||||
var subWindow: Int = 0,
|
||||
var font: Int = 0,
|
||||
var fontSize: Int = 20,
|
||||
var locale: Int = 2,
|
||||
|
||||
//TimeStamps
|
||||
var timeStampsEnabled: Boolean = true,
|
||||
var useProxyForTimeStamps: Boolean = true,
|
||||
var showTimeStampButton: Boolean = true,
|
||||
|
||||
//Auto
|
||||
var autoSkipOPED: Boolean = false,
|
||||
var autoPlay: Boolean = true,
|
||||
var autoSkipFiller: Boolean = false,
|
||||
|
||||
//Update Progress
|
||||
var askIndividual: Boolean = true,
|
||||
var updateForH: Boolean = false,
|
||||
var watchPercentage: Float = 0.8f,
|
||||
|
||||
//Behaviour
|
||||
var alwaysContinue: Boolean = true,
|
||||
var focusPause: Boolean = true,
|
||||
var gestures: Boolean = true,
|
||||
var doubleTap: Boolean = true,
|
||||
var seekTime: Int = 10,
|
||||
var skipTime: Int = 85,
|
||||
|
||||
//Other
|
||||
var cast: Boolean = false,
|
||||
var pip: Boolean = true
|
||||
) : Serializable
|
|
@ -0,0 +1,398 @@
|
|||
package ani.dantotsu.settings
|
||||
|
||||
import android.app.AlertDialog
|
||||
import android.content.Intent
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.inputmethod.EditorInfo
|
||||
import androidx.activity.addCallback
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.view.updateLayoutParams
|
||||
import androidx.core.widget.addTextChangedListener
|
||||
import ani.dantotsu.*
|
||||
import ani.dantotsu.databinding.ActivityPlayerSettingsBinding
|
||||
import ani.dantotsu.media.Media
|
||||
import ani.dantotsu.others.getSerialized
|
||||
import ani.dantotsu.parsers.Subtitle
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
|
||||
class PlayerSettingsActivity : AppCompatActivity() {
|
||||
lateinit var binding: ActivityPlayerSettingsBinding
|
||||
private val player = "player_settings"
|
||||
|
||||
var media:Media?=null
|
||||
var subtitle:Subtitle?=null
|
||||
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
binding = ActivityPlayerSettingsBinding.inflate(layoutInflater)
|
||||
setContentView(binding.root)
|
||||
|
||||
initActivity(this)
|
||||
|
||||
onBackPressedDispatcher.addCallback(this) {
|
||||
finish()
|
||||
}
|
||||
|
||||
try {
|
||||
media = intent.getSerialized("media")
|
||||
subtitle = intent.getSerialized("subtitle")
|
||||
} catch (e: Exception) {
|
||||
toast(e.toString())
|
||||
}
|
||||
|
||||
binding.playerSettingsContainer.updateLayoutParams<ViewGroup.MarginLayoutParams> {
|
||||
topMargin = statusBarHeight
|
||||
bottomMargin = navBarHeight
|
||||
}
|
||||
|
||||
val settings = loadData<PlayerSettings>(player, toast = false) ?: PlayerSettings().apply { saveData(player, this) }
|
||||
|
||||
binding.playerSettingsBack.setOnClickListener {
|
||||
onBackPressedDispatcher.onBackPressed()
|
||||
}
|
||||
|
||||
//Video
|
||||
binding.playerSettingsVideoInfo.isChecked = settings.videoInfo
|
||||
binding.playerSettingsVideoInfo.setOnCheckedChangeListener { _, isChecked ->
|
||||
settings.videoInfo = isChecked
|
||||
saveData(player, settings)
|
||||
}
|
||||
|
||||
binding.playerSettingsQualityHeight.setText((loadData<Int>("maxHeight", toast = false) ?: 480).toString())
|
||||
binding.playerSettingsQualityHeight.addTextChangedListener {
|
||||
val height = binding.playerSettingsQualityHeight.text.toString().toIntOrNull()
|
||||
saveData("maxHeight", height)
|
||||
}
|
||||
binding.playerSettingsQualityWidth.setText((loadData<Int>("maxWidth", toast = false) ?: 720).toString())
|
||||
binding.playerSettingsQualityWidth.addTextChangedListener {
|
||||
val height = binding.playerSettingsQualityWidth.text.toString().toIntOrNull()
|
||||
saveData("maxWidth", height)
|
||||
}
|
||||
|
||||
|
||||
val speeds = arrayOf(0.25f, 0.33f, 0.5f, 0.66f, 0.75f, 1f, 1.25f, 1.33f, 1.5f, 1.66f, 1.75f, 2f)
|
||||
val cursedSpeeds = arrayOf(1f, 1.25f, 1.5f, 1.75f, 2f, 2.5f, 3f, 4f, 5f, 10f, 25f, 50f)
|
||||
var curSpeedArr = if (settings.cursedSpeeds) cursedSpeeds else speeds
|
||||
var speedsName = curSpeedArr.map { "${it}x" }.toTypedArray()
|
||||
binding.playerSettingsSpeed.text = getString(R.string.default_playback_speed, speedsName[settings.defaultSpeed])
|
||||
val speedDialog = AlertDialog.Builder(this, R.style.DialogTheme).setTitle(getString(R.string.default_speed))
|
||||
binding.playerSettingsSpeed.setOnClickListener {
|
||||
speedDialog.setSingleChoiceItems(speedsName, settings.defaultSpeed) { dialog, i ->
|
||||
settings.defaultSpeed = i
|
||||
binding.playerSettingsSpeed.text = getString(R.string.default_playback_speed, speedsName[i])
|
||||
saveData(player, settings)
|
||||
dialog.dismiss()
|
||||
}.show()
|
||||
}
|
||||
|
||||
binding.playerSettingsCursedSpeeds.isChecked = settings.cursedSpeeds
|
||||
binding.playerSettingsCursedSpeeds.setOnCheckedChangeListener { _, isChecked ->
|
||||
settings.cursedSpeeds = isChecked
|
||||
curSpeedArr = if (settings.cursedSpeeds) cursedSpeeds else speeds
|
||||
settings.defaultSpeed = if (settings.cursedSpeeds) 0 else 5
|
||||
speedsName = curSpeedArr.map { "${it}x" }.toTypedArray()
|
||||
binding.playerSettingsSpeed.text = getString(R.string.default_playback_speed, speedsName[settings.defaultSpeed])
|
||||
saveData(player, settings)
|
||||
}
|
||||
|
||||
//Time Stamp
|
||||
binding.playerSettingsTimeStamps.isChecked = settings.timeStampsEnabled
|
||||
binding.playerSettingsTimeStamps.setOnCheckedChangeListener { _, isChecked ->
|
||||
settings.timeStampsEnabled = isChecked
|
||||
saveData(player, settings)
|
||||
}
|
||||
|
||||
binding.playerSettingsTimeStampsProxy.isChecked = settings.useProxyForTimeStamps
|
||||
binding.playerSettingsTimeStampsProxy.setOnCheckedChangeListener { _, isChecked ->
|
||||
settings.useProxyForTimeStamps = isChecked
|
||||
saveData(player, settings)
|
||||
}
|
||||
|
||||
binding.playerSettingsShowTimeStamp.isChecked = settings.showTimeStampButton
|
||||
binding.playerSettingsShowTimeStamp.setOnCheckedChangeListener { _, isChecked ->
|
||||
settings.showTimeStampButton = isChecked
|
||||
saveData(player, settings)
|
||||
}
|
||||
|
||||
|
||||
//Auto
|
||||
binding.playerSettingsAutoSkipOpEd.isChecked = settings.autoSkipOPED
|
||||
binding.playerSettingsAutoSkipOpEd.setOnCheckedChangeListener { _, isChecked ->
|
||||
settings.autoSkipOPED = isChecked
|
||||
saveData(player, settings)
|
||||
}
|
||||
|
||||
binding.playerSettingsAutoPlay.isChecked = settings.autoPlay
|
||||
binding.playerSettingsAutoPlay.setOnCheckedChangeListener { _, isChecked ->
|
||||
settings.autoPlay = isChecked
|
||||
saveData(player, settings)
|
||||
}
|
||||
binding.playerSettingsAutoSkip.isChecked = settings.autoSkipFiller
|
||||
binding.playerSettingsAutoSkip.setOnCheckedChangeListener { _, isChecked ->
|
||||
settings.autoSkipFiller = isChecked
|
||||
saveData(player, settings)
|
||||
}
|
||||
|
||||
//Update Progress
|
||||
binding.playerSettingsAskUpdateProgress.isChecked = settings.askIndividual
|
||||
binding.playerSettingsAskUpdateProgress.setOnCheckedChangeListener { _, isChecked ->
|
||||
settings.askIndividual = isChecked
|
||||
saveData(player, settings)
|
||||
}
|
||||
binding.playerSettingsAskUpdateHentai.isChecked = settings.updateForH
|
||||
binding.playerSettingsAskUpdateHentai.setOnCheckedChangeListener { _, isChecked ->
|
||||
settings.updateForH = isChecked
|
||||
if (isChecked) snackString(getString(R.string.very_bold))
|
||||
saveData(player, settings)
|
||||
}
|
||||
binding.playerSettingsCompletePercentage.value = (settings.watchPercentage * 100).roundToInt().toFloat()
|
||||
binding.playerSettingsCompletePercentage.addOnChangeListener { _, value, _ ->
|
||||
settings.watchPercentage = value / 100
|
||||
saveData(player, settings)
|
||||
}
|
||||
|
||||
//Behaviour
|
||||
binding.playerSettingsAlwaysContinue.isChecked = settings.alwaysContinue
|
||||
binding.playerSettingsAlwaysContinue.setOnCheckedChangeListener { _, isChecked ->
|
||||
settings.alwaysContinue = isChecked
|
||||
saveData(player, settings)
|
||||
}
|
||||
|
||||
binding.playerSettingsPauseVideo.isChecked = settings.focusPause
|
||||
binding.playerSettingsPauseVideo.setOnCheckedChangeListener { _, isChecked ->
|
||||
settings.focusPause = isChecked
|
||||
saveData(player, settings)
|
||||
}
|
||||
|
||||
binding.playerSettingsVerticalGestures.isChecked = settings.gestures
|
||||
binding.playerSettingsVerticalGestures.setOnCheckedChangeListener { _, isChecked ->
|
||||
settings.gestures = isChecked
|
||||
saveData(player, settings)
|
||||
}
|
||||
|
||||
binding.playerSettingsDoubleTap.isChecked = settings.doubleTap
|
||||
binding.playerSettingsDoubleTap.setOnCheckedChangeListener { _, isChecked ->
|
||||
settings.doubleTap = isChecked
|
||||
saveData(player, settings)
|
||||
}
|
||||
|
||||
binding.playerSettingsSeekTime.value = settings.seekTime.toFloat()
|
||||
binding.playerSettingsSeekTime.addOnChangeListener { _, value, _ ->
|
||||
settings.seekTime = value.toInt()
|
||||
saveData(player, settings)
|
||||
}
|
||||
|
||||
binding.exoSkipTime.setText(settings.skipTime.toString())
|
||||
binding.exoSkipTime.setOnEditorActionListener { _, actionId, _ ->
|
||||
if (actionId == EditorInfo.IME_ACTION_DONE) {
|
||||
binding.exoSkipTime.clearFocus()
|
||||
}
|
||||
false
|
||||
}
|
||||
binding.exoSkipTime.addTextChangedListener {
|
||||
val time = binding.exoSkipTime.text.toString().toIntOrNull()
|
||||
if (time != null) {
|
||||
settings.skipTime = time
|
||||
saveData(player, settings)
|
||||
}
|
||||
}
|
||||
|
||||
//Other
|
||||
binding.playerSettingsPiP.apply {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
visibility = View.VISIBLE
|
||||
isChecked = settings.pip
|
||||
setOnCheckedChangeListener { _, isChecked ->
|
||||
settings.pip = isChecked
|
||||
saveData(player, settings)
|
||||
}
|
||||
} else visibility = View.GONE
|
||||
}
|
||||
|
||||
binding.playerSettingsCast.isChecked = settings.cast
|
||||
binding.playerSettingsCast.setOnCheckedChangeListener { _, isChecked ->
|
||||
settings.cast = isChecked
|
||||
saveData(player, settings)
|
||||
}
|
||||
|
||||
val resizeModes = arrayOf("Original", "Zoom", "Stretch")
|
||||
val resizeDialog = AlertDialog.Builder(this, R.style.DialogTheme).setTitle(getString(R.string.default_resize_mode))
|
||||
binding.playerResizeMode.setOnClickListener {
|
||||
resizeDialog.setSingleChoiceItems(resizeModes, settings.resize) { dialog, count ->
|
||||
settings.resize = count
|
||||
saveData(player, settings)
|
||||
dialog.dismiss()
|
||||
}.show()
|
||||
}
|
||||
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()
|
||||
}
|
||||
}
|
||||
|
||||
fun toggleButton(button: android.widget.Button, toggle: Boolean) {
|
||||
button.isClickable = toggle
|
||||
button.alpha = when (toggle) {
|
||||
true -> 1f
|
||||
false -> 0.5f
|
||||
}
|
||||
}
|
||||
|
||||
fun toggleSubOptions(isChecked: Boolean) {
|
||||
toggleButton(binding.videoSubColorPrimary, isChecked)
|
||||
toggleButton(binding.videoSubColorSecondary, isChecked)
|
||||
toggleButton(binding.videoSubOutline, isChecked)
|
||||
toggleButton(binding.videoSubFont, isChecked)
|
||||
binding.subtitleFontSizeCard.isEnabled = isChecked
|
||||
binding.subtitleFontSizeCard.isClickable = isChecked
|
||||
binding.subtitleFontSizeCard.alpha = when (isChecked) {
|
||||
true -> 1f
|
||||
false -> 0.5f
|
||||
}
|
||||
binding.subtitleFontSize.isEnabled = isChecked
|
||||
binding.subtitleFontSize.isClickable = isChecked
|
||||
binding.subtitleFontSize.alpha = when (isChecked) {
|
||||
true -> 1f
|
||||
false -> 0.5f
|
||||
}
|
||||
ActivityPlayerSettingsBinding.bind(binding.root).subtitleFontSizeText.isEnabled = isChecked
|
||||
ActivityPlayerSettingsBinding.bind(binding.root).subtitleFontSizeText.isClickable = isChecked
|
||||
ActivityPlayerSettingsBinding.bind(binding.root).subtitleFontSizeText.alpha = when (isChecked) {
|
||||
true -> 1f
|
||||
false -> 0.5f
|
||||
}
|
||||
}
|
||||
binding.subSwitch.isChecked = settings.subtitles
|
||||
binding.subSwitch.setOnCheckedChangeListener { _, isChecked ->
|
||||
settings.subtitles = isChecked
|
||||
saveData(player, settings)
|
||||
toggleSubOptions(isChecked)
|
||||
restartApp()
|
||||
}
|
||||
val colorsPrimary =
|
||||
arrayOf("Black", "Dark Gray", "Gray", "Light Gray", "White", "Red", "Yellow", "Green", "Cyan", "Blue", "Magenta")
|
||||
val primaryColorDialog = AlertDialog.Builder(this, R.style.DialogTheme).setTitle(getString(R.string.primary_sub_color))
|
||||
binding.videoSubColorPrimary.setOnClickListener {
|
||||
primaryColorDialog.setSingleChoiceItems(colorsPrimary, settings.primaryColor) { dialog, count ->
|
||||
settings.primaryColor = count
|
||||
saveData(player, settings)
|
||||
dialog.dismiss()
|
||||
}.show()
|
||||
}
|
||||
val colorsSecondary = arrayOf(
|
||||
"Black",
|
||||
"Dark Gray",
|
||||
"Gray",
|
||||
"Light Gray",
|
||||
"White",
|
||||
"Red",
|
||||
"Yellow",
|
||||
"Green",
|
||||
"Cyan",
|
||||
"Blue",
|
||||
"Magenta",
|
||||
"Transparent"
|
||||
)
|
||||
val secondaryColorDialog = AlertDialog.Builder(this, R.style.DialogTheme).setTitle(getString(R.string.outline_sub_color))
|
||||
binding.videoSubColorSecondary.setOnClickListener {
|
||||
secondaryColorDialog.setSingleChoiceItems(colorsSecondary, settings.secondaryColor) { dialog, count ->
|
||||
settings.secondaryColor = count
|
||||
saveData(player, settings)
|
||||
dialog.dismiss()
|
||||
}.show()
|
||||
}
|
||||
val typesOutline = arrayOf("Outline", "Shine", "Drop Shadow", "None")
|
||||
val outlineDialog = AlertDialog.Builder(this, R.style.DialogTheme).setTitle(getString(R.string.outline_type))
|
||||
binding.videoSubOutline.setOnClickListener {
|
||||
outlineDialog.setSingleChoiceItems(typesOutline, settings.outline) { dialog, count ->
|
||||
settings.outline = count
|
||||
saveData(player, settings)
|
||||
dialog.dismiss()
|
||||
}.show()
|
||||
}
|
||||
val colorsSubBackground = arrayOf(
|
||||
"Transparent",
|
||||
"Black",
|
||||
"Dark Gray",
|
||||
"Gray",
|
||||
"Light Gray",
|
||||
"White",
|
||||
"Red",
|
||||
"Yellow",
|
||||
"Green",
|
||||
"Cyan",
|
||||
"Blue",
|
||||
"Magenta"
|
||||
)
|
||||
val subBackgroundDialog = AlertDialog.Builder(this, R.style.DialogTheme).setTitle(getString(R.string.outline_sub_color))
|
||||
binding.videoSubColorBackground.setOnClickListener {
|
||||
subBackgroundDialog.setSingleChoiceItems(colorsSubBackground, settings.subBackground) { dialog, count ->
|
||||
settings.subBackground = count
|
||||
saveData(player, settings)
|
||||
dialog.dismiss()
|
||||
}.show()
|
||||
}
|
||||
|
||||
val colorsSubWindow = arrayOf(
|
||||
"Transparent",
|
||||
"Black",
|
||||
"Dark Gray",
|
||||
"Gray",
|
||||
"Light Gray",
|
||||
"White",
|
||||
"Red",
|
||||
"Yellow",
|
||||
"Green",
|
||||
"Cyan",
|
||||
"Blue",
|
||||
"Magenta"
|
||||
)
|
||||
val subWindowDialog = AlertDialog.Builder(this, R.style.DialogTheme).setTitle(getString(R.string.outline_sub_color))
|
||||
binding.videoSubColorWindow.setOnClickListener {
|
||||
subWindowDialog.setSingleChoiceItems(colorsSubWindow, settings.subWindow) { dialog, count ->
|
||||
settings.subWindow = count
|
||||
saveData(player, settings)
|
||||
dialog.dismiss()
|
||||
}.show()
|
||||
}
|
||||
val fonts = arrayOf("Poppins Semi Bold", "Poppins Bold", "Poppins", "Poppins Thin")
|
||||
val fontDialog = AlertDialog.Builder(this, R.style.DialogTheme).setTitle(getString(R.string.subtitle_font))
|
||||
binding.videoSubFont.setOnClickListener {
|
||||
fontDialog.setSingleChoiceItems(fonts, settings.font) { dialog, count ->
|
||||
settings.font = count
|
||||
saveData(player, settings)
|
||||
dialog.dismiss()
|
||||
}.show()
|
||||
}
|
||||
binding.subtitleFontSize.setText(settings.fontSize.toString())
|
||||
binding.subtitleFontSize.setOnEditorActionListener { _, actionId, _ ->
|
||||
if (actionId == EditorInfo.IME_ACTION_DONE) {
|
||||
binding.subtitleFontSize.clearFocus()
|
||||
}
|
||||
false
|
||||
}
|
||||
binding.subtitleFontSize.addTextChangedListener {
|
||||
val size = binding.subtitleFontSize.text.toString().toIntOrNull()
|
||||
if (size != null) {
|
||||
settings.fontSize = size
|
||||
saveData(player, settings)
|
||||
}
|
||||
}
|
||||
toggleSubOptions(settings.subtitles)
|
||||
}
|
||||
}
|
14
app/src/main/java/ani/dantotsu/settings/ReaderSettings.kt
Normal file
14
app/src/main/java/ani/dantotsu/settings/ReaderSettings.kt
Normal file
|
@ -0,0 +1,14 @@
|
|||
package ani.dantotsu.settings
|
||||
|
||||
import java.io.Serializable
|
||||
|
||||
data class ReaderSettings(
|
||||
var showSource: Boolean = true,
|
||||
var showSystemBars: Boolean = false,
|
||||
|
||||
var autoDetectWebtoon: Boolean = true,
|
||||
var default: CurrentReaderSettings = CurrentReaderSettings(),
|
||||
|
||||
var askIndividual: Boolean = true,
|
||||
var updateForH: Boolean = false
|
||||
) : Serializable
|
|
@ -0,0 +1,185 @@
|
|||
package ani.dantotsu.settings
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.ViewGroup
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.view.updateLayoutParams
|
||||
import ani.dantotsu.R
|
||||
import ani.dantotsu.databinding.ActivityReaderSettingsBinding
|
||||
import ani.dantotsu.initActivity
|
||||
import ani.dantotsu.loadData
|
||||
import ani.dantotsu.navBarHeight
|
||||
import ani.dantotsu.saveData
|
||||
import ani.dantotsu.snackString
|
||||
import ani.dantotsu.statusBarHeight
|
||||
|
||||
class ReaderSettingsActivity : AppCompatActivity() {
|
||||
lateinit var binding: ActivityReaderSettingsBinding
|
||||
private val reader = "reader_settings"
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
binding = ActivityReaderSettingsBinding.inflate(layoutInflater)
|
||||
setContentView(binding.root)
|
||||
|
||||
initActivity(this)
|
||||
binding.readerSettingsContainer.updateLayoutParams<ViewGroup.MarginLayoutParams> {
|
||||
topMargin = statusBarHeight
|
||||
bottomMargin = navBarHeight
|
||||
}
|
||||
|
||||
val settings = loadData<ReaderSettings>(reader, toast = false) ?: ReaderSettings().apply { saveData(reader, this) }
|
||||
|
||||
binding.readerSettingsBack.setOnClickListener {
|
||||
onBackPressedDispatcher.onBackPressed()
|
||||
}
|
||||
|
||||
//General
|
||||
binding.readerSettingsSourceName.isChecked = settings.showSource
|
||||
binding.readerSettingsSourceName.setOnCheckedChangeListener { _, isChecked ->
|
||||
settings.showSource = isChecked
|
||||
saveData(reader, settings)
|
||||
}
|
||||
|
||||
binding.readerSettingsSystemBars.isChecked = settings.showSystemBars
|
||||
binding.readerSettingsSystemBars.setOnCheckedChangeListener { _, isChecked ->
|
||||
settings.showSystemBars = isChecked
|
||||
saveData(reader, settings)
|
||||
}
|
||||
|
||||
binding.readerSettingsAutoWebToon.isChecked = settings.autoDetectWebtoon
|
||||
binding.readerSettingsAutoWebToon.setOnCheckedChangeListener { _, isChecked ->
|
||||
settings.autoDetectWebtoon = isChecked
|
||||
saveData(reader, settings)
|
||||
}
|
||||
|
||||
//Default
|
||||
val layoutList = listOf(
|
||||
binding.readerSettingsPaged,
|
||||
binding.readerSettingsContinuousPaged,
|
||||
binding.readerSettingsContinuous
|
||||
)
|
||||
|
||||
binding.readerSettingsLayoutText.text = resources.getStringArray(R.array.manga_layouts)[settings.default.layout.ordinal]
|
||||
var selectedLayout = layoutList[settings.default.layout.ordinal]
|
||||
selectedLayout.alpha = 1f
|
||||
|
||||
layoutList.forEachIndexed { index, imageButton ->
|
||||
imageButton.setOnClickListener {
|
||||
selectedLayout.alpha = 0.33f
|
||||
selectedLayout = imageButton
|
||||
selectedLayout.alpha = 1f
|
||||
settings.default.layout = CurrentReaderSettings.Layouts[index]?:CurrentReaderSettings.Layouts.CONTINUOUS
|
||||
binding.readerSettingsLayoutText.text = resources.getStringArray(R.array.manga_layouts)[settings.default.layout.ordinal]
|
||||
saveData(reader, settings)
|
||||
}
|
||||
}
|
||||
|
||||
binding.readerSettingsDirectionText.text = resources.getStringArray(R.array.manga_directions)[settings.default.direction.ordinal]
|
||||
binding.readerSettingsDirection.rotation = 90f * (settings.default.direction.ordinal)
|
||||
binding.readerSettingsDirection.setOnClickListener {
|
||||
settings.default.direction = CurrentReaderSettings.Directions[settings.default.direction.ordinal + 1] ?: CurrentReaderSettings.Directions.TOP_TO_BOTTOM
|
||||
binding.readerSettingsDirectionText.text = resources.getStringArray(R.array.manga_directions)[settings.default.direction.ordinal]
|
||||
binding.readerSettingsDirection.rotation = 90f * (settings.default.direction.ordinal)
|
||||
saveData(reader, settings)
|
||||
}
|
||||
|
||||
val dualList = listOf(
|
||||
binding.readerSettingsDualNo,
|
||||
binding.readerSettingsDualAuto,
|
||||
binding.readerSettingsDualForce
|
||||
)
|
||||
|
||||
binding.readerSettingsDualPageText.text = settings.default.dualPageMode.toString()
|
||||
var selectedDual = dualList[settings.default.dualPageMode.ordinal]
|
||||
selectedDual.alpha = 1f
|
||||
|
||||
dualList.forEachIndexed { index, imageButton ->
|
||||
imageButton.setOnClickListener {
|
||||
selectedDual.alpha = 0.33f
|
||||
selectedDual = imageButton
|
||||
selectedDual.alpha = 1f
|
||||
settings.default.dualPageMode = CurrentReaderSettings.DualPageModes[index] ?: CurrentReaderSettings.DualPageModes.Automatic
|
||||
binding.readerSettingsDualPageText.text = settings.default.dualPageMode.toString()
|
||||
saveData(reader, settings)
|
||||
}
|
||||
}
|
||||
binding.readerSettingsTrueColors.isChecked = settings.default.trueColors
|
||||
binding.readerSettingsTrueColors.setOnCheckedChangeListener { _, isChecked ->
|
||||
settings.default.trueColors = isChecked
|
||||
saveData(reader, settings)
|
||||
}
|
||||
|
||||
binding.readerSettingsCropBorders.isChecked = settings.default.cropBorders
|
||||
binding.readerSettingsCropBorders.setOnCheckedChangeListener { _, isChecked ->
|
||||
settings.default.cropBorders = isChecked
|
||||
saveData(reader, settings)
|
||||
}
|
||||
|
||||
binding.readerSettingsImageRotation.isChecked = settings.default.rotation
|
||||
binding.readerSettingsImageRotation.setOnCheckedChangeListener { _, isChecked ->
|
||||
settings.default.rotation = isChecked
|
||||
saveData(reader, settings)
|
||||
}
|
||||
|
||||
binding.readerSettingsHorizontalScrollBar.isChecked = settings.default.horizontalScrollBar
|
||||
binding.readerSettingsHorizontalScrollBar.setOnCheckedChangeListener { _, isChecked ->
|
||||
settings.default.horizontalScrollBar = isChecked
|
||||
saveData(reader, settings)
|
||||
}
|
||||
binding.readerSettingsPadding.isChecked = settings.default.padding
|
||||
binding.readerSettingsPadding.setOnCheckedChangeListener { _, isChecked ->
|
||||
settings.default.padding = isChecked
|
||||
saveData(reader, settings)
|
||||
}
|
||||
|
||||
binding.readerSettingsKeepScreenOn.isChecked = settings.default.keepScreenOn
|
||||
binding.readerSettingsKeepScreenOn.setOnCheckedChangeListener { _, isChecked ->
|
||||
settings.default.keepScreenOn = isChecked
|
||||
saveData(reader, settings)
|
||||
}
|
||||
|
||||
binding.readerSettingsHidePageNumbers.isChecked = settings.default.hidePageNumbers
|
||||
binding.readerSettingsHidePageNumbers.setOnCheckedChangeListener { _, isChecked ->
|
||||
settings.default.hidePageNumbers = isChecked
|
||||
saveData(reader, settings)
|
||||
}
|
||||
|
||||
binding.readerSettingsOverscroll.isChecked = settings.default.overScrollMode
|
||||
binding.readerSettingsOverscroll.setOnCheckedChangeListener { _,isChecked ->
|
||||
settings.default.overScrollMode = isChecked
|
||||
saveData(reader, settings)
|
||||
}
|
||||
|
||||
binding.readerSettingsVolumeButton.isChecked = settings.default.volumeButtons
|
||||
binding.readerSettingsVolumeButton.setOnCheckedChangeListener { _,isChecked ->
|
||||
settings.default.volumeButtons = isChecked
|
||||
saveData(reader, settings)
|
||||
}
|
||||
|
||||
binding.readerSettingsWrapImages.isChecked = settings.default.wrapImages
|
||||
binding.readerSettingsWrapImages.setOnCheckedChangeListener { _,isChecked ->
|
||||
settings.default.wrapImages = isChecked
|
||||
saveData(reader, settings)
|
||||
}
|
||||
|
||||
binding.readerSettingsLongClickImage.isChecked = settings.default.longClickImage
|
||||
binding.readerSettingsLongClickImage.setOnCheckedChangeListener { _,isChecked ->
|
||||
settings.default.longClickImage = isChecked
|
||||
saveData(reader, settings)
|
||||
}
|
||||
|
||||
//Update Progress
|
||||
binding.readerSettingsAskUpdateProgress.isChecked = settings.askIndividual
|
||||
binding.readerSettingsAskUpdateProgress.setOnCheckedChangeListener { _, isChecked ->
|
||||
settings.askIndividual = isChecked
|
||||
saveData(reader, settings)
|
||||
}
|
||||
binding.readerSettingsAskUpdateDoujins.isChecked = settings.updateForH
|
||||
binding.readerSettingsAskUpdateDoujins.setOnCheckedChangeListener { _, isChecked ->
|
||||
settings.updateForH = isChecked
|
||||
if (isChecked) snackString(getString(R.string.very_bold))
|
||||
saveData(reader, settings)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
519
app/src/main/java/ani/dantotsu/settings/SettingsActivity.kt
Normal file
519
app/src/main/java/ani/dantotsu/settings/SettingsActivity.kt
Normal file
|
@ -0,0 +1,519 @@
|
|||
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.*
|
||||
import android.os.Build.VERSION.*
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.ArrayAdapter
|
||||
import android.widget.TextView
|
||||
import androidx.activity.OnBackPressedCallback
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.view.updateLayoutParams
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import ani.dantotsu.*
|
||||
import ani.dantotsu.connections.anilist.Anilist
|
||||
import ani.dantotsu.connections.discord.Discord
|
||||
import ani.dantotsu.connections.mal.MAL
|
||||
import ani.dantotsu.databinding.ActivitySettingsBinding
|
||||
import ani.dantotsu.others.AppUpdater
|
||||
import ani.dantotsu.others.CustomBottomDialog
|
||||
import ani.dantotsu.parsers.AnimeSources
|
||||
import ani.dantotsu.parsers.MangaSources
|
||||
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 io.noties.markwon.Markwon
|
||||
import io.noties.markwon.SoftBreakAddsNewLinePlugin
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlin.random.Random
|
||||
|
||||
|
||||
class SettingsActivity : AppCompatActivity() {
|
||||
private val restartMainActivity = object : OnBackPressedCallback(false) {
|
||||
override fun handleOnBackPressed() = startMainActivity(this@SettingsActivity)
|
||||
}
|
||||
lateinit var binding: ActivitySettingsBinding
|
||||
|
||||
@SuppressLint("SetTextI18n")
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
binding = ActivitySettingsBinding.inflate(layoutInflater)
|
||||
setContentView(binding.root)
|
||||
|
||||
initActivity(this)
|
||||
|
||||
binding.settingsVersion.text = getString(R.string.version_current, BuildConfig.VERSION_NAME)
|
||||
binding.settingsVersion.setOnLongClickListener {
|
||||
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"
|
||||
}
|
||||
|
||||
val info = """
|
||||
dantotsu Version: ${BuildConfig.VERSION_NAME}
|
||||
Device: $BRAND $DEVICE
|
||||
Architecture: ${getArch()}
|
||||
OS Version: $CODENAME $RELEASE ($SDK_INT)
|
||||
""".trimIndent()
|
||||
copyToClipboard(info, 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()
|
||||
}
|
||||
|
||||
val animeSource = loadData<Int>("settings_def_anime_source")?.let { if (it >= AnimeSources.names.size) 0 else it } ?: 0
|
||||
if (MangaSources.names.isNotEmpty() && animeSource in 0 until MangaSources.names.size) {
|
||||
binding.mangaSource.setText(MangaSources.names[animeSource], false)
|
||||
}
|
||||
|
||||
binding.animeSource.setAdapter(ArrayAdapter(this, R.layout.item_dropdown, AnimeSources.names))
|
||||
binding.animeSource.setOnItemClickListener { _, _, i, _ ->
|
||||
saveData("settings_def_anime_source", i)
|
||||
binding.animeSource.clearFocus()
|
||||
}
|
||||
|
||||
binding.settingsPlayer.setOnClickListener {
|
||||
startActivity(Intent(this, PlayerSettingsActivity::class.java))
|
||||
}
|
||||
|
||||
val managers = arrayOf("Default", "1DM", "ADM")
|
||||
val downloadManagerDialog = AlertDialog.Builder(this, R.style.DialogTheme).setTitle("Download Manager")
|
||||
var downloadManager = loadData<Int>("settings_download_manager") ?: 0
|
||||
binding.settingsDownloadManager.setOnClickListener {
|
||||
downloadManagerDialog.setSingleChoiceItems(managers, downloadManager) { dialog, count ->
|
||||
downloadManager = count
|
||||
saveData("settings_download_manager", downloadManager)
|
||||
dialog.dismiss()
|
||||
}.show()
|
||||
}
|
||||
|
||||
binding.settingsDownloadInSd.isChecked = loadData("sd_dl") ?: false
|
||||
binding.settingsDownloadInSd.setOnCheckedChangeListener { _, isChecked ->
|
||||
if (isChecked) {
|
||||
val arrayOfFiles = ContextCompat.getExternalFilesDirs(this, null)
|
||||
if (arrayOfFiles.size > 1 && arrayOfFiles[1] != null) {
|
||||
saveData("sd_dl", true)
|
||||
} else {
|
||||
binding.settingsDownloadInSd.isChecked = false
|
||||
saveData("sd_dl", false)
|
||||
snackString(getString(R.string.noSdFound))
|
||||
}
|
||||
} else saveData("sd_dl", false)
|
||||
}
|
||||
|
||||
binding.settingsContinueMedia.isChecked = loadData("continue_media") ?: true
|
||||
binding.settingsContinueMedia.setOnCheckedChangeListener { _, isChecked ->
|
||||
saveData("continue_media", isChecked)
|
||||
}
|
||||
|
||||
binding.settingsRecentlyListOnly.isChecked = loadData("recently_list_only") ?: false
|
||||
binding.settingsRecentlyListOnly.setOnCheckedChangeListener { _, isChecked ->
|
||||
saveData("recently_list_only", isChecked)
|
||||
}
|
||||
|
||||
val dns = listOf("None", "Google", "Cloudflare", "AdGuard")
|
||||
binding.settingsDns.setText(dns[loadData("settings_dns") ?: 0], false)
|
||||
binding.settingsDns.setAdapter(ArrayAdapter(this, R.layout.item_dropdown, dns))
|
||||
binding.settingsDns.setOnItemClickListener { _, _, i, _ ->
|
||||
saveData("settings_dns", i)
|
||||
initializeNetwork(this)
|
||||
binding.settingsDns.clearFocus()
|
||||
}
|
||||
|
||||
binding.settingsPreferDub.isChecked = loadData("settings_prefer_dub") ?: false
|
||||
binding.settingsPreferDub.setOnCheckedChangeListener { _, isChecked ->
|
||||
saveData("settings_prefer_dub", isChecked)
|
||||
}
|
||||
|
||||
val mangaSource = loadData<Int>("settings_def_manga_source")?.let { if (it >= MangaSources.names.size) 0 else it } ?: 0
|
||||
if (MangaSources.names.isNotEmpty() && mangaSource in 0 until MangaSources.names.size) {
|
||||
binding.mangaSource.setText(MangaSources.names[mangaSource], false)
|
||||
}
|
||||
|
||||
binding.mangaSource.setAdapter(ArrayAdapter(this, R.layout.item_dropdown, MangaSources.names))
|
||||
binding.mangaSource.setOnItemClickListener { _, _, i, _ ->
|
||||
saveData("settings_def_manga_source", i)
|
||||
binding.mangaSource.clearFocus()
|
||||
}
|
||||
|
||||
binding.settingsReader.setOnClickListener {
|
||||
startActivity(Intent(this, ReaderSettingsActivity::class.java))
|
||||
}
|
||||
|
||||
val uiSettings: UserInterfaceSettings =
|
||||
loadData("ui_settings", toast = false) ?: UserInterfaceSettings().apply { saveData("ui_settings", this) }
|
||||
var previous: View = when (uiSettings.darkMode) {
|
||||
null -> binding.settingsUiAuto
|
||||
true -> binding.settingsUiDark
|
||||
false -> binding.settingsUiLight
|
||||
}
|
||||
previous.alpha = 1f
|
||||
fun uiTheme(mode: Boolean?, current: View) {
|
||||
previous.alpha = 0.33f
|
||||
previous = current
|
||||
current.alpha = 1f
|
||||
uiSettings.darkMode = mode
|
||||
saveData("ui_settings", uiSettings)
|
||||
Refresh.all()
|
||||
finish()
|
||||
startActivity(Intent(this, SettingsActivity::class.java))
|
||||
initActivity(this)
|
||||
}
|
||||
|
||||
binding.settingsUiAuto.setOnClickListener {
|
||||
uiTheme(null, it)
|
||||
}
|
||||
|
||||
binding.settingsUiLight.setOnClickListener {
|
||||
uiTheme(false, it)
|
||||
}
|
||||
|
||||
binding.settingsUiDark.setOnClickListener {
|
||||
uiTheme(true, it)
|
||||
}
|
||||
|
||||
var previousStart: View = when (uiSettings.defaultStartUpTab) {
|
||||
0 -> binding.uiSettingsAnime
|
||||
1 -> binding.uiSettingsHome
|
||||
2 -> binding.uiSettingsManga
|
||||
else -> binding.uiSettingsHome
|
||||
}
|
||||
previousStart.alpha = 1f
|
||||
fun uiTheme(mode: Int, current: View) {
|
||||
previousStart.alpha = 0.33f
|
||||
previousStart = current
|
||||
current.alpha = 1f
|
||||
uiSettings.defaultStartUpTab = mode
|
||||
saveData("ui_settings", uiSettings)
|
||||
initActivity(this)
|
||||
}
|
||||
|
||||
binding.uiSettingsAnime.setOnClickListener {
|
||||
uiTheme(0, it)
|
||||
}
|
||||
|
||||
binding.uiSettingsHome.setOnClickListener {
|
||||
uiTheme(1, it)
|
||||
}
|
||||
|
||||
binding.uiSettingsManga.setOnClickListener {
|
||||
uiTheme(2, it)
|
||||
}
|
||||
|
||||
binding.settingsShowYt.isChecked = uiSettings.showYtButton
|
||||
binding.settingsShowYt.setOnCheckedChangeListener { _, isChecked ->
|
||||
uiSettings.showYtButton = isChecked
|
||||
saveData("ui_settings", uiSettings)
|
||||
}
|
||||
|
||||
var previousEp: View = when (uiSettings.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
|
||||
uiSettings.animeDefaultView = mode
|
||||
saveData("ui_settings", uiSettings)
|
||||
}
|
||||
|
||||
binding.settingsEpList.setOnClickListener {
|
||||
uiEp(0, it)
|
||||
}
|
||||
|
||||
binding.settingsEpGrid.setOnClickListener {
|
||||
uiEp(1, it)
|
||||
}
|
||||
|
||||
binding.settingsEpCompact.setOnClickListener {
|
||||
uiEp(2, it)
|
||||
}
|
||||
|
||||
var previousChp: View = when (uiSettings.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
|
||||
uiSettings.mangaDefaultView = mode
|
||||
saveData("ui_settings", uiSettings)
|
||||
}
|
||||
|
||||
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.settingUPI.visibility = if (checkCountry(this)) View.VISIBLE else View.GONE
|
||||
lifecycleScope.launch {
|
||||
binding.settingUPI.pop()
|
||||
}
|
||||
|
||||
binding.loginDiscord.setOnClickListener {
|
||||
openLinkInBrowser(getString(R.string.discord))
|
||||
}
|
||||
binding.loginGithub.setOnClickListener {
|
||||
openLinkInBrowser(getString(R.string.github))
|
||||
}
|
||||
|
||||
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 {
|
||||
(binding.settingsLogo.drawable as Animatable).start()
|
||||
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 = loadData<Int>("subscriptions_time") ?: 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.DialogTheme).setTitle(R.string.subscriptions_checking_time)
|
||||
binding.settingsSubscriptionsTime.setOnClickListener {
|
||||
speedDialog.setSingleChoiceItems(timeNames, curTime) { dialog, i ->
|
||||
curTime = i
|
||||
binding.settingsSubscriptionsTime.text = getString(R.string.subscriptions_checking_time_s, timeNames[i])
|
||||
saveData("subscriptions_time", curTime)
|
||||
dialog.dismiss()
|
||||
startSubscription(true)
|
||||
}.show()
|
||||
}
|
||||
|
||||
binding.settingsSubscriptionsTime.setOnLongClickListener {
|
||||
startSubscription(true)
|
||||
true
|
||||
}
|
||||
|
||||
binding.settingsNotificationsCheckingSubscriptions.isChecked = loadData("subscription_checking_notifications") ?: true
|
||||
binding.settingsNotificationsCheckingSubscriptions.setOnCheckedChangeListener { _, isChecked ->
|
||||
saveData("subscription_checking_notifications", 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)
|
||||
}
|
||||
|
||||
|
||||
binding.settingsCheckUpdate.isChecked = loadData("check_update") ?: true
|
||||
binding.settingsCheckUpdate.setOnCheckedChangeListener { _, isChecked ->
|
||||
saveData("check_update", isChecked)
|
||||
if (!isChecked) {
|
||||
snackString(getString(R.string.long_click_to_check_update))
|
||||
}
|
||||
}
|
||||
|
||||
binding.settingsLogo.setOnLongClickListener {
|
||||
lifecycleScope.launch(Dispatchers.IO) {
|
||||
AppUpdater.check(this@SettingsActivity, true)
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
binding.settingsCheckUpdate.setOnLongClickListener {
|
||||
lifecycleScope.launch(Dispatchers.IO) {
|
||||
AppUpdater.check(this@SettingsActivity, true)
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
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(it.context)
|
||||
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) {
|
||||
if (Discord.avatar != null) {
|
||||
binding.settingsDiscordAvatar.loadImage(Discord.avatar)
|
||||
}
|
||||
binding.settingsDiscordUsername.visibility = View.VISIBLE
|
||||
binding.settingsDiscordUsername.text = Discord.userid ?: Discord.token?.replace(Regex("."),"*")
|
||||
binding.settingsDiscordLogin.setText(R.string.logout)
|
||||
binding.settingsDiscordLogin.setOnClickListener {
|
||||
Discord.removeSavedToken(this)
|
||||
restartMainActivity.isEnabled = true
|
||||
reload()
|
||||
}
|
||||
} else {
|
||||
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!\nOnce we reach the goal of $1000 (60%+ already reached!), Get ready to get an Offline Player & Manga Downloads!"
|
||||
})
|
||||
|
||||
setNegativeButton("no moners :(") {
|
||||
snackString("That's alright, you'll be a rich man soon :prayge:")
|
||||
dismiss()
|
||||
}
|
||||
|
||||
setPositiveButton("denote :)") {
|
||||
if (binding.settingUPI.visibility == View.VISIBLE) binding.settingUPI.performClick()
|
||||
else binding.settingBuyMeCoffee.performClick()
|
||||
dismiss()
|
||||
}
|
||||
show(supportFragmentManager, "dialog")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,85 @@
|
|||
package ani.dantotsu.settings
|
||||
|
||||
import android.app.DownloadManager
|
||||
import android.content.ActivityNotFoundException
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.core.content.ContextCompat
|
||||
import ani.dantotsu.*
|
||||
import ani.dantotsu.connections.anilist.Anilist
|
||||
import ani.dantotsu.others.imagesearch.ImageSearchActivity
|
||||
import ani.dantotsu.databinding.BottomSheetSettingsBinding
|
||||
|
||||
|
||||
class SettingsDialogFragment : BottomSheetDialogFragment() {
|
||||
private var _binding: BottomSheetSettingsBinding? = null
|
||||
private val binding get() = _binding!!
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
|
||||
_binding = BottomSheetSettingsBinding.inflate(inflater, container, false)
|
||||
return binding.root
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
if (Anilist.token != null) {
|
||||
binding.settingsLogin.setText(R.string.logout)
|
||||
binding.settingsLogin.setOnClickListener {
|
||||
Anilist.removeSavedToken(it.context)
|
||||
dismiss()
|
||||
startMainActivity(requireActivity(),)
|
||||
}
|
||||
binding.settingsUsername.text = Anilist.username
|
||||
binding.settingsUserAvatar.loadImage(Anilist.avatar)
|
||||
} else {
|
||||
binding.settingsUsername.visibility = View.GONE
|
||||
binding.settingsLogin.setText(R.string.login)
|
||||
binding.settingsLogin.setOnClickListener {
|
||||
dismiss()
|
||||
Anilist.loginIntent(requireActivity())
|
||||
}
|
||||
}
|
||||
|
||||
binding.settingsExtensionSettings.setSafeOnClickListener {
|
||||
startActivity(Intent(activity, ExtensionsActivity::class.java))
|
||||
dismiss()
|
||||
}
|
||||
binding.settingsSettings.setSafeOnClickListener {
|
||||
startActivity(Intent(activity, SettingsActivity::class.java))
|
||||
dismiss()
|
||||
}
|
||||
binding.settingsAnilistSettings.setOnClickListener {
|
||||
openLinkInBrowser("https://anilist.co/settings/lists")
|
||||
dismiss()
|
||||
}
|
||||
binding.imageSearch.setOnClickListener {
|
||||
startActivity(Intent(activity, ImageSearchActivity::class.java))
|
||||
dismiss()
|
||||
}
|
||||
binding.settingsDownloads.setSafeOnClickListener {
|
||||
try {
|
||||
val arrayOfFiles = ContextCompat.getExternalFilesDirs(requireContext(), null)
|
||||
startActivity(
|
||||
if (loadData<Boolean>("sd_dl") == true && arrayOfFiles.size > 1 && arrayOfFiles[0] != null && arrayOfFiles[1] != null) {
|
||||
val parentDirectory = arrayOfFiles[1].toString()
|
||||
val intent = Intent(Intent.ACTION_VIEW)
|
||||
intent.setDataAndType(Uri.parse(parentDirectory), "resource/folder")
|
||||
} else Intent(DownloadManager.ACTION_VIEW_DOWNLOADS)
|
||||
)
|
||||
} catch (e: ActivityNotFoundException) {
|
||||
toast(getString(R.string.file_manager_not_found))
|
||||
}
|
||||
dismiss()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
super.onDestroyView()
|
||||
_binding = null
|
||||
}
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
package ani.dantotsu.settings
|
||||
|
||||
import java.io.Serializable
|
||||
|
||||
data class UserInterfaceSettings(
|
||||
var darkMode: Boolean? = null,
|
||||
var showYtButton: Boolean = true,
|
||||
var animeDefaultView: Int = 0,
|
||||
var mangaDefaultView: Int = 0,
|
||||
|
||||
//App
|
||||
var immersiveMode: Boolean = false,
|
||||
var smallView: Boolean = true,
|
||||
var defaultStartUpTab: Int = 1,
|
||||
var homeLayoutShow: MutableList<Boolean> = mutableListOf(true, false, false, true, false, false, true),
|
||||
|
||||
//Animations
|
||||
var bannerAnimations: Boolean = true,
|
||||
var layoutAnimations: Boolean = true,
|
||||
var animationSpeed: Float = 1f
|
||||
|
||||
) : Serializable
|
|
@ -0,0 +1,107 @@
|
|||
package ani.dantotsu.settings
|
||||
|
||||
import android.app.AlertDialog
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.view.ViewGroup
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.view.updateLayoutParams
|
||||
import ani.dantotsu.*
|
||||
import ani.dantotsu.databinding.ActivityUserInterfaceSettingsBinding
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
|
||||
class UserInterfaceSettingsActivity : AppCompatActivity() {
|
||||
lateinit var binding: ActivityUserInterfaceSettingsBinding
|
||||
private val ui = "ui_settings"
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
binding = ActivityUserInterfaceSettingsBinding.inflate(layoutInflater)
|
||||
setContentView(binding.root)
|
||||
|
||||
initActivity(this)
|
||||
binding.uiSettingsContainer.updateLayoutParams<ViewGroup.MarginLayoutParams> {
|
||||
topMargin = statusBarHeight
|
||||
bottomMargin = navBarHeight
|
||||
}
|
||||
|
||||
val settings = loadData<UserInterfaceSettings>(ui, toast = false) ?: UserInterfaceSettings().apply { saveData(ui, this) }
|
||||
|
||||
binding.uiSettingsBack.setOnClickListener {
|
||||
onBackPressedDispatcher.onBackPressed()
|
||||
}
|
||||
|
||||
val views = resources.getStringArray(R.array.home_layouts)
|
||||
binding.uiSettingsHomeLayout.setOnClickListener {
|
||||
AlertDialog.Builder(this, R.style.DialogTheme).setTitle(getString(R.string.home_layout_show)).apply {
|
||||
setMultiChoiceItems(views, settings.homeLayoutShow.toBooleanArray()) { _, i, value ->
|
||||
settings.homeLayoutShow[i] = value
|
||||
saveData(ui, settings)
|
||||
}
|
||||
}.show()
|
||||
}
|
||||
|
||||
binding.uiSettingsSmallView.isChecked = settings.smallView
|
||||
binding.uiSettingsSmallView.setOnCheckedChangeListener { _, isChecked ->
|
||||
settings.smallView = isChecked
|
||||
saveData(ui, settings)
|
||||
restartApp()
|
||||
}
|
||||
|
||||
binding.uiSettingsImmersive.isChecked = settings.immersiveMode
|
||||
binding.uiSettingsImmersive.setOnCheckedChangeListener { _, isChecked ->
|
||||
settings.immersiveMode = isChecked
|
||||
saveData(ui, settings)
|
||||
restartApp()
|
||||
}
|
||||
|
||||
binding.uiSettingsBannerAnimation.isChecked = settings.bannerAnimations
|
||||
binding.uiSettingsBannerAnimation.setOnCheckedChangeListener { _, isChecked ->
|
||||
settings.bannerAnimations = isChecked
|
||||
saveData(ui, settings)
|
||||
restartApp()
|
||||
}
|
||||
|
||||
binding.uiSettingsLayoutAnimation.isChecked = settings.layoutAnimations
|
||||
binding.uiSettingsLayoutAnimation.setOnCheckedChangeListener { _, isChecked ->
|
||||
settings.layoutAnimations = isChecked
|
||||
saveData(ui, settings)
|
||||
restartApp()
|
||||
}
|
||||
|
||||
val map = mapOf(
|
||||
2f to 0.5f,
|
||||
1.75f to 0.625f,
|
||||
1.5f to 0.75f,
|
||||
1.25f to 0.875f,
|
||||
1f to 1f,
|
||||
0.75f to 1.25f,
|
||||
0.5f to 1.5f,
|
||||
0.25f to 1.75f,
|
||||
0f to 0f
|
||||
)
|
||||
val mapReverse = map.map { it.value to it.key }.toMap()
|
||||
binding.uiSettingsAnimationSpeed.value = mapReverse[settings.animationSpeed] ?: 1f
|
||||
binding.uiSettingsAnimationSpeed.addOnChangeListener { _, value, _ ->
|
||||
settings.animationSpeed = map[value] ?: 1f
|
||||
saveData(ui, settings)
|
||||
restartApp()
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
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()
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue