Prepare for database
This commit is contained in:
parent
e5929e7086
commit
feec030726
17 changed files with 265 additions and 12 deletions
|
@ -68,6 +68,11 @@ dependencies {
|
|||
implementation(libs.androidx.material3.window.size.class1)
|
||||
implementation(libs.okhttp.sse)
|
||||
implementation(libs.androidx.datastore)
|
||||
implementation(libs.hilt.navigation.compose)
|
||||
implementation(libs.androidx.room.runtime)
|
||||
implementation(libs.androidx.room.compiler)
|
||||
implementation(libs.androidx.room.paging)
|
||||
implementation(libs.androidx.room.ktx)
|
||||
testImplementation(libs.junit)
|
||||
androidTestImplementation(libs.androidx.junit)
|
||||
androidTestImplementation(libs.androidx.espresso.core)
|
||||
|
|
|
@ -4,5 +4,4 @@ import android.app.Application
|
|||
import dagger.hilt.android.HiltAndroidApp
|
||||
|
||||
@HiltAndroidApp
|
||||
class ChatApplication : Application() {
|
||||
}
|
||||
class ChatApplication : Application()
|
|
@ -27,8 +27,8 @@ import androidx.compose.ui.input.nestedscroll.nestedScroll
|
|||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.min
|
||||
import androidx.hilt.navigation.compose.hiltViewModel
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import eu.m724.chatapp.R
|
||||
import eu.m724.chatapp.activity.chat.quick_settings.composable.ModelCard
|
||||
import eu.m724.chatapp.api.data.response.models.LanguageModel
|
||||
|
@ -38,7 +38,7 @@ fun ChatQuickSettings(
|
|||
modifier: Modifier = Modifier,
|
||||
onModelSelected: (LanguageModel) -> Unit,
|
||||
onDismiss: () -> Unit,
|
||||
viewModel: ChatQuickSettingsViewModel = viewModel(),
|
||||
viewModel: ChatQuickSettingsViewModel = hiltViewModel(),
|
||||
) {
|
||||
val uiState by viewModel.uiState.collectAsStateWithLifecycle()
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@ import androidx.compose.ui.Alignment
|
|||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import androidx.hilt.navigation.compose.hiltViewModel
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import eu.m724.chatapp.R
|
||||
import eu.m724.chatapp.activity.chat.ChatActivity
|
||||
|
@ -52,7 +52,7 @@ class MainActivity : ComponentActivity() {
|
|||
@Composable
|
||||
fun Content(
|
||||
modifier: Modifier = Modifier,
|
||||
viewModel: MainActivityViewModel = viewModel()
|
||||
viewModel: MainActivityViewModel = hiltViewModel()
|
||||
) {
|
||||
val uiState by viewModel.uiState.collectAsState()
|
||||
val context = LocalContext.current
|
||||
|
|
|
@ -5,6 +5,7 @@ import androidx.lifecycle.viewModelScope
|
|||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import eu.m724.chatapp.api.AiApiService
|
||||
import eu.m724.chatapp.store.data.Chat
|
||||
import eu.m724.chatapp.store.room.ChatDao
|
||||
import kotlinx.coroutines.channels.Channel
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
|
@ -16,7 +17,8 @@ import javax.inject.Inject
|
|||
|
||||
@HiltViewModel
|
||||
class MainActivityViewModel @Inject constructor(
|
||||
val aiApiService: AiApiService
|
||||
val aiApiService: AiApiService,
|
||||
val chatDao: ChatDao
|
||||
) : ViewModel() {
|
||||
private val _uiState = MutableStateFlow(MainActivityUiState())
|
||||
val uiState: StateFlow<MainActivityUiState> = _uiState.asStateFlow()
|
||||
|
@ -43,6 +45,8 @@ class MainActivityViewModel @Inject constructor(
|
|||
messages = emptyList()
|
||||
)
|
||||
|
||||
chatDao.insertChat()
|
||||
|
||||
_uiEvents.send(MainActivityUiEvent.StartChat(chat))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,6 +7,11 @@ import kotlinx.parcelize.Parcelize
|
|||
|
||||
@Parcelize
|
||||
data class Chat(
|
||||
/**
|
||||
* The unique identifier of this chat.
|
||||
*/
|
||||
val id: Int,
|
||||
|
||||
/**
|
||||
* The title of this chat.
|
||||
*/
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
package eu.m724.chatapp.store.proto
|
||||
|
||||
import eu.m724.chatapp.proto.Chat
|
||||
|
||||
class DataStoreModule {
|
||||
val a: Chat
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
package eu.m724.chatapp.store.proto
|
||||
|
||||
import androidx.datastore.core.Serializer
|
||||
import eu.m724.chatapp.proto.ProtoChat
|
||||
|
||||
object ProtoChatSerializer : Serializer<ProtoChat> {
|
||||
override val defaultValue: ProtoChat = Settings.getDefaultInstance()
|
||||
|
||||
override suspend fun readFrom(input: InputStream): Settings {
|
||||
try {
|
||||
return Settings.parseFrom(input)
|
||||
} catch (exception: InvalidProtocolBufferException) {
|
||||
throw CorruptionException("Cannot read proto.", exception)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun writeTo(
|
||||
t: Settings,
|
||||
output: OutputStream) = t.writeTo(output)
|
||||
}
|
30
app/src/main/java/eu/m724/chatapp/store/room/ChatDao.kt
Normal file
30
app/src/main/java/eu/m724/chatapp/store/room/ChatDao.kt
Normal file
|
@ -0,0 +1,30 @@
|
|||
package eu.m724.chatapp.store.room
|
||||
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Insert
|
||||
import androidx.room.Query
|
||||
import androidx.room.Update
|
||||
import eu.m724.chatapp.store.room.entity.ChatEntity
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
@Dao
|
||||
interface ChatDao {
|
||||
@Query("SELECT * FROM chats")
|
||||
fun getAllChats(): List<ChatEntity>
|
||||
|
||||
@Query("SELECT * FROM chats WHERE id = :id")
|
||||
fun getChatById(id: Int): ChatEntity?
|
||||
|
||||
@Query("""
|
||||
SELECT * FROM chats
|
||||
JOIN chats_fts ON chats.id = chats_fts.rowid
|
||||
WHERE chats_fts MATCH :query
|
||||
""")
|
||||
fun searchChats(query: String): Flow<List<ChatEntity>>
|
||||
|
||||
@Insert
|
||||
fun insertChat(chat: ChatEntity)
|
||||
|
||||
@Update
|
||||
fun updateChat(chat: ChatEntity)
|
||||
}
|
21
app/src/main/java/eu/m724/chatapp/store/room/MessageDao.kt
Normal file
21
app/src/main/java/eu/m724/chatapp/store/room/MessageDao.kt
Normal file
|
@ -0,0 +1,21 @@
|
|||
package eu.m724.chatapp.store.room
|
||||
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Insert
|
||||
import androidx.room.Query
|
||||
import androidx.room.Update
|
||||
import eu.m724.chatapp.store.room.entity.MessageEntity
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
@Dao
|
||||
interface MessageDao {
|
||||
@Insert
|
||||
suspend fun insertMessage(message: MessageEntity)
|
||||
|
||||
@Update
|
||||
suspend fun updateMessage(message: MessageEntity)
|
||||
|
||||
@Query("SELECT * FROM messages WHERE chatId = :chatId ORDER BY index ASC")
|
||||
fun getMessagesForChat(chatId: Int): Flow<List<MessageEntity>>
|
||||
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
package eu.m724.chatapp.store.room.database
|
||||
|
||||
import androidx.room.Database
|
||||
import androidx.room.RoomDatabase
|
||||
import eu.m724.chatapp.store.room.ChatDao
|
||||
import eu.m724.chatapp.store.room.MessageDao
|
||||
import eu.m724.chatapp.store.room.entity.ChatEntity
|
||||
import eu.m724.chatapp.store.room.entity.ChatEntityFts
|
||||
import eu.m724.chatapp.store.room.entity.MessageEntity
|
||||
|
||||
@Database(entities = [
|
||||
ChatEntity::class,
|
||||
ChatEntityFts::class,
|
||||
MessageEntity::class
|
||||
], version = 1)
|
||||
abstract class AppDatabase : RoomDatabase() {
|
||||
abstract fun chatDao(): ChatDao
|
||||
abstract fun messageDao(): MessageDao
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
package eu.m724.chatapp.store.room.database
|
||||
|
||||
import android.content.Context
|
||||
import androidx.room.Room
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import eu.m724.chatapp.store.room.ChatDao
|
||||
import eu.m724.chatapp.store.room.MessageDao
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Module
|
||||
@InstallIn(SingletonComponent::class)
|
||||
object DatabaseModule {
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideAppDatabase(@ApplicationContext context: Context): AppDatabase {
|
||||
return Room.databaseBuilder(
|
||||
context,
|
||||
AppDatabase::class.java,
|
||||
"chatapp-database"
|
||||
).build()
|
||||
}
|
||||
|
||||
@Provides
|
||||
fun provideChatDao(appDatabase: AppDatabase): ChatDao {
|
||||
return appDatabase.chatDao()
|
||||
}
|
||||
|
||||
@Provides
|
||||
fun provideMessageDao(appDatabase: AppDatabase): MessageDao {
|
||||
return appDatabase.messageDao()
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
package eu.m724.chatapp.store.room.entity
|
||||
|
||||
import androidx.room.Entity
|
||||
import androidx.room.PrimaryKey
|
||||
|
||||
@Entity(tableName = "chats")
|
||||
data class ChatEntity(
|
||||
/**
|
||||
* The unique identifier of this chat.
|
||||
*/
|
||||
@PrimaryKey(autoGenerate = true)
|
||||
val id: Int = 0,
|
||||
|
||||
/**
|
||||
* The title of this chat, null if not set.
|
||||
*/
|
||||
val title: String?,
|
||||
|
||||
/**
|
||||
* The model ID used in this chat.
|
||||
*/
|
||||
val model: String,
|
||||
)
|
|
@ -0,0 +1,13 @@
|
|||
package eu.m724.chatapp.store.room.entity
|
||||
|
||||
import androidx.room.ColumnInfo
|
||||
import androidx.room.Entity
|
||||
import androidx.room.Fts4
|
||||
|
||||
@Entity(tableName = "chats_fts")
|
||||
@Fts4
|
||||
data class ChatEntityFts(
|
||||
@ColumnInfo(name = "title")
|
||||
val title: String
|
||||
|
||||
)
|
|
@ -0,0 +1,34 @@
|
|||
package eu.m724.chatapp.store.room.entity
|
||||
|
||||
import androidx.room.Entity
|
||||
import androidx.room.Index
|
||||
import androidx.room.PrimaryKey
|
||||
|
||||
@Entity(
|
||||
tableName = "messages",
|
||||
indices = [
|
||||
Index(value = ["chatId"])
|
||||
]
|
||||
)
|
||||
data class MessageEntity(
|
||||
/**
|
||||
* The unique identifier of this message. TODO make random perhaps
|
||||
*/
|
||||
@PrimaryKey(autoGenerate = true)
|
||||
val id: Int = 0,
|
||||
|
||||
/**
|
||||
* The index of this message in the chat.
|
||||
*/
|
||||
val index: Int,
|
||||
|
||||
/**
|
||||
* The ID of the chat this message belongs to.
|
||||
*/
|
||||
val chatId: Int,
|
||||
|
||||
/**
|
||||
* The content of this message.
|
||||
*/
|
||||
val content: String
|
||||
)
|
22
app/src/main/proto/chat.proto
Normal file
22
app/src/main/proto/chat.proto
Normal file
|
@ -0,0 +1,22 @@
|
|||
syntax = "proto3";
|
||||
|
||||
option java_package = "eu.m724.chatapp.proto";
|
||||
option java_multiple_files = true;
|
||||
|
||||
enum ProtoChatMessageRole {
|
||||
User = 0;
|
||||
Assistant = 1;
|
||||
}
|
||||
|
||||
message ProtoChatMessage {
|
||||
int64 id = 1;
|
||||
string content = 2;
|
||||
ProtoChatMessageRole role = 3;
|
||||
}
|
||||
|
||||
message ProtoChat {
|
||||
int64 id = 1;
|
||||
string title = 2;
|
||||
string model_id = 3;
|
||||
repeated ProtoChatMessage messages = 4;
|
||||
}
|
|
@ -10,7 +10,8 @@ material = "1.12.0"
|
|||
lifecycleRuntimeKtx = "2.9.1"
|
||||
activityCompose = "1.10.1"
|
||||
composeBom = "2025.06.01"
|
||||
hilt = "2.56.2"
|
||||
hiltAndroid = "2.56.2"
|
||||
hiltCompiler = "2.56.2"
|
||||
ksp = "2.1.21-2.0.2"
|
||||
retrofit = "3.0.0"
|
||||
secrets = "2.0.1"
|
||||
|
@ -19,6 +20,13 @@ material3WindowSizeClass = "1.3.2"
|
|||
okhttpSse = "4.12.0"
|
||||
parcelize = "2.1.21"
|
||||
datastore = "1.1.7"
|
||||
hiltNavigationCompose = "1.2.0"
|
||||
roomRuntime = "2.7.2"
|
||||
roomCompiler = "2.7.2"
|
||||
roomPaging = "2.7.2"
|
||||
roomKtx = "2.7.2"
|
||||
pagingRuntime = "3.3.6"
|
||||
pagingCompose = "3.3.6"
|
||||
|
||||
[libraries]
|
||||
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
|
||||
|
@ -37,20 +45,27 @@ androidx-ui-tooling-preview = { group = "androidx.compose.ui", name = "ui-toolin
|
|||
androidx-ui-test-manifest = { group = "androidx.compose.ui", name = "ui-test-manifest" }
|
||||
androidx-ui-test-junit4 = { group = "androidx.compose.ui", name = "ui-test-junit4" }
|
||||
androidx-material3 = { group = "androidx.compose.material3", name = "material3" }
|
||||
hilt-android = { group = "com.google.dagger", name = "hilt-android", version.ref = "hilt" }
|
||||
hilt-compiler = { group = "com.google.dagger", name = "hilt-compiler", version.ref = "hilt" }
|
||||
hilt-android = { group = "com.google.dagger", name = "hilt-android", version.ref = "hiltAndroid" }
|
||||
hilt-compiler = { group = "com.google.dagger", name = "hilt-compiler", version.ref = "hiltCompiler" }
|
||||
retrofit = { group = "com.squareup.retrofit2", name = "retrofit", version.ref = "retrofit" }
|
||||
retrofit-converter-gson = { group = "com.squareup.retrofit2", name = "converter-gson", version.ref = "retrofit"}
|
||||
logging-interceptor = { group = "com.squareup.okhttp3", name = "logging-interceptor", version.ref = "loggingInterceptor" }
|
||||
androidx-material3-window-size-class1 = { group = "androidx.compose.material3", name = "material3-window-size-class", version.ref = "material3WindowSizeClass" }
|
||||
okhttp-sse = { group = "com.squareup.okhttp3", name = "okhttp-sse", version.ref = "okhttpSse" }
|
||||
androidx-datastore = { group = "androidx.datastore", name = "datastore", version.ref = "datastore" }
|
||||
hilt-navigation-compose = { group = "androidx.hilt", name = "hilt-navigation-compose", version.ref = "hiltNavigationCompose" }
|
||||
androidx-room-runtime = { group = "androidx.room", name = "room-runtime", version.ref = "roomRuntime" }
|
||||
androidx-room-compiler = { group = "androidx.room", name = "room-compiler", version.ref = "roomCompiler" }
|
||||
androidx-room-paging = { group = "androidx.room", name = "room-paging", version.ref = "roomPaging" }
|
||||
androidx-room-ktx = { group = "androidx.room", name = "room-ktx", version.ref = "roomKtx" }
|
||||
androidx-paging-runtime = { group = "androidx.paging", name = "paging-runtime", version.ref = "pagingRuntime" }
|
||||
androidx-paging-compose = { group = "androidx.paging", name = "paging-compose", version.ref = "pagingCompose" }
|
||||
|
||||
[plugins]
|
||||
android-application = { id = "com.android.application", version.ref = "agp" }
|
||||
kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
|
||||
kotlin-compose = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" }
|
||||
hilt-android = { id = "com.google.dagger.hilt.android", version.ref = "hilt" }
|
||||
hilt-android = { id = "com.google.dagger.hilt.android", version.ref = "hiltAndroid" }
|
||||
ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" }
|
||||
secrets = { id = "com.google.android.libraries.mapsplatform.secrets-gradle-plugin", version.ref = "secrets" }
|
||||
parcelize = { id = "org.jetbrains.kotlin.plugin.parcelize", version.ref = "parcelize" }
|
||||
parcelize = { id = "org.jetbrains.kotlin.plugin.parcelize", version.ref = "parcelize" }
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue