Skip to content

Commit 45ee7d7

Browse files
authored
VOICEC-1469: Android Jetpack compose refactor (#57)
* Wip * Use state flows * Fix android chat app * cleanup resources * Simplified Call Activity * Fix flickering UI on hold * SImplify DialerFragment * Improved Push Tokens management * Add authorization to custom backend * Fix session error handling * Bump sdk version
1 parent 2ce3316 commit 45ee7d7

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

58 files changed

+1537
-1385
lines changed

contact-center/android-chat/app/build.gradle

Lines changed: 48 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -5,26 +5,28 @@ plugins {
55
id 'com.google.gms.google-services'
66
id 'com.google.android.libraries.mapsplatform.secrets-gradle-plugin'
77
// Kotlin Serialization Plugin
8-
id 'kotlinx-serialization'
8+
id 'org.jetbrains.kotlin.plugin.serialization'
99
// Hilt Gradle Plugin
10-
id 'dagger.hilt.android.plugin'
10+
id 'com.google.dagger.hilt.android'
11+
// Kapt for annotation processing
1112
id 'kotlin-kapt'
13+
id 'org.jetbrains.kotlin.plugin.compose'
1214
}
1315

1416
android {
15-
namespace 'com.example.vonage.chatsampleapp'
16-
compileSdk 33
17+
namespace = 'com.example.vonage.chatsampleapp'
18+
compileSdk = 36
1719

1820
defaultConfig {
19-
applicationId "com.example.vonage.chatsampleapp"
20-
minSdk 23
21-
targetSdk 33
21+
applicationId = "com.example.vonage.chatsampleapp"
22+
minSdk = 23
23+
targetSdk = 36
2224
versionCode 1
2325
versionName "1.0"
2426

25-
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
27+
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
2628
vectorDrawables {
27-
useSupportLibrary true
29+
useSupportLibrary = true
2830
}
2931
}
3032

@@ -42,11 +44,8 @@ android {
4244
jvmTarget = '1.8'
4345
}
4446
buildFeatures {
45-
dataBinding = true
46-
compose true
47-
}
48-
composeOptions {
49-
kotlinCompilerExtensionVersion '1.4.3'
47+
compose = true
48+
buildConfig = true
5049
}
5150
packagingOptions {
5251
resources {
@@ -57,59 +56,61 @@ android {
5756

5857
dependencies {
5958

60-
implementation 'androidx.core:core-ktx:1.7.0'
61-
implementation 'androidx.appcompat:appcompat:1.6.1'
62-
implementation 'com.google.android.material:material:1.9.0'
63-
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
64-
implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.3.1'
65-
implementation 'androidx.activity:activity-compose:1.3.1'
66-
implementation "androidx.compose.ui:ui:$compose_ui_version"
67-
implementation "androidx.compose.ui:ui-tooling-preview:$compose_ui_version"
68-
implementation "androidx.compose.material:material:$compose_ui_version"
69-
implementation "androidx.compose.material:material-icons-extended:$compose_ui_version"
70-
testImplementation 'junit:junit:4.13.2'
71-
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
72-
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
59+
implementation 'androidx.core:core-ktx:1.17.0'
60+
implementation 'androidx.appcompat:appcompat:1.7.1'
61+
62+
// Jetpack Compose BOM
63+
implementation platform('androidx.compose:compose-bom:2025.11.00')
64+
implementation 'androidx.compose.ui:ui'
65+
implementation 'androidx.compose.ui:ui-graphics'
66+
implementation 'androidx.compose.ui:ui-tooling-preview'
67+
implementation 'androidx.compose.material3:material3'
68+
implementation 'androidx.compose.material:material-icons-extended'
69+
implementation 'androidx.activity:activity-compose:1.11.0'
70+
implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.9.4'
71+
implementation 'androidx.lifecycle:lifecycle-viewmodel-compose:2.9.4'
7372

74-
androidTestImplementation "androidx.compose.ui:ui-test-junit4:$compose_ui_version"
75-
debugImplementation "androidx.compose.ui:ui-tooling:$compose_ui_version"
76-
debugImplementation "androidx.compose.ui:ui-test-manifest:$compose_ui_version"
73+
// Compose Tooling
74+
debugImplementation 'androidx.compose.ui:ui-tooling'
75+
debugImplementation 'androidx.compose.ui:ui-test-manifest'
76+
77+
testImplementation 'junit:junit:4.13.2'
78+
androidTestImplementation 'androidx.test.ext:junit:1.3.0'
79+
androidTestImplementation 'androidx.test.espresso:espresso-core:3.7.0'
80+
androidTestImplementation platform('androidx.compose:compose-bom:2025.11.00')
81+
androidTestImplementation 'androidx.compose.ui:ui-test-junit4'
7782

7883
// Firebase
79-
implementation platform('com.google.firebase:firebase-bom:31.3.0')
80-
implementation('com.google.gms:google-services:4.3.15')
81-
implementation 'com.google.firebase:firebase-messaging-ktx:23.1.2'
84+
implementation platform('com.google.firebase:firebase-bom:34.5.0')
85+
implementation('com.google.gms:google-services:4.4.4')
86+
implementation 'com.google.firebase:firebase-messaging-ktx:24.1.2'
8287
implementation 'com.google.firebase:firebase-messaging-ktx'
8388

8489
// Vonage Client SDK
85-
implementation("com.vonage:client-sdk-chat:1.4.0")
90+
implementation("com.vonage:client-sdk-chat:2.1.3")
8691

8792
// Dagger - HILT (Dependency Injector)
88-
implementation 'com.google.dagger:hilt-android:2.45'
89-
kapt 'com.google.dagger:hilt-compiler:2.45'
93+
implementation 'com.google.dagger:hilt-android:2.57.2'
94+
kapt 'com.google.dagger:hilt-compiler:2.57.2'
9095

9196
// Constraint Layout Plugin for Compose
92-
implementation 'androidx.constraintlayout:constraintlayout-compose:1.0.1'
97+
implementation 'androidx.constraintlayout:constraintlayout-compose:1.1.1'
9398

9499
// Coil Compose (to load images)
95-
implementation 'io.coil-kt:coil-compose:2.2.2'
96-
97-
// Compose lifecycle
98-
implementation 'androidx.lifecycle:lifecycle-runtime-compose:2.6.1'
99-
implementation 'androidx.lifecycle:lifecycle-viewmodel-compose:2.6.1'
100+
implementation 'io.coil-kt:coil-compose:2.7.0'
100101

101102
// Paging
102-
implementation 'androidx.paging:paging-common-ktx:3.1.1'
103-
implementation 'androidx.paging:paging-compose:1.0.0-alpha20'
103+
implementation 'androidx.paging:paging-common-ktx:3.3.6'
104+
implementation 'androidx.paging:paging-compose:3.3.6'
104105

105106
// Kotlin Serialization
106-
implementation 'org.jetbrains.kotlinx:kotlinx-serialization-json:1.5.0'
107+
implementation 'org.jetbrains.kotlinx:kotlinx-serialization-json:1.9.0'
107108

108109
// Retrofit + Moshi (HTTP Client)
109-
def retrofit_version = "2.9.0"
110+
def retrofit_version = "3.0.0"
110111
implementation "com.squareup.retrofit2:retrofit:$retrofit_version"
111112
implementation "com.squareup.retrofit2:converter-moshi:$retrofit_version"
112-
def moshi_version = "1.12.0"
113+
def moshi_version = "1.15.2"
113114
implementation "com.squareup.moshi:moshi:$moshi_version"
114115
implementation "com.squareup.moshi:moshi-kotlin:$moshi_version"
115116
}

contact-center/android-chat/app/src/main/java/com/example/vonage/chatsampleapp/chat/ChatClientManager.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,11 @@ class ChatClientManager(
192192
is CustomConversationEvent -> "$sender has sent a custom event in the conversation ${event.conversationId}"
193193
is EphemeralConversationEvent -> "$sender has sent an ephemeral event in the conversation ${event.conversationId}"
194194
is EventDeleteConversationEvent -> "$sender has deleted event body ${event.body} in conversation ${event.conversationId}"
195+
is MessageDeliveredEvent -> "$sender message delivered in conversation ${event.conversationId}"
196+
is MessageRejectedEvent -> "$sender message rejected in conversation ${event.conversationId}"
197+
is MessageSeenEvent -> "$sender message seen in conversation ${event.conversationId}"
198+
is MessageSubmittedEvent -> "$sender message submitted in conversation ${event.conversationId}"
199+
is MessageUndeliverableEvent -> "$sender message undeliverable in conversation ${event.conversationId}"
195200
}
196201

197202
// TODO: Provide utility to parse Conversation?

contact-center/android-chat/app/src/main/java/com/example/vonage/chatsampleapp/view/AddConversationActivity.kt

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,9 @@ import androidx.compose.foundation.rememberScrollState
99
import androidx.compose.foundation.text.KeyboardActions
1010
import androidx.compose.foundation.text.KeyboardOptions
1111
import androidx.compose.foundation.verticalScroll
12-
import androidx.compose.material.*
12+
import androidx.compose.material3.*
1313
import androidx.compose.material.icons.Icons
14-
import androidx.compose.material.icons.filled.ArrowBack
14+
import androidx.compose.material.icons.automirrored.filled.ArrowBack
1515
import androidx.compose.runtime.*
1616
import androidx.compose.ui.Alignment
1717
import androidx.compose.ui.Modifier
@@ -57,6 +57,7 @@ class AddConversationActivity : ComponentActivity() {
5757
)
5858
}
5959

60+
@OptIn(ExperimentalMaterial3Api::class)
6061
@Composable
6162
fun TopAppBar(){
6263
TopAppBar(
@@ -67,7 +68,7 @@ class AddConversationActivity : ComponentActivity() {
6768
},
6869
navigationIcon = {
6970
TopAppBarActionButton(
70-
imageVector = Icons.Filled.ArrowBack,
71+
imageVector = Icons.AutoMirrored.Filled.ArrowBack,
7172
description = stringResource(R.string.arrow_back_description)
7273
){ finish() }
7374
}
@@ -137,7 +138,7 @@ class AddConversationActivity : ComponentActivity() {
137138
}
138139
Text(
139140
text = stringResource(R.string.new_conversation_label),
140-
style = MaterialTheme.typography.h6,
141+
style = MaterialTheme.typography.titleLarge,
141142
modifier = Modifier
142143
.fillMaxWidth(0.9f)
143144
.padding(top = 10.dp, bottom = 10.dp)
@@ -215,7 +216,7 @@ class AddConversationActivity : ComponentActivity() {
215216

216217
Text(
217218
text = stringResource(R.string.existing_conversation_label),
218-
style = MaterialTheme.typography.h6,
219+
style = MaterialTheme.typography.titleLarge,
219220
modifier = Modifier
220221
.fillMaxWidth(0.9f)
221222
.padding(top = 10.dp, bottom = 10.dp)

contact-center/android-chat/app/src/main/java/com/example/vonage/chatsampleapp/view/ChatActivity.kt

Lines changed: 28 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,18 @@ import androidx.compose.foundation.clickable
88
import androidx.compose.foundation.layout.*
99
import androidx.compose.foundation.shape.CircleShape
1010
import androidx.compose.foundation.shape.RoundedCornerShape
11-
import androidx.compose.material.*
11+
import androidx.compose.material3.*
1212
import androidx.compose.material.icons.Icons
13-
import androidx.compose.material.icons.filled.ArrowBack
13+
import androidx.compose.material.icons.automirrored.filled.ArrowBack
14+
import androidx.compose.material.icons.automirrored.filled.Send
1415
import androidx.compose.material.icons.filled.MoreVert
15-
import androidx.compose.material.icons.filled.Send
1616
import androidx.compose.runtime.*
1717
import androidx.compose.ui.Modifier
1818
import androidx.compose.ui.draw.clip
1919
import androidx.compose.ui.res.stringResource
2020
import androidx.compose.ui.tooling.preview.Preview
2121
import androidx.compose.ui.unit.dp
22+
import androidx.core.view.WindowCompat
2223
import androidx.lifecycle.Lifecycle
2324
import androidx.lifecycle.lifecycleScope
2425
import androidx.lifecycle.repeatOnLifecycle
@@ -46,6 +47,8 @@ class ChatActivity : ComponentActivity() {
4647
}
4748
override fun onCreate(savedInstanceState: Bundle?) {
4849
super.onCreate(savedInstanceState)
50+
// Enable edge-to-edge and handle IME insets properly
51+
WindowCompat.setDecorFitsSystemWindows(window, false)
4952
subscribeToEvents()
5053
setContent {
5154
ChatSampleAppTheme {
@@ -68,9 +71,12 @@ class ChatActivity : ComponentActivity() {
6871
newEventsList: List<ConversationEvent>
6972
){
7073
Scaffold(
74+
modifier = Modifier.fillMaxSize(),
7175
topBar = { TopAppBar(conversationName, hasJoinedConversation) },
72-
content = { padding -> ChatView(padding, hasJoinedConversation, username, eventsList, newEventsList) },
73-
)
76+
contentWindowInsets = WindowInsets(0, 0, 0, 0)
77+
) { padding ->
78+
ChatView(padding, hasJoinedConversation, username, eventsList, newEventsList)
79+
}
7480
}
7581

7682
@Composable
@@ -89,7 +95,9 @@ class ChatActivity : ComponentActivity() {
8995
modifier = Modifier
9096
.padding(padding)
9197
.padding(start = 20.dp, end = 20.dp, top = 10.dp, bottom = 10.dp)
92-
.fillMaxSize(),
98+
.fillMaxSize()
99+
.imePadding()
100+
.navigationBarsPadding(),
93101
verticalArrangement = Arrangement.SpaceBetween
94102
) {
95103
EventsList(
@@ -113,7 +121,7 @@ class ChatActivity : ComponentActivity() {
113121
maxLines = 6,
114122
trailingIcon = {
115123
Icon(
116-
imageVector = Icons.Default.Send,
124+
imageVector = Icons.AutoMirrored.Filled.Send,
117125
contentDescription = stringResource(R.string.send_message_text),
118126
modifier = Modifier
119127
.clip(CircleShape)
@@ -157,6 +165,7 @@ class ChatActivity : ComponentActivity() {
157165
}
158166
}
159167

168+
@OptIn(ExperimentalMaterial3Api::class)
160169
@Composable
161170
fun TopAppBar(conversationName: String, hasJoinedConversation: Boolean){
162171
var showMenu by remember { mutableStateOf(false) }
@@ -170,7 +179,7 @@ class ChatActivity : ComponentActivity() {
170179
},
171180
navigationIcon = {
172181
TopAppBarActionButton(
173-
imageVector = Icons.Filled.ArrowBack,
182+
imageVector = Icons.AutoMirrored.Filled.ArrowBack,
174183
description = stringResource(R.string.arrow_back_description)
175184
) { finish() }
176185
},
@@ -185,16 +194,18 @@ class ChatActivity : ComponentActivity() {
185194
expanded = showMenu,
186195
onDismissRequest = { showMenu = false }
187196
) {
188-
DropdownMenuItem(onClick = {
189-
navigateToDetailsActivity(viewModel.intentExtras())
190-
showMenu = false
191-
}) {
192-
Text(stringResource(R.string.conversation_details_text))
193-
}
194-
if(hasJoinedConversation){
195-
DropdownMenuItem(onClick = { showDialog = true }) {
196-
Text(stringResource(R.string.leave_conversation_text))
197+
DropdownMenuItem(
198+
text = { Text(stringResource(R.string.conversation_details_text)) },
199+
onClick = {
200+
navigateToDetailsActivity(viewModel.intentExtras())
201+
showMenu = false
197202
}
203+
)
204+
if(hasJoinedConversation){
205+
DropdownMenuItem(
206+
text = { Text(stringResource(R.string.leave_conversation_text)) },
207+
onClick = { showDialog = true }
208+
)
198209
}
199210
}
200211
if(showDialog){

0 commit comments

Comments
 (0)