prepare room for servers

This commit is contained in:
Gary Wang 2021-11-16 00:16:36 +08:00
parent d0800429c5
commit 9e98340fd2
10 changed files with 132 additions and 24 deletions

6
README.md Normal file
View File

@ -0,0 +1,6 @@
TODO:
- [ ] Add server
- [ ] Music playback
- [ ] Download music to local folder
- [ ] Back key to navigate folder up

View File

@ -3,6 +3,8 @@ plugins {
id 'kotlin-android'
}
apply plugin: 'kotlin-kapt'
android {
compileSdk 31
@ -51,16 +53,29 @@ dependencies {
implementation 'androidx.core:core-ktx:1.7.0'
implementation 'androidx.appcompat:appcompat:1.3.1'
implementation 'com.google.android.material:material:1.4.0'
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-icons-extended:$compose_version"
implementation "androidx.compose.ui:ui-tooling-preview:$compose_version"
def nav_compose_version = '2.4.0-beta02'
implementation "androidx.navigation:navigation-compose:$nav_compose_version"
implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.4.0'
def lifecycle_version = '2.4.0'
implementation "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycle_version"
implementation "androidx.lifecycle:lifecycle-runtime-ktx:$lifecycle_version"
implementation 'androidx.activity:activity-compose:1.4.0'
implementation "androidx.datastore:datastore-preferences:1.0.0"
def room_version = '2.3.0'
kapt "androidx.room:room-compiler:$room_version"
implementation "androidx.room:room-ktx:$room_version"
implementation "androidx.room:room-runtime:$room_version"
annotationProcessor "androidx.room:room-compiler:$room_version"
implementation("com.squareup.okhttp3:okhttp:4.9.0")
testImplementation 'junit:junit:4.+'

View File

@ -5,6 +5,7 @@
<uses-permission android:name="android.permission.INTERNET"/>
<application
android:name=".MainApplication"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"

View File

@ -15,7 +15,9 @@ import net.blumia.pcmdroid.ui.theme.PrivateCloudMusicTheme
class MainActivity : ComponentActivity() {
private val model: MainViewModel by viewModels()
private val model: MainViewModel by viewModels {
MainViewModelFactory((application as MainApplication).repository)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)

View File

@ -0,0 +1,12 @@
package net.blumia.pcmdroid
import android.app.Application
import net.blumia.pcmdroid.databases.PcmRoomDatabase
import net.blumia.pcmdroid.repository.ServerRepository
class MainApplication : Application() {
// Using by lazy so the database and the repository are only created when they're needed
// rather than when the application starts
val database by lazy { PcmRoomDatabase.getDatabase(this) }
val repository by lazy { ServerRepository(database.serverDao()) }
}

View File

@ -2,10 +2,7 @@ package net.blumia.pcmdroid
import android.net.Uri
import android.util.Log
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import androidx.lifecycle.*
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.async
import kotlinx.coroutines.launch
@ -13,28 +10,19 @@ import net.blumia.pcmdroid.model.Folder
import net.blumia.pcmdroid.model.Server
import net.blumia.pcmdroid.model.Song
import net.blumia.pcmdroid.model.parseFromJsonString
import net.blumia.pcmdroid.repository.ServerRepository
import okhttp3.FormBody
import okhttp3.OkHttpClient
import okhttp3.Request
class MainViewModel : ViewModel() {
class MainViewModel(private val repository: ServerRepository) : ViewModel() {
private val httpClient: OkHttpClient = OkHttpClient()
val servers: LiveData<List<Server>> = MutableLiveData<List<Server>>(
listOf(
Server(
url = "https://localhost/api.php",
name = "PCM",
baseFolderName = "pcm",
),
Server(
url = "https://localhost/pcm.cgi",
name = "Chris",
baseFolderName = "pcm2",
)
)
)
val servers: LiveData<List<Server>> = repository.allServers.asLiveData()
fun addServer(server: Server) = viewModelScope.launch {
repository.insert(server)
}
private val _currentServer: MutableLiveData<Server> = MutableLiveData(null)
val currentServer: LiveData<Server> = _currentServer;
@ -139,4 +127,14 @@ class MainViewModel : ViewModel() {
}
}
}
}
class MainViewModelFactory(private val repository: ServerRepository) : ViewModelProvider.Factory {
override fun <T : ViewModel> create(modelClass: Class<T>): T {
if (modelClass.isAssignableFrom(MainViewModel::class.java)) {
@Suppress("UNCHECKED_CAST")
return MainViewModel(repository) as T
}
throw IllegalArgumentException("Unknown ViewModel class")
}
}

View File

@ -0,0 +1,35 @@
package net.blumia.pcmdroid.databases
import android.content.Context
import androidx.room.Database
import androidx.room.Room
import androidx.room.RoomDatabase
import net.blumia.pcmdroid.model.Server
import net.blumia.pcmdroid.model.ServerDao
// Annotates class to be a Room Database with a table (entity) of the Word class
@Database(entities = [Server::class], version = 1, exportSchema = false)
public abstract class PcmRoomDatabase : RoomDatabase() {
abstract fun serverDao(): ServerDao
companion object {
// Singleton prevents multiple instances of database opening at the same time.
@Volatile
private var INSTANCE: PcmRoomDatabase? = null
fun getDatabase(context: Context): PcmRoomDatabase {
// if the INSTANCE is not null, then return it,
// if it is, then create the database
return INSTANCE ?: synchronized(this) {
val instance = Room.databaseBuilder(
context.applicationContext,
PcmRoomDatabase::class.java,
"pcm_database"
).build()
INSTANCE = instance
// return instance
instance
}
}
}
}

View File

@ -1,11 +1,31 @@
package net.blumia.pcmdroid.model
import androidx.room.*
import kotlinx.coroutines.flow.Flow
@Entity(tableName = "server_table")
data class Server (
@PrimaryKey @ColumnInfo(name = "url")
val url: String,
@ColumnInfo(name = "name")
val name: String,
@ColumnInfo(name = "baseFolderName")
val baseFolderName: String,
) {
fun displayName(): String {
return name
}
}
@Dao
interface ServerDao {
@Query("SELECT * FROM server_table") // ORDER BY wtf ASC
fun getServers(): Flow<List<Server>>
@Insert(onConflict = OnConflictStrategy.IGNORE)
suspend fun insert(server: Server)
@Query("DELETE FROM server_table")
suspend fun deleteAll()
}

View File

@ -1,4 +1,24 @@
package net.blumia.pcmdroid.repository
class ServerRepository {
import androidx.annotation.WorkerThread
import kotlinx.coroutines.flow.Flow
import net.blumia.pcmdroid.model.Server
import net.blumia.pcmdroid.model.ServerDao
// Declares the DAO as a private property in the constructor. Pass in the DAO
// instead of the whole database, because you only need access to the DAO
class ServerRepository(private val serverDao: ServerDao) {
// Room executes all queries on a separate thread.
// Observed Flow will notify the observer when the data has changed.
val allServers: Flow<List<Server>> = serverDao.getServers()
// By default Room runs suspend queries off the main thread, therefore, we don't need to
// implement anything else to ensure we're not doing long running database work
// off the main thread.
@Suppress("RedundantSuspendModifier")
@WorkerThread
suspend fun insert(server: Server) {
serverDao.insert(server)
}
}

View File

@ -1,9 +1,8 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
ext {
compose_version = '1.1.0-beta02'
nav_compose_version = '2.4.0-beta02'
kotlin_version = '1.5.31'
compose_version = '1.1.0-beta02'
}
repositories {
google()