a shabby viewmodel for addserver screen
This commit is contained in:
		@ -21,6 +21,7 @@ import net.blumia.pcmdroid.service.PlaybackService
 | 
				
			|||||||
import net.blumia.pcmdroid.ui.NavGraph
 | 
					import net.blumia.pcmdroid.ui.NavGraph
 | 
				
			||||||
import net.blumia.pcmdroid.ui.screen.main.MainPlayer
 | 
					import net.blumia.pcmdroid.ui.screen.main.MainPlayer
 | 
				
			||||||
import net.blumia.pcmdroid.ui.theme.PrivateCloudMusicTheme
 | 
					import net.blumia.pcmdroid.ui.theme.PrivateCloudMusicTheme
 | 
				
			||||||
 | 
					import net.blumia.pcmdroid.viewmodel.AddServerViewModel
 | 
				
			||||||
import java.lang.Exception
 | 
					import java.lang.Exception
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class MainActivity : ComponentActivity() {
 | 
					class MainActivity : ComponentActivity() {
 | 
				
			||||||
@ -29,7 +30,10 @@ class MainActivity : ComponentActivity() {
 | 
				
			|||||||
    private val browser: MediaBrowser?
 | 
					    private val browser: MediaBrowser?
 | 
				
			||||||
        get() = if (browserFuture.isDone) browserFuture.get() else null
 | 
					        get() = if (browserFuture.isDone) browserFuture.get() else null
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private val model: MainViewModel by viewModels {
 | 
					    private val mainViewModel: MainViewModel by viewModels {
 | 
				
			||||||
 | 
					        MainViewModelFactory((application as MainApplication).repository)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    private val addServerViewModel: AddServerViewModel by viewModels {
 | 
				
			||||||
        MainViewModelFactory((application as MainApplication).repository)
 | 
					        MainViewModelFactory((application as MainApplication).repository)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -39,7 +43,7 @@ class MainActivity : ComponentActivity() {
 | 
				
			|||||||
            PrivateCloudMusicTheme {
 | 
					            PrivateCloudMusicTheme {
 | 
				
			||||||
                // A surface container using the 'background' color from the theme
 | 
					                // A surface container using the 'background' color from the theme
 | 
				
			||||||
                Surface(color = MaterialTheme.colors.background) {
 | 
					                Surface(color = MaterialTheme.colors.background) {
 | 
				
			||||||
                    NavGraph(model, browser)
 | 
					                    NavGraph(mainViewModel, addServerViewModel, browser)
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
				
			|||||||
@ -14,6 +14,7 @@ import net.blumia.pcmdroid.model.Server
 | 
				
			|||||||
import net.blumia.pcmdroid.model.Song
 | 
					import net.blumia.pcmdroid.model.Song
 | 
				
			||||||
import net.blumia.pcmdroid.model.parseFromJsonString
 | 
					import net.blumia.pcmdroid.model.parseFromJsonString
 | 
				
			||||||
import net.blumia.pcmdroid.repository.ServerRepository
 | 
					import net.blumia.pcmdroid.repository.ServerRepository
 | 
				
			||||||
 | 
					import net.blumia.pcmdroid.viewmodel.AddServerViewModel
 | 
				
			||||||
import okhttp3.FormBody
 | 
					import okhttp3.FormBody
 | 
				
			||||||
import okhttp3.OkHttpClient
 | 
					import okhttp3.OkHttpClient
 | 
				
			||||||
import okhttp3.Request
 | 
					import okhttp3.Request
 | 
				
			||||||
@ -137,6 +138,9 @@ class MainViewModelFactory(private val repository: ServerRepository) : ViewModel
 | 
				
			|||||||
        if (modelClass.isAssignableFrom(MainViewModel::class.java)) {
 | 
					        if (modelClass.isAssignableFrom(MainViewModel::class.java)) {
 | 
				
			||||||
            @Suppress("UNCHECKED_CAST")
 | 
					            @Suppress("UNCHECKED_CAST")
 | 
				
			||||||
            return MainViewModel(repository) as T
 | 
					            return MainViewModel(repository) as T
 | 
				
			||||||
 | 
					        } else if (modelClass.isAssignableFrom(AddServerViewModel::class.java)) {
 | 
				
			||||||
 | 
					            @Suppress("UNCHECKED_CAST")
 | 
				
			||||||
 | 
					            return AddServerViewModel() as T
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        throw IllegalArgumentException("Unknown ViewModel class")
 | 
					        throw IllegalArgumentException("Unknown ViewModel class")
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
				
			|||||||
@ -1,8 +1,11 @@
 | 
				
			|||||||
package net.blumia.pcmdroid.model
 | 
					package net.blumia.pcmdroid.model
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import android.util.Log
 | 
				
			||||||
import androidx.lifecycle.LiveData
 | 
					import androidx.lifecycle.LiveData
 | 
				
			||||||
import androidx.room.*
 | 
					import androidx.room.*
 | 
				
			||||||
import kotlinx.coroutines.flow.Flow
 | 
					import kotlinx.coroutines.flow.Flow
 | 
				
			||||||
 | 
					import org.json.JSONException
 | 
				
			||||||
 | 
					import org.json.JSONObject
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@Entity(tableName = "server_table")
 | 
					@Entity(tableName = "server_table")
 | 
				
			||||||
data class Server (
 | 
					data class Server (
 | 
				
			||||||
@ -52,3 +55,24 @@ interface ServerDao {
 | 
				
			|||||||
    @Query("DELETE FROM server_table")
 | 
					    @Query("DELETE FROM server_table")
 | 
				
			||||||
    suspend fun deleteAll()
 | 
					    suspend fun deleteAll()
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fun parseServerFromJsonString(jsonString: String): Map<String, String> {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    val kv = mutableMapOf<String, String>()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    try {
 | 
				
			||||||
 | 
					        val jsonObj = JSONObject(jsonString)
 | 
				
			||||||
 | 
					        val result = jsonObj.getJSONObject("result")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        kv["serverName"] = result.getString("serverName")
 | 
				
			||||||
 | 
					        kv["serverShortName"] = result.getString("serverShortName")
 | 
				
			||||||
 | 
					        kv["baseFolderNameHint"] = result.getString("baseFolderNameHint")
 | 
				
			||||||
 | 
					        kv["preferredFormatsHint"] = result.getString("preferredFormatsHint")
 | 
				
			||||||
 | 
					        kv["mediaRootUrl"] = result.getString("mediaRootUrl")
 | 
				
			||||||
 | 
					    } catch (e: JSONException) {
 | 
				
			||||||
 | 
					        e.printStackTrace()
 | 
				
			||||||
 | 
					        Log.d("vvv", jsonString)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return kv;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -1,6 +1,7 @@
 | 
				
			|||||||
package net.blumia.pcmdroid.ui
 | 
					package net.blumia.pcmdroid.ui
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import android.util.Log
 | 
					import android.util.Log
 | 
				
			||||||
 | 
					import androidx.activity.viewModels
 | 
				
			||||||
import androidx.compose.runtime.Composable
 | 
					import androidx.compose.runtime.Composable
 | 
				
			||||||
import androidx.compose.runtime.getValue
 | 
					import androidx.compose.runtime.getValue
 | 
				
			||||||
import androidx.compose.runtime.livedata.observeAsState
 | 
					import androidx.compose.runtime.livedata.observeAsState
 | 
				
			||||||
@ -13,7 +14,9 @@ import androidx.navigation.compose.NavHost
 | 
				
			|||||||
import androidx.navigation.compose.composable
 | 
					import androidx.navigation.compose.composable
 | 
				
			||||||
import androidx.navigation.compose.rememberNavController
 | 
					import androidx.navigation.compose.rememberNavController
 | 
				
			||||||
import androidx.navigation.navArgument
 | 
					import androidx.navigation.navArgument
 | 
				
			||||||
 | 
					import net.blumia.pcmdroid.MainApplication
 | 
				
			||||||
import net.blumia.pcmdroid.MainViewModel
 | 
					import net.blumia.pcmdroid.MainViewModel
 | 
				
			||||||
 | 
					import net.blumia.pcmdroid.MainViewModelFactory
 | 
				
			||||||
import net.blumia.pcmdroid.model.Folder
 | 
					import net.blumia.pcmdroid.model.Folder
 | 
				
			||||||
import net.blumia.pcmdroid.model.Server
 | 
					import net.blumia.pcmdroid.model.Server
 | 
				
			||||||
import net.blumia.pcmdroid.model.Song
 | 
					import net.blumia.pcmdroid.model.Song
 | 
				
			||||||
@ -21,6 +24,7 @@ import net.blumia.pcmdroid.ui.screen.addserver.AddServerScreen
 | 
				
			|||||||
import net.blumia.pcmdroid.ui.screen.editserver.EditServerScreen
 | 
					import net.blumia.pcmdroid.ui.screen.editserver.EditServerScreen
 | 
				
			||||||
import net.blumia.pcmdroid.ui.screen.main.MainPlayer
 | 
					import net.blumia.pcmdroid.ui.screen.main.MainPlayer
 | 
				
			||||||
import net.blumia.pcmdroid.ui.screen.settings.SettingsScreen
 | 
					import net.blumia.pcmdroid.ui.screen.settings.SettingsScreen
 | 
				
			||||||
 | 
					import net.blumia.pcmdroid.viewmodel.AddServerViewModel
 | 
				
			||||||
 | 
					
 | 
				
			||||||
object MainDestinations {
 | 
					object MainDestinations {
 | 
				
			||||||
    const val MAIN_ROUTE = "main"
 | 
					    const val MAIN_ROUTE = "main"
 | 
				
			||||||
@ -31,7 +35,8 @@ object MainDestinations {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
@Composable
 | 
					@Composable
 | 
				
			||||||
fun NavGraph(
 | 
					fun NavGraph(
 | 
				
			||||||
    viewModel: MainViewModel,
 | 
					    mainViewModel: MainViewModel,
 | 
				
			||||||
 | 
					    addServerViewModel: AddServerViewModel,
 | 
				
			||||||
    browser: MediaBrowser?,
 | 
					    browser: MediaBrowser?,
 | 
				
			||||||
    navController: NavHostController = rememberNavController(),
 | 
					    navController: NavHostController = rememberNavController(),
 | 
				
			||||||
    startDestination: String = MainDestinations.MAIN_ROUTE,
 | 
					    startDestination: String = MainDestinations.MAIN_ROUTE,
 | 
				
			||||||
@ -42,12 +47,12 @@ fun NavGraph(
 | 
				
			|||||||
    ) {
 | 
					    ) {
 | 
				
			||||||
        composable(MainDestinations.MAIN_ROUTE) {
 | 
					        composable(MainDestinations.MAIN_ROUTE) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            val curServer: Server? by viewModel.currentServer.observeAsState(initial = null)
 | 
					            val curServer: Server? by mainViewModel.currentServer.observeAsState(initial = null)
 | 
				
			||||||
            val servers: List<Server> by viewModel.servers.observeAsState(initial = listOf())
 | 
					            val servers: List<Server> by mainViewModel.servers.observeAsState(initial = listOf())
 | 
				
			||||||
            val drawerFolders: List<Folder> by viewModel.drawerFolders.observeAsState(initial = listOf())
 | 
					            val drawerFolders: List<Folder> by mainViewModel.drawerFolders.observeAsState(initial = listOf())
 | 
				
			||||||
            val curFolder: Folder? by viewModel.currentFolder.observeAsState(initial = null)
 | 
					            val curFolder: Folder? by mainViewModel.currentFolder.observeAsState(initial = null)
 | 
				
			||||||
            val folders: List<Folder> by viewModel.folders.observeAsState(listOf())
 | 
					            val folders: List<Folder> by mainViewModel.folders.observeAsState(listOf())
 | 
				
			||||||
            val songs: List<Song> by viewModel.songs.observeAsState(listOf())
 | 
					            val songs: List<Song> by mainViewModel.songs.observeAsState(listOf())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            MainPlayer(
 | 
					            MainPlayer(
 | 
				
			||||||
                currentServer = curServer,
 | 
					                currentServer = curServer,
 | 
				
			||||||
@ -60,10 +65,10 @@ fun NavGraph(
 | 
				
			|||||||
                    navController.navigate(MainDestinations.ADD_SERVER_ROUTE)
 | 
					                    navController.navigate(MainDestinations.ADD_SERVER_ROUTE)
 | 
				
			||||||
                },
 | 
					                },
 | 
				
			||||||
                onServerItemIconClicked = { server ->
 | 
					                onServerItemIconClicked = { server ->
 | 
				
			||||||
                    viewModel.fetchServer(server)
 | 
					                    mainViewModel.fetchServer(server)
 | 
				
			||||||
                },
 | 
					                },
 | 
				
			||||||
                onFolderItemClicked = { folder ->
 | 
					                onFolderItemClicked = { folder ->
 | 
				
			||||||
                    viewModel.fetchFolder(folder)
 | 
					                    mainViewModel.fetchFolder(folder)
 | 
				
			||||||
                },
 | 
					                },
 | 
				
			||||||
                onSongItemClicked = { song, songs ->
 | 
					                onSongItemClicked = { song, songs ->
 | 
				
			||||||
                    Log.d("vvv", song.url + browser.toString())
 | 
					                    Log.d("vvv", song.url + browser.toString())
 | 
				
			||||||
@ -79,7 +84,7 @@ fun NavGraph(
 | 
				
			|||||||
                    navController.navigate( "${MainDestinations.EDIT_SERVER_ROUTE}?id=${server.serverId}")
 | 
					                    navController.navigate( "${MainDestinations.EDIT_SERVER_ROUTE}?id=${server.serverId}")
 | 
				
			||||||
                },
 | 
					                },
 | 
				
			||||||
                onDeleteServerActionTriggered = { server ->
 | 
					                onDeleteServerActionTriggered = { server ->
 | 
				
			||||||
                    viewModel.deleteServer(server)
 | 
					                    mainViewModel.deleteServer(server)
 | 
				
			||||||
                },
 | 
					                },
 | 
				
			||||||
                settingsActionTriggered = {
 | 
					                settingsActionTriggered = {
 | 
				
			||||||
                    navController.navigate(MainDestinations.SETTINGS_ROUTE)
 | 
					                    navController.navigate(MainDestinations.SETTINGS_ROUTE)
 | 
				
			||||||
@ -93,9 +98,10 @@ fun NavGraph(
 | 
				
			|||||||
                    navController.navigateUp()
 | 
					                    navController.navigateUp()
 | 
				
			||||||
                },
 | 
					                },
 | 
				
			||||||
                onSubmitServerTriggered = { srv ->
 | 
					                onSubmitServerTriggered = { srv ->
 | 
				
			||||||
                    viewModel.addServer(srv)
 | 
					                    mainViewModel.addServer(srv)
 | 
				
			||||||
                    navController.navigateUp()
 | 
					                    navController.navigateUp()
 | 
				
			||||||
                }
 | 
					                },
 | 
				
			||||||
 | 
					                viewModel = addServerViewModel,
 | 
				
			||||||
            )
 | 
					            )
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -111,7 +117,7 @@ fun NavGraph(
 | 
				
			|||||||
            "${MainDestinations.EDIT_SERVER_ROUTE}?id={id}",
 | 
					            "${MainDestinations.EDIT_SERVER_ROUTE}?id={id}",
 | 
				
			||||||
            arguments = listOf(navArgument("id") { type = NavType.LongType })
 | 
					            arguments = listOf(navArgument("id") { type = NavType.LongType })
 | 
				
			||||||
        ) {
 | 
					        ) {
 | 
				
			||||||
            val srv = viewModel.getServerById(it.arguments?.getLong("id")!!)
 | 
					            val srv = mainViewModel.getServerById(it.arguments?.getLong("id")!!)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            EditServerScreen(
 | 
					            EditServerScreen(
 | 
				
			||||||
                server = srv,
 | 
					                server = srv,
 | 
				
			||||||
@ -119,7 +125,7 @@ fun NavGraph(
 | 
				
			|||||||
                    navController.navigateUp()
 | 
					                    navController.navigateUp()
 | 
				
			||||||
                },
 | 
					                },
 | 
				
			||||||
                onSaveButtonTriggered = { server ->
 | 
					                onSaveButtonTriggered = { server ->
 | 
				
			||||||
                    viewModel.editServer(server)
 | 
					                    mainViewModel.editServer(server)
 | 
				
			||||||
                    navController.navigateUp()
 | 
					                    navController.navigateUp()
 | 
				
			||||||
                },
 | 
					                },
 | 
				
			||||||
            )
 | 
					            )
 | 
				
			||||||
 | 
				
			|||||||
@ -11,6 +11,7 @@ import androidx.compose.material.icons.filled.AddCircle
 | 
				
			|||||||
import androidx.compose.material.icons.filled.Close
 | 
					import androidx.compose.material.icons.filled.Close
 | 
				
			||||||
import androidx.compose.material.icons.rounded.AddCircle
 | 
					import androidx.compose.material.icons.rounded.AddCircle
 | 
				
			||||||
import androidx.compose.runtime.*
 | 
					import androidx.compose.runtime.*
 | 
				
			||||||
 | 
					import androidx.compose.runtime.livedata.observeAsState
 | 
				
			||||||
import androidx.compose.runtime.saveable.rememberSaveable
 | 
					import androidx.compose.runtime.saveable.rememberSaveable
 | 
				
			||||||
import androidx.compose.ui.Alignment
 | 
					import androidx.compose.ui.Alignment
 | 
				
			||||||
import androidx.compose.ui.Modifier
 | 
					import androidx.compose.ui.Modifier
 | 
				
			||||||
@ -20,11 +21,11 @@ import androidx.compose.ui.text.style.TextAlign
 | 
				
			|||||||
import androidx.compose.ui.tooling.preview.Preview
 | 
					import androidx.compose.ui.tooling.preview.Preview
 | 
				
			||||||
import androidx.compose.ui.unit.dp
 | 
					import androidx.compose.ui.unit.dp
 | 
				
			||||||
import net.blumia.pcmdroid.model.Server
 | 
					import net.blumia.pcmdroid.model.Server
 | 
				
			||||||
 | 
					import net.blumia.pcmdroid.viewmodel.AddServerViewModel
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@Composable
 | 
					@Composable
 | 
				
			||||||
fun StepEnterApiUrl(
 | 
					fun StepEnterApiUrl(
 | 
				
			||||||
    urlStr: String = "",
 | 
					    viewModel: AddServerViewModel = AddServerViewModel(),
 | 
				
			||||||
    onUrlStrChange: (String) -> Unit = {},
 | 
					 | 
				
			||||||
) {
 | 
					) {
 | 
				
			||||||
    Column(
 | 
					    Column(
 | 
				
			||||||
        modifier = Modifier.fillMaxSize(),
 | 
					        modifier = Modifier.fillMaxSize(),
 | 
				
			||||||
@ -51,6 +52,9 @@ fun StepEnterApiUrl(
 | 
				
			|||||||
            textAlign = TextAlign.Center,
 | 
					            textAlign = TextAlign.Center,
 | 
				
			||||||
            style = MaterialTheme.typography.subtitle2,
 | 
					            style = MaterialTheme.typography.subtitle2,
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        val urlStr: String by viewModel.apiUrl.observeAsState("")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        OutlinedTextField(
 | 
					        OutlinedTextField(
 | 
				
			||||||
            modifier = Modifier
 | 
					            modifier = Modifier
 | 
				
			||||||
                .fillMaxWidth()
 | 
					                .fillMaxWidth()
 | 
				
			||||||
@ -58,8 +62,9 @@ fun StepEnterApiUrl(
 | 
				
			|||||||
            keyboardOptions = KeyboardOptions(
 | 
					            keyboardOptions = KeyboardOptions(
 | 
				
			||||||
                keyboardType = KeyboardType.Uri,
 | 
					                keyboardType = KeyboardType.Uri,
 | 
				
			||||||
            ),
 | 
					            ),
 | 
				
			||||||
 | 
					            singleLine = true,
 | 
				
			||||||
            value = urlStr,
 | 
					            value = urlStr,
 | 
				
			||||||
            onValueChange = onUrlStrChange,
 | 
					            onValueChange = viewModel::setApiUrl,
 | 
				
			||||||
            label = { Text("Server API Url") },
 | 
					            label = { Text("Server API Url") },
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -67,16 +72,7 @@ fun StepEnterApiUrl(
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
@Composable
 | 
					@Composable
 | 
				
			||||||
fun StepOtherDetail(
 | 
					fun StepOtherDetail(
 | 
				
			||||||
    nameStr: String = "",
 | 
					    viewModel: AddServerViewModel = AddServerViewModel(),
 | 
				
			||||||
    onNameStrChange: (String) -> Unit = {},
 | 
					 | 
				
			||||||
    shortNameStr: String = "",
 | 
					 | 
				
			||||||
    onShortNameStrChange: (String) -> Unit = {},
 | 
					 | 
				
			||||||
    baseFolderNameStr: String = "",
 | 
					 | 
				
			||||||
    onBaseFolderNameStrChange: (String) -> Unit = {},
 | 
					 | 
				
			||||||
    mediaBaseUrlStr: String = "",
 | 
					 | 
				
			||||||
    mediaBaseUrlStrChange: (String) -> Unit = {},
 | 
					 | 
				
			||||||
    preferredFormatsStr: String = "",
 | 
					 | 
				
			||||||
    preferredFormatsStrChange: (String) -> Unit = {},
 | 
					 | 
				
			||||||
) {
 | 
					) {
 | 
				
			||||||
    Column(
 | 
					    Column(
 | 
				
			||||||
        modifier = Modifier
 | 
					        modifier = Modifier
 | 
				
			||||||
@ -84,12 +80,19 @@ fun StepOtherDetail(
 | 
				
			|||||||
            .verticalScroll(rememberScrollState()),
 | 
					            .verticalScroll(rememberScrollState()),
 | 
				
			||||||
        horizontalAlignment = Alignment.CenterHorizontally,
 | 
					        horizontalAlignment = Alignment.CenterHorizontally,
 | 
				
			||||||
    ) {
 | 
					    ) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        val nameStr: String by viewModel.nameStr.observeAsState("")
 | 
				
			||||||
 | 
					        val shortNameStr: String by viewModel.shortNameStr.observeAsState("")
 | 
				
			||||||
 | 
					        val baseFolderNameStr: String by viewModel.baseFolderNameStr.observeAsState("")
 | 
				
			||||||
 | 
					        val mediaBaseUrlStr: String by viewModel.mediaBaseUrlStr.observeAsState("")
 | 
				
			||||||
 | 
					        val preferredFormatsStr: String by viewModel.preferredFormatsStr.observeAsState("")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        OutlinedTextField(
 | 
					        OutlinedTextField(
 | 
				
			||||||
            modifier = Modifier
 | 
					            modifier = Modifier
 | 
				
			||||||
                .fillMaxWidth()
 | 
					                .fillMaxWidth()
 | 
				
			||||||
                .padding(vertical = 10.dp),
 | 
					                .padding(vertical = 10.dp),
 | 
				
			||||||
            value = shortNameStr,
 | 
					            value = shortNameStr,
 | 
				
			||||||
            onValueChange = onShortNameStrChange,
 | 
					            onValueChange = viewModel::setShortNameStr,
 | 
				
			||||||
            label = { Text("Server short name") },
 | 
					            label = { Text("Server short name") },
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -98,7 +101,7 @@ fun StepOtherDetail(
 | 
				
			|||||||
                .fillMaxWidth()
 | 
					                .fillMaxWidth()
 | 
				
			||||||
                .padding(vertical = 10.dp),
 | 
					                .padding(vertical = 10.dp),
 | 
				
			||||||
            value = nameStr,
 | 
					            value = nameStr,
 | 
				
			||||||
            onValueChange = onNameStrChange,
 | 
					            onValueChange = viewModel::setNameStr,
 | 
				
			||||||
            label = { Text("Server name") },
 | 
					            label = { Text("Server name") },
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -107,7 +110,7 @@ fun StepOtherDetail(
 | 
				
			|||||||
                .fillMaxWidth()
 | 
					                .fillMaxWidth()
 | 
				
			||||||
                .padding(vertical = 10.dp),
 | 
					                .padding(vertical = 10.dp),
 | 
				
			||||||
            value = baseFolderNameStr,
 | 
					            value = baseFolderNameStr,
 | 
				
			||||||
            onValueChange = onBaseFolderNameStrChange,
 | 
					            onValueChange = viewModel::setBaseFolderNameStr,
 | 
				
			||||||
            label = { Text("Base folder name") },
 | 
					            label = { Text("Base folder name") },
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -116,7 +119,7 @@ fun StepOtherDetail(
 | 
				
			|||||||
                .fillMaxWidth()
 | 
					                .fillMaxWidth()
 | 
				
			||||||
                .padding(vertical = 10.dp),
 | 
					                .padding(vertical = 10.dp),
 | 
				
			||||||
            value = mediaBaseUrlStr,
 | 
					            value = mediaBaseUrlStr,
 | 
				
			||||||
            onValueChange = mediaBaseUrlStrChange,
 | 
					            onValueChange = viewModel::setMediaBaseUrlStr,
 | 
				
			||||||
            label = { Text("Media base url") },
 | 
					            label = { Text("Media base url") },
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -125,7 +128,7 @@ fun StepOtherDetail(
 | 
				
			|||||||
                .fillMaxWidth()
 | 
					                .fillMaxWidth()
 | 
				
			||||||
                .padding(vertical = 10.dp),
 | 
					                .padding(vertical = 10.dp),
 | 
				
			||||||
            value = preferredFormatsStr,
 | 
					            value = preferredFormatsStr,
 | 
				
			||||||
            onValueChange = preferredFormatsStrChange,
 | 
					            onValueChange = viewModel::setPreferredFormatsStr,
 | 
				
			||||||
            label = { Text("Preferred formats") },
 | 
					            label = { Text("Preferred formats") },
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -136,6 +139,7 @@ fun StepOtherDetail(
 | 
				
			|||||||
fun AddServerScreen(
 | 
					fun AddServerScreen(
 | 
				
			||||||
    onCloseActionTriggered: () -> Unit = {},
 | 
					    onCloseActionTriggered: () -> Unit = {},
 | 
				
			||||||
    onSubmitServerTriggered: (Server) -> Unit = {},
 | 
					    onSubmitServerTriggered: (Server) -> Unit = {},
 | 
				
			||||||
 | 
					    viewModel: AddServerViewModel = AddServerViewModel(),
 | 
				
			||||||
) {
 | 
					) {
 | 
				
			||||||
    var stepState by remember { mutableStateOf(0) }
 | 
					    var stepState by remember { mutableStateOf(0) }
 | 
				
			||||||
    val finalStep = 1
 | 
					    val finalStep = 1
 | 
				
			||||||
@ -172,13 +176,6 @@ fun AddServerScreen(
 | 
				
			|||||||
                .padding(20.dp),
 | 
					                .padding(20.dp),
 | 
				
			||||||
            horizontalAlignment = Alignment.CenterHorizontally
 | 
					            horizontalAlignment = Alignment.CenterHorizontally
 | 
				
			||||||
        ) {
 | 
					        ) {
 | 
				
			||||||
            var urlStr by rememberSaveable { mutableStateOf("") }
 | 
					 | 
				
			||||||
            var nameStr by rememberSaveable { mutableStateOf("") }
 | 
					 | 
				
			||||||
            var shortNameStr by rememberSaveable { mutableStateOf("") }
 | 
					 | 
				
			||||||
            var baseFolderNameStr by rememberSaveable { mutableStateOf("") }
 | 
					 | 
				
			||||||
            var mediaBaseUrlStr by rememberSaveable { mutableStateOf("") }
 | 
					 | 
				
			||||||
            var preferredFormatsStr by rememberSaveable { mutableStateOf("") }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            Column(
 | 
					            Column(
 | 
				
			||||||
                modifier = Modifier
 | 
					                modifier = Modifier
 | 
				
			||||||
                    .fillMaxWidth()
 | 
					                    .fillMaxWidth()
 | 
				
			||||||
@ -188,34 +185,12 @@ fun AddServerScreen(
 | 
				
			|||||||
                when (stepState) {
 | 
					                when (stepState) {
 | 
				
			||||||
                    0 -> {
 | 
					                    0 -> {
 | 
				
			||||||
                        StepEnterApiUrl(
 | 
					                        StepEnterApiUrl(
 | 
				
			||||||
                            urlStr,
 | 
					                            viewModel,
 | 
				
			||||||
                            onUrlStrChange = { value ->
 | 
					 | 
				
			||||||
                                urlStr = value
 | 
					 | 
				
			||||||
                            },
 | 
					 | 
				
			||||||
                        )
 | 
					                        )
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                    1 -> {
 | 
					                    1 -> {
 | 
				
			||||||
                        StepOtherDetail(
 | 
					                        StepOtherDetail(
 | 
				
			||||||
                            nameStr,
 | 
					                            viewModel = viewModel,
 | 
				
			||||||
                            onNameStrChange = { value ->
 | 
					 | 
				
			||||||
                                nameStr = value
 | 
					 | 
				
			||||||
                            },
 | 
					 | 
				
			||||||
                            shortNameStr,
 | 
					 | 
				
			||||||
                            onShortNameStrChange = { value ->
 | 
					 | 
				
			||||||
                                shortNameStr = value
 | 
					 | 
				
			||||||
                            },
 | 
					 | 
				
			||||||
                            baseFolderNameStr,
 | 
					 | 
				
			||||||
                            onBaseFolderNameStrChange = { value ->
 | 
					 | 
				
			||||||
                                baseFolderNameStr = value
 | 
					 | 
				
			||||||
                            },
 | 
					 | 
				
			||||||
                            mediaBaseUrlStr,
 | 
					 | 
				
			||||||
                            mediaBaseUrlStrChange = { value ->
 | 
					 | 
				
			||||||
                                mediaBaseUrlStr = value
 | 
					 | 
				
			||||||
                            },
 | 
					 | 
				
			||||||
                            preferredFormatsStr,
 | 
					 | 
				
			||||||
                            preferredFormatsStrChange = { value ->
 | 
					 | 
				
			||||||
                                preferredFormatsStr = value
 | 
					 | 
				
			||||||
                            },
 | 
					 | 
				
			||||||
                        )
 | 
					                        )
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
@ -236,15 +211,16 @@ fun AddServerScreen(
 | 
				
			|||||||
                Button(
 | 
					                Button(
 | 
				
			||||||
                    onClick = {
 | 
					                    onClick = {
 | 
				
			||||||
                        if (stepState != finalStep) {
 | 
					                        if (stepState != finalStep) {
 | 
				
			||||||
 | 
					                            viewModel.fetchContentFromApiUrl()
 | 
				
			||||||
                            onNextStepButtonTriggered()
 | 
					                            onNextStepButtonTriggered()
 | 
				
			||||||
                        } else {
 | 
					                        } else {
 | 
				
			||||||
                            val srv = Server(
 | 
					                            val srv = Server(
 | 
				
			||||||
                                url = urlStr,
 | 
					                                url = viewModel.apiUrl.value!!,
 | 
				
			||||||
                                name = nameStr,
 | 
					                                name = viewModel.nameStr.value!!,
 | 
				
			||||||
                                shortName = shortNameStr,
 | 
					                                shortName = viewModel.shortNameStr.value!!,
 | 
				
			||||||
                                baseFolderName = baseFolderNameStr,
 | 
					                                baseFolderName = viewModel.baseFolderNameStr.value!!,
 | 
				
			||||||
                                mediaBaseUrl = mediaBaseUrlStr,
 | 
					                                mediaBaseUrl = viewModel.mediaBaseUrlStr.value!!,
 | 
				
			||||||
                                preferredFormats = preferredFormatsStr,
 | 
					                                preferredFormats = viewModel.preferredFormatsStr.value!!,
 | 
				
			||||||
                            )
 | 
					                            )
 | 
				
			||||||
                            onSubmitServerTriggered(srv)
 | 
					                            onSubmitServerTriggered(srv)
 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
 | 
				
			|||||||
@ -0,0 +1,97 @@
 | 
				
			|||||||
 | 
					package net.blumia.pcmdroid.viewmodel
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import android.util.Log
 | 
				
			||||||
 | 
					import android.webkit.URLUtil
 | 
				
			||||||
 | 
					import androidx.lifecycle.LiveData
 | 
				
			||||||
 | 
					import androidx.lifecycle.MutableLiveData
 | 
				
			||||||
 | 
					import androidx.lifecycle.ViewModel
 | 
				
			||||||
 | 
					import androidx.lifecycle.viewModelScope
 | 
				
			||||||
 | 
					import kotlinx.coroutines.Dispatchers
 | 
				
			||||||
 | 
					import kotlinx.coroutines.launch
 | 
				
			||||||
 | 
					import net.blumia.pcmdroid.model.Server
 | 
				
			||||||
 | 
					import net.blumia.pcmdroid.model.parseFromJsonString
 | 
				
			||||||
 | 
					import net.blumia.pcmdroid.model.parseServerFromJsonString
 | 
				
			||||||
 | 
					import okhttp3.FormBody
 | 
				
			||||||
 | 
					import okhttp3.OkHttpClient
 | 
				
			||||||
 | 
					import okhttp3.Request
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class AddServerViewModel : ViewModel() {
 | 
				
			||||||
 | 
					//    private val httpClient: OkHttpClient = OkHttpClient()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private val _apiUrl: MutableLiveData<String> = MutableLiveData("")
 | 
				
			||||||
 | 
					    val apiUrl: LiveData<String> = _apiUrl
 | 
				
			||||||
 | 
					    fun setApiUrl(url: String) {
 | 
				
			||||||
 | 
					        // FIXME: do we really need to use postValue here?
 | 
				
			||||||
 | 
					        //        will the setter for the LiveData object trigger observer?
 | 
				
			||||||
 | 
					        _apiUrl.postValue(url)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private val _nameStr: MutableLiveData<String> = MutableLiveData("")
 | 
				
			||||||
 | 
					    val nameStr: LiveData<String> = _nameStr
 | 
				
			||||||
 | 
					    fun setNameStr(name: String) {
 | 
				
			||||||
 | 
					        _nameStr.postValue(name)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private val _shortNameStr: MutableLiveData<String> = MutableLiveData("")
 | 
				
			||||||
 | 
					    val shortNameStr: LiveData<String> = _shortNameStr
 | 
				
			||||||
 | 
					    fun setShortNameStr(shortName: String) {
 | 
				
			||||||
 | 
					        _shortNameStr.postValue(shortName)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private val _baseFolderNameStr: MutableLiveData<String> = MutableLiveData("")
 | 
				
			||||||
 | 
					    val baseFolderNameStr: LiveData<String> = _baseFolderNameStr
 | 
				
			||||||
 | 
					    fun setBaseFolderNameStr(str: String) {
 | 
				
			||||||
 | 
					        _baseFolderNameStr.postValue(str)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private val _mediaBaseUrlStr: MutableLiveData<String> = MutableLiveData("")
 | 
				
			||||||
 | 
					    val mediaBaseUrlStr: LiveData<String> = _mediaBaseUrlStr
 | 
				
			||||||
 | 
					    fun setMediaBaseUrlStr(str: String) {
 | 
				
			||||||
 | 
					        _mediaBaseUrlStr.postValue(str)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private val _preferredFormatsStr: MutableLiveData<String> = MutableLiveData("")
 | 
				
			||||||
 | 
					    val preferredFormatsStr: LiveData<String> = _preferredFormatsStr
 | 
				
			||||||
 | 
					    fun setPreferredFormatsStr(str: String) {
 | 
				
			||||||
 | 
					        _preferredFormatsStr.postValue(str)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fun isApiUrlValid(): Boolean {
 | 
				
			||||||
 | 
					        return URLUtil.isNetworkUrl(apiUrl.value)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fun fetchContentFromApiUrl() {
 | 
				
			||||||
 | 
					        val httpClient: OkHttpClient = OkHttpClient()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        viewModelScope.launch(context = Dispatchers.IO) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            val formBody = FormBody.Builder()
 | 
				
			||||||
 | 
					                .add("do", "getserverinfo")
 | 
				
			||||||
 | 
					                .build()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            val request = Request.Builder()
 | 
				
			||||||
 | 
					//                .url("http://localhost/")
 | 
				
			||||||
 | 
					                .url(apiUrl.value!!)
 | 
				
			||||||
 | 
					                .post(formBody)
 | 
				
			||||||
 | 
					                .build()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            try {
 | 
				
			||||||
 | 
					                httpClient.newCall(request).execute().use { response ->
 | 
				
			||||||
 | 
					                    if (!response.isSuccessful) {
 | 
				
			||||||
 | 
					                        // TODO: non-200 response will go to here too.
 | 
				
			||||||
 | 
					                        return@use
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    val kv = parseServerFromJsonString(response.body!!.string())
 | 
				
			||||||
 | 
					                    Log.d("vvv", kv.toString())
 | 
				
			||||||
 | 
					                    if (kv["serverName"] != null) setNameStr(kv["serverName"]!!)
 | 
				
			||||||
 | 
					                    if (kv["serverShortName"] != null) setShortNameStr(kv["serverShortName"]!!)
 | 
				
			||||||
 | 
					                    if (kv["baseFolderNameHint"] != null) setBaseFolderNameStr(kv["baseFolderNameHint"]!!)
 | 
				
			||||||
 | 
					                    if (kv["preferredFormatsHint"] != null) setPreferredFormatsStr(kv["preferredFormatsHint"]!!)
 | 
				
			||||||
 | 
					                    if (kv["mediaRootUrl"] != null) setMediaBaseUrlStr(kv["mediaRootUrl"]!!)
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            } catch (e: java.io.IOException) {
 | 
				
			||||||
 | 
					                e.printStackTrace()
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Reference in New Issue
	
	Block a user