Add storage usage to Tools screen
parent
bd3d800cde
commit
3be9def609
@ -0,0 +1,89 @@
|
|||||||
|
package org.koitharu.kotatsu.base.ui.widgets
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.graphics.Canvas
|
||||||
|
import android.graphics.Outline
|
||||||
|
import android.graphics.Paint
|
||||||
|
import android.util.AttributeSet
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewOutlineProvider
|
||||||
|
import androidx.annotation.ColorInt
|
||||||
|
import androidx.annotation.FloatRange
|
||||||
|
import androidx.core.graphics.ColorUtils
|
||||||
|
import org.koitharu.kotatsu.parsers.util.replaceWith
|
||||||
|
import org.koitharu.kotatsu.utils.ext.resolveDp
|
||||||
|
import kotlin.random.Random
|
||||||
|
|
||||||
|
class SegmentedBarView @JvmOverloads constructor(
|
||||||
|
context: Context,
|
||||||
|
attrs: AttributeSet? = null,
|
||||||
|
defStyleAttr: Int = 0,
|
||||||
|
) : View(context, attrs, defStyleAttr) {
|
||||||
|
|
||||||
|
private val paint = Paint(Paint.ANTI_ALIAS_FLAG)
|
||||||
|
private val segmentsData = ArrayList<Segment>()
|
||||||
|
private val minSegmentSize = context.resources.resolveDp(3f)
|
||||||
|
|
||||||
|
var segments: List<Segment>
|
||||||
|
get() = segmentsData
|
||||||
|
set(value) {
|
||||||
|
segmentsData.replaceWith(value)
|
||||||
|
invalidate()
|
||||||
|
}
|
||||||
|
|
||||||
|
init {
|
||||||
|
paint.style = Paint.Style.FILL
|
||||||
|
outlineProvider = OutlineProvider()
|
||||||
|
clipToOutline = true
|
||||||
|
|
||||||
|
if (isInEditMode) {
|
||||||
|
segments = List(Random.nextInt(3, 5)) {
|
||||||
|
Segment(
|
||||||
|
percent = Random.nextFloat(),
|
||||||
|
color = ColorUtils.HSLToColor(floatArrayOf(Random.nextInt(0, 360).toFloat(), 0.5f, 0.5f)),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDraw(canvas: Canvas) {
|
||||||
|
var x = 0f
|
||||||
|
val w = width.toFloat()
|
||||||
|
for (segment in segmentsData) {
|
||||||
|
paint.color = segment.color
|
||||||
|
val segmentWidth = (w * segment.percent).coerceAtLeast(minSegmentSize)
|
||||||
|
canvas.drawRect(x, 0f, x + segmentWidth, height.toFloat(), paint)
|
||||||
|
x += segmentWidth
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Segment(
|
||||||
|
@FloatRange(from = 0.0, to = 1.0) val percent: Float,
|
||||||
|
@ColorInt val color: Int,
|
||||||
|
) {
|
||||||
|
|
||||||
|
override fun equals(other: Any?): Boolean {
|
||||||
|
if (this === other) return true
|
||||||
|
if (javaClass != other?.javaClass) return false
|
||||||
|
|
||||||
|
other as Segment
|
||||||
|
|
||||||
|
if (percent != other.percent) return false
|
||||||
|
if (color != other.color) return false
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun hashCode(): Int {
|
||||||
|
var result = percent.hashCode()
|
||||||
|
result = 31 * result + color
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class OutlineProvider : ViewOutlineProvider() {
|
||||||
|
override fun getOutline(view: View, outline: Outline) {
|
||||||
|
outline.setRoundRect(0, 0, view.width, view.height, view.height / 2f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,44 @@
|
|||||||
|
package org.koitharu.kotatsu.settings.tools
|
||||||
|
|
||||||
|
import androidx.lifecycle.LiveData
|
||||||
|
import androidx.lifecycle.liveData
|
||||||
|
import androidx.lifecycle.viewModelScope
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import org.koitharu.kotatsu.base.ui.BaseViewModel
|
||||||
|
import org.koitharu.kotatsu.local.data.CacheDir
|
||||||
|
import org.koitharu.kotatsu.local.data.LocalStorageManager
|
||||||
|
import org.koitharu.kotatsu.settings.tools.model.StorageUsage
|
||||||
|
|
||||||
|
class ToolsViewModel(
|
||||||
|
private val storageManager: LocalStorageManager,
|
||||||
|
) : BaseViewModel() {
|
||||||
|
|
||||||
|
val storageUsage: LiveData<StorageUsage> = liveData(
|
||||||
|
context = viewModelScope.coroutineContext + Dispatchers.Default,
|
||||||
|
) {
|
||||||
|
emit(collectStorageUsage())
|
||||||
|
}
|
||||||
|
|
||||||
|
private suspend fun collectStorageUsage(): StorageUsage {
|
||||||
|
val pagesCacheSize = storageManager.computeCacheSize(CacheDir.PAGES)
|
||||||
|
val otherCacheSize = storageManager.computeCacheSize() - pagesCacheSize
|
||||||
|
val storageSize = storageManager.computeStorageSize()
|
||||||
|
val availableSpace = storageManager.computeAvailableSize()
|
||||||
|
val totalBytes = pagesCacheSize + otherCacheSize + storageSize + availableSpace
|
||||||
|
return StorageUsage(
|
||||||
|
savedManga = StorageUsage.Item(
|
||||||
|
bytes = storageSize,
|
||||||
|
percent = (storageSize.toDouble() / totalBytes).toFloat(),
|
||||||
|
), pagesCache = StorageUsage.Item(
|
||||||
|
bytes = pagesCacheSize,
|
||||||
|
percent = (pagesCacheSize.toDouble() / totalBytes).toFloat(),
|
||||||
|
), otherCache = StorageUsage.Item(
|
||||||
|
bytes = otherCacheSize,
|
||||||
|
percent = (otherCacheSize.toDouble() / totalBytes).toFloat(),
|
||||||
|
), available = StorageUsage.Item(
|
||||||
|
bytes = availableSpace,
|
||||||
|
percent = (availableSpace.toDouble() / totalBytes).toFloat(),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,14 @@
|
|||||||
|
package org.koitharu.kotatsu.settings.tools.model
|
||||||
|
|
||||||
|
class StorageUsage(
|
||||||
|
val savedManga: Item,
|
||||||
|
val pagesCache: Item,
|
||||||
|
val otherCache: Item,
|
||||||
|
val available: Item,
|
||||||
|
) {
|
||||||
|
|
||||||
|
class Item(
|
||||||
|
val bytes: Long,
|
||||||
|
val percent: Float,
|
||||||
|
)
|
||||||
|
}
|
||||||
@ -0,0 +1,69 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout
|
||||||
|
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:padding="@dimen/screen_padding">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/storage_usage"
|
||||||
|
android:textAppearance="?textAppearanceTitleMedium" />
|
||||||
|
|
||||||
|
<org.koitharu.kotatsu.base.ui.widgets.SegmentedBarView
|
||||||
|
android:id="@+id/bar"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="8dp"
|
||||||
|
android:layout_marginVertical="@dimen/margin_normal"
|
||||||
|
android:background="?colorSecondaryContainer" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/label_storage"
|
||||||
|
style="@style/Widget.Kotatsu.TextView.Indicator"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/saved_manga"
|
||||||
|
android:visibility="gone"
|
||||||
|
app:drawableStartCompat="@drawable/bg_circle"
|
||||||
|
tools:drawableTint="?colorPrimary"
|
||||||
|
tools:visibility="visible" />
|
||||||
|
|
||||||
|
<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_marginTop="@dimen/margin_small"
|
||||||
|
android:text="@string/pages_cache"
|
||||||
|
android:visibility="gone"
|
||||||
|
app:drawableStartCompat="@drawable/bg_circle"
|
||||||
|
tools:drawableTint="?colorSecondary"
|
||||||
|
tools:visibility="visible" />
|
||||||
|
|
||||||
|
<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_marginTop="@dimen/margin_small"
|
||||||
|
android:text="@string/other_cache"
|
||||||
|
android:visibility="gone"
|
||||||
|
app:drawableStartCompat="@drawable/bg_circle"
|
||||||
|
tools:drawableTint="?colorTertiary"
|
||||||
|
tools:visibility="visible" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/label_available"
|
||||||
|
style="@style/Widget.Kotatsu.TextView.Indicator"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="@dimen/margin_small"
|
||||||
|
android:text="@string/computing_"
|
||||||
|
app:drawableStartCompat="@drawable/bg_circle"
|
||||||
|
app:drawableTint="?colorSecondaryContainer" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
Loading…
Reference in New Issue