This commit is contained in:
Marcel Hibbe 2025-06-18 18:52:49 +02:00 committed by GitHub
commit 94bbc5ec0a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
41 changed files with 606 additions and 349 deletions

View File

@ -28,13 +28,13 @@ apply plugin: "org.jlleitschuh.gradle.ktlint"
apply plugin: 'kotlinx-serialization'
android {
compileSdk 34
compileSdk 35
namespace 'com.nextcloud.talk'
defaultConfig {
minSdkVersion 26
targetSdkVersion 34
targetSdkVersion 35
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
// mayor.minor.hotfix.increment (for increment: 01-50=Alpha / 51-89=RC / 90-99=stable)
@ -303,7 +303,7 @@ dependencies {
implementation 'androidx.core:core-ktx:1.13.1'
implementation 'androidx.activity:activity-ktx:1.9.3'
implementation 'com.github.nextcloud.android-common:ui:0.23.2'
implementation 'com.github.nextcloud.android-common:ui:0.26.0'
implementation 'com.github.nextcloud-deps:android-talk-webrtc:132.6834.0'
gplayImplementation 'com.google.android.gms:play-services-base:18.6.0'

View File

@ -91,7 +91,7 @@ class AccountVerificationActivity : BaseActivity() {
requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
setContentView(binding.root)
actionBar?.hide()
setupSystemColors()
initSystemBars()
handleIntent()
}

View File

@ -78,7 +78,7 @@ class ServerSelectionActivity : BaseActivity() {
requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
setContentView(binding.root)
actionBar?.hide()
setupSystemColors()
initSystemBars()
onBackPressedDispatcher.addCallback(this, onBackPressedCallback)
}

View File

@ -86,7 +86,7 @@ class SwitchAccountActivity : BaseActivity() {
requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
setContentView(binding.root)
setupActionBar()
setupSystemColors()
initSystemBars()
Configuration.getInstance().load(context, PreferenceManager.getDefaultSharedPreferences(context))

View File

@ -114,7 +114,7 @@ class WebViewLoginActivity : BaseActivity() {
requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
setContentView(binding.root)
actionBar?.hide()
setupSystemColors()
initSystemBars()
onBackPressedDispatcher.addCallback(this, onBackPressedCallback)
handleIntent()

View File

@ -11,11 +11,13 @@ package com.nextcloud.talk.activities
import android.annotation.SuppressLint
import android.content.Context
import android.content.Intent
import android.os.Build
import android.os.Bundle
import android.text.TextUtils
import android.util.Log
import android.view.View
import android.view.ViewGroup
import android.view.WindowInsets
import android.view.WindowManager
import android.view.inputmethod.EditorInfo
import android.webkit.SslErrorHandler
@ -37,6 +39,7 @@ import com.nextcloud.talk.ui.theme.ViewThemeUtils
import com.nextcloud.talk.utils.DisplayUtils
import com.nextcloud.talk.utils.FileViewerUtils
import com.nextcloud.talk.utils.UriUtils
import com.nextcloud.talk.utils.adjustUIForAPILevel35
import com.nextcloud.talk.utils.bundle.BundleKeys
import com.nextcloud.talk.utils.database.user.CurrentUserProviderNew
import com.nextcloud.talk.utils.preferences.AppPreferences
@ -81,6 +84,7 @@ open class BaseActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
NextcloudTalkApplication.sharedApplication!!.componentApplication.inject(this)
adjustUIForAPILevel35()
super.onCreate(savedInstanceState)
cleanTempCertPreference()
@ -111,10 +115,23 @@ open class BaseActivity : AppCompatActivity() {
eventBus.unregister(this)
}
fun setupSystemColors() {
/*
* May be aligned with android-common lib in the future: .../ui/util/extensions/AppCompatActivityExtensions.kt
*/
fun initSystemBars() {
window.decorView.setOnApplyWindowInsetsListener { view, insets ->
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM) {
val statusBarHeight = insets.getInsets(WindowInsets.Type.statusBars()).top
view.setPadding(0, statusBarHeight, 0, 0)
val color = ResourcesCompat.getColor(resources, R.color.bg_default, context.theme)
view.setBackgroundColor(color)
} else {
colorizeStatusBar()
colorizeNavigationBar()
}
insets
}
}
open fun colorizeStatusBar() {
if (resources != null) {

View File

@ -0,0 +1,41 @@
/*
* Nextcloud Talk - Android Client
*
* SPDX-FileCopyrightText: 2025 Marcel Hibbe <dev@mhibbe.de>
* SPDX-License-Identifier: GPL-3.0-or-later
*/
package com.nextcloud.talk.adapters.items
import android.view.View
import com.nextcloud.talk.R
import eu.davidea.flexibleadapter.FlexibleAdapter
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
import eu.davidea.flexibleadapter.items.IFlexible
import eu.davidea.viewholders.FlexibleViewHolder
class SpacerItem(private val height: Int) : AbstractFlexibleItem<SpacerItem.ViewHolder>() {
override fun getLayoutRes(): Int = R.layout.item_spacer
override fun createViewHolder(view: View?, adapter: FlexibleAdapter<IFlexible<*>?>?): ViewHolder {
return ViewHolder(view!!, adapter!!)
}
override fun bindViewHolder(
adapter: FlexibleAdapter<IFlexible<*>?>?,
holder: ViewHolder,
position: Int,
payloads: MutableList<Any>?
) {
holder.itemView.layoutParams.height = height
}
override fun equals(other: Any?) = other is SpacerItem
override fun hashCode(): Int {
return 0
}
class ViewHolder(view: View, adapter: FlexibleAdapter<*>) :
FlexibleViewHolder(view, adapter)
}

View File

@ -66,6 +66,8 @@ import androidx.core.graphics.drawable.toDrawable
import androidx.core.net.toUri
import androidx.core.os.bundleOf
import androidx.core.text.bold
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import androidx.emoji2.text.EmojiCompat
import androidx.fragment.app.DialogFragment
import androidx.fragment.app.commit
@ -458,7 +460,28 @@ class ChatActivity :
binding = ActivityChatBinding.inflate(layoutInflater)
setupActionBar()
setContentView(binding.root)
setupSystemColors()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM) {
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.chat_container)) { view, insets ->
val statusBarInsets = insets.getInsets(WindowInsetsCompat.Type.statusBars())
val navBarInsets = insets.getInsets(WindowInsetsCompat.Type.navigationBars())
val imeInsets = insets.getInsets(WindowInsetsCompat.Type.ime())
val isKeyboardVisible = insets.isVisible(WindowInsetsCompat.Type.ime())
val bottomPadding = if (isKeyboardVisible) imeInsets.bottom else navBarInsets.bottom
view.setPadding(
view.paddingLeft,
statusBarInsets.top,
view.paddingRight,
bottomPadding
)
WindowInsetsCompat.CONSUMED
}
} else {
colorizeStatusBar()
colorizeNavigationBar()
}
conversationUser = currentUserProvider.currentUser.blockingGet()
handleIntent(intent)
@ -486,7 +509,7 @@ class ChatActivity :
initObservers()
pickMultipleMedia = registerForActivityResult(
ActivityResultContracts.PickMultipleVisualMedia(5)
ActivityResultContracts.PickMultipleVisualMedia(MAX_AMOUNT_MEDIA_FILE_PICKER)
) { uris ->
if (uris.isNotEmpty()) {
onChooseFileResult(uris)
@ -684,7 +707,7 @@ class ChatActivity :
?.split("#")
?.getOrNull(1)
?.toLongOrNull()
val currentTimeStamp = (System.currentTimeMillis() / 1000).toLong()
val currentTimeStamp = (System.currentTimeMillis() / ONE_SECOND_IN_MILLIS).toLong()
val retentionPeriod = retentionOfEventRooms(spreedCapabilities)
val isPastEvent = eventEndTimeStamp?.let { it < currentTimeStamp }
if (isPastEvent == true && retentionPeriod != 0) {
@ -4193,5 +4216,6 @@ class ChatActivity :
const val OUT_OF_OFFICE_ALPHA = 76
const val ZERO_INDEX = 0
const val ONE_INDEX = 1
const val MAX_AMOUNT_MEDIA_FILE_PICKER = 10
}
}

View File

@ -1,7 +1,6 @@
/*
* Nextcloud Talk - Android Client
*
* SPDX-FileCopyrightText: 2024 Sowjanya Kota <sowjanya.kch@gmail.com>
* SPDX-FileCopyrightText: 2025 Marcel Hibbe <dev@mhibbe.de>
* SPDX-License-Identifier: GPL-3.0-or-later
*/
@ -9,16 +8,41 @@
package com.nextcloud.talk.components
import android.app.Activity
import android.os.Build
import androidx.compose.foundation.background
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.statusBars
import androidx.compose.foundation.layout.windowInsetsTopHeight
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.toArgb
import androidx.compose.ui.platform.LocalView
import androidx.core.view.WindowCompat
@Composable
fun SetupSystemBars() {
fun ColoredStatusBar() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM) {
Box(modifier = Modifier.fillMaxSize()) {
Box(
Modifier
.windowInsetsTopHeight(WindowInsets.statusBars)
.fillMaxWidth()
.background(MaterialTheme.colorScheme.surface)
)
}
} else {
ColorLegacyStatusBar()
}
}
@Composable
private fun ColorLegacyStatusBar() {
val view = LocalView.current
val isDarkMode = isSystemInDarkTheme()
val statusBarColor = MaterialTheme.colorScheme.surface.toArgb()

View File

@ -0,0 +1,24 @@
/*
* Nextcloud Talk - Android Client
*
* SPDX-FileCopyrightText: 2025 Marcel Hibbe <dev@mhibbe.de>
* SPDX-License-Identifier: GPL-3.0-or-later
*/
package com.nextcloud.talk.components
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.RowScope
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
@Composable
fun VerticallyCenteredRow(content: @Composable RowScope.() -> Unit) {
Row(
modifier = Modifier.fillMaxHeight(),
verticalAlignment = Alignment.CenterVertically,
content = content
)
}

View File

@ -18,9 +18,9 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle
import autodagger.AutoInjector
import com.nextcloud.talk.activities.BaseActivity
import com.nextcloud.talk.application.NextcloudTalkApplication
import com.nextcloud.talk.components.ColoredStatusBar
import com.nextcloud.talk.contacts.CompanionClass.Companion.KEY_HIDE_ALREADY_EXISTING_PARTICIPANTS
import com.nextcloud.talk.extensions.getParcelableArrayListExtraProvider
import com.nextcloud.talk.components.SetupSystemBars
import com.nextcloud.talk.models.json.autocomplete.AutocompleteUser
import com.nextcloud.talk.utils.bundle.BundleKeys
import javax.inject.Inject
@ -64,11 +64,11 @@ class ContactsActivity : BaseActivity() {
MaterialTheme(
colorScheme = colorScheme
) {
ColoredStatusBar()
ContactsScreen(
contactsViewModel = contactsViewModel,
uiState = uiState.value
)
SetupSystemBars()
}
}
}

View File

@ -11,16 +11,18 @@ package com.nextcloud.talk.contacts
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.statusBarsPadding
import androidx.compose.material3.Scaffold
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.colorResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.nextcloud.talk.R
import com.nextcloud.talk.contacts.components.AppBar
import com.nextcloud.talk.contacts.components.ContactsAppBar
import com.nextcloud.talk.contacts.components.ContactsList
import com.nextcloud.talk.contacts.components.ContactsSearchAppBar
import com.nextcloud.talk.contacts.components.ConversationCreationOptions
@Composable
@ -32,35 +34,37 @@ fun ContactsScreen(contactsViewModel: ContactsViewModel, uiState: ContactsUiStat
val enableAddButton by contactsViewModel.enableAddButton.collectAsStateWithLifecycle()
Scaffold(
modifier = Modifier
.statusBarsPadding(),
topBar = {
AppBar(
title = stringResource(R.string.nc_app_product_name),
if (isSearchActive) {
ContactsSearchAppBar(
searchQuery = searchQuery,
isSearchActive = isSearchActive,
isAddParticipants = isAddParticipants,
autocompleteUsers = autocompleteUsers,
onEnableSearch = {
contactsViewModel.setSearchActive(true)
onTextChange = {
contactsViewModel.updateSearchQuery(it)
contactsViewModel.getContactsFromSearchParams()
},
onDisableSearch = {
onCloseSearch = {
contactsViewModel.updateSearchQuery("")
contactsViewModel.setSearchActive(false)
},
onUpdateSearchQuery = {
contactsViewModel.updateSearchQuery(query = it)
},
onUpdateAutocompleteUsers = {
contactsViewModel.getContactsFromSearchParams()
},
enableAddButton = enableAddButton,
clickAddButton = {
contactsViewModel.modifyClickAddButton(it)
}
isAddParticipants = isAddParticipants,
clickAddButton = { contactsViewModel.modifyClickAddButton(true) }
)
} else {
ContactsAppBar(
isAddParticipants = isAddParticipants,
autocompleteUsers = autocompleteUsers,
onStartSearch = { contactsViewModel.setSearchActive(true) }
)
}
},
content = {
content = { paddingValues ->
Column(
Modifier
.padding(it)
.padding(0.dp, paddingValues.calculateTopPadding(), 0.dp, 0.dp)
.background(colorResource(id = R.color.bg_default))
) {
if (!isAddParticipants) {

View File

@ -1,117 +0,0 @@
/*
* Nextcloud Talk - Android Client
*
* SPDX-FileCopyrightText: 2024 Sowjanya Kota <sowjanya.kch@gmail.com>
* SPDX-FileCopyrightText: 2025 Marcel Hibbe <dev@mhibbe.de>
* SPDX-License-Identifier: GPL-3.0-or-later
*/
package com.nextcloud.talk.contacts.components
import android.annotation.SuppressLint
import android.app.Activity
import android.content.Intent
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.wrapContentWidth
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.ArrowBack
import androidx.compose.material.icons.filled.Search
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.material3.TopAppBar
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import com.nextcloud.talk.R
import com.nextcloud.talk.models.json.autocomplete.AutocompleteUser
@SuppressLint("UnrememberedMutableState")
@OptIn(ExperimentalMaterial3Api::class)
@Suppress("LongParameterList", "LongMethod")
@Composable
fun AppBar(
title: String,
searchQuery: String,
isSearchActive: Boolean,
isAddParticipants: Boolean,
autocompleteUsers: List<AutocompleteUser>,
onEnableSearch: () -> Unit,
onDisableSearch: () -> Unit,
onUpdateSearchQuery: (String) -> Unit,
onUpdateAutocompleteUsers: () -> Unit,
enableAddButton: Boolean,
clickAddButton: (Boolean) -> Unit
) {
val context = LocalContext.current
val appTitle = if (!isSearchActive) {
title
} else {
""
}
TopAppBar(
title = { Text(text = appTitle) },
navigationIcon = {
IconButton(onClick = {
(context as? Activity)?.finish()
}) {
Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = stringResource(R.string.back_button))
}
},
actions = {
if (!isSearchActive) {
IconButton(onClick = onEnableSearch) {
Icon(Icons.Filled.Search, contentDescription = stringResource(R.string.search_icon))
}
if (isAddParticipants) {
Text(
text = stringResource(id = R.string.nc_contacts_done),
modifier = Modifier.clickable {
val resultIntent = Intent().apply {
putParcelableArrayListExtra(
"selectedParticipants",
ArrayList(autocompleteUsers)
)
}
(context as? Activity)?.setResult(Activity.RESULT_OK, resultIntent)
(context as? Activity)?.finish()
}
)
}
}
}
)
if (isSearchActive) {
Row(modifier = Modifier.fillMaxWidth()) {
SearchComponent(
text = searchQuery,
onTextChange = { searchQuery ->
onUpdateSearchQuery(searchQuery)
onUpdateAutocompleteUsers()
},
onDisableSearch = onDisableSearch,
modifier = Modifier.weight(1f)
)
if (isAddParticipants) {
TextButton(
modifier = Modifier.align(Alignment.CenterVertically).wrapContentWidth(),
onClick = {
onDisableSearch()
onUpdateSearchQuery("")
clickAddButton(true)
onUpdateAutocompleteUsers()
},
enabled = enableAddButton
) {
Text(text = context.getString(R.string.add_participants))
}
}
}
}
}

View File

@ -0,0 +1,77 @@
/*
* Nextcloud Talk - Android Client
*
* SPDX-FileCopyrightText: 2024 Sowjanya Kota <sowjanya.kch@gmail.com>
* SPDX-FileCopyrightText: 2025 Marcel Hibbe <dev@mhibbe.de>
* SPDX-License-Identifier: GPL-3.0-or-later
*/
package com.nextcloud.talk.contacts.components
import android.app.Activity
import android.content.Intent
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.height
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.ArrowBack
import androidx.compose.material.icons.filled.Search
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import com.nextcloud.talk.R
import com.nextcloud.talk.components.VerticallyCenteredRow
import com.nextcloud.talk.models.json.autocomplete.AutocompleteUser
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun ContactsAppBar(isAddParticipants: Boolean, autocompleteUsers: List<AutocompleteUser>, onStartSearch: () -> Unit) {
val context = LocalContext.current
TopAppBar(
modifier = Modifier
.height(60.dp),
title = {
VerticallyCenteredRow {
Text(
text = if (isAddParticipants) {
stringResource(R.string.nc_participants_add)
} else {
stringResource(R.string.nc_new_conversation)
}
)
}
},
navigationIcon = {
VerticallyCenteredRow {
IconButton(onClick = { (context as? Activity)?.finish() }) {
Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = stringResource(R.string.back_button))
}
}
},
actions = {
VerticallyCenteredRow {
IconButton(onClick = onStartSearch) {
Icon(Icons.Filled.Search, contentDescription = stringResource(R.string.search_icon))
}
if (isAddParticipants) {
Text(
text = stringResource(id = R.string.nc_contacts_done),
modifier = Modifier.clickable {
val resultIntent = Intent().apply {
putParcelableArrayListExtra("selectedParticipants", ArrayList(autocompleteUsers))
}
(context as? Activity)?.setResult(Activity.RESULT_OK, resultIntent)
(context as? Activity)?.finish()
}
)
}
}
}
)
}

View File

@ -15,7 +15,6 @@ import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.material3.HorizontalDivider
@ -44,9 +43,13 @@ fun ContactsItem(contacts: List<AutocompleteUser>, contactsViewModel: ContactsVi
}
LazyColumn(
modifier = Modifier
.padding(8.dp)
.fillMaxWidth(),
contentPadding = PaddingValues(all = 10.dp),
contentPadding = PaddingValues(
top = 10.dp,
bottom = 40.dp,
start = 10.dp,
end = 10.dp
),
verticalArrangement = Arrangement.spacedBy(10.dp)
) {
groupedContacts.forEach { (initial, contactsForInitial) ->

View File

@ -0,0 +1,104 @@
/*
* Nextcloud Talk - Android Client
*
* SPDX-FileCopyrightText: 2024 Sowjanya Kota <sowjanya.kch@gmail.com>
* SPDX-FileCopyrightText: 2025 Marcel Hibbe <dev@mhibbe.de>
* SPDX-License-Identifier: GPL-3.0-or-later
*/
package com.nextcloud.talk.contacts.components
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.ArrowBack
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.material3.TextField
import androidx.compose.material3.TextFieldDefaults
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalSoftwareKeyboardController
import androidx.compose.ui.platform.SoftwareKeyboardController
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.unit.dp
import com.nextcloud.talk.R
import com.nextcloud.talk.components.VerticallyCenteredRow
@Suppress("LongParameterList")
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun ContactsSearchAppBar(
searchQuery: String,
onTextChange: (String) -> Unit,
onCloseSearch: () -> Unit,
enableAddButton: Boolean,
isAddParticipants: Boolean,
clickAddButton: (Boolean) -> Unit
) {
val keyboardController = LocalSoftwareKeyboardController.current
Surface(
modifier = Modifier.height(60.dp)
) {
VerticallyCenteredRow {
IconButton(
modifier = Modifier
.padding(start = 4.dp),
onClick = onCloseSearch
) {
Icon(
imageVector = Icons.AutoMirrored.Filled.ArrowBack,
contentDescription = stringResource(R.string.back_button)
)
}
TextField(
value = searchQuery,
onValueChange = onTextChange,
placeholder = { Text(text = stringResource(R.string.nc_search)) },
singleLine = true,
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Search),
keyboardActions = searchKeyboardActions(searchQuery, keyboardController),
colors = searchTextFieldColors()
)
if (isAddParticipants) {
TextButton(
onClick = {
onCloseSearch()
clickAddButton(true)
},
enabled = enableAddButton
) {
Text(text = stringResource(R.string.add_participants))
}
}
}
}
}
@Composable
fun searchTextFieldColors() =
TextFieldDefaults.colors(
focusedIndicatorColor = Color.Transparent,
unfocusedIndicatorColor = Color.Transparent,
disabledIndicatorColor = Color.Transparent
)
fun searchKeyboardActions(text: String, keyboardController: SoftwareKeyboardController?) =
KeyboardActions(
onSearch = {
if (text.trim().isNotEmpty()) {
keyboardController?.hide()
}
}
)

View File

@ -1,105 +0,0 @@
/*
* Nextcloud Talk - Android Client
*
* SPDX-FileCopyrightText: 2025 Julius Linus <juliuslinus1@gmail.com>
* SPDX-License-Identifier: GPL-3.0-or-later
*/
package com.nextcloud.talk.contacts.components
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.ArrowBack
import androidx.compose.material.icons.filled.Close
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.material3.TextField
import androidx.compose.material3.TextFieldDefaults
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalSoftwareKeyboardController
import androidx.compose.ui.platform.SoftwareKeyboardController
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.nextcloud.talk.R
@Composable
fun SearchComponent(
text: String,
onTextChange: (String) -> Unit,
onDisableSearch: () -> Unit,
modifier: Modifier = Modifier
) {
val keyboardController = LocalSoftwareKeyboardController.current
TextField(
value = text,
onValueChange = { onTextChange(it) },
modifier = modifier
.background(MaterialTheme.colorScheme.background)
.height(60.dp),
placeholder = { Text(text = stringResource(R.string.nc_search)) },
textStyle = TextStyle(fontSize = 16.sp),
singleLine = true,
leadingIcon = { LeadingIcon(onTextChange, onDisableSearch) },
trailingIcon = { TrailingIcon(text, onTextChange) },
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Search),
keyboardActions = searchKeyboardActions(text, keyboardController),
colors = searchTextFieldColors(),
maxLines = 1
)
}
@Composable
fun searchTextFieldColors() =
TextFieldDefaults.colors(
focusedIndicatorColor = Color.Transparent,
unfocusedIndicatorColor = Color.Transparent,
disabledIndicatorColor = Color.Transparent
)
@Composable
fun LeadingIcon(onTextChange: (String) -> Unit, onDisableSearch: () -> Unit) {
IconButton(
onClick = {
onTextChange("")
onDisableSearch()
}
) {
Icon(
imageVector = Icons.AutoMirrored.Default.ArrowBack,
contentDescription = stringResource(R.string.back_button)
)
}
}
@Composable
fun TrailingIcon(text: String, onTextChange: (String) -> Unit) {
if (text.isNotEmpty()) {
IconButton(
onClick = { onTextChange("") }
) {
Icon(
imageVector = Icons.Default.Close,
contentDescription = stringResource(R.string.close_icon)
)
}
}
}
fun searchKeyboardActions(text: String, keyboardController: SoftwareKeyboardController?) =
KeyboardActions(
onSearch = {
if (text.trim().isNotEmpty()) {
keyboardController?.hide()
}
}
)

View File

@ -84,8 +84,8 @@ import com.nextcloud.talk.R
import com.nextcloud.talk.activities.BaseActivity
import com.nextcloud.talk.application.NextcloudTalkApplication
import com.nextcloud.talk.chat.ChatActivity
import com.nextcloud.talk.components.ColoredStatusBar
import com.nextcloud.talk.contacts.ContactsActivity
import com.nextcloud.talk.components.SetupSystemBars
import com.nextcloud.talk.contacts.loadImage
import com.nextcloud.talk.extensions.getParcelableArrayListExtraProvider
import com.nextcloud.talk.models.json.autocomplete.AutocompleteUser
@ -117,7 +117,6 @@ class ConversationCreationActivity : BaseActivity() {
colorScheme = colorScheme
) {
ConversationCreationScreen(conversationCreationViewModel, context, pickImage)
SetupSystemBars()
}
}
}
@ -172,6 +171,7 @@ fun ConversationCreationScreen(
}
)
ColoredStatusBar()
Scaffold(
topBar = {
TopAppBar(
@ -191,7 +191,7 @@ fun ConversationCreationScreen(
content = { paddingValues ->
Column(
modifier = Modifier
.padding(paddingValues)
.padding(0.dp, paddingValues.calculateTopPadding(), 0.dp, 0.dp)
.background(colorResource(id = R.color.bg_default))
.fillMaxSize()
.verticalScroll(rememberScrollState())

View File

@ -190,7 +190,7 @@ class ConversationInfoActivity :
binding = ActivityConversationInfoBinding.inflate(layoutInflater)
setupActionBar()
setContentView(binding.root)
setupSystemColors()
initSystemBars()
viewModel =
ViewModelProvider(this, viewModelFactory)[ConversationInfoViewModel::class.java]

View File

@ -99,7 +99,7 @@ class ConversationInfoEditActivity : BaseActivity() {
binding = ActivityConversationInfoEditBinding.inflate(layoutInflater)
setupActionBar()
setContentView(binding.root)
setupSystemColors()
initSystemBars()
val extras: Bundle? = intent.extras

View File

@ -81,6 +81,7 @@ import com.nextcloud.talk.adapters.items.GenericTextHeaderItem
import com.nextcloud.talk.adapters.items.LoadMoreResultsItem
import com.nextcloud.talk.adapters.items.MessageResultItem
import com.nextcloud.talk.adapters.items.MessagesTextHeaderItem
import com.nextcloud.talk.adapters.items.SpacerItem
import com.nextcloud.talk.api.NcApi
import com.nextcloud.talk.application.NextcloudTalkApplication
import com.nextcloud.talk.arbitrarystorage.ArbitraryStorageManager
@ -266,7 +267,7 @@ class ConversationsListActivity :
binding = ActivityConversationsBinding.inflate(layoutInflater)
setupActionBar()
setContentView(binding.root)
setupSystemColors()
initSystemBars()
viewThemeUtils.material.themeCardView(binding.searchToolbar)
viewThemeUtils.material.themeSearchBarText(binding.searchText)
@ -293,10 +294,9 @@ class ConversationsListActivity :
override fun onResume() {
super.onResume()
// actionBar?.show()
if (adapter == null) {
adapter = FlexibleAdapter(conversationItems, this, true)
addEmptyItemForEdgeToEdgeIfNecessary()
} else {
binding.loadingContent.visibility = View.GONE
}
@ -342,6 +342,14 @@ class ConversationsListActivity :
showSearchOrToolbar()
}
// if edge to edge is used, add an empty item at the bottom of the list
@Suppress("MagicNumber")
private fun addEmptyItemForEdgeToEdgeIfNecessary() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM) {
adapter?.addScrollableFooter(SpacerItem(200))
}
}
@Suppress("LongMethod")
private fun initObservers() {
this.lifecycleScope.launch {
@ -963,8 +971,7 @@ class ConversationsListActivity :
} else {
showToolbar()
}
colorizeStatusBar()
colorizeNavigationBar()
initSystemBars()
}
}

View File

@ -21,6 +21,7 @@ import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.statusBarsPadding
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold
import androidx.compose.runtime.collectAsState
@ -28,8 +29,9 @@ import androidx.compose.runtime.mutableStateOf
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.colorResource
import androidx.compose.ui.res.stringResource
import androidx.lifecycle.ViewModelProvider
import androidx.compose.ui.unit.dp
import androidx.core.net.toUri
import androidx.lifecycle.ViewModelProvider
import autodagger.AutoInjector
import com.nextcloud.talk.BuildConfig
import com.nextcloud.talk.R
@ -37,8 +39,8 @@ import com.nextcloud.talk.activities.BaseActivity
import com.nextcloud.talk.api.NcApi
import com.nextcloud.talk.application.NextcloudTalkApplication
import com.nextcloud.talk.arbitrarystorage.ArbitraryStorageManager
import com.nextcloud.talk.components.ColoredStatusBar
import com.nextcloud.talk.components.StandardAppBar
import com.nextcloud.talk.components.SetupSystemBars
import com.nextcloud.talk.users.UserManager
import com.nextcloud.talk.utils.BrandingUtils
import com.nextcloud.talk.utils.ClosedInterfaceImpl
@ -109,18 +111,22 @@ class DiagnoseActivity : BaseActivity() {
MaterialTheme(
colorScheme = colorScheme
) {
ColoredStatusBar()
Scaffold(
modifier = Modifier
.statusBarsPadding(),
topBar = {
StandardAppBar(
title = stringResource(R.string.nc_settings_diagnose_title),
menuItems
)
},
content = {
content = { paddingValues ->
val viewState = diagnoseViewModel.notificationViewState.collectAsState().value
Column(
Modifier
.padding(it)
.padding(0.dp, paddingValues.calculateTopPadding(), 0.dp, 0.dp)
.background(backgroundColor)
.fillMaxSize()
) {
@ -136,7 +142,6 @@ class DiagnoseActivity : BaseActivity() {
}
}
)
SetupSystemBars()
}
}
}

View File

@ -65,7 +65,12 @@ fun DiagnoseContentComposable(
Column(
modifier = Modifier
.fillMaxSize()
.padding(16.dp)
.padding(
start = 16.dp,
top = 0.dp,
end = 16.dp,
bottom = 0.dp
)
.verticalScroll(rememberScrollState())
) {
data.value.forEach { element ->
@ -100,6 +105,7 @@ fun DiagnoseContentComposable(
ShowTestPushButton(onTestPushClick)
}
ShowNotificationData(isLoading, showDialog, context, viewState, onDismissDialog)
Spacer(modifier = Modifier.height(40.dp))
}
}

View File

@ -65,7 +65,7 @@ class InvitationsActivity : BaseActivity() {
binding = ActivityInvitationsBinding.inflate(layoutInflater)
setupActionBar()
setContentView(binding.root)
setupSystemColors()
initSystemBars()
adapter = InvitationsAdapter(currentUser) { invitation, action ->
handleInvitation(invitation, action)

View File

@ -67,7 +67,7 @@ class GeocodingActivity :
binding = ActivityGeocodingBinding.inflate(layoutInflater)
setupActionBar()
setContentView(binding.root)
setupSystemColors()
initSystemBars()
Configuration.getInstance().load(context, PreferenceManager.getDefaultSharedPreferences(context))

View File

@ -129,7 +129,7 @@ class LocationPickerActivity :
binding = ActivityLocationBinding.inflate(layoutInflater)
setupActionBar()
setContentView(binding.root)
setupSystemColors()
initSystemBars()
getInstance().load(context, PreferenceManager.getDefaultSharedPreferences(context))

View File

@ -70,7 +70,7 @@ class MessageSearchActivity : BaseActivity() {
binding = ActivityMessageSearchBinding.inflate(layoutInflater)
setupActionBar()
setContentView(binding.root)
setupSystemColors()
initSystemBars()
viewModel = ViewModelProvider(this, viewModelFactory)[MessageSearchViewModel::class.java]
user = currentUserProvider.currentUser.blockingGet()

View File

@ -57,7 +57,7 @@ class ListOpenConversationsActivity : BaseActivity() {
binding = ActivityOpenConversationsBinding.inflate(layoutInflater)
setupActionBar()
setContentView(binding.root)
setupSystemColors()
initSystemBars()
viewThemeUtils.platform.colorImageView(binding.searchOpenConversations, ColorRole.ON_SURFACE)
viewThemeUtils.material.colorTextInputLayout(binding.textInputLayout)

View File

@ -119,7 +119,7 @@ class ProfileActivity : BaseActivity() {
binding = ActivityProfileBinding.inflate(layoutInflater)
setupActionBar()
setContentView(binding.root)
setupSystemColors()
initSystemBars()
}
override fun onResume() {

View File

@ -145,7 +145,7 @@ class SettingsActivity :
binding = ActivitySettingsBinding.inflate(layoutInflater)
setupActionBar()
setContentView(binding.root)
setupSystemColors()
initSystemBars()
binding.avatarImage.let { ViewCompat.setTransitionName(it, "userAvatar.transitionTag") }

View File

@ -13,7 +13,6 @@ import android.os.Bundle
import android.util.Log
import android.view.MenuItem
import android.view.View
import androidx.core.content.res.ResourcesCompat
import androidx.lifecycle.ViewModelProvider
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.LinearLayoutManager
@ -28,7 +27,6 @@ import com.nextcloud.talk.databinding.ActivitySharedItemsBinding
import com.nextcloud.talk.shareditems.adapters.SharedItemsAdapter
import com.nextcloud.talk.shareditems.model.SharedItemType
import com.nextcloud.talk.shareditems.viewmodels.SharedItemsViewModel
import com.nextcloud.talk.utils.DisplayUtils
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_CONVERSATION_NAME
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_ROOM_TOKEN
import javax.inject.Inject
@ -57,15 +55,11 @@ class SharedItemsActivity : BaseActivity() {
setSupportActionBar(binding.sharedItemsToolbar)
setContentView(binding.root)
viewThemeUtils.platform.themeStatusBar(this)
initSystemBars()
viewThemeUtils.material.themeToolbar(binding.sharedItemsToolbar)
viewThemeUtils.material.themeTabLayoutOnSurface(binding.sharedItemsTabs)
DisplayUtils.applyColorToNavigationBar(
this.window,
ResourcesCompat.getColor(resources, R.color.bg_default, null)
)
supportActionBar?.title = conversationName
supportActionBar?.setDisplayHomeAsUpEnabled(true)

View File

@ -86,7 +86,7 @@ class TranslateActivity : BaseActivity() {
}
setupActionBar()
setContentView(binding.root)
setupSystemColors()
initSystemBars()
setupTextViews()
viewModel.getLanguages()
setupCopyButton()

View File

@ -0,0 +1,38 @@
/*
* Nextcloud Talk - Android Client
*
* SPDX-FileCopyrightText: 2025 Marcel Hibbe <dev@mhibbe.de>
* SPDX-License-Identifier: GPL-3.0-or-later
*/
package com.nextcloud.talk.utils
import android.graphics.Color
import android.os.Build
import androidx.activity.SystemBarStyle
import androidx.activity.enableEdgeToEdge
import androidx.appcompat.app.AppCompatActivity
/**
* This method is similar to "adjustUIForAPILevel35" in
* AppCompatActivityExtensions.kt in https://github.com/nextcloud/android-common/
* Only window.addSystemBarPaddings() had to be removed. This could be unified again at some point.
*/
@JvmOverloads
fun AppCompatActivity.adjustUIForAPILevel35(
statusBarStyle: SystemBarStyle = SystemBarStyle.auto(Color.TRANSPARENT, Color.TRANSPARENT),
// It may make sense to change navigationBarStyle to "SystemBarStyle.auto(Color.TRANSPARENT, Color.TRANSPARENT)"
// For now, it is set to "light" to have a fully transparent navigation bar to align with the XML screens.
// It may be wanted to have a semi transparent navigation bar in the future. Then set it to "auto" and try to
// migrate the XML screens to Compose (having semi transparent navigation bar for XML did not work out. In
// general, supporting both XML and Compose system bar handling is a pain and we will have it easier without XML)
// So in short: migrate all screens to Compose. Then it's easier to decide if navigation bar should be semi
// transparent or not for all screens.
navigationBarStyle: SystemBarStyle = SystemBarStyle.light(Color.TRANSPARENT, Color.TRANSPARENT)
) {
val isApiLevel35OrHigher = (Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM)
if (!isApiLevel35OrHigher) {
return
}
enableEdgeToEdge(statusBarStyle, navigationBarStyle)
}

View File

@ -91,6 +91,7 @@
</LinearLayout>
</com.google.android.material.appbar.MaterialToolbar>
</com.google.android.material.appbar.AppBarLayout>
<RelativeLayout

View File

@ -553,7 +553,7 @@
android:layout_marginTop="@dimen/standard_quarter_margin"
android:background="?android:attr/selectableItemBackground"
android:orientation="horizontal"
android:padding="@dimen/standard_padding">
android:padding="@dimen/standard_half_padding">
<ImageView
android:layout_width="24dp"
@ -579,7 +579,7 @@
android:layout_marginTop="@dimen/standard_quarter_margin"
android:background="?android:attr/selectableItemBackground"
android:orientation="horizontal"
android:padding="@dimen/standard_padding">
android:padding="@dimen/standard_half_padding">
<ImageView
android:layout_width="24dp"
@ -605,7 +605,7 @@
android:layout_marginTop="@dimen/standard_quarter_margin"
android:background="?android:attr/selectableItemBackground"
android:orientation="horizontal"
android:padding="@dimen/standard_padding">
android:padding="@dimen/standard_half_padding">
<ImageView
android:layout_width="24dp"
@ -625,6 +625,9 @@
</LinearLayout>
</LinearLayout>
<Space
android:layout_width="match_parent"
android:layout_height="50dp" />
</LinearLayout>
</androidx.core.widget.NestedScrollView>
</LinearLayout>

View File

@ -292,7 +292,8 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_margin="16dp"
android:layout_marginEnd="16dp"
android:layout_marginBottom="36dp"
android:contentDescription="@string/nc_new_conversation"
app:borderWidth="0dp"
app:srcCompat="@drawable/ic_pencil_grey600_24dp"

View File

@ -906,6 +906,9 @@
</LinearLayout>
</LinearLayout>
</LinearLayout>
<Space
android:layout_width="match_parent"
android:layout_height="50dp" />
</LinearLayout>
</ScrollView>
</LinearLayout>

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?><!--
~ Nextcloud Talk - Android Client
~
~ SPDX-FileCopyrightText: 2025 Marcel Hibbe <dev@mhibbe.de>
~ SPDX-License-Identifier: GPL-3.0-or-later
-->
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="0dp"/>

View File

@ -29,6 +29,9 @@
<item name="popupMenuStyle">@style/ChatSendButtonMenu</item>
<item name="dialogCornerRadius">@dimen/dialogBorderRadius</item>
<item name="android:windowBackground">@color/bg_default</item>
<!-- <item name="android:windowTranslucentStatus">false</item>-->
<!-- <item name="android:windowDrawsSystemBarBackgrounds">true</item>-->
<!-- <item name="android:statusBarColor">@android:color/transparent</item>-->
</style>
<style name="ThemeOverlay.AppTheme.PopupMenu" parent="ThemeOverlay.Material3.Dark">

View File

@ -1383,6 +1383,8 @@ vCeonVI7Q1CkIHt8u7eMgzfEkaiPLZlI0l0RpfT4pnNieqg=
-----END PGP PUBLIC KEY BLOCK-----
pub BAC30622339994C4
uid Chris Povirk <cpovirk@google.com>
sub FC9BDC25FB378008
-----BEGIN PGP PUBLIC KEY BLOCK-----
@ -1391,20 +1393,21 @@ Gyoc9ZmChrhLoim7z4ILqmNo8eegknepQ3dGdUij4NVIhR+m+8irayTbsNHvo3UG
9y7eM5tTSjyNYkyk5fAVuT7OhzIzMA+qtc3GRVxNYRKnaHajt+pOSqr+uoDtMG3n
6eAMHCAnhgh5Nd+dCFcNT+syl3zCwolA1wrzGxxOaif+xi5wwXjmF/lAt4PDIuDT
etA2/AqPM4zAC0BtC0iqVgVypjFV3EAexm/g0LNMiG/M/krzwjPq5gf1DY/57jU0
02FpKd79HmR7bHdc4e2olEf9NlHxfbPXDDsHABEBAAG5AQ0EWUwTFgEIANmMpV3N
K8aLrLgQTyh5++det8C3D3T5tkEdljHOuN31/qdKNge8H6uKH8zXRZsj5pd8adpW
kD4TzIMvzIwzizsGw34O9hf1E2XPoDqvQr39p1sovX3PeDvRJY/7JFNt9DsphVc3
xWQfNkC7JdMPa6JRiFHd3ynfbQ+wplf4tfaDVn1JXAWp0NSGgMtXfn5i19hHQWjm
RNAKNQLdVn8UczI8XdVM7bS4giDpQMukSyjsjgAo466iRK2+8f8BwIRe1JRvF37B
dnbvTg/dzoi1/E4ukwVJD6YE2LlDwzdGno9KxPlRsuY3nnheVgjbrGJ2XKRJkIk8
7cMGh41VKw6L4usAEQEAAYkBHwQYAQIACQUCWUwTFgIbDAAKCRC6wwYiM5mUxEiH
CACQViGOHi0BoZ78ZJz6L48YNMx8fSdSv3YJ83Ih1n5DWCJgrDV5S3/edYinkoVI
0Lusy3MdftRg6OWaYOuOTf6MYcddO/mY363jiMByf9Uh3Dqq4sKqVLRnZbAqgD1o
dRoj2NkEQfgEH/H4JRVrxquzAKoWwJh3MhY+kajYJRJyWfc1/Bm3Bj1tcMGlGeIQ
fgWheeMg3kxrxJ9TXPqVi6VVPaPKIU5i8l46S+Wg3uvMs8vC3XzOIvhY6cwguJv9
UkjZwGDSI952wLqnREMy0gFZ+OAB0qJpYM3nDEekWZP38G80kojnN61tZjRThu9I
i8/b+PwSW+nW3EpQZdLqZtOU
=2H2i
02FpKd79HmR7bHdc4e2olEf9NlHxfbPXDDsHABEBAAG0IUNocmlzIFBvdmlyayA8
Y3Bvdmlya0Bnb29nbGUuY29tPrkBDQRZTBMWAQgA2YylXc0rxousuBBPKHn75163
wLcPdPm2QR2WMc643fX+p0o2B7wfq4ofzNdFmyPml3xp2laQPhPMgy/MjDOLOwbD
fg72F/UTZc+gOq9Cvf2nWyi9fc94O9Elj/skU230OymFVzfFZB82QLsl0w9rolGI
Ud3fKd9tD7CmV/i19oNWfUlcBanQ1IaAy1d+fmLX2EdBaOZE0Ao1At1WfxRzMjxd
1UzttLiCIOlAy6RLKOyOACjjrqJErb7x/wHAhF7UlG8XfsF2du9OD93OiLX8Ti6T
BUkPpgTYuUPDN0aej0rE+VGy5jeeeF5WCNusYnZcpEmQiTztwwaHjVUrDovi6wAR
AQABiQEfBBgBAgAJBQJZTBMWAhsMAAoJELrDBiIzmZTESIcIAJBWIY4eLQGhnvxk
nPovjxg0zHx9J1K/dgnzciHWfkNYImCsNXlLf951iKeShUjQu6zLcx1+1GDo5Zpg
645N/oxhx107+ZjfreOIwHJ/1SHcOqriwqpUtGdlsCqAPWh1GiPY2QRB+AQf8fgl
FWvGq7MAqhbAmHcyFj6RqNglEnJZ9zX8GbcGPW1wwaUZ4hB+BaF54yDeTGvEn1Nc
+pWLpVU9o8ohTmLyXjpL5aDe68yzy8LdfM4i+FjpzCC4m/1SSNnAYNIj3nbAuqdE
QzLSAVn44AHSomlgzecMR6RZk/fwbzSSiOc3rW1mNFOG70iLz9v4/BJb6dbcSlBl
0upm05Q=
=Gf3Y
-----END PGP PUBLIC KEY BLOCK-----
pub BCF4173966770193
@ -1433,15 +1436,18 @@ IaddzrPZPmaZ8CtzzyB7+JdSNItBB2Sp
-----END PGP PUBLIC KEY BLOCK-----
pub BDD2A76422470515
uid Dave Brosius <dbrosius@mebigfatguy.com>
sub 0C77E993AC36C97C
-----BEGIN PGP PUBLIC KEY BLOCK-----
mDMEaDypvxYJKwYBBAHaRw8BAQdAv3OEFRIQWBhSii0M3S9P3eGlZLalGY9smzBQ
C0aiVXW4OARoPKm/EgorBgEEAZdVAQUBAQdA2THBTS3MqZPdTuKmc7QkAvlvwmJa
WEQsXXqkjQdEwD4DAQgHiH4EGBYKACYWIQSu/rh4kM398rwIxKq90qdkIkcFFQUC
aDypvwIbDAUJBaOagAAKCRC90qdkIkcFFfyUAPsGJcpKQP2/sQe+XN69rVZMFXhk
dYg0U9EhpY/7GHDpHQD+J5Uy2s3USLxeyIylXUFWtxqOocB+vZhvH3Yhmjhwmgw=
=zAHg
C0aiVXW0J0RhdmUgQnJvc2l1cyA8ZGJyb3NpdXNAbWViaWdmYXRndXkuY29tPrg4
BGg8qb8SCisGAQQBl1UBBQEBB0DZMcFNLcypk91O4qZztCQC+W/CYlpYRCxdeqSN
B0TAPgMBCAeIfgQYFgoAJhYhBK7+uHiQzf3yvAjEqr3Sp2QiRwUVBQJoPKm/AhsM
BQkFo5qAAAoJEL3Sp2QiRwUV/JQA+wYlykpA/b+xB75c3r2tVkwVeGR1iDRT0SGl
j/sYcOkdAP4nlTLazdRIvF7IjKVdQVa3Go6hwH69mG8fdiGaOHCaDA==
=wcNA
-----END PGP PUBLIC KEY BLOCK-----
pub BEDE11EAF1164480
@ -6180,8 +6186,6 @@ c8LNGrDaCFdXnOdlNV/zT9VvBk/RkV+Tl/Lk4g==
-----END PGP PUBLIC KEY BLOCK-----
pub 7905DE25C78AD456
uid Protobuf Release <protobuf@googlegroups.com>
sub DBC5123E2E98FEFE
-----BEGIN PGP PUBLIC KEY BLOCK-----
@ -6193,26 +6197,25 @@ Uul7vR3iNRXtbnS31qIgCYWAoX6w0xHf6KUeIPWV21ZIUu5cg6kQr/sPt/OQuGS2
nKk+InYtopDi6d7AUh8WI2TP7qAMIoRkhAeDEQ99DiopwFNPA/7M4g99AQfFSmp3
acPCdeXXAZeDAqoFGFKTlqzg3FLWpGkubI/iXyHkpQfOXv4MtYuPGVNheBXGcWbf
XPjbkFYjkGIN2Wx4i7yf43hMCk6ArhswfgCcgoORI+DCVdm7ORID1PjIU2Z71EA2
qDdFwdoOdEV42YUAEQEAAbQsUHJvdG9idWYgUmVsZWFzZSA8cHJvdG9idWZAZ29v
Z2xlZ3JvdXBzLmNvbT65AY0EZKxkKwEMAK4LeTj1dr8F9E98Up6y4AKHY0Zbeb5v
c/TzsJX6UCudzygYTbQnEcrPIcJ5TJV5leniAlxnqUz/qJxmpBtGCNH63c9+iJNh
VqJEZh9dbupqQn+mqtBvsPABbHU+C46TLebmOK4R99zgtxVlSYabJubuG2Mqnq96
mutBUWKI3iY5j0JAMLY1DJesAGwAWP8gvUZHhd4LJN3iikNSTWyUE0Hnwm2VKFq4
cxI/6qaCpztfuSD1y0JplSfmKRd+ecLSqhDvlMZkwigUpjCvF7iSaPvpxWdkFabS
frMeIjwbGU/fLV8ilwtPPb57X6Nrk9NIUdVa6ZbxiuIErIcp3JfgfUfy7wxcI/Uj
Mq1I50NOwizLVprZbmKv1P88bACmdon612pnDhhs84phJmA7fzQ/jAqF1JQ4Crdz
L+6g56Kkx1VlN3dSmPjuycjTzykuNwZ/Fi0Lj9Czg4LVp6peSsPWS+lp9h9tOSzt
lQev+GXiQKZTYt8JxvBPOkm0hd5M30BDbwARAQABiQG8BBgBCgAmFiEEGlXwka0o
wH+DH6RNeQXeJceK1FYFAmSsZCsCGwwFCQPCZwAACgkQeQXeJceK1FbX9wwAmLBK
Q8JljEwk0KqYxawrusWXwaH+1I83urf/WsOJYEkKoiQObsFGTuaolyln6ZHyF+gt
uKeWtlbvG6aXqv9XXcsVQG7NMGdEAy6DTNj77uBAXMWTxVpD09iVeepvWSiz7r7M
gzJfluNgGDOGKpkxxIjS8NnOAsK9uquyvBQa97I+YniarTkpnVWpgSR/7V3HHf6Q
2aCKL3ihdK2uIS4dIrFi+mVCt2zDad8U8N7S2Gv2VO/vBF+hIFCV788hLH9HeX3f
70E99X57hrVCh0MeColOIV1zwK8GLeV7bpr6x11x5cjiv27xky95WteyH5w9w/Xq
Tu0NQ5YyKX/0PUYVX3mLs59H7Wys6ANygWJs59JT4KSwb3pIEV7gWSwp3mWkstlF
m4Tq/d+gVF64ItrHylZg0WpHPv1s+dH6/tWcsBnkgR/OS33PkijQgvMW4imQNRxg
ymOZIduHXX1X+KzlRZTXvv4tSFnIQ0mWY1ySiOJQJS2WABVwFpFc8rECm6eN
=z4dc
qDdFwdoOdEV42YUAEQEAAbkBjQRkrGQrAQwArgt5OPV2vwX0T3xSnrLgAodjRlt5
vm9z9POwlfpQK53PKBhNtCcRys8hwnlMlXmV6eICXGepTP+onGakG0YI0frdz36I
k2FWokRmH11u6mpCf6aq0G+w8AFsdT4LjpMt5uY4rhH33OC3FWVJhpsm5u4bYyqe
r3qa60FRYojeJjmPQkAwtjUMl6wAbABY/yC9RkeF3gsk3eKKQ1JNbJQTQefCbZUo
WrhzEj/qpoKnO1+5IPXLQmmVJ+YpF355wtKqEO+UxmTCKBSmMK8XuJJo++nFZ2QV
ptJ+sx4iPBsZT98tXyKXC089vntfo2uT00hR1VrplvGK4gSshyncl+B9R/LvDFwj
9SMyrUjnQ07CLMtWmtluYq/U/zxsAKZ2ifrXamcOGGzzimEmYDt/ND+MCoXUlDgK
t3Mv7qDnoqTHVWU3d1KY+O7JyNPPKS43Bn8WLQuP0LODgtWnql5Kw9ZL6Wn2H205
LO2VB6/4ZeJAplNi3wnG8E86SbSF3kzfQENvABEBAAGJAbwEGAEKACYWIQQaVfCR
rSjAf4MfpE15Bd4lx4rUVgUCZKxkKwIbDAUJA8JnAAAKCRB5Bd4lx4rUVtf3DACY
sEpDwmWMTCTQqpjFrCu6xZfBof7Ujze6t/9aw4lgSQqiJA5uwUZO5qiXKWfpkfIX
6C24p5a2Vu8bppeq/1ddyxVAbs0wZ0QDLoNM2Pvu4EBcxZPFWkPT2JV56m9ZKLPu
vsyDMl+W42AYM4YqmTHEiNLw2c4Cwr26q7K8FBr3sj5ieJqtOSmdVamBJH/tXccd
/pDZoIoveKF0ra4hLh0isWL6ZUK3bMNp3xTw3tLYa/ZU7+8EX6EgUJXvzyEsf0d5
fd/vQT31fnuGtUKHQx4KiU4hXXPArwYt5XtumvrHXXHlyOK/bvGTL3la17IfnD3D
9epO7Q1DljIpf/Q9RhVfeYuzn0ftbKzoA3KBYmzn0lPgpLBvekgRXuBZLCneZaSy
2UWbhOr936BUXrgi2sfKVmDRakc+/Wz50fr+1ZywGeSBH85Lfc+SKNCC8xbiKZA1
HGDKY5kh24ddfVf4rOVFlNe+/i1IWchDSZZjXJKI4lAlLZYAFXAWkVzysQKbp40=
=UiVm
-----END PGP PUBLIC KEY BLOCK-----
pub 793FD5751A0F0780

View File

@ -34,8 +34,10 @@
<trusted-key id="0F06FF86BEEAF4E71866EE5232EE5355A6BC6E42">
<trusting group="androidx.appcompat"/>
<trusting group="androidx.camera"/>
<trusting group="androidx.collection"/>
<trusting group="androidx.compose.runtime"/>
<trusting group="androidx.constraintlayout"/>
<trusting group="androidx.core"/>
<trusting group="androidx.databinding"/>
<trusting group="androidx.datastore"/>
<trusting group="androidx.exifinterface" name="exifinterface" version="1.4.0"/>
@ -235,7 +237,10 @@
<trusting group="^androidx[.]test($|([.].*))" regex="true"/>
<trusting group="^com[.]android($|([.].*))" regex="true"/>
</trusted-key>
<trusted-key id="A6D6C97108B8585F91B158748671A8DF71296252" group="com.squareup" name="javapoet" version="1.10.0"/>
<trusted-key id="A6D6C97108B8585F91B158748671A8DF71296252">
<trusting name="javapoet" group="com.squareup" version="1.10.0"/>
<trusting group="com.squareup.okhttp3"/>
</trusted-key>
<trusted-key id="A7892505CF1A58076453E52D7999BEFBA1039E8B" group="net.bytebuddy"/>
<trusted-key id="AA417737BD805456DB3CBDDE6601E5C08DCCBB96" group="info.picocli" name="picocli" version="4.7.5"/>
<trusted-key id="AA70C7C433D501636392EC02153E7A3C2B4E5118" group="org.eclipse.ee4j" name="project"/>
@ -252,7 +257,10 @@
<trusting group="joda-time" name="joda-time" version="2.13.1"/>
<trusting group="joda-time" name="joda-time" version="2.14.0"/>
</trusted-key>
<trusted-key id="B6E73D84EA4FCC47166087253FAAD2CD5ECBB314" group="org.apache.commons" name="commons-parent" version="52"/>
<trusted-key id="B6E73D84EA4FCC47166087253FAAD2CD5ECBB314">
<trusting group="org.apache.commons"/>
<trusting name="commons-parent" group="org.apache.commons" version="52"/>
</trusted-key>
<trusted-key id="B801E2F8EF035068EC1139CC29579F18FA8FD93B" group="com.google.j2objc" name="j2objc-annotations" version="1.3"/>
<trusted-key id="BC87A3FD0A54480F0BADBEBD21939FF0CA2A6567" group="commons-codec" name="commons-codec" version="1.15"/>
<trusted-key id="BCC135FC7ED8214F823D73E97FE9900F412D622E" group="com.google.flatbuffers" name="flatbuffers-java" version="1.12.0"/>
@ -332,6 +340,11 @@
<sha256 value="27a4be7462629c312da0b831a0978d2076fc34074145fb61dd4e86d7c8469b82" origin="Generated by Gradle" reason="Artifact is not signed"/>
</artifact>
</component>
<component name="activity" group="androidx.activity" version="1.1.0">
<artifact name="activity-1.1.0.pom">
<sha256 origin="Generated by Gradle" reason="Artifact is not signed" value="3690001fc5a57ad176cacf7a13f56219bffb73b93c7978dbac1e1e5db082d6c0"/>
</artifact>
</component>
<component group="androidx.activity" name="activity" version="1.2.4">
<artifact name="activity-1.2.4.aar">
<sha256 value="ae8e9c7de57e387d2ad90e73f3a5a5dfd502bd4f034c1dccfdb3506d1d2df81a" origin="Generated by Gradle" reason="Artifact is not signed"/>
@ -974,6 +987,11 @@
<sha256 value="cf968e0494335d200dc0a2bf82df7501b14bbccde74d615672ef8b915cd6045a" origin="Generated by Gradle" reason="Artifact is not signed"/>
</artifact>
</component>
<component name="compose-bom" group="androidx.compose" version="2025.06.00">
<artifact name="compose-bom-2025.06.00.pom">
<sha256 origin="Generated by Gradle" reason="Artifact is not signed" value="a8b9c186caa05ec7bf27fc33db0c1b494a78b4f9a0c3ce1fa3c6f6b970ddc5ec"/>
</artifact>
</component>
<component group="androidx.compose.animation" name="animation" version="1.7.7">
<artifact name="animation-1.7.7.module">
<sha256 value="3431b3d00a8e6e0d54aff825a0a66402d8e924c2b2e6a165669e4f41c7a63fc9" origin="Generated by Gradle"/>
@ -1970,6 +1988,11 @@
<sha256 value="69b79724566d49140846700690b8d2165231c577e93e66726a443e8f976bbe19" origin="Generated by Gradle" reason="Artifact is not signed"/>
</artifact>
</component>
<component name="constraintlayout" group="androidx.constraintlayout" version="1.1.3">
<artifact name="constraintlayout-1.1.3.pom">
<sha256 origin="Generated by Gradle" reason="Artifact is not signed" value="a47057d0a9b23342c3779d3d56b60944997e98f0c5d8886fda29e4f1074d9ea6"/>
</artifact>
</component>
<component group="androidx.constraintlayout" name="constraintlayout" version="2.0.1">
<artifact name="constraintlayout-2.0.1.aar">
<sha256 value="ec15b5d4a2eff07888bc1499ce2e2c6efe24c0ed60cc57b08c9dc4b6fd3c2189" origin="Generated by Gradle" reason="Artifact is not signed"/>
@ -2079,6 +2102,11 @@
<sha256 value="2a10979bbb3bcd7b25b7f664ab4e9b016fabf2174a26768b677e12e4bea4c7c4" origin="Generated by Gradle"/>
</artifact>
</component>
<component name="core" group="androidx.core" version="1.16.0">
<artifact name="core-1.16.0.aar">
<sha256 origin="Generated by Gradle" value="6bf03d39dbe3744acce227d3b697374c3625aae1025fbec8ad9fd7bd58bce431"/>
</artifact>
</component>
<component group="androidx.core" name="core" version="1.2.0">
<artifact name="core-1.2.0.aar">
<sha256 value="524b8b88ceb6a74a7e44e6b567a135660f211799904cb218bfee5be1166820b2" origin="Generated by Gradle" reason="Artifact is not signed"/>
@ -2113,6 +2141,11 @@
<sha256 value="8674ade1d12962469dd2d1e6edc03b465f20d180b0840a129bc40b351e8651d1" origin="Generated by Gradle" reason="Artifact is not signed"/>
</artifact>
</component>
<component name="core-ktx" group="androidx.core" version="1.1.0">
<artifact name="core-ktx-1.1.0.pom">
<sha256 origin="Generated by Gradle" reason="Artifact is not signed" value="729d11bad16d87c6212dc9ab80e9c770d333115062136e0732164a6b1696e11c"/>
</artifact>
</component>
<component group="androidx.core" name="core-ktx" version="1.13.1">
<artifact name="core-ktx-1.13.1.aar">
<sha256 value="19ba50d094c7368ede1b4ccf1195ceb83e35970736593f823e5af716f8d05d70" origin="Generated by Gradle"/>
@ -3011,7 +3044,7 @@
<sha256 value="8770c180103e0b8c04a07eb4c59153af639b09eca25deae9bdcdaf869d1e5b6b" origin="Generated by Gradle"/>
</artifact>
<artifact name="exifinterface-1.3.2.module">
<sha256 value="10ba5b5cbea7f5c8758be4fdaec60a3545e891a1130d830a442b88cf5336a885" origin="Generated by Gradle"/>
<sha256 origin="Generated by Gradle" reason="Artifact is not signed" value="10ba5b5cbea7f5c8758be4fdaec60a3545e891a1130d830a442b88cf5336a885"/>
</artifact>
</component>
<component group="androidx.exifinterface" name="exifinterface" version="1.3.6">
@ -10235,6 +10268,14 @@
<sha256 value="16df4da63602c412d8712018c4b35ce24cb040761bcbc026fbcd836dbe953171" origin="Generated by Gradle" reason="Artifact is not signed"/>
</artifact>
</component>
<component name="core" group="com.github.nextcloud.android-common" version="0.26.0">
<artifact name="core-0.26.0.aar">
<sha256 origin="Generated by Gradle" reason="Artifact is not signed" value="933d612d1324b21d2e7e04a890bb2c7afda4ffdbe91b76fdea625976f14ba1fb"/>
</artifact>
<artifact name="core-0.26.0.module">
<sha256 origin="Generated by Gradle" reason="Artifact is not signed" value="b0194f2d5ce11e87603eb9d8d0f61a38442cf310d6445e02bb7c04b593d04ebd"/>
</artifact>
</component>
<component group="com.github.nextcloud.android-common" name="material-color-utilities" version="0.18.0">
<artifact name="material-color-utilities-0.18.0.jar">
<sha256 value="e04a3f4a3caff6e4b2ce3f14f91f0485ab1f012af652102eba61ab6bcf3d8240" origin="Generated by Gradle" reason="Artifact is not signed"/>
@ -10299,6 +10340,14 @@
<sha256 value="ca3c0835e5534a549d3718380982ba8cead70613ca436d65606f16cd2e3a0f01" origin="Generated by Gradle" reason="Artifact is not signed"/>
</artifact>
</component>
<component name="material-color-utilities" group="com.github.nextcloud.android-common" version="0.26.0">
<artifact name="material-color-utilities-0.26.0.jar">
<sha256 origin="Generated by Gradle" reason="Artifact is not signed" value="64c9e61afb6fd0d4ee03dd394429ab1c393f5b66429e036b618285d1bb7d8160"/>
</artifact>
<artifact name="material-color-utilities-0.26.0.module">
<sha256 origin="Generated by Gradle" reason="Artifact is not signed" value="6e646b238fad314fcbb72e59b198e2d39183191a7fd2dff273ef3e924cf1b915"/>
</artifact>
</component>
<component group="com.github.nextcloud.android-common" name="ui" version="0.18.0">
<artifact name="ui-0.18.0.aar">
<sha256 value="7d900a930d7ad1f7de91177b8b661abef13deef032493cee99fe9842f85bcf16" origin="Generated by Gradle" reason="Artifact is not signed"/>
@ -10363,6 +10412,14 @@
<sha256 value="4af371de8c6cd41a24f1a3ade9cd010c5d226a583d95ff909b1ca80f02d86db6" origin="Generated by Gradle" reason="Artifact is not signed"/>
</artifact>
</component>
<component name="ui" group="com.github.nextcloud.android-common" version="0.26.0">
<artifact name="ui-0.26.0.aar">
<sha256 origin="Generated by Gradle" reason="Artifact is not signed" value="6a34b9c6e11d1ad2e6578421f9432997b62ca456e41ffcc0c2cbfaa508eb9f11"/>
</artifact>
<artifact name="ui-0.26.0.module">
<sha256 origin="Generated by Gradle" reason="Artifact is not signed" value="7aadbf0d9e84d63996bdc9f70fdb36a15e633fccda902627241d418bf8363e25"/>
</artifact>
</component>
<component group="com.github.spotbugs" name="spotbugs" version="4.8.6">
<artifact name="spotbugs-4.8.6.jar">
<sha256 value="69fde8787971a26b2372d416015d806bf7df4f847f7121bd5eeef239324cf180" origin="Generated by Gradle"/>
@ -10560,6 +10617,11 @@
<sha256 value="96f6e6d9f5e5db840ee3da20449e16828ed4ba2c07783dde3397d13aaf814e19" origin="Generated by Gradle" reason="Artifact is not signed"/>
</artifact>
</component>
<component name="play-services-base" group="com.google.android.gms" version="18.1.0">
<artifact name="play-services-base-18.1.0.pom">
<sha256 origin="Generated by Gradle" reason="Artifact is not signed" value="30df78ba3ead133c2b36784b425a9eeee7f02531907e8aaee4e8922354f732a7"/>
</artifact>
</component>
<component group="com.google.android.gms" name="play-services-base" version="18.2.0">
<artifact name="play-services-base-18.2.0.aar">
<sha256 value="ba1efe418b7e2696878cc604c27dc7af32a2c71462df55632307c909aa9c2e11" origin="Generated by Gradle" reason="Artifact is not signed"/>
@ -10704,6 +10766,11 @@
<sha256 value="9ddba12b5c80444c45413f043b34fd3127c2493c506a9db1ecbfe63039d83e34" origin="Generated by Gradle" reason="Artifact is not signed"/>
</artifact>
</component>
<component name="material" group="com.google.android.material" version="1.3.0">
<artifact name="material-1.3.0.module">
<sha256 origin="Generated by Gradle" reason="Artifact is not signed" value="5d6b782ba57e549b8f00bc902664085e9a63c11e177f934589ba6331a764543b"/>
</artifact>
</component>
<component group="com.google.android.material" name="material" version="1.4.0">
<artifact name="material-1.4.0.aar">
<sha256 value="80a0e02abf8a8a8cbe5716e06ac80cd683840b9f5b0d2f19a2a279e47f2895ee" origin="Generated by Gradle" reason="Artifact is not signed"/>
@ -10712,6 +10779,11 @@
<sha256 value="91eecf4b1272aacc4fdb41fefaa6324cbd36218c51866d300dcf237670e4e0cc" origin="Generated by Gradle" reason="Artifact is not signed"/>
</artifact>
</component>
<component name="material" group="com.google.android.material" version="1.8.0">
<artifact name="material-1.8.0.module">
<sha256 origin="Generated by Gradle" reason="Artifact is not signed" value="94935b8018ddb4ef844eb107c46f2fa2bc6b548cf6642c26e30ab3ac6daa77ab"/>
</artifact>
</component>
<component group="com.google.api.grpc" name="proto-google-common-protos" version="2.0.1">
<artifact name="proto-google-common-protos-2.0.1.pom">
<sha256 value="8b62bfd85d693ebcffd828232af7424f34fd212c5e28e5ed99b0dc5d2bc7d4f5" origin="Generated by Gradle"/>
@ -11141,6 +11213,11 @@
<sha256 value="14ecb4776a8071e86129833319431399b2a69e6e9bfedcb2992538bdaca6cfc0" origin="Generated by Gradle"/>
</artifact>
</component>
<component name="symbol-processing-api" group="com.google.devtools.ksp" version="2.1.21-2.0.2">
<artifact name="symbol-processing-api-2.1.21-2.0.2.module">
<sha256 origin="Generated by Gradle" value="763cb8bfabf57ae1ac3c5c69baed6cf6a849eaa90b1222d87e8ddf754222168e"/>
</artifact>
</component>
<component group="com.google.devtools.ksp" name="symbol-processing-cmdline" version="2.1.10-1.0.29">
<artifact name="symbol-processing-cmdline-2.1.10-1.0.29.jar">
<sha256 value="b5c69be50ef939a21c23d1132457ce1566a0aced2c44cabceca8788320df58b8" origin="Generated by Gradle"/>
@ -14300,6 +14377,11 @@
<sha256 value="80eb61b0c87fdd826a069313b28b672da3f1885832da447b51e6e8a6197e7ecb" origin="Generated by Gradle"/>
</artifact>
</component>
<component name="commons-parent" group="org.apache.commons" version="78">
<artifact name="commons-parent-78.pom">
<sha256 origin="Generated by Gradle" value="022d202e655edd04f2a10ecbe453d92977924d38380a4ca8c359f1817a80320e"/>
</artifact>
</component>
<component group="org.apache.commons" name="commons-text" version="1.10.0">
<artifact name="commons-text-1.10.0.jar">
<sha256 value="770cd903fa7b604d1f7ef7ba17f84108667294b2b478be8ed1af3bffb4ae0018" origin="Generated by Gradle"/>
@ -17219,6 +17301,11 @@
<sha256 value="e67459d4882424ac6374f40db1c8f4a2e88946b340ba072c80be932a2be4644d" origin="Generated by Gradle"/>
</artifact>
</component>
<component name="junit-bom" group="org.junit" version="5.11.2">
<artifact name="junit-bom-5.11.2.pom">
<sha256 origin="Generated by Gradle" value="f48e88538aac145eb3ae0345a9ebd055b28f329a35dce8d1e9281325ca9b0ea2"/>
</artifact>
</component>
<component group="org.junit" name="junit-bom" version="5.11.4">
<artifact name="junit-bom-5.11.4.module">
<sha256 value="a9a4f27be94e99b9d570162d246a80f686d277d5d31aeb5481047cf51daf46e4" origin="Generated by Gradle"/>