fix livedata not updated, playlist not scrollable
This commit is contained in:
		@ -52,6 +52,7 @@ dependencies {
 | 
				
			|||||||
    implementation 'androidx.appcompat:appcompat:1.3.1'
 | 
					    implementation 'androidx.appcompat:appcompat:1.3.1'
 | 
				
			||||||
    implementation 'com.google.android.material:material:1.4.0'
 | 
					    implementation 'com.google.android.material:material:1.4.0'
 | 
				
			||||||
    implementation "androidx.compose.ui:ui:$compose_version"
 | 
					    implementation "androidx.compose.ui:ui:$compose_version"
 | 
				
			||||||
 | 
					    implementation "androidx.compose.runtime:runtime-livedata:$compose_version"
 | 
				
			||||||
    implementation "androidx.compose.material:material:$compose_version"
 | 
					    implementation "androidx.compose.material:material:$compose_version"
 | 
				
			||||||
    implementation "androidx.compose.material:material-icons-extended:$compose_version"
 | 
					    implementation "androidx.compose.material:material-icons-extended:$compose_version"
 | 
				
			||||||
    implementation "androidx.compose.ui:ui-tooling-preview:$compose_version"
 | 
					    implementation "androidx.compose.ui:ui-tooling-preview:$compose_version"
 | 
				
			||||||
@ -59,6 +60,9 @@ dependencies {
 | 
				
			|||||||
    implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.4.0'
 | 
					    implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.4.0'
 | 
				
			||||||
    implementation 'androidx.activity:activity-compose:1.4.0'
 | 
					    implementation 'androidx.activity:activity-compose:1.4.0'
 | 
				
			||||||
    implementation "androidx.datastore:datastore-preferences:1.0.0"
 | 
					    implementation "androidx.datastore:datastore-preferences:1.0.0"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    implementation("com.squareup.okhttp3:okhttp:4.9.0")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    testImplementation 'junit:junit:4.+'
 | 
					    testImplementation 'junit:junit:4.+'
 | 
				
			||||||
    androidTestImplementation 'androidx.test.ext:junit:1.1.3'
 | 
					    androidTestImplementation 'androidx.test.ext:junit:1.1.3'
 | 
				
			||||||
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
 | 
					    androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
 | 
				
			||||||
 | 
				
			|||||||
@ -1,63 +1,132 @@
 | 
				
			|||||||
package net.blumia.pcmdroid
 | 
					package net.blumia.pcmdroid
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import android.net.Uri
 | 
					import android.net.Uri
 | 
				
			||||||
 | 
					import android.util.Log
 | 
				
			||||||
import androidx.lifecycle.LiveData
 | 
					import androidx.lifecycle.LiveData
 | 
				
			||||||
import androidx.lifecycle.MutableLiveData
 | 
					import androidx.lifecycle.MutableLiveData
 | 
				
			||||||
import androidx.lifecycle.ViewModel
 | 
					import androidx.lifecycle.ViewModel
 | 
				
			||||||
 | 
					import androidx.lifecycle.viewModelScope
 | 
				
			||||||
 | 
					import kotlinx.coroutines.Dispatchers
 | 
				
			||||||
 | 
					import kotlinx.coroutines.async
 | 
				
			||||||
 | 
					import kotlinx.coroutines.launch
 | 
				
			||||||
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
 | 
				
			||||||
 | 
					import net.blumia.pcmdroid.model.parseFromJsonString
 | 
				
			||||||
 | 
					import okhttp3.FormBody
 | 
				
			||||||
 | 
					import okhttp3.OkHttpClient
 | 
				
			||||||
 | 
					import okhttp3.Request
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class MainViewModel : ViewModel() {
 | 
					class MainViewModel : ViewModel() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private val httpClient: OkHttpClient = OkHttpClient()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    val servers: LiveData<List<Server>> = MutableLiveData<List<Server>>(
 | 
					    val servers: LiveData<List<Server>> = MutableLiveData<List<Server>>(
 | 
				
			||||||
        listOf(
 | 
					        listOf(
 | 
				
			||||||
            Server(
 | 
					            Server(
 | 
				
			||||||
                url = Uri.parse("https://localhost/api.php"),
 | 
					                url = "http://localhost/api.php",
 | 
				
			||||||
                name = "PCM",
 | 
					                name = "PCM",
 | 
				
			||||||
                baseFolderName = "pcm",
 | 
					                baseFolderName = "pcm",
 | 
				
			||||||
            ),
 | 
					            ),
 | 
				
			||||||
            Server(
 | 
					            Server(
 | 
				
			||||||
                url = Uri.parse("https://localhost/api.php"),
 | 
					                url = "http://localhost/api.php",
 | 
				
			||||||
                name = "PCM2",
 | 
					                name = "PCM2",
 | 
				
			||||||
                baseFolderName = "pcm2",
 | 
					                baseFolderName = "pcm2",
 | 
				
			||||||
            )
 | 
					            )
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    val currentPath: LiveData<String> = MutableLiveData("")
 | 
					    private val _currentServer: MutableLiveData<Server> = MutableLiveData(null)
 | 
				
			||||||
 | 
					    val currentServer: LiveData<Server> = _currentServer;
 | 
				
			||||||
 | 
					    fun setCurrentServer(srv: Server) {
 | 
				
			||||||
 | 
					        _currentServer.postValue(srv)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    val drawerFolders: LiveData<List<Folder>> = MutableLiveData(
 | 
					    private val _currentPath: MutableLiveData<String> = MutableLiveData("")
 | 
				
			||||||
 | 
					    val currentPath: LiveData<String> = _currentPath
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private val _drawerFolders: MutableLiveData<List<Folder>> = MutableLiveData(
 | 
				
			||||||
        listOf(
 | 
					        listOf(
 | 
				
			||||||
            Folder("Test/"),
 | 
					            Folder("Test/"),
 | 
				
			||||||
            Folder("Folder/")
 | 
					            Folder("Folder/")
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
 | 
					    val drawerFolders: LiveData<List<Folder>> = _drawerFolders
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    val folders: LiveData<List<Folder>> = MutableLiveData(
 | 
					    private val _folders: MutableLiveData<List<Folder>> = MutableLiveData(
 | 
				
			||||||
        listOf(
 | 
					        listOf(
 | 
				
			||||||
            Folder("Test/Converted-Modules/")
 | 
					            Folder("Test/Converted-Modules/")
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
 | 
					    val folders: LiveData<List<Folder>> = _folders
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    val songs: LiveData<List<Song>> = MutableLiveData(
 | 
					    private val _songs: MutableLiveData<List<Song>> = MutableLiveData(
 | 
				
			||||||
        listOf(
 | 
					        listOf(
 | 
				
			||||||
            Song(
 | 
					            Song(
 | 
				
			||||||
                filePath = "Test/Rick Astley - Never Gonna Give You Up.mp3",
 | 
					                filePath = "Test/Rick Astley - Never Gonna Give You Up.mp3",
 | 
				
			||||||
                url = Uri.parse("http://localhost/rickroll.mp3")
 | 
					                url = "http://localhost/rickroll.mp3"
 | 
				
			||||||
            ),
 | 
					            ),
 | 
				
			||||||
            Song(
 | 
					            Song(
 | 
				
			||||||
                filePath = "Test/哇 好东西一堆.xm",
 | 
					                filePath = "Test/哇 好东西一堆.xm",
 | 
				
			||||||
                url = Uri.parse("http://localhost/rickroll.mp3")
 | 
					                url = "http://localhost/rickroll.mp3"
 | 
				
			||||||
            )
 | 
					            )
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
 | 
					    val songs: LiveData<List<Song>> = _songs
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fun fetchServer(srv: Server) {
 | 
					    fun fetchServer(srv: Server) {
 | 
				
			||||||
        //
 | 
					        viewModelScope.launch(context = Dispatchers.IO) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            val formBody = FormBody.Builder()
 | 
				
			||||||
 | 
					                .add("do", "getfilelist")
 | 
				
			||||||
 | 
					                .build()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            val request = Request.Builder()
 | 
				
			||||||
 | 
					                .url(srv.url)
 | 
				
			||||||
 | 
					                .post(formBody)
 | 
				
			||||||
 | 
					                .build()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            httpClient.newCall(request).execute().use { response ->
 | 
				
			||||||
 | 
					                if (!response.isSuccessful) {
 | 
				
			||||||
 | 
					                    // TODO: non-200 response will go to here too.
 | 
				
			||||||
 | 
					                    return@use
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                val pair = parseFromJsonString(response.body!!.string())
 | 
				
			||||||
 | 
					                _drawerFolders.postValue(pair.first)
 | 
				
			||||||
 | 
					                setCurrentServer(srv)
 | 
				
			||||||
 | 
					                Log.d("vvv", drawerFolders.value.toString())
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					//            Thread.sleep(5_000)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fun fetchFolder(folder: Folder) {
 | 
					    fun fetchFolder(folder: Folder) {
 | 
				
			||||||
        //
 | 
					        if (currentServer.value == null) return
 | 
				
			||||||
 | 
					        val srv = currentServer.value!!
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        viewModelScope.launch(context = Dispatchers.IO) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            val formBody = FormBody.Builder()
 | 
				
			||||||
 | 
					                .add("do", "getfilelist")
 | 
				
			||||||
 | 
					                .add("folder", folder.folderPath)
 | 
				
			||||||
 | 
					                .build()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            val request = Request.Builder()
 | 
				
			||||||
 | 
					                .url(srv.url)
 | 
				
			||||||
 | 
					                .post(formBody)
 | 
				
			||||||
 | 
					                .build()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            httpClient.newCall(request).execute().use { response ->
 | 
				
			||||||
 | 
					                if (!response.isSuccessful) {
 | 
				
			||||||
 | 
					                    // TODO: non-200 response will go to here too.
 | 
				
			||||||
 | 
					                    return@use
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                val pair = parseFromJsonString(response.body!!.string())
 | 
				
			||||||
 | 
					                _folders.postValue(pair.first)
 | 
				
			||||||
 | 
					                _songs.postValue(pair.second)
 | 
				
			||||||
 | 
					                Log.d("vvv", folders.value.toString())
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					//            Thread.sleep(5_000)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -1,9 +1,7 @@
 | 
				
			|||||||
package net.blumia.pcmdroid.model
 | 
					package net.blumia.pcmdroid.model
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import android.net.Uri
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
data class Server (
 | 
					data class Server (
 | 
				
			||||||
    val url: Uri,
 | 
					    val url: String,
 | 
				
			||||||
    val name: String,
 | 
					    val name: String,
 | 
				
			||||||
    val baseFolderName: String,
 | 
					    val baseFolderName: String,
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
				
			|||||||
@ -1,13 +1,16 @@
 | 
				
			|||||||
package net.blumia.pcmdroid.model
 | 
					package net.blumia.pcmdroid.model
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import android.net.Uri
 | 
					import android.net.Uri
 | 
				
			||||||
 | 
					import org.json.JSONException
 | 
				
			||||||
 | 
					import org.json.JSONObject
 | 
				
			||||||
 | 
					import java.net.URLDecoder
 | 
				
			||||||
 | 
					
 | 
				
			||||||
data class Song (
 | 
					data class Song (
 | 
				
			||||||
    val filePath: String, // with file name
 | 
					    val filePath: String, // with file name
 | 
				
			||||||
    val modifiedTime: Int = 0,
 | 
					    val modifiedTime: Long = 0,
 | 
				
			||||||
    val fileSize: Int = 0,
 | 
					    val fileSize: Int = 0,
 | 
				
			||||||
    val additionalInfo: Boolean = false, // if sidecar meta-info json file exist.
 | 
					    val additionalInfo: Boolean = false, // if sidecar meta-info json file exist.
 | 
				
			||||||
    val url: Uri,
 | 
					    val url: String,
 | 
				
			||||||
) {
 | 
					) {
 | 
				
			||||||
    fun displayName(): String {
 | 
					    fun displayName(): String {
 | 
				
			||||||
        return Uri.parse(filePath).lastPathSegment ?: "???"
 | 
					        return Uri.parse(filePath).lastPathSegment ?: "???"
 | 
				
			||||||
@ -18,6 +21,41 @@ data class Folder (
 | 
				
			|||||||
    val folderPath: String,
 | 
					    val folderPath: String,
 | 
				
			||||||
) {
 | 
					) {
 | 
				
			||||||
    fun displayName(): String {
 | 
					    fun displayName(): String {
 | 
				
			||||||
        return Uri.parse(folderPath).lastPathSegment ?: "???"
 | 
					        return URLDecoder.decode(Uri.parse(folderPath).lastPathSegment ?: "???", "UTF-8")
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fun parseFromJsonString(jsonString: String): Pair<List<Folder>, List<Song>> {
 | 
				
			||||||
 | 
					    val folders = mutableListOf<Folder>()
 | 
				
			||||||
 | 
					    val songs = mutableListOf<Song>()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    try {
 | 
				
			||||||
 | 
					        val jsonObj = JSONObject(jsonString)
 | 
				
			||||||
 | 
					        val result = jsonObj.getJSONObject("result")
 | 
				
			||||||
 | 
					        val data = result.getJSONObject("data")
 | 
				
			||||||
 | 
					        val subFolders = data.getJSONArray("subFolderList")
 | 
				
			||||||
 | 
					        val musicList = data.getJSONArray("musicList")
 | 
				
			||||||
 | 
					        for (i in 0 until subFolders.length()) {
 | 
				
			||||||
 | 
					            val rawFolderName = subFolders.getString(i)
 | 
				
			||||||
 | 
					            folders.add(Folder(rawFolderName))
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        for (i in 0 until musicList.length()) {
 | 
				
			||||||
 | 
					            val fileObject = musicList.getJSONObject(i)
 | 
				
			||||||
 | 
					            val rawFileName = fileObject.getString("fileName")
 | 
				
			||||||
 | 
					            val fileName = URLDecoder.decode(rawFileName, "UTF-8")
 | 
				
			||||||
 | 
					            val modifiedTime = fileObject.getLong("modifiedTime")
 | 
				
			||||||
 | 
					            val fileSize = fileObject.getLong("fileSize")
 | 
				
			||||||
 | 
					            songs.add(
 | 
				
			||||||
 | 
					                Song(
 | 
				
			||||||
 | 
					                    rawFileName,
 | 
				
			||||||
 | 
					                    modifiedTime = modifiedTime,
 | 
				
			||||||
 | 
					                    url = rawFileName
 | 
				
			||||||
 | 
					                )
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    } catch (e: JSONException) {
 | 
				
			||||||
 | 
					        e.printStackTrace()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return Pair(folders, songs)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -1,11 +1,16 @@
 | 
				
			|||||||
package net.blumia.pcmdroid.ui
 | 
					package net.blumia.pcmdroid.ui
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import androidx.compose.runtime.Composable
 | 
					import androidx.compose.runtime.Composable
 | 
				
			||||||
 | 
					import androidx.compose.runtime.getValue
 | 
				
			||||||
 | 
					import androidx.compose.runtime.livedata.observeAsState
 | 
				
			||||||
import androidx.navigation.NavHostController
 | 
					import androidx.navigation.NavHostController
 | 
				
			||||||
import androidx.navigation.compose.NavHost
 | 
					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 net.blumia.pcmdroid.MainViewModel
 | 
					import net.blumia.pcmdroid.MainViewModel
 | 
				
			||||||
 | 
					import net.blumia.pcmdroid.model.Folder
 | 
				
			||||||
 | 
					import net.blumia.pcmdroid.model.Server
 | 
				
			||||||
 | 
					import net.blumia.pcmdroid.model.Song
 | 
				
			||||||
import net.blumia.pcmdroid.ui.screen.addserver.AddServerScreen
 | 
					import net.blumia.pcmdroid.ui.screen.addserver.AddServerScreen
 | 
				
			||||||
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
 | 
				
			||||||
@ -27,11 +32,26 @@ fun NavGraph(
 | 
				
			|||||||
        startDestination = startDestination
 | 
					        startDestination = startDestination
 | 
				
			||||||
    ) {
 | 
					    ) {
 | 
				
			||||||
        composable(MainDestinations.MAIN_ROUTE) {
 | 
					        composable(MainDestinations.MAIN_ROUTE) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            val servers: List<Server> by viewModel.servers.observeAsState(initial = listOf())
 | 
				
			||||||
 | 
					            val drawerFolders: List<Folder> by viewModel.drawerFolders.observeAsState(initial = listOf())
 | 
				
			||||||
 | 
					            val folders: List<Folder> by viewModel.folders.observeAsState(listOf())
 | 
				
			||||||
 | 
					            val songs: List<Song> by viewModel.songs.observeAsState(listOf())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            MainPlayer(
 | 
					            MainPlayer(
 | 
				
			||||||
                viewModel = viewModel,
 | 
					                servers = servers,
 | 
				
			||||||
 | 
					                drawerFolders = drawerFolders,
 | 
				
			||||||
 | 
					                folders = folders,
 | 
				
			||||||
 | 
					                songs = songs,
 | 
				
			||||||
                addServerActionTriggered = {
 | 
					                addServerActionTriggered = {
 | 
				
			||||||
                    navController.navigate(MainDestinations.ADD_SERVER_ROUTE)
 | 
					                    navController.navigate(MainDestinations.ADD_SERVER_ROUTE)
 | 
				
			||||||
                },
 | 
					                },
 | 
				
			||||||
 | 
					                onServerItemIconClicked = { server ->
 | 
				
			||||||
 | 
					                    viewModel.fetchServer(server)
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                onDrawerFolderItemClicked = { folder ->
 | 
				
			||||||
 | 
					                    viewModel.fetchFolder(folder)
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
                settingsActionTriggered = {
 | 
					                settingsActionTriggered = {
 | 
				
			||||||
                    navController.navigate(MainDestinations.SETTINGS_ROUTE)
 | 
					                    navController.navigate(MainDestinations.SETTINGS_ROUTE)
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
				
			|||||||
@ -1,12 +1,9 @@
 | 
				
			|||||||
package net.blumia.pcmdroid.ui.screen.main
 | 
					package net.blumia.pcmdroid.ui.screen.main
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import android.net.Uri
 | 
					import android.net.Uri
 | 
				
			||||||
import androidx.compose.foundation.Image
 | 
					import androidx.compose.foundation.*
 | 
				
			||||||
import androidx.compose.foundation.clickable
 | 
					 | 
				
			||||||
import androidx.compose.foundation.gestures.scrollable
 | 
					import androidx.compose.foundation.gestures.scrollable
 | 
				
			||||||
import androidx.compose.foundation.horizontalScroll
 | 
					 | 
				
			||||||
import androidx.compose.foundation.layout.*
 | 
					import androidx.compose.foundation.layout.*
 | 
				
			||||||
import androidx.compose.foundation.rememberScrollState
 | 
					 | 
				
			||||||
import androidx.compose.material.*
 | 
					import androidx.compose.material.*
 | 
				
			||||||
import androidx.compose.material.icons.Icons
 | 
					import androidx.compose.material.icons.Icons
 | 
				
			||||||
import androidx.compose.material.icons.filled.*
 | 
					import androidx.compose.material.icons.filled.*
 | 
				
			||||||
@ -15,6 +12,9 @@ import androidx.compose.material.icons.rounded.PlayArrow
 | 
				
			|||||||
import androidx.compose.material.icons.rounded.PlayCircle
 | 
					import androidx.compose.material.icons.rounded.PlayCircle
 | 
				
			||||||
import androidx.compose.material.icons.rounded.PlayCircleOutline
 | 
					import androidx.compose.material.icons.rounded.PlayCircleOutline
 | 
				
			||||||
import androidx.compose.runtime.*
 | 
					import androidx.compose.runtime.*
 | 
				
			||||||
 | 
					import androidx.compose.runtime.getValue
 | 
				
			||||||
 | 
					import androidx.compose.runtime.setValue
 | 
				
			||||||
 | 
					import androidx.compose.runtime.livedata.observeAsState
 | 
				
			||||||
import androidx.compose.ui.Alignment
 | 
					import androidx.compose.ui.Alignment
 | 
				
			||||||
import androidx.compose.ui.Modifier
 | 
					import androidx.compose.ui.Modifier
 | 
				
			||||||
import androidx.compose.ui.graphics.vector.ImageVector
 | 
					import androidx.compose.ui.graphics.vector.ImageVector
 | 
				
			||||||
@ -24,7 +24,6 @@ import androidx.compose.ui.res.stringResource
 | 
				
			|||||||
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 kotlinx.coroutines.launch
 | 
					import kotlinx.coroutines.launch
 | 
				
			||||||
import net.blumia.pcmdroid.MainViewModel
 | 
					 | 
				
			||||||
import net.blumia.pcmdroid.R
 | 
					import net.blumia.pcmdroid.R
 | 
				
			||||||
import net.blumia.pcmdroid.model.Folder
 | 
					import net.blumia.pcmdroid.model.Folder
 | 
				
			||||||
import net.blumia.pcmdroid.model.Server
 | 
					import net.blumia.pcmdroid.model.Server
 | 
				
			||||||
@ -74,15 +73,17 @@ fun NowPlaying() {
 | 
				
			|||||||
@OptIn(ExperimentalMaterialApi::class)
 | 
					@OptIn(ExperimentalMaterialApi::class)
 | 
				
			||||||
@Composable
 | 
					@Composable
 | 
				
			||||||
fun DrawerContent(
 | 
					fun DrawerContent(
 | 
				
			||||||
    viewModel: MainViewModel = MainViewModel(),
 | 
					    servers: List<Server> = listOf(),
 | 
				
			||||||
 | 
					    drawerFolders: List<Folder> = listOf(),
 | 
				
			||||||
    addServerActionTriggered: () -> Unit = {},
 | 
					    addServerActionTriggered: () -> Unit = {},
 | 
				
			||||||
 | 
					    onServerItemIconClicked: (Server) -> Unit = {},
 | 
				
			||||||
 | 
					    onDrawerFolderItemClicked: (Folder) -> Unit = {},
 | 
				
			||||||
    settingsActionTriggered: () -> Unit = {},
 | 
					    settingsActionTriggered: () -> Unit = {},
 | 
				
			||||||
) {
 | 
					) {
 | 
				
			||||||
    Row(modifier = Modifier.fillMaxSize()) {
 | 
					    Row(modifier = Modifier.fillMaxSize()) {
 | 
				
			||||||
        var selectedItem by remember { mutableStateOf<Int?>(0) }
 | 
					        var selectedItem by remember { mutableStateOf<Int?>(0) }
 | 
				
			||||||
        val servers = viewModel.servers.value
 | 
					 | 
				
			||||||
        NavigationRail {
 | 
					        NavigationRail {
 | 
				
			||||||
            servers?.forEachIndexed { index, server ->
 | 
					            servers.forEachIndexed { index, server ->
 | 
				
			||||||
                NavigationRailItem(
 | 
					                NavigationRailItem(
 | 
				
			||||||
                    icon = {
 | 
					                    icon = {
 | 
				
			||||||
                        Icon(
 | 
					                        Icon(
 | 
				
			||||||
@ -94,7 +95,7 @@ fun DrawerContent(
 | 
				
			|||||||
                    },
 | 
					                    },
 | 
				
			||||||
                    selected = selectedItem == index,
 | 
					                    selected = selectedItem == index,
 | 
				
			||||||
                    onClick = {
 | 
					                    onClick = {
 | 
				
			||||||
                        viewModel.fetchServer(server)
 | 
					                        onServerItemIconClicked(server)
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                )
 | 
					                )
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
@ -133,11 +134,10 @@ fun DrawerContent(
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
            Divider()
 | 
					            Divider()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            val drawerFolders = viewModel.drawerFolders.value
 | 
					            drawerFolders.forEach { folder ->
 | 
				
			||||||
            drawerFolders?.forEach { folder ->
 | 
					 | 
				
			||||||
                ListItem(
 | 
					                ListItem(
 | 
				
			||||||
                    modifier = Modifier.clickable{
 | 
					                    modifier = Modifier.clickable{
 | 
				
			||||||
                        viewModel.fetchFolder(folder)
 | 
					                        onDrawerFolderItemClicked(folder)
 | 
				
			||||||
                    },
 | 
					                    },
 | 
				
			||||||
                    text = {
 | 
					                    text = {
 | 
				
			||||||
                        Text(
 | 
					                        Text(
 | 
				
			||||||
@ -155,8 +155,13 @@ fun DrawerContent(
 | 
				
			|||||||
@OptIn(ExperimentalMaterialApi::class)
 | 
					@OptIn(ExperimentalMaterialApi::class)
 | 
				
			||||||
@Composable
 | 
					@Composable
 | 
				
			||||||
fun MainPlayer(
 | 
					fun MainPlayer(
 | 
				
			||||||
    viewModel: MainViewModel = MainViewModel(),
 | 
					    servers: List<Server> = listOf(),
 | 
				
			||||||
 | 
					    drawerFolders: List<Folder> = listOf(),
 | 
				
			||||||
 | 
					    folders: List<Folder> = listOf(),
 | 
				
			||||||
 | 
					    songs: List<Song> = listOf(),
 | 
				
			||||||
    addServerActionTriggered: () -> Unit = {},
 | 
					    addServerActionTriggered: () -> Unit = {},
 | 
				
			||||||
 | 
					    onServerItemIconClicked: (Server) -> Unit = {},
 | 
				
			||||||
 | 
					    onDrawerFolderItemClicked: (Folder) -> Unit = {},
 | 
				
			||||||
    settingsActionTriggered: () -> Unit = {},
 | 
					    settingsActionTriggered: () -> Unit = {},
 | 
				
			||||||
) {
 | 
					) {
 | 
				
			||||||
    val drawerState = rememberDrawerState(initialValue = DrawerValue.Closed)
 | 
					    val drawerState = rememberDrawerState(initialValue = DrawerValue.Closed)
 | 
				
			||||||
@ -165,8 +170,11 @@ fun MainPlayer(
 | 
				
			|||||||
        drawerState = drawerState,
 | 
					        drawerState = drawerState,
 | 
				
			||||||
        drawerContent = {
 | 
					        drawerContent = {
 | 
				
			||||||
            DrawerContent(
 | 
					            DrawerContent(
 | 
				
			||||||
                viewModel = viewModel,
 | 
					                servers = servers,
 | 
				
			||||||
 | 
					                drawerFolders = drawerFolders,
 | 
				
			||||||
                addServerActionTriggered = addServerActionTriggered,
 | 
					                addServerActionTriggered = addServerActionTriggered,
 | 
				
			||||||
 | 
					                onServerItemIconClicked = onServerItemIconClicked,
 | 
				
			||||||
 | 
					                onDrawerFolderItemClicked = onDrawerFolderItemClicked,
 | 
				
			||||||
                settingsActionTriggered = settingsActionTriggered,
 | 
					                settingsActionTriggered = settingsActionTriggered,
 | 
				
			||||||
            )
 | 
					            )
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@ -195,7 +203,11 @@ fun MainPlayer(
 | 
				
			|||||||
            Column(
 | 
					            Column(
 | 
				
			||||||
                modifier = Modifier.fillMaxSize()
 | 
					                modifier = Modifier.fillMaxSize()
 | 
				
			||||||
            ) {
 | 
					            ) {
 | 
				
			||||||
                Column(modifier = Modifier.weight(1f, fill = true)) {
 | 
					                Column(
 | 
				
			||||||
 | 
					                    modifier = Modifier
 | 
				
			||||||
 | 
					                        .weight(1f, fill = true)
 | 
				
			||||||
 | 
					                        .verticalScroll(rememberScrollState())
 | 
				
			||||||
 | 
					                ) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    val iconLeftPadding = 16.dp
 | 
					                    val iconLeftPadding = 16.dp
 | 
				
			||||||
                    val iconVerticalPadding = 12.dp
 | 
					                    val iconVerticalPadding = 12.dp
 | 
				
			||||||
@ -229,7 +241,7 @@ fun MainPlayer(
 | 
				
			|||||||
                        }
 | 
					                        }
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    viewModel.folders.value?.forEach { folder ->
 | 
					                    folders.forEach { folder ->
 | 
				
			||||||
                        ListItem(
 | 
					                        ListItem(
 | 
				
			||||||
                            modifier = Modifier.clickable {  },
 | 
					                            modifier = Modifier.clickable {  },
 | 
				
			||||||
                            icon = {
 | 
					                            icon = {
 | 
				
			||||||
@ -244,7 +256,7 @@ fun MainPlayer(
 | 
				
			|||||||
                        )
 | 
					                        )
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    viewModel.songs.value?.forEach { song ->
 | 
					                    songs.forEach { song ->
 | 
				
			||||||
                        ListItem(
 | 
					                        ListItem(
 | 
				
			||||||
                            modifier = Modifier.clickable {  },
 | 
					                            modifier = Modifier.clickable {  },
 | 
				
			||||||
                            icon = {
 | 
					                            icon = {
 | 
				
			||||||
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user