Adding Room to Compose View #1
13 changed files with 253 additions and 86 deletions
1
.idea/gradle.xml
generated
1
.idea/gradle.xml
generated
|
@ -1,5 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="GradleMigrationSettings" migrationVersion="1" />
|
||||
<component name="GradleSettings">
|
||||
<option name="linkedExternalProjectsSettings">
|
||||
<GradleProjectSettings>
|
||||
|
|
1
.idea/misc.xml
generated
1
.idea/misc.xml
generated
|
@ -1,4 +1,3 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ExternalStorageConfigurationManager" enabled="true" />
|
||||
<component name="MarkdownSettingsMigration">
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
plugins {
|
||||
id 'com.android.application'
|
||||
id 'org.jetbrains.kotlin.android'
|
||||
id 'com.google.devtools.ksp'
|
||||
Azea_Avenbright marked this conversation as resolved
|
||||
}
|
||||
|
||||
android {
|
||||
|
@ -27,11 +28,11 @@ android {
|
|||
}
|
||||
}
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_8
|
||||
targetCompatibility JavaVersion.VERSION_1_8
|
||||
sourceCompatibility JavaVersion.VERSION_17
|
||||
targetCompatibility JavaVersion.VERSION_17
|
||||
}
|
||||
kotlinOptions {
|
||||
jvmTarget = '1.8'
|
||||
jvmTarget = '17'
|
||||
}
|
||||
buildFeatures {
|
||||
compose true
|
||||
|
@ -48,6 +49,9 @@ android {
|
|||
|
||||
dependencies {
|
||||
|
||||
def activity_version = '1.8.0'
|
||||
|
||||
implementation "androidx.activity:activity-ktx:$activity_version"
|
||||
implementation 'androidx.core:core-ktx:1.9.0'
|
||||
implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.6.2'
|
||||
implementation 'androidx.activity:activity-compose:1.8.0'
|
||||
|
@ -66,4 +70,58 @@ dependencies {
|
|||
implementation 'androidx.room:room-common:2.5.2'
|
||||
implementation 'androidx.room:room-ktx:2.5.2'
|
||||
implementation 'androidx.navigation:navigation-runtime-ktx:2.7.4'
|
||||
|
||||
def lifecycle_version = "2.6.2"
|
||||
def arch_version = "2.2.0"
|
||||
def roomVersion = '2.3.0'
|
||||
|
||||
|
||||
// ViewModel
|
||||
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version"
|
||||
// ViewModel utilities for Compose
|
||||
implementation "androidx.lifecycle:lifecycle-viewmodel-compose:$lifecycle_version"
|
||||
// LiveData
|
||||
implementation "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycle_version"
|
||||
// Lifecycles only (without ViewModel or LiveData)
|
||||
implementation "androidx.lifecycle:lifecycle-runtime-ktx:$lifecycle_version"
|
||||
// Lifecycle utilities for Compose
|
||||
implementation "androidx.lifecycle:lifecycle-runtime-compose:$lifecycle_version"
|
||||
|
||||
//Fragment
|
||||
def fragment_version = "1.6.1"
|
||||
|
||||
// Kotlin
|
||||
implementation "androidx.fragment:fragment-ktx:$fragment_version"
|
||||
|
||||
// Saved state module for ViewModel
|
||||
implementation "androidx.lifecycle:lifecycle-viewmodel-savedstate:$lifecycle_version"
|
||||
|
||||
ksp 'androidx.room:room-compiler:2.5.0'
|
||||
|
||||
// Annotation processor
|
||||
annotationProcessor "androidx.room:room-compiler:$roomVersion"
|
||||
// alternately - if using Java8, use the following instead of lifecycle-compiler
|
||||
implementation "androidx.lifecycle:lifecycle-common-java8:$lifecycle_version"
|
||||
|
||||
// optional - helpers for implementing LifecycleOwner in a Service
|
||||
implementation "androidx.lifecycle:lifecycle-service:$lifecycle_version"
|
||||
|
||||
// optional - ProcessLifecycleOwner provides a lifecycle for the whole application process
|
||||
implementation "androidx.lifecycle:lifecycle-process:$lifecycle_version"
|
||||
|
||||
// optional - ReactiveStreams support for LiveData
|
||||
implementation "androidx.lifecycle:lifecycle-reactivestreams-ktx:$lifecycle_version"
|
||||
|
||||
// optional - Test helpers for LiveData
|
||||
testImplementation "androidx.arch.core:core-testing:$arch_version"
|
||||
|
||||
// optional - Test helpers for Lifecycle runtime
|
||||
testImplementation "androidx.lifecycle:lifecycle-runtime-testing:$lifecycle_version"
|
||||
|
||||
//Runtime
|
||||
implementation "androidx.compose.runtime:runtime:1.5.3"
|
||||
implementation "androidx.compose.runtime:runtime-livedata:1.5.3"
|
||||
implementation "androidx.compose.runtime:runtime-rxjava2:1.5.3"
|
||||
|
||||
|
||||
}
|
|
@ -3,6 +3,7 @@
|
|||
xmlns:tools="http://schemas.android.com/tools">
|
||||
|
||||
<application
|
||||
android:name=".database.polycule.PolyculeApplication"
|
||||
android:allowBackup="true"
|
||||
android:dataExtractionRules="@xml/data_extraction_rules"
|
||||
android:fullBackupContent="@xml/backup_rules"
|
||||
|
|
|
@ -1,40 +1,46 @@
|
|||
package com.menagerie.ophelia
|
||||
|
||||
import android.app.Activity
|
||||
import android.app.Application
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import androidx.activity.ComponentActivity
|
||||
import androidx.activity.compose.setContent
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.ListItem
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.livedata.observeAsState
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import com.menagerie.ophelia.database.polycule.PolyculeDatabase
|
||||
import com.menagerie.ophelia.database.polycule.PolyculeDatabaseManager
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import com.menagerie.ophelia.database.polycule.BioListViewModel
|
||||
import com.menagerie.ophelia.database.polycule.PolyculeApplication
|
||||
import com.menagerie.ophelia.database.polycule.PolyculeRepository
|
||||
import com.menagerie.ophelia.database.polycule.entity.Bio
|
||||
import com.menagerie.ophelia.ui.theme.OpheliaTheme
|
||||
|
||||
class MainActivity : ComponentActivity() {
|
||||
|
||||
private val db by lazy { PolyculeDatabase.getDatabase(this) }
|
||||
private val polyculeRepository by lazy {
|
||||
PolyculeRepository(
|
||||
bioDao = db.bioDao()
|
||||
)
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
PolyculeDatabaseManager.polyculeRepository = polyculeRepository
|
||||
setContent {
|
||||
OpheliaTheme {
|
||||
// A surface container using the 'background' color from the theme
|
||||
Surface(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
color = MaterialTheme.colorScheme.error
|
||||
) {
|
||||
Greeting("Android")
|
||||
val repository = (application as PolyculeApplication).repository
|
||||
Greeting("Android", repository)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -42,17 +48,40 @@ class MainActivity : ComponentActivity() {
|
|||
}
|
||||
|
||||
@Composable
|
||||
fun Greeting(name: String, modifier: Modifier = Modifier) {
|
||||
Text(
|
||||
text = "Hello $name!",
|
||||
modifier = modifier
|
||||
fun Greeting(name: String, repository: PolyculeRepository, modifier: Modifier = Modifier) {
|
||||
Log.d("Tawni", "Test")
|
||||
val mBioListViewModel: BioListViewModel = viewModel(
|
||||
factory = BioListViewModel.BioListViewModelFactory(repository)
|
||||
)
|
||||
}
|
||||
|
||||
@Preview(showBackground = true)
|
||||
@Composable
|
||||
fun GreetingPreview() {
|
||||
OpheliaTheme {
|
||||
Greeting("Android")
|
||||
|
||||
val items = mBioListViewModel.allBios.observeAsState(listOf()).value
|
||||
|
||||
|
||||
|
||||
Column(
|
||||
modifier = Modifier.padding(16.dp)
|
||||
) {
|
||||
Text(text = "FUCKING FINAALLLLLLYY")
|
||||
Spacer(modifier = Modifier.padding(16.dp))
|
||||
BioList(list = items, mBioListViewModel = mBioListViewModel)
|
||||
Spacer(modifier = Modifier.padding(16.dp))
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun BioList(
|
||||
list: List<Bio>,
|
||||
mBioListViewModel: BioListViewModel
|
||||
) {
|
||||
Log.d("Test" ,"${list.size}")
|
||||
LazyColumn() {
|
||||
items(list) {bio ->
|
||||
|
||||
ListItem(
|
||||
headlineText = {Text(text = bio.name)}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
package com.menagerie.ophelia.database.polycule
|
||||
|
||||
import android.app.Application
|
||||
import android.content.Context
|
||||
import android.view.View
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.asLiveData
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.menagerie.ophelia.database.polycule.entity.Bio
|
||||
import kotlinx.coroutines.launch
|
||||
import java.lang.IllegalArgumentException
|
||||
|
||||
|
||||
class BioListViewModel(private val repository: PolyculeRepository) : ViewModel() {
|
||||
|
||||
val allBios: LiveData<List<Bio>> = repository.getAllBios().asLiveData()
|
||||
|
||||
fun insert(bio: Bio) = viewModelScope.launch {
|
||||
repository.upsertBio(bio)
|
||||
}
|
||||
|
||||
class BioListViewModelFactory(
|
||||
private val repository: PolyculeRepository) :
|
||||
ViewModelProvider.Factory {
|
||||
override fun <T : ViewModel> create(modelClass: Class<T>): T {
|
||||
if (modelClass.isAssignableFrom(BioListViewModel::class.java)) {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
return BioListViewModel(repository) as T
|
||||
}
|
||||
throw IllegalArgumentException("Unknown ViewModel Class")
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,18 +0,0 @@
|
|||
package com.menagerie.ophelia.database.polycule
|
||||
|
||||
import android.util.LruCache
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
import kotlinx.coroutines.sync.withLock
|
||||
|
||||
abstract class CachedDao<K, V> (capacity: Int = 100) {
|
||||
|
||||
private val cache: LruCache<K, V> = LruCache(capacity)
|
||||
|
||||
private val cacheMutex: Mutex = Mutex()
|
||||
|
||||
protected suspend fun <R> withDaoCache(cacheBlock: suspend LruCache<K, V>.()->R): R {
|
||||
return cacheMutex.withLock {
|
||||
cacheBlock(cache)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
package com.menagerie.ophelia.database.polycule
|
||||
|
||||
import android.app.Application
|
||||
import android.util.Log
|
||||
import com.menagerie.ophelia.database.polycule.entity.Bio
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.SupervisorJob
|
||||
|
||||
class PolyculeApplication : Application() {
|
||||
|
||||
private val applicationScope = CoroutineScope(SupervisorJob())
|
||||
|
||||
val database by lazy { PolyculeDatabase.getDatabase(this, applicationScope)}
|
||||
val repository by lazy { PolyculeRepository(database.bioDao())}
|
||||
}
|
|
@ -1,11 +1,16 @@
|
|||
package com.menagerie.ophelia.database.polycule
|
||||
|
||||
import android.content.Context
|
||||
import android.util.Log
|
||||
import androidx.room.Database
|
||||
import androidx.room.Room
|
||||
import androidx.room.RoomDatabase
|
||||
import androidx.sqlite.db.SupportSQLiteDatabase
|
||||
import com.menagerie.ophelia.database.polycule.entity.Bio
|
||||
import com.menagerie.ophelia.database.polycule.entity.BioDao
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.flow.count
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
|
||||
@Database(
|
||||
|
@ -23,19 +28,69 @@ abstract class PolyculeDatabase : RoomDatabase() {
|
|||
@Volatile
|
||||
private var INSTANCE: PolyculeDatabase? = null
|
||||
|
||||
fun getDatabase(context: Context): PolyculeDatabase {
|
||||
fun getDatabase(
|
||||
context: Context,
|
||||
scope: CoroutineScope,
|
||||
): PolyculeDatabase {
|
||||
return INSTANCE ?: synchronized(this)
|
||||
{
|
||||
Log.d("huh?", "FUCK")
|
||||
val instance = Room.databaseBuilder(
|
||||
context.applicationContext,
|
||||
PolyculeDatabase::class.java,
|
||||
PolyculeDatabase::class.java,
|
||||
"polycule.db"
|
||||
)
|
||||
.fallbackToDestructiveMigration()
|
||||
.addCallback(PolyculeDatabaseCallback(scope))
|
||||
.build()
|
||||
INSTANCE = instance
|
||||
instance
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class PolyculeDatabaseCallback(
|
||||
private val scope: CoroutineScope
|
||||
) : Callback() {
|
||||
|
||||
override fun onCreate(db: SupportSQLiteDatabase) {
|
||||
super.onCreate(db)
|
||||
Log.d("WWW" , "FUCK")
|
||||
INSTANCE?.let { database ->
|
||||
scope.launch {
|
||||
Log.d("WWWWWWWWW", "FUCK")
|
||||
populateDatabase(database.bioDao())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun populateDatabase(bioDao: BioDao) {
|
||||
Log.d("TAWNI", "AAAAA")
|
||||
|
||||
var bio = Bio(
|
||||
name = "Fuck")
|
||||
bioDao.insert(bio)
|
||||
bio = Bio(
|
||||
name = "Off")
|
||||
bioDao.insert(bio)
|
||||
|
||||
|
||||
|
||||
bio = Bio(
|
||||
name = "Android!")
|
||||
bioDao.insert(bio)
|
||||
bio = Bio(
|
||||
name = "(Now")
|
||||
bioDao.insert(bio)
|
||||
bio = Bio(
|
||||
name = "In")
|
||||
bioDao.insert(bio)
|
||||
bio = Bio(
|
||||
name = "Compose!)")
|
||||
bioDao.insert(bio)
|
||||
val count = bioDao.getAllAlphabetisedBios().count()
|
||||
Log.d("Count", "$count")
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,7 +1,10 @@
|
|||
package com.menagerie.ophelia.database.polycule
|
||||
|
||||
import androidx.lifecycle.LiveData
|
||||
import com.menagerie.ophelia.database.polycule.entity.Bio
|
||||
import com.menagerie.ophelia.database.polycule.entity.BioDao
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.count
|
||||
|
||||
|
||||
class PolyculeRepository(
|
||||
|
@ -9,7 +12,20 @@ class PolyculeRepository(
|
|||
) {
|
||||
|
||||
suspend fun upsertBio(bio: Bio): Long {
|
||||
return bioDao.findOrInsert(bio)
|
||||
return 0
|
||||
//return bioDao.findOrInsert(bio)
|
||||
}
|
||||
|
||||
fun getAlphabetisedBios(): Flow<List<Bio>> {
|
||||
return bioDao.getAllAlphabetisedBios()
|
||||
}
|
||||
|
||||
fun getAllBios(): Flow<List<Bio>> {
|
||||
return bioDao.getAllBios()
|
||||
}
|
||||
|
||||
suspend fun insert(bio : Bio) {
|
||||
bioDao.insert(bio)
|
||||
}
|
||||
|
||||
}
|
|
@ -1,19 +1,14 @@
|
|||
package com.menagerie.ophelia.database.polycule.entity
|
||||
|
||||
import androidx.room.ColumnInfo
|
||||
import androidx.room.Entity
|
||||
import androidx.room.ForeignKey
|
||||
import androidx.room.PrimaryKey
|
||||
|
||||
@Entity(
|
||||
foreignKeys = [
|
||||
ForeignKey(
|
||||
entity = Identity::class,
|
||||
parentColumns = ["id"],
|
||||
childColumns = ["uniqueId"]
|
||||
)
|
||||
]
|
||||
tableName = "bio_table",
|
||||
)
|
||||
data class Bio(
|
||||
@PrimaryKey(autoGenerate = true) val id: Long,
|
||||
/*FK*/ val uniqueId: Long
|
||||
@PrimaryKey
|
||||
@ColumnInfo(name = "name") val name: String,
|
||||
)
|
|
@ -3,43 +3,23 @@ package com.menagerie.ophelia.database.polycule.entity
|
|||
import androidx.room.Dao
|
||||
import androidx.room.Insert
|
||||
import androidx.room.Query
|
||||
import androidx.room.Transaction
|
||||
import androidx.room.Update
|
||||
import com.menagerie.ophelia.database.polycule.CachedDao
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.count
|
||||
|
||||
@Dao
|
||||
abstract class BioDao : CachedDao<Long, Bio>() {
|
||||
abstract class BioDao {
|
||||
|
||||
@Insert
|
||||
abstract suspend fun insert(newBio: Bio): Long
|
||||
abstract suspend fun insert(newBio: Bio)
|
||||
|
||||
@Update
|
||||
abstract suspend fun update(existingBio: Bio)
|
||||
abstract suspend fun update(existingBio: Bio) : Int
|
||||
|
||||
@Query("SELECT * FROM Bio WHERE uniqueId = :uniqueId")
|
||||
abstract suspend fun findByUniqueId(uniqueId: Long): Bio?
|
||||
@Query("SELECT * FROM bio_table ORDER BY name ASC")
|
||||
abstract fun getAllAlphabetisedBios(): Flow<List<Bio>>
|
||||
|
||||
@Transaction
|
||||
open suspend fun findOrInsert(bio: Bio): Long {
|
||||
return withDaoCache {
|
||||
val key = bio.uniqueId
|
||||
val returnVal: Bio =
|
||||
get(key)
|
||||
@Query("SELECT * FROM bio_table")
|
||||
abstract fun getAllBios(): Flow<List<Bio>>
|
||||
|
||||
?: findByUniqueId(key)
|
||||
?: run {
|
||||
val newId: Long = insert(bio)
|
||||
bio.copy(id = newId)
|
||||
}
|
||||
if (bio != returnVal) {
|
||||
if (returnVal.id == 0L) {
|
||||
insert(bio)
|
||||
} else {
|
||||
update(bio)
|
||||
}
|
||||
}
|
||||
put(key, returnVal)
|
||||
returnVal.id
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,4 +2,5 @@
|
|||
plugins {
|
||||
id 'com.android.application' version '8.1.2' apply false
|
||||
id 'org.jetbrains.kotlin.android' version '1.8.10' apply false
|
||||
id 'com.google.devtools.ksp' version '1.8.10-1.0.9' apply false
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue
KSP is our main tool for connecting room to compose, but we'll never see it