Skip to content

Commit

Permalink
better downloads mvp (works but minor bugs in ui are present)
Browse files Browse the repository at this point in the history
  • Loading branch information
nift4 committed Aug 23, 2024
1 parent 7ec02e5 commit 5da2861
Show file tree
Hide file tree
Showing 9 changed files with 99 additions and 74 deletions.
1 change: 0 additions & 1 deletion app/src/main/java/org/andbootmgr/app/BackupRestoreFlow.kt
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,6 @@ private fun SelectDroidBoot(c: CreateBackupDataHolder) {
else -> ""
}
)
val next =
Button(onClick = {
if (c.action != 1) {
c.vm.activity.chooseFile("*/*") {
Expand Down
1 change: 1 addition & 0 deletions app/src/main/java/org/andbootmgr/app/CreatePartFlow.kt
Original file line number Diff line number Diff line change
Expand Up @@ -654,6 +654,7 @@ private fun Flash(c: CreatePartDataHolder) {
val vm = c.vm
Terminal(logFile = "install_${System.currentTimeMillis()}.txt") { terminal ->
c.vm.logic.extractToolkit(terminal)
c.vm.downloadRemainingFiles(terminal)
if (c.partitionName == null) { // OS install
val createdParts = mutableListOf<Pair<Part, Int>>() // order is important
val fn = c.romFolderName
Expand Down
1 change: 1 addition & 0 deletions app/src/main/java/org/andbootmgr/app/DroidBootFlow.kt
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,7 @@ private fun Flash(d: DroidBootFlowDataHolder) {
val vm = d.vm
Terminal(logFile = "blflash_${System.currentTimeMillis()}.txt") { terminal ->
vm.logic.extractToolkit(terminal)
vm.downloadRemainingFiles(terminal)
terminal.add(vm.activity.getString(R.string.term_preparing_fs))
if (vm.logic.checkMounted()) {
terminal.add(vm.activity.getString(R.string.term_mount_state_bad))
Expand Down
1 change: 1 addition & 0 deletions app/src/main/java/org/andbootmgr/app/FixDroidBootFlow.kt
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ private fun Start(vm: WizardState) {
private fun Flash(vm: WizardState) {
Terminal(logFile = "blfix_${System.currentTimeMillis()}.txt") { terminal ->
vm.logic.extractToolkit(terminal)
vm.downloadRemainingFiles(terminal)
val tmpFile = if (vm.deviceInfo.postInstallScript) {
vm.chosen["_install.sh_"]!!.toFile(vm).also {
it.setExecutable(true)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ private fun Start(vm: WizardState) {
private fun Flash(vm: WizardState) {
Terminal(logFile = "blup_${System.currentTimeMillis()}.txt") { terminal ->
vm.logic.extractToolkit(terminal)
vm.downloadRemainingFiles(terminal)
val tmpFile = if (vm.deviceInfo.postInstallScript) {
vm.chosen["_install.sh_"]!!.toFile(vm).also {
it.setExecutable(true)
Expand Down
1 change: 1 addition & 0 deletions app/src/main/java/org/andbootmgr/app/UpdateFlow.kt
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,7 @@ private fun Local(u: UpdateFlowDataHolder) {
private fun Flash(u: UpdateFlowDataHolder) {
Terminal(logFile = "update_${System.currentTimeMillis()}.txt") { terminal ->
u.vm.logic.extractToolkit(terminal)
u.vm.downloadRemainingFiles(terminal)
val sp = u.e!!["xpart"]!!.split(":")
val meta = SDUtils.generateMeta(u.vm.deviceInfo)!!
Shell.cmd(SDUtils.umsd(meta)).exec()
Expand Down
99 changes: 41 additions & 58 deletions app/src/main/java/org/andbootmgr/app/Wizard.kt
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
package org.andbootmgr.app

import android.net.Uri
import android.util.Log
import android.os.CancellationSignal
import android.view.WindowManager
import android.widget.Toast
import androidx.activity.compose.BackHandler
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
Expand All @@ -12,7 +11,6 @@ import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.Button
import androidx.compose.material3.Card
import androidx.compose.material3.Icon
Expand All @@ -38,18 +36,18 @@ import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.rememberNavController
import com.topjohnwu.superuser.io.SuFileOutputStream
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.andbootmgr.app.util.AbmOkHttp
import org.andbootmgr.app.util.SOUtils
import org.andbootmgr.app.util.TerminalCancelException
import org.andbootmgr.app.util.TerminalList
import java.io.File
import java.io.FileInputStream
import java.io.IOException
import java.io.InputStream
import java.io.OutputStream
import java.nio.file.Files
import java.nio.file.StandardCopyOption
import java.util.concurrent.CancellationException

abstract class WizardFlow {
abstract fun get(vm: WizardState): List<IWizardPage>
Expand Down Expand Up @@ -140,7 +138,42 @@ class WizardState(val mvm: MainActivityState) {
throw IllegalStateException("invalid DledFile OR safFile failure")
}
}
//suspend fun downloadRemainingFiles
suspend fun downloadRemainingFiles(terminal: TerminalList) {
terminal.isCancelled.value = false
for (id in idNeeded.filter { !chosen.containsKey(it) }) {
if (!inetAvailable.containsKey(id))
throw IllegalStateException("$id not chosen and not available from inet")
terminal.add(activity.getString(R.string.downloading_s, id))
val inet = inetAvailable[id]!!
val f = File(logic.cacheDir, System.currentTimeMillis().toString())
terminal.add(activity.getString(R.string.connecting_text))
val client = AbmOkHttp(inet.url, f, inet.hash) { readBytes, total, done ->
terminal[terminal.size - 1] = if (done) activity.getString(R.string.done) else
activity.getString(
R.string.download_progress,
"${readBytes / (1024 * 1024)} MiB", "${total / (1024 * 1024)} MiB"
)
}
terminal.cancel = { terminal.isCancelled.value = true; client.cancel() }
try {
client.run()
} catch (e: IOException) {
if (terminal.isCancelled.value == true) {
throw TerminalCancelException()
}
throw e
}
if (terminal.isCancelled.value == true) {
throw TerminalCancelException()
}
chosen[id] = DownloadedFile(null, f)
}
if (terminal.isCancelled.value == true) {
throw TerminalCancelException()
} else {
terminal.isCancelled.value = null
}
}

fun navigate(next: String) {
prevText = null
Expand Down Expand Up @@ -224,21 +257,6 @@ fun WizardDownloader(vm: WizardState, next: String) {
Text(stringResource(id = R.string.provide_images))
}
}
var cancelDownload by remember { mutableStateOf<(() -> Unit)?>(null) }
var progressText by remember { mutableStateOf(vm.activity.getString(R.string.connecting_text)) }
if (cancelDownload != null) {
AlertDialog(
onDismissRequest = {},
confirmButton = {
Button(onClick = { cancelDownload!!() }) {
Text(stringResource(id = R.string.cancel))
}
},
title = { Text(stringResource(R.string.downloading)) },
text = {
LoadingCircle(progressText, paddingBetween = 10.dp)
})
}
for (i in vm.idNeeded) {
Row(
verticalAlignment = Alignment.CenterVertically,
Expand All @@ -261,41 +279,6 @@ fun WizardDownloader(vm: WizardState, next: String) {
Text(stringResource(R.string.undo))
}
} else {
/*if (vm.inetAvailable.containsKey(i)) {
Button(onClick = {
CoroutineScope(Dispatchers.Main).launch {
val url = vm.inetAvailable[i]!!.url
val downloadedFile = File(vm.logic.cacheDir, i)
val h = vm.inetAvailable[i]!!.hash
val client = AbmOkHttp(url, downloadedFile, h) { bytesRead, contentLength, _ ->
progressText = vm.activity.getString(R.string.download_progress,
SOUtils.humanReadableByteCountBin(bytesRead), SOUtils.humanReadableByteCountBin(contentLength))
}
try {
progressText = vm.activity.getString(R.string.connecting_text)
cancelDownload = {
client.cancel()
cancelDownload = null
}
if (client.run()) {
vm.chosen[i] = WizardState.DownloadedFile(null, downloadedFile)
}
} catch (e: Exception) {
Log.e("ABM", Log.getStackTraceString(e))
withContext(Dispatchers.Main) {
Toast.makeText(
vm.activity,
vm.activity.getString(R.string.dl_error),
Toast.LENGTH_LONG
).show()
}
}
cancelDownload = null
}
}) {
Text(stringResource(R.string.download))
}
}*/
Button(onClick = {
vm.activity.chooseFile("*/*") {
vm.chosen[i] = WizardState.DownloadedFile(it, null)
Expand Down
67 changes: 52 additions & 15 deletions app/src/main/java/org/andbootmgr/app/util/Terminal.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,16 @@ package org.andbootmgr.app.util

import android.util.Log
import androidx.compose.foundation.horizontalScroll
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.Button
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
Expand All @@ -18,6 +21,7 @@ import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalLifecycleOwner
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.unit.dp
import kotlinx.coroutines.CoroutineScope
Expand All @@ -31,9 +35,12 @@ import java.io.File
import java.io.FileOutputStream

private class BudgetCallbackList(private val scope: CoroutineScope,
private val log: FileOutputStream?) : MutableList<String> {
private val log: FileOutputStream?)
: MutableList<String>, TerminalList {
override val isCancelled = mutableStateOf<Boolean?>(null)
override var cancel: (() -> Unit)? = null
val internalList = ArrayList<String>()
var cb: ((String) -> Unit)? = null
var cb: (() -> Unit)? = null
override val size: Int
get() = internalList.size

Expand Down Expand Up @@ -118,7 +125,9 @@ private class BudgetCallbackList(private val scope: CoroutineScope,
}

override fun set(index: Int, element: String): String {
return internalList.set(index, element)
return internalList.set(index, element).also {
cb?.invoke()
}
}

override fun subList(fromIndex: Int, toIndex: Int): MutableList<String> {
Expand All @@ -129,18 +138,26 @@ private class BudgetCallbackList(private val scope: CoroutineScope,
scope.launch {
log?.write((element + "\n").encodeToByteArray())
}
cb?.invoke(element)
cb?.invoke()
}
}

interface TerminalList : MutableList<String> {
val isCancelled: MutableState<Boolean?>
var cancel: (() -> Unit)?
}
class TerminalCancelException : RuntimeException()

/* Monospace auto-scrolling text view, fed using MutableList<String>, catching exceptions and running logic on a different thread */
@OptIn(ExperimentalCoroutinesApi::class)
@Composable
fun Terminal(logFile: String? = null, doWhenDone: (() -> Unit)? = null,
action: (suspend (MutableList<String>) -> Unit)?) {
action: (suspend (TerminalList) -> Unit)?) {
val scrollH = rememberScrollState()
val scrollV = rememberScrollState()
val scope = rememberCoroutineScope()
val scope = rememberCoroutineScope { Dispatchers.Main }
var isCancelledState by remember { mutableStateOf(mutableStateOf<Boolean?>(null)) }
var doCancelState by remember { mutableStateOf<(() -> Unit)?>(null) }
var didConnectAndFinish by rememberSaveable { mutableStateOf(false) }
var text by rememberSaveable { mutableStateOf("") }
val ctx = LocalContext.current.applicationContext
Expand All @@ -161,9 +178,12 @@ fun Terminal(logFile: String? = null, doWhenDone: (() -> Unit)? = null,
val logDispatcher = Dispatchers.IO.limitedParallelism(1)
val log = logFile?.let { FileOutputStream(File(ctx.externalCacheDir, it)) }
val s = BudgetCallbackList(CoroutineScope(logDispatcher), log)
s.cb = { element ->
isCancelledState = s.isCancelled
doCancelState = { s.cancel!!() }
s.cb = {
val l = s.toList()
scope.launch {
text += element + "\n"
text = l.joinToString("\n").let { if (s.isNotEmpty()) it + "\n" else it }
delay(200) // Give it time to re-measure
scrollV.animateScrollTo(scrollV.maxValue)
scrollH.animateScrollTo(0)
Expand All @@ -173,6 +193,8 @@ fun Terminal(logFile: String? = null, doWhenDone: (() -> Unit)? = null,
withContext(Dispatchers.Default) {
try {
action(s)
} catch (e: TerminalCancelException) {
s.add(ctx.getString(R.string.install_canceled))
} catch (e: Throwable) {
s.add(ctx.getString(R.string.term_failure))
s.add(ctx.getString(R.string.dev_details))
Expand All @@ -185,22 +207,37 @@ fun Terminal(logFile: String? = null, doWhenDone: (() -> Unit)? = null,
}, s)
} else {
val s = service.workExtra as BudgetCallbackList
isCancelledState = s.isCancelled
doCancelState = { s.cancel!!() }
text = s.joinToString("\n").let { if (s.isNotEmpty()) it + "\n" else it }
s.cb = { element ->
s.cb = {
val l = s.toList()
scope.launch {
text += element + "\n"
text = l.joinToString("\n").let { if (s.isNotEmpty()) it + "\n" else it }
delay(200) // Give it time to re-measure
scrollV.animateScrollTo(scrollV.maxValue)
scrollH.animateScrollTo(0)
}
}

}
}
}
}
Text(text, modifier = Modifier
.fillMaxSize()
.horizontalScroll(scrollH)
.verticalScroll(scrollV)
.padding(10.dp), fontFamily = FontFamily.Monospace)
Column(modifier = Modifier.fillMaxSize()) {
Text(text, modifier = Modifier
.fillMaxSize()
.weight(1f)
.horizontalScroll(scrollH)
.verticalScroll(scrollV)
.padding(10.dp), fontFamily = FontFamily.Monospace
)
if (isCancelledState.value == false) {
Button({
doCancelState?.invoke()
}) {
Text(stringResource(R.string.cancel))
}
}
}
}
1 change: 1 addition & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
<string name="install">Install</string>
<string name="connecting_text">(Connecting…)</string>
<string name="downloading">Downloading…</string>
<string name="downloading_s">Downloading %s…</string>
<string name="provide_images">Please now provide images for all required IDs. You can use the recommended ones using the \"Download\" button!</string>
<string name="user_selected">User-selected</string>
<string name="undo">Undo</string>
Expand Down

0 comments on commit 5da2861

Please sign in to comment.