Private
Public Access
1
0

Start integration with app: adds Hilt for dep injection, implements a view model

This commit is contained in:
2023-08-17 00:37:11 -07:00
parent 28f2bfe580
commit 4eef98aef4
17 changed files with 149 additions and 32 deletions

2
.idea/compiler.xml generated
View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CompilerConfiguration">
<bytecodeTargetLevel target="17" />
<bytecodeTargetLevel target="1.8" />
</component>
</project>

2
.idea/kotlinc.xml generated
View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="KotlinJpsPluginSettings">
<option name="version" value="1.9.0" />
<option name="version" value="1.8.22" />
</component>
</project>

3
.idea/misc.xml generated
View File

@@ -1,6 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="ProjectRootManager" version="2" languageLevel="JDK_17" project-jdk-name="jbr-17" project-jdk-type="JavaSDK">
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" project-jdk-name="jbr-17" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/build/classes" />
</component>
<component name="ProjectType">

View File

@@ -1,6 +1,8 @@
plugins {
id 'com.android.application'
id 'org.jetbrains.kotlin.android'
id 'kotlin-kapt'
id 'com.google.dagger.hilt.android'
}
android {
@@ -31,24 +33,31 @@ android {
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = '1.8'
jvmTarget = JavaVersion.VERSION_1_8.toString()
}
buildFeatures {
compose true
}
composeOptions {
kotlinCompilerExtensionVersion '1.5.0'
// Note: this is strictly tied to a kotlin version, but isn't the version of kotlin exactly.
// See: https://developer.android.com/jetpack/androidx/releases/compose-kotlin
kotlinCompilerExtensionVersion '1.4.8'
}
packagingOptions {
resources {
excludes += '/META-INF/{AL2.0,LGPL2.1}'
}
}
buildToolsVersion '33.0.1'
}
kotlin {
jvmToolchain(8)
}
dependencies {
implementation 'androidx.compose.material3:material3:1.1.1'
implementation 'androidx.core:core-ktx:1.10.1'
implementation "androidx.compose.material3:material3:1.1.1"
implementation "androidx.core:core-ktx:${kotlin_version}"
// Kordophone lib
implementation project(':backend')
@@ -73,14 +82,23 @@ dependencies {
// Jetpack Compose Integration
implementation "androidx.navigation:navigation-compose:$nav_version"
implementation 'androidx.core:core-ktx:1.10.1'
implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.3.1'
implementation 'androidx.activity:activity-compose:1.4.3'
implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.6.1'
implementation 'androidx.lifecycle:lifecycle-viewmodel-compose:2.6.1'
implementation "androidx.compose.ui:ui:1.4.3"
implementation 'androidx.compose.material:material:1.4.3'
implementation "androidx.compose.foundation:foundation:1.4.3"
debugImplementation 'androidx.compose.ui:ui-tooling:1.4.3'
// Hilt (dependency injection)
implementation "com.google.dagger:hilt-android:${hilt_version}"
implementation "androidx.hilt:hilt-navigation-compose:1.0.0"
kapt "com.google.dagger:hilt-compiler:${hilt_version}"
debugImplementation 'androidx.compose.ui:ui-tooling:1.4.3'
}
// Allow references to generated code
kapt {
correctErrorTypes true
}

View File

@@ -12,6 +12,7 @@
android:supportsRtl="true"
android:theme="@style/Theme.KordophoneDroid"
android:name=".KordophoneApplication"
android:networkSecurityConfig="@xml/network_security_config"
tools:targetApi="31">
<activity
android:name=".MainActivity"

View File

@@ -0,0 +1,25 @@
package net.buzzert.kordophonedroid
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import net.buzzert.kordophone.backend.db.CachedChatDatabase
import net.buzzert.kordophone.backend.server.ChatRepository
import net.buzzert.kordophone.backend.server.RetrofitAPIClient
import java.net.URL
import javax.inject.Singleton
@Module
@InstallIn(SingletonComponent::class)
object AppModule {
@Singleton
@Provides
fun provideChatRepository(): ChatRepository {
val host = "http://192.168.1.123:5738"
val client = RetrofitAPIClient(URL(host))
val apiInterface = client.getAPIInterface()
val database = CachedChatDatabase.liveDatabase()
return ChatRepository(apiInterface, database)
}
}

View File

@@ -1,9 +1,11 @@
package net.buzzert.kordophonedroid
import android.app.Application
import dagger.hilt.android.HiltAndroidApp
import net.buzzert.kordophonedroid.data.AppContainer
import net.buzzert.kordophonedroid.data.AppContainerImpl
@HiltAndroidApp
class KordophoneApplication : Application() {
lateinit var container: AppContainer

View File

@@ -3,9 +3,11 @@ package net.buzzert.kordophonedroid
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import dagger.hilt.android.AndroidEntryPoint
import net.buzzert.kordophonedroid.data.AppContainerImpl
import net.buzzert.kordophonedroid.ui.KordophoneApp
@AndroidEntryPoint
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)

View File

@@ -1,10 +1,18 @@
package net.buzzert.kordophonedroid.data
interface AppContainer {
val something: String
import androidx.lifecycle.ViewModelStore
import androidx.lifecycle.ViewModelStoreOwner
import net.buzzert.kordophone.backend.server.ChatRepository
interface AppContainer: ViewModelStoreOwner {
val repository: ChatRepository
}
class AppContainerImpl() : AppContainer {
override val something: String
override val repository: ChatRepository
get() = TODO("Not yet implemented")
override val viewModelStore: ViewModelStore
get() = TODO("Not yet implemented")
}

View File

@@ -30,7 +30,7 @@ fun KordophoneApp(
startDestination = Destination.ConversationList.route,
) {
composable(route = Destination.ConversationList.route) {
ConversationListScreen(onMessageSelected = {
ConversationListScreen(onConversationSelected = {
navController.navigate(Destination.MessageList.createRoute(it))
})
}

View File

@@ -11,7 +11,8 @@ import androidx.compose.material.*
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.rounded.Info
import androidx.compose.runtime.Composable
import androidx.compose.runtime.ComposeCompilerApi
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.TextStyle
@@ -20,16 +21,24 @@ import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.hilt.navigation.compose.hiltViewModel
import net.buzzert.kordophone.backend.model.Conversation
@Composable
fun ConversationListScreen(
onMessageSelected: (conversationID: String) -> Unit
viewModel: ConversationListViewModel = hiltViewModel(),
onConversationSelected: (conversationID: String) -> Unit
) {
val convos = ArrayList<String>()
for (i in 0..200) {
convos += "Test"
val conversations by viewModel.conversations.collectAsState(initial = listOf())
ConversationListView(conversations = conversations, onConversationSelected = onConversationSelected)
}
@Composable
fun ConversationListView(
conversations: List<Conversation>,
onConversationSelected: (conversationID: String) -> Unit
) {
val listState = rememberLazyListState()
Scaffold(
@@ -42,12 +51,12 @@ fun ConversationListScreen(
}
) {
LazyColumn(state = listState, modifier = Modifier.padding(it)) {
items(convos) { conversation ->
items(conversations) { conversation ->
ConversationListItem(
name = "James Magahern",
id = "asdf",
isUnread = false,
onClick = { onMessageSelected("asdf") }
name = conversation.formattedDisplayName(),
id = conversation.guid,
isUnread = conversation.unreadCount > 0,
onClick = { onConversationSelected(conversation.guid) }
)
}
}
@@ -137,5 +146,5 @@ fun ConversationListItemPreview() {
@Preview
@Composable
fun ConversationListScreenPreview() {
ConversationListScreen(onMessageSelected = {})
ConversationListScreen(onConversationSelected = {})
}

View File

@@ -0,0 +1,24 @@
package net.buzzert.kordophonedroid.ui.conversationlist
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.launch
import net.buzzert.kordophone.backend.model.Conversation
import net.buzzert.kordophone.backend.server.ChatRepository
import javax.inject.Inject
@HiltViewModel
class ConversationListViewModel @Inject constructor(
private val repository: ChatRepository
) : ViewModel() {
val conversations: Flow<List<Conversation>>
get() = repository.conversationChanges
init {
viewModelScope.launch {
repository.synchronize()
}
}
}

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<domain-config cleartextTrafficPermitted="true">
<domain includeSubdomains="true">192.168.1.123</domain>
</domain-config>
</network-security-config>

View File

@@ -27,7 +27,7 @@ android {
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = '1.8'
jvmTarget = JavaVersion.VERSION_1_8.toString()
}
}
@@ -48,7 +48,7 @@ dependencies {
implementation 'com.google.code.gson:gson:2.9.0'
// Realm
implementation 'io.realm.kotlin:library-base:1.10.0'
implementation "io.realm.kotlin:library-base:${realm_version}"
// https://mvnrepository.com/artifact/org.jetbrains.kotlinx/kotlinx-coroutines-core
implementation group: 'org.jetbrains.kotlinx', name: 'kotlinx-coroutines-core', version: '1.7.3', ext: 'pom'

View File

@@ -27,6 +27,11 @@ data class Conversation(
@SerializedName("lastMessage")
var lastMessage: Message?,
) {
fun formattedDisplayName(): String {
return displayName ?: participants.joinToString(", ")
}
override fun equals(other: Any?): Boolean {
if (other == null || javaClass != other.javaClass) return false
@@ -39,4 +44,15 @@ data class Conversation(
unreadCount == o.unreadCount
)
}
override fun hashCode(): Int {
var result = guid.hashCode()
result = 31 * result + date.hashCode()
result = 31 * result + participants.hashCode()
result = 31 * result + (displayName?.hashCode() ?: 0)
result = 31 * result + unreadCount
result = 31 * result + (lastMessagePreview?.hashCode() ?: 0)
result = 31 * result + (lastMessage?.hashCode() ?: 0)
return result
}
}

View File

@@ -30,6 +30,7 @@ import retrofit2.Response
import java.util.Date
import java.util.UUID
@OptIn(ExperimentalStdlibApi::class)
class MockServer {
val version = "Kordophone-2.0"
val conversations: MutableList<Conversation> = mutableListOf()

View File

@@ -1,5 +1,8 @@
buildscript {
ext {
kotlin_version = '1.8.22'
realm_version = '1.10.0'
hilt_version = '2.44'
}
}
@@ -7,6 +10,7 @@ buildscript {
plugins {
id 'com.android.application' version '8.0.2' apply false
id 'com.android.library' version '8.0.2' apply false
id 'org.jetbrains.kotlin.android' version '1.9.0' apply false
id 'io.realm.kotlin' version '1.10.0' apply false
id 'org.jetbrains.kotlin.android' version "${kotlin_version}" apply false
id 'io.realm.kotlin' version "${realm_version}" apply false
id 'com.google.dagger.hilt.android' version "${hilt_version}" apply false
}