diff --git a/.idea/compiler.xml b/.idea/compiler.xml
index b589d56..61a9130 100644
--- a/.idea/compiler.xml
+++ b/.idea/compiler.xml
@@ -1,6 +1,6 @@
-
+
\ No newline at end of file
diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml
index fdf8d99..9a55c2d 100644
--- a/.idea/kotlinc.xml
+++ b/.idea/kotlinc.xml
@@ -1,6 +1,6 @@
-
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
index 773fe0f..e7b1341 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -1,6 +1,7 @@
+
-
+
diff --git a/app/build.gradle b/app/build.gradle
index f0c7a9b..27780a9 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -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}"
-}
\ No newline at end of file
+ debugImplementation 'androidx.compose.ui:ui-tooling:1.4.3'
+}
+
+// Allow references to generated code
+kapt {
+ correctErrorTypes true
+}
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 5ad0368..b7a30fc 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -12,6 +12,7 @@
android:supportsRtl="true"
android:theme="@style/Theme.KordophoneDroid"
android:name=".KordophoneApplication"
+ android:networkSecurityConfig="@xml/network_security_config"
tools:targetApi="31">
Unit
+ viewModel: ConversationListViewModel = hiltViewModel(),
+ onConversationSelected: (conversationID: String) -> Unit
+) {
+ val conversations by viewModel.conversations.collectAsState(initial = listOf())
+ ConversationListView(conversations = conversations, onConversationSelected = onConversationSelected)
+}
+
+@Composable
+fun ConversationListView(
+ conversations: List,
+ onConversationSelected: (conversationID: String) -> Unit
) {
- val convos = ArrayList()
- for (i in 0..200) {
- convos += "Test"
- }
val listState = rememberLazyListState()
@@ -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 = {})
}
\ No newline at end of file
diff --git a/app/src/main/java/net/buzzert/kordophonedroid/ui/conversationlist/ConversationListViewModel.kt b/app/src/main/java/net/buzzert/kordophonedroid/ui/conversationlist/ConversationListViewModel.kt
new file mode 100644
index 0000000..f79276a
--- /dev/null
+++ b/app/src/main/java/net/buzzert/kordophonedroid/ui/conversationlist/ConversationListViewModel.kt
@@ -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>
+ get() = repository.conversationChanges
+
+ init {
+ viewModelScope.launch {
+ repository.synchronize()
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/res/xml/network_security_config.xml b/app/src/main/res/xml/network_security_config.xml
new file mode 100644
index 0000000..5289581
--- /dev/null
+++ b/app/src/main/res/xml/network_security_config.xml
@@ -0,0 +1,6 @@
+
+
+
+ 192.168.1.123
+
+
\ No newline at end of file
diff --git a/backend/build.gradle b/backend/build.gradle
index b66ebea..853d470 100644
--- a/backend/build.gradle
+++ b/backend/build.gradle
@@ -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'
diff --git a/backend/src/main/java/net/buzzert/kordophone/backend/model/Conversation.kt b/backend/src/main/java/net/buzzert/kordophone/backend/model/Conversation.kt
index d03b0b6..dbad24b 100644
--- a/backend/src/main/java/net/buzzert/kordophone/backend/model/Conversation.kt
+++ b/backend/src/main/java/net/buzzert/kordophone/backend/model/Conversation.kt
@@ -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
+ }
}
diff --git a/backend/src/test/java/net/buzzert/kordophone/backend/MockServer.kt b/backend/src/test/java/net/buzzert/kordophone/backend/MockServer.kt
index 8f1c012..a803a15 100644
--- a/backend/src/test/java/net/buzzert/kordophone/backend/MockServer.kt
+++ b/backend/src/test/java/net/buzzert/kordophone/backend/MockServer.kt
@@ -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 = mutableListOf()
diff --git a/build.gradle b/build.gradle
index 524cf5e..5d66039 100644
--- a/build.gradle
+++ b/build.gradle
@@ -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
}
\ No newline at end of file