Skip to content
Merged
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
1 change: 1 addition & 0 deletions FloconDesktop/composeApp/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ kotlin {
implementation(libs.androidx.lifecycle.viewmodel)
implementation(libs.androidx.lifecycle.runtime.compose)
implementation(libs.kotlinx.coroutines.core)
implementation(libs.zxing.core)

implementation(project.dependencies.platform(libs.koin.bom))
implementation(libs.koin.core)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,14 @@
<string name="tabs_close_left">Fermer les onglets à gauche</string>
<string name="tabs_close_others">Fermer les autres onglets</string>
<string name="tabs_close_right">Fermer les onglets à droite</string>
<string name="topbar_connect">Connecter un appareil</string>
<string name="connect_title">Connecter</string>
<string name="connect_scan">Scanner pour connecter</string>
<string name="connect_copy">Copier l\'adresse</string>
<string name="connect_pick_network">Choisissez le réseau sur lequel est votre téléphone.</string>
<string name="connect_hint">Même Wi-Fi que cet ordinateur, puis scannez, ou appelez Flocon.connect("%1$s")</string>
<string name="connect_empty">Aucune adresse du réseau local trouvée. Vérifiez que cet ordinateur est connecté à un réseau.</string>
<string name="connect_port">port %1$d</string>
<string name="topbar_open_folder">Ouvrir le dossier Flocon</string>
<string name="topbar_record">Enregistrer l’écran</string>
<string name="topbar_restart">Redémarrer l’app</string>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -400,6 +400,14 @@
<string name="tabs_close_left">Close Tabs to the Left</string>
<string name="tabs_close_others">Close Other Tabs</string>
<string name="tabs_close_right">Close Tabs to the Right</string>
<string name="topbar_connect">connect a device</string>
<string name="connect_title">Connect</string>
<string name="connect_scan">Scan to connect</string>
<string name="connect_copy">Copy address</string>
<string name="connect_pick_network">Pick the network your phone is on.</string>
<string name="connect_hint">Same Wi-Fi as this computer, then scan, or call Flocon.connect("%1$s")</string>
<string name="connect_empty">No local network address found. Check that this computer is connected to a network.</string>
<string name="connect_port">port %1$d</string>
<string name="topbar_open_folder">open flocon folder</string>
<string name="topbar_record">Record</string>
<string name="topbar_restart">restart</string>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ import androidx.compose.material.icons.outlined.ArrowCircleUp
import androidx.compose.material3.Icon
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
Expand All @@ -43,7 +47,9 @@ import io.github.openflocon.flocondesktop.app.ui.model.DeviceItemUiModel
import io.github.openflocon.flocondesktop.app.ui.model.DevicesStateUiModel
import io.github.openflocon.flocondesktop.app.ui.model.RecordVideoStateUiModel
import io.github.openflocon.flocondesktop.app.ui.view.topbar.actions.TopBarActions
import io.github.openflocon.flocondesktop.app.ui.view.topbar.actions.TopBarConnectButton
import io.github.openflocon.flocondesktop.app.version.VersionCheckerViewModel
import io.github.openflocon.flocondesktop.features.connect.view.ConnectDialog
import io.github.openflocon.library.designsystem.FloconTheme
import io.github.openflocon.library.designsystem.components.floconIsland
import org.jetbrains.compose.resources.painterResource
Expand All @@ -66,6 +72,11 @@ fun MainScreenTopBar(
updateChip: VersionCheckerViewModel.UpdateChipUiModel? = null,
onUpdateChipClicked: (VersionCheckerViewModel.UpdateChipUiModel) -> Unit = {},
) {
var showConnectDialog by remember { mutableStateOf(false) }
if (showConnectDialog) {
ConnectDialog(onDismissRequest = { showConnectDialog = false })
}

Row(
modifier = modifier
.floconIsland(
Expand Down Expand Up @@ -100,6 +111,7 @@ fun MainScreenTopBar(
onOpenFolderClicked = onOpenFolderClicked,
devicesState = devicesState,
)
TopBarConnectButton(onClicked = { showConnectDialog = true })
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package io.github.openflocon.flocondesktop.app.ui.view.topbar.actions

import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.padding
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.Laptop
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import flocondesktop.composeapp.generated.resources.Res
import flocondesktop.composeapp.generated.resources.topbar_connect
import io.github.openflocon.library.designsystem.FloconTheme
import org.jetbrains.compose.resources.stringResource

/** Standalone button, on purpose not part of the [TopBarActions] group. */
@Composable
internal fun TopBarConnectButton(
onClicked: () -> Unit,
modifier: Modifier = Modifier,
) {
val colors = FloconTheme.colors

Box(
modifier = modifier
.background(colors.bg100, FloconTheme.shapes.medium)
.border(1.dp, colors.line, FloconTheme.shapes.medium)
.padding(FloconTheme.spacing.extraSmall),
) {
TopBarButton(
active = false,
imageVector = Icons.Outlined.Laptop,
contentDescription = stringResource(Res.string.topbar_connect),
onClicked = onClicked,
isEnabled = true,
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import io.github.openflocon.flocondesktop.app.ui.settings.settingsModule
import io.github.openflocon.flocondesktop.features.accessibility.accessibilityModule
import io.github.openflocon.flocondesktop.features.adbcommander.adbCommanderModule
import io.github.openflocon.flocondesktop.features.analytics.analyticsModule
import io.github.openflocon.flocondesktop.features.connect.connectModule
import io.github.openflocon.flocondesktop.features.crashreporter.crashReporterModule
import io.github.openflocon.flocondesktop.features.dashboard.dashboardModule
import io.github.openflocon.flocondesktop.features.database.databaseModule
Expand All @@ -22,6 +23,7 @@ import org.koin.dsl.module
val featuresModule = module {
includes(
analyticsModule,
connectModule,
featureFlagsModule,
accessibilityModule,
databaseModule,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package io.github.openflocon.flocondesktop.features.connect

import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import io.github.openflocon.domain.Constant
import io.github.openflocon.domain.common.DispatcherProvider
import io.github.openflocon.domain.connect.usecase.GetLocalAddressesUseCase
import io.github.openflocon.domain.settings.usecase.ObserveMascotEnabledUseCase
import io.github.openflocon.flocondesktop.common.utils.stateInWhileSubscribed
import io.github.openflocon.flocondesktop.features.connect.model.ConnectUiState
import io.github.openflocon.flocondesktop.features.connect.model.LocalAddressUiModel
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.persistentListOf
import kotlinx.collections.immutable.toImmutableList
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext

class ConnectViewModel(
private val dispatcherProvider: DispatcherProvider,
private val getLocalAddressesUseCase: GetLocalAddressesUseCase,
observeMascotEnabledUseCase: ObserveMascotEnabledUseCase,
) : ViewModel() {

private val addresses = MutableStateFlow<ImmutableList<LocalAddressUiModel>>(persistentListOf())

val uiState: StateFlow<ConnectUiState> = combine(
addresses,
observeMascotEnabledUseCase(),
) { addresses, mascotEnabled ->
ConnectUiState(
addresses = addresses,
port = Constant.SERVER_WEBSOCKET_PORT,
mascotEnabled = mascotEnabled,
)
}.stateInWhileSubscribed(
ConnectUiState(
addresses = persistentListOf(),
port = Constant.SERVER_WEBSOCKET_PORT,
mascotEnabled = false,
),
)

/** The network can change while the app is open, so addresses are read again each time the dialog opens. */
fun refresh() {
viewModelScope.launch {
addresses.value = withContext(dispatcherProvider.viewModel) {
getLocalAddressesUseCase()
.map { LocalAddressUiModel(interfaceName = it.interfaceName, ip = it.ip) }
.toImmutableList()
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package io.github.openflocon.flocondesktop.features.connect

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

val connectModule = module {
viewModelOf(::ConnectViewModel)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package io.github.openflocon.flocondesktop.features.connect.model

import androidx.compose.runtime.Immutable
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.persistentListOf
import kotlinx.collections.immutable.toImmutableList

@Immutable
data class LocalAddressUiModel(
val interfaceName: String,
val ip: String,
)

@Immutable
data class ConnectUiState(
val addresses: ImmutableList<LocalAddressUiModel>,
val port: Int,
val mascotEnabled: Boolean,
)

fun previewConnectUiState() = ConnectUiState(
addresses = persistentListOf(
LocalAddressUiModel(interfaceName = "en0", ip = "192.168.1.20"),
LocalAddressUiModel(interfaceName = "en5", ip = "10.0.0.12"),
LocalAddressUiModel(interfaceName = "bridge0", ip = "172.20.10.4"),
),
port = 9023,
mascotEnabled = true,
)

fun previewSingleConnectUiState() = previewConnectUiState().let { it.copy(addresses = it.addresses.take(1).toImmutableList()) }
Loading
Loading