Start integration with app: adds Hilt for dep injection, implements a view model
This commit is contained in:
2
.idea/compiler.xml
generated
2
.idea/compiler.xml
generated
@@ -1,6 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="CompilerConfiguration">
|
<component name="CompilerConfiguration">
|
||||||
<bytecodeTargetLevel target="17" />
|
<bytecodeTargetLevel target="1.8" />
|
||||||
</component>
|
</component>
|
||||||
</project>
|
</project>
|
||||||
2
.idea/kotlinc.xml
generated
2
.idea/kotlinc.xml
generated
@@ -1,6 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="KotlinJpsPluginSettings">
|
<component name="KotlinJpsPluginSettings">
|
||||||
<option name="version" value="1.9.0" />
|
<option name="version" value="1.8.22" />
|
||||||
</component>
|
</component>
|
||||||
</project>
|
</project>
|
||||||
3
.idea/misc.xml
generated
3
.idea/misc.xml
generated
@@ -1,6 +1,7 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="ExternalStorageConfigurationManager" enabled="true" />
|
<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" />
|
<output url="file://$PROJECT_DIR$/build/classes" />
|
||||||
</component>
|
</component>
|
||||||
<component name="ProjectType">
|
<component name="ProjectType">
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
plugins {
|
plugins {
|
||||||
id 'com.android.application'
|
id 'com.android.application'
|
||||||
id 'org.jetbrains.kotlin.android'
|
id 'org.jetbrains.kotlin.android'
|
||||||
|
id 'kotlin-kapt'
|
||||||
|
id 'com.google.dagger.hilt.android'
|
||||||
}
|
}
|
||||||
|
|
||||||
android {
|
android {
|
||||||
@@ -31,24 +33,31 @@ android {
|
|||||||
targetCompatibility JavaVersion.VERSION_1_8
|
targetCompatibility JavaVersion.VERSION_1_8
|
||||||
}
|
}
|
||||||
kotlinOptions {
|
kotlinOptions {
|
||||||
jvmTarget = '1.8'
|
jvmTarget = JavaVersion.VERSION_1_8.toString()
|
||||||
}
|
}
|
||||||
buildFeatures {
|
buildFeatures {
|
||||||
compose true
|
compose true
|
||||||
}
|
}
|
||||||
composeOptions {
|
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 {
|
packagingOptions {
|
||||||
resources {
|
resources {
|
||||||
excludes += '/META-INF/{AL2.0,LGPL2.1}'
|
excludes += '/META-INF/{AL2.0,LGPL2.1}'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
buildToolsVersion '33.0.1'
|
||||||
|
}
|
||||||
|
|
||||||
|
kotlin {
|
||||||
|
jvmToolchain(8)
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation 'androidx.compose.material3:material3:1.1.1'
|
implementation "androidx.compose.material3:material3:1.1.1"
|
||||||
implementation 'androidx.core:core-ktx:1.10.1'
|
implementation "androidx.core:core-ktx:${kotlin_version}"
|
||||||
|
|
||||||
// Kordophone lib
|
// Kordophone lib
|
||||||
implementation project(':backend')
|
implementation project(':backend')
|
||||||
@@ -73,14 +82,23 @@ dependencies {
|
|||||||
// Jetpack Compose Integration
|
// Jetpack Compose Integration
|
||||||
implementation "androidx.navigation:navigation-compose:$nav_version"
|
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.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.ui:ui:1.4.3"
|
||||||
implementation 'androidx.compose.material:material:1.4.3'
|
implementation 'androidx.compose.material:material:1.4.3'
|
||||||
implementation "androidx.compose.foundation:foundation: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
|
||||||
}
|
}
|
||||||
@@ -12,6 +12,7 @@
|
|||||||
android:supportsRtl="true"
|
android:supportsRtl="true"
|
||||||
android:theme="@style/Theme.KordophoneDroid"
|
android:theme="@style/Theme.KordophoneDroid"
|
||||||
android:name=".KordophoneApplication"
|
android:name=".KordophoneApplication"
|
||||||
|
android:networkSecurityConfig="@xml/network_security_config"
|
||||||
tools:targetApi="31">
|
tools:targetApi="31">
|
||||||
<activity
|
<activity
|
||||||
android:name=".MainActivity"
|
android:name=".MainActivity"
|
||||||
|
|||||||
25
app/src/main/java/net/buzzert/kordophonedroid/AppModule.kt
Normal file
25
app/src/main/java/net/buzzert/kordophonedroid/AppModule.kt
Normal 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)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,9 +1,11 @@
|
|||||||
package net.buzzert.kordophonedroid
|
package net.buzzert.kordophonedroid
|
||||||
|
|
||||||
import android.app.Application
|
import android.app.Application
|
||||||
|
import dagger.hilt.android.HiltAndroidApp
|
||||||
import net.buzzert.kordophonedroid.data.AppContainer
|
import net.buzzert.kordophonedroid.data.AppContainer
|
||||||
import net.buzzert.kordophonedroid.data.AppContainerImpl
|
import net.buzzert.kordophonedroid.data.AppContainerImpl
|
||||||
|
|
||||||
|
@HiltAndroidApp
|
||||||
class KordophoneApplication : Application() {
|
class KordophoneApplication : Application() {
|
||||||
lateinit var container: AppContainer
|
lateinit var container: AppContainer
|
||||||
|
|
||||||
|
|||||||
@@ -3,9 +3,11 @@ package net.buzzert.kordophonedroid
|
|||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import androidx.activity.ComponentActivity
|
import androidx.activity.ComponentActivity
|
||||||
import androidx.activity.compose.setContent
|
import androidx.activity.compose.setContent
|
||||||
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
import net.buzzert.kordophonedroid.data.AppContainerImpl
|
import net.buzzert.kordophonedroid.data.AppContainerImpl
|
||||||
import net.buzzert.kordophonedroid.ui.KordophoneApp
|
import net.buzzert.kordophonedroid.ui.KordophoneApp
|
||||||
|
|
||||||
|
@AndroidEntryPoint
|
||||||
class MainActivity : ComponentActivity() {
|
class MainActivity : ComponentActivity() {
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
|||||||
@@ -1,10 +1,18 @@
|
|||||||
package net.buzzert.kordophonedroid.data
|
package net.buzzert.kordophonedroid.data
|
||||||
|
|
||||||
interface AppContainer {
|
import androidx.lifecycle.ViewModelStore
|
||||||
val something: String
|
import androidx.lifecycle.ViewModelStoreOwner
|
||||||
|
import net.buzzert.kordophone.backend.server.ChatRepository
|
||||||
|
|
||||||
|
interface AppContainer: ViewModelStoreOwner {
|
||||||
|
val repository: ChatRepository
|
||||||
}
|
}
|
||||||
|
|
||||||
class AppContainerImpl() : AppContainer {
|
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")
|
get() = TODO("Not yet implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ fun KordophoneApp(
|
|||||||
startDestination = Destination.ConversationList.route,
|
startDestination = Destination.ConversationList.route,
|
||||||
) {
|
) {
|
||||||
composable(route = Destination.ConversationList.route) {
|
composable(route = Destination.ConversationList.route) {
|
||||||
ConversationListScreen(onMessageSelected = {
|
ConversationListScreen(onConversationSelected = {
|
||||||
navController.navigate(Destination.MessageList.createRoute(it))
|
navController.navigate(Destination.MessageList.createRoute(it))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,8 @@ import androidx.compose.material.*
|
|||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.rounded.Info
|
import androidx.compose.material.icons.rounded.Info
|
||||||
import androidx.compose.runtime.Composable
|
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.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.text.TextStyle
|
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.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.unit.sp
|
import androidx.compose.ui.unit.sp
|
||||||
|
import androidx.hilt.navigation.compose.hiltViewModel
|
||||||
|
import net.buzzert.kordophone.backend.model.Conversation
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun ConversationListScreen(
|
fun ConversationListScreen(
|
||||||
onMessageSelected: (conversationID: String) -> Unit
|
viewModel: ConversationListViewModel = hiltViewModel(),
|
||||||
|
onConversationSelected: (conversationID: String) -> Unit
|
||||||
) {
|
) {
|
||||||
val convos = ArrayList<String>()
|
val conversations by viewModel.conversations.collectAsState(initial = listOf())
|
||||||
for (i in 0..200) {
|
ConversationListView(conversations = conversations, onConversationSelected = onConversationSelected)
|
||||||
convos += "Test"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun ConversationListView(
|
||||||
|
conversations: List<Conversation>,
|
||||||
|
onConversationSelected: (conversationID: String) -> Unit
|
||||||
|
) {
|
||||||
|
|
||||||
val listState = rememberLazyListState()
|
val listState = rememberLazyListState()
|
||||||
|
|
||||||
Scaffold(
|
Scaffold(
|
||||||
@@ -42,12 +51,12 @@ fun ConversationListScreen(
|
|||||||
}
|
}
|
||||||
) {
|
) {
|
||||||
LazyColumn(state = listState, modifier = Modifier.padding(it)) {
|
LazyColumn(state = listState, modifier = Modifier.padding(it)) {
|
||||||
items(convos) { conversation ->
|
items(conversations) { conversation ->
|
||||||
ConversationListItem(
|
ConversationListItem(
|
||||||
name = "James Magahern",
|
name = conversation.formattedDisplayName(),
|
||||||
id = "asdf",
|
id = conversation.guid,
|
||||||
isUnread = false,
|
isUnread = conversation.unreadCount > 0,
|
||||||
onClick = { onMessageSelected("asdf") }
|
onClick = { onConversationSelected(conversation.guid) }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -137,5 +146,5 @@ fun ConversationListItemPreview() {
|
|||||||
@Preview
|
@Preview
|
||||||
@Composable
|
@Composable
|
||||||
fun ConversationListScreenPreview() {
|
fun ConversationListScreenPreview() {
|
||||||
ConversationListScreen(onMessageSelected = {})
|
ConversationListScreen(onConversationSelected = {})
|
||||||
}
|
}
|
||||||
@@ -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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
6
app/src/main/res/xml/network_security_config.xml
Normal file
6
app/src/main/res/xml/network_security_config.xml
Normal 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>
|
||||||
@@ -27,7 +27,7 @@ android {
|
|||||||
targetCompatibility JavaVersion.VERSION_1_8
|
targetCompatibility JavaVersion.VERSION_1_8
|
||||||
}
|
}
|
||||||
kotlinOptions {
|
kotlinOptions {
|
||||||
jvmTarget = '1.8'
|
jvmTarget = JavaVersion.VERSION_1_8.toString()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -48,7 +48,7 @@ dependencies {
|
|||||||
implementation 'com.google.code.gson:gson:2.9.0'
|
implementation 'com.google.code.gson:gson:2.9.0'
|
||||||
|
|
||||||
// Realm
|
// 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
|
// 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'
|
implementation group: 'org.jetbrains.kotlinx', name: 'kotlinx-coroutines-core', version: '1.7.3', ext: 'pom'
|
||||||
|
|||||||
@@ -27,6 +27,11 @@ data class Conversation(
|
|||||||
@SerializedName("lastMessage")
|
@SerializedName("lastMessage")
|
||||||
var lastMessage: Message?,
|
var lastMessage: Message?,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
|
fun formattedDisplayName(): String {
|
||||||
|
return displayName ?: participants.joinToString(", ")
|
||||||
|
}
|
||||||
|
|
||||||
override fun equals(other: Any?): Boolean {
|
override fun equals(other: Any?): Boolean {
|
||||||
if (other == null || javaClass != other.javaClass) return false
|
if (other == null || javaClass != other.javaClass) return false
|
||||||
|
|
||||||
@@ -39,4 +44,15 @@ data class Conversation(
|
|||||||
unreadCount == o.unreadCount
|
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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ import retrofit2.Response
|
|||||||
import java.util.Date
|
import java.util.Date
|
||||||
import java.util.UUID
|
import java.util.UUID
|
||||||
|
|
||||||
|
@OptIn(ExperimentalStdlibApi::class)
|
||||||
class MockServer {
|
class MockServer {
|
||||||
val version = "Kordophone-2.0"
|
val version = "Kordophone-2.0"
|
||||||
val conversations: MutableList<Conversation> = mutableListOf()
|
val conversations: MutableList<Conversation> = mutableListOf()
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
buildscript {
|
buildscript {
|
||||||
ext {
|
ext {
|
||||||
|
kotlin_version = '1.8.22'
|
||||||
|
realm_version = '1.10.0'
|
||||||
|
hilt_version = '2.44'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -7,6 +10,7 @@ buildscript {
|
|||||||
plugins {
|
plugins {
|
||||||
id 'com.android.application' version '8.0.2' apply false
|
id 'com.android.application' version '8.0.2' apply false
|
||||||
id 'com.android.library' 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 'org.jetbrains.kotlin.android' version "${kotlin_version}" apply false
|
||||||
id 'io.realm.kotlin' version '1.10.0' apply false
|
id 'io.realm.kotlin' version "${realm_version}" apply false
|
||||||
|
id 'com.google.dagger.hilt.android' version "${hilt_version}" apply false
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user