Add QR scanning to username link flow.

This commit is contained in:
Greyson Parrelli 2023-04-03 09:56:44 -04:00 committed by Nicholas Tinsley
parent bb8fdcabcb
commit dc2e249566
15 changed files with 882 additions and 36 deletions

View file

@ -559,6 +559,7 @@ dependencies {
}
implementation libs.dnsjava
implementation libs.kotlinx.collections.immutable
implementation libs.accompanist.permissions
spinnerImplementation project(":spinner")

View file

@ -2,6 +2,7 @@ package org.thoughtcrime.securesms.components.settings.app.usernamelinks
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.material3.Surface
import androidx.compose.runtime.Composable
@ -93,12 +94,12 @@ private fun DrawScope.drawQr(
}
// Logo border
val deadzonePaddingPercent = 0.02f
val deadzonePaddingPercent = 0.03f
val logoBorderRadiusPx = ((deadzonePercent - deadzonePaddingPercent) * size.width) / 2
drawCircle(
color = foregroundColor,
radius = logoBorderRadiusPx,
style = Stroke(width = cellWidthPx * 0.7f),
style = Stroke(width = 4.dp.toPx()),
center = this.center
)
@ -156,9 +157,7 @@ private fun Preview() {
Surface {
QrCode(
data = QrCodeData.forData("https://signal.org", 64),
modifier = Modifier
.width(100.dp)
.height(100.dp),
modifier = Modifier.size(200.dp),
deadzonePercent = 0.3f
)
}

View file

@ -0,0 +1,16 @@
package org.thoughtcrime.securesms.components.settings.app.usernamelinks.main
import org.thoughtcrime.securesms.recipients.Recipient
/**
* Result of taking data from the QR scanner and trying to resolve it to a recipient.
*/
sealed class QrScanResult {
class Success(val recipient: Recipient) : QrScanResult()
class NotFound(val username: String) : QrScanResult()
object InvalidData : QrScanResult()
object NetworkError : QrScanResult()
}

View file

@ -1,25 +1,61 @@
package org.thoughtcrime.securesms.components.settings.app.usernamelinks.main
import android.os.Bundle
import android.view.View
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.slideInHorizontally
import androidx.compose.animation.slideOutHorizontally
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.defaultMinSize
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold
import androidx.compose.material3.SnackbarHost
import androidx.compose.material3.SnackbarHostState
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.fragment.app.viewModels
import androidx.navigation.NavController
import androidx.navigation.fragment.findNavController
import com.google.accompanist.permissions.ExperimentalPermissionsApi
import com.google.accompanist.permissions.PermissionState
import com.google.accompanist.permissions.isGranted
import com.google.accompanist.permissions.rememberPermissionState
import kotlinx.coroutines.CoroutineScope
import org.signal.core.ui.Buttons
import org.signal.core.ui.Dialogs
import org.signal.core.ui.theme.SignalTheme
import org.signal.core.util.concurrent.LifecycleDisposable
import org.thoughtcrime.securesms.R
import org.thoughtcrime.securesms.components.settings.app.usernamelinks.main.UsernameLinkSettingsState.ActiveTab
import org.thoughtcrime.securesms.compose.ComposeFragment
@OptIn(ExperimentalMaterial3Api::class)
@OptIn(
ExperimentalMaterial3Api::class,
ExperimentalPermissionsApi::class
)
class UsernameLinkSettingsFragment : ComposeFragment() {
val viewModel: UsernameLinkSettingsViewModel by viewModels()
private val viewModel: UsernameLinkSettingsViewModel by viewModels()
private val disposables: LifecycleDisposable = LifecycleDisposable()
@Composable
override fun FragmentContent() {
@ -29,23 +65,121 @@ class UsernameLinkSettingsFragment : ComposeFragment() {
val navController: NavController by remember { mutableStateOf(findNavController()) }
Scaffold(
snackbarHost = { SnackbarHost(hostState = snackbarHostState) }
snackbarHost = { SnackbarHost(hostState = snackbarHostState) },
topBar = { TopAppBarContent(state.activeTab) }
) { contentPadding ->
UsernameLinkShareScreen(
state = state,
snackbarHostState = snackbarHostState,
scope = scope,
contentPadding = contentPadding,
navController = navController
)
if (state.indeterminateProgress) {
Dialogs.IndeterminateProgressDialog()
}
AnimatedVisibility(
visible = state.activeTab == ActiveTab.Code,
enter = slideInHorizontally(initialOffsetX = { fullWidth -> -fullWidth }),
exit = slideOutHorizontally(targetOffsetX = { fullWidth -> -fullWidth })
) {
UsernameLinkShareScreen(
state = state,
snackbarHostState = snackbarHostState,
scope = scope,
modifier = Modifier.padding(contentPadding),
navController = navController
)
}
AnimatedVisibility(
visible = state.activeTab == ActiveTab.Scan,
enter = slideInHorizontally(initialOffsetX = { fullWidth -> fullWidth }),
exit = slideOutHorizontally(targetOffsetX = { fullWidth -> fullWidth })
) {
UsernameQrScanScreen(
lifecycleOwner = viewLifecycleOwner,
disposables = disposables.disposables,
qrScanResult = state.qrScanResult,
onQrCodeScanned = { data -> viewModel.onQrCodeScanned(data) },
onQrResultHandled = { viewModel.onQrResultHandled() },
modifier = Modifier.padding(contentPadding)
)
}
}
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
disposables.bindTo(viewLifecycleOwner)
}
override fun onResume() {
super.onResume()
viewModel.onResume()
}
@Composable
private fun TopAppBarContent(activeTab: ActiveTab) {
val cameraPermissionState: PermissionState = rememberPermissionState(permission = android.Manifest.permission.CAMERA)
Box(
modifier = Modifier
.fillMaxWidth()
.height(64.dp)
) {
Row(
modifier = Modifier
.fillMaxWidth()
.fillMaxHeight(),
horizontalArrangement = Arrangement.Center,
verticalAlignment = Alignment.CenterVertically
) {
TabButton(
label = stringResource(R.string.UsernameLinkSettings_code_tab_name),
active = activeTab == ActiveTab.Code,
onClick = { viewModel.onTabSelected(ActiveTab.Code) },
modifier = Modifier.padding(end = 8.dp)
)
TabButton(
label = stringResource(R.string.UsernameLinkSettings_scan_tab_name),
active = activeTab == ActiveTab.Scan,
onClick = {
if (cameraPermissionState.status.isGranted) {
viewModel.onTabSelected(ActiveTab.Scan)
} else {
cameraPermissionState.launchPermissionRequest()
}
}
)
}
}
}
@Composable
private fun TabButton(label: String, active: Boolean, onClick: () -> Unit, modifier: Modifier = Modifier) {
val colors = if (active) {
ButtonDefaults.filledTonalButtonColors()
} else {
ButtonDefaults.buttonColors(
containerColor = SignalTheme.colors.colorSurface2,
contentColor = MaterialTheme.colorScheme.onSurface
)
}
Buttons.MediumTonal(
onClick = onClick,
modifier = modifier.defaultMinSize(minWidth = 100.dp),
shape = RoundedCornerShape(12.dp),
colors = colors
) {
Text(label)
}
}
@Preview
@Composable
private fun AppBarPreview() {
SignalTheme(isDarkMode = false) {
Surface {
TopAppBarContent(activeTab = ActiveTab.Code)
}
}
}
@Preview
@Composable
fun PreviewAll() {

View file

@ -7,8 +7,15 @@ import org.thoughtcrime.securesms.components.settings.app.usernamelinks.Username
* Represents the UI state of the [UsernameLinkSettingsFragment].
*/
data class UsernameLinkSettingsState(
val activeTab: ActiveTab,
val username: String,
val usernameLink: String,
val qrCodeData: QrCodeData?,
val qrCodeColorScheme: UsernameQrCodeColorScheme
)
val qrCodeColorScheme: UsernameQrCodeColorScheme,
val qrScanResult: QrScanResult? = null,
val indeterminateProgress: Boolean = false
) {
enum class ActiveTab {
Code, Scan
}
}

View file

@ -9,17 +9,27 @@ import io.reactivex.rxjava3.disposables.CompositeDisposable
import io.reactivex.rxjava3.kotlin.plusAssign
import io.reactivex.rxjava3.schedulers.Schedulers
import io.reactivex.rxjava3.subjects.BehaviorSubject
import org.signal.core.util.logging.Log
import org.signal.libsignal.usernames.BaseUsernameException
import org.thoughtcrime.securesms.components.settings.app.usernamelinks.QrCodeData
import org.thoughtcrime.securesms.components.settings.app.usernamelinks.main.UsernameLinkSettingsState.ActiveTab
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies
import org.thoughtcrime.securesms.keyvalue.SignalStore
import org.thoughtcrime.securesms.recipients.Recipient
import org.thoughtcrime.securesms.util.UsernameUtil
import org.whispersystems.signalservice.api.push.ACI
import org.whispersystems.signalservice.api.push.exceptions.NonSuccessfulResponseCodeException
import java.io.IOException
class UsernameLinkSettingsViewModel : ViewModel() {
private val TAG = Log.tag(UsernameLinkSettingsViewModel::class.java)
private val username: BehaviorSubject<String> = BehaviorSubject.createDefault(Recipient.self().username.get())
private val _state = mutableStateOf(
UsernameLinkSettingsState(
activeTab = ActiveTab.Code,
username = username.value!!,
usernameLink = UsernameUtil.generateLink(username.value!!),
qrCodeData = null,
@ -54,6 +64,61 @@ class UsernameLinkSettingsViewModel : ViewModel() {
)
}
fun onTabSelected(tab: ActiveTab) {
_state.value = _state.value.copy(
activeTab = tab
)
}
fun onQrCodeScanned(url: String) {
_state.value = _state.value.copy(
indeterminateProgress = true
)
disposable += Single
.fromCallable {
val username: String? = UsernameUtil.parseLink(url)
if (username == null) {
Log.w(TAG, "Failed to parse username from url")
return@fromCallable QrScanResult.InvalidData
}
return@fromCallable try {
val hashed: String = UsernameUtil.hashUsernameToBase64(username)
val aci: ACI = ApplicationDependencies.getSignalServiceAccountManager().getAciByUsernameHash(hashed)
QrScanResult.Success(Recipient.externalUsername(aci, username))
} catch (e: BaseUsernameException) {
Log.w(TAG, "Invalid username", e)
QrScanResult.InvalidData
} catch (e: NonSuccessfulResponseCodeException) {
Log.w(TAG, "Non-successful response during username resolution", e)
if (e.code == 404) {
QrScanResult.NotFound(username)
} else {
QrScanResult.NetworkError
}
} catch (e: IOException) {
Log.w(TAG, "Network error during username resolution", e)
QrScanResult.NetworkError
}
}
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe { result ->
_state.value = _state.value.copy(
qrScanResult = result,
indeterminateProgress = false
)
}
}
fun onQrResultHandled() {
_state.value = _state.value.copy(
qrScanResult = null
)
}
private fun generateQrCodeData(url: String): Single<QrCodeData> {
return Single.fromCallable {
QrCodeData.forData(url, 64)

View file

@ -5,7 +5,6 @@ import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
@ -36,6 +35,7 @@ import org.thoughtcrime.securesms.R
import org.thoughtcrime.securesms.components.settings.app.usernamelinks.QrCodeBadge
import org.thoughtcrime.securesms.components.settings.app.usernamelinks.QrCodeData
import org.thoughtcrime.securesms.components.settings.app.usernamelinks.UsernameQrCodeColorScheme
import org.thoughtcrime.securesms.components.settings.app.usernamelinks.main.UsernameLinkSettingsState.ActiveTab
import org.thoughtcrime.securesms.util.UsernameUtil
import org.thoughtcrime.securesms.util.Util
import org.thoughtcrime.securesms.util.navigation.safeNavigate
@ -49,12 +49,10 @@ fun UsernameLinkShareScreen(
snackbarHostState: SnackbarHostState,
scope: CoroutineScope,
navController: NavController,
modifier: Modifier = Modifier,
contentPadding: PaddingValues = PaddingValues(0.dp)
modifier: Modifier = Modifier
) {
Column(
modifier = modifier
.padding(contentPadding)
.verticalScroll(rememberScrollState())
) {
QrCodeBadge(
@ -85,7 +83,8 @@ fun UsernameLinkShareScreen(
text = stringResource(id = R.string.UsernameLinkSettings_qr_description),
textAlign = TextAlign.Center,
style = MaterialTheme.typography.bodyMedium,
modifier = Modifier.padding(top = 24.dp, bottom = 36.dp, start = 43.dp, end = 43.dp)
modifier = Modifier.padding(top = 24.dp, bottom = 36.dp, start = 43.dp, end = 43.dp),
color = MaterialTheme.colorScheme.onSurfaceVariant
)
Row(
@ -186,6 +185,7 @@ private fun ScreenPreviewDarkTheme() {
private fun previewState(): UsernameLinkSettingsState {
val link = UsernameUtil.generateLink("maya.45")
return UsernameLinkSettingsState(
activeTab = ActiveTab.Code,
username = "maya.45",
usernameLink = link,
qrCodeData = QrCodeData.forData(link, 64),

View file

@ -1,14 +1,144 @@
package org.thoughtcrime.securesms.components.settings.app.usernamelinks.main
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.drawWithContent
import androidx.compose.ui.geometry.CornerRadius
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.geometry.Size
import androidx.compose.ui.graphics.BlendMode
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.drawscope.DrawScope
import androidx.compose.ui.graphics.drawscope.Fill
import androidx.compose.ui.graphics.drawscope.Stroke
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.compose.ui.viewinterop.AndroidView
import androidx.lifecycle.LifecycleOwner
import io.reactivex.rxjava3.disposables.CompositeDisposable
import io.reactivex.rxjava3.kotlin.plusAssign
import org.signal.core.ui.Dialogs
import org.signal.qr.QrScannerView
import org.thoughtcrime.securesms.R
import org.thoughtcrime.securesms.mediasend.camerax.CameraXModelBlocklist
import org.thoughtcrime.securesms.util.CommunicationActions
/**
* A screen that allows you to scan a QR code to start a chat.
*/
@Composable
fun UsernameQrScanScreen(modifier: Modifier = Modifier) {
// TODO
Text(text = "QR Scanner Placeholder")
fun UsernameQrScanScreen(
lifecycleOwner: LifecycleOwner,
disposables: CompositeDisposable,
qrScanResult: QrScanResult?,
onQrCodeScanned: (String) -> Unit,
onQrResultHandled: () -> Unit,
modifier: Modifier = Modifier
) {
when (qrScanResult) {
QrScanResult.InvalidData -> {
QrScanResultDialog(stringResource(R.string.UsernameLinkSettings_qr_result_invalid), onDismiss = onQrResultHandled)
}
QrScanResult.NetworkError -> {
QrScanResultDialog(stringResource(R.string.UsernameLinkSettings_qr_result_network_error), onDismiss = onQrResultHandled)
}
is QrScanResult.NotFound -> {
QrScanResultDialog(stringResource(R.string.UsernameLinkSettings_qr_result_not_found, qrScanResult.username), onDismiss = onQrResultHandled)
}
is QrScanResult.Success -> {
CommunicationActions.startConversation(LocalContext.current, qrScanResult.recipient, null)
onQrResultHandled()
}
null -> {}
}
Column(
modifier = modifier
.fillMaxWidth()
.fillMaxHeight()
) {
AndroidView(
factory = { context ->
val view = QrScannerView(context)
disposables += view.qrData.subscribe { data ->
onQrCodeScanned(data)
}
view
},
update = { view ->
view.start(lifecycleOwner = lifecycleOwner, forceLegacy = CameraXModelBlocklist.isBlocklisted())
},
modifier = Modifier
.fillMaxWidth()
.weight(1f, true)
.drawWithContent {
drawContent()
drawQrCrosshair()
}
)
Row(
modifier = Modifier
.fillMaxWidth()
.padding(16.dp),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.Center
) {
Text(
text = stringResource(R.string.UsernameLinkSettings_qr_scan_description),
style = MaterialTheme.typography.bodyMedium,
color = MaterialTheme.colorScheme.onSurfaceVariant
)
}
}
}
@Composable
private fun QrScanResultDialog(message: String, onDismiss: () -> Unit) {
Dialogs.SimpleMessageDialog(
message = message,
dismiss = stringResource(id = android.R.string.ok),
onDismiss = onDismiss
)
}
private fun DrawScope.drawQrCrosshair() {
val crosshairWidth: Float = size.minDimension * 0.6f
val clearWidth: Float = crosshairWidth * 0.75f
// Draw a full white rounded rect...
drawRoundRect(
color = Color.White,
topLeft = center - Offset(crosshairWidth / 2, crosshairWidth / 2),
style = Stroke(width = 3.dp.toPx()),
size = Size(crosshairWidth, crosshairWidth),
cornerRadius = CornerRadius(10.dp.toPx(), 10.dp.toPx())
)
// ...then cut out the middle parts with BlendMode.Clear to leave us with just the corners
drawRect(
color = Color.White,
topLeft = Offset(center.x - clearWidth / 2, 0f),
style = Fill,
size = Size(clearWidth, size.height),
blendMode = BlendMode.Clear
)
drawRect(
color = Color.White,
topLeft = Offset(0f, center.y - clearWidth / 2),
style = Fill,
size = Size(size.width, clearWidth),
blendMode = BlendMode.Clear
)
}

View file

@ -247,14 +247,7 @@ public class ManageProfileFragment extends LoggingFragment {
binding.manageProfileUsernameShare.setVisibility(View.GONE);
} else {
binding.manageProfileUsername.setText(username);
try {
binding.manageProfileUsernameSubtitle.setText(UsernameUtil.generateLink(username));
} catch (BaseUsernameException e) {
Log.w(TAG, "Could not format username link", e);
binding.manageProfileUsernameSubtitle.setText(R.string.ManageProfileFragment_your_username);
}
binding.manageProfileUsernameSubtitle.setText(UsernameUtil.generateLink(username));
binding.manageProfileUsernameShare.setVisibility(View.VISIBLE);
}
}

View file

@ -14,6 +14,10 @@ public final class Base64 {
return org.whispersystems.util.Base64.decode(s);
}
public static @NonNull byte[] decodeWithoutPadding(@NonNull String s) throws IOException {
return org.whispersystems.util.Base64.decodeWithoutPadding(s);
}
public static @NonNull String encodeBytes(@NonNull byte[] source) {
return org.whispersystems.util.Base64.encodeBytes(source);
}

View file

@ -18,8 +18,10 @@ import org.whispersystems.signalservice.api.push.ServiceId;
import org.whispersystems.util.Base64UrlSafe;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Locale;
import java.util.Optional;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class UsernameUtil {
@ -31,6 +33,7 @@ public class UsernameUtil {
private static final Pattern FULL_PATTERN = Pattern.compile(String.format(Locale.US, "^[a-zA-Z_][a-zA-Z0-9_]{%d,%d}$", MIN_LENGTH - 1, MAX_LENGTH - 1), Pattern.CASE_INSENSITIVE);
private static final Pattern DIGIT_START_PATTERN = Pattern.compile("^[0-9].*$");
private static final Pattern URL_PATTERN = Pattern.compile("(https://)?signal.me/#u/([a-zA-Z0-9+/]*={0,2})");
private static final String BASE_URL_SCHEMELESS = "signal.me/#u/";
@ -80,6 +83,14 @@ public class UsernameUtil {
}
}
/**
* Hashes a username to a url-safe base64 string.
* @throws BaseUsernameException If the username is invalid and un-hashable.
*/
public static String hashUsernameToBase64(String username) throws BaseUsernameException {
return Base64UrlSafe.encodeBytesWithoutPadding(Username.hash(username));
}
@WorkerThread
public static @NonNull Optional<ServiceId> fetchAciForUsernameHash(@NonNull String base64UrlSafeEncodedUsernameHash) {
try {
@ -91,13 +102,33 @@ public class UsernameUtil {
}
}
public static String generateLink(String username) throws BaseUsernameException {
byte[] hash = Username.hash(username);
String base64 = Base64UrlSafe.encodeBytesWithoutPadding(hash);
public static String generateLink(String username) {
String base64 = Base64UrlSafe.encodeBytesWithoutPadding(username.getBytes(StandardCharsets.UTF_8));
return BASE_URL + base64;
}
/**
* Parses the username from a link if possible, otherwise null.
*/
public static @Nullable String parseLink(String url) {
Matcher matcher = URL_PATTERN.matcher(url);
if (!matcher.matches()) {
return null;
}
String base64 = matcher.group(2);
if (base64 == null) {
return null;
}
try {
return new String(Base64.decodeWithoutPadding(base64));
} catch (IOException e) {
return null;
}
}
public enum InvalidReason {
TOO_SHORT, TOO_LONG, INVALID_CHARACTERS, STARTS_WITH_NUMBER
}

View file

@ -6095,6 +6095,12 @@
<string name="UsernameLinkSettings_qr_scan_description">Scan the QR Code on your contacts device.</string>
<!-- App bar title for the username QR code color picker screen -->
<string name="UsernameLinkSettings_color_picker_app_bar_title">Color</string>
<!-- Body of a dialog that is displayed when we failed to read a username QR code. -->
<string name="UsernameLinkSettings_qr_result_invalid">The QR code was invalid.</string>
<!-- Body of a dialog that is displayed when the username we looked up could not be found. -->
<string name="UsernameLinkSettings_qr_result_not_found">A user with username $1$s could not be found.</string>
<!-- Body of a dialog that is displayed when we experienced a network error when looking up a username. -->
<string name="UsernameLinkSettings_qr_result_network_error">Experienced a network error. Please try again.</string>
<!-- EOF -->
</resources>

View file

@ -1,11 +1,16 @@
package org.signal.core.ui
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.size
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.DialogProperties
import org.signal.core.ui.Dialogs.SimpleAlertDialog
import org.signal.core.ui.Dialogs.SimpleMessageDialog
@ -72,6 +77,28 @@ object Dialogs {
properties = properties
)
}
/**
* A dialog that *just* shows a spinner. Useful for short actions where you need to
* let the user know that some action is completing.
*/
@Composable
fun IndeterminateProgressDialog() {
androidx.compose.material3.AlertDialog(
onDismissRequest = {},
confirmButton = {},
dismissButton = {},
text = {
CircularProgressIndicator(
modifier = Modifier
.fillMaxWidth()
.fillMaxHeight()
)
},
modifier = Modifier
.size(100.dp)
)
}
}
@Preview
@ -96,3 +123,9 @@ private fun MessageDialogPreview() {
onDismiss = {}
)
}
@Preview
@Composable
private fun IndeterminateProgressDialogPreview() {
Dialogs.IndeterminateProgressDialog()
}

View file

@ -16,6 +16,7 @@ dependencyResolutionManagement {
version('libsignal-client', '0.25.0')
version('mp4parser', '1.9.39')
version('android-gradle-plugin', '7.4.1')
version('accompanist', '0.28.0')
// Android Plugins
alias('android-library').to('com.android.library', 'com.android.library.gradle.plugin').versionRef('android-gradle-plugin')
@ -28,6 +29,9 @@ dependencyResolutionManagement {
alias('androidx-compose-ui-tooling-core').to('androidx.compose.ui', 'ui-tooling').withoutVersion()
alias('ktlint-twitter-compose').to('com.twitter.compose.rules:ktlint:0.0.26')
// Accompanist
alias('accompanist-permissions').to('com.google.accompanist', 'accompanist-permissions').versionRef('accompanist')
// Desugaring
alias('android-tools-desugar').to('com.android.tools:desugar_jdk_libs:1.1.5')

View file

@ -36,6 +36,14 @@ https://docs.gradle.org/current/userguide/dependency_verification.html
<sha256 value="b561e41c1bddb2160f79b9bc7541ad9ed110147ab2ccf63719a23d498470b043" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="androidx.activity" name="activity" version="1.7.0">
<artifact name="activity-1.7.0.aar">
<sha256 value="e44b2032273387156982912c591ef7e2dd485ba0b2e689b528b5a42f271a4f27" origin="Generated by Gradle"/>
</artifact>
<artifact name="activity-1.7.0.module">
<sha256 value="2a746b0126a8ab2f576e7167f1a785b452ef7ee997abd979ee0c5a29c36f6ea6" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="androidx.activity" name="activity-compose" version="1.3.0">
<artifact name="activity-compose-1.3.0.aar">
<sha256 value="32b2cdbb3ffb514bb4e09d00a7b4ccacf1dbb78a4a16fad0a600cf1c37204382" origin="Generated by Gradle"/>
@ -52,6 +60,14 @@ https://docs.gradle.org/current/userguide/dependency_verification.html
<sha256 value="10a44d247a4555af19e3bb8e06b5f24c4ed72252c5feace8de244a35ece256f7" origin="Generated by Gradle"/>
</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"/>
</artifact>
<artifact name="activity-compose-1.7.0.module">
<sha256 value="f7a29bcba338575dcf89a553cff9cfad3f140340eaf2b56fd0193244da602c0a" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="androidx.activity" name="activity-ktx" version="1.5.1">
<artifact name="activity-ktx-1.5.1.aar">
<sha256 value="fd69a5ccb99244cb7c5224580a58e23238d10ed4086199a33e9bfc31c4e4834f" origin="Generated by Gradle"/>
@ -68,6 +84,14 @@ https://docs.gradle.org/current/userguide/dependency_verification.html
<sha256 value="574b89ee589c530ec4d3fc412aac890066842db45a6a9a1bbe89542e0b47e81b" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="androidx.activity" name="activity-ktx" version="1.7.0">
<artifact name="activity-ktx-1.7.0.aar">
<sha256 value="fce317d61a22f12967b475bfcb80c89dda66e418975e890ea703cb74e12b5b11" origin="Generated by Gradle"/>
</artifact>
<artifact name="activity-ktx-1.7.0.module">
<sha256 value="f4001a709b6f7132b22a5e17c24f8b8a9b3c462a598de3b0f16cc57a4344bab6" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="androidx.annotation" name="annotation" version="1.0.0">
<artifact name="annotation-1.0.0.jar">
<sha256 value="0baae9755f7caf52aa80cd04324b91ba93af55d4d1d17dcc9a7b53d99ef7c016" origin="Generated by Gradle"/>
@ -173,6 +197,14 @@ https://docs.gradle.org/current/userguide/dependency_verification.html
<sha256 value="fe1237bf029d063e7f29fe39aeaf73ef74c8b0a3658486fc29d3c54326653889" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="androidx.arch.core" name="core-common" version="2.2.0">
<artifact name="core-common-2.2.0.jar">
<sha256 value="65308a06b1c00ee186cb9e19321383f043b993813f1522c47f4a3e3303bdba41" origin="Generated by Gradle"/>
</artifact>
<artifact name="core-common-2.2.0.module">
<sha256 value="edf4200cfdc2d946232252c99e5dcb9c61bb909eb5450b2613d1d4fdc974b981" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="androidx.arch.core" name="core-runtime" version="2.0.0">
<artifact name="core-runtime-2.0.0.aar">
<sha256 value="87e65fc767c712b437649c7cee2431ebb4bed6daef82e501d4125b3ed3f65f8e" origin="Generated by Gradle"/>
@ -183,6 +215,14 @@ https://docs.gradle.org/current/userguide/dependency_verification.html
<sha256 value="dd77615bd3dd275afb11b62df25bae46b10b4a117cd37943af45bdcbf8755852" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="androidx.arch.core" name="core-runtime" version="2.2.0">
<artifact name="core-runtime-2.2.0.aar">
<sha256 value="a1be5e0caa2b07623862af6ae21b3ab0718123245184d0e30dea81b53f990a47" origin="Generated by Gradle"/>
</artifact>
<artifact name="core-runtime-2.2.0.module">
<sha256 value="a8b17513949e5db6c9601c30be19df953762dd877512f1e2cfcfae81d2440944" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="androidx.asynclayoutinflater" name="asynclayoutinflater" version="1.0.0">
<artifact name="asynclayoutinflater-1.0.0.aar">
<sha256 value="f7eab60c57addd94bb06275832fe7600611beaaae1a1ec597c231956faf96c8b" origin="Generated by Gradle"/>
@ -365,6 +405,11 @@ https://docs.gradle.org/current/userguide/dependency_verification.html
<sha256 value="2bfc54475c047131913361f56d0f7f019c6e5bee53eeb0eb7d94a7c499a05227" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="androidx.compose.animation" name="animation" version="1.1.1">
<artifact name="animation-1.1.1.module">
<sha256 value="078b4dcd5f09689281415d9ea0e09d2775d80f016041dacbcee22d54c43a5fa1" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="androidx.compose.animation" name="animation" version="1.3.3">
<artifact name="animation-1.3.3.aar">
<sha256 value="83aebdaef792029760b580bc466567e2eadde06b29dc57691a0fe84dcebe7789" origin="Generated by Gradle"/>
@ -373,6 +418,14 @@ https://docs.gradle.org/current/userguide/dependency_verification.html
<sha256 value="fe86610a3ce138c5bd0147ea7727380cc341107c166ad729750273270f75ae7f" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="androidx.compose.animation" name="animation" version="1.4.0">
<artifact name="animation-1.4.0.aar">
<sha256 value="7242778ad5de01d7b3778a8ac93eb4a27d5900fc0cdd5407ac6124b9cc88c420" origin="Generated by Gradle"/>
</artifact>
<artifact name="animation-1.4.0.module">
<sha256 value="0d48b6b4792c9c91c57456041f90a408d5f319f59c7b2602f8f733c5bf622776" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="androidx.compose.animation" name="animation-core" version="1.3.3">
<artifact name="animation-core-1.3.3.aar">
<sha256 value="08b1efa990353b5eefe720529439c33be91e62b93c14db17c5dab06b8fe517ec" origin="Generated by Gradle"/>
@ -381,6 +434,14 @@ https://docs.gradle.org/current/userguide/dependency_verification.html
<sha256 value="71b8b7efad8d7d1749c99b824797448a598c8d2ee1ee6cc57ee5b700b51095cf" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="androidx.compose.animation" name="animation-core" version="1.4.0">
<artifact name="animation-core-1.4.0.aar">
<sha256 value="f275f322b92b505f066b07bcdfcc5e38d10ce53ccb9a74892191c33060d932b0" origin="Generated by Gradle"/>
</artifact>
<artifact name="animation-core-1.4.0.module">
<sha256 value="a2abdea92a060a26898d671ce93ba1731d86b8a6cb62b071de0653f385ed11ce" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="androidx.compose.compiler" name="compiler" version="1.3.2">
<artifact name="compiler-1.3.2.jar">
<sha256 value="d19beb5fc48395e1730acad2f654daa49a17f6b44a2a45a2e23a0dec806a6931" origin="Generated by Gradle"/>
@ -397,6 +458,14 @@ https://docs.gradle.org/current/userguide/dependency_verification.html
<sha256 value="77b3ecfd07ce23783d0d4712f6ce3611a5fe54aabaefd9dc07c2dcd903a29160" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="androidx.compose.foundation" name="foundation" version="1.4.0">
<artifact name="foundation-1.4.0.aar">
<sha256 value="60a8d42c0094979707c29332558f36a62670b6a54811a1eece93e315acdb73da" origin="Generated by Gradle"/>
</artifact>
<artifact name="foundation-1.4.0.module">
<sha256 value="952c00601ac6a964744a2cdc822c9454ef3bfc15c37e8086068f111bc439dbc1" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="androidx.compose.foundation" name="foundation-layout" version="1.3.1">
<artifact name="foundation-layout-1.3.1.aar">
<sha256 value="ea210c796514b4a83cbe551b9697db5e91ff5a5c7bb73a4c380b3e43a7b3409c" origin="Generated by Gradle"/>
@ -405,6 +474,14 @@ https://docs.gradle.org/current/userguide/dependency_verification.html
<sha256 value="3c28bdbd02932c83cd3a9dcae1c8cab884c8806d47e9a777c2cc4e54f263e340" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="androidx.compose.foundation" name="foundation-layout" version="1.4.0">
<artifact name="foundation-layout-1.4.0.aar">
<sha256 value="4c7620c5380f37cdd270949723d3123798f97401dd16835ec02ad39c30915277" origin="Generated by Gradle"/>
</artifact>
<artifact name="foundation-layout-1.4.0.module">
<sha256 value="58623de7c95f366dcb38ea760c7d27d4246be7775bde52df458cbf1be3eaf61c" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="androidx.compose.material" name="material" version="1.3.1">
<artifact name="material-1.3.1.aar">
<sha256 value="2fd1e1f90183da75be66a18308f8bdac9ad3ad3623744fb64ff53b6ac58c0380" origin="Generated by Gradle"/>
@ -413,6 +490,14 @@ https://docs.gradle.org/current/userguide/dependency_verification.html
<sha256 value="5e5c12caf47d1cc89908b31e58e69121370b40b4181c7ccbc8dc0a310a0f631b" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="androidx.compose.material" name="material" version="1.4.0">
<artifact name="material-1.4.0.aar">
<sha256 value="83d31b2ae4b37d6460de133ba4ad99aaaa9b701eabd90a6c53abeca54dac818f" origin="Generated by Gradle"/>
</artifact>
<artifact name="material-1.4.0.module">
<sha256 value="22fa7e9b4f3e856ba8baf36a0855f416e08b94d18638b4f10c74b943ca1310f8" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="androidx.compose.material" name="material-icons-core" version="1.3.1">
<artifact name="material-icons-core-1.3.1.aar">
<sha256 value="bd6e43230d57d70dce837b0b627ae68ef4294ec4931be9ebd6e5e21b0175c703" origin="Generated by Gradle"/>
@ -421,6 +506,14 @@ https://docs.gradle.org/current/userguide/dependency_verification.html
<sha256 value="bd0a0b3a35aaa70194153de405823428efae73d9c7408e3be0e95d23b1682805" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="androidx.compose.material" name="material-icons-core" version="1.4.0">
<artifact name="material-icons-core-1.4.0.aar">
<sha256 value="7a254689d80a3b3f18dd3f11dbb20f2988790c6bc68920325a539cd7d77bbc84" origin="Generated by Gradle"/>
</artifact>
<artifact name="material-icons-core-1.4.0.module">
<sha256 value="37b54a09c44b86f98ed612dd8b78b4d3b7ef6363106d75df6383a852cd106305" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="androidx.compose.material" name="material-ripple" version="1.3.1">
<artifact name="material-ripple-1.3.1.aar">
<sha256 value="4c8e5bcdecd48858487fa20bdc194e882aed0fd035181015b9f39346ed856f91" origin="Generated by Gradle"/>
@ -429,6 +522,22 @@ https://docs.gradle.org/current/userguide/dependency_verification.html
<sha256 value="2d89e99ae979853bd2359a7d5da16405479bce776d176168c2c7e8b431398d80" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="androidx.compose.material" name="material-ripple" version="1.4.0">
<artifact name="material-ripple-1.4.0.aar">
<sha256 value="071c3dcbd68ea352eae4518c24577c44beced6e8c0f50adb8948bf87f640c685" origin="Generated by Gradle"/>
</artifact>
<artifact name="material-ripple-1.4.0.module">
<sha256 value="9ed75200e7a031bbb8ee9cac62cafde0fb5a2dbe46851d88b82fcae204c22588" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="androidx.compose.material3" name="material3" version="1.0.0">
<artifact name="material3-1.0.0.aar">
<sha256 value="2d4235830df205e352e04def892f4798b1e9fba265ec43b7ce3818a21440746a" origin="Generated by Gradle"/>
</artifact>
<artifact name="material3-1.0.0.module">
<sha256 value="92753455f420ab0dbf6a7af078a9975b544eca1f73b45ae4a9ecb3ca92253c53" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="androidx.compose.material3" name="material3" version="1.0.1">
<artifact name="material3-1.0.1.aar">
<sha256 value="7204378ecadec4089da57492fbdb4cb637758e4bc740f26fe6f2db4d8876af05" origin="Generated by Gradle"/>
@ -437,6 +546,16 @@ https://docs.gradle.org/current/userguide/dependency_verification.html
<sha256 value="993a826a5cb89f2932d7e0d9dc2dc071c7b6f684420f93b304bd07ddbbfb902b" origin="Generated by Gradle"/>
</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" version="1.3.1">
<artifact name="runtime-1.3.1.module">
<sha256 value="4dd46221296f5d6695577eeb1cfbd58aae8374df6790b4c13bd9dd1b87c6f5ba" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="androidx.compose.runtime" name="runtime" version="1.3.3">
<artifact name="runtime-1.3.3.aar">
<sha256 value="dbacc6ea9322ed9a85aa5b0f5703bec4c83212f09beb6a64a3f023c7fca985b5" origin="Generated by Gradle"/>
@ -445,6 +564,19 @@ https://docs.gradle.org/current/userguide/dependency_verification.html
<sha256 value="9dfea413c99373004ee8cac6f026d5b633f110b2ae3da0d082b36c18e3588709" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="androidx.compose.runtime" name="runtime" version="1.4.0">
<artifact name="runtime-1.4.0.aar">
<sha256 value="0b6e672a16ba336961d72676281e49955a92fda071725adefaecaaa9427d567e" origin="Generated by Gradle"/>
</artifact>
<artifact name="runtime-1.4.0.module">
<sha256 value="e7ec58f6c62c49f04f1f75eeeb82356016e37e7093f7ed9882e678e1f251863f" 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.runtime" name="runtime-saveable" version="1.3.3">
<artifact name="runtime-saveable-1.3.3.aar">
<sha256 value="1c3b5573034188e7f60a8acff1fba7af522dd6774f642f210f53befb663fcfba" origin="Generated by Gradle"/>
@ -453,6 +585,24 @@ https://docs.gradle.org/current/userguide/dependency_verification.html
<sha256 value="df3788596724558905520c10b6b6451e7158194d8885317ad155f49b8c030df6" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="androidx.compose.runtime" name="runtime-saveable" version="1.4.0">
<artifact name="runtime-saveable-1.4.0.aar">
<sha256 value="b7df4f0ba6e0a4df18c5d8c0d3be10d45113e347d018603764d0f192bbb70c16" origin="Generated by Gradle"/>
</artifact>
<artifact name="runtime-saveable-1.4.0.module">
<sha256 value="93c8a47a9333f2e274941228cf06cefe6c8be88f49a58b13a0416dcae1872507" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="androidx.compose.ui" name="ui" version="1.0.1">
<artifact name="ui-1.0.1.module">
<sha256 value="57031a6ac9b60e5b56792ebf5cde6e16812ff566ed9190cbd188b00b46c13779" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="androidx.compose.ui" name="ui" version="1.3.1">
<artifact name="ui-1.3.1.module">
<sha256 value="ba79d53cd1b581ade9c96cbeba9fb7a57606c966130b38daa29013cfe1056e9f" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="androidx.compose.ui" name="ui" version="1.3.3">
<artifact name="ui-1.3.3.aar">
<sha256 value="eaac567d35c4eeadf760540b258dfbfcfbced6fbc7d1f3f8bdf3674343685819" origin="Generated by Gradle"/>
@ -461,6 +611,14 @@ https://docs.gradle.org/current/userguide/dependency_verification.html
<sha256 value="0092bd8bec7779f973a1fe4350e8c326a448edd21eb83dc9670ecaa9ad2332ae" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="androidx.compose.ui" name="ui" version="1.4.0">
<artifact name="ui-1.4.0.aar">
<sha256 value="67ad10ce59f0966cf8e1146c51184b4c268f0224dc45193fc205d6dcd73ee865" origin="Generated by Gradle"/>
</artifact>
<artifact name="ui-1.4.0.module">
<sha256 value="1882306db57c00a5e1dc593126957aed6a2e54fc1a328229db86571bef3c25a9" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="androidx.compose.ui" name="ui-geometry" version="1.3.3">
<artifact name="ui-geometry-1.3.3.aar">
<sha256 value="b52894760837fb3e555b4409c2e8d0f01cea72ac96c0521e383b5c0e8dd06a45" origin="Generated by Gradle"/>
@ -469,6 +627,19 @@ https://docs.gradle.org/current/userguide/dependency_verification.html
<sha256 value="2cbf42666cc5138c83776fc634820ddd244d40d425134072ed09ddaf3580f06f" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="androidx.compose.ui" name="ui-geometry" version="1.4.0">
<artifact name="ui-geometry-1.4.0.aar">
<sha256 value="c180747cb03ef3fd2cdf9584a649a6bf9926504ee6322f275a4b1ffe7ddccaa4" origin="Generated by Gradle"/>
</artifact>
<artifact name="ui-geometry-1.4.0.module">
<sha256 value="b55860e086814d3bb4bdc010d5e7ad800c2fc7b792829d5c46c14e00c494fd6e" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="androidx.compose.ui" name="ui-graphics" version="1.1.1">
<artifact name="ui-graphics-1.1.1.module">
<sha256 value="170b229a8012c6724b4101058dc4c2cfe0f11e78a34aac4a4627cce8888f1a59" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="androidx.compose.ui" name="ui-graphics" version="1.3.3">
<artifact name="ui-graphics-1.3.3.aar">
<sha256 value="87e39f927a3fb79635c468a3ae86aad82a39817d5785d043a26c72c3fa223d01" origin="Generated by Gradle"/>
@ -477,6 +648,19 @@ https://docs.gradle.org/current/userguide/dependency_verification.html
<sha256 value="f901bf63ce3bc41e00d5f927c741fdb0ca4f73d55feae506efef0fb4ef74eb52" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="androidx.compose.ui" name="ui-graphics" version="1.4.0">
<artifact name="ui-graphics-1.4.0.aar">
<sha256 value="e09b76d28172ada94f42cacfc5f7737d7cca2800ff5a5ce191dcf0c250460866" origin="Generated by Gradle"/>
</artifact>
<artifact name="ui-graphics-1.4.0.module">
<sha256 value="5961cdcc35430904624e3ede5611b1bac52260101f3fc0b0c1473d54c4042ba0" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="androidx.compose.ui" name="ui-text" version="1.0.0">
<artifact name="ui-text-1.0.0.module">
<sha256 value="a85fde2fe3c50e9e956daa449f27e7a10c13fe4a1cafe7f41b478ed9ecb6166b" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="androidx.compose.ui" name="ui-text" version="1.3.3">
<artifact name="ui-text-1.3.3.aar">
<sha256 value="89f186445ba99f74964b1fd13c1673e288b5e4b74e6392c43297d4e406332c38" origin="Generated by Gradle"/>
@ -485,6 +669,14 @@ https://docs.gradle.org/current/userguide/dependency_verification.html
<sha256 value="2c5aa2d18e4f186e3b8d6d0e8088c8263e3b98e167c65a8dc058a55b7ef89d6f" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="androidx.compose.ui" name="ui-text" version="1.4.0">
<artifact name="ui-text-1.4.0.aar">
<sha256 value="5c7bb05938ff04b2526489cdbbdb6737f61a701f872d69d8fedace39981b7308" origin="Generated by Gradle"/>
</artifact>
<artifact name="ui-text-1.4.0.module">
<sha256 value="f2be62ed6b69e89d9f85a0eeddbf701aee0709857874acd3d77a2e6598d8afb5" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="androidx.compose.ui" name="ui-tooling" version="1.3.3">
<artifact name="ui-tooling-1.3.3.aar">
<sha256 value="2bd2a2577de7d579a84071f99c2bf7f1f6a95730d680822541613dfa454d5156" origin="Generated by Gradle"/>
@ -493,6 +685,14 @@ https://docs.gradle.org/current/userguide/dependency_verification.html
<sha256 value="e7478124b26e096e69270378d613d793f0d4a58bc769434409a1c8833d2ad376" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="androidx.compose.ui" name="ui-tooling" version="1.4.0">
<artifact name="ui-tooling-1.4.0.aar">
<sha256 value="8f51323653e9719bde8bcc7d76850ce736af29e5b3731df94b28c36df23bff57" origin="Generated by Gradle"/>
</artifact>
<artifact name="ui-tooling-1.4.0.module">
<sha256 value="bc8f7396b72e3bbf4c507b69b6b2eafb3496e1d5284c02c162cc405421562a12" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="androidx.compose.ui" name="ui-tooling-data" version="1.3.3">
<artifact name="ui-tooling-data-1.3.3.aar">
<sha256 value="25099479e93b84d909c01543480d7cea90bbf346fee2ae4daee6bc507f0ceb47" origin="Generated by Gradle"/>
@ -501,6 +701,14 @@ https://docs.gradle.org/current/userguide/dependency_verification.html
<sha256 value="f7748c8d41486fc1af8fb779558ba5760f559c63a41307a8e6d30edf221a6121" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="androidx.compose.ui" name="ui-tooling-data" version="1.4.0">
<artifact name="ui-tooling-data-1.4.0.aar">
<sha256 value="b66cc25cc67937179385d544dfdd08520377ef2ed27d60dc0016b85ebb924315" origin="Generated by Gradle"/>
</artifact>
<artifact name="ui-tooling-data-1.4.0.module">
<sha256 value="345f96cfcc9df60730f36da201feace69cd2791a31019911ca3df71ebadf34ba" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="androidx.compose.ui" name="ui-tooling-preview" version="1.3.3">
<artifact name="ui-tooling-preview-1.3.3.aar">
<sha256 value="6460b1c9edfd43a65077c4aa0342bf5c6d6cce779c384a1ad9017893cb41c329" origin="Generated by Gradle"/>
@ -509,6 +717,14 @@ https://docs.gradle.org/current/userguide/dependency_verification.html
<sha256 value="eba68751ef544e531ecd44fdb517534aaaccd396b2b3d5a66679b5f675c15fa8" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="androidx.compose.ui" name="ui-tooling-preview" version="1.4.0">
<artifact name="ui-tooling-preview-1.4.0.aar">
<sha256 value="89f77d938f5c636601602ca62674b6f662dafac7b3902a62d932308497070722" origin="Generated by Gradle"/>
</artifact>
<artifact name="ui-tooling-preview-1.4.0.module">
<sha256 value="0583eec2c75819b270eaaf0ceac212cd9f0d95cd6d62bfff92ecfce04547296d" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="androidx.compose.ui" name="ui-unit" version="1.3.3">
<artifact name="ui-unit-1.3.3.aar">
<sha256 value="d2f59c9fae6b135ecafb54d0cf62d547bdbcefbbbe023b21fb2f935cb201e22f" origin="Generated by Gradle"/>
@ -517,6 +733,19 @@ https://docs.gradle.org/current/userguide/dependency_verification.html
<sha256 value="63e0ac1138cef02cfcd5131aaf636e901f3fddacff3fcf6fb22472ddadd32f18" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="androidx.compose.ui" name="ui-unit" version="1.4.0">
<artifact name="ui-unit-1.4.0.aar">
<sha256 value="9493d0a5914bf5711b3b2ccdea97e684c36b04bbb37bb63b07c98d57cdcb27ab" origin="Generated by Gradle"/>
</artifact>
<artifact name="ui-unit-1.4.0.module">
<sha256 value="f14c0ab4e0ba514fcfa6dad7386da83eb2841b18c883e34f602f5db55500089e" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="androidx.compose.ui" name="ui-util" version="1.0.0">
<artifact name="ui-util-1.0.0.module">
<sha256 value="a09871728e5a9d050d2fdcb99a875ef2120dc6deea808f5a6d443dd887e081ca" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="androidx.compose.ui" name="ui-util" version="1.3.3">
<artifact name="ui-util-1.3.3.aar">
<sha256 value="8276a623a1170dbcc259c806bd71f1ac64f2299ef30ada6e5d23d581d08e172c" origin="Generated by Gradle"/>
@ -525,6 +754,14 @@ https://docs.gradle.org/current/userguide/dependency_verification.html
<sha256 value="ce3cece139d9fdc7ceffdd5d061694c04cbeac3fd12fcf13d30d570c7d231e39" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="androidx.compose.ui" name="ui-util" version="1.4.0">
<artifact name="ui-util-1.4.0.aar">
<sha256 value="7fd70da282462349650e021352172f65407ebe494d45863a2e6d61496f3fe2be" origin="Generated by Gradle"/>
</artifact>
<artifact name="ui-util-1.4.0.module">
<sha256 value="97f82685e4b0d5d80c4d66a46ea8473bb5baf6c6d7fcbad0b4391df78aa60fff" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="androidx.concurrent" name="concurrent-futures" version="1.0.0">
<artifact name="concurrent-futures-1.0.0.jar">
<sha256 value="5595a40e278a7b39fa78a09490e3d7f3faa95c7b01447148bd38b5ade0605c35" origin="Generated by Gradle"/>
@ -713,6 +950,14 @@ https://docs.gradle.org/current/userguide/dependency_verification.html
<sha256 value="9d1996cca03777baa1f27cd15531db983a633dae37b90f85bd53501acb56699d" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="androidx.emoji2" name="emoji2" version="1.3.0">
<artifact name="emoji2-1.3.0.aar">
<sha256 value="2bf23818b23a996ddaa1b5fd5bb32129daff6bbb2dce15166e2fccdd2010b1a5" origin="Generated by Gradle"/>
</artifact>
<artifact name="emoji2-1.3.0.module">
<sha256 value="ddc851edba65fd15a7a1bc3ad18648e2f732dd5ad8ef3602224bce0647f5b4d1" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="androidx.emoji2" name="emoji2-views-helper" version="1.2.0">
<artifact name="emoji2-views-helper-1.2.0.aar">
<sha256 value="7ffa4d464d9db259fca0cdb50fbd4ab63d6872bcda59468b9f7555504c7d5ac4" origin="Generated by Gradle"/>
@ -721,6 +966,14 @@ https://docs.gradle.org/current/userguide/dependency_verification.html
<sha256 value="a3a9db581abf1787b01ff15c40f059530e8e64f3937caa2d788f42eb39893268" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="androidx.emoji2" name="emoji2-views-helper" version="1.3.0">
<artifact name="emoji2-views-helper-1.3.0.aar">
<sha256 value="9a1351295a4f739df0efe8344adaa9afb34856c3af584d4a9afbec105a45b90b" origin="Generated by Gradle"/>
</artifact>
<artifact name="emoji2-views-helper-1.3.0.module">
<sha256 value="09974bb5ef9780de9d56715d71171a35c78fb2e17fd865773b0c83a3acac039c" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="androidx.exifinterface" name="exifinterface" version="1.2.0">
<artifact name="exifinterface-1.2.0.aar">
<sha256 value="aae68e513095e475a7670556eacba772ec2bb592d17187091578d3fef947aea7" origin="Generated by Gradle"/>
@ -819,6 +1072,11 @@ https://docs.gradle.org/current/userguide/dependency_verification.html
<sha256 value="5fb7c8514d8c56cada5e29ef89dc0289e71942ab4cb0b2e6dca137b9dcb8fdd4" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="androidx.lifecycle" name="lifecycle-common" version="2.4.0">
<artifact name="lifecycle-common-2.4.0.module">
<sha256 value="5ad5eafc22e8b04e58fa81d18d2570562971977e18f009500b5bd449bc6337bc" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="androidx.lifecycle" name="lifecycle-common" version="2.5.1">
<artifact name="lifecycle-common-2.5.1.jar">
<sha256 value="20ad1520f625cf455e6afd7290988306d3a9886efa993e0860fbabf4bb3f7bda" origin="Generated by Gradle"/>
@ -827,6 +1085,14 @@ https://docs.gradle.org/current/userguide/dependency_verification.html
<sha256 value="7d4bc2961cd5bd399e3621d434f0c453dd6cadf891f917a946cc291abdda8f1a" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="androidx.lifecycle" name="lifecycle-common" version="2.6.1">
<artifact name="lifecycle-common-2.6.1.jar">
<sha256 value="f34831b6c71cd844e1d35d1be49d5e79447c5ab856346531b1e8676fda7374b1" origin="Generated by Gradle"/>
</artifact>
<artifact name="lifecycle-common-2.6.1.module">
<sha256 value="93747a9145cb36bc71005f598ede32e2b1149ade5a16e62b0e4969345bc62d85" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="androidx.lifecycle" name="lifecycle-common-java8" version="2.3.0">
<artifact name="lifecycle-common-java8-2.3.0.module">
<sha256 value="2de56435ecd68ba2d49ae48011c34b758304af0a8e7e09ad2e8edfd2fe349b9c" origin="Generated by Gradle"/>
@ -840,6 +1106,14 @@ https://docs.gradle.org/current/userguide/dependency_verification.html
<sha256 value="11b1add50e65c46e4d780adf9697c16f4785a8a982b1841b7d093d3a0a3d10f0" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="androidx.lifecycle" name="lifecycle-common-java8" version="2.6.1">
<artifact name="lifecycle-common-java8-2.6.1.jar">
<sha256 value="c6deada2fac53b8ea6523dbda77597b128006674616f140f04df23264c6d1aa3" origin="Generated by Gradle"/>
</artifact>
<artifact name="lifecycle-common-java8-2.6.1.module">
<sha256 value="1beb0b9fffb630a005deca1d3583d2acbec8685d6de809a3a6e0e433f418b6c3" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="androidx.lifecycle" name="lifecycle-livedata" version="2.0.0">
<artifact name="lifecycle-livedata-2.0.0.aar">
<sha256 value="c82609ced8c498f0a701a30fb6771bb7480860daee84d82e0a81ee86edf7ba39" origin="Generated by Gradle"/>
@ -853,6 +1127,14 @@ https://docs.gradle.org/current/userguide/dependency_verification.html
<sha256 value="b5f4a08193d7802ac3574d91ef442ae31c633ff3095f1c4973c80d68908a48bc" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="androidx.lifecycle" name="lifecycle-livedata" version="2.6.1">
<artifact name="lifecycle-livedata-2.6.1.aar">
<sha256 value="67359f609dfc2bf65da1270b23033f856064ec279f058e0a70c715f7c9003031" origin="Generated by Gradle"/>
</artifact>
<artifact name="lifecycle-livedata-2.6.1.module">
<sha256 value="e2659e87e890b52b66f300471828b387a205e5387a392713190166f399ecf641" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="androidx.lifecycle" name="lifecycle-livedata-core" version="2.0.0">
<artifact name="lifecycle-livedata-core-2.0.0.aar">
<sha256 value="fde334ec7e22744c0f5bfe7caf1a84c9d717327044400577bdf9bd921ec4f7bc" origin="Generated by Gradle"/>
@ -866,6 +1148,14 @@ https://docs.gradle.org/current/userguide/dependency_verification.html
<sha256 value="3f388e9e078901970c2bfcfc02fecae948de4b46be5211919ae07d012ca2980d" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="androidx.lifecycle" name="lifecycle-livedata-core" version="2.6.1">
<artifact name="lifecycle-livedata-core-2.6.1.aar">
<sha256 value="2256780a3cff4a1e57fbb3d442557c17dc363ab8af105bcaf5261d8e2d5db949" origin="Generated by Gradle"/>
</artifact>
<artifact name="lifecycle-livedata-core-2.6.1.module">
<sha256 value="e9c0dc3f0ac54419c0cfed8ff5cecb82943a7c58f7a54169f0d849b2c60a3552" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="androidx.lifecycle" name="lifecycle-livedata-core-ktx" version="2.5.1">
<artifact name="lifecycle-livedata-core-ktx-2.5.1.aar">
<sha256 value="95c235e6f33e7f201e9d24cd5e7095ed0ae1e5d2cb4778a6daa29671aa1fc388" origin="Generated by Gradle"/>
@ -874,6 +1164,14 @@ https://docs.gradle.org/current/userguide/dependency_verification.html
<sha256 value="8076fd96e862164e46b34560bf40e02ae75965a28a209e47284ccbb7b5808e8c" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="androidx.lifecycle" name="lifecycle-livedata-core-ktx" version="2.6.1">
<artifact name="lifecycle-livedata-core-ktx-2.6.1.aar">
<sha256 value="9f2c16e33a55ba8d67a3623a55befff2ec80643e3f0a926760df1d957c3f8aef" origin="Generated by Gradle"/>
</artifact>
<artifact name="lifecycle-livedata-core-ktx-2.6.1.module">
<sha256 value="d8699c515516aee3a0613de951649d9f1e137d33fedf077be0a6aa9e01ae211f" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="androidx.lifecycle" name="lifecycle-livedata-ktx" version="2.5.1">
<artifact name="lifecycle-livedata-ktx-2.5.1.aar">
<sha256 value="bf9193356d0d66248ede7e41f1cc242d0c60a64a75e67a777375f8d640e7cdf0" origin="Generated by Gradle"/>
@ -882,6 +1180,14 @@ https://docs.gradle.org/current/userguide/dependency_verification.html
<sha256 value="1cedc0f971979cdec31f1542f263a8d41df6cfffc4857ea73a7d85643b73486d" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="androidx.lifecycle" name="lifecycle-livedata-ktx" version="2.6.1">
<artifact name="lifecycle-livedata-ktx-2.6.1.aar">
<sha256 value="f8e955cdcded64055fd8ac3be2960f1a6ce27d2724fbc450759cf0d13eb9ecce" origin="Generated by Gradle"/>
</artifact>
<artifact name="lifecycle-livedata-ktx-2.6.1.module">
<sha256 value="fbbb8bde686ea420f7d6fc8199bbe872eee92d33d68e834f5cc1afd759a63166" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="androidx.lifecycle" name="lifecycle-process" version="2.4.1">
<artifact name="lifecycle-process-2.4.1.aar">
<sha256 value="db649b3efa24e31052145310b002db91da346b3f89c093ec38c3046db45e794e" origin="Generated by Gradle"/>
@ -898,6 +1204,14 @@ https://docs.gradle.org/current/userguide/dependency_verification.html
<sha256 value="4363f8e0f37436b6599beaf893874c827f987e2a3d9636c221e80066f4774f3f" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="androidx.lifecycle" name="lifecycle-process" version="2.6.1">
<artifact name="lifecycle-process-2.6.1.aar">
<sha256 value="0f33b1bd017f965a6afb2e7bf3e3bd343c624061c1986dea8ba2469d04349437" origin="Generated by Gradle"/>
</artifact>
<artifact name="lifecycle-process-2.6.1.module">
<sha256 value="58c9e27371ccf7a22a233f44926d348c9d07e78c41a56588a4265ff6ae76645a" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="androidx.lifecycle" name="lifecycle-reactivestreams" version="2.5.1">
<artifact name="lifecycle-reactivestreams-2.5.1.aar">
<sha256 value="39c09b99ed45a532f43e64bd6fffdf31f8ba89bab162a7a49595d2a4b2e9f436" origin="Generated by Gradle"/>
@ -906,6 +1220,14 @@ https://docs.gradle.org/current/userguide/dependency_verification.html
<sha256 value="bdc4f25d5e2bd69cde23e2f0c191f3fc92d1430e0c04315d4a31386d9ff359bb" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="androidx.lifecycle" name="lifecycle-reactivestreams" version="2.6.1">
<artifact name="lifecycle-reactivestreams-2.6.1.aar">
<sha256 value="d719255866119c150a58b9691c4bf112db095f08ea584f272c789529d7aee38d" origin="Generated by Gradle"/>
</artifact>
<artifact name="lifecycle-reactivestreams-2.6.1.module">
<sha256 value="6a5f86173e11a5fbc2e5c545e6a10efe20f6429034a69aefbc23fa235cc1dc73" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="androidx.lifecycle" name="lifecycle-reactivestreams-ktx" version="2.5.1">
<artifact name="lifecycle-reactivestreams-ktx-2.5.1.aar">
<sha256 value="33ace4ac0718e51ce24e9419e4578b0743be88c469f68d7813f734437ea216b4" origin="Generated by Gradle"/>
@ -914,6 +1236,14 @@ https://docs.gradle.org/current/userguide/dependency_verification.html
<sha256 value="5a4bd51048208cb534b44545983898494ef90df68a5839a24b9d875b24a0c2ef" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="androidx.lifecycle" name="lifecycle-reactivestreams-ktx" version="2.6.1">
<artifact name="lifecycle-reactivestreams-ktx-2.6.1.aar">
<sha256 value="6f52e228bf5744037afb3273523e5ee307169507c5cf97f350526c1252a041e2" origin="Generated by Gradle"/>
</artifact>
<artifact name="lifecycle-reactivestreams-ktx-2.6.1.module">
<sha256 value="06c8ad910d5d19a3bd8aec9476f4cee46b6f910792bc1aaed9563463a81f5189" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="androidx.lifecycle" name="lifecycle-runtime" version="2.0.0">
<artifact name="lifecycle-runtime-2.0.0.aar">
<sha256 value="e4afc9e636183f6f3e0edf1cf46121a492ffd2c673075bb07f55c7a99dd43cfb" origin="Generated by Gradle"/>
@ -935,6 +1265,14 @@ https://docs.gradle.org/current/userguide/dependency_verification.html
<sha256 value="0027dc887fa3b243c23db40ab0f763fc7efacaafa15df923d233344acfe81a16" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="androidx.lifecycle" name="lifecycle-runtime" version="2.6.1">
<artifact name="lifecycle-runtime-2.6.1.aar">
<sha256 value="4867fd5279742fba8388821930cb2affe06d81a52814e7e41e70392ea0ef887c" origin="Generated by Gradle"/>
</artifact>
<artifact name="lifecycle-runtime-2.6.1.module">
<sha256 value="a4cbb01a42d07047bd8d870017c96a1b0b7b4673320e86b66317a13be2ec10c7" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="androidx.lifecycle" name="lifecycle-runtime-ktx" version="2.5.1">
<artifact name="lifecycle-runtime-ktx-2.5.1.aar">
<sha256 value="b3988ae01aae021ac666f232b85f88e8a75cacb2ac7bd6749cab73972540ce07" origin="Generated by Gradle"/>
@ -943,6 +1281,14 @@ https://docs.gradle.org/current/userguide/dependency_verification.html
<sha256 value="488d174a07733b1cff27ddf426097f4e3fe71ed34c6a0000b56424f8d06c51fd" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="androidx.lifecycle" name="lifecycle-runtime-ktx" version="2.6.1">
<artifact name="lifecycle-runtime-ktx-2.6.1.aar">
<sha256 value="28a0b834f40edd52e2f8010bdc3057d2a0cc76aaa5ac9311adb0b9ce919ca9cc" origin="Generated by Gradle"/>
</artifact>
<artifact name="lifecycle-runtime-ktx-2.6.1.module">
<sha256 value="39854f32c9b010f652f4e5041ca4ce06981dcb6954128c1e8e1cc02e63ab185f" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="androidx.lifecycle" name="lifecycle-viewmodel" version="2.0.0">
<artifact name="lifecycle-viewmodel-2.0.0.aar">
<sha256 value="d6460aea1b6bad80ab14cf88297e9e43bfde8d87c3e5c28f2c508233ffbcc062" origin="Generated by Gradle"/>
@ -956,6 +1302,14 @@ https://docs.gradle.org/current/userguide/dependency_verification.html
<sha256 value="01e413b73cbe38cb714dc5bdb21bd860931124c8e5f2369803f4aacc49081c9f" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="androidx.lifecycle" name="lifecycle-viewmodel" version="2.6.1">
<artifact name="lifecycle-viewmodel-2.6.1.aar">
<sha256 value="e4ff4338999e1c6c9c724719f5d4aa7dd61bf6f545d5256a27a9d375df9f2330" origin="Generated by Gradle"/>
</artifact>
<artifact name="lifecycle-viewmodel-2.6.1.module">
<sha256 value="2b406faea5c12f2b8df4b7a60931f846648f2e1f4d78361e198d1184f19a4797" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="androidx.lifecycle" name="lifecycle-viewmodel-compose" version="2.5.1">
<artifact name="lifecycle-viewmodel-compose-2.5.1.aar">
<sha256 value="4b0f50cca837753d82942822b996c214f09c8c709524f1cc95e03facd96bf466" origin="Generated by Gradle"/>
@ -972,6 +1326,14 @@ https://docs.gradle.org/current/userguide/dependency_verification.html
<sha256 value="e292838f93ba9df0ec8331659bd116ff8fbe7dce48c1482b3f1b0e887c1e3d6d" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="androidx.lifecycle" name="lifecycle-viewmodel-ktx" version="2.6.1">
<artifact name="lifecycle-viewmodel-ktx-2.6.1.aar">
<sha256 value="7fc0fa234a3321b1f34db5862b17da83d1c62c1bc66ec2fd4f1bb0a771acfabb" origin="Generated by Gradle"/>
</artifact>
<artifact name="lifecycle-viewmodel-ktx-2.6.1.module">
<sha256 value="a5110f85788bc167df9fe8fbe08004ddc5c5dd9b15cb7376ceeaef025fccaaf8" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="androidx.lifecycle" name="lifecycle-viewmodel-savedstate" version="2.5.1">
<artifact name="lifecycle-viewmodel-savedstate-2.5.1.aar">
<sha256 value="8481141f97f0e6213dd33fcc89a784c4bd11a6ff7d4779a1cf6a0e9fbdbf24e0" origin="Generated by Gradle"/>
@ -980,6 +1342,14 @@ https://docs.gradle.org/current/userguide/dependency_verification.html
<sha256 value="29acd5fe614b3f89123eb838f688d625eaa8b422c8d1905b48ad8e760cd7ad8b" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="androidx.lifecycle" name="lifecycle-viewmodel-savedstate" version="2.6.1">
<artifact name="lifecycle-viewmodel-savedstate-2.6.1.aar">
<sha256 value="c82f89221adbe19df7c7adbab63f4ecc857fc746e3c9494256ab8fa5c20491b2" origin="Generated by Gradle"/>
</artifact>
<artifact name="lifecycle-viewmodel-savedstate-2.6.1.module">
<sha256 value="dafb8649763d29c29cda27bc22fcdab9a9efc53c0fff9ae3de90882eabaa8944" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="androidx.loader" name="loader" version="1.0.0">
<artifact name="loader-1.0.0.aar">
<sha256 value="11f735cb3b55c458d470bed9e25254375b518b4b1bad6926783a7026db0f5025" origin="Generated by Gradle"/>
@ -1133,6 +1503,14 @@ https://docs.gradle.org/current/userguide/dependency_verification.html
<sha256 value="7093bdffed3f18bc4ddfbd0784f75c1dbbd70e8ab3ccf4bff5b0e1c2713edbbe" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="androidx.profileinstaller" name="profileinstaller" version="1.3.0">
<artifact name="profileinstaller-1.3.0.aar">
<sha256 value="34e8b2bfc74e23c1525e3da903ae449b7f1b440aef45e18159ee470e91997f48" origin="Generated by Gradle"/>
</artifact>
<artifact name="profileinstaller-1.3.0.module">
<sha256 value="a16fe511e599c2042da122be09569aecd3f4f90cad37ef08bd0bbc39118c92c8" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="androidx.recyclerview" name="recyclerview" version="1.1.0">
<artifact name="recyclerview-1.1.0.aar">
<sha256 value="f0d2b5a67d0a91ee1b1c73ef2b636a81f3563925ddd15a1d4e1c41ec28de7a4f" origin="Generated by Gradle"/>
@ -1162,6 +1540,14 @@ https://docs.gradle.org/current/userguide/dependency_verification.html
<sha256 value="4247c23308abcb5d0ff8cdaf7dfd583f3c2a1016f68d13f1a41c21600b6fafd7" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="androidx.savedstate" name="savedstate" version="1.2.1">
<artifact name="savedstate-1.2.1.aar">
<sha256 value="21a7d4bcf6bdb94ad7b9283801529300b4fbb8808ca4f191e0cdce6fd8e4705a" origin="Generated by Gradle"/>
</artifact>
<artifact name="savedstate-1.2.1.module">
<sha256 value="5bb656fc760d9e3996b535160cbb4106033c9f736e9089e6ef4eb0c669785066" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="androidx.savedstate" name="savedstate-ktx" version="1.2.0">
<artifact name="savedstate-ktx-1.2.0.aar">
<sha256 value="43112928d3cbb108801ee11130f303404bc4892cf78908811568195107bba7fe" origin="Generated by Gradle"/>
@ -1170,6 +1556,14 @@ https://docs.gradle.org/current/userguide/dependency_verification.html
<sha256 value="1c834feaa235c69ca9feacee06ba57d11d6f6a5fb4125a49dfce2679a313dfb7" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="androidx.savedstate" name="savedstate-ktx" version="1.2.1">
<artifact name="savedstate-ktx-1.2.1.aar">
<sha256 value="8553f87e7136c24ec5243560f48f1c32cba56daa77722f89589a5cafcb8f7894" origin="Generated by Gradle"/>
</artifact>
<artifact name="savedstate-ktx-1.2.1.module">
<sha256 value="94359184b2ba51c0f498a2b9055d37b372231ef9bcc54a4972ac99f0303afff1" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="androidx.sharetarget" name="sharetarget" version="1.2.0-rc02">
<artifact name="sharetarget-1.2.0-rc02.aar">
<sha256 value="adbfcc4e46b85303cf6ef7d9eec02bc19c34459b33a928159a05c4a86dc96aa9" origin="Generated by Gradle"/>
@ -2609,6 +3003,14 @@ https://docs.gradle.org/current/userguide/dependency_verification.html
<sha256 value="2f6174e3049008f263fd832813390df645ac5c7cfa79f170ace58690810476f2" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="com.google.accompanist" name="accompanist-permissions" version="0.28.0">
<artifact name="accompanist-permissions-0.28.0.aar">
<sha256 value="8e0c961b18dfa0581adcc6314b00fe3b60a3aa58d2a455819fa2e82b19a806e5" origin="Generated by Gradle"/>
</artifact>
<artifact name="accompanist-permissions-0.28.0.module">
<sha256 value="95aba47bcaaaf412baccb8ce9aaa7e5e23f2af74e19f9266a8dbea866a857f32" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="com.google.android" name="annotations" version="4.1.1.4">
<artifact name="annotations-4.1.1.4.jar">
<sha256 value="ba734e1e84c09d615af6a09d33034b4f0442f8772dec120efb376d86a565ae15" origin="Generated by Gradle"/>
@ -3708,6 +4110,27 @@ https://docs.gradle.org/current/userguide/dependency_verification.html
<sha256 value="b0a5159e926de8084ff066025142270443533656bc599b8bb31d14d11fd138a4" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="io.github.aakira" name="napier" version="1.4.1">
<artifact name="napier-1.4.1.module">
<sha256 value="10296ebb83b6812d87b4d3c9f965eafcf5c7b2c8f737c5a044bbd987c4221970" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="io.github.aakira" name="napier-android" version="1.4.1">
<artifact name="napier-android-1.4.1.module">
<sha256 value="83fee939426a4d3189efc897a0829ed2211e6a81ff054234669f0614c658a31c" origin="Generated by Gradle"/>
</artifact>
<artifact name="napier-release.aar">
<sha256 value="269cc7b43a2e4b5d37df2938d2752d2946bea9b98ffb80ec30af150380451f4c" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="io.github.aakira" name="napier-android-debug" version="1.4.1">
<artifact name="napier-android-debug-1.4.1.module">
<sha256 value="046c57059fac35e2381055a8f65892be36f2b66265d6b613b069b551fd011f8b" origin="Generated by Gradle"/>
</artifact>
<artifact name="napier-debug.aar">
<sha256 value="783f73dcd5bcc7817d4f76865c61050c70e48934d81329afd27204bfd85ef2d6" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="io.github.detekt.sarif4k" name="sarif4k" version="0.0.1">
<artifact name="sarif4k-0.0.1.jar">
<sha256 value="41ec72cf2521783224581c76aaa7e97d4a50f396a66d642500ff4777b395a376" origin="Generated by Gradle"/>