Skip to content

Commit

Permalink
bump version to 1.0.0-alpha02
Browse files Browse the repository at this point in the history
view ak3 output
drop previews
drop state holders
switch to MutableState
  • Loading branch information
capntrips committed May 1, 2022
1 parent aff6f62 commit c162946
Show file tree
Hide file tree
Showing 32 changed files with 1,054 additions and 1,350 deletions.
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Kernel Flasher

Kernel Flasher is an Android app to flash, backup, and restore kernels.

## Usage

`View` a slot and choose to `Flash` an AK3 zip, `Backup` the kernel related partitions, or `Restore` a previous backup.

There are also options to toggle the mount and map status of `vendor_dlkm` and to save `dmesg` and `logcat`.
5 changes: 2 additions & 3 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ android {
applicationId "com.github.capntrips.kernelflasher"
minSdk 31
targetSdk 32
versionCode 1
versionName "1.0.0-alpha01"
versionCode 2
versionName "1.0.0-alpha02"

testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
vectorDrawables {
Expand Down Expand Up @@ -49,7 +49,6 @@ dependencies {
implementation "androidx.activity:activity-compose:$activity_version"
implementation "androidx.compose.material3:material3:$material3_version"
implementation "androidx.compose.foundation:foundation:$compose_version"
implementation "androidx.compose.ui:ui-tooling-preview:$compose_version"
implementation "androidx.compose.ui:ui:$compose_version"
implementation "androidx.core:core-ktx:$core_version"
implementation "androidx.core:core-splashscreen:$splashscreen_version"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,8 @@ import androidx.activity.compose.setContent
import androidx.activity.viewModels
import androidx.compose.animation.ExperimentalAnimationApi
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.ExperimentalUnitApi
import androidx.core.animation.doOnEnd
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
import androidx.core.view.WindowCompat
Expand All @@ -24,6 +23,7 @@ import com.github.capntrips.kernelflasher.ui.screens.main.MainContent
import com.github.capntrips.kernelflasher.ui.screens.main.MainViewModel
import com.github.capntrips.kernelflasher.ui.screens.main.MainViewModelFactory
import com.github.capntrips.kernelflasher.ui.screens.slot.SlotContent
import com.github.capntrips.kernelflasher.ui.screens.slot.SlotFlashContent
import com.github.capntrips.kernelflasher.ui.theme.KernelFlasherTheme
import com.google.accompanist.navigation.animation.AnimatedNavHost
import com.google.accompanist.navigation.animation.composable
Expand All @@ -38,6 +38,7 @@ class MainActivity : ComponentActivity() {
private lateinit var mainListener: MainListener
var isAwaitingResult = false

@Suppress("SameParameterValue")
private fun copyAsset(filename: String) {
val dest = File(filesDir, filename)
assets.open(filename).use { inputStream ->
Expand All @@ -48,6 +49,8 @@ class MainActivity : ComponentActivity() {
Shell.cmd("chmod +x $dest").exec()
}

@Suppress("OPT_IN_MARKER_ON_OVERRIDE_WARNING")
@ExperimentalUnitApi
override fun onCreate(savedInstanceState: Bundle?) {
installSplashScreen()
super.onCreate(savedInstanceState)
Expand Down Expand Up @@ -88,73 +91,67 @@ class MainActivity : ComponentActivity() {
mainListener = MainListener {
mainViewModel.refresh(this)
}
val slotViewModelA = mainViewModel.toSlotViewModelA()
val slotStateA by slotViewModelA.uiState.collectAsState()
val slotViewModelB = mainViewModel.toSlotViewModelB()
val slotStateB by slotViewModelA.uiState.collectAsState()
val backupsViewModel = mainViewModel.toBackupsViewModel()
val backupsState by backupsViewModel.uiState.collectAsState()
val slotViewModelA = mainViewModel.slotA
val slotViewModelB = mainViewModel.slotB
val backupsViewModel = mainViewModel.backups
AnimatedNavHost(navController = navController, startDestination = "main") {
composable("main") {
slotStateA.wasFlashed = false
slotStateB.wasFlashed = false
RefreshableScreen(mainViewModel, navController) {
MainContent(mainViewModel, navController)
}
}
composable("slotA") {
RefreshableScreen(mainViewModel, navController) {
SlotContent(slotViewModelA, "_a", navController)
composable("slot{slotSuffix}") { backStackEntry ->
val slotSuffix = backStackEntry.arguments?.getString("slotSuffix")!!
val slotViewModel = if (slotSuffix == "_a") slotViewModelA else slotViewModelB
if (slotSuffix == "_a") {
slotViewModelA.clearFlash()
} else {
slotViewModelB.clearFlash()
}
}
composable("slotA/backups") {
backupsState.clearCurrent()
RefreshableScreen(mainViewModel, navController) {
SlotBackupsContent(slotViewModelA, backupsViewModel, "_a", navController)
}
}
composable("slotA/backups/{backupId}") {backStackEntry ->
backupsState.currentBackup = backStackEntry.arguments?.getString("backupId")
if (backupsState.backups.containsKey(backupsState.currentBackup)) {
RefreshableScreen(mainViewModel, navController) {
SlotBackupsContent(slotViewModelA, backupsViewModel, "_a", navController)
}
SlotContent(slotViewModel, slotSuffix, navController)
}
}
composable("slotB") {
composable("slot{slotSuffix}/flash") { backStackEntry ->
val slotSuffix = backStackEntry.arguments?.getString("slotSuffix")!!
val slotViewModel = if (slotSuffix == "_a") slotViewModelA else slotViewModelB
RefreshableScreen(mainViewModel, navController) {
SlotContent(slotViewModelB, "_b", navController)
SlotFlashContent(slotViewModel, navController)
}
}
composable("slotB/backups") {
backupsState.clearCurrent()
composable("slot{slotSuffix}/backups") { backStackEntry ->
val slotSuffix = backStackEntry.arguments?.getString("slotSuffix")!!
val slotViewModel = if (slotSuffix == "_a") slotViewModelA else slotViewModelB
backupsViewModel.clearCurrent()
RefreshableScreen(mainViewModel, navController) {
SlotBackupsContent(slotViewModelB, backupsViewModel, "_b", navController)
SlotBackupsContent(slotViewModel, backupsViewModel, slotSuffix, navController)
}
}
composable("slotB/backups/{backupId}") {backStackEntry ->
backupsState.currentBackup = backStackEntry.arguments?.getString("backupId")
if (backupsState.backups.containsKey(backupsState.currentBackup)) {
composable("slot{slotSuffix}/backups/{backupId}") { backStackEntry ->
val slotSuffix = backStackEntry.arguments?.getString("slotSuffix")!!
val slotViewModel = if (slotSuffix == "_a") slotViewModelA else slotViewModelB
backupsViewModel.currentBackup = backStackEntry.arguments?.getString("backupId")
if (backupsViewModel.backups.containsKey(backupsViewModel.currentBackup)) {
RefreshableScreen(mainViewModel, navController) {
SlotBackupsContent(slotViewModelB, backupsViewModel, "_b", navController)
SlotBackupsContent(slotViewModel, backupsViewModel, slotSuffix, navController)
}
}
}
composable("backups") {
backupsState.clearCurrent()
backupsViewModel.clearCurrent()
RefreshableScreen(mainViewModel, navController) {
BackupsContent(backupsViewModel, navController)
}
}
composable("backups/{backupId}") {backStackEntry ->
backupsState.currentBackup = backStackEntry.arguments?.getString("backupId")
if (backupsState.backups.containsKey(backupsState.currentBackup)) {
composable("backups/{backupId}") { backStackEntry ->
backupsViewModel.currentBackup = backStackEntry.arguments?.getString("backupId")
if (backupsViewModel.backups.containsKey(backupsViewModel.currentBackup)) {
RefreshableScreen(mainViewModel, navController) {
BackupsContent(backupsViewModel, navController)
}
}
}
composable("error/{error}") {backStackEntry ->
composable("error/{error}") { backStackEntry ->
val error = backStackEntry.arguments?.getString("error")
ErrorScreen(error!!)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package com.github.capntrips.kernelflasher

internal class MainListener constructor(private val callback: () -> Unit) {
internal class MainListener(private val callback: () -> Unit) {
fun resume() {
callback.invoke()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,15 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import com.github.capntrips.kernelflasher.MainActivity
import com.github.capntrips.kernelflasher.R
import com.github.capntrips.kernelflasher.ui.state.slot.SlotStateInterface
import com.github.capntrips.kernelflasher.ui.screens.slot.SlotViewModel

@ExperimentalAnimationApi
@ExperimentalMaterial3Api
@Composable
fun FlashButton(slot: SlotStateInterface) {
fun FlashButton(
viewModel: SlotViewModel,
callback: () -> Unit
) {
val mainActivity = LocalContext.current as MainActivity
val result = remember { mutableStateOf<Uri?>(null) }
val launcher = rememberLauncherForActivityResult(ActivityResultContracts.GetContent()) {
Expand All @@ -45,7 +48,7 @@ fun FlashButton(slot: SlotStateInterface) {
}
result.value?.let {uri ->
if (mainActivity.isAwaitingResult) {
slot.flash(mainActivity, uri)
viewModel.checkZip(mainActivity, uri, callback = callback)
}
mainActivity.isAwaitingResult = false
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,55 +4,50 @@ import androidx.compose.animation.AnimatedVisibility
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.font.FontWeight
import androidx.navigation.NavController
import com.github.capntrips.kernelflasher.R
import com.github.capntrips.kernelflasher.ui.state.slot.SlotStateInterface
import kotlinx.coroutines.flow.StateFlow
import com.github.capntrips.kernelflasher.ui.screens.slot.SlotViewModel

@ExperimentalMaterial3Api
@Composable
fun SlotCard(
title: String,
slotStateFlow: StateFlow<SlotStateInterface>,
viewModel: SlotViewModel,
navController: NavController,
isSlotScreen: Boolean = false,
) {
val slot by slotStateFlow.collectAsState()
val isRefreshing by slot.isRefreshing.collectAsState()
DataCard (
title = title,
button = {
if (!isSlotScreen) {
AnimatedVisibility(!isRefreshing) {
AnimatedVisibility(!viewModel.isRefreshing) {
ViewButton {
navController.navigate(if (slot.slotSuffix == "_a") "slotA" else "slotB")
navController.navigate("slot${viewModel.slotSuffix}")
}
}
}
}
) {
DataRow(
label = stringResource(R.string.boot_sha1),
value = slot.sha1.substring(0, 8),
value = viewModel.sha1.substring(0, 8),
valueStyle = MaterialTheme.typography.titleSmall.copy(
fontFamily = FontFamily.Monospace,
fontWeight = FontWeight.Thin
)
)
AnimatedVisibility(!isRefreshing && slot.kernelVersion != null) {
AnimatedVisibility(!viewModel.isRefreshing && viewModel.kernelVersion != null) {
DataRow(
label = stringResource(R.string.kernel_version),
value = if (slot.kernelVersion != null) slot.kernelVersion!! else ""
value = if (viewModel.kernelVersion != null) viewModel.kernelVersion!! else ""
)
}
var vendorDlkmValue = stringResource(R.string.not_found)
if (slot.hasVendorDlkm) {
vendorDlkmValue = if (slot.isVendorDlkmMounted) {
if (viewModel.hasVendorDlkm) {
vendorDlkmValue = if (viewModel.isVendorDlkmMounted) {
String.format("%s, %s", stringResource(R.string.exists), stringResource(R.string.mounted))
} else {
String.format("%s, %s", stringResource(R.string.exists), stringResource(R.string.unmounted))
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package com.github.capntrips.kernelflasher.ui.screens

import android.content.res.Configuration
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.ColumnScope
Expand All @@ -23,29 +22,22 @@ import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.navigation.NavController
import androidx.navigation.compose.rememberNavController
import com.github.capntrips.kernelflasher.R
import com.github.capntrips.kernelflasher.ui.screens.main.MainContent
import com.github.capntrips.kernelflasher.ui.screens.main.MainViewModelInterface
import com.github.capntrips.kernelflasher.ui.screens.main.MainViewModelPreview
import com.github.capntrips.kernelflasher.ui.theme.KernelFlasherTheme
import com.github.capntrips.kernelflasher.ui.screens.main.MainViewModel
import com.google.accompanist.swiperefresh.SwipeRefresh
import com.google.accompanist.swiperefresh.SwipeRefreshIndicator
import com.google.accompanist.swiperefresh.rememberSwipeRefreshState

@ExperimentalMaterial3Api
@Composable
fun RefreshableScreen(
viewModel: MainViewModelInterface,
viewModel: MainViewModel,
navController: NavController,
content: @Composable ColumnScope.() -> Unit
) {
Expand Down Expand Up @@ -85,12 +77,11 @@ fun RefreshableScreen(
}
) { paddingValues ->
val context = LocalContext.current
val isRefreshing by viewModel.isRefreshing.collectAsState()
SwipeRefresh(
modifier = Modifier
.padding(paddingValues)
.fillMaxSize(),
state = rememberSwipeRefreshState(isRefreshing),
state = rememberSwipeRefreshState(viewModel.isRefreshing),
onRefresh = { viewModel.refresh(context) },
indicator = { state, trigger ->
SwipeRefreshIndicator(
Expand All @@ -112,27 +103,3 @@ fun RefreshableScreen(
}
}
}

@ExperimentalMaterial3Api
@Preview(
showBackground = true,
uiMode = Configuration.UI_MODE_NIGHT_YES
)
@Composable
fun MainScreenPreviewDark() {
MainScreenPreviewLight()
}

@ExperimentalMaterial3Api
@Preview(showBackground = true)
@Composable
fun MainScreenPreviewLight() {
KernelFlasherTheme {
val context = LocalContext.current
val navController = rememberNavController()
val viewModel = MainViewModelPreview(context, navController)
RefreshableScreen(viewModel, navController) {
MainContent(viewModel, navController)
}
}
}
Loading

0 comments on commit c162946

Please sign in to comment.