Skip to content

Commit 1c9e4a2

Browse files
committed
Merge branch 'worktree-explorer'
# Conflicts: # app-workspace-explorer/src/main/java/eu/darken/butler/explorer/ui/explorer/ExplorerWorkspacePage.kt
2 parents f4f55c7 + 01b6b6a commit 1c9e4a2

33 files changed

Lines changed: 1661 additions & 1034 deletions

File tree

app/src/main/java/eu/darken/butler/common/EasterEggs.kt renamed to app-common/src/main/java/eu/darken/butler/common/EasterEggs.kt

File renamed without changes.
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
package eu.darken.butler.common.progress
2+
3+
import android.content.Context
4+
import android.text.format.Formatter
5+
import eu.darken.butler.common.ca.CaDrawable
6+
import eu.darken.butler.common.ca.CaString
7+
import eu.darken.butler.common.ca.toCaString
8+
import eu.darken.butler.common.easterEggProgressMsg
9+
import kotlinx.coroutines.flow.Flow
10+
import kotlin.math.ceil
11+
12+
interface Progress {
13+
14+
data class Data(
15+
val icon: CaDrawable? = null,
16+
val primary: CaString = eu.darken.butler.common.R.string.general_progress_loading.toCaString(),
17+
val secondary: CaString = easterEggProgressMsg.toCaString(),
18+
val count: Count = Count.Indeterminate(),
19+
val extra: Any? = null
20+
)
21+
22+
interface Host {
23+
val progress: Flow<Data?>
24+
}
25+
26+
interface Client {
27+
fun updateProgress(update: (Data?) -> Data?)
28+
}
29+
30+
sealed interface Count {
31+
val current: Long
32+
val max: Long
33+
fun displayValue(context: Context): String?
34+
35+
data class Percent(override val current: Long, override val max: Long) : Count {
36+
37+
constructor(current: Int, max: Int) : this(current.toLong(), max.toLong())
38+
constructor(max: Int) : this(0, max)
39+
constructor(max: Long) : this(0, max)
40+
41+
override fun displayValue(context: Context): String {
42+
if (current == 0L && max == 0L) return "NaN"
43+
if (current == 0L) return "0%"
44+
return "${ceil(((current.toDouble() / max.toDouble()) * 100)).toInt()}%"
45+
}
46+
47+
fun increment(value: Int = 1): Percent {
48+
return Percent(current + value, max)
49+
}
50+
}
51+
52+
class Counter(override val current: Long, override val max: Long) : Count {
53+
54+
constructor(current: Int, max: Int) : this(current.toLong(), max.toLong())
55+
constructor(max: Int) : this(0, max)
56+
constructor(max: Long) : this(0, max)
57+
58+
override fun displayValue(context: Context): String = "$current/$max"
59+
60+
fun increment(value: Int = 1) = Counter(current + value, max)
61+
}
62+
63+
data class Size(override val current: Long, override val max: Long) : Count {
64+
override fun displayValue(context: Context): String {
65+
val curSize = Formatter.formatShortFileSize(context, current)
66+
val maxSize = Formatter.formatShortFileSize(context, max)
67+
return "$curSize/$maxSize"
68+
}
69+
}
70+
71+
data class Indeterminate(override val current: Long = 0, override val max: Long = 0) : Count {
72+
override fun displayValue(context: Context): String = ""
73+
}
74+
75+
data class None(override val current: Long = -1, override val max: Long = -1) : Count {
76+
override fun displayValue(context: Context): String? = null
77+
}
78+
}
79+
}
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
package eu.darken.butler.common.progress
2+
3+
import android.content.Context
4+
import android.graphics.drawable.Drawable
5+
import androidx.annotation.StringRes
6+
import eu.darken.butler.common.ca.CaDrawable
7+
import eu.darken.butler.common.ca.CaString
8+
import eu.darken.butler.common.ca.caString
9+
import eu.darken.butler.common.ca.toCaDrawable
10+
import eu.darken.butler.common.ca.toCaString
11+
import eu.darken.butler.common.debug.logging.Logging.Priority.*
12+
import eu.darken.butler.common.debug.logging.log
13+
import kotlinx.coroutines.CoroutineScope
14+
import kotlinx.coroutines.cancel
15+
import kotlinx.coroutines.cancelAndJoin
16+
import kotlinx.coroutines.currentCoroutineContext
17+
import kotlinx.coroutines.flow.launchIn
18+
import kotlinx.coroutines.flow.onCompletion
19+
import kotlinx.coroutines.flow.onEach
20+
import kotlinx.coroutines.isActive
21+
import kotlin.coroutines.EmptyCoroutineContext
22+
23+
fun <T : Progress.Client> T.updateProgressIcon(icon: Drawable) {
24+
updateProgress { (it ?: Progress.Data()).copy(icon = icon.toCaDrawable()) }
25+
}
26+
27+
fun <T : Progress.Client> T.updateProgressIcon(icon: CaDrawable?) {
28+
updateProgress { (it ?: Progress.Data()).copy(icon = icon) }
29+
}
30+
31+
fun <T : Progress.Client> T.updateProgressIcon(resolv: (Context) -> Drawable) {
32+
updateProgress { (it ?: Progress.Data()).copy(icon = resolv.toCaDrawable()) }
33+
}
34+
35+
fun <T : Progress.Client> T.updateProgressPrimary(primary: String) {
36+
updateProgress { (it ?: Progress.Data()).copy(primary = primary.toCaString()) }
37+
}
38+
39+
fun <T : Progress.Client> T.updateProgressPrimary(primary: CaString) {
40+
updateProgress { (it ?: Progress.Data()).copy(primary = primary) }
41+
}
42+
43+
fun <T : Progress.Client> T.updateProgressPrimary(resolv: (Context) -> String) {
44+
updateProgress { (it ?: Progress.Data()).copy(primary = caString { resolv(this) }) }
45+
}
46+
47+
fun <T : Progress.Client> T.updateProgressPrimary(@StringRes primary: Int, vararg args: Any) {
48+
updateProgress { (it ?: Progress.Data()).copy(primary = (primary to args).toCaString()) }
49+
}
50+
51+
fun <T : Progress.Client> T.updateProgressSecondary(secondary: String) {
52+
updateProgress { (it ?: Progress.Data()).copy(secondary = secondary.toCaString()) }
53+
}
54+
55+
fun <T : Progress.Client> T.updateProgressSecondary(resolv: (Context) -> String) {
56+
updateProgress { (it ?: Progress.Data()).copy(secondary = caString { resolv(this) }) }
57+
}
58+
59+
fun <T : Progress.Client> T.updateProgressSecondary(secondary: CaString = CaString.EMPTY) {
60+
updateProgress { (it ?: Progress.Data()).copy(secondary = secondary) }
61+
}
62+
63+
fun <T : Progress.Client> T.updateProgressSecondary(@StringRes secondary: Int, vararg args: Any) {
64+
updateProgress { (it ?: Progress.Data()).copy(secondary = (secondary to args).toCaString()) }
65+
}
66+
67+
fun <T : Progress.Client> T.updateProgressCount(count: Progress.Count) {
68+
updateProgress { (it ?: Progress.Data()).copy(count = count) }
69+
}
70+
71+
fun <T : Progress.Client> T.increaseProgress(value: Int = 1) {
72+
updateProgress {
73+
when (it?.count) {
74+
is Progress.Count.Counter -> it.copy(count = it.count.increment(value))
75+
is Progress.Count.Percent -> it.copy(count = it.count.increment(value))
76+
else -> {
77+
log(ERROR) { "Can't increaseProgress() on type: ${it?.count}" }
78+
it
79+
}
80+
}
81+
}
82+
}
83+
84+
suspend fun <T : Progress.Host> T.forwardProgressTo(
85+
client: Progress.Client,
86+
onUpdate: (existing: Progress.Data?, new: Progress.Data?) -> Progress.Data?,
87+
onCompletion: (Progress.Data?) -> Progress.Data?,
88+
) = progress
89+
.onEach { new -> client.updateProgress { onUpdate(it, new) } }
90+
.onCompletion { if (currentCoroutineContext().isActive) client.updateProgress { onCompletion(it) } }
91+
92+
suspend fun <T : Progress.Host, R> T.withProgress(
93+
client: Progress.Client,
94+
onUpdate: (existing: Progress.Data?, new: Progress.Data?) -> Progress.Data? = { _, new -> new },
95+
onCompletion: (Progress.Data?) -> Progress.Data? = { Progress.Data() },
96+
action: suspend T.() -> R
97+
): R {
98+
val scope = CoroutineScope(EmptyCoroutineContext)
99+
100+
val forwardingJob = forwardProgressTo(
101+
client,
102+
onUpdate,
103+
onCompletion
104+
).launchIn(scope)
105+
106+
return try {
107+
action()
108+
} finally {
109+
forwardingJob.cancelAndJoin()
110+
scope.cancel("Finished scope")
111+
}
112+
}

app-workspace-editor/src/main/java/eu/darken/butler/editor/ui/EditorWorkspaceViewModel.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ class EditorWorkspaceViewModel @AssistedInject constructor(
4848
private val workspaceProvider: WorkspaceProvider,
4949
) : ViewModel4(dispatchers, logTag("Workspace", "Editor", id.shortTag, "Page"), navCtrl) {
5050

51-
private val workspace = runBlocking { workspaceProvider.get(id).first() as EditorWorkspace }
51+
private val workspace = runBlocking { workspaceProvider.retrieve(id).first() as EditorWorkspace }
5252
private val dataSource: EditorDataSource =
5353
workspace.filePath?.let { filePath ->
5454
fileDataSourceFactory.create(filePath, gatewaySwitch)

app-workspace-explorer/src/main/java/eu/darken/butler/explorer/core/ExplorerEngine.kt

Lines changed: 0 additions & 105 deletions
This file was deleted.

app-workspace-explorer/src/main/java/eu/darken/butler/explorer/core/ExplorerEntry.kt

Lines changed: 0 additions & 52 deletions
This file was deleted.

0 commit comments

Comments
 (0)