Add MemoryUsageView

This commit is contained in:
Koitharu
2023-02-12 10:05:05 +02:00
parent 5ce2bc92d6
commit e3a67940d0
6 changed files with 105 additions and 83 deletions

View File

@@ -1,35 +1,24 @@
package org.koitharu.kotatsu.settings.tools
import android.content.Intent
import android.content.res.ColorStateList
import android.os.Bundle
import android.transition.TransitionManager
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.CompoundButton
import androidx.annotation.ColorInt
import androidx.core.graphics.ColorUtils
import androidx.core.graphics.Insets
import androidx.core.net.toUri
import androidx.core.view.isVisible
import androidx.core.view.updatePadding
import androidx.core.widget.TextViewCompat
import androidx.fragment.app.viewModels
import com.google.android.material.color.MaterialColors
import dagger.hilt.android.AndroidEntryPoint
import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.base.ui.BaseFragment
import org.koitharu.kotatsu.base.ui.widgets.SegmentedBarView
import org.koitharu.kotatsu.core.github.AppVersion
import org.koitharu.kotatsu.databinding.FragmentToolsBinding
import org.koitharu.kotatsu.download.ui.DownloadsActivity
import org.koitharu.kotatsu.settings.SettingsActivity
import org.koitharu.kotatsu.settings.about.AppUpdateDialog
import org.koitharu.kotatsu.settings.tools.model.StorageUsage
import org.koitharu.kotatsu.utils.FileSize
import org.koitharu.kotatsu.utils.ext.getThemeColor
import com.google.android.material.R as materialR
@AndroidEntryPoint
class ToolsFragment :
@@ -50,11 +39,14 @@ class ToolsFragment :
binding.cardUpdate.buttonChangelog.setOnClickListener(this)
binding.cardUpdate.buttonDownload.setOnClickListener(this)
binding.switchIncognito.setOnCheckedChangeListener(this)
binding.memoryUsageView.setManageButtonOnClickListener(this)
viewModel.isIncognitoModeEnabled.observe(viewLifecycleOwner) {
binding.switchIncognito.isChecked = it
}
viewModel.storageUsage.observe(viewLifecycleOwner, ::onStorageUsageChanged)
viewModel.storageUsage.observe(viewLifecycleOwner) {
binding.memoryUsageView.bind(it)
}
viewModel.appUpdate.observe(viewLifecycleOwner, ::onAppUpdateAvailable)
}
@@ -96,51 +88,6 @@ class ToolsFragment :
binding.cardUpdate.root.isVisible = true
}
private fun onStorageUsageChanged(usage: StorageUsage) {
val storageSegment = SegmentedBarView.Segment(usage.savedManga.percent, segmentColor(1))
val pagesSegment = SegmentedBarView.Segment(usage.pagesCache.percent, segmentColor(2))
val otherSegment = SegmentedBarView.Segment(usage.otherCache.percent, segmentColor(3))
with(binding.layoutStorage) {
buttonManage.setOnClickListener(this@ToolsFragment)
bar.segments = listOf(storageSegment, pagesSegment, otherSegment)
val pattern = getString(R.string.memory_usage_pattern)
labelStorage.text = pattern.format(
FileSize.BYTES.format(root.context, usage.savedManga.bytes),
getString(R.string.saved_manga),
)
labelPagesCache.text = pattern.format(
FileSize.BYTES.format(root.context, usage.pagesCache.bytes),
getString(R.string.pages_cache),
)
labelOtherCache.text = pattern.format(
FileSize.BYTES.format(root.context, usage.otherCache.bytes),
getString(R.string.other_cache),
)
labelAvailable.text = pattern.format(
FileSize.BYTES.format(root.context, usage.available.bytes),
getString(R.string.available),
)
TextViewCompat.setCompoundDrawableTintList(labelStorage, ColorStateList.valueOf(storageSegment.color))
TextViewCompat.setCompoundDrawableTintList(labelPagesCache, ColorStateList.valueOf(pagesSegment.color))
TextViewCompat.setCompoundDrawableTintList(labelOtherCache, ColorStateList.valueOf(otherSegment.color))
if (!labelStorage.isVisible) {
TransitionManager.beginDelayedTransition(root)
}
labelStorage.isVisible = true
labelPagesCache.isVisible = true
labelOtherCache.isVisible = true
}
}
@ColorInt
private fun segmentColor(i: Int): Int {
val hue = (93.6f * i) % 360
val color = ColorUtils.HSLToColor(floatArrayOf(hue, 0.4f, 0.6f))
val backgroundColor = requireContext().getThemeColor(materialR.attr.colorSecondaryContainer)
return MaterialColors.harmonize(color, backgroundColor)
}
companion object {
fun newInstance() = ToolsFragment()

View File

@@ -5,7 +5,6 @@ import androidx.lifecycle.asLiveData
import androidx.lifecycle.liveData
import androidx.lifecycle.viewModelScope
import dagger.hilt.android.lifecycle.HiltViewModel
import javax.inject.Inject
import kotlinx.coroutines.Dispatchers
import org.koitharu.kotatsu.base.ui.BaseViewModel
import org.koitharu.kotatsu.core.github.AppUpdateRepository
@@ -14,6 +13,7 @@ import org.koitharu.kotatsu.core.prefs.observeAsLiveData
import org.koitharu.kotatsu.local.data.CacheDir
import org.koitharu.kotatsu.local.data.LocalStorageManager
import org.koitharu.kotatsu.settings.tools.model.StorageUsage
import javax.inject.Inject
@HiltViewModel
class ToolsViewModel @Inject constructor(
@@ -25,7 +25,7 @@ class ToolsViewModel @Inject constructor(
val appUpdate = appUpdateRepository.observeAvailableUpdate()
.asLiveData(viewModelScope.coroutineContext)
val storageUsage: LiveData<StorageUsage> = liveData(
val storageUsage: LiveData<StorageUsage?> = liveData(
context = viewModelScope.coroutineContext + Dispatchers.Default,
) {
emit(collectStorageUsage())

View File

@@ -0,0 +1,77 @@
package org.koitharu.kotatsu.settings.tools.views
import android.content.Context
import android.content.res.ColorStateList
import android.util.AttributeSet
import android.view.LayoutInflater
import android.widget.LinearLayout
import androidx.annotation.ColorInt
import androidx.annotation.StringRes
import androidx.core.graphics.ColorUtils
import androidx.core.widget.TextViewCompat
import com.google.android.material.color.MaterialColors
import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.base.ui.widgets.SegmentedBarView
import org.koitharu.kotatsu.databinding.LayoutMemoryUsageBinding
import org.koitharu.kotatsu.settings.tools.model.StorageUsage
import org.koitharu.kotatsu.utils.FileSize
import org.koitharu.kotatsu.utils.ext.getThemeColor
class MemoryUsageView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null
) : LinearLayout(context, attrs) {
private val binding = LayoutMemoryUsageBinding.inflate(LayoutInflater.from(context), this)
private val labelPattern = context.getString(R.string.memory_usage_pattern)
init {
orientation = VERTICAL
bind(null)
}
fun setManageButtonOnClickListener(listener: OnClickListener?) {
binding.buttonManage.setOnClickListener(listener)
}
fun bind(usage: StorageUsage?) {
val storageSegment = SegmentedBarView.Segment(usage?.savedManga?.percent ?: 0f, segmentColor(1))
val pagesSegment = SegmentedBarView.Segment(usage?.pagesCache?.percent ?: 0f, segmentColor(2))
val otherSegment = SegmentedBarView.Segment(usage?.otherCache?.percent ?: 0f, segmentColor(3))
with(binding) {
bar.segments = listOf(storageSegment, pagesSegment, otherSegment).filter { it.percent > 0f }
labelStorage.text = formatLabel(usage?.savedManga, R.string.saved_manga)
labelPagesCache.text = formatLabel(usage?.pagesCache, R.string.pages_cache)
labelOtherCache.text = formatLabel(usage?.otherCache, R.string.other_cache)
labelAvailable.text = formatLabel(usage?.available, R.string.available, R.string.available)
TextViewCompat.setCompoundDrawableTintList(labelStorage, ColorStateList.valueOf(storageSegment.color))
TextViewCompat.setCompoundDrawableTintList(labelPagesCache, ColorStateList.valueOf(pagesSegment.color))
TextViewCompat.setCompoundDrawableTintList(labelOtherCache, ColorStateList.valueOf(otherSegment.color))
}
}
private fun formatLabel(
item: StorageUsage.Item?,
@StringRes labelResId: Int,
@StringRes emptyResId: Int = R.string.computing_,
): String {
return if (item != null) {
labelPattern.format(
FileSize.BYTES.format(context, item.bytes),
context.getString(labelResId),
)
} else {
context.getString(emptyResId)
}
}
@ColorInt
private fun segmentColor(i: Int): Int {
val hue = (93.6f * i) % 360
val color = ColorUtils.HSLToColor(floatArrayOf(hue, 0.4f, 0.6f))
val backgroundColor = context.getThemeColor(com.google.android.material.R.attr.colorSecondaryContainer)
return MaterialColors.harmonize(color, backgroundColor)
}
}

View File

@@ -40,9 +40,8 @@
app:layout_constraintTop_toTopOf="parent"
tools:visibility="visible" />
<include
android:id="@+id/layout_storage"
layout="@layout/layout_memory_usage"
<org.koitharu.kotatsu.settings.tools.views.MemoryUsageView
android:id="@+id/memory_usage_view"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintEnd_toStartOf="@id/guideline"

View File

@@ -34,9 +34,8 @@
android:visibility="gone"
tools:visibility="visible" />
<include
android:id="@+id/layout_storage"
layout="@layout/layout_memory_usage"
<org.koitharu.kotatsu.settings.tools.views.MemoryUsageView
android:id="@+id/memory_usage_view"
android:layout_width="match_parent"
android:layout_height="wrap_content" />

View File

@@ -1,19 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
<merge
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:paddingStart="@dimen/screen_padding"
android:paddingTop="@dimen/margin_small"
android:paddingBottom="@dimen/screen_padding"
tools:ignore="RtlSymmetry">
android:layout_height="wrap_content"
tools:ignore="RtlSymmetry"
tools:orientation="vertical"
tools:parentTag="android.widget.LinearLayout">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/screen_padding"
android:layout_marginTop="@dimen/margin_small">
<TextView
android:layout_width="0dp"
@@ -36,6 +36,7 @@
android:id="@+id/bar"
android:layout_width="match_parent"
android:layout_height="16dp"
android:layout_marginStart="@dimen/screen_padding"
android:layout_marginEnd="@dimen/screen_padding"
android:background="?colorSecondaryContainer" />
@@ -44,49 +45,48 @@
style="@style/Widget.Kotatsu.TextView.Indicator"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/screen_padding"
android:layout_marginTop="@dimen/margin_normal"
android:layout_marginEnd="@dimen/screen_padding"
android:text="@string/saved_manga"
android:visibility="gone"
app:drawableStartCompat="@drawable/bg_circle"
tools:drawableTint="?colorPrimary"
tools:visibility="visible" />
tools:drawableTint="?colorPrimary" />
<TextView
android:id="@+id/label_pages_cache"
style="@style/Widget.Kotatsu.TextView.Indicator"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/screen_padding"
android:layout_marginTop="@dimen/margin_small"
android:layout_marginEnd="@dimen/screen_padding"
android:text="@string/pages_cache"
android:visibility="gone"
app:drawableStartCompat="@drawable/bg_circle"
tools:drawableTint="?colorSecondary"
tools:visibility="visible" />
tools:drawableTint="?colorSecondary" />
<TextView
android:id="@+id/label_other_cache"
style="@style/Widget.Kotatsu.TextView.Indicator"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/screen_padding"
android:layout_marginTop="@dimen/margin_small"
android:layout_marginEnd="@dimen/screen_padding"
android:text="@string/other_cache"
android:visibility="gone"
app:drawableStartCompat="@drawable/bg_circle"
tools:drawableTint="?colorTertiary"
tools:visibility="visible" />
tools:drawableTint="?colorTertiary" />
<TextView
android:id="@+id/label_available"
style="@style/Widget.Kotatsu.TextView.Indicator"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/screen_padding"
android:layout_marginTop="@dimen/margin_small"
android:layout_marginEnd="@dimen/screen_padding"
android:layout_marginBottom="@dimen/screen_padding"
android:text="@string/computing_"
app:drawableStartCompat="@drawable/bg_circle"
app:drawableTint="?colorSecondaryContainer" />
</LinearLayout>
</merge>