Add MemoryUsageView
This commit is contained in:
@@ -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()
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
@@ -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"
|
||||
|
||||
@@ -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" />
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user