Merge pull request #4011 from nextcloud/contacts_theming

Contacts theming
This commit is contained in:
Marcel Hibbe 2024-08-09 15:51:13 +02:00 коммит произвёл GitHub
Родитель a9593f25b6 4508cbb0aa
Коммит 85b94d679b
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: B5690EEEBB952194
16 изменённых файлов: 555 добавлений и 115 удалений

Просмотреть файл

@ -158,6 +158,8 @@ ext {
workVersion = "2.9.1" workVersion = "2.9.1"
espressoVersion = "3.6.1" espressoVersion = "3.6.1"
media3_version = "1.4.0" media3_version = "1.4.0"
coroutines_version = "1.3.9"
mockitoKotlinVersion = "4.1.0"
} }
configurations.configureEach { configurations.configureEach {
@ -333,6 +335,14 @@ dependencies {
implementation "com.google.dagger:hilt-android:$hilt_version" implementation "com.google.dagger:hilt-android:$hilt_version"
kapt "com.google.dagger:hilt-android-compiler:$hilt_version" kapt "com.google.dagger:hilt-android-compiler:$hilt_version"
implementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.8.3")
testImplementation("junit:junit:4.13.2")
androidTestImplementation(platform("androidx.compose:compose-bom:2024.06.00"))
androidTestImplementation("androidx.compose.ui:ui-test-junit4")
testImplementation "org.mockito.kotlin:mockito-kotlin:$mockitoKotlinVersion"
testImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:$coroutines_version"
} }
tasks.register('installGitHooks', Copy) { tasks.register('installGitHooks', Copy) {

Просмотреть файл

@ -13,10 +13,8 @@ import android.content.Context
import android.content.Intent import android.content.Intent
import android.os.Bundle import android.os.Bundle
import android.util.Log import android.util.Log
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent import androidx.activity.compose.setContent
import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.Image
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.clickable import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
@ -35,6 +33,7 @@ import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items import androidx.compose.foundation.lazy.items
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.ArrowBack import androidx.compose.material.icons.automirrored.filled.ArrowBack
import androidx.compose.material.icons.automirrored.filled.List
import androidx.compose.material.icons.filled.Search import androidx.compose.material.icons.filled.Search
import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3Api
@ -61,9 +60,8 @@ import androidx.compose.ui.unit.sp
import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.ViewModelProvider
import autodagger.AutoInjector import autodagger.AutoInjector
import coil.compose.AsyncImage import coil.compose.AsyncImage
import coil.request.ImageRequest
import coil.transform.CircleCropTransformation
import com.nextcloud.talk.R import com.nextcloud.talk.R
import com.nextcloud.talk.activities.BaseActivity
import com.nextcloud.talk.application.NextcloudTalkApplication import com.nextcloud.talk.application.NextcloudTalkApplication
import com.nextcloud.talk.chat.ChatActivity import com.nextcloud.talk.chat.ChatActivity
import com.nextcloud.talk.models.json.autocomplete.AutocompleteUser import com.nextcloud.talk.models.json.autocomplete.AutocompleteUser
@ -72,7 +70,7 @@ import com.nextcloud.talk.utils.bundle.BundleKeys
import javax.inject.Inject import javax.inject.Inject
@AutoInjector(NextcloudTalkApplication::class) @AutoInjector(NextcloudTalkApplication::class)
class ContactsActivityCompose : ComponentActivity() { class ContactsActivityCompose : BaseActivity() {
@Inject @Inject
lateinit var viewModelFactory: ViewModelProvider.Factory lateinit var viewModelFactory: ViewModelProvider.Factory
@ -83,9 +81,12 @@ class ContactsActivityCompose : ComponentActivity() {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
NextcloudTalkApplication.sharedApplication!!.componentApplication.inject(this) NextcloudTalkApplication.sharedApplication!!.componentApplication.inject(this)
contactsViewModel = ViewModelProvider(this, viewModelFactory)[ContactsViewModel::class.java] contactsViewModel = ViewModelProvider(this, viewModelFactory)[ContactsViewModel::class.java]
setContent { setContent {
MaterialTheme { val colorScheme = viewThemeUtils.getColorScheme(this)
val uiState = contactsViewModel.contactsViewState.collectAsState()
MaterialTheme(
colorScheme = colorScheme
) {
val context = LocalContext.current val context = LocalContext.current
Scaffold( Scaffold(
topBar = { topBar = {
@ -96,7 +97,6 @@ class ContactsActivityCompose : ComponentActivity() {
) )
}, },
content = { content = {
val uiState = contactsViewModel.contactsViewState.collectAsState()
Column(Modifier.padding(it)) { Column(Modifier.padding(it)) {
ConversationCreationOptions(context = context) ConversationCreationOptions(context = context)
ContactsList( ContactsList(
@ -170,6 +170,7 @@ fun ContactsItem(contacts: List<AutocompleteUser>, contactsViewModel: ContactsVi
} }
items(contactsForInitial) { contact -> items(contactsForInitial) { contact ->
ContactItemRow(contact = contact, contactsViewModel = contactsViewModel, context = context) ContactItemRow(contact = contact, contactsViewModel = contactsViewModel, context = context)
Log.d(CompanionClass.TAG, "Contacts:$contact")
} }
} }
} }
@ -205,15 +206,10 @@ fun ContactItemRow(contact: AutocompleteUser, contactsViewModel: ContactsViewMod
verticalAlignment = Alignment.CenterVertically verticalAlignment = Alignment.CenterVertically
) { ) {
val imageUri = contact.id?.let { contactsViewModel.getImageUri(it, true) } val imageUri = contact.id?.let { contactsViewModel.getImageUri(it, true) }
val imageRequest = ImageRequest.Builder(context) val errorPlaceholderImage: Int = R.drawable.account_circle_96dp
.data(imageUri) val loadedImage = loadImage(imageUri, context, errorPlaceholderImage)
.transformations(CircleCropTransformation())
.error(R.drawable.account_circle_96dp)
.placeholder(R.drawable.account_circle_96dp)
.build()
AsyncImage( AsyncImage(
model = imageRequest, model = loadedImage,
contentDescription = stringResource(R.string.user_avatar), contentDescription = stringResource(R.string.user_avatar),
modifier = Modifier.size(width = 45.dp, height = 45.dp) modifier = Modifier.size(width = 45.dp, height = 45.dp)
) )
@ -246,8 +242,10 @@ fun ContactItemRow(contact: AutocompleteUser, contactsViewModel: ContactsViewMod
fun AppBar(title: String, context: Context, contactsViewModel: ContactsViewModel) { fun AppBar(title: String, context: Context, contactsViewModel: ContactsViewModel) {
val searchQuery by contactsViewModel.searchQuery.collectAsState() val searchQuery by contactsViewModel.searchQuery.collectAsState()
val searchState = contactsViewModel.searchState.collectAsState() val searchState = contactsViewModel.searchState.collectAsState()
TopAppBar( TopAppBar(
title = { Text(text = title) }, title = { Text(text = title) },
navigationIcon = { navigationIcon = {
IconButton(onClick = { IconButton(onClick = {
(context as? Activity)?.finish() (context as? Activity)?.finish()
@ -282,13 +280,13 @@ fun ConversationCreationOptions(context: Context) {
modifier = Modifier.padding(start = 16.dp, end = 16.dp, top = 16.dp, bottom = 8.dp), modifier = Modifier.padding(start = 16.dp, end = 16.dp, top = 16.dp, bottom = 8.dp),
verticalAlignment = Alignment.CenterVertically verticalAlignment = Alignment.CenterVertically
) { ) {
Image( Icon(
painter = painterResource(id = R.drawable.baseline_chat_bubble_outline_24),
modifier = Modifier modifier = Modifier
.width(40.dp) .width(40.dp)
.height(40.dp) .height(40.dp)
.padding(8.dp), .padding(8.dp),
painter = painterResource(R.drawable.baseline_chat_bubble_outline_24), contentDescription = null
contentDescription = stringResource(R.string.new_conversation_creation_icon)
) )
Text( Text(
modifier = Modifier modifier = Modifier
@ -308,13 +306,13 @@ fun ConversationCreationOptions(context: Context) {
}, },
verticalAlignment = Alignment.CenterVertically verticalAlignment = Alignment.CenterVertically
) { ) {
Image( Icon(
Icons.AutoMirrored.Filled.List,
modifier = Modifier modifier = Modifier
.width(40.dp) .width(40.dp)
.height(40.dp) .height(40.dp)
.padding(8.dp), .padding(8.dp),
painter = painterResource(R.drawable.baseline_format_list_bulleted_24), contentDescription = null
contentDescription = stringResource(R.string.join_open_conversations_icon)
) )
Text( Text(
modifier = Modifier modifier = Modifier

Просмотреть файл

@ -0,0 +1,36 @@
/*
* Nextcloud Talk - Android Client
*
* SPDX-FileCopyrightText: 2024 Your Name <your@email.com>
* SPDX-License-Identifier: GPL-3.0-or-later
*/
package com.nextcloud.talk.contacts
import android.app.Application
import coil.ImageLoader
import coil.ImageLoaderFactory
import coil.disk.DiskCache
import coil.memory.MemoryCache
import coil.util.DebugLogger
import com.nextcloud.talk.utils.ContactUtils
class ContactsApplication : Application(), ImageLoaderFactory {
override fun newImageLoader(): ImageLoader {
val imageLoader = ImageLoader.Builder(this)
.memoryCache {
MemoryCache.Builder(this)
.maxSizePercent(ContactUtils.CACHE_MEMORY_SIZE_PERCENTAGE)
.build()
}
.diskCache {
DiskCache.Builder()
.maxSizePercent(ContactUtils.CACHE_DISK_SIZE_PERCENTAGE)
.directory(cacheDir)
.build()
}
.logger(DebugLogger())
.build()
return imageLoader
}
}

Просмотреть файл

@ -13,4 +13,5 @@ import com.nextcloud.talk.models.json.conversations.RoomOverall
interface ContactsRepository { interface ContactsRepository {
suspend fun getContacts(searchQuery: String?, shareTypes: List<String>): AutocompleteOverall suspend fun getContacts(searchQuery: String?, shareTypes: List<String>): AutocompleteOverall
suspend fun createRoom(roomType: String, sourceType: String, userId: String, conversationName: String?): RoomOverall suspend fun createRoom(roomType: String, sourceType: String, userId: String, conversationName: String?): RoomOverall
fun getImageUri(avatarId: String, requestBigSize: Boolean): String
} }

Просмотреть файл

@ -64,4 +64,12 @@ class ContactsRepositoryImpl(
) )
return response return response
} }
override fun getImageUri(avatarId: String, requestBigSize: Boolean): String {
return ApiUtils.getUrlForAvatar(
_currentUser.baseUrl,
avatarId,
requestBigSize
)
}
} }

Просмотреть файл

@ -9,27 +9,21 @@ package com.nextcloud.talk.contacts
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import com.nextcloud.talk.data.user.model.User
import com.nextcloud.talk.models.json.autocomplete.AutocompleteUser import com.nextcloud.talk.models.json.autocomplete.AutocompleteUser
import com.nextcloud.talk.models.json.conversations.Conversation import com.nextcloud.talk.models.json.conversations.Conversation
import com.nextcloud.talk.users.UserManager
import com.nextcloud.talk.utils.ApiUtils
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import javax.inject.Inject import javax.inject.Inject
class ContactsViewModel @Inject constructor( class ContactsViewModel @Inject constructor(
private val repository: ContactsRepository, private val repository: ContactsRepository
private val userManager: UserManager
) : ViewModel() { ) : ViewModel() {
private val _contactsViewState = MutableStateFlow<ContactsUiState>(ContactsUiState.None) private val _contactsViewState = MutableStateFlow<ContactsUiState>(ContactsUiState.None)
val contactsViewState: StateFlow<ContactsUiState> = _contactsViewState val contactsViewState: StateFlow<ContactsUiState> = _contactsViewState
private val _roomViewState = MutableStateFlow<RoomUiState>(RoomUiState.None) private val _roomViewState = MutableStateFlow<RoomUiState>(RoomUiState.None)
val roomViewState: StateFlow<RoomUiState> = _roomViewState val roomViewState: StateFlow<RoomUiState> = _roomViewState
private val _currentUser = userManager.currentUser.blockingGet()
val currentUser: User = _currentUser
private val _searchQuery = MutableStateFlow("") private val _searchQuery = MutableStateFlow("")
val searchQuery: StateFlow<String> = _searchQuery val searchQuery: StateFlow<String> = _searchQuery
private val shareTypes: MutableList<String> = mutableListOf(ShareType.User.shareType) private val shareTypes: MutableList<String> = mutableListOf(ShareType.User.shareType)
@ -86,13 +80,8 @@ class ContactsViewModel @Inject constructor(
} }
} }
} }
fun getImageUri(avatarId: String, requestBigSize: Boolean): String { fun getImageUri(avatarId: String, requestBigSize: Boolean): String {
return ApiUtils.getUrlForAvatar( return repository.getImageUri(avatarId, requestBigSize)
_currentUser.baseUrl,
avatarId,
requestBigSize
)
} }
} }

Просмотреть файл

@ -0,0 +1,24 @@
/*
* Nextcloud Talk - Android Client
*
* SPDX-FileCopyrightText: 2024 Sowjanya Kota <sowjanya.kch@email.com>
* SPDX-License-Identifier: GPL-3.0-or-later
*/
package com.nextcloud.talk.contacts
import android.content.Context
import androidx.compose.runtime.Composable
import coil.request.ImageRequest
import coil.transform.CircleCropTransformation
@Composable
fun loadImage(imageUri: String?, context: Context, errorPlaceholderImage: Int): ImageRequest {
val imageRequest = ImageRequest.Builder(context)
.data(imageUri)
.transformations(CircleCropTransformation())
.error(errorPlaceholderImage)
.placeholder(errorPlaceholderImage)
.build()
return imageRequest
}

Просмотреть файл

@ -7,7 +7,6 @@
package com.nextcloud.talk.contacts package com.nextcloud.talk.contacts
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.height
import androidx.compose.foundation.text.KeyboardActions import androidx.compose.foundation.text.KeyboardActions
@ -17,13 +16,10 @@ import androidx.compose.material.icons.automirrored.filled.ArrowBack
import androidx.compose.material.icons.filled.Close import androidx.compose.material.icons.filled.Close
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton import androidx.compose.material3.IconButton
import androidx.compose.material3.Surface
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.material3.TextField import androidx.compose.material3.TextField
import androidx.compose.material3.TextFieldDefaults
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalSoftwareKeyboardController import androidx.compose.ui.platform.LocalSoftwareKeyboardController
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.TextStyle
@ -34,82 +30,65 @@ import com.nextcloud.talk.R
@Composable @Composable
fun DisplaySearch(text: String, onTextChange: (String) -> Unit, contactsViewModel: ContactsViewModel) { fun DisplaySearch(text: String, onTextChange: (String) -> Unit, contactsViewModel: ContactsViewModel) {
Surface( val keyboardController = LocalSoftwareKeyboardController.current
TextField(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.height(60.dp) .height(60.dp),
.background(Color.White) value = text,
) { onValueChange = { onTextChange(it) },
val keyboardController = LocalSoftwareKeyboardController.current placeholder = {
TextField( Text(
modifier = Modifier text = stringResource(R.string.nc_search)
.fillMaxWidth(), )
value = text, },
onValueChange = { onTextChange(it) },
placeholder = {
Text(
text = stringResource(R.string.nc_search),
color = Color.DarkGray
)
},
textStyle = TextStyle( textStyle = TextStyle(
color = Color.Black, fontSize = 16.sp
fontSize = 16.sp ),
), singleLine = true,
singleLine = true, leadingIcon = {
leadingIcon = { IconButton(
onClick = {
onTextChange("")
contactsViewModel.updateSearchState(false)
}
) {
Icon(
imageVector = Icons.AutoMirrored.Default.ArrowBack,
contentDescription = stringResource(R.string.back_button)
)
}
},
trailingIcon = {
if (text.isNotEmpty()) {
IconButton( IconButton(
onClick = { onClick = {
onTextChange("") onTextChange("")
contactsViewModel.updateSearchState(false)
} }
) { ) {
Icon( Icon(
imageVector = Icons.AutoMirrored.Default.ArrowBack, imageVector = Icons.Default.Close,
contentDescription = stringResource(R.string.back_button), contentDescription = stringResource(R.string.close_icon)
tint = Color.Black
) )
} }
}, }
},
trailingIcon = { keyboardOptions = KeyboardOptions(
if (text.isNotEmpty()) { imeAction = ImeAction.Search
IconButton( ),
onClick = {
onTextChange("") keyboardActions = KeyboardActions(
} onSearch = {
) { if (text.trim().isNotEmpty()) {
Icon( keyboardController?.hide()
imageVector = Icons.Default.Close, } else {
contentDescription = stringResource(R.string.close_icon), return@KeyboardActions
tint = Color.Black
)
}
} }
}, }
),
keyboardOptions = KeyboardOptions( maxLines = 1
imeAction = ImeAction.Search )
),
keyboardActions = KeyboardActions(
onSearch = {
if (text.trim().isNotEmpty()) {
keyboardController?.hide()
} else {
return@KeyboardActions
}
}
),
maxLines = 1,
colors = TextFieldDefaults.colors(
focusedContainerColor = Color.White,
unfocusedContainerColor = Color.White,
disabledContainerColor = Color.White,
focusedTextColor = Color.Black,
cursorColor = Color.Black
)
)
}
} }

Просмотреть файл

@ -12,6 +12,8 @@ import android.provider.ContactsContract
object ContactUtils { object ContactUtils {
const val MAX_CONTACT_LIMIT = 50 const val MAX_CONTACT_LIMIT = 50
const val CACHE_MEMORY_SIZE_PERCENTAGE = 0.1
const val CACHE_DISK_SIZE_PERCENTAGE = 0.02
fun getDisplayNameFromDeviceContact(context: Context, id: String?): String? { fun getDisplayNameFromDeviceContact(context: Context, id: String?): String? {
var displayName: String? = null var displayName: String? = null

Просмотреть файл

@ -11,8 +11,8 @@
android:viewportHeight="24" android:viewportHeight="24"
android:viewportWidth="24" android:viewportWidth="24"
android:width="24dp"> android:width="24dp">
<path android:fillColor="@android:color/white" <path android:fillColor="@android:color/white"
android:pathData="M20,2L4,2c-1.1,0 -2,0.9 -2,2v18l4,-4h14c1.1,0 2,-0.9 2,-2L22,4c0,-1.1 -0.9,-2 -2,-2zM20,16L6,16l-2,2L4,4h16v12z"/> android:pathData="M20,2L4,2c-1.1,0 -2,0.9 -2,2v18l4,-4h14c1.1,0 2,-0.9 2,-2L22,4c0,-1.1 -0.9,-2 -2,-2zM20,16L6,16l-2,2L4,4h16v12z"/>
</vector> </vector>

Просмотреть файл

@ -0,0 +1,126 @@
/*
* Nextcloud Talk - Android Client
*
* SPDX-FileCopyrightText: 2024 Sowjanya Kota <sowjanya.kch@gmail.com>
* SPDX-License-Identifier: GPL-3.0-or-later
*/
package com.nextcloud.talk.contacts
import com.nextcloud.talk.contacts.apiService.FakeItem
import com.nextcloud.talk.contacts.repository.FakeRepositoryError
import com.nextcloud.talk.contacts.repository.FakeRepositorySuccess
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.TestDispatcher
import kotlinx.coroutines.test.UnconfinedTestDispatcher
import kotlinx.coroutines.test.resetMain
import kotlinx.coroutines.test.runTest
import kotlinx.coroutines.test.setMain
import org.junit.After
import org.junit.Before
import org.junit.Test
@OptIn(ExperimentalCoroutinesApi::class)
class ContactsViewModelTest {
private lateinit var viewModel: ContactsViewModel
private val repository: ContactsRepository = FakeRepositorySuccess()
val dispatcher: TestDispatcher = UnconfinedTestDispatcher()
@Before
fun setup() {
Dispatchers.setMain(dispatcher)
}
@After
fun tearDown() {
Dispatchers.resetMain()
}
@Before
fun setUp() {
viewModel = ContactsViewModel(repository)
}
@Test
fun `fetch contacts`() =
runTest {
viewModel = ContactsViewModel(repository)
viewModel.getContactsFromSearchParams()
assert(viewModel.contactsViewState.value is ContactsUiState.Success)
val successState = viewModel.contactsViewState.value as ContactsUiState.Success
assert(successState.contacts == FakeItem.contacts)
}
@Test
fun `test error contacts state`() =
runTest {
viewModel = ContactsViewModel(FakeRepositoryError())
assert(viewModel.contactsViewState.value is ContactsUiState.Error)
val errorState = viewModel.contactsViewState.value as ContactsUiState.Error
assert(errorState.message == "unable to fetch contacts")
}
@Test
fun `update search query`() {
viewModel.updateSearchQuery("Ma")
assert(viewModel.searchQuery.value == "Ma")
}
@Test
fun `initial search query is empty string`() {
viewModel.updateSearchQuery("")
assert(viewModel.searchQuery.value == "")
}
@Test
fun `initial shareType is User`() {
assert(viewModel.shareTypeList.contains(ShareType.User.shareType))
}
@Test
fun `update shareTypes`() {
viewModel.updateShareTypes(ShareType.Group.shareType)
assert(viewModel.shareTypeList.contains(ShareType.Group.shareType))
}
@Test
fun `initial room state is none`() =
runTest {
assert(viewModel.roomViewState.value is RoomUiState.None)
}
@Test
fun `test success room state`() =
runTest {
viewModel.createRoom("1", "users", "s@gmail.com", null)
assert(viewModel.roomViewState.value is RoomUiState.Success)
val successState = viewModel.roomViewState.value as RoomUiState.Success
assert(successState.conversation == FakeItem.roomOverall.ocs!!.data)
}
@Test
fun `test failure room state`() =
runTest {
viewModel = ContactsViewModel(FakeRepositoryError())
viewModel.createRoom("1", "users", "s@gmail.com", null)
assert(viewModel.roomViewState.value is RoomUiState.Error)
val errorState = viewModel.roomViewState.value as RoomUiState.Error
assert(errorState.message == "unable to create room")
}
@Test
fun `test image uri`() {
val expectedImageUri = "https://mydomain.com/index.php/avatar/vidya/512"
val imageUri = viewModel.getImageUri("vidya", false)
assert(imageUri == expectedImageUri)
}
@Test
fun `test error image uri`() {
val expectedImageUri = "https://mydoman.com/index.php/avatar/vidya/512"
val imageUri = viewModel.getImageUri("vidya", false)
assert(imageUri != expectedImageUri)
}
}

Просмотреть файл

@ -0,0 +1,58 @@
/*
* Nextcloud Talk - Android Client
*
* SPDX-FileCopyrightText: 2024 Sowjanya Kota <sowjanya.kch@gmail.com>
* SPDX-License-Identifier: GPL-3.0-or-later
*/
package com.nextcloud.talk.contacts.apiService
import com.nextcloud.talk.models.json.autocomplete.AutocompleteOCS
import com.nextcloud.talk.models.json.autocomplete.AutocompleteOverall
import com.nextcloud.talk.models.json.autocomplete.AutocompleteUser
import com.nextcloud.talk.models.json.conversations.Conversation
import com.nextcloud.talk.models.json.conversations.RoomOCS
import com.nextcloud.talk.models.json.conversations.RoomOverall
import com.nextcloud.talk.models.json.generic.GenericMeta
import org.mockito.Mockito.mock
object FakeItem {
val contacts: List<AutocompleteUser> =
listOf(
AutocompleteUser(id = "android", label = "Android", source = "users"),
AutocompleteUser(id = "android1", label = "Android 1", source = "users"),
AutocompleteUser(id = "android2", label = "Android 2", source = "users"),
AutocompleteUser(id = "Benny", label = "Benny J", source = "users"),
AutocompleteUser(id = "Benjamin", label = "Benjamin Schmidt", source = "users"),
AutocompleteUser(id = "Chris", label = "Christoph Schmidt", source = "users"),
AutocompleteUser(id = "Daniel", label = "Daniel H", source = "users"),
AutocompleteUser(id = "Dennis", label = "Dennis Richard", source = "users"),
AutocompleteUser(id = "Emma", label = "Emma Jackson", source = "users"),
AutocompleteUser(id = "Emily", label = "Emily Jackson", source = "users"),
AutocompleteUser(id = "Mario", label = "Mario Schmidt", source = "users"),
AutocompleteUser(id = "Maria", label = "Maria Schmidt", source = "users"),
AutocompleteUser(id = "Samsung", label = "Samsung A52", source = "users"),
AutocompleteUser(id = "Tom", label = "Tom Müller", source = "users"),
AutocompleteUser(id = "Tony", label = "Tony Baker", source = "users")
)
val contactsOverall = AutocompleteOverall(
ocs = AutocompleteOCS(
meta = GenericMeta(
status = "ok",
statusCode = 200,
message = "OK"
),
data = contacts
)
)
val roomOverall: RoomOverall = RoomOverall(
ocs = RoomOCS(
meta = GenericMeta(
status = "ok",
statusCode = 200,
message = "OK"
),
data = mock(Conversation::class.java)
)
)
}

Просмотреть файл

@ -0,0 +1,31 @@
/*
* Nextcloud Talk - Android Client
*
* SPDX-FileCopyrightText: 2024 Sowjanya Kota <sowjanya.kota@gmail.com>
* SPDX-License-Identifier: GPL-3.0-or-later
*/
package com.nextcloud.talk.contacts.repository
import com.nextcloud.talk.contacts.ContactsRepository
import com.nextcloud.talk.models.json.autocomplete.AutocompleteOverall
import com.nextcloud.talk.models.json.conversations.RoomOverall
class FakeRepositoryError : ContactsRepository {
override suspend fun getContacts(searchQuery: String?, shareTypes: List<String>): AutocompleteOverall {
throw Exception("unable to fetch contacts")
}
override suspend fun createRoom(
roomType: String,
sourceType: String,
userId: String,
conversationName: String?
): RoomOverall {
throw Exception("unable to create room")
}
override fun getImageUri(avatarId: String, requestBigSize: Boolean): String {
return "https://mydoman.com/index.php/avatar/$avatarId/512"
}
}

Просмотреть файл

@ -0,0 +1,32 @@
/*
* Nextcloud Talk - Android Client
*
* SPDX-FileCopyrightText: 2024 Sowjanya Kota <sowjanya.kch@email.com>
* SPDX-License-Identifier: GPL-3.0-or-later
*/
package com.nextcloud.talk.contacts.repository
import com.nextcloud.talk.contacts.ContactsRepository
import com.nextcloud.talk.contacts.apiService.FakeItem
import com.nextcloud.talk.models.json.autocomplete.AutocompleteOverall
import com.nextcloud.talk.models.json.conversations.RoomOverall
class FakeRepositorySuccess : ContactsRepository {
override suspend fun getContacts(searchQuery: String?, shareTypes: List<String>): AutocompleteOverall {
return FakeItem.contactsOverall
}
override suspend fun createRoom(
roomType: String,
sourceType: String,
userId: String,
conversationName: String?
): RoomOverall {
return FakeItem.roomOverall
}
override fun getImageUri(avatarId: String, requestBigSize: Boolean): String {
return "https://mydomain.com/index.php/avatar/$avatarId/512"
}
}

Просмотреть файл

@ -11,12 +11,10 @@
buildscript { buildscript {
ext { ext {
kotlinVersion = '1.9.23'
hilt_version = '2.44'
kotlinVersion = '2.0.0' kotlinVersion = '2.0.0'
hilt_version = '2.44'
} }
repositories { repositories {
google() google()
gradlePluginPortal() gradlePluginPortal()

Просмотреть файл

@ -4,13 +4,13 @@
<verify-metadata>true</verify-metadata> <verify-metadata>true</verify-metadata>
<verify-signatures>true</verify-signatures> <verify-signatures>true</verify-signatures>
<trusted-artifacts> <trusted-artifacts>
<trust file="tensorflow-lite-metadata-0.1.0-rc2.pom" reason="differing hash on every CI run - temp global trust"/>
<trust group="androidx.fragment"/>
<trust group="com.android.tools.build" name="aapt2" version="8.4.1-11315950" reason="ships OS specific artifacts (win/linux) - temp global trust"/> <trust group="com.android.tools.build" name="aapt2" version="8.4.1-11315950" reason="ships OS specific artifacts (win/linux) - temp global trust"/>
<trust group="com.github.nextcloud-deps" name="android-talk-webrtc" version="110.5481.0" reason="ships OS specific artifacts (win/linux) - temp global trust"/> <trust group="com.github.nextcloud-deps" name="android-talk-webrtc" version="110.5481.0" reason="ships OS specific artifacts (win/linux) - temp global trust"/>
<trust group="com.google.dagger"/>
<trust group="org.javassist" name="javassist" version="3.26.0-GA" reason="java assist"/>
<trust file=".*-sources[.]jar" regex="true"/> <trust file=".*-sources[.]jar" regex="true"/>
<trust group="com.google.dagger" />
<trust group="org.javassist" name="javassist" version="3.26.0-GA" reason="java assist"/>
<trust group="androidx.fragment"/>
<trust file="tensorflow-lite-metadata-0.1.0-rc2.pom" reason="differing hash on every CI run - temp global trust"/>
</trusted-artifacts> </trusted-artifacts>
<ignored-keys> <ignored-keys>
<ignored-key id="0AA3E5C3D232E79B" reason="Key couldn't be downloaded from any key server"/> <ignored-key id="0AA3E5C3D232E79B" reason="Key couldn't be downloaded from any key server"/>
@ -39,7 +39,10 @@
<trusted-key id="0F07D1201BDDAB67CFB84EB479752DB6C966F0B8" group="com.google.android" name="annotations" version="4.1.1.4"/> <trusted-key id="0F07D1201BDDAB67CFB84EB479752DB6C966F0B8" group="com.google.android" name="annotations" version="4.1.1.4"/>
<trusted-key id="10F3C7A02ECA55E502BADCF3991EFB94DB91127D" group="org.ow2" name="ow2" version="1.5.1"/> <trusted-key id="10F3C7A02ECA55E502BADCF3991EFB94DB91127D" group="org.ow2" name="ow2" version="1.5.1"/>
<trusted-key id="120D6F34E627ED3A772EBBFE55C7E5E701832382" group="org.snakeyaml" name="snakeyaml-engine" version="2.6"/> <trusted-key id="120D6F34E627ED3A772EBBFE55C7E5E701832382" group="org.snakeyaml" name="snakeyaml-engine" version="2.6"/>
<trusted-key id="147B691A19097624902F4EA9689CBE64F4BC997F" group="org.mockito"/> <trusted-key id="147B691A19097624902F4EA9689CBE64F4BC997F">
<trusting group="org.mockito"/>
<trusting group="org.mockito.kotlin" name="mockito-kotlin" version="4.1.0"/>
</trusted-key>
<trusted-key id="1597AB231B7ADD7E14B1D9C43F00DB67AE236E2E" group="org.conscrypt" name="conscrypt-android" version="2.5.2"/> <trusted-key id="1597AB231B7ADD7E14B1D9C43F00DB67AE236E2E" group="org.conscrypt" name="conscrypt-android" version="2.5.2"/>
<trusted-key id="190D5A957FF22273E601F7A7C92C5FEC70161C62" group="org.apache" name="apache" version="18"/> <trusted-key id="190D5A957FF22273E601F7A7C92C5FEC70161C62" group="org.apache" name="apache" version="18"/>
<trusted-key id="19BEAB2D799C020F17C69126B16698A4ADF4D638" group="org.checkerframework"/> <trusted-key id="19BEAB2D799C020F17C69126B16698A4ADF4D638" group="org.checkerframework"/>
@ -156,6 +159,7 @@
<trusted-key id="8756C4F765C9AC3CB6B85D62379CE192D401AB61"> <trusted-key id="8756C4F765C9AC3CB6B85D62379CE192D401AB61">
<trusting group="eu.davidea"/> <trusting group="eu.davidea"/>
<trusting group="org.jetbrains.intellij.deps"/> <trusting group="org.jetbrains.intellij.deps"/>
<trusting group="org.jetbrains.kotlinx"/>
</trusted-key> </trusted-key>
<trusted-key id="8E3A02905A1AE67E7B0F9ACD3967D4EDA591B991" group="org.jetbrains.kotlinx" name="kotlinx-html-jvm" version="0.8.1"/> <trusted-key id="8E3A02905A1AE67E7B0F9ACD3967D4EDA591B991" group="org.jetbrains.kotlinx" name="kotlinx-html-jvm" version="0.8.1"/>
<trusted-key id="8F9A3C6D105B9F57844A721D79E193516BE7998F" group="org.dom4j" name="dom4j" version="2.1.4"/> <trusted-key id="8F9A3C6D105B9F57844A721D79E193516BE7998F" group="org.dom4j" name="dom4j" version="2.1.4"/>
@ -232,6 +236,7 @@
<trusted-key id="E4AC7874F3479A0F1F8ECF9960BB45F36B649F22" group="fr.dudie" name="nominatim-api" version="3.4"/> <trusted-key id="E4AC7874F3479A0F1F8ECF9960BB45F36B649F22" group="fr.dudie" name="nominatim-api" version="3.4"/>
<trusted-key id="E77417AC194160A3FABD04969A259C7EE636C5ED" group="^com[.]google($|([.].*))" regex="true"/> <trusted-key id="E77417AC194160A3FABD04969A259C7EE636C5ED" group="^com[.]google($|([.].*))" regex="true"/>
<trusted-key id="E7DC75FC24FB3C8DFE8086AD3D5839A2262CBBFB" group="org.jetbrains.kotlinx"/> <trusted-key id="E7DC75FC24FB3C8DFE8086AD3D5839A2262CBBFB" group="org.jetbrains.kotlinx"/>
<trusted-key id="64B9B09F164AA0BF88742EB61188B69F6D6259CA" group="com.google.accompanist"/>
<trusted-key id="E82D2EAF2E83830CE1F7F6BE571A5291E827E1C7" group="net.java" name="jvnet-parent" version="3"/> <trusted-key id="E82D2EAF2E83830CE1F7F6BE571A5291E827E1C7" group="net.java" name="jvnet-parent" version="3"/>
<trusted-key id="E85AED155021AF8A6C6B7A4A7C7D8456294423BA" group="org.objenesis"/> <trusted-key id="E85AED155021AF8A6C6B7A4A7C7D8456294423BA" group="org.objenesis"/>
<trusted-key id="EAA526B91DD83BA3E1B9636FA730529CA355A63E" group="org.ccil.cowan.tagsoup" name="tagsoup" version="1.2.1"/> <trusted-key id="EAA526B91DD83BA3E1B9636FA730529CA355A63E" group="org.ccil.cowan.tagsoup" name="tagsoup" version="1.2.1"/>
@ -294,6 +299,14 @@
<sha256 value="f7a29bcba338575dcf89a553cff9cfad3f140340eaf2b56fd0193244da602c0a" origin="Generated by Gradle" reason="Artifact is not signed"/> <sha256 value="f7a29bcba338575dcf89a553cff9cfad3f140340eaf2b56fd0193244da602c0a" origin="Generated by Gradle" reason="Artifact is not signed"/>
</artifact> </artifact>
</component> </component>
<component group="androidx.activity" name="activity-compose" version="1.7.0">
<artifact name="activity-compose-1.7.0.aar">
<sha256 value="caa72885d1ce7979c1d6c59a8b255c6097b770780d4d4da95d56979a348646cd" origin="Generated by Gradle" reason="Artifact is not signed"/>
</artifact>
<artifact name="activity-compose-1.7.0.module">
<sha256 value="f7a29bcba338575dcf89a553cff9cfad3f140340eaf2b56fd0193244da602c0a" origin="Generated by Gradle" reason="Artifact is not signed"/>
</artifact>
</component>
<component group="androidx.annotation" name="annotation" version="1.0.0"> <component group="androidx.annotation" name="annotation" version="1.0.0">
<artifact name="annotation-1.0.0.jar"> <artifact name="annotation-1.0.0.jar">
<sha256 value="0baae9755f7caf52aa80cd04324b91ba93af55d4d1d17dcc9a7b53d99ef7c016" origin="Generated by Gradle" reason="Artifact is not signed"/> <sha256 value="0baae9755f7caf52aa80cd04324b91ba93af55d4d1d17dcc9a7b53d99ef7c016" origin="Generated by Gradle" reason="Artifact is not signed"/>
@ -326,6 +339,50 @@
<sha256 value="9516c2ae44284ea0bd3d0eade0ee638879b708cbe31e3af92ba96c300604ebc3" origin="Generated by Gradle" reason="Artifact is not signed"/> <sha256 value="9516c2ae44284ea0bd3d0eade0ee638879b708cbe31e3af92ba96c300604ebc3" origin="Generated by Gradle" reason="Artifact is not signed"/>
</artifact> </artifact>
</component> </component>
<component group="androidx.exifinterface" name="exifinterface" version="1.3.6">
<artifact name="exifinterface-1.3.6.aar">
<sha256 value="1804105e9e05fdd8f760413bad5de498c381aa329f4f9d94c851bc891ac654c6" origin="Generated by Gradle" reason="Artifact is not signed"/>
</artifact>
<artifact name="exifinterface-1.3.6.module">
<sha256 value="5e9fd84ca3fd3b7706f6856fa4383107de8676bf7c42b7d4b8108949414d6201" origin="Generated by Gradle" reason="Artifact is not signed"/>
</artifact>
</component>
<component group="androidx.core" name="core" version="1.1.0">
<artifact name="core-1.1.0.pom">
<sha256 value="dae46132cdcd46b798425f7cb78fd65890869b6d26101ccdcd43461a4f51754c" origin="Generated by Gradle" reason="Artifact is not signed"/>
</artifact>
</component>
<component group="androidx.core" name="core" version="1.3.2">
<artifact name="core-1.3.2.pom">
<sha256 value="afb5ea494dd083ed404cd51f580d218e37362f8ae326e893bee521290ed34920" origin="Generated by Gradle" reason="Artifact is not signed"/>
</artifact>
</component>
<component group="androidx.test.ext" name="junit" version="1.1.5">
<artifact name="junit-1.1.5.aar">
<sha256 value="4307c0e60f5d701db9c59bcd9115af705113c36a9132fa3dbad58db1294e9bfd" origin="Generated by Gradle" reason="Artifact is not signed"/>
</artifact>
<artifact name="junit-1.1.5.pom">
<sha256 value="4cff0df04cae25831e821ef2f9129245783460e98d0fd67d8f6824065a134c4e" origin="Generated by Gradle" reason="Artifact is not signed"/>
</artifact>
</component>
<component group="androidx.core" name="core-ktx" version="1.8.0">
<artifact name="core-ktx-1.8.0.module">
<sha256 value="a91bc3e02f209f643dd8275345a9e3003ce20d64fc0760eccf479c1709842f72" origin="Generated by Gradle" reason="Artifact is not signed"/>
</artifact>
</component>
<component group="androidx.annotation" name="annotation-experimental" version="1.3.0">
<artifact name="annotation-experimental-1.3.0.aar">
<sha256 value="abfd29c8556e5bd0325a9f769ab9e9d154ff4a5515c476cdd5a2a8285b1b19dc" origin="Generated by Gradle" reason="Artifact is not signed"/>
</artifact>
<artifact name="annotation-experimental-1.3.0.module">
<sha256 value="5eebeaff01d042e06dcf292abf8964ad391e4b0159f0090f16253d6045d38da0" origin="Generated by Gradle" reason="Artifact is not signed"/>
</artifact>
</component>
<component group="androidx.annotation" name="annotation-experimental" version="1.1.0-rc01">
<artifact name="annotation-experimental-1.1.0-rc01.module">
<sha256 value="d45ac493e84d968aabb2bea2b7744031a98cf5074447c0f3b862d600fc44b55c" origin="Generated by Gradle" reason="Artifact is not signed"/>
</artifact>
</component>
<component group="androidx.annotation" name="annotation" version="1.5.0"> <component group="androidx.annotation" name="annotation" version="1.5.0">
<artifact name="annotation-1.5.0.jar"> <artifact name="annotation-1.5.0.jar">
<sha256 value="261fb7c0210858500bab66d34354972a75166ab4182add283780b05513d6ec4a" origin="Generated by Gradle" reason="Artifact is not signed"/> <sha256 value="261fb7c0210858500bab66d34354972a75166ab4182add283780b05513d6ec4a" origin="Generated by Gradle" reason="Artifact is not signed"/>
@ -342,6 +399,14 @@
<sha256 value="fbc64f5c44a7added8b6eab517cf7d70555e25153bf5d44a6ed9b0e5312f7de9" origin="Generated by Gradle" reason="Artifact is not signed"/> <sha256 value="fbc64f5c44a7added8b6eab517cf7d70555e25153bf5d44a6ed9b0e5312f7de9" origin="Generated by Gradle" reason="Artifact is not signed"/>
</artifact> </artifact>
</component> </component>
<component group="androidx.exifinterface" name="exifinterface" version="1.3.2">
<artifact name="exifinterface-1.3.2.aar">
<sha256 value="8770c180103e0b8c04a07eb4c59153af639b09eca25deae9bdcdaf869d1e5b6b" origin="Generated by Gradle"/>
</artifact>
<artifact name="exifinterface-1.3.2.module">
<sha256 value="10ba5b5cbea7f5c8758be4fdaec60a3545e891a1130d830a442b88cf5336a885" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="androidx.annotation" name="annotation-experimental" version="1.0.0"> <component group="androidx.annotation" name="annotation-experimental" version="1.0.0">
<artifact name="annotation-experimental-1.0.0.pom"> <artifact name="annotation-experimental-1.0.0.pom">
<sha256 value="6b73ff6608f4b1d6cbab620b65708a382d0b39901cf4e6b0d16f84a1b04d7732" origin="Generated by Gradle" reason="Artifact is not signed"/> <sha256 value="6b73ff6608f4b1d6cbab620b65708a382d0b39901cf4e6b0d16f84a1b04d7732" origin="Generated by Gradle" reason="Artifact is not signed"/>
@ -355,6 +420,11 @@
<sha256 value="0361d1526a4d7501255e19779e09e93cdbd07fee0e2f5c50b7a137432d510119" origin="Generated by Gradle" reason="Artifact is not signed"/> <sha256 value="0361d1526a4d7501255e19779e09e93cdbd07fee0e2f5c50b7a137432d510119" origin="Generated by Gradle" reason="Artifact is not signed"/>
</artifact> </artifact>
</component> </component>
<component group="androidx.annotation" name="annotation-experimental" version="1.1.0-rc01">
<artifact name="annotation-experimental-1.1.0-rc01.module">
<sha256 value="d45ac493e84d968aabb2bea2b7744031a98cf5074447c0f3b862d600fc44b55c" origin="Generated by Gradle" reason="Artifact is not signed"/>
</artifact>
</component>
<component group="androidx.annotation" name="annotation-experimental" version="1.1.0-rc01"> <component group="androidx.annotation" name="annotation-experimental" version="1.1.0-rc01">
<artifact name="annotation-experimental-1.1.0-rc01.module"> <artifact name="annotation-experimental-1.1.0-rc01.module">
<sha256 value="d45ac493e84d968aabb2bea2b7744031a98cf5074447c0f3b862d600fc44b55c" origin="Generated by Gradle" reason="Artifact is not signed"/> <sha256 value="d45ac493e84d968aabb2bea2b7744031a98cf5074447c0f3b862d600fc44b55c" origin="Generated by Gradle" reason="Artifact is not signed"/>
@ -376,6 +446,76 @@
<sha256 value="9b6974a7dfe26d3c209dd63e16f8ee2461b57a091789160ca1eb492bb1bf3f84" origin="Generated by Gradle" reason="Artifact is not signed"/> <sha256 value="9b6974a7dfe26d3c209dd63e16f8ee2461b57a091789160ca1eb492bb1bf3f84" origin="Generated by Gradle" reason="Artifact is not signed"/>
</artifact> </artifact>
</component> </component>
<component group="androidx.annotation" name="annotation-experimental" version="1.3.0">
<artifact name="annotation-experimental-1.3.0.aar">
<sha256 value="abfd29c8556e5bd0325a9f769ab9e9d154ff4a5515c476cdd5a2a8285b1b19dc" origin="Generated by Gradle" reason="Artifact is not signed"/>
</artifact>
<artifact name="annotation-experimental-1.3.0.module">
<sha256 value="5eebeaff01d042e06dcf292abf8964ad391e4b0159f0090f16253d6045d38da0" origin="Generated by Gradle" reason="Artifact is not signed"/>
</artifact>
</component>
<component group="androidx.activity" name="activity-compose" version="1.7.0">
<artifact name="activity-compose-1.7.0.aar">
<sha256 value="caa72885d1ce7979c1d6c59a8b255c6097b770780d4d4da95d56979a348646cd" origin="Generated by Gradle" reason="Artifact is not signed"/>
</artifact>
<artifact name="activity-compose-1.7.0.module">
<sha256 value="f7a29bcba338575dcf89a553cff9cfad3f140340eaf2b56fd0193244da602c0a" origin="Generated by Gradle" reason="Artifact is not signed"/>
</artifact>
</component>
<component group="androidx.compose.runtime" name="runtime" version="1.0.1">
<artifact name="runtime-1.0.1.module">
<sha256 value="2543a8c7edc16bde91f140286b4fd3773d7204a283a4ec99f6e5e286aa92c0c3" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="androidx.compose.runtime" name="runtime-saveable" version="1.0.1">
<artifact name="runtime-saveable-1.0.1.module">
<sha256 value="c0d6f142542d8d74f65481ef6526d2be265f01f812a112948fcde87a458f4fb6" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="androidx.compose.ui" name="ui" version="1.0.1">
<artifact name="ui-1.0.1.aar">
<sha256 value="1943daa4a3412861b9a2bdc1a7c8c2ff05d9b8191c1d3e56ebb223d2eb4a8526" origin="Generated by Gradle"/>
</artifact>
<artifact name="ui-1.0.1.module">
<sha256 value="57031a6ac9b60e5b56792ebf5cde6e16812ff566ed9190cbd188b00b46c13779" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="androidx.compose" name="compose-bom" version="2024.06.00">
<artifact name="compose-bom-2024.06.00.pom">
<sha256 value="1b391a969ff81c0bb43b3711e92d977e8bfa72457a11d8a37910a7051bdc3045" origin="Generated by Gradle" reason="Artifact is not signed"/>
</artifact>
</component>
<component group="androidx.activity" name="activity-compose" version="1.7.0">
<artifact name="activity-compose-1.7.0.aar">
<sha256 value="caa72885d1ce7979c1d6c59a8b255c6097b770780d4d4da95d56979a348646cd" origin="Generated by Gradle" reason="Artifact is not signed"/>
</artifact>
<artifact name="activity-compose-1.7.0.module">
<sha256 value="f7a29bcba338575dcf89a553cff9cfad3f140340eaf2b56fd0193244da602c0a" origin="Generated by Gradle" reason="Artifact is not signed"/>
</artifact>
</component>
<component group="androidx.compose.runtime" name="runtime" version="1.0.1">
<artifact name="runtime-1.0.1.module">
<sha256 value="2543a8c7edc16bde91f140286b4fd3773d7204a283a4ec99f6e5e286aa92c0c3" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="androidx.compose.runtime" name="runtime-saveable" version="1.0.1">
<artifact name="runtime-saveable-1.0.1.module">
<sha256 value="c0d6f142542d8d74f65481ef6526d2be265f01f812a112948fcde87a458f4fb6" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="androidx.compose.ui" name="ui" version="1.0.1">
<artifact name="ui-1.0.1.aar">
<sha256 value="1943daa4a3412861b9a2bdc1a7c8c2ff05d9b8191c1d3e56ebb223d2eb4a8526" origin="Generated by Gradle"/>
</artifact>
<artifact name="ui-1.0.1.module">
<sha256 value="57031a6ac9b60e5b56792ebf5cde6e16812ff566ed9190cbd188b00b46c13779" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="androidx.compose" name="compose-bom" version="2024.06.00">
<artifact name="compose-bom-2024.06.00.pom">
<sha256 value="1b391a969ff81c0bb43b3711e92d977e8bfa72457a11d8a37910a7051bdc3045" origin="Generated by Gradle" reason="Artifact is not signed"/>
</artifact>
</component>
<component group="androidx.appcompat" name="appcompat" version="1.1.0"> <component group="androidx.appcompat" name="appcompat" version="1.1.0">
<artifact name="appcompat-1.1.0.pom"> <artifact name="appcompat-1.1.0.pom">
<sha256 value="340d617121f8ef8e02a6680c8f357aa3e542276d0c8a1cdcb6fd98984b2cb7b9" origin="Generated by Gradle" reason="Artifact is not signed"/> <sha256 value="340d617121f8ef8e02a6680c8f357aa3e542276d0c8a1cdcb6fd98984b2cb7b9" origin="Generated by Gradle" reason="Artifact is not signed"/>
@ -4902,6 +5042,14 @@
<sha256 value="9a35e48f20f3021c21e469d52fa88b3acc08b20dab77b6c646f72f6fb205ec92" origin="Generated by Gradle" reason="A key couldn't be downloaded"/> <sha256 value="9a35e48f20f3021c21e469d52fa88b3acc08b20dab77b6c646f72f6fb205ec92" origin="Generated by Gradle" reason="A key couldn't be downloaded"/>
</artifact> </artifact>
</component> </component>
<component group="com.novoda" name="merlin" version="1.2.1">
<artifact name="merlin-1.2.1.aar">
<sha256 value="c62d03d0fde57f26fa633feeee24d7dfed3d66cc81097e4d6306b076cc7d70b6" origin="Generated by Gradle" reason="Artifact is not signed"/>
</artifact>
<artifact name="merlin-1.2.1.pom">
<sha256 value="62dbaffb68b60ca317c05bba83a9fea8d866c3d3e7a2bd928c69591aa2fe4418" origin="Generated by Gradle" reason="Artifact is not signed"/>
</artifact>
</component>
<component group="com.squareup" name="javapoet" version="1.2.0"> <component group="com.squareup" name="javapoet" version="1.2.0">
<artifact name="javapoet-1.2.0.pom"> <artifact name="javapoet-1.2.0.pom">
<pgp value="9E84765A7AA3E3D3D5598A408E3F0DE7AE354651"/> <pgp value="9E84765A7AA3E3D3D5598A408E3F0DE7AE354651"/>
@ -5860,7 +6008,7 @@
<ignored-keys> <ignored-keys>
<ignored-key id="DB0597E3144342256BC81E3EC727D053C4481CF5" reason="PGP verification failed"/> <ignored-key id="DB0597E3144342256BC81E3EC727D053C4481CF5" reason="PGP verification failed"/>
</ignored-keys> </ignored-keys>
<sha256 value="8359ad51e0476c8e0df7188a43f16d49733c4a428fb45e99794b783f01b97520" origin="Generated by Gradle" reason="PGP signature verification failed!"/> <sha256 value="9a4f5e5674366c156c90391662f03ed7c5971d6aa63832df74a271da6ff82e96" origin="Generated by Gradle" reason="PGP signature verification failed!"/>
</artifact> </artifact>
</component> </component>
<component group="org.xerial" name="sqlite-jdbc" version="3.41.2.2"> <component group="org.xerial" name="sqlite-jdbc" version="3.41.2.2">