Hoist state, base for events handling

This commit is contained in:
Kamil Gurgul
2021-11-19 15:52:13 +01:00
parent ae5c4f0af6
commit b78e001207
5 changed files with 73 additions and 27 deletions
+3 -4
View File
@@ -1,13 +1,11 @@
<img src="info/icon_glow.png" width="100" height="100" />
CPU Info<br/>
========
CPU Info (refactor-in-progress ⛏)
=================================
CPU Info provides information about Android device hardware and software.
Most of the code is written in Kotlin but some old widgets are still in
Java.
Due to lack of time, this project will be updated sporadically. Right now it is only a sandbox.
[<img src="https://f-droid.org/badge/get-it-on.png"
alt="Get it on F-Droid"
height="80">](https://f-droid.org/packages/com.kgurgul.cpuinfo/)
@@ -17,6 +15,7 @@ Due to lack of time, this project will be updated sporadically. Right now it is
Still TODO
==========
* Unify architecture - add interactors and data providers
* Replace layouts with Compose
* Replace Travis
* Replace RxJava with coroutines
@@ -3,12 +3,11 @@ package com.kgurgul.cpuinfo.features.applications
import android.content.res.Configuration
import android.net.Uri
import androidx.compose.foundation.Image
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Surface
import androidx.compose.material.Text
import androidx.compose.material.*
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
@@ -25,38 +24,61 @@ import com.kgurgul.cpuinfo.theme.CpuInfoTheme
import com.kgurgul.cpuinfo.utils.wrappers.Result
@Composable
fun ApplicationsScreen(viewModel: NewApplicationsViewModel = viewModel()) {
fun ApplicationsScreen(
viewModel: NewApplicationsViewModel = viewModel(),
scaffoldState: ScaffoldState = rememberScaffoldState(),
onAppClicked: (packageName: String) -> Unit
) {
val uiState by viewModel.applicationList.collectAsState()
val isRefreshingState = uiState is Result.Loading
Surface {
Scaffold(
scaffoldState = scaffoldState
) {
SwipeRefresh(
state = rememberSwipeRefreshState(isRefreshingState),
onRefresh = { viewModel.refreshApplications() },
) {
(uiState as? Result.Success)?.let {
ApplicationsList(state = it)
ApplicationsList(
appList = it.data,
onAppClicked = onAppClicked
)
}
}
}
}
@Composable
fun ApplicationsList(state: Result.Success<List<ExtendedApplicationData>>) {
fun ApplicationsList(
appList: List<ExtendedApplicationData>,
onAppClicked: (packageName: String) -> Unit
) {
LazyColumn(
modifier = Modifier
.fillMaxSize()
) {
items(state.data) {
ApplicationItem(appData = it)
items(appList) {
ApplicationItem(
appData = it,
onAppClicked = onAppClicked
)
}
}
}
@Composable
fun ApplicationItem(appData: ExtendedApplicationData) {
fun ApplicationItem(
appData: ExtendedApplicationData,
onAppClicked: (packageName: String) -> Unit
) {
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier.padding(8.dp)
modifier = Modifier
.fillMaxWidth()
.clickable(onClick = { onAppClicked(appData.packageName) })
.padding(8.dp),
) {
Image(
painter = rememberImagePainter(
@@ -85,7 +107,7 @@ fun ApplicationItem(appData: ExtendedApplicationData) {
fun ApplicationInfoPreviewLight() {
CpuInfoTheme {
Surface {
ApplicationItem(testAppData)
ApplicationItem(previewAppData) {}
}
}
}
@@ -95,12 +117,12 @@ fun ApplicationInfoPreviewLight() {
fun ApplicationInfoPreviewDark() {
CpuInfoTheme {
Surface {
ApplicationItem(testAppData)
ApplicationItem(previewAppData) {}
}
}
}
private val testAppData = ExtendedApplicationData(
private val previewAppData = ExtendedApplicationData(
"Cpu Info",
"com.kgurgul.cpuinfo",
"/testDir",
@@ -6,6 +6,7 @@ import android.view.View
import android.view.ViewGroup
import androidx.compose.ui.platform.ComposeView
import androidx.fragment.app.Fragment
import androidx.fragment.app.viewModels
import com.kgurgul.cpuinfo.R
import com.kgurgul.cpuinfo.theme.CpuInfoTheme
import dagger.hilt.android.AndroidEntryPoint
@@ -13,6 +14,8 @@ import dagger.hilt.android.AndroidEntryPoint
@AndroidEntryPoint
class NewApplicationsFragment : Fragment() {
private val viewModel: NewApplicationsViewModel by viewModels()
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
@@ -26,7 +29,10 @@ class NewApplicationsFragment : Fragment() {
)
setContent {
CpuInfoTheme {
ApplicationsScreen()
ApplicationsScreen(
viewModel = viewModel,
onAppClicked = viewModel::onApplicationClicked
)
}
}
}
@@ -2,12 +2,17 @@ package com.kgurgul.cpuinfo.features.applications
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.kgurgul.cpuinfo.R
import com.kgurgul.cpuinfo.domain.model.sortOrderFromBoolean
import com.kgurgul.cpuinfo.domain.observable.ApplicationsDataObservable
import com.kgurgul.cpuinfo.utils.wrappers.Result
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.receiveAsFlow
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch
import timber.log.Timber
import javax.inject.Inject
@HiltViewModel
@@ -18,6 +23,9 @@ class NewApplicationsViewModel @Inject constructor(
val applicationList = applicationsDataObservable.observe()
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), Result.Loading)
private val eventChannel = Channel<Event>(Channel.BUFFERED)
val eventsFlow = eventChannel.receiveAsFlow()
init {
refreshApplications()
}
@@ -30,4 +38,15 @@ class NewApplicationsViewModel @Inject constructor(
)
)
}
fun onApplicationClicked(packageName: String) {
viewModelScope.launch {
eventChannel.send(Event.ShowSnackbar(R.string.cpu_open))
}
Timber.d("App clicked: %s", packageName)
}
sealed class Event {
data class ShowSnackbar(val messageRes: Int) : Event()
}
}
@@ -47,10 +47,10 @@ class UtilsTest {
@Test
fun humanReadableByteCountFormatting() {
/* When */
val bytes = Utils.humanReadableByteCount(10)
val kilo = Utils.humanReadableByteCount(1500)
val mega = Utils.humanReadableByteCount(1500 * 1024)
val giga = Utils.humanReadableByteCount(1500 * 1024 * 1024)
val bytes = Utils.humanReadableByteCount(10L)
val kilo = Utils.humanReadableByteCount(1500L)
val mega = Utils.humanReadableByteCount(1500L * 1024L)
val giga = Utils.humanReadableByteCount(1500L * 1024L * 1024L)
val teta = Utils.humanReadableByteCount(1500L * 1024L * 1024L * 1024L)
val peta = Utils.humanReadableByteCount(1500L * 1024L * 1024L * 1024L * 1024L)
val e = Utils.humanReadableByteCount(1500L * 1024L * 1024L * 1024L * 1024L * 1024L)
@@ -68,10 +68,10 @@ class UtilsTest {
@Test
fun bytesToMegaFormatting() {
/* When */
val bytes = Utils.convertBytesToMega(10)
val kilo = Utils.convertBytesToMega(1500)
val mega = Utils.convertBytesToMega(1500 * 1024)
val giga = Utils.convertBytesToMega(1500 * 1024 * 1024)
val bytes = Utils.convertBytesToMega(10L)
val kilo = Utils.convertBytesToMega(1500L)
val mega = Utils.convertBytesToMega(1500L * 1024L)
val giga = Utils.convertBytesToMega(1500L * 1024L * 1024L)
/* Then */
assertEquals("0 MB", bytes)