diff --git a/app/build.gradle.kts b/app/build.gradle.kts index c4f6cbc..871f4b2 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -64,7 +64,7 @@ dependencies { implementation("org.matrix.android:matrix-android-sdk2:1.5.30") implementation("com.squareup.okhttp3:okhttp:4.12.0") implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.6.2") - implementation("androidx.activity:activity-compose:1.8.0") + implementation("androidx.activity:activity-compose:1.8.1") implementation(platform("androidx.compose:compose-bom:2023.03.00")) implementation("androidx.compose.ui:ui") implementation("androidx.compose.ui:ui-graphics") diff --git a/app/src/main/java/eu/steffo/twom/create/CreateActivity.kt b/app/src/main/java/eu/steffo/twom/create/CreateActivity.kt index 7cafddc..bda6921 100644 --- a/app/src/main/java/eu/steffo/twom/create/CreateActivity.kt +++ b/app/src/main/java/eu/steffo/twom/create/CreateActivity.kt @@ -1,5 +1,25 @@ package eu.steffo.twom.create +import android.os.Bundle import androidx.activity.ComponentActivity +import androidx.activity.compose.setContent -class CreateActivity : ComponentActivity() \ No newline at end of file +class CreateActivity : ComponentActivity() { + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + setContent { + CreateActivityScaffold( + onClickBack = { + setResult(RESULT_CANCELED) + finish() + }, + onClickCreate = { + setResult(RESULT_OK) + finish() + }, + ) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/eu/steffo/twom/create/CreateActivityContent.kt b/app/src/main/java/eu/steffo/twom/create/CreateActivityContent.kt new file mode 100644 index 0000000..e8ba84b --- /dev/null +++ b/app/src/main/java/eu/steffo/twom/create/CreateActivityContent.kt @@ -0,0 +1,97 @@ +package eu.steffo.twom.create + +import android.graphics.BitmapFactory +import android.net.Uri +import androidx.activity.compose.rememberLauncherForActivityResult +import androidx.activity.result.PickVisualMediaRequest +import androidx.activity.result.contract.ActivityResultContracts +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.material3.TextField +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.saveable.rememberSaveable +import androidx.compose.runtime.setValue +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.graphics.ImageBitmap +import androidx.compose.ui.graphics.asImageBitmap +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.semantics.contentDescription +import androidx.compose.ui.semantics.semantics +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import eu.steffo.twom.R +import eu.steffo.twom.matrix.avatar.AvatarFromBitmap +import eu.steffo.twom.theme.TwoMPadding + +@Composable +@Preview +fun CreateActivityContent( + modifier: Modifier = Modifier, +) { + val context = LocalContext.current + + var name by rememberSaveable { mutableStateOf("") } + var avatarUri by rememberSaveable { mutableStateOf(null) } + var avatarBitmap by remember { mutableStateOf(null) } + + // val avatarBitmap = if(avatarUri != null) BitmapFactory.decodeFile(avatarUri.toString()).asImageBitmap() else null + val avatarSelectLauncher = + rememberLauncherForActivityResult(ActivityResultContracts.PickVisualMedia()) { + avatarUri = it + if (it == null) { + avatarBitmap = null + } else { + val stream = context.contentResolver.openInputStream(it) + if (stream != null) { + avatarBitmap = BitmapFactory.decodeStream(stream).asImageBitmap() + stream.close() + } + } + } + + Column(modifier) { + Row(TwoMPadding.base) { + val avatarContentDescription = stringResource(R.string.create_avatar_label) + Box( + modifier = Modifier + .size(60.dp) + .clip(MaterialTheme.shapes.medium) + .clickable { + avatarSelectLauncher.launch(PickVisualMediaRequest(ActivityResultContracts.PickVisualMedia.ImageOnly)) + } + .semantics { + this.contentDescription = avatarContentDescription + } + ) { + AvatarFromBitmap( + bitmap = avatarBitmap, + ) + } + + TextField( + modifier = Modifier + .height(60.dp) + .padding(start = 10.dp) + .fillMaxWidth(), + label = { + Text(stringResource(R.string.create_name_label)) + }, + value = name, + onValueChange = { name = it } + ) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/eu/steffo/twom/create/CreateActivityScaffold.kt b/app/src/main/java/eu/steffo/twom/create/CreateActivityScaffold.kt new file mode 100644 index 0000000..38fd0e9 --- /dev/null +++ b/app/src/main/java/eu/steffo/twom/create/CreateActivityScaffold.kt @@ -0,0 +1,28 @@ +package eu.steffo.twom.create + +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.Scaffold +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.tooling.preview.Preview +import eu.steffo.twom.theme.TwoMTheme + +@Composable +@Preview +fun CreateActivityScaffold( + onClickBack: () -> Unit = {}, + onClickCreate: () -> Unit = {}, +) { + TwoMTheme { + Scaffold( + topBar = { + CreateActivityTopBar() + }, + content = { + CreateActivityContent( + modifier = Modifier.padding(it), + ) + } + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/eu/steffo/twom/create/CreateActivityTopBar.kt b/app/src/main/java/eu/steffo/twom/create/CreateActivityTopBar.kt new file mode 100644 index 0000000..599a403 --- /dev/null +++ b/app/src/main/java/eu/steffo/twom/create/CreateActivityTopBar.kt @@ -0,0 +1,35 @@ +package eu.steffo.twom.create + +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.ArrowBack +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.tooling.preview.Preview +import eu.steffo.twom.R + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +@Preview +fun CreateActivityTopBar( + modifier: Modifier = Modifier, + onBack: () -> Unit = {}, +) { + TopAppBar( + modifier = modifier, + navigationIcon = { + IconButton(onClick = onBack) { + Icon( + imageVector = Icons.Filled.ArrowBack, + contentDescription = LocalContext.current.getString(R.string.back) + ) + } + }, + title = { Text(LocalContext.current.getString(R.string.create_title)) } + ) +} \ No newline at end of file diff --git a/app/src/main/java/eu/steffo/twom/matrix/avatar/AvatarFromBitmap.kt b/app/src/main/java/eu/steffo/twom/matrix/avatar/AvatarFromBitmap.kt new file mode 100644 index 0000000..f4a57c2 --- /dev/null +++ b/app/src/main/java/eu/steffo/twom/matrix/avatar/AvatarFromBitmap.kt @@ -0,0 +1,30 @@ +package eu.steffo.twom.matrix.avatar + +import androidx.compose.foundation.Image +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.ImageBitmap +import androidx.compose.ui.tooling.preview.Preview + +@Composable +@Preview(widthDp = 40, heightDp = 40) +fun AvatarFromBitmap( + modifier: Modifier = Modifier, + bitmap: ImageBitmap? = null, + fallbackText: String = "?", + contentDescription: String = "", +) { + if (bitmap == null) { + AvatarFromDefault( + modifier = modifier, + fallbackText = fallbackText, + contentDescription = contentDescription, + ) + } else { + Image( + modifier = modifier, + bitmap = bitmap, + contentDescription = contentDescription, + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/eu/steffo/twom/matrix/avatar/AvatarFromDefault.kt b/app/src/main/java/eu/steffo/twom/matrix/avatar/AvatarFromDefault.kt index d853e10..ff40acf 100644 --- a/app/src/main/java/eu/steffo/twom/matrix/avatar/AvatarFromDefault.kt +++ b/app/src/main/java/eu/steffo/twom/matrix/avatar/AvatarFromDefault.kt @@ -16,6 +16,7 @@ import androidx.compose.ui.tooling.preview.Preview @Preview(widthDp = 40, heightDp = 40) fun AvatarFromDefault( modifier: Modifier = Modifier, + fallbackText: String = "?", contentDescription: String = "", ) { Box( @@ -30,7 +31,7 @@ fun AvatarFromDefault( this.contentDescription = "" }, color = MaterialTheme.colorScheme.onTertiary, - text = "?", + text = fallbackText, ) } } \ No newline at end of file diff --git a/app/src/main/java/eu/steffo/twom/matrix/avatar/AvatarFromURL.kt b/app/src/main/java/eu/steffo/twom/matrix/avatar/AvatarFromURL.kt index 6706f76..9671462 100644 --- a/app/src/main/java/eu/steffo/twom/matrix/avatar/AvatarFromURL.kt +++ b/app/src/main/java/eu/steffo/twom/matrix/avatar/AvatarFromURL.kt @@ -20,6 +20,7 @@ import eu.steffo.twom.matrix.LocalSession fun AvatarFromURL( modifier: Modifier = Modifier, url: String? = "", + fallbackText: String = "?", contentDescription: String = "", ) { val session = LocalSession.current @@ -55,6 +56,7 @@ fun AvatarFromURL( if (session == null || url == null || avatar == null) { AvatarFromDefault( modifier = modifier, + fallbackText = fallbackText, contentDescription = contentDescription ) } else { diff --git a/app/src/main/java/eu/steffo/twom/matrix/avatar/AvatarFromUserId.kt b/app/src/main/java/eu/steffo/twom/matrix/avatar/AvatarFromUserId.kt index 820b230..1a1ea85 100644 --- a/app/src/main/java/eu/steffo/twom/matrix/avatar/AvatarFromUserId.kt +++ b/app/src/main/java/eu/steffo/twom/matrix/avatar/AvatarFromUserId.kt @@ -16,6 +16,7 @@ import eu.steffo.twom.matrix.LocalSession fun AvatarFromUserId( modifier: Modifier = Modifier, userId: String = "", + fallbackText: String = "?", contentDescription: String = "", ) { val session = LocalSession.current @@ -38,12 +39,14 @@ fun AvatarFromUserId( if (avatarUrl == null) { AvatarFromDefault( modifier = modifier, + fallbackText = fallbackText, contentDescription = contentDescription, ) } else { AvatarFromURL( modifier = modifier, url = avatarUrl!!, + fallbackText = fallbackText, contentDescription = contentDescription, ) } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 7060fc3..46a9ea2 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -27,4 +27,7 @@ New Log into your Matrix account by clicking the icon on the top right of the screen. Login + Create a new happening + Name + Select happening avatar \ No newline at end of file