Pre-fill last hostname and add history to suggestions in connect screen (#1134)

This commit is contained in:
Max Rumpf authored and GitHub committed 2023-08-17 22:34:45 +02:00
1 parent 4de69d8845
commit c1d0561704
6 files changed
+83 -23

No files matched your search

@@ -62,6 +62,12 @@ class ApiClientController(
}
}
suspend fun loadPreviouslyUsedServers(): List<ServerEntity> = withContext(Dispatchers.IO) {
serverDao.getAllServers().filterNot { server ->
server.id == appPreferences.currentServerId
}
}
private fun configureApiClientServer(server: ServerEntity?) {
apiClient.baseUrl = server?.hostname
}
@@ -17,6 +17,9 @@ interface ServerDao {
@Query("SELECT * FROM $TABLE_NAME WHERE id = :id")
fun getServer(id: Long): ServerEntity?
@Query("SELECT * FROM $TABLE_NAME ORDER BY last_used_timestamp DESC")
fun getAllServers(): List<ServerEntity>
@Query("SELECT * FROM $TABLE_NAME WHERE hostname = :hostname")
fun getServerByHostname(hostname: String): ServerEntity?
}
@@ -13,10 +13,10 @@ import org.jellyfin.mobile.ui.screens.connect.ConnectScreen
import org.jellyfin.mobile.ui.utils.AppTheme
import org.jellyfin.mobile.utils.Constants
import org.jellyfin.mobile.utils.applyWindowInsetsAsMargins
import org.koin.androidx.viewmodel.ext.android.sharedViewModel
import org.koin.androidx.viewmodel.ext.android.activityViewModel
class ConnectFragment : Fragment() {
private val mainViewModel: MainViewModel by sharedViewModel()
private val mainViewModel: MainViewModel by activityViewModel()
private var _viewBinding: FragmentComposeBinding? = null
private val viewBinding get() = _viewBinding!!
private val composeView: ComposeView get() = viewBinding.composeView
@@ -53,31 +53,61 @@ import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.unit.dp
import kotlinx.coroutines.launch
import org.jellyfin.mobile.R
import org.jellyfin.mobile.app.ApiClientController
import org.jellyfin.mobile.setup.ConnectionHelper
import org.jellyfin.mobile.ui.state.CheckUrlState
import org.jellyfin.mobile.ui.state.ServerSelectionType
import org.jellyfin.mobile.ui.state.ServerSelectionMode
import org.jellyfin.mobile.ui.utils.CenterRow
import org.jellyfin.sdk.model.api.ServerDiscoveryInfo
import org.koin.androidx.compose.get
import org.koin.compose.koinInject
@OptIn(ExperimentalComposeUiApi::class)
@Suppress("LongMethod")
@Composable
fun ServerSelection(
showExternalConnectionError: Boolean,
connectionHelper: ConnectionHelper = get(),
apiClientController: ApiClientController = koinInject(),
connectionHelper: ConnectionHelper = koinInject(),
onConnected: suspend (String) -> Unit,
) {
val coroutineScope = rememberCoroutineScope()
val keyboardController = LocalSoftwareKeyboardController.current
var serverSelectionType by remember { mutableStateOf(ServerSelectionType.ADDRESS) }
var serverSelectionMode by remember { mutableStateOf(ServerSelectionMode.ADDRESS) }
var hostname by remember { mutableStateOf("") }
val serverSuggestions = remember { mutableStateListOf<ServerSuggestion>() }
var checkUrlState by remember<MutableState<CheckUrlState>> { mutableStateOf(CheckUrlState.Unchecked) }
var externalError by remember { mutableStateOf(showExternalConnectionError) }
val discoveredServers = remember { mutableStateListOf<ServerDiscoveryInfo>() }
// Prefill currently selected server if available
LaunchedEffect(Unit) {
val server = apiClientController.loadSavedServer()
if (server != null) {
hostname = server.hostname
}
}
LaunchedEffect(Unit) {
// Suggest saved servers
apiClientController.loadPreviouslyUsedServers().mapTo(serverSuggestions) { server ->
ServerSuggestion(
type = ServerSuggestion.Type.SAVED,
name = server.hostname,
address = server.hostname,
timestamp = server.lastUsedTimestamp,
)
}
// Prepend discovered servers to suggestions
connectionHelper.discoverServersAsFlow().collect { serverInfo ->
discoveredServers.add(serverInfo)
serverSuggestions.removeIf { existing -> existing.address == serverInfo.address }
serverSuggestions.add(
index = 0,
ServerSuggestion(
type = ServerSuggestion.Type.DISCOVERED,
name = serverInfo.name,
address = serverInfo.address,
timestamp = System.currentTimeMillis(),
),
)
}
}
@@ -99,9 +129,12 @@ fun ServerSelection(
modifier = Modifier.padding(bottom = 8.dp),
style = MaterialTheme.typography.h5,
)
Crossfade(serverSelectionType) { selectionType ->
Crossfade(
targetState = serverSelectionMode,
label = "Server selection mode",
) { selectionType ->
when (selectionType) {
ServerSelectionType.ADDRESS -> AddressSelection(
ServerSelectionMode.ADDRESS -> AddressSelection(
text = hostname,
errorText = when {
externalError -> stringResource(R.string.connection_error_cannot_connect)
@@ -116,20 +149,20 @@ fun ServerSelection(
onDiscoveryClick = {
externalError = false
keyboardController?.hide()
serverSelectionType = ServerSelectionType.AUTO_DISCOVERY
serverSelectionMode = ServerSelectionMode.AUTO_DISCOVERY
},
onSubmit = {
onSubmit()
},
)
ServerSelectionType.AUTO_DISCOVERY -> ServerDiscoveryList(
discoveredServers = discoveredServers,
ServerSelectionMode.AUTO_DISCOVERY -> ServerDiscoveryList(
serverSuggestions = serverSuggestions,
onGoBack = {
serverSelectionType = ServerSelectionType.ADDRESS
serverSelectionMode = ServerSelectionMode.ADDRESS
},
onSelectServer = { url ->
hostname = url
serverSelectionType = ServerSelectionType.ADDRESS
serverSelectionMode = ServerSelectionMode.ADDRESS
onSubmit()
},
)
@@ -257,7 +290,7 @@ private fun StyledTextButton(
@Stable
@Composable
private fun ServerDiscoveryList(
discoveredServers: SnapshotStateList<ServerDiscoveryInfo>,
serverSuggestions: SnapshotStateList<ServerSuggestion>,
onGoBack: () -> Unit,
onSelectServer: (String) -> Unit,
) {
@@ -290,9 +323,9 @@ private fun ServerDiscoveryList(
shape = MaterialTheme.shapes.medium,
),
) {
items(discoveredServers) { server ->
items(serverSuggestions) { server ->
ServerDiscoveryItem(
serverInfo = server,
serverSuggestion = server,
onClickServer = {
onSelectServer(server.address)
},
@@ -306,7 +339,7 @@ private fun ServerDiscoveryList(
@Stable
@Composable
private fun ServerDiscoveryItem(
serverInfo: ServerDiscoveryInfo,
serverSuggestion: ServerSuggestion,
onClickServer: () -> Unit,
) {
ListItem(
@@ -314,10 +347,10 @@ private fun ServerDiscoveryItem(
.clip(MaterialTheme.shapes.medium)
.clickable(onClick = onClickServer),
text = {
Text(text = serverInfo.name)
Text(text = serverSuggestion.name)
},
secondaryText = {
Text(text = serverInfo.address)
Text(text = serverSuggestion.address)
},
)
}
@@ -0,0 +1,18 @@
package org.jellyfin.mobile.ui.screens.connect
data class ServerSuggestion(
val type: Type,
val name: String,
val address: String,
/**
* A timestamp for this suggestion, used for sorting.
* For discovered servers, this should be the discovery time,
* for saved servers, this should be the last used time.
*/
val timestamp: Long,
) {
enum class Type {
DISCOVERED,
SAVED,
}
}
@@ -1,6 +1,6 @@
package org.jellyfin.mobile.ui.state
enum class ServerSelectionType {
enum class ServerSelectionMode {
ADDRESS,
AUTO_DISCOVERY,
}