feat: [DATABASE] display previous queries (#333)

Co-authored-by: Florent Champigny <florent@bere.al>
This commit is contained in:
Florent CHAMPIGNY 2025-10-12 21:30:40 +02:00 committed by GitHub
parent 0a6c15099e
commit c38e95d8b0
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 81 additions and 17 deletions

View file

@ -7,6 +7,7 @@ import androidx.lifecycle.viewModelScope
import io.github.openflocon.domain.common.DispatcherProvider
import io.github.openflocon.domain.common.combines
import io.github.openflocon.domain.database.usecase.ExecuteDatabaseQueryUseCase
import io.github.openflocon.domain.database.usecase.ObserveLastSuccessQueriesUseCase
import io.github.openflocon.domain.database.usecase.favorite.GetFavoriteQueryByIdDatabaseUseCase
import io.github.openflocon.domain.database.usecase.favorite.SaveQueryAsFavoriteDatabaseUseCase
import io.github.openflocon.domain.feedback.FeedbackDisplayer
@ -14,7 +15,6 @@ import io.github.openflocon.flocondesktop.features.database.mapper.toUi
import io.github.openflocon.flocondesktop.features.database.model.DatabaseScreenState
import io.github.openflocon.flocondesktop.features.database.model.DatabaseTabAction
import io.github.openflocon.flocondesktop.features.database.model.QueryResultUiModel
import io.github.openflocon.flocondesktop.features.network.list.model.NetworkAction
import io.github.openflocon.library.designsystem.common.copyToClipboard
import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
@ -38,6 +38,7 @@ class DatabaseTabViewModel(
private val getFavoriteQueryUseCase: GetFavoriteQueryByIdDatabaseUseCase,
private val dispatcherProvider: DispatcherProvider,
private val feedbackDisplayer: FeedbackDisplayer,
private val observeLastSuccessQueriesUseCase: ObserveLastSuccessQueriesUseCase,
) : ViewModel() {
@Immutable
@ -49,6 +50,15 @@ class DatabaseTabViewModel(
var query = mutableStateOf("")
val lastQueries = observeLastSuccessQueriesUseCase(params.databaseId)
.map { it.filterNot { it.isBlank() } }
.flowOn(dispatcherProvider.data)
.stateIn(
viewModelScope,
started = SharingStarted.WhileSubscribed(5_000),
emptyList()
)
private val autoUpdateJob = AtomicReference<Job?>(null)
data class AutoUpdate(
@ -119,12 +129,21 @@ class DatabaseTabViewModel(
viewModelScope.launch(dispatcherProvider.viewModel) {
when (action) {
is DatabaseTabAction.ClearQuery -> clearQuery()
is DatabaseTabAction.ExecuteQuery -> executeQuery(query = query.value, editAutoUpdate = true)
is DatabaseTabAction.ExecuteQuery -> {
query.value = action.query
updateQuery(action.query)
executeQuery(
query = action.query,
editAutoUpdate = true
)
}
is DatabaseTabAction.UpdateAutoUpdate -> updateAutoUpdate(action.value)
DatabaseTabAction.Copy -> {
copyToClipboard(query.value)
feedbackDisplayer.displayMessage("copied")
}
DatabaseTabAction.Import -> {
// TODO
}

View file

@ -9,12 +9,15 @@ import androidx.compose.foundation.layout.aspectRatio
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.CopyAll
import androidx.compose.material.icons.filled.Delete
import androidx.compose.material.icons.filled.StarBorder
import androidx.compose.material.icons.outlined.History
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Text
import androidx.compose.material3.VerticalDivider
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
@ -27,14 +30,19 @@ import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.ColorFilter
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.unit.dp
import androidx.compose.ui.util.fastForEach
import io.github.openflocon.flocondesktop.features.database.model.DatabaseTabAction
import io.github.openflocon.library.designsystem.FloconTheme
import io.github.openflocon.library.designsystem.components.FloconExposedDropdownMenu
import io.github.openflocon.library.designsystem.components.FloconExposedDropdownMenuBox
@OptIn(ExperimentalMaterial3Api::class)
@Composable
internal fun DatabaseQueryToolbarView(
favoritesTitles: Set<String>,
onAction: (action: DatabaseTabAction) -> Unit,
isQueryEmpty: Boolean,
lastQueries: List<String>,
modifier: Modifier = Modifier,
) {
var showFavoriteDialog by remember { mutableStateOf(false) }
@ -62,6 +70,7 @@ internal fun DatabaseQueryToolbarView(
)
}
VerticalDivider(modifier = Modifier.padding(vertical = 6.dp, horizontal = 2.dp))
Box(
modifier = Modifier.clip(RoundedCornerShape(2.dp))
.clickable(enabled = isQueryEmpty.not()) {
@ -79,19 +88,47 @@ internal fun DatabaseQueryToolbarView(
colorFilter = ColorFilter.tint(FloconTheme.colorPalette.onPrimary)
)
}
VerticalDivider(modifier = Modifier.padding(vertical = 6.dp, horizontal = 2.dp))
Box(
modifier = Modifier.clip(RoundedCornerShape(2.dp)).clickable {
}.aspectRatio(1f, true),
contentAlignment = Alignment.Center
VerticalDivider(modifier = Modifier.padding(vertical = 6.dp, horizontal = 2.dp))
var isHistoryExpanded by remember { mutableStateOf(false) }
val displayOldQueries = isHistoryExpanded && lastQueries.isNotEmpty()
FloconExposedDropdownMenuBox(
expanded = displayOldQueries,
onExpandedChange = { isHistoryExpanded = false },
) {
Image(
Icons.Outlined.History,
contentDescription = null,
modifier = Modifier.size(20.dp),
colorFilter = ColorFilter.tint(FloconTheme.colorPalette.onPrimary)
)
Box(
modifier = Modifier.clip(RoundedCornerShape(2.dp))
.clickable(enabled = lastQueries.isNotEmpty()) {
isHistoryExpanded = true
}.aspectRatio(1f, true),
contentAlignment = Alignment.Center
) {
Image(
Icons.Outlined.History,
contentDescription = null,
modifier = Modifier.size(20.dp),
colorFilter = ColorFilter.tint(FloconTheme.colorPalette.onPrimary)
)
}
FloconExposedDropdownMenu(
expanded = displayOldQueries,
onDismissRequest = { isHistoryExpanded = false },
modifier = Modifier.width(300.dp)
) {
lastQueries.fastForEach { query ->
Text(
modifier = Modifier.padding(horizontal = 12.dp, vertical = 8.dp).clickable {
onAction(DatabaseTabAction.ExecuteQuery(query))
isHistoryExpanded = false
},
text = query,
style = FloconTheme.typography.bodySmall,
)
}
}
}
/* for another MR
@ -138,4 +175,4 @@ internal fun DatabaseQueryToolbarView(
}
)
}
}
}

View file

@ -40,6 +40,7 @@ fun DatabaseQueryView(
query: String,
autoUpdate: Boolean,
favoritesTitles: Set<String>,
lastQueries: List<String>,
updateQuery: (query: String) -> Unit,
onAction: (action: DatabaseTabAction) -> Unit,
modifier: Modifier = Modifier,
@ -54,6 +55,7 @@ fun DatabaseQueryView(
DatabaseQueryToolbarView(
favoritesTitles = favoritesTitles,
onAction = onAction,
lastQueries = lastQueries,
modifier = Modifier.fillMaxWidth(),
isQueryEmpty = query.isBlank(),
)
@ -148,7 +150,8 @@ private fun DatabaseQueryViewPreview() {
updateQuery = {},
autoUpdate = true,
onAction = {},
favoritesTitles = emptySet()
favoritesTitles = emptySet(),
lastQueries = emptyList(),
)
}
}

View file

@ -7,7 +7,6 @@ import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.lifecycle.compose.collectAsStateWithLifecycle
@ -44,12 +43,15 @@ fun DatabaseTabView(
val state: DatabaseScreenState by viewModel.state.collectAsStateWithLifecycle()
val autoUpdate by viewModel.isAutoUpdateEnabled.collectAsStateWithLifecycle()
val lastQueries by viewModel.lastQueries.collectAsStateWithLifecycle()
DatabaseTabViewContent(
query = viewModel.query.value,
autoUpdate = autoUpdate,
updateQuery = viewModel::updateQuery,
onAction = viewModel::onAction,
state = state,
lastQueries = lastQueries,
favoritesTitles = favoritesTitles,
)
}
@ -62,6 +64,7 @@ private fun DatabaseTabViewContent(
updateQuery: (String) -> Unit,
onAction: (action: DatabaseTabAction) -> Unit,
state: DatabaseScreenState,
lastQueries: List<String>,
) {
Column(
Modifier.fillMaxSize(),
@ -76,6 +79,7 @@ private fun DatabaseTabViewContent(
autoUpdate = autoUpdate,
onAction = onAction,
favoritesTitles = favoritesTitles,
lastQueries = lastQueries,
modifier = Modifier
.fillMaxWidth()
)

View file

@ -2,6 +2,7 @@ package io.github.openflocon.domain.database.usecase
import io.github.openflocon.domain.device.usecase.ObserveCurrentDeviceIdAndPackageNameUseCase
import io.github.openflocon.domain.database.repository.DatabaseRepository
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flowOf
@ -11,7 +12,7 @@ class ObserveLastSuccessQueriesUseCase(
) {
operator fun invoke(
databaseId: String,
) = observeCurrentDeviceIdAndPackageNameUseCase().flatMapLatest { model ->
): Flow<List<String>> = observeCurrentDeviceIdAndPackageNameUseCase().flatMapLatest { model ->
if (model == null) {
flowOf(emptyList())
} else {