new theme options

This commit is contained in:
Finnley Somdahl 2023-11-26 21:00:46 -06:00
parent b4093b0c47
commit e5f2bb6566
11 changed files with 309 additions and 50 deletions

View file

@ -1,5 +1,6 @@
package ani.dantotsu.media
import android.graphics.Bitmap
import ani.dantotsu.connections.anilist.api.FuzzyDate
import ani.dantotsu.connections.anilist.api.MediaEdge
import ani.dantotsu.connections.anilist.api.MediaList
@ -119,4 +120,5 @@ data class Media(
object MediaSingleton {
var media: Media? = null
var bitmap: Bitmap? = null
}

View file

@ -4,10 +4,14 @@ import android.annotation.SuppressLint
import android.app.Activity
import android.content.Context
import android.content.Intent
import android.graphics.Bitmap
import android.graphics.Canvas
import android.graphics.drawable.BitmapDrawable
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.animation.AccelerateDecelerateInterpolator
import android.widget.ImageView
import androidx.appcompat.content.res.AppCompatResources
import androidx.core.content.ContextCompat
import androidx.core.view.updateLayoutParams
@ -248,14 +252,14 @@ class MediaAdaptor(
inner class MediaViewHolder(val binding: ItemMediaCompactBinding) : RecyclerView.ViewHolder(binding.root) {
init {
if (matchParent) itemView.updateLayoutParams { width = -1 }
itemView.setSafeOnClickListener { clicked(bindingAdapterPosition) }
itemView.setSafeOnClickListener { clicked(bindingAdapterPosition, resizeBitmap(getBitmapFromImageView(binding.itemCompactImage), 100)) }
itemView.setOnLongClickListener { longClicked(bindingAdapterPosition) }
}
}
inner class MediaLargeViewHolder(val binding: ItemMediaLargeBinding) : RecyclerView.ViewHolder(binding.root) {
init {
itemView.setSafeOnClickListener { clicked(bindingAdapterPosition) }
itemView.setSafeOnClickListener { clicked(bindingAdapterPosition, resizeBitmap(getBitmapFromImageView(binding.itemCompactImage), 100)) }
itemView.setOnLongClickListener { longClicked(bindingAdapterPosition) }
}
}
@ -263,7 +267,7 @@ class MediaAdaptor(
@SuppressLint("ClickableViewAccessibility")
inner class MediaPageViewHolder(val binding: ItemMediaPageBinding) : RecyclerView.ViewHolder(binding.root) {
init {
binding.itemCompactImage.setSafeOnClickListener { clicked(bindingAdapterPosition) }
binding.itemCompactImage.setSafeOnClickListener { clicked(bindingAdapterPosition, resizeBitmap(getBitmapFromImageView(binding.itemCompactImage), 100)) }
itemView.setOnTouchListener { _, _ -> true }
binding.itemCompactImage.setOnLongClickListener { longClicked(bindingAdapterPosition) }
}
@ -272,16 +276,17 @@ class MediaAdaptor(
@SuppressLint("ClickableViewAccessibility")
inner class MediaPageSmallViewHolder(val binding: ItemMediaPageSmallBinding) : RecyclerView.ViewHolder(binding.root) {
init {
binding.itemCompactImage.setSafeOnClickListener { clicked(bindingAdapterPosition) }
binding.itemCompactTitleContainer.setSafeOnClickListener { clicked(bindingAdapterPosition) }
binding.itemCompactImage.setSafeOnClickListener { clicked(bindingAdapterPosition, resizeBitmap(getBitmapFromImageView(binding.itemCompactImage), 100)) }
binding.itemCompactTitleContainer.setSafeOnClickListener { clicked(bindingAdapterPosition, resizeBitmap(getBitmapFromImageView(binding.itemCompactImage), 100)) }
itemView.setOnTouchListener { _, _ -> true }
binding.itemCompactImage.setOnLongClickListener { longClicked(bindingAdapterPosition) }
}
}
fun clicked(position: Int) {
fun clicked(position: Int, bitmap: Bitmap? = null) {
if ((mediaList?.size ?: 0) > position && position != -1) {
val media = mediaList?.get(position)
if (bitmap != null) MediaSingleton.bitmap = bitmap
ContextCompat.startActivity(
activity,
Intent(activity, MediaDetailsActivity::class.java).putExtra(
@ -302,4 +307,44 @@ class MediaAdaptor(
}
return false
}
fun getBitmapFromImageView(imageView: ImageView): Bitmap? {
val drawable = imageView.drawable ?: return null
// If the drawable is a BitmapDrawable, then just get the bitmap
if (drawable is BitmapDrawable) {
return drawable.bitmap
}
// Create a bitmap with the same dimensions as the drawable
val bitmap = Bitmap.createBitmap(drawable.intrinsicWidth,
drawable.intrinsicHeight,
Bitmap.Config.ARGB_8888)
// Draw the drawable onto the bitmap
val canvas = Canvas(bitmap)
drawable.setBounds(0, 0, canvas.width, canvas.height)
drawable.draw(canvas)
return bitmap
}
fun resizeBitmap(source: Bitmap?, maxDimension: Int): Bitmap? {
if (source == null) return null
val width = source.width
val height = source.height
val newWidth: Int
val newHeight: Int
if (width > height) {
newWidth = maxDimension
newHeight = (height * (maxDimension.toFloat() / width)).toInt()
} else {
newHeight = maxDimension
newWidth = (width * (maxDimension.toFloat() / height)).toInt()
}
return Bitmap.createScaledBitmap(source, newWidth, newHeight, true)
}
}

View file

@ -5,6 +5,7 @@ import android.annotation.SuppressLint
import android.content.Intent
import android.os.Bundle
import android.text.SpannableStringBuilder
import android.util.Log
import android.util.TypedValue
import android.view.GestureDetector
import android.view.MotionEvent
@ -73,7 +74,9 @@ class MediaDetailsActivity : AppCompatActivity(), AppBarLayout.OnOffsetChangedLi
@SuppressLint("SetTextI18n", "ClickableViewAccessibility")
override fun onCreate(savedInstanceState: Bundle?) {
LangSet.setLocale(this)
ThemeManager(this).applyTheme()
var media: Media = intent.getSerialized("media") ?: return
ThemeManager(this).applyTheme(MediaSingleton.bitmap)
MediaSingleton.bitmap = null
super.onCreate(savedInstanceState)
binding = ActivityMediaBinding.inflate(layoutInflater)
setContentView(binding.root)
@ -119,7 +122,7 @@ class MediaDetailsActivity : AppCompatActivity(), AppBarLayout.OnOffsetChangedLi
viewPager.isUserInputEnabled = false
viewPager.setPageTransformer(ZoomOutPageTransformer(uiSettings))
var media: Media = intent.getSerialized("media") ?: return
val isDownload = intent.getBooleanExtra("download", false)
media.selected = model.loadSelected(media, isDownload)

View file

@ -5,12 +5,14 @@ import android.app.AlertDialog
import android.content.Context
import android.content.Intent
import android.graphics.drawable.Animatable
import android.os.Build
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.LinearLayout
import android.widget.TextView
import android.widget.Toast
import androidx.activity.OnBackPressedCallback
@ -36,6 +38,7 @@ import ani.dantotsu.themes.ThemeManager
import ani.dantotsu.others.LangSet
import com.google.android.material.snackbar.Snackbar
import com.google.android.material.textfield.TextInputEditText
import com.skydoves.colorpickerview.listeners.ColorListener
import eu.kanade.domain.base.BasePreferences
import eu.kanade.tachiyomi.network.NetworkPreferences
import io.noties.markwon.Markwon
@ -61,7 +64,7 @@ class SettingsActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
LangSet.setLocale(this)
ThemeManager(this).applyTheme()
ThemeManager(this).applyTheme()
binding = ActivitySettingsBinding.inflate(layoutInflater)
setContentView(binding.root)
@ -82,10 +85,10 @@ ThemeManager(this).applyTheme()
}
val info = """
dantotsu Version: ${BuildConfig.VERSION_NAME}
Device: $BRAND $DEVICE
Architecture: ${getArch()}
OS Version: $CODENAME $RELEASE ($SDK_INT)
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))
@ -106,12 +109,30 @@ OS Version: $CODENAME $RELEASE ($SDK_INT)
binding.settingsUseMaterialYou.isChecked = getSharedPreferences("Dantotsu", Context.MODE_PRIVATE).getBoolean("use_material_you", false)
binding.settingsUseMaterialYou.setOnCheckedChangeListener { _, isChecked ->
getSharedPreferences("Dantotsu", Context.MODE_PRIVATE).edit().putBoolean("use_material_you", isChecked).apply()
if(isChecked) binding.settingsUseCustomTheme.isChecked = false
restartApp()
}
binding.settingsUseCustomTheme.isChecked = getSharedPreferences("Dantotsu", Context.MODE_PRIVATE).getBoolean("use_custom_theme", false)
binding.settingsUseCustomTheme.setOnCheckedChangeListener { _, isChecked ->
getSharedPreferences("Dantotsu", Context.MODE_PRIVATE).edit().putBoolean("use_custom_theme", isChecked).apply()
if(isChecked) {
binding.settingsUseOLED.isChecked = false
binding.settingsUseMaterialYou.isChecked = false
}
restartApp()
}
binding.settingsUseSourceTheme.isChecked = getSharedPreferences("Dantotsu", Context.MODE_PRIVATE).getBoolean("use_source_theme", false)
binding.settingsUseSourceTheme.setOnCheckedChangeListener { _, isChecked ->
getSharedPreferences("Dantotsu", Context.MODE_PRIVATE).edit().putBoolean("use_source_theme", isChecked).apply()
}
binding.settingsUseOLED.isChecked = getSharedPreferences("Dantotsu", Context.MODE_PRIVATE).getBoolean("use_oled", false)
binding.settingsUseOLED.setOnCheckedChangeListener { _, isChecked ->
getSharedPreferences("Dantotsu", Context.MODE_PRIVATE).edit().putBoolean("use_oled", isChecked).apply()
if(isChecked) binding.settingsUseCustomTheme.isChecked = false
restartApp()
}
@ -121,13 +142,40 @@ OS Version: $CODENAME $RELEASE ($SDK_INT)
binding.themeSwitcher.setAdapter(ArrayAdapter(this, R.layout.item_dropdown, ThemeManager.Companion.Theme.values().map { it.theme.substring(0, 1) + it.theme.substring(1).lowercase() }))
binding.themeSwitcher.setOnItemClickListener { _, _, i, _ ->
getSharedPreferences("Dantotsu", Context.MODE_PRIVATE).edit().putString("theme", ThemeManager.Companion.Theme.values()[i].theme).apply()
getSharedPreferences("Dantotsu", Context.MODE_PRIVATE).edit().putString("custom_theme", ThemeManager.Companion.Theme.values()[i].theme).apply()
//ActivityHelper.shouldRefreshMainActivity = true
binding.themeSwitcher.clearFocus()
restartApp()
}
binding.customTheme.setOnClickListener{
var passedColor: Int = 0
val dialogView = layoutInflater.inflate(R.layout.dialog_color_picker, null)
val alertDialog = AlertDialog.Builder(this ,R.style.MyPopup)
.setTitle("Custom Theme")
.setView(dialogView)
.setPositiveButton("OK") { dialog, _ ->
getSharedPreferences("Dantotsu", Context.MODE_PRIVATE).edit().putInt("custom_theme", passedColor).apply()
logger("Custom Theme: $passedColor")
dialog.dismiss()
restartApp()
}
.setNegativeButton("Cancel") { dialog, _ ->
dialog.dismiss()
}
.create()
val colorPickerView = dialogView.findViewById<com.skydoves.colorpickerview.ColorPickerView>(R.id.colorPickerView)
colorPickerView.setColorListener(ColorListener { color, fromUser ->
val linearLayout = dialogView.findViewById<LinearLayout>(R.id.linear)
passedColor = color
linearLayout.setBackgroundColor(color)
})
alertDialog.show()
}
//val animeSource = loadData<Int>("settings_def_anime_source_s")?.let { if (it >= AnimeSources.names.size) 0 else it } ?: 0
val animeSource = getSharedPreferences("Dantotsu", Context.MODE_PRIVATE).getInt("settings_def_anime_source_s_r", 0)
if (AnimeSources.names.isNotEmpty() && animeSource in 0 until AnimeSources.names.size) {
@ -177,7 +225,6 @@ OS Version: $CODENAME $RELEASE ($SDK_INT)
}
// binding.userAgent.setText(networkPreferences.defaultUserAgent().get())
binding.userAgent.setOnClickListener{
val dialogView = layoutInflater.inflate(R.layout.dialog_user_agent, null)
val editText = dialogView.findViewById<TextInputEditText>(R.id.userAgentTextBox)
@ -295,6 +342,7 @@ OS Version: $CODENAME $RELEASE ($SDK_INT)
}
binding.settingsUiLight.setOnClickListener {
binding.settingsUseOLED.isChecked = false
uiTheme(false, it)
}

View file

@ -3,27 +3,40 @@ package ani.dantotsu.themes
import android.app.Activity
import android.content.Context
import android.content.res.Configuration
import android.graphics.Bitmap
import android.util.Log
import ani.dantotsu.FileUrl
import ani.dantotsu.R
import ani.dantotsu.logger
import ani.dantotsu.media.manga.mangareader.BaseImageAdapter.Companion.loadBitmap
import ani.dantotsu.media.manga.mangareader.BaseImageAdapter.Companion.loadBitmap_old
import com.google.android.material.color.DynamicColors
import com.google.android.material.color.DynamicColorsOptions
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.TimeoutCancellationException
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.withContext
import kotlinx.coroutines.withTimeout
class ThemeManager(private val context: Context) {
fun applyTheme() {
fun applyTheme(fromImage: Bitmap? = null) {
val useOLED = context.getSharedPreferences("Dantotsu", Context.MODE_PRIVATE).getBoolean("use_oled", false) && isDarkThemeActive(context)
if(context.getSharedPreferences("Dantotsu", Context.MODE_PRIVATE).getBoolean("use_material_you", false)){
if (useOLED) {
val options = DynamicColorsOptions.Builder()
.setThemeOverlay(R.style.AppTheme_Amoled)
.build()
val activity = context as Activity
DynamicColors.applyToActivityIfAvailable(activity, options)
} else {
val activity = context as Activity
DynamicColors.applyToActivityIfAvailable(activity)
}
val useCustomTheme = context.getSharedPreferences("Dantotsu", Context.MODE_PRIVATE).getBoolean("use_custom_theme", false)
val customTheme = context.getSharedPreferences("Dantotsu", Context.MODE_PRIVATE).getInt("custom_theme", 16712221)
val useSource = context.getSharedPreferences("Dantotsu", Context.MODE_PRIVATE).getBoolean("use_source_theme", false)
val useMaterial = context.getSharedPreferences("Dantotsu", Context.MODE_PRIVATE).getBoolean("use_material_you", false)
if(useSource){
applyDynamicColors(useMaterial, context, useOLED, fromImage, useCustom = if(useCustomTheme) customTheme else null)
return
} else if (useCustomTheme) {
applyDynamicColors(useMaterial, context, useOLED, useCustom = customTheme)
return
} else {
val returnedEarly = applyDynamicColors(useMaterial, context, useOLED, useCustom = null)
if(!returnedEarly) return
}
val theme = context.getSharedPreferences("Dantotsu", Context.MODE_PRIVATE).getString("theme", "PURPLE")!!
@ -42,6 +55,35 @@ class ThemeManager(private val context: Context) {
context.setTheme(themeToApply)
}
private fun applyDynamicColors(useMaterialYou: Boolean, context: Context, useOLED: Boolean, bitmap: Bitmap? = null, useCustom: Int? = null): Boolean {
val builder = DynamicColorsOptions.Builder()
var needMaterial = true
// Set content-based source if a bitmap is provided
if (bitmap != null) {
builder.setContentBasedSource(bitmap)
needMaterial = false
}else if (useCustom != null){
builder.setContentBasedSource(useCustom)
needMaterial = false
}
// Set the theme overlay based on conditions
if (useOLED) {
builder.setThemeOverlay(R.style.AppTheme_Amoled)
needMaterial = false
}
if(needMaterial && !useMaterialYou) return true
// Build the options
val options = builder.build()
// Apply the dynamic colors to the activity
val activity = context as Activity
DynamicColors.applyToActivityIfAvailable(activity, options)
return false
}
private fun isDarkThemeActive(context: Context): Boolean {
return when (context.resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK) {
Configuration.UI_MODE_NIGHT_YES -> true