Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions FloconAndroid/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
xmlns:tools="http://schemas.android.com/tools">

<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>

<application
android:allowBackup="true"
Expand Down
2 changes: 1 addition & 1 deletion FloconDesktop/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
plugins {
// this is necessary to avoid the plugins to be loaded multiple times
// in each subproject's classloader
alias(libs.plugins.composeHotReload) apply false
// alias(libs.plugins.composeHotReload) apply false
alias(libs.plugins.composeMultiplatform) apply false
alias(libs.plugins.composeCompiler) apply false
alias(libs.plugins.kotlinJvm) apply false
Expand Down
2 changes: 1 addition & 1 deletion FloconDesktop/composeApp/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ plugins {
alias(libs.plugins.kotlinMultiplatform)
alias(libs.plugins.composeMultiplatform)
alias(libs.plugins.composeCompiler)
alias(libs.plugins.composeHotReload)
// alias(libs.plugins.composeHotReload)
alias(libs.plugins.kotlinx.serialization)
alias(libs.plugins.ksp) // Add KSP plugin
alias(libs.plugins.room)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
@file:Suppress("unused", "UnusedVariable")

@file:OptIn(ExperimentalFoundationApi::class)

package io.github.openflocon.flocondesktop
Expand All @@ -20,6 +22,7 @@ import io.github.openflocon.flocondesktop.app.di.appModule
import io.github.openflocon.flocondesktop.common.di.commonModule
import io.github.openflocon.flocondesktop.common.ui.feedback.FeedbackDisplayerView
import io.github.openflocon.flocondesktop.core.di.coreModule
import io.github.openflocon.flocondesktop.device.deviceModule
import io.github.openflocon.flocondesktop.features.featuresModule
import io.github.openflocon.flocondesktop.main.di.mainModule
import io.github.openflocon.flocondesktop.main.ui.MainScreen
Expand All @@ -41,6 +44,7 @@ fun App() {
commonModule,
appModule,
coreModule,
deviceModule,
mainModule,
featuresModule,
domainModule,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package io.github.openflocon.flocondesktop.common.ui.window
import androidx.compose.runtime.Composable
import androidx.compose.ui.unit.DpSize
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.FrameWindowScope

interface FloconWindowState

Expand All @@ -18,5 +19,5 @@ expect fun FloconWindow(
state: FloconWindowState,
onCloseRequest: () -> Unit,
alwaysOnTop: Boolean = false,
content: @Composable () -> Unit
content: @Composable FrameWindowScope.() -> Unit,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package io.github.openflocon.flocondesktop.device

import org.koin.core.module.dsl.viewModelOf
import org.koin.dsl.module

internal val deviceModule = module {
viewModelOf(::DeviceViewModel)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package io.github.openflocon.flocondesktop.device

internal sealed interface DeviceAction {

data class SelectTab(val selected: DeviceTab) : DeviceAction

data object Refresh : DeviceAction

data class ChangePermission(val permission: String, val granted: Boolean) : DeviceAction

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
package io.github.openflocon.flocondesktop.device

import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
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.foundation.pager.HorizontalPager
import androidx.compose.foundation.pager.rememberPagerState
import androidx.compose.foundation.text.selection.SelectionContainer
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.Refresh
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import io.github.openflocon.domain.device.models.DeviceId
import io.github.openflocon.flocondesktop.common.ui.window.FloconWindow
import io.github.openflocon.flocondesktop.common.ui.window.createFloconWindowState
import io.github.openflocon.flocondesktop.device.models.DeviceUiState
import io.github.openflocon.flocondesktop.device.models.previewDeviceUiState
import io.github.openflocon.flocondesktop.device.pages.BatteryPage
import io.github.openflocon.flocondesktop.device.pages.CpuPage
import io.github.openflocon.flocondesktop.device.pages.InfoPage
import io.github.openflocon.flocondesktop.device.pages.MemoryPage
import io.github.openflocon.flocondesktop.device.pages.PermissionPage
import io.github.openflocon.library.designsystem.FloconTheme
import io.github.openflocon.library.designsystem.components.FloconHorizontalDivider
import io.github.openflocon.library.designsystem.components.FloconIconButton
import io.github.openflocon.library.designsystem.components.FloconScaffold
import io.github.openflocon.library.designsystem.components.FloconScrollableTabRow
import io.github.openflocon.library.designsystem.components.FloconSurface
import io.github.openflocon.library.designsystem.components.FloconTab
import org.jetbrains.compose.ui.tooling.preview.Preview
import org.koin.compose.viewmodel.koinViewModel
import org.koin.core.parameter.parametersOf

@Composable
internal fun DeviceScreen(
deviceId: DeviceId,
onCloseRequest: () -> Unit
) {
val viewModel = koinViewModel<DeviceViewModel> {
parametersOf(deviceId)
}
val uiState by viewModel.uiState.collectAsStateWithLifecycle()

Content(
uiState = uiState,
onCloseRequest = onCloseRequest,
onAction = viewModel::onAction
)
}

@Composable
private fun Content(
uiState: DeviceUiState,
onCloseRequest: () -> Unit,
onAction: (DeviceAction) -> Unit
) {
val tabs = remember { DeviceTab.entries }
val pagerState = rememberPagerState { tabs.size }

LaunchedEffect(uiState.contentState.selectedTab) {
pagerState.animateScrollToPage(uiState.contentState.selectedTab.ordinal)
}

FloconWindow(
title = "Device - ${uiState.infoState.model}",
onCloseRequest = onCloseRequest,
state = createFloconWindowState()
) {
// window.minimumSize = Dimension(500, 500) // TODO
FloconSurface(
modifier = Modifier.fillMaxSize()
) {
FloconScaffold(
topBar = {
Column(
modifier = Modifier.fillMaxWidth()
) {
Header(
uiState = uiState,
onAction = onAction
)
FloconScrollableTabRow(
selectedTabIndex = uiState.contentState.selectedTab.ordinal,
modifier = Modifier.fillMaxWidth()
) {
tabs.forEach { tab ->
FloconTab(
text = tab.title,
selected = uiState.contentState.selectedTab == tab,
onClick = { onAction(DeviceAction.SelectTab(tab)) },
selectedContentColor = FloconTheme.colorPalette.onSurface
)
}
}
FloconHorizontalDivider(
modifier = Modifier.fillMaxWidth(),
color = FloconTheme.colorPalette.primary
)
}
}
) {
HorizontalPager(
state = pagerState,
userScrollEnabled = false,
contentPadding = PaddingValues(8.dp),
pageSpacing = 8.dp,
modifier = Modifier
.fillMaxSize()
.padding(it)
) { index ->
when (tabs[index]) {
DeviceTab.INFORMATION -> InfoPage(uiState.infoState)
DeviceTab.BATTERY -> BatteryPage(uiState.batteryState)
DeviceTab.CPU -> CpuPage(uiState.cpuState, onAction)
DeviceTab.MEMORY -> MemoryPage(uiState.memoryState)
DeviceTab.PERMISSION -> PermissionPage(uiState.permissionState, onAction)
}
}
}
}
}
}

@Composable
private fun Header(
uiState: DeviceUiState,
onAction: (DeviceAction) -> Unit
) {
Row(
verticalAlignment = Alignment.CenterVertically
) {
Column(
modifier = Modifier
.fillMaxWidth()
.padding(16.dp)
.weight(1f)
) {
Text(
text = uiState.infoState.model,
style = FloconTheme.typography.headlineSmall
)
SelectionContainer {
Text(
text = uiState.infoState.serialNumber,
style = FloconTheme.typography.labelSmall
)
}
}
FloconIconButton(
imageVector = Icons.Outlined.Refresh,
onClick = { onAction(DeviceAction.Refresh) }
)
}
}

@Composable
@Preview
private fun Preview() {
FloconTheme {
Content(
uiState = previewDeviceUiState(),
onCloseRequest = {},
onAction = {}
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package io.github.openflocon.flocondesktop.device

enum class DeviceTab {
INFORMATION,
BATTERY,
CPU,
MEMORY,
PERMISSION
}

val DeviceTab.title: String
get() = when (this) {
DeviceTab.INFORMATION -> "Info"
DeviceTab.BATTERY -> "Battery"
DeviceTab.CPU -> "CPU"
DeviceTab.MEMORY -> "Memory"
DeviceTab.PERMISSION -> "Permission"
}
Loading