commit
795221f478
209 changed files with 2904 additions and 901 deletions
|
|
@ -18,16 +18,15 @@ package io.element.android.x
|
||||||
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import androidx.activity.compose.setContent
|
import androidx.activity.compose.setContent
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.material3.MaterialTheme
|
|
||||||
import androidx.compose.material3.Surface
|
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
|
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
|
||||||
import androidx.core.view.WindowCompat
|
import androidx.core.view.WindowCompat
|
||||||
import com.bumble.appyx.core.integration.NodeHost
|
import com.bumble.appyx.core.integration.NodeHost
|
||||||
import com.bumble.appyx.core.integrationpoint.NodeComponentActivity
|
import com.bumble.appyx.core.integrationpoint.NodeComponentActivity
|
||||||
import io.element.android.libraries.architecture.bindings
|
import io.element.android.libraries.architecture.bindings
|
||||||
import io.element.android.libraries.designsystem.ElementXTheme
|
import io.element.android.libraries.designsystem.theme.ElementTheme
|
||||||
import io.element.android.libraries.di.DaggerComponentOwner
|
import io.element.android.libraries.di.DaggerComponentOwner
|
||||||
import io.element.android.x.di.AppBindings
|
import io.element.android.x.di.AppBindings
|
||||||
import io.element.android.x.node.RootFlowNode
|
import io.element.android.x.node.RootFlowNode
|
||||||
|
|
@ -41,10 +40,9 @@ class MainActivity : NodeComponentActivity() {
|
||||||
appBindings.matrixClientsHolder().restore(savedInstanceState)
|
appBindings.matrixClientsHolder().restore(savedInstanceState)
|
||||||
WindowCompat.setDecorFitsSystemWindows(window, false)
|
WindowCompat.setDecorFitsSystemWindows(window, false)
|
||||||
setContent {
|
setContent {
|
||||||
ElementXTheme {
|
ElementTheme {
|
||||||
Surface(
|
Box(
|
||||||
modifier = Modifier.fillMaxSize(),
|
modifier = Modifier.fillMaxSize(),
|
||||||
color = MaterialTheme.colorScheme.background
|
|
||||||
) {
|
) {
|
||||||
NodeHost(integrationPoint = appyxIntegrationPoint) {
|
NodeHost(integrationPoint = appyxIntegrationPoint) {
|
||||||
RootFlowNode(
|
RootFlowNode(
|
||||||
|
|
|
||||||
|
|
@ -20,13 +20,13 @@ import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.layout.size
|
import androidx.compose.foundation.layout.size
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.filled.Close
|
import androidx.compose.material.icons.filled.Close
|
||||||
import androidx.compose.material3.Button
|
|
||||||
import androidx.compose.material3.Icon
|
|
||||||
import androidx.compose.material3.IconButton
|
|
||||||
import androidx.compose.material3.Text
|
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
|
import io.element.android.libraries.designsystem.theme.components.Button
|
||||||
|
import io.element.android.libraries.designsystem.theme.components.Icon
|
||||||
|
import io.element.android.libraries.designsystem.theme.components.IconButton
|
||||||
|
import io.element.android.libraries.designsystem.theme.components.Text
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
internal fun ShowkaseButton(
|
internal fun ShowkaseButton(
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,6 @@ import com.squareup.anvil.annotations.ContributesTo
|
||||||
import io.element.android.libraries.di.AppScope
|
import io.element.android.libraries.di.AppScope
|
||||||
import io.element.android.libraries.matrix.auth.MatrixAuthenticationService
|
import io.element.android.libraries.matrix.auth.MatrixAuthenticationService
|
||||||
import io.element.android.x.root.RootPresenter
|
import io.element.android.x.root.RootPresenter
|
||||||
import kotlinx.coroutines.CoroutineScope
|
|
||||||
|
|
||||||
@ContributesTo(AppScope::class)
|
@ContributesTo(AppScope::class)
|
||||||
interface AppBindings {
|
interface AppBindings {
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,6 @@ package io.element.android.x.node
|
||||||
import android.os.Parcelable
|
import android.os.Parcelable
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.material3.Text
|
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
|
@ -37,6 +36,7 @@ import io.element.android.features.roomlist.RoomListNode
|
||||||
import io.element.android.libraries.architecture.animation.rememberDefaultTransitionHandler
|
import io.element.android.libraries.architecture.animation.rememberDefaultTransitionHandler
|
||||||
import io.element.android.libraries.architecture.bindings
|
import io.element.android.libraries.architecture.bindings
|
||||||
import io.element.android.libraries.architecture.createNode
|
import io.element.android.libraries.architecture.createNode
|
||||||
|
import io.element.android.libraries.designsystem.theme.components.Text
|
||||||
import io.element.android.libraries.di.DaggerComponentOwner
|
import io.element.android.libraries.di.DaggerComponentOwner
|
||||||
import io.element.android.libraries.matrix.MatrixClient
|
import io.element.android.libraries.matrix.MatrixClient
|
||||||
import io.element.android.libraries.matrix.core.RoomId
|
import io.element.android.libraries.matrix.core.RoomId
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,6 @@ package io.element.android.x.node
|
||||||
import android.os.Parcelable
|
import android.os.Parcelable
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.material3.CircularProgressIndicator
|
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
|
@ -36,6 +35,7 @@ import com.bumble.appyx.navmodel.backstack.operation.push
|
||||||
import io.element.android.features.rageshake.bugreport.BugReportNode
|
import io.element.android.features.rageshake.bugreport.BugReportNode
|
||||||
import io.element.android.libraries.architecture.animation.rememberDefaultTransitionHandler
|
import io.element.android.libraries.architecture.animation.rememberDefaultTransitionHandler
|
||||||
import io.element.android.libraries.architecture.createNode
|
import io.element.android.libraries.architecture.createNode
|
||||||
|
import io.element.android.libraries.designsystem.theme.components.CircularProgressIndicator
|
||||||
import io.element.android.libraries.di.DaggerComponentOwner
|
import io.element.android.libraries.di.DaggerComponentOwner
|
||||||
import io.element.android.libraries.matrix.auth.MatrixAuthenticationService
|
import io.element.android.libraries.matrix.auth.MatrixAuthenticationService
|
||||||
import io.element.android.libraries.matrix.core.SessionId
|
import io.element.android.libraries.matrix.core.SessionId
|
||||||
|
|
|
||||||
|
|
@ -14,8 +14,6 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@file:OptIn(ExperimentalMaterial3Api::class)
|
|
||||||
|
|
||||||
package io.element.android.features.login.changeserver
|
package io.element.android.features.login.changeserver
|
||||||
|
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
|
|
@ -33,13 +31,7 @@ import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
import androidx.compose.foundation.text.KeyboardActions
|
import androidx.compose.foundation.text.KeyboardActions
|
||||||
import androidx.compose.foundation.text.KeyboardOptions
|
import androidx.compose.foundation.text.KeyboardOptions
|
||||||
import androidx.compose.foundation.verticalScroll
|
import androidx.compose.foundation.verticalScroll
|
||||||
import androidx.compose.material3.Button
|
|
||||||
import androidx.compose.material3.CircularProgressIndicator
|
|
||||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.OutlinedTextField
|
|
||||||
import androidx.compose.material3.Surface
|
|
||||||
import androidx.compose.material3.Text
|
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
|
|
@ -57,6 +49,12 @@ import io.element.android.features.login.error.changeServerError
|
||||||
import io.element.android.libraries.architecture.Async
|
import io.element.android.libraries.architecture.Async
|
||||||
import io.element.android.libraries.designsystem.components.VectorIcon
|
import io.element.android.libraries.designsystem.components.VectorIcon
|
||||||
import io.element.android.libraries.designsystem.components.form.textFieldState
|
import io.element.android.libraries.designsystem.components.form.textFieldState
|
||||||
|
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
|
||||||
|
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
|
||||||
|
import io.element.android.libraries.designsystem.theme.components.Button
|
||||||
|
import io.element.android.libraries.designsystem.theme.components.CircularProgressIndicator
|
||||||
|
import io.element.android.libraries.designsystem.theme.components.OutlinedTextField
|
||||||
|
import io.element.android.libraries.designsystem.theme.components.Text
|
||||||
import io.element.android.libraries.testtags.TestTags
|
import io.element.android.libraries.testtags.TestTags
|
||||||
import io.element.android.libraries.testtags.testTag
|
import io.element.android.libraries.testtags.testTag
|
||||||
|
|
||||||
|
|
@ -66,126 +64,129 @@ fun ChangeServerView(
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
onChangeServerSuccess: () -> Unit = {},
|
onChangeServerSuccess: () -> Unit = {},
|
||||||
) {
|
) {
|
||||||
Surface(
|
val eventSink = state.eventSink
|
||||||
modifier = modifier,
|
val scrollState = rememberScrollState()
|
||||||
color = MaterialTheme.colorScheme.background,
|
Box(
|
||||||
|
modifier = modifier
|
||||||
|
.fillMaxSize()
|
||||||
|
.systemBarsPadding()
|
||||||
|
.imePadding()
|
||||||
) {
|
) {
|
||||||
val eventSink = state.eventSink
|
Column(
|
||||||
val scrollState = rememberScrollState()
|
|
||||||
Box(
|
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxSize()
|
.verticalScroll(
|
||||||
.systemBarsPadding()
|
state = scrollState,
|
||||||
.imePadding()
|
)
|
||||||
|
.padding(horizontal = 16.dp)
|
||||||
) {
|
) {
|
||||||
Column(
|
val isError = state.changeServerAction is Async.Failure
|
||||||
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.verticalScroll(
|
.padding(top = 99.dp)
|
||||||
state = scrollState,
|
.size(width = 81.dp, height = 73.dp)
|
||||||
|
.align(Alignment.CenterHorizontally)
|
||||||
|
.background(
|
||||||
|
color = MaterialTheme.colorScheme.surfaceVariant,
|
||||||
|
shape = RoundedCornerShape(32.dp)
|
||||||
)
|
)
|
||||||
.padding(horizontal = 16.dp)
|
|
||||||
) {
|
) {
|
||||||
val isError = state.changeServerAction is Async.Failure
|
VectorIcon(
|
||||||
Box(
|
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.padding(top = 99.dp)
|
.align(Alignment.Center)
|
||||||
.size(width = 81.dp, height = 73.dp)
|
.size(width = 48.dp, height = 48.dp),
|
||||||
.align(Alignment.CenterHorizontally)
|
// TODO Update with design input
|
||||||
.background(
|
resourceId = R.drawable.ic_baseline_dataset_24,
|
||||||
color = MaterialTheme.colorScheme.surfaceVariant,
|
|
||||||
shape = RoundedCornerShape(32.dp)
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
VectorIcon(
|
|
||||||
modifier = Modifier
|
|
||||||
.align(Alignment.Center)
|
|
||||||
.size(width = 48.dp, height = 48.dp),
|
|
||||||
// TODO Update with design input
|
|
||||||
resourceId = R.drawable.ic_baseline_dataset_24,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Text(
|
|
||||||
text = "Your server",
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxWidth()
|
|
||||||
.defaultMinSize(minHeight = 56.dp)
|
|
||||||
.align(Alignment.CenterHorizontally)
|
|
||||||
.padding(top = 38.dp),
|
|
||||||
textAlign = TextAlign.Center,
|
|
||||||
fontWeight = FontWeight.Bold,
|
|
||||||
fontSize = 24.sp,
|
|
||||||
)
|
)
|
||||||
Text(
|
}
|
||||||
text = "A server is a home for all your data.\n" +
|
Text(
|
||||||
"You choose your server and it’s easy to make one.", // TODO "Learn more.",
|
text = "Your server",
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.align(Alignment.CenterHorizontally)
|
.defaultMinSize(minHeight = 56.dp)
|
||||||
.padding(top = 16.dp),
|
.align(Alignment.CenterHorizontally)
|
||||||
textAlign = TextAlign.Center,
|
.padding(top = 38.dp),
|
||||||
fontSize = 16.sp,
|
textAlign = TextAlign.Center,
|
||||||
color = MaterialTheme.colorScheme.secondary
|
fontWeight = FontWeight.Bold,
|
||||||
|
fontSize = 24.sp,
|
||||||
|
color = MaterialTheme.colorScheme.primary,
|
||||||
|
)
|
||||||
|
Text(
|
||||||
|
text = "A server is a home for all your data.\n" +
|
||||||
|
"You choose your server and it’s easy to make one.", // TODO "Learn more.",
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.align(Alignment.CenterHorizontally)
|
||||||
|
.padding(top = 16.dp),
|
||||||
|
textAlign = TextAlign.Center,
|
||||||
|
fontSize = 16.sp,
|
||||||
|
color = MaterialTheme.colorScheme.secondary,
|
||||||
|
)
|
||||||
|
var homeserverFieldState by textFieldState(stateValue = state.homeserver)
|
||||||
|
OutlinedTextField(
|
||||||
|
value = homeserverFieldState,
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.testTag(TestTags.changeServerServer)
|
||||||
|
.padding(top = 200.dp),
|
||||||
|
onValueChange = {
|
||||||
|
homeserverFieldState = it
|
||||||
|
eventSink(ChangeServerEvents.SetServer(it))
|
||||||
|
},
|
||||||
|
label = {
|
||||||
|
Text(text = "Server")
|
||||||
|
},
|
||||||
|
isError = isError,
|
||||||
|
keyboardOptions = KeyboardOptions(
|
||||||
|
keyboardType = KeyboardType.Password,
|
||||||
|
imeAction = ImeAction.Done,
|
||||||
|
),
|
||||||
|
keyboardActions = KeyboardActions(
|
||||||
|
onDone = { eventSink(ChangeServerEvents.Submit) }
|
||||||
)
|
)
|
||||||
var homeserverFieldState by textFieldState(stateValue = state.homeserver)
|
)
|
||||||
OutlinedTextField(
|
if (state.changeServerAction is Async.Failure) {
|
||||||
value = homeserverFieldState,
|
Text(
|
||||||
modifier = Modifier
|
text = changeServerError(
|
||||||
.fillMaxWidth()
|
state.homeserver,
|
||||||
.testTag(TestTags.changeServerServer)
|
state.changeServerAction.error
|
||||||
.padding(top = 200.dp),
|
|
||||||
onValueChange = {
|
|
||||||
homeserverFieldState = it
|
|
||||||
eventSink(ChangeServerEvents.SetServer(it))
|
|
||||||
},
|
|
||||||
label = {
|
|
||||||
Text(text = "Server")
|
|
||||||
},
|
|
||||||
isError = isError,
|
|
||||||
keyboardOptions = KeyboardOptions(
|
|
||||||
keyboardType = KeyboardType.Password,
|
|
||||||
imeAction = ImeAction.Done,
|
|
||||||
),
|
),
|
||||||
keyboardActions = KeyboardActions(
|
color = MaterialTheme.colorScheme.error,
|
||||||
onDone = { eventSink(ChangeServerEvents.Submit) }
|
style = MaterialTheme.typography.bodySmall,
|
||||||
)
|
modifier = Modifier.padding(start = 16.dp)
|
||||||
)
|
|
||||||
if (state.changeServerAction is Async.Failure) {
|
|
||||||
Text(
|
|
||||||
text = changeServerError(
|
|
||||||
state.homeserver,
|
|
||||||
state.changeServerAction.error
|
|
||||||
),
|
|
||||||
color = MaterialTheme.colorScheme.error,
|
|
||||||
style = MaterialTheme.typography.bodySmall,
|
|
||||||
modifier = Modifier.padding(start = 16.dp)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Button(
|
|
||||||
onClick = { eventSink(ChangeServerEvents.Submit) },
|
|
||||||
enabled = state.submitEnabled,
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxWidth()
|
|
||||||
.testTag(TestTags.changeServerContinue)
|
|
||||||
.padding(top = 44.dp)
|
|
||||||
) {
|
|
||||||
Text(text = "Continue")
|
|
||||||
}
|
|
||||||
if (state.changeServerAction is Async.Success) {
|
|
||||||
onChangeServerSuccess()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (state.changeServerAction is Async.Loading) {
|
|
||||||
CircularProgressIndicator(
|
|
||||||
modifier = Modifier.align(Alignment.Center)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
Button(
|
||||||
|
onClick = { eventSink(ChangeServerEvents.Submit) },
|
||||||
|
enabled = state.submitEnabled,
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.testTag(TestTags.changeServerContinue)
|
||||||
|
.padding(top = 44.dp)
|
||||||
|
) {
|
||||||
|
Text(text = "Continue")
|
||||||
|
}
|
||||||
|
if (state.changeServerAction is Async.Success) {
|
||||||
|
onChangeServerSuccess()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (state.changeServerAction is Async.Loading) {
|
||||||
|
CircularProgressIndicator(
|
||||||
|
modifier = Modifier.align(Alignment.Center)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
|
||||||
@Preview
|
@Preview
|
||||||
fun ChangeServerContentPreview() {
|
@Composable
|
||||||
|
fun ChangeServerViewLightPreview() = ElementPreviewLight { ContentToPreview() }
|
||||||
|
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
fun ChangeServerViewDarkPreview() = ElementPreviewDark { ContentToPreview() }
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun ContentToPreview() {
|
||||||
ChangeServerView(
|
ChangeServerView(
|
||||||
state = ChangeServerState(homeserver = "matrix.org"),
|
state = ChangeServerState(homeserver = "matrix.org"),
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -14,8 +14,6 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@file:OptIn(ExperimentalMaterial3Api::class)
|
|
||||||
|
|
||||||
package io.element.android.features.login.root
|
package io.element.android.features.login.root
|
||||||
|
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
|
|
@ -32,15 +30,7 @@ import androidx.compose.foundation.verticalScroll
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.filled.Visibility
|
import androidx.compose.material.icons.filled.Visibility
|
||||||
import androidx.compose.material.icons.filled.VisibilityOff
|
import androidx.compose.material.icons.filled.VisibilityOff
|
||||||
import androidx.compose.material3.Button
|
|
||||||
import androidx.compose.material3.CircularProgressIndicator
|
|
||||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
|
||||||
import androidx.compose.material3.Icon
|
|
||||||
import androidx.compose.material3.IconButton
|
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.OutlinedTextField
|
|
||||||
import androidx.compose.material3.Surface
|
|
||||||
import androidx.compose.material3.Text
|
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
|
@ -60,12 +50,19 @@ import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.unit.sp
|
import androidx.compose.ui.unit.sp
|
||||||
import io.element.android.features.login.error.loginError
|
import io.element.android.features.login.error.loginError
|
||||||
import io.element.android.libraries.designsystem.components.form.textFieldState
|
import io.element.android.libraries.designsystem.components.form.textFieldState
|
||||||
|
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
|
||||||
|
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
|
||||||
|
import io.element.android.libraries.designsystem.theme.components.Button
|
||||||
|
import io.element.android.libraries.designsystem.theme.components.CircularProgressIndicator
|
||||||
|
import io.element.android.libraries.designsystem.theme.components.Icon
|
||||||
|
import io.element.android.libraries.designsystem.theme.components.IconButton
|
||||||
|
import io.element.android.libraries.designsystem.theme.components.OutlinedTextField
|
||||||
|
import io.element.android.libraries.designsystem.theme.components.Text
|
||||||
import io.element.android.libraries.matrix.core.SessionId
|
import io.element.android.libraries.matrix.core.SessionId
|
||||||
import io.element.android.libraries.testtags.TestTags
|
import io.element.android.libraries.testtags.TestTags
|
||||||
import io.element.android.libraries.testtags.testTag
|
import io.element.android.libraries.testtags.testTag
|
||||||
import io.element.android.libraries.ui.strings.R as StringR
|
import io.element.android.libraries.ui.strings.R as StringR
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterial3Api::class)
|
|
||||||
@Composable
|
@Composable
|
||||||
fun LoginRootScreen(
|
fun LoginRootScreen(
|
||||||
state: LoginRootState,
|
state: LoginRootState,
|
||||||
|
|
@ -74,161 +71,164 @@ fun LoginRootScreen(
|
||||||
onLoginWithSuccess: (SessionId) -> Unit = {},
|
onLoginWithSuccess: (SessionId) -> Unit = {},
|
||||||
) {
|
) {
|
||||||
val eventSink = state.eventSink
|
val eventSink = state.eventSink
|
||||||
Surface(
|
Box(
|
||||||
modifier = modifier,
|
modifier = modifier
|
||||||
color = MaterialTheme.colorScheme.background,
|
.fillMaxSize()
|
||||||
|
.systemBarsPadding()
|
||||||
|
.imePadding()
|
||||||
) {
|
) {
|
||||||
Box(
|
val scrollState = rememberScrollState()
|
||||||
|
var loginFieldState by textFieldState(stateValue = state.formState.login)
|
||||||
|
var passwordFieldState by textFieldState(stateValue = state.formState.password)
|
||||||
|
|
||||||
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxSize()
|
.verticalScroll(
|
||||||
.systemBarsPadding()
|
state = scrollState,
|
||||||
.imePadding()
|
)
|
||||||
|
.padding(horizontal = 16.dp),
|
||||||
) {
|
) {
|
||||||
val scrollState = rememberScrollState()
|
val isError = state.loggedInState is LoggedInState.ErrorLoggingIn
|
||||||
var loginFieldState by textFieldState(stateValue = state.formState.login)
|
// Title
|
||||||
var passwordFieldState by textFieldState(stateValue = state.formState.password)
|
Text(
|
||||||
|
text = stringResource(id = StringR.string.ftue_auth_welcome_back_title),
|
||||||
Column(
|
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.verticalScroll(
|
.fillMaxWidth()
|
||||||
state = scrollState,
|
.padding(horizontal = 16.dp, vertical = 48.dp),
|
||||||
)
|
textAlign = TextAlign.Center,
|
||||||
.padding(horizontal = 16.dp),
|
fontWeight = FontWeight.Bold,
|
||||||
|
fontSize = 24.sp,
|
||||||
|
color = MaterialTheme.colorScheme.primary,
|
||||||
|
)
|
||||||
|
// Form
|
||||||
|
Column(
|
||||||
|
// modifier = Modifier.weight(1f),
|
||||||
) {
|
) {
|
||||||
val isError = state.loggedInState is LoggedInState.ErrorLoggingIn
|
Box(
|
||||||
// Title
|
modifier = Modifier.fillMaxWidth()
|
||||||
Text(
|
|
||||||
text = stringResource(id = StringR.string.ftue_auth_welcome_back_title),
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxWidth()
|
|
||||||
.padding(horizontal = 16.dp, vertical = 48.dp),
|
|
||||||
textAlign = TextAlign.Center,
|
|
||||||
fontWeight = FontWeight.Bold,
|
|
||||||
fontSize = 24.sp,
|
|
||||||
)
|
|
||||||
// Form
|
|
||||||
Column(
|
|
||||||
// modifier = Modifier.weight(1f),
|
|
||||||
) {
|
) {
|
||||||
Box(
|
|
||||||
modifier = Modifier.fillMaxWidth()
|
|
||||||
) {
|
|
||||||
OutlinedTextField(
|
|
||||||
value = state.homeserver,
|
|
||||||
modifier = Modifier.fillMaxWidth(),
|
|
||||||
onValueChange = { /* no op */ },
|
|
||||||
enabled = false,
|
|
||||||
label = {
|
|
||||||
Text(text = "Server")
|
|
||||||
},
|
|
||||||
keyboardOptions = KeyboardOptions(
|
|
||||||
keyboardType = KeyboardType.Uri,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
Button(
|
|
||||||
onClick = onChangeServer,
|
|
||||||
modifier = Modifier
|
|
||||||
.align(Alignment.CenterEnd)
|
|
||||||
.testTag(TestTags.loginChangeServer)
|
|
||||||
.padding(top = 8.dp, end = 8.dp),
|
|
||||||
content = {
|
|
||||||
Text(text = "Change")
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
OutlinedTextField(
|
OutlinedTextField(
|
||||||
value = loginFieldState,
|
value = state.homeserver,
|
||||||
modifier = Modifier
|
modifier = Modifier.fillMaxWidth(),
|
||||||
.fillMaxWidth()
|
onValueChange = { /* no op */ },
|
||||||
.testTag(TestTags.loginEmailUsername)
|
enabled = false,
|
||||||
.padding(top = 60.dp),
|
|
||||||
label = {
|
label = {
|
||||||
Text(text = stringResource(id = StringR.string.login_signin_username_hint))
|
Text(text = "Server")
|
||||||
},
|
|
||||||
onValueChange = {
|
|
||||||
loginFieldState = it
|
|
||||||
eventSink(LoginRootEvents.SetLogin(it))
|
|
||||||
},
|
},
|
||||||
keyboardOptions = KeyboardOptions(
|
keyboardOptions = KeyboardOptions(
|
||||||
keyboardType = KeyboardType.Email,
|
keyboardType = KeyboardType.Uri,
|
||||||
imeAction = ImeAction.Next
|
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
var passwordVisible by remember { mutableStateOf(false) }
|
Button(
|
||||||
if (state.loggedInState is LoggedInState.LoggingIn) {
|
onClick = onChangeServer,
|
||||||
// Ensure password is hidden when user submits the form
|
|
||||||
passwordVisible = false
|
|
||||||
}
|
|
||||||
OutlinedTextField(
|
|
||||||
value = passwordFieldState,
|
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.align(Alignment.CenterEnd)
|
||||||
.testTag(TestTags.loginPassword)
|
.testTag(TestTags.loginChangeServer)
|
||||||
.padding(top = 24.dp),
|
.padding(top = 8.dp, end = 8.dp),
|
||||||
onValueChange = {
|
content = {
|
||||||
passwordFieldState = it
|
Text(text = "Change")
|
||||||
eventSink(LoginRootEvents.SetPassword(it))
|
}
|
||||||
},
|
)
|
||||||
label = {
|
}
|
||||||
Text(text = "Password")
|
OutlinedTextField(
|
||||||
},
|
value = loginFieldState,
|
||||||
isError = isError,
|
modifier = Modifier
|
||||||
visualTransformation = if (passwordVisible) VisualTransformation.None else PasswordVisualTransformation(),
|
.fillMaxWidth()
|
||||||
trailingIcon = {
|
.testTag(TestTags.loginEmailUsername)
|
||||||
val image =
|
.padding(top = 60.dp),
|
||||||
if (passwordVisible) Icons.Filled.Visibility else Icons.Filled.VisibilityOff
|
label = {
|
||||||
val description =
|
Text(text = stringResource(id = StringR.string.login_signin_username_hint))
|
||||||
if (passwordVisible) "Hide password" else "Show password"
|
},
|
||||||
|
onValueChange = {
|
||||||
|
loginFieldState = it
|
||||||
|
eventSink(LoginRootEvents.SetLogin(it))
|
||||||
|
},
|
||||||
|
keyboardOptions = KeyboardOptions(
|
||||||
|
keyboardType = KeyboardType.Email,
|
||||||
|
imeAction = ImeAction.Next
|
||||||
|
),
|
||||||
|
)
|
||||||
|
var passwordVisible by remember { mutableStateOf(false) }
|
||||||
|
if (state.loggedInState is LoggedInState.LoggingIn) {
|
||||||
|
// Ensure password is hidden when user submits the form
|
||||||
|
passwordVisible = false
|
||||||
|
}
|
||||||
|
OutlinedTextField(
|
||||||
|
value = passwordFieldState,
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.testTag(TestTags.loginPassword)
|
||||||
|
.padding(top = 24.dp),
|
||||||
|
onValueChange = {
|
||||||
|
passwordFieldState = it
|
||||||
|
eventSink(LoginRootEvents.SetPassword(it))
|
||||||
|
},
|
||||||
|
label = {
|
||||||
|
Text(text = "Password")
|
||||||
|
},
|
||||||
|
isError = isError,
|
||||||
|
visualTransformation = if (passwordVisible) VisualTransformation.None else PasswordVisualTransformation(),
|
||||||
|
trailingIcon = {
|
||||||
|
val image =
|
||||||
|
if (passwordVisible) Icons.Filled.Visibility else Icons.Filled.VisibilityOff
|
||||||
|
val description =
|
||||||
|
if (passwordVisible) "Hide password" else "Show password"
|
||||||
|
|
||||||
IconButton(onClick = { passwordVisible = !passwordVisible }) {
|
IconButton(onClick = { passwordVisible = !passwordVisible }) {
|
||||||
Icon(imageVector = image, description)
|
Icon(imageVector = image, description)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
keyboardOptions = KeyboardOptions(
|
keyboardOptions = KeyboardOptions(
|
||||||
keyboardType = KeyboardType.Password,
|
keyboardType = KeyboardType.Password,
|
||||||
imeAction = ImeAction.Done,
|
imeAction = ImeAction.Done,
|
||||||
),
|
),
|
||||||
keyboardActions = KeyboardActions(
|
keyboardActions = KeyboardActions(
|
||||||
onDone = { eventSink(LoginRootEvents.Submit) }
|
onDone = { eventSink(LoginRootEvents.Submit) }
|
||||||
),
|
),
|
||||||
)
|
|
||||||
if (state.loggedInState is LoggedInState.ErrorLoggingIn) {
|
|
||||||
Text(
|
|
||||||
text = loginError(state.formState, state.loggedInState.failure),
|
|
||||||
color = MaterialTheme.colorScheme.error,
|
|
||||||
style = MaterialTheme.typography.bodySmall,
|
|
||||||
modifier = Modifier.padding(start = 16.dp)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Submit
|
|
||||||
Button(
|
|
||||||
onClick = { eventSink(LoginRootEvents.Submit) },
|
|
||||||
enabled = state.submitEnabled,
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxWidth()
|
|
||||||
.testTag(TestTags.loginContinue)
|
|
||||||
.padding(vertical = 32.dp)
|
|
||||||
) {
|
|
||||||
Text(text = "Continue")
|
|
||||||
}
|
|
||||||
when (val loggedInState = state.loggedInState) {
|
|
||||||
is LoggedInState.LoggedIn -> onLoginWithSuccess(loggedInState.sessionId)
|
|
||||||
else -> Unit
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (state.loggedInState is LoggedInState.LoggingIn) {
|
|
||||||
CircularProgressIndicator(
|
|
||||||
modifier = Modifier.align(Alignment.Center)
|
|
||||||
)
|
)
|
||||||
|
if (state.loggedInState is LoggedInState.ErrorLoggingIn) {
|
||||||
|
Text(
|
||||||
|
text = loginError(state.formState, state.loggedInState.failure),
|
||||||
|
color = MaterialTheme.colorScheme.error,
|
||||||
|
style = MaterialTheme.typography.bodySmall,
|
||||||
|
modifier = Modifier.padding(start = 16.dp)
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
// Submit
|
||||||
|
Button(
|
||||||
|
onClick = { eventSink(LoginRootEvents.Submit) },
|
||||||
|
enabled = state.submitEnabled,
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.testTag(TestTags.loginContinue)
|
||||||
|
.padding(vertical = 32.dp)
|
||||||
|
) {
|
||||||
|
Text(text = "Continue")
|
||||||
|
}
|
||||||
|
when (val loggedInState = state.loggedInState) {
|
||||||
|
is LoggedInState.LoggedIn -> onLoginWithSuccess(loggedInState.sessionId)
|
||||||
|
else -> Unit
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (state.loggedInState is LoggedInState.LoggingIn) {
|
||||||
|
CircularProgressIndicator(
|
||||||
|
modifier = Modifier.align(Alignment.Center)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
|
||||||
@Preview
|
@Preview
|
||||||
fun LoginContentPreview() {
|
@Composable
|
||||||
|
fun LoginRootScreenLightPreview() = ElementPreviewLight { ContentToPreview() }
|
||||||
|
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
fun LoginRootScreenDarkPreview() = ElementPreviewDark { ContentToPreview() }
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun ContentToPreview() {
|
||||||
LoginRootScreen(
|
LoginRootScreen(
|
||||||
state = LoginRootState(
|
state = LoginRootState(
|
||||||
homeserver = "matrix.org",
|
homeserver = "matrix.org",
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,8 @@ import io.element.android.libraries.designsystem.components.ProgressDialog
|
||||||
import io.element.android.libraries.designsystem.components.dialogs.ConfirmationDialog
|
import io.element.android.libraries.designsystem.components.dialogs.ConfirmationDialog
|
||||||
import io.element.android.libraries.designsystem.components.preferences.PreferenceCategory
|
import io.element.android.libraries.designsystem.components.preferences.PreferenceCategory
|
||||||
import io.element.android.libraries.designsystem.components.preferences.PreferenceText
|
import io.element.android.libraries.designsystem.components.preferences.PreferenceText
|
||||||
|
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
|
||||||
|
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
|
||||||
import io.element.android.libraries.ui.strings.R as StringR
|
import io.element.android.libraries.ui.strings.R as StringR
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
|
|
@ -88,8 +90,15 @@ fun LogoutPreferenceContent(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
|
||||||
@Preview
|
@Preview
|
||||||
fun LogoutContentPreview() {
|
@Composable
|
||||||
|
fun LogoutPreferenceViewLightPreview() = ElementPreviewLight { ContentToPreview() }
|
||||||
|
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
fun LogoutPreferenceViewDarkPreview() = ElementPreviewDark { ContentToPreview() }
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun ContentToPreview() {
|
||||||
LogoutPreferenceView(LogoutPreferenceState())
|
LogoutPreferenceView(LogoutPreferenceState())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -39,13 +39,8 @@ import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.filled.ArrowBack
|
import androidx.compose.material.icons.filled.ArrowBack
|
||||||
import androidx.compose.material.rememberModalBottomSheetState
|
import androidx.compose.material.rememberModalBottomSheetState
|
||||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
import androidx.compose.material3.Icon
|
|
||||||
import androidx.compose.material3.IconButton
|
|
||||||
import androidx.compose.material3.Scaffold
|
|
||||||
import androidx.compose.material3.SnackbarHost
|
import androidx.compose.material3.SnackbarHost
|
||||||
import androidx.compose.material3.SnackbarHostState
|
import androidx.compose.material3.SnackbarHostState
|
||||||
import androidx.compose.material3.Text
|
|
||||||
import androidx.compose.material3.TopAppBar
|
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.runtime.rememberCoroutineScope
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
|
|
@ -64,6 +59,11 @@ import io.element.android.features.messages.timeline.TimelineView
|
||||||
import io.element.android.features.messages.timeline.model.TimelineItem
|
import io.element.android.features.messages.timeline.model.TimelineItem
|
||||||
import io.element.android.libraries.designsystem.components.avatar.Avatar
|
import io.element.android.libraries.designsystem.components.avatar.Avatar
|
||||||
import io.element.android.libraries.designsystem.components.avatar.AvatarData
|
import io.element.android.libraries.designsystem.components.avatar.AvatarData
|
||||||
|
import io.element.android.libraries.designsystem.theme.components.Icon
|
||||||
|
import io.element.android.libraries.designsystem.theme.components.IconButton
|
||||||
|
import io.element.android.libraries.designsystem.theme.components.Scaffold
|
||||||
|
import io.element.android.libraries.designsystem.theme.components.Text
|
||||||
|
import io.element.android.libraries.designsystem.theme.components.TopAppBar
|
||||||
import io.element.android.libraries.designsystem.utils.LogCompositions
|
import io.element.android.libraries.designsystem.utils.LogCompositions
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
|
|
|
||||||
|
|
@ -29,11 +29,10 @@ import androidx.compose.foundation.lazy.items
|
||||||
import androidx.compose.material.ExperimentalMaterialApi
|
import androidx.compose.material.ExperimentalMaterialApi
|
||||||
import androidx.compose.material.ListItem
|
import androidx.compose.material.ListItem
|
||||||
import androidx.compose.material.LocalContentColor
|
import androidx.compose.material.LocalContentColor
|
||||||
import androidx.compose.material.MaterialTheme
|
|
||||||
import androidx.compose.material.ModalBottomSheetLayout
|
|
||||||
import androidx.compose.material.ModalBottomSheetState
|
import androidx.compose.material.ModalBottomSheetState
|
||||||
import androidx.compose.material.ModalBottomSheetValue
|
import androidx.compose.material.ModalBottomSheetValue
|
||||||
import androidx.compose.material.Text
|
import androidx.compose.material.Text
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.runtime.rememberCoroutineScope
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
|
|
@ -44,6 +43,7 @@ import androidx.compose.ui.unit.dp
|
||||||
import io.element.android.features.messages.actionlist.model.TimelineItemAction
|
import io.element.android.features.messages.actionlist.model.TimelineItemAction
|
||||||
import io.element.android.features.messages.timeline.model.TimelineItem
|
import io.element.android.features.messages.timeline.model.TimelineItem
|
||||||
import io.element.android.libraries.designsystem.components.VectorIcon
|
import io.element.android.libraries.designsystem.components.VectorIcon
|
||||||
|
import io.element.android.libraries.designsystem.theme.components.ModalBottomSheetLayout
|
||||||
import kotlinx.coroutines.flow.filter
|
import kotlinx.coroutines.flow.filter
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
|
|
@ -85,7 +85,7 @@ fun ActionListView(
|
||||||
.imePadding()
|
.imePadding()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
) {}
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
|
|
@ -115,13 +115,13 @@ private fun SheetContent(
|
||||||
text = {
|
text = {
|
||||||
Text(
|
Text(
|
||||||
text = action.title,
|
text = action.title,
|
||||||
color = if (action.destructive) MaterialTheme.colors.error else Color.Unspecified,
|
color = if (action.destructive) MaterialTheme.colorScheme.error else Color.Unspecified,
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
icon = {
|
icon = {
|
||||||
VectorIcon(
|
VectorIcon(
|
||||||
resourceId = action.icon,
|
resourceId = action.icon,
|
||||||
tint = if (action.destructive) MaterialTheme.colors.error else LocalContentColor.current,
|
tint = if (action.destructive) MaterialTheme.colorScheme.error else LocalContentColor.current,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@ package io.element.android.features.messages.actionlist.model
|
||||||
|
|
||||||
import androidx.annotation.DrawableRes
|
import androidx.annotation.DrawableRes
|
||||||
import androidx.compose.runtime.Immutable
|
import androidx.compose.runtime.Immutable
|
||||||
|
import io.element.android.libraries.designsystem.VectorIcons
|
||||||
|
|
||||||
@Immutable
|
@Immutable
|
||||||
sealed class TimelineItemAction(
|
sealed class TimelineItemAction(
|
||||||
|
|
@ -25,9 +26,9 @@ sealed class TimelineItemAction(
|
||||||
@DrawableRes val icon: Int,
|
@DrawableRes val icon: Int,
|
||||||
val destructive: Boolean = false
|
val destructive: Boolean = false
|
||||||
) {
|
) {
|
||||||
object Forward : TimelineItemAction("Forward", io.element.android.libraries.designsystem.VectorIcons.ArrowForward)
|
object Forward : TimelineItemAction("Forward", VectorIcons.ArrowForward)
|
||||||
object Copy : TimelineItemAction("Copy", io.element.android.libraries.designsystem.VectorIcons.Copy)
|
object Copy : TimelineItemAction("Copy", VectorIcons.Copy)
|
||||||
object Redact : TimelineItemAction("Redact", io.element.android.libraries.designsystem.VectorIcons.Delete, destructive = true)
|
object Redact : TimelineItemAction("Redact", VectorIcons.Delete, destructive = true)
|
||||||
object Reply : TimelineItemAction("Reply", io.element.android.libraries.designsystem.VectorIcons.Reply)
|
object Reply : TimelineItemAction("Reply", VectorIcons.Reply)
|
||||||
object Edit : TimelineItemAction("Edit", io.element.android.libraries.designsystem.VectorIcons.Edit)
|
object Edit : TimelineItemAction("Edit", VectorIcons.Edit)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ package io.element.android.features.messages.textcomposer
|
||||||
|
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import io.element.android.libraries.designsystem.LocalIsDarkTheme
|
import io.element.android.libraries.designsystem.theme.ElementTheme
|
||||||
import io.element.android.libraries.textcomposer.TextComposer
|
import io.element.android.libraries.textcomposer.TextComposer
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
|
|
@ -51,7 +51,7 @@ fun MessageComposerView(
|
||||||
onComposerTextChange = ::onComposerTextChange,
|
onComposerTextChange = ::onComposerTextChange,
|
||||||
composerCanSendMessage = state.isSendButtonVisible,
|
composerCanSendMessage = state.isSendButtonVisible,
|
||||||
composerText = state.text?.charSequence?.toString(),
|
composerText = state.text?.charSequence?.toString(),
|
||||||
isInDarkMode = LocalIsDarkTheme.current,
|
isInDarkMode = !ElementTheme.colors.isLight,
|
||||||
modifier = modifier
|
modifier = modifier
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -39,11 +39,7 @@ import androidx.compose.foundation.lazy.rememberLazyListState
|
||||||
import androidx.compose.foundation.shape.CircleShape
|
import androidx.compose.foundation.shape.CircleShape
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.filled.ArrowDownward
|
import androidx.compose.material.icons.filled.ArrowDownward
|
||||||
import androidx.compose.material3.CircularProgressIndicator
|
|
||||||
import androidx.compose.material3.FloatingActionButton
|
|
||||||
import androidx.compose.material3.Icon
|
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.Text
|
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.runtime.derivedStateOf
|
import androidx.compose.runtime.derivedStateOf
|
||||||
|
|
@ -79,6 +75,12 @@ import io.element.android.features.messages.timeline.model.content.TimelineItemT
|
||||||
import io.element.android.features.messages.timeline.model.content.TimelineItemUnknownContent
|
import io.element.android.features.messages.timeline.model.content.TimelineItemUnknownContent
|
||||||
import io.element.android.libraries.designsystem.components.avatar.Avatar
|
import io.element.android.libraries.designsystem.components.avatar.Avatar
|
||||||
import io.element.android.libraries.designsystem.components.avatar.AvatarData
|
import io.element.android.libraries.designsystem.components.avatar.AvatarData
|
||||||
|
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
|
||||||
|
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
|
||||||
|
import io.element.android.libraries.designsystem.theme.components.CircularProgressIndicator
|
||||||
|
import io.element.android.libraries.designsystem.theme.components.FloatingActionButton
|
||||||
|
import io.element.android.libraries.designsystem.theme.components.Icon
|
||||||
|
import io.element.android.libraries.designsystem.theme.components.Text
|
||||||
import io.element.android.libraries.designsystem.utils.PairCombinedPreviewParameter
|
import io.element.android.libraries.designsystem.utils.PairCombinedPreviewParameter
|
||||||
import io.element.android.libraries.matrix.core.EventId
|
import io.element.android.libraries.matrix.core.EventId
|
||||||
import kotlinx.collections.immutable.ImmutableList
|
import kotlinx.collections.immutable.ImmutableList
|
||||||
|
|
@ -355,19 +357,26 @@ class MessagesItemGroupPositionToMessagesTimelineItemContentProvider :
|
||||||
TimelineItemGroupPositionProvider() to MessagesTimelineItemContentProvider()
|
TimelineItemGroupPositionProvider() to MessagesTimelineItemContentProvider()
|
||||||
)
|
)
|
||||||
|
|
||||||
@Suppress("PreviewPublic")
|
|
||||||
@Preview
|
@Preview
|
||||||
@Composable
|
@Composable
|
||||||
fun TimelineItemsPreview(
|
fun LoginRootScreenLightPreview(
|
||||||
@PreviewParameter(MessagesTimelineItemContentProvider::class)
|
@PreviewParameter(MessagesTimelineItemContentProvider::class) content: TimelineItemContent
|
||||||
content: TimelineItemContent
|
) = ElementPreviewLight { ContentToPreview(content) }
|
||||||
) {
|
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
fun LoginRootScreenDarkPreview(
|
||||||
|
@PreviewParameter(MessagesTimelineItemContentProvider::class) content: TimelineItemContent
|
||||||
|
) = ElementPreviewDark { ContentToPreview(content) }
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun ContentToPreview(content: TimelineItemContent) {
|
||||||
val timelineItems = persistentListOf(
|
val timelineItems = persistentListOf(
|
||||||
// 3 items (First Middle Last) with isMine = false
|
// 3 items (First Middle Last) with isMine = false
|
||||||
createMessageEvent(
|
createMessageEvent(
|
||||||
isMine = false,
|
isMine = false,
|
||||||
content = content,
|
content = content,
|
||||||
groupPosition = MessagesItemGroupPosition.First
|
groupPosition = MessagesItemGroupPosition.Last
|
||||||
),
|
),
|
||||||
createMessageEvent(
|
createMessageEvent(
|
||||||
isMine = false,
|
isMine = false,
|
||||||
|
|
@ -377,13 +386,13 @@ fun TimelineItemsPreview(
|
||||||
createMessageEvent(
|
createMessageEvent(
|
||||||
isMine = false,
|
isMine = false,
|
||||||
content = content,
|
content = content,
|
||||||
groupPosition = MessagesItemGroupPosition.Last
|
groupPosition = MessagesItemGroupPosition.First
|
||||||
),
|
),
|
||||||
// 3 items (First Middle Last) with isMine = true
|
// 3 items (First Middle Last) with isMine = true
|
||||||
createMessageEvent(
|
createMessageEvent(
|
||||||
isMine = true,
|
isMine = true,
|
||||||
content = content,
|
content = content,
|
||||||
groupPosition = MessagesItemGroupPosition.First
|
groupPosition = MessagesItemGroupPosition.Last
|
||||||
),
|
),
|
||||||
createMessageEvent(
|
createMessageEvent(
|
||||||
isMine = true,
|
isMine = true,
|
||||||
|
|
@ -393,7 +402,7 @@ fun TimelineItemsPreview(
|
||||||
createMessageEvent(
|
createMessageEvent(
|
||||||
isMine = true,
|
isMine = true,
|
||||||
content = content,
|
content = content,
|
||||||
groupPosition = MessagesItemGroupPosition.Last
|
groupPosition = MessagesItemGroupPosition.First
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
TimelineView(
|
TimelineView(
|
||||||
|
|
|
||||||
|
|
@ -23,20 +23,14 @@ import androidx.compose.foundation.layout.offset
|
||||||
import androidx.compose.foundation.layout.widthIn
|
import androidx.compose.foundation.layout.widthIn
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
import androidx.compose.material.ripple.rememberRipple
|
import androidx.compose.material.ripple.rememberRipple
|
||||||
import androidx.compose.material3.Surface
|
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.clip
|
import androidx.compose.ui.draw.clip
|
||||||
import androidx.compose.ui.graphics.Shape
|
import androidx.compose.ui.graphics.Shape
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import io.element.android.features.messages.timeline.model.MessagesItemGroupPosition
|
import io.element.android.features.messages.timeline.model.MessagesItemGroupPosition
|
||||||
import io.element.android.libraries.designsystem.LocalIsDarkTheme
|
import io.element.android.libraries.designsystem.theme.ElementTheme
|
||||||
import io.element.android.libraries.designsystem.MessageHighlightDark
|
import io.element.android.libraries.designsystem.theme.components.Surface
|
||||||
import io.element.android.libraries.designsystem.MessageHighlightLight
|
|
||||||
import io.element.android.libraries.designsystem.SystemGrey5Dark
|
|
||||||
import io.element.android.libraries.designsystem.SystemGrey5Light
|
|
||||||
import io.element.android.libraries.designsystem.SystemGrey6Dark
|
|
||||||
import io.element.android.libraries.designsystem.SystemGrey6Light
|
|
||||||
|
|
||||||
private val BUBBLE_RADIUS = 16.dp
|
private val BUBBLE_RADIUS = 16.dp
|
||||||
|
|
||||||
|
|
@ -88,24 +82,12 @@ fun MessageEventBubble(
|
||||||
}
|
}
|
||||||
|
|
||||||
val backgroundBubbleColor = if (isHighlighted) {
|
val backgroundBubbleColor = if (isHighlighted) {
|
||||||
if (LocalIsDarkTheme.current) {
|
ElementTheme.colors.messageHighlightedBackground
|
||||||
MessageHighlightDark
|
|
||||||
} else {
|
|
||||||
MessageHighlightLight
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
if (isMine) {
|
if (isMine) {
|
||||||
if (LocalIsDarkTheme.current) {
|
ElementTheme.colors.messageFromMeBackground
|
||||||
SystemGrey5Dark
|
|
||||||
} else {
|
|
||||||
SystemGrey5Light
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
if (LocalIsDarkTheme.current) {
|
ElementTheme.colors.messageFromOtherBackground
|
||||||
SystemGrey6Dark
|
|
||||||
} else {
|
|
||||||
SystemGrey6Light
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val bubbleShape = bubbleShape()
|
val bubbleShape = bubbleShape()
|
||||||
|
|
|
||||||
|
|
@ -14,11 +14,8 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@file:OptIn(ExperimentalFoundationApi::class)
|
|
||||||
|
|
||||||
package io.element.android.features.messages.timeline.components
|
package io.element.android.features.messages.timeline.components
|
||||||
|
|
||||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.aspectRatio
|
import androidx.compose.foundation.layout.aspectRatio
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
|
|
||||||
|
|
@ -20,16 +20,21 @@ import androidx.compose.foundation.layout.Row
|
||||||
import androidx.compose.foundation.layout.Spacer
|
import androidx.compose.foundation.layout.Spacer
|
||||||
import androidx.compose.foundation.layout.size
|
import androidx.compose.foundation.layout.size
|
||||||
import androidx.compose.foundation.layout.width
|
import androidx.compose.foundation.layout.width
|
||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.filled.Delete
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.Text
|
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.graphics.vector.ImageVector
|
import androidx.compose.ui.graphics.vector.ImageVector
|
||||||
import androidx.compose.ui.text.font.FontStyle
|
import androidx.compose.ui.text.font.FontStyle
|
||||||
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.unit.sp
|
import androidx.compose.ui.unit.sp
|
||||||
|
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
|
||||||
|
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
|
||||||
|
import io.element.android.libraries.designsystem.theme.components.Icon
|
||||||
|
import io.element.android.libraries.designsystem.theme.components.Text
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun TimelineItemInformativeView(
|
fun TimelineItemInformativeView(
|
||||||
|
|
@ -57,3 +62,20 @@ fun TimelineItemInformativeView(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
fun MatrixUserRowLightPreview() = ElementPreviewLight { ContentToPreview() }
|
||||||
|
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
fun MatrixUserRowDarkPreview() = ElementPreviewDark { ContentToPreview() }
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun ContentToPreview() {
|
||||||
|
TimelineItemInformativeView(
|
||||||
|
text = "Info",
|
||||||
|
iconDescription = "",
|
||||||
|
icon = Icons.Default.Delete
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -24,8 +24,6 @@ import androidx.compose.foundation.layout.width
|
||||||
import androidx.compose.foundation.shape.CornerSize
|
import androidx.compose.foundation.shape.CornerSize
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.Surface
|
|
||||||
import androidx.compose.material3.Text
|
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
|
@ -34,6 +32,8 @@ import androidx.compose.ui.unit.sp
|
||||||
import com.google.accompanist.flowlayout.FlowRow
|
import com.google.accompanist.flowlayout.FlowRow
|
||||||
import io.element.android.features.messages.timeline.model.AggregatedReaction
|
import io.element.android.features.messages.timeline.model.AggregatedReaction
|
||||||
import io.element.android.features.messages.timeline.model.TimelineItemReactions
|
import io.element.android.features.messages.timeline.model.TimelineItemReactions
|
||||||
|
import io.element.android.libraries.designsystem.theme.components.Surface
|
||||||
|
import io.element.android.libraries.designsystem.theme.components.Text
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun TimelineItemReactionsView(
|
fun TimelineItemReactionsView(
|
||||||
|
|
|
||||||
|
|
@ -28,8 +28,6 @@ import androidx.compose.foundation.text.appendInlineContent
|
||||||
import androidx.compose.material3.ColorScheme
|
import androidx.compose.material3.ColorScheme
|
||||||
import androidx.compose.material3.LocalTextStyle
|
import androidx.compose.material3.LocalTextStyle
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.Surface
|
|
||||||
import androidx.compose.material3.Text
|
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.drawBehind
|
import androidx.compose.ui.draw.drawBehind
|
||||||
|
|
@ -49,6 +47,8 @@ import androidx.compose.ui.unit.sp
|
||||||
import com.google.accompanist.flowlayout.FlowRow
|
import com.google.accompanist.flowlayout.FlowRow
|
||||||
import io.element.android.libraries.designsystem.LinkColor
|
import io.element.android.libraries.designsystem.LinkColor
|
||||||
import io.element.android.libraries.designsystem.components.ClickableLinkText
|
import io.element.android.libraries.designsystem.components.ClickableLinkText
|
||||||
|
import io.element.android.libraries.designsystem.theme.components.Surface
|
||||||
|
import io.element.android.libraries.designsystem.theme.components.Text
|
||||||
import io.element.android.libraries.matrix.permalink.PermalinkData
|
import io.element.android.libraries.matrix.permalink.PermalinkData
|
||||||
import io.element.android.libraries.matrix.permalink.PermalinkParser
|
import io.element.android.libraries.matrix.permalink.PermalinkParser
|
||||||
import kotlinx.collections.immutable.persistentMapOf
|
import kotlinx.collections.immutable.persistentMapOf
|
||||||
|
|
|
||||||
|
|
@ -14,8 +14,6 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@file:OptIn(ExperimentalMaterial3Api::class)
|
|
||||||
|
|
||||||
package io.element.android.features.onboarding
|
package io.element.android.features.onboarding
|
||||||
|
|
||||||
import androidx.compose.foundation.Image
|
import androidx.compose.foundation.Image
|
||||||
|
|
@ -26,10 +24,6 @@ import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.layout.size
|
import androidx.compose.foundation.layout.size
|
||||||
import androidx.compose.foundation.layout.systemBarsPadding
|
import androidx.compose.foundation.layout.systemBarsPadding
|
||||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
|
||||||
import androidx.compose.material3.MaterialTheme
|
|
||||||
import androidx.compose.material3.Surface
|
|
||||||
import androidx.compose.material3.Text
|
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
|
|
@ -49,7 +43,8 @@ import com.google.accompanist.pager.ExperimentalPagerApi
|
||||||
import com.google.accompanist.pager.HorizontalPager
|
import com.google.accompanist.pager.HorizontalPager
|
||||||
import com.google.accompanist.pager.HorizontalPagerIndicator
|
import com.google.accompanist.pager.HorizontalPagerIndicator
|
||||||
import com.google.accompanist.pager.rememberPagerState
|
import com.google.accompanist.pager.rememberPagerState
|
||||||
import io.element.android.libraries.designsystem.components.VectorButton
|
import io.element.android.libraries.designsystem.theme.components.Button
|
||||||
|
import io.element.android.libraries.designsystem.theme.components.Text
|
||||||
import io.element.android.libraries.testtags.TestTags
|
import io.element.android.libraries.testtags.TestTags
|
||||||
import io.element.android.libraries.testtags.testTag
|
import io.element.android.libraries.testtags.testTag
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
|
|
@ -67,71 +62,55 @@ fun OnBoardingScreen(
|
||||||
val carrouselState = remember { SplashCarouselStateFactory().create() }
|
val carrouselState = remember { SplashCarouselStateFactory().create() }
|
||||||
val nbOfPages = carrouselState.items.size
|
val nbOfPages = carrouselState.items.size
|
||||||
var key by remember { mutableStateOf(false) }
|
var key by remember { mutableStateOf(false) }
|
||||||
Surface(
|
Box(
|
||||||
modifier = modifier,
|
modifier = modifier
|
||||||
color = MaterialTheme.colorScheme.background,
|
.fillMaxSize()
|
||||||
|
.systemBarsPadding()
|
||||||
|
.padding(vertical = 16.dp)
|
||||||
) {
|
) {
|
||||||
Box(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier.fillMaxSize(),
|
||||||
.fillMaxSize()
|
|
||||||
.systemBarsPadding()
|
|
||||||
.padding(vertical = 16.dp)
|
|
||||||
) {
|
) {
|
||||||
Column(
|
val pagerState = rememberPagerState()
|
||||||
modifier = Modifier.fillMaxSize(),
|
LaunchedEffect(key) {
|
||||||
|
launch {
|
||||||
|
delay(3_000)
|
||||||
|
pagerState.animateScrollToPage((pagerState.currentPage + 1) % nbOfPages)
|
||||||
|
// https://stackoverflow.com/questions/73714228/accompanist-pager-animatescrolltopage-doesnt-scroll-to-next-page-correctly
|
||||||
|
key = !key
|
||||||
|
}
|
||||||
|
}
|
||||||
|
LaunchedEffect(pagerState) {
|
||||||
|
// Collect from the pager state a snapshotFlow reading the currentPage
|
||||||
|
snapshotFlow { pagerState.currentPage }.collect { page ->
|
||||||
|
onPageChanged(page)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
HorizontalPager(
|
||||||
|
modifier = Modifier.weight(1f),
|
||||||
|
count = nbOfPages,
|
||||||
|
state = pagerState,
|
||||||
|
) { page ->
|
||||||
|
// Our page content
|
||||||
|
OnBoardingPage(carrouselState.items[page])
|
||||||
|
}
|
||||||
|
HorizontalPagerIndicator(
|
||||||
|
pagerState = pagerState,
|
||||||
|
modifier = Modifier
|
||||||
|
.align(CenterHorizontally)
|
||||||
|
.padding(16.dp),
|
||||||
|
)
|
||||||
|
Button(
|
||||||
|
onClick = {
|
||||||
|
onSignIn()
|
||||||
|
},
|
||||||
|
enabled = true,
|
||||||
|
modifier = Modifier
|
||||||
|
.align(CenterHorizontally)
|
||||||
|
.testTag(TestTags.onBoardingSignIn)
|
||||||
|
.padding(top = 16.dp)
|
||||||
) {
|
) {
|
||||||
val pagerState = rememberPagerState()
|
Text(text = stringResource(id = StringR.string.login_splash_submit))
|
||||||
LaunchedEffect(key) {
|
|
||||||
launch {
|
|
||||||
delay(3_000)
|
|
||||||
pagerState.animateScrollToPage((pagerState.currentPage + 1) % nbOfPages)
|
|
||||||
// https://stackoverflow.com/questions/73714228/accompanist-pager-animatescrolltopage-doesnt-scroll-to-next-page-correctly
|
|
||||||
key = !key
|
|
||||||
}
|
|
||||||
}
|
|
||||||
LaunchedEffect(pagerState) {
|
|
||||||
// Collect from the pager state a snapshotFlow reading the currentPage
|
|
||||||
snapshotFlow { pagerState.currentPage }.collect { page ->
|
|
||||||
onPageChanged(page)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
HorizontalPager(
|
|
||||||
modifier = Modifier.weight(1f),
|
|
||||||
count = nbOfPages,
|
|
||||||
state = pagerState,
|
|
||||||
) { page ->
|
|
||||||
// Our page content
|
|
||||||
OnBoardingPage(carrouselState.items[page])
|
|
||||||
}
|
|
||||||
HorizontalPagerIndicator(
|
|
||||||
pagerState = pagerState,
|
|
||||||
modifier = Modifier
|
|
||||||
.align(CenterHorizontally)
|
|
||||||
.padding(16.dp),
|
|
||||||
)
|
|
||||||
/*
|
|
||||||
VectorButton(
|
|
||||||
text = "CREATE ACCOUNT",
|
|
||||||
onClick = {
|
|
||||||
onSignUp()
|
|
||||||
},
|
|
||||||
enabled = true,
|
|
||||||
modifier = Modifier
|
|
||||||
.align(CenterHorizontally)
|
|
||||||
.padding(top = 16.dp)
|
|
||||||
)
|
|
||||||
*/
|
|
||||||
VectorButton(
|
|
||||||
text = stringResource(id = StringR.string.login_splash_submit),
|
|
||||||
onClick = {
|
|
||||||
onSignIn()
|
|
||||||
},
|
|
||||||
enabled = true,
|
|
||||||
modifier = Modifier
|
|
||||||
.align(CenterHorizontally)
|
|
||||||
.testTag(TestTags.onBoardingSignIn)
|
|
||||||
.padding(top = 16.dp)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,8 @@ import io.element.android.features.rageshake.preferences.RageshakePreferencesSta
|
||||||
import io.element.android.features.rageshake.preferences.RageshakePreferencesView
|
import io.element.android.features.rageshake.preferences.RageshakePreferencesView
|
||||||
import io.element.android.libraries.architecture.Async
|
import io.element.android.libraries.architecture.Async
|
||||||
import io.element.android.libraries.designsystem.components.preferences.PreferenceView
|
import io.element.android.libraries.designsystem.components.preferences.PreferenceView
|
||||||
|
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
|
||||||
|
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
|
||||||
import io.element.android.libraries.ui.strings.R as StringR
|
import io.element.android.libraries.ui.strings.R as StringR
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
|
|
@ -56,7 +58,14 @@ fun PreferencesRootView(
|
||||||
|
|
||||||
@Preview
|
@Preview
|
||||||
@Composable
|
@Composable
|
||||||
fun PreferencesContentPreview() {
|
fun PreferencesRootViewLightPreview() = ElementPreviewLight { ContentToPreview() }
|
||||||
|
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
fun PreferencesRootViewDarkPreview() = ElementPreviewDark { ContentToPreview() }
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun ContentToPreview() {
|
||||||
val state = PreferencesRootState(
|
val state = PreferencesRootState(
|
||||||
logoutState = LogoutPreferenceState(),
|
logoutState = LogoutPreferenceState(),
|
||||||
rageshakeState = RageshakePreferencesState(),
|
rageshakeState = RageshakePreferencesState(),
|
||||||
|
|
|
||||||
|
|
@ -26,13 +26,7 @@ import androidx.compose.foundation.layout.systemBarsPadding
|
||||||
import androidx.compose.foundation.rememberScrollState
|
import androidx.compose.foundation.rememberScrollState
|
||||||
import androidx.compose.foundation.text.KeyboardOptions
|
import androidx.compose.foundation.text.KeyboardOptions
|
||||||
import androidx.compose.foundation.verticalScroll
|
import androidx.compose.foundation.verticalScroll
|
||||||
import androidx.compose.material3.Button
|
|
||||||
import androidx.compose.material3.CircularProgressIndicator
|
|
||||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.OutlinedTextField
|
|
||||||
import androidx.compose.material3.Surface
|
|
||||||
import androidx.compose.material3.Text
|
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
|
|
@ -54,10 +48,15 @@ import io.element.android.libraries.architecture.Async
|
||||||
import io.element.android.libraries.designsystem.components.LabelledCheckbox
|
import io.element.android.libraries.designsystem.components.LabelledCheckbox
|
||||||
import io.element.android.libraries.designsystem.components.dialogs.ErrorDialog
|
import io.element.android.libraries.designsystem.components.dialogs.ErrorDialog
|
||||||
import io.element.android.libraries.designsystem.components.form.textFieldState
|
import io.element.android.libraries.designsystem.components.form.textFieldState
|
||||||
|
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
|
||||||
|
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
|
||||||
|
import io.element.android.libraries.designsystem.theme.components.Button
|
||||||
|
import io.element.android.libraries.designsystem.theme.components.CircularProgressIndicator
|
||||||
|
import io.element.android.libraries.designsystem.theme.components.OutlinedTextField
|
||||||
|
import io.element.android.libraries.designsystem.theme.components.Text
|
||||||
import io.element.android.libraries.designsystem.utils.LogCompositions
|
import io.element.android.libraries.designsystem.utils.LogCompositions
|
||||||
import io.element.android.libraries.ui.strings.R as StringR
|
import io.element.android.libraries.ui.strings.R as StringR
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterial3Api::class)
|
|
||||||
@Composable
|
@Composable
|
||||||
fun BugReportView(
|
fun BugReportView(
|
||||||
state: BugReportState,
|
state: BugReportState,
|
||||||
|
|
@ -73,147 +72,151 @@ fun BugReportView(
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
Surface(
|
Box(
|
||||||
modifier = modifier,
|
modifier = modifier
|
||||||
color = MaterialTheme.colorScheme.background,
|
.fillMaxSize()
|
||||||
|
.systemBarsPadding()
|
||||||
|
.imePadding()
|
||||||
) {
|
) {
|
||||||
Box(
|
val scrollState = rememberScrollState()
|
||||||
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxSize()
|
.verticalScroll(
|
||||||
.systemBarsPadding()
|
state = scrollState,
|
||||||
.imePadding()
|
)
|
||||||
|
.padding(horizontal = 16.dp),
|
||||||
) {
|
) {
|
||||||
val scrollState = rememberScrollState()
|
val isError = state.sending is Async.Failure
|
||||||
Column(
|
val isFormEnabled = state.sending !is Async.Loading
|
||||||
|
// Title
|
||||||
|
Text(
|
||||||
|
text = stringResource(id = StringR.string.send_bug_report),
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.verticalScroll(
|
.fillMaxWidth()
|
||||||
state = scrollState,
|
.padding(horizontal = 16.dp, vertical = 16.dp),
|
||||||
)
|
textAlign = TextAlign.Center,
|
||||||
.padding(horizontal = 16.dp),
|
fontWeight = FontWeight.Bold,
|
||||||
|
fontSize = 24.sp,
|
||||||
|
color = MaterialTheme.colorScheme.primary,
|
||||||
|
)
|
||||||
|
// Form
|
||||||
|
Text(
|
||||||
|
text = stringResource(id = StringR.string.send_bug_report_description),
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(horizontal = 16.dp, vertical = 16.dp),
|
||||||
|
fontSize = 16.sp,
|
||||||
|
color = MaterialTheme.colorScheme.primary,
|
||||||
|
)
|
||||||
|
var descriptionFieldState by textFieldState(
|
||||||
|
stateValue = state.formState.description
|
||||||
|
)
|
||||||
|
Column(
|
||||||
|
// modifier = Modifier.weight(1f),
|
||||||
) {
|
) {
|
||||||
val isError = state.sending is Async.Failure
|
OutlinedTextField(
|
||||||
val isFormEnabled = state.sending !is Async.Loading
|
value = descriptionFieldState,
|
||||||
// Title
|
|
||||||
Text(
|
|
||||||
text = stringResource(id = StringR.string.send_bug_report),
|
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.padding(horizontal = 16.dp, vertical = 16.dp),
|
.padding(top = 16.dp),
|
||||||
textAlign = TextAlign.Center,
|
|
||||||
fontWeight = FontWeight.Bold,
|
|
||||||
fontSize = 24.sp,
|
|
||||||
)
|
|
||||||
// Form
|
|
||||||
Text(
|
|
||||||
text = stringResource(id = StringR.string.send_bug_report_description),
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxWidth()
|
|
||||||
.padding(horizontal = 16.dp, vertical = 16.dp),
|
|
||||||
fontSize = 16.sp,
|
|
||||||
)
|
|
||||||
var descriptionFieldState by textFieldState(
|
|
||||||
stateValue = state.formState.description
|
|
||||||
)
|
|
||||||
Column(
|
|
||||||
// modifier = Modifier.weight(1f),
|
|
||||||
) {
|
|
||||||
OutlinedTextField(
|
|
||||||
value = descriptionFieldState,
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxWidth()
|
|
||||||
.padding(top = 16.dp),
|
|
||||||
enabled = isFormEnabled,
|
|
||||||
label = {
|
|
||||||
Text(text = stringResource(id = StringR.string.send_bug_report_placeholder))
|
|
||||||
},
|
|
||||||
supportingText = {
|
|
||||||
Text(text = stringResource(id = StringR.string.send_bug_report_description_in_english))
|
|
||||||
},
|
|
||||||
onValueChange = {
|
|
||||||
descriptionFieldState = it
|
|
||||||
eventSink(BugReportEvents.SetDescription(it))
|
|
||||||
},
|
|
||||||
keyboardOptions = KeyboardOptions(
|
|
||||||
keyboardType = KeyboardType.Text,
|
|
||||||
imeAction = ImeAction.Next
|
|
||||||
),
|
|
||||||
// TODO Error text too short
|
|
||||||
)
|
|
||||||
}
|
|
||||||
LabelledCheckbox(
|
|
||||||
checked = state.formState.sendLogs,
|
|
||||||
onCheckedChange = { eventSink(BugReportEvents.SetSendLog(it)) },
|
|
||||||
enabled = isFormEnabled,
|
enabled = isFormEnabled,
|
||||||
text = stringResource(id = StringR.string.send_bug_report_include_logs)
|
label = {
|
||||||
|
Text(text = stringResource(id = StringR.string.send_bug_report_placeholder))
|
||||||
|
},
|
||||||
|
supportingText = {
|
||||||
|
Text(text = stringResource(id = StringR.string.send_bug_report_description_in_english))
|
||||||
|
},
|
||||||
|
onValueChange = {
|
||||||
|
descriptionFieldState = it
|
||||||
|
eventSink(BugReportEvents.SetDescription(it))
|
||||||
|
},
|
||||||
|
keyboardOptions = KeyboardOptions(
|
||||||
|
keyboardType = KeyboardType.Text,
|
||||||
|
imeAction = ImeAction.Next
|
||||||
|
),
|
||||||
|
// TODO Error text too short
|
||||||
)
|
)
|
||||||
if (state.hasCrashLogs) {
|
}
|
||||||
LabelledCheckbox(
|
LabelledCheckbox(
|
||||||
checked = state.formState.sendCrashLogs,
|
checked = state.formState.sendLogs,
|
||||||
onCheckedChange = { eventSink(BugReportEvents.SetSendCrashLog(it)) },
|
onCheckedChange = { eventSink(BugReportEvents.SetSendLog(it)) },
|
||||||
enabled = isFormEnabled,
|
enabled = isFormEnabled,
|
||||||
text = stringResource(id = StringR.string.send_bug_report_include_crash_logs)
|
text = stringResource(id = StringR.string.send_bug_report_include_logs)
|
||||||
)
|
)
|
||||||
}
|
if (state.hasCrashLogs) {
|
||||||
LabelledCheckbox(
|
LabelledCheckbox(
|
||||||
checked = state.formState.canContact,
|
checked = state.formState.sendCrashLogs,
|
||||||
onCheckedChange = { eventSink(BugReportEvents.SetCanContact(it)) },
|
onCheckedChange = { eventSink(BugReportEvents.SetSendCrashLog(it)) },
|
||||||
enabled = isFormEnabled,
|
enabled = isFormEnabled,
|
||||||
text = stringResource(id = StringR.string.you_may_contact_me)
|
text = stringResource(id = StringR.string.send_bug_report_include_crash_logs)
|
||||||
)
|
)
|
||||||
if (state.screenshotUri != null) {
|
}
|
||||||
LabelledCheckbox(
|
LabelledCheckbox(
|
||||||
checked = state.formState.sendScreenshot,
|
checked = state.formState.canContact,
|
||||||
onCheckedChange = { eventSink(BugReportEvents.SetSendScreenshot(it)) },
|
onCheckedChange = { eventSink(BugReportEvents.SetCanContact(it)) },
|
||||||
enabled = isFormEnabled,
|
enabled = isFormEnabled,
|
||||||
text = stringResource(id = StringR.string.send_bug_report_include_screenshot)
|
text = stringResource(id = StringR.string.you_may_contact_me)
|
||||||
)
|
)
|
||||||
if (state.formState.sendScreenshot) {
|
if (state.screenshotUri != null) {
|
||||||
Box(
|
LabelledCheckbox(
|
||||||
modifier = Modifier.fillMaxWidth(),
|
checked = state.formState.sendScreenshot,
|
||||||
contentAlignment = Alignment.Center
|
onCheckedChange = { eventSink(BugReportEvents.SetSendScreenshot(it)) },
|
||||||
) {
|
enabled = isFormEnabled,
|
||||||
val context = LocalContext.current
|
text = stringResource(id = StringR.string.send_bug_report_include_screenshot)
|
||||||
val model = ImageRequest.Builder(context)
|
)
|
||||||
.data(state.screenshotUri)
|
if (state.formState.sendScreenshot) {
|
||||||
.build()
|
Box(
|
||||||
AsyncImage(
|
modifier = Modifier.fillMaxWidth(),
|
||||||
modifier = Modifier.fillMaxWidth(fraction = 0.5f),
|
contentAlignment = Alignment.Center
|
||||||
model = model,
|
) {
|
||||||
contentDescription = null
|
val context = LocalContext.current
|
||||||
)
|
val model = ImageRequest.Builder(context)
|
||||||
}
|
.data(state.screenshotUri)
|
||||||
|
.build()
|
||||||
|
AsyncImage(
|
||||||
|
modifier = Modifier.fillMaxWidth(fraction = 0.5f),
|
||||||
|
model = model,
|
||||||
|
contentDescription = null
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Submit
|
|
||||||
Button(
|
|
||||||
onClick = { eventSink(BugReportEvents.SendBugReport) },
|
|
||||||
enabled = state.submitEnabled,
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxWidth()
|
|
||||||
.padding(vertical = 32.dp)
|
|
||||||
) {
|
|
||||||
Text(text = stringResource(id = StringR.string.action_send))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
when (state.sending) {
|
// Submit
|
||||||
is Async.Loading -> {
|
Button(
|
||||||
CircularProgressIndicator(
|
onClick = { eventSink(BugReportEvents.SendBugReport) },
|
||||||
progress = state.sendingProgress,
|
enabled = state.submitEnabled,
|
||||||
modifier = Modifier.align(Alignment.Center)
|
modifier = Modifier
|
||||||
)
|
.fillMaxWidth()
|
||||||
}
|
.padding(vertical = 32.dp)
|
||||||
is Async.Failure -> ErrorDialog(
|
) {
|
||||||
content = state.sending.error.toString(),
|
Text(text = stringResource(id = StringR.string.action_send))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
when (state.sending) {
|
||||||
|
is Async.Loading -> {
|
||||||
|
CircularProgressIndicator(
|
||||||
|
progress = state.sendingProgress,
|
||||||
|
modifier = Modifier.align(Alignment.Center)
|
||||||
)
|
)
|
||||||
else -> Unit
|
|
||||||
}
|
}
|
||||||
|
is Async.Failure -> ErrorDialog(
|
||||||
|
content = state.sending.error.toString(),
|
||||||
|
)
|
||||||
|
else -> Unit
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
|
||||||
@Preview
|
@Preview
|
||||||
fun BugReportContentPreview() {
|
@Composable
|
||||||
|
fun BugReportViewLightPreview() = ElementPreviewLight { ContentToPreview() }
|
||||||
|
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
fun BugReportViewDarkPreview() = ElementPreviewDark { ContentToPreview() }
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun ContentToPreview() {
|
||||||
BugReportView(
|
BugReportView(
|
||||||
state = BugReportState(),
|
state = BugReportState(),
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,8 @@ import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.tooling.preview.Preview
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
import io.element.android.libraries.designsystem.components.dialogs.ConfirmationDialog
|
import io.element.android.libraries.designsystem.components.dialogs.ConfirmationDialog
|
||||||
|
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
|
||||||
|
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
|
||||||
import io.element.android.libraries.designsystem.utils.LogCompositions
|
import io.element.android.libraries.designsystem.utils.LogCompositions
|
||||||
import io.element.android.libraries.ui.strings.R as StringR
|
import io.element.android.libraries.ui.strings.R as StringR
|
||||||
|
|
||||||
|
|
@ -67,7 +69,14 @@ fun CrashDetectionContent(
|
||||||
|
|
||||||
@Preview
|
@Preview
|
||||||
@Composable
|
@Composable
|
||||||
fun CrashDetectionContentPreview() {
|
fun CrashDetectionContentLightPreview() = ElementPreviewLight { ContentToPreview() }
|
||||||
|
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
fun CrashDetectionContentDarkPreview() = ElementPreviewDark { ContentToPreview() }
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun ContentToPreview() {
|
||||||
CrashDetectionContent(
|
CrashDetectionContent(
|
||||||
state = CrashDetectionState()
|
state = CrashDetectionState()
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,8 @@ import io.element.android.features.rageshake.screenshot.ImageResult
|
||||||
import io.element.android.features.rageshake.screenshot.screenshot
|
import io.element.android.features.rageshake.screenshot.screenshot
|
||||||
import io.element.android.libraries.androidutils.hardware.vibrate
|
import io.element.android.libraries.androidutils.hardware.vibrate
|
||||||
import io.element.android.libraries.designsystem.components.dialogs.ConfirmationDialog
|
import io.element.android.libraries.designsystem.components.dialogs.ConfirmationDialog
|
||||||
|
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
|
||||||
|
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
|
||||||
import io.element.android.libraries.designsystem.utils.LogCompositions
|
import io.element.android.libraries.designsystem.utils.LogCompositions
|
||||||
import io.element.android.libraries.designsystem.utils.OnLifecycleEvent
|
import io.element.android.libraries.designsystem.utils.OnLifecycleEvent
|
||||||
import io.element.android.libraries.ui.strings.R as StringR
|
import io.element.android.libraries.ui.strings.R as StringR
|
||||||
|
|
@ -99,6 +101,13 @@ fun RageshakeDialogContent(
|
||||||
|
|
||||||
@Preview
|
@Preview
|
||||||
@Composable
|
@Composable
|
||||||
fun RageshakeDialogContentPreview() {
|
fun RageshakeDialogContentLightPreview() = ElementPreviewLight { ContentToPreview() }
|
||||||
|
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
fun RageshakeDialogContentDarkPreview() = ElementPreviewDark { ContentToPreview() }
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun ContentToPreview() {
|
||||||
RageshakeDialogContent()
|
RageshakeDialogContent()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,8 @@ import io.element.android.libraries.designsystem.components.preferences.Preferen
|
||||||
import io.element.android.libraries.designsystem.components.preferences.PreferenceSlide
|
import io.element.android.libraries.designsystem.components.preferences.PreferenceSlide
|
||||||
import io.element.android.libraries.designsystem.components.preferences.PreferenceSwitch
|
import io.element.android.libraries.designsystem.components.preferences.PreferenceSwitch
|
||||||
import io.element.android.libraries.designsystem.components.preferences.PreferenceText
|
import io.element.android.libraries.designsystem.components.preferences.PreferenceText
|
||||||
|
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
|
||||||
|
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
|
||||||
import io.element.android.libraries.ui.strings.R as StringR
|
import io.element.android.libraries.ui.strings.R as StringR
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
|
|
@ -73,14 +75,28 @@ fun RageshakePreferencesView(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
|
||||||
@Preview
|
@Preview
|
||||||
fun RageshakePreferencesViewPreview() {
|
@Composable
|
||||||
|
fun RageshakePreferencesViewLightPreview() = ElementPreviewLight { ContentToPreview() }
|
||||||
|
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
fun RageshakePreferencesViewDarkPreview() = ElementPreviewDark { ContentToPreview() }
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun ContentToPreview() {
|
||||||
RageshakePreferencesView(RageshakePreferencesState(isEnabled = true, isSupported = true, sensitivity = 0.5f))
|
RageshakePreferencesView(RageshakePreferencesState(isEnabled = true, isSupported = true, sensitivity = 0.5f))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
|
||||||
@Preview
|
@Preview
|
||||||
fun RageshakePreferenceNotSupportedPreview() {
|
@Composable
|
||||||
|
fun RageshakePreferencesViewNotSupportedLightPreview() = ElementPreviewLight { ContentNotSupportedToPreview() }
|
||||||
|
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
fun RageshakePreferencesViewNotSupportedDarkPreview() = ElementPreviewDark { ContentNotSupportedToPreview() }
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun ContentNotSupportedToPreview() {
|
||||||
RageshakePreferencesView(RageshakePreferencesState(isEnabled = true, isSupported = false, sensitivity = 0.5f))
|
RageshakePreferencesView(RageshakePreferencesState(isEnabled = true, isSupported = false, sensitivity = 0.5f))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,8 +14,6 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@file:OptIn(ExperimentalMaterial3Api::class)
|
|
||||||
|
|
||||||
package io.element.android.features.roomlist
|
package io.element.android.features.roomlist
|
||||||
|
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
|
|
@ -24,7 +22,6 @@ import androidx.compose.foundation.lazy.LazyColumn
|
||||||
import androidx.compose.foundation.lazy.items
|
import androidx.compose.foundation.lazy.items
|
||||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
import androidx.compose.material3.Scaffold
|
|
||||||
import androidx.compose.material3.TopAppBarDefaults
|
import androidx.compose.material3.TopAppBarDefaults
|
||||||
import androidx.compose.material3.rememberTopAppBarState
|
import androidx.compose.material3.rememberTopAppBarState
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
|
@ -43,6 +40,9 @@ import io.element.android.features.roomlist.model.RoomListRoomSummary
|
||||||
import io.element.android.features.roomlist.model.RoomListState
|
import io.element.android.features.roomlist.model.RoomListState
|
||||||
import io.element.android.features.roomlist.model.stubbedRoomSummaries
|
import io.element.android.features.roomlist.model.stubbedRoomSummaries
|
||||||
import io.element.android.libraries.designsystem.components.avatar.AvatarData
|
import io.element.android.libraries.designsystem.components.avatar.AvatarData
|
||||||
|
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
|
||||||
|
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
|
||||||
|
import io.element.android.libraries.designsystem.theme.components.Scaffold
|
||||||
import io.element.android.libraries.designsystem.utils.LogCompositions
|
import io.element.android.libraries.designsystem.utils.LogCompositions
|
||||||
import io.element.android.libraries.matrix.core.RoomId
|
import io.element.android.libraries.matrix.core.RoomId
|
||||||
import io.element.android.libraries.matrix.core.UserId
|
import io.element.android.libraries.matrix.core.UserId
|
||||||
|
|
@ -76,6 +76,7 @@ fun RoomListView(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun RoomListView(
|
fun RoomListView(
|
||||||
roomSummaries: ImmutableList<RoomListRoomSummary>,
|
roomSummaries: ImmutableList<RoomListRoomSummary>,
|
||||||
|
|
@ -125,11 +126,15 @@ fun RoomListView(
|
||||||
filter = filter,
|
filter = filter,
|
||||||
onFilterChanged = onFilterChanged,
|
onFilterChanged = onFilterChanged,
|
||||||
onOpenSettings = onOpenSettings,
|
onOpenSettings = onOpenSettings,
|
||||||
scrollBehavior = scrollBehavior
|
scrollBehavior = scrollBehavior,
|
||||||
|
modifier = Modifier,
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
content = { padding ->
|
content = { padding ->
|
||||||
Column(modifier = Modifier.padding(padding)) {
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(padding)
|
||||||
|
) {
|
||||||
LazyColumn(
|
LazyColumn(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.weight(1f)
|
.weight(1f)
|
||||||
|
|
@ -152,7 +157,14 @@ private fun RoomListRoomSummary.contentType() = isPlaceholder
|
||||||
|
|
||||||
@Preview
|
@Preview
|
||||||
@Composable
|
@Composable
|
||||||
fun RoomListViewPreview() {
|
fun RoomListViewLightPreview() = ElementPreviewLight { ContentToPreview() }
|
||||||
|
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
fun RoomListViewDarkPreview() = ElementPreviewDark { ContentToPreview() }
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun ContentToPreview() {
|
||||||
RoomListView(
|
RoomListView(
|
||||||
roomSummaries = stubbedRoomSummaries(),
|
roomSummaries = stubbedRoomSummaries(),
|
||||||
matrixUser = MatrixUser(id = UserId("@id"), username = "User#1", avatarData = AvatarData("U")),
|
matrixUser = MatrixUser(id = UserId("@id"), username = "User#1", avatarData = AvatarData("U")),
|
||||||
|
|
|
||||||
|
|
@ -27,14 +27,7 @@ import androidx.compose.material.icons.filled.Close
|
||||||
import androidx.compose.material.icons.filled.Search
|
import androidx.compose.material.icons.filled.Search
|
||||||
import androidx.compose.material.icons.filled.Settings
|
import androidx.compose.material.icons.filled.Settings
|
||||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
import androidx.compose.material3.Icon
|
|
||||||
import androidx.compose.material3.IconButton
|
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.MediumTopAppBar
|
|
||||||
import androidx.compose.material3.Text
|
|
||||||
import androidx.compose.material3.TextField
|
|
||||||
import androidx.compose.material3.TextFieldDefaults
|
|
||||||
import androidx.compose.material3.TopAppBar
|
|
||||||
import androidx.compose.material3.TopAppBarScrollBehavior
|
import androidx.compose.material3.TopAppBarScrollBehavior
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
|
|
@ -46,7 +39,6 @@ import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.focus.FocusRequester
|
import androidx.compose.ui.focus.FocusRequester
|
||||||
import androidx.compose.ui.focus.focusRequester
|
import androidx.compose.ui.focus.focusRequester
|
||||||
import androidx.compose.ui.graphics.Color
|
|
||||||
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.text.TextStyle
|
import androidx.compose.ui.text.TextStyle
|
||||||
|
|
@ -54,6 +46,12 @@ import androidx.compose.ui.text.font.FontWeight
|
||||||
import androidx.compose.ui.unit.sp
|
import androidx.compose.ui.unit.sp
|
||||||
import io.element.android.libraries.designsystem.components.avatar.Avatar
|
import io.element.android.libraries.designsystem.components.avatar.Avatar
|
||||||
import io.element.android.libraries.designsystem.components.form.textFieldState
|
import io.element.android.libraries.designsystem.components.form.textFieldState
|
||||||
|
import io.element.android.libraries.designsystem.theme.components.Icon
|
||||||
|
import io.element.android.libraries.designsystem.theme.components.IconButton
|
||||||
|
import io.element.android.libraries.designsystem.theme.components.MediumTopAppBar
|
||||||
|
import io.element.android.libraries.designsystem.theme.components.Text
|
||||||
|
import io.element.android.libraries.designsystem.theme.components.TextField
|
||||||
|
import io.element.android.libraries.designsystem.theme.components.TopAppBar
|
||||||
import io.element.android.libraries.designsystem.utils.LogCompositions
|
import io.element.android.libraries.designsystem.utils.LogCompositions
|
||||||
import io.element.android.libraries.matrix.ui.model.MatrixUser
|
import io.element.android.libraries.matrix.ui.model.MatrixUser
|
||||||
import io.element.android.libraries.ui.strings.R as StringR
|
import io.element.android.libraries.ui.strings.R as StringR
|
||||||
|
|
@ -64,7 +62,8 @@ fun RoomListTopBar(
|
||||||
filter: String,
|
filter: String,
|
||||||
onFilterChanged: (String) -> Unit,
|
onFilterChanged: (String) -> Unit,
|
||||||
onOpenSettings: () -> Unit,
|
onOpenSettings: () -> Unit,
|
||||||
scrollBehavior: TopAppBarScrollBehavior
|
scrollBehavior: TopAppBarScrollBehavior,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
) {
|
) {
|
||||||
LogCompositions(
|
LogCompositions(
|
||||||
tag = "RoomListScreen",
|
tag = "RoomListScreen",
|
||||||
|
|
@ -87,6 +86,7 @@ fun RoomListTopBar(
|
||||||
onFilterChanged = onFilterChanged,
|
onFilterChanged = onFilterChanged,
|
||||||
onCloseClicked = ::closeFilter,
|
onCloseClicked = ::closeFilter,
|
||||||
scrollBehavior = scrollBehavior,
|
scrollBehavior = scrollBehavior,
|
||||||
|
modifier = modifier,
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
DefaultRoomListTopBar(
|
DefaultRoomListTopBar(
|
||||||
|
|
@ -96,6 +96,7 @@ fun RoomListTopBar(
|
||||||
searchWidgetStateIsOpened = true
|
searchWidgetStateIsOpened = true
|
||||||
},
|
},
|
||||||
scrollBehavior = scrollBehavior,
|
scrollBehavior = scrollBehavior,
|
||||||
|
modifier = modifier,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -148,14 +149,6 @@ fun SearchRoomListTopBar(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
colors = TextFieldDefaults.textFieldColors(
|
|
||||||
textColor = MaterialTheme.colorScheme.onBackground,
|
|
||||||
containerColor = Color.Transparent,
|
|
||||||
cursorColor = MaterialTheme.colorScheme.onBackground.copy(alpha = ContentAlpha.medium),
|
|
||||||
focusedIndicatorColor = Color.Transparent,
|
|
||||||
unfocusedIndicatorColor = Color.Transparent,
|
|
||||||
disabledIndicatorColor = Color.Transparent
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
navigationIcon = {
|
navigationIcon = {
|
||||||
|
|
@ -182,10 +175,11 @@ private fun DefaultRoomListTopBar(
|
||||||
matrixUser: MatrixUser?,
|
matrixUser: MatrixUser?,
|
||||||
onOpenSettings: () -> Unit,
|
onOpenSettings: () -> Unit,
|
||||||
onSearchClicked: () -> Unit,
|
onSearchClicked: () -> Unit,
|
||||||
scrollBehavior: TopAppBarScrollBehavior
|
scrollBehavior: TopAppBarScrollBehavior,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
) {
|
) {
|
||||||
MediumTopAppBar(
|
MediumTopAppBar(
|
||||||
modifier = Modifier
|
modifier = modifier
|
||||||
.nestedScroll(scrollBehavior.nestedScrollConnection),
|
.nestedScroll(scrollBehavior.nestedScrollConnection),
|
||||||
title = {
|
title = {
|
||||||
Text(
|
Text(
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,6 @@ import androidx.compose.foundation.layout.size
|
||||||
import androidx.compose.foundation.shape.CircleShape
|
import androidx.compose.foundation.shape.CircleShape
|
||||||
import androidx.compose.material.ripple.rememberRipple
|
import androidx.compose.material.ripple.rememberRipple
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.Text
|
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
|
|
@ -54,6 +53,13 @@ import androidx.compose.ui.unit.sp
|
||||||
import com.google.accompanist.placeholder.material.placeholder
|
import com.google.accompanist.placeholder.material.placeholder
|
||||||
import io.element.android.features.roomlist.model.RoomListRoomSummary
|
import io.element.android.features.roomlist.model.RoomListRoomSummary
|
||||||
import io.element.android.libraries.designsystem.components.avatar.Avatar
|
import io.element.android.libraries.designsystem.components.avatar.Avatar
|
||||||
|
import io.element.android.libraries.designsystem.theme.ElementTheme
|
||||||
|
import io.element.android.libraries.designsystem.theme.components.Text
|
||||||
|
import io.element.android.libraries.designsystem.theme.roomListPlaceHolder
|
||||||
|
import io.element.android.libraries.designsystem.theme.roomListRoomMessage
|
||||||
|
import io.element.android.libraries.designsystem.theme.roomListRoomMessageDate
|
||||||
|
import io.element.android.libraries.designsystem.theme.roomListRoomName
|
||||||
|
import io.element.android.libraries.designsystem.theme.roomListUnreadIndicator
|
||||||
|
|
||||||
private val minHeight = 72.dp
|
private val minHeight = 72.dp
|
||||||
|
|
||||||
|
|
@ -95,7 +101,11 @@ internal fun DefaultRoomSummaryRow(
|
||||||
) {
|
) {
|
||||||
Avatar(
|
Avatar(
|
||||||
room.avatarData,
|
room.avatarData,
|
||||||
modifier = Modifier.placeholder(room.isPlaceholder, shape = CircleShape)
|
modifier = Modifier.placeholder(
|
||||||
|
visible = room.isPlaceholder,
|
||||||
|
shape = CircleShape,
|
||||||
|
color = ElementTheme.colors.roomListPlaceHolder(),
|
||||||
|
)
|
||||||
)
|
)
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
|
|
@ -105,19 +115,27 @@ internal fun DefaultRoomSummaryRow(
|
||||||
) {
|
) {
|
||||||
// Name
|
// Name
|
||||||
Text(
|
Text(
|
||||||
modifier = Modifier
|
modifier = Modifier.placeholder(
|
||||||
.placeholder(room.isPlaceholder, shape = TextPlaceholderShape),
|
visible = room.isPlaceholder,
|
||||||
|
shape = TextPlaceholderShape,
|
||||||
|
color = ElementTheme.colors.roomListPlaceHolder(),
|
||||||
|
),
|
||||||
fontSize = 16.sp,
|
fontSize = 16.sp,
|
||||||
fontWeight = FontWeight.SemiBold,
|
fontWeight = FontWeight.SemiBold,
|
||||||
text = room.name,
|
text = room.name,
|
||||||
|
color = MaterialTheme.roomListRoomName(),
|
||||||
maxLines = 1,
|
maxLines = 1,
|
||||||
overflow = TextOverflow.Ellipsis
|
overflow = TextOverflow.Ellipsis
|
||||||
)
|
)
|
||||||
// Last Message
|
// Last Message
|
||||||
Text(
|
Text(
|
||||||
modifier = Modifier.placeholder(room.isPlaceholder, shape = TextPlaceholderShape),
|
modifier = Modifier.placeholder(
|
||||||
|
visible = room.isPlaceholder,
|
||||||
|
shape = TextPlaceholderShape,
|
||||||
|
color = ElementTheme.colors.roomListPlaceHolder(),
|
||||||
|
),
|
||||||
text = room.lastMessage?.toString().orEmpty(),
|
text = room.lastMessage?.toString().orEmpty(),
|
||||||
color = MaterialTheme.colorScheme.secondary,
|
color = MaterialTheme.roomListRoomMessage(),
|
||||||
fontSize = 14.sp,
|
fontSize = 14.sp,
|
||||||
maxLines = 1,
|
maxLines = 1,
|
||||||
overflow = TextOverflow.Ellipsis
|
overflow = TextOverflow.Ellipsis
|
||||||
|
|
@ -129,14 +147,18 @@ internal fun DefaultRoomSummaryRow(
|
||||||
.alignByBaseline(),
|
.alignByBaseline(),
|
||||||
) {
|
) {
|
||||||
Text(
|
Text(
|
||||||
modifier = Modifier.placeholder(room.isPlaceholder, shape = TextPlaceholderShape),
|
modifier = Modifier.placeholder(
|
||||||
|
visible = room.isPlaceholder,
|
||||||
|
shape = TextPlaceholderShape,
|
||||||
|
color = ElementTheme.colors.roomListPlaceHolder(),
|
||||||
|
),
|
||||||
fontSize = 12.sp,
|
fontSize = 12.sp,
|
||||||
text = room.timestamp ?: "",
|
text = room.timestamp ?: "",
|
||||||
color = MaterialTheme.colorScheme.secondary,
|
color = MaterialTheme.roomListRoomMessageDate(),
|
||||||
)
|
)
|
||||||
Spacer(Modifier.size(4.dp))
|
Spacer(Modifier.size(4.dp))
|
||||||
val unreadIndicatorColor =
|
val unreadIndicatorColor =
|
||||||
if (room.hasUnread) MaterialTheme.colorScheme.primary else Color.Transparent
|
if (room.hasUnread) MaterialTheme.roomListUnreadIndicator() else Color.Transparent
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.size(12.dp)
|
.size(12.dp)
|
||||||
|
|
|
||||||
|
|
@ -17,11 +17,14 @@
|
||||||
package io.element.android.features.template
|
package io.element.android.features.template
|
||||||
|
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.tooling.preview.Preview
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
|
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
|
||||||
|
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
|
||||||
|
import io.element.android.libraries.designsystem.theme.components.Text
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun TemplateView(
|
fun TemplateView(
|
||||||
|
|
@ -29,13 +32,23 @@ fun TemplateView(
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
) {
|
) {
|
||||||
Box(modifier, contentAlignment = Alignment.Center) {
|
Box(modifier, contentAlignment = Alignment.Center) {
|
||||||
Text("Template feature view")
|
Text(
|
||||||
|
"Template feature view",
|
||||||
|
color = MaterialTheme.colorScheme.primary,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
|
||||||
@Preview
|
@Preview
|
||||||
fun TemplateViewPreview() {
|
@Composable
|
||||||
|
fun TemplateViewLightPreview() = ElementPreviewLight { ContentToPreview() }
|
||||||
|
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
fun TemplateViewDarkPreview() = ElementPreviewDark { ContentToPreview() }
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun ContentToPreview() {
|
||||||
TemplateView(
|
TemplateView(
|
||||||
state = TemplateState(),
|
state = TemplateState(),
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ ksp = "1.8.0-1.0.8"
|
||||||
molecule = "0.7.0"
|
molecule = "0.7.0"
|
||||||
|
|
||||||
# AndroidX
|
# AndroidX
|
||||||
material = "1.6.1"
|
material = "1.8.0"
|
||||||
corektx = "1.9.0"
|
corektx = "1.9.0"
|
||||||
datastore = "1.0.0"
|
datastore = "1.0.0"
|
||||||
constraintlayout = "2.1.4"
|
constraintlayout = "2.1.4"
|
||||||
|
|
|
||||||
|
|
@ -52,10 +52,4 @@ val ElementGreen = Color(0xFF0DBD8B)
|
||||||
val ElementOrange = Color(0xFFD9B072)
|
val ElementOrange = Color(0xFFD9B072)
|
||||||
val Vermilion = Color(0xFFFF5B55)
|
val Vermilion = Color(0xFFFF5B55)
|
||||||
|
|
||||||
// TODO Update color
|
|
||||||
val MessageHighlightLight = Azure
|
|
||||||
|
|
||||||
// TODO Update color
|
|
||||||
val MessageHighlightDark = Azure
|
|
||||||
|
|
||||||
val LinkColor = Color(0xFF054F6E)
|
val LinkColor = Color(0xFF054F6E)
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,6 @@ fun Boolean.toEnabledColor(): Color {
|
||||||
return if (this) {
|
return if (this) {
|
||||||
MaterialTheme.colorScheme.primary
|
MaterialTheme.colorScheme.primary
|
||||||
} else {
|
} else {
|
||||||
MaterialTheme.colorScheme.secondary
|
MaterialTheme.colorScheme.primary.copy(alpha = 0.40f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,55 +16,13 @@
|
||||||
|
|
||||||
package io.element.android.libraries.designsystem
|
package io.element.android.libraries.designsystem
|
||||||
|
|
||||||
import androidx.compose.material3.Typography
|
|
||||||
import androidx.compose.ui.text.TextStyle
|
import androidx.compose.ui.text.TextStyle
|
||||||
import androidx.compose.ui.text.font.FontFamily
|
|
||||||
import androidx.compose.ui.text.font.FontStyle
|
import androidx.compose.ui.text.font.FontStyle
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
import androidx.compose.ui.text.style.TextAlign
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
import androidx.compose.ui.unit.sp
|
import androidx.compose.ui.unit.sp
|
||||||
import com.airbnb.android.showkase.annotation.ShowkaseTypography
|
|
||||||
|
|
||||||
@ShowkaseTypography(name = "Body Large", group = "Element")
|
|
||||||
val bodyLarge = TextStyle(
|
|
||||||
fontFamily = FontFamily.Default,
|
|
||||||
fontWeight = FontWeight.Normal,
|
|
||||||
fontSize = 16.sp,
|
|
||||||
lineHeight = 24.sp,
|
|
||||||
letterSpacing = 0.5.sp
|
|
||||||
)
|
|
||||||
|
|
||||||
@ShowkaseTypography(name = "Headline Small", group = "Element")
|
|
||||||
val headlineSmall = TextStyle(
|
|
||||||
fontFamily = FontFamily.Default,
|
|
||||||
fontWeight = FontWeight.Bold,
|
|
||||||
fontSize = 32.sp,
|
|
||||||
lineHeight = 24.sp,
|
|
||||||
letterSpacing = 0.5.sp
|
|
||||||
)
|
|
||||||
|
|
||||||
// Set of Material typography styles to start with
|
|
||||||
val Typography = Typography(
|
|
||||||
bodyLarge = bodyLarge,
|
|
||||||
headlineSmall = headlineSmall,
|
|
||||||
/* Other default text styles to override
|
|
||||||
titleLarge = TextStyle(
|
|
||||||
fontFamily = FontFamily.Default,
|
|
||||||
fontWeight = FontWeight.Normal,
|
|
||||||
fontSize = 22.sp,
|
|
||||||
lineHeight = 28.sp,
|
|
||||||
letterSpacing = 0.sp
|
|
||||||
),
|
|
||||||
labelSmall = TextStyle(
|
|
||||||
fontFamily = FontFamily.Default,
|
|
||||||
fontWeight = FontWeight.Medium,
|
|
||||||
fontSize = 11.sp,
|
|
||||||
lineHeight = 16.sp,
|
|
||||||
letterSpacing = 0.5.sp
|
|
||||||
)
|
|
||||||
*/
|
|
||||||
)
|
|
||||||
|
|
||||||
|
// TODO Remove
|
||||||
object ElementTextStyles {
|
object ElementTextStyles {
|
||||||
|
|
||||||
object Bold {
|
object Bold {
|
||||||
|
|
@ -21,7 +21,7 @@ import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||||
import androidx.compose.foundation.interaction.PressInteraction
|
import androidx.compose.foundation.interaction.PressInteraction
|
||||||
import androidx.compose.foundation.text.InlineTextContent
|
import androidx.compose.foundation.text.InlineTextContent
|
||||||
import androidx.compose.material3.LocalTextStyle
|
import androidx.compose.material3.LocalTextStyle
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
|
|
@ -32,6 +32,7 @@ import androidx.compose.ui.platform.LocalUriHandler
|
||||||
import androidx.compose.ui.text.AnnotatedString
|
import androidx.compose.ui.text.AnnotatedString
|
||||||
import androidx.compose.ui.text.TextLayoutResult
|
import androidx.compose.ui.text.TextLayoutResult
|
||||||
import androidx.compose.ui.text.TextStyle
|
import androidx.compose.ui.text.TextStyle
|
||||||
|
import io.element.android.libraries.designsystem.theme.components.Text
|
||||||
import kotlinx.collections.immutable.ImmutableMap
|
import kotlinx.collections.immutable.ImmutableMap
|
||||||
import kotlinx.collections.immutable.persistentMapOf
|
import kotlinx.collections.immutable.persistentMapOf
|
||||||
|
|
||||||
|
|
@ -83,6 +84,7 @@ fun ClickableLinkText(
|
||||||
onTextLayout = {
|
onTextLayout = {
|
||||||
layoutResult.value = it
|
layoutResult.value = it
|
||||||
},
|
},
|
||||||
inlineContent = inlineContent
|
inlineContent = inlineContent,
|
||||||
|
color = MaterialTheme.colorScheme.primary,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,12 +18,15 @@ package io.element.android.libraries.designsystem.components
|
||||||
|
|
||||||
import androidx.compose.foundation.layout.Row
|
import androidx.compose.foundation.layout.Row
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.material3.Checkbox
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.Text
|
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.tooling.preview.Preview
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
|
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
|
||||||
|
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
|
||||||
|
import io.element.android.libraries.designsystem.theme.components.Checkbox
|
||||||
|
import io.element.android.libraries.designsystem.theme.components.Text
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun LabelledCheckbox(
|
fun LabelledCheckbox(
|
||||||
|
|
@ -42,13 +45,23 @@ fun LabelledCheckbox(
|
||||||
onCheckedChange = onCheckedChange,
|
onCheckedChange = onCheckedChange,
|
||||||
enabled = enabled,
|
enabled = enabled,
|
||||||
)
|
)
|
||||||
Text(text = text)
|
Text(
|
||||||
|
text = text,
|
||||||
|
color = MaterialTheme.colorScheme.primary,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Preview
|
@Preview
|
||||||
@Composable
|
@Composable
|
||||||
fun LabelledCheckboxPreview() {
|
fun LabelledCheckboxLightPreview() = ElementPreviewLight { ContentToPreview() }
|
||||||
|
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
fun LabelledCheckboxDarkPreview() = ElementPreviewDark { ContentToPreview() }
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun ContentToPreview() {
|
||||||
LabelledCheckbox(
|
LabelledCheckbox(
|
||||||
checked = true,
|
checked = true,
|
||||||
text = "Some text",
|
text = "Some text",
|
||||||
|
|
|
||||||
|
|
@ -22,9 +22,7 @@ import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
import androidx.compose.material3.CircularProgressIndicator
|
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.Text
|
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
|
@ -32,6 +30,10 @@ import androidx.compose.ui.tooling.preview.Preview
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.window.Dialog
|
import androidx.compose.ui.window.Dialog
|
||||||
import androidx.compose.ui.window.DialogProperties
|
import androidx.compose.ui.window.DialogProperties
|
||||||
|
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
|
||||||
|
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
|
||||||
|
import io.element.android.libraries.designsystem.theme.components.CircularProgressIndicator
|
||||||
|
import io.element.android.libraries.designsystem.theme.components.Text
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun ProgressDialog(
|
fun ProgressDialog(
|
||||||
|
|
@ -48,19 +50,19 @@ fun ProgressDialog(
|
||||||
modifier = modifier
|
modifier = modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.background(
|
.background(
|
||||||
color = MaterialTheme.colorScheme.onBackground,
|
color = MaterialTheme.colorScheme.surfaceVariant,
|
||||||
shape = RoundedCornerShape(8.dp)
|
shape = RoundedCornerShape(8.dp)
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
Column(horizontalAlignment = Alignment.CenterHorizontally) {
|
Column(horizontalAlignment = Alignment.CenterHorizontally) {
|
||||||
CircularProgressIndicator(
|
CircularProgressIndicator(
|
||||||
modifier = Modifier.padding(16.dp),
|
modifier = Modifier.padding(16.dp),
|
||||||
color = MaterialTheme.colorScheme.background
|
color = MaterialTheme.colorScheme.onSurfaceVariant
|
||||||
)
|
)
|
||||||
if (!text.isNullOrBlank()) {
|
if (!text.isNullOrBlank()) {
|
||||||
Text(
|
Text(
|
||||||
text = text,
|
text = text,
|
||||||
color = MaterialTheme.colorScheme.background,
|
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||||
modifier = Modifier.padding(16.dp)
|
modifier = Modifier.padding(16.dp)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -69,8 +71,15 @@ fun ProgressDialog(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
|
||||||
@Preview
|
@Preview
|
||||||
fun ProgressDialogPreview() {
|
@Composable
|
||||||
|
fun ProgressDialogLightPreview() = ElementPreviewLight { ContentToPreview() }
|
||||||
|
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
fun ProgressDialogDarkPreview() = ElementPreviewDark { ContentToPreview() }
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun ContentToPreview() {
|
||||||
ProgressDialog(text = "test dialog content")
|
ProgressDialog(text = "test dialog content")
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,6 @@
|
||||||
|
|
||||||
package io.element.android.libraries.designsystem.components
|
package io.element.android.libraries.designsystem.components
|
||||||
|
|
||||||
import androidx.compose.material3.Icon
|
|
||||||
import androidx.compose.material3.LocalContentColor
|
import androidx.compose.material3.LocalContentColor
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
|
@ -29,7 +28,7 @@ fun VectorIcon(
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
tint: Color = LocalContentColor.current,
|
tint: Color = LocalContentColor.current,
|
||||||
) {
|
) {
|
||||||
Icon(
|
androidx.compose.material3.Icon(
|
||||||
painter = painterResource(id = resourceId),
|
painter = painterResource(id = resourceId),
|
||||||
contentDescription = null,
|
contentDescription = null,
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,6 @@ import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.size
|
import androidx.compose.foundation.layout.size
|
||||||
import androidx.compose.foundation.shape.CircleShape
|
import androidx.compose.foundation.shape.CircleShape
|
||||||
import androidx.compose.material3.Text
|
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
|
@ -34,6 +33,9 @@ import androidx.compose.ui.unit.sp
|
||||||
import coil.compose.AsyncImage
|
import coil.compose.AsyncImage
|
||||||
import io.element.android.libraries.designsystem.AvatarGradientEnd
|
import io.element.android.libraries.designsystem.AvatarGradientEnd
|
||||||
import io.element.android.libraries.designsystem.AvatarGradientStart
|
import io.element.android.libraries.designsystem.AvatarGradientStart
|
||||||
|
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
|
||||||
|
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
|
||||||
|
import io.element.android.libraries.designsystem.theme.components.Text
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
|
|
@ -97,6 +99,13 @@ private fun InitialsAvatar(
|
||||||
|
|
||||||
@Preview
|
@Preview
|
||||||
@Composable
|
@Composable
|
||||||
fun InitialsAvatarPreview() {
|
fun AvatarLightPreview() = ElementPreviewLight { ContentToPreview() }
|
||||||
|
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
fun AvatarDarkPreview() = ElementPreviewDark { ContentToPreview() }
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun ContentToPreview() {
|
||||||
Avatar(AvatarData(name = "A"))
|
Avatar(AvatarData(name = "A"))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -22,13 +22,20 @@ import androidx.compose.foundation.layout.Row
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.material3.AlertDialog
|
import androidx.compose.material3.AlertDialog
|
||||||
import androidx.compose.material3.Button
|
import androidx.compose.material3.AlertDialogDefaults
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.graphics.Shape
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.tooling.preview.Preview
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
|
import androidx.compose.ui.unit.Dp
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
|
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
|
||||||
|
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
|
||||||
|
import io.element.android.libraries.designsystem.theme.components.Button
|
||||||
|
import io.element.android.libraries.designsystem.theme.components.Text
|
||||||
import io.element.android.libraries.ui.strings.R as StringR
|
import io.element.android.libraries.ui.strings.R as StringR
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
|
|
@ -43,6 +50,12 @@ fun ConfirmationDialog(
|
||||||
onCancelClicked: () -> Unit = {},
|
onCancelClicked: () -> Unit = {},
|
||||||
onThirdButtonClicked: () -> Unit = {},
|
onThirdButtonClicked: () -> Unit = {},
|
||||||
onDismiss: () -> Unit = {},
|
onDismiss: () -> Unit = {},
|
||||||
|
shape: Shape = AlertDialogDefaults.shape,
|
||||||
|
containerColor: Color = MaterialTheme.colorScheme.surfaceVariant,
|
||||||
|
iconContentColor: Color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||||
|
titleContentColor: Color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||||
|
textContentColor: Color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||||
|
tonalElevation: Dp = AlertDialogDefaults.TonalElevation,
|
||||||
) {
|
) {
|
||||||
AlertDialog(
|
AlertDialog(
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
|
|
@ -93,12 +106,25 @@ fun ConfirmationDialog(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
shape = shape,
|
||||||
|
containerColor = containerColor,
|
||||||
|
iconContentColor = iconContentColor,
|
||||||
|
titleContentColor = titleContentColor,
|
||||||
|
textContentColor = textContentColor,
|
||||||
|
tonalElevation = tonalElevation,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
|
||||||
@Preview
|
@Preview
|
||||||
fun ConfirmationDialogPreview() {
|
@Composable
|
||||||
|
fun ConfirmationDialogLightPreview() = ElementPreviewLight { ContentToPreview() }
|
||||||
|
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
fun ConfirmationDialogDarkPreview() = ElementPreviewDark { ContentToPreview() }
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun ContentToPreview() {
|
||||||
ConfirmationDialog(
|
ConfirmationDialog(
|
||||||
title = "Title",
|
title = "Title",
|
||||||
content = "Content",
|
content = "Content",
|
||||||
|
|
|
||||||
|
|
@ -21,13 +21,20 @@ import androidx.compose.foundation.layout.Row
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.material3.AlertDialog
|
import androidx.compose.material3.AlertDialog
|
||||||
import androidx.compose.material3.Button
|
import androidx.compose.material3.AlertDialogDefaults
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.graphics.Shape
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.tooling.preview.Preview
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
|
import androidx.compose.ui.unit.Dp
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
|
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
|
||||||
|
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
|
||||||
|
import io.element.android.libraries.designsystem.theme.components.Button
|
||||||
|
import io.element.android.libraries.designsystem.theme.components.Text
|
||||||
import io.element.android.libraries.ui.strings.R as StringR
|
import io.element.android.libraries.ui.strings.R as StringR
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
|
|
@ -37,6 +44,12 @@ fun ErrorDialog(
|
||||||
title: String = stringResource(id = StringR.string.dialog_title_error),
|
title: String = stringResource(id = StringR.string.dialog_title_error),
|
||||||
submitText: String = stringResource(id = StringR.string.ok),
|
submitText: String = stringResource(id = StringR.string.ok),
|
||||||
onDismiss: () -> Unit = {},
|
onDismiss: () -> Unit = {},
|
||||||
|
shape: Shape = AlertDialogDefaults.shape,
|
||||||
|
containerColor: Color = MaterialTheme.colorScheme.surfaceVariant,
|
||||||
|
iconContentColor: Color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||||
|
titleContentColor: Color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||||
|
textContentColor: Color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||||
|
tonalElevation: Dp = AlertDialogDefaults.TonalElevation,
|
||||||
) {
|
) {
|
||||||
AlertDialog(
|
AlertDialog(
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
|
|
@ -62,12 +75,25 @@ fun ErrorDialog(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
shape = shape,
|
||||||
|
containerColor = containerColor,
|
||||||
|
iconContentColor = iconContentColor,
|
||||||
|
titleContentColor = titleContentColor,
|
||||||
|
textContentColor = textContentColor,
|
||||||
|
tonalElevation = tonalElevation,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
|
||||||
@Preview
|
@Preview
|
||||||
fun ErrorDialogPreview() {
|
@Composable
|
||||||
|
fun ErrorDialogLightPreview() = ElementPreviewLight { ContentToPreview() }
|
||||||
|
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
fun ErrorDialogDarkPreview() = ElementPreviewDark { ContentToPreview() }
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun ContentToPreview() {
|
||||||
ErrorDialog(
|
ErrorDialog(
|
||||||
content = "Content",
|
content = "Content",
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -20,13 +20,18 @@ import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.ColumnScope
|
import androidx.compose.foundation.layout.ColumnScope
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.material3.Divider
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.filled.Announcement
|
||||||
|
import androidx.compose.material.icons.filled.BugReport
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.Text
|
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.tooling.preview.Preview
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
|
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
|
||||||
|
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
|
||||||
|
import io.element.android.libraries.designsystem.theme.components.Divider
|
||||||
|
import io.element.android.libraries.designsystem.theme.components.Text
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun PreferenceCategory(
|
fun PreferenceCategory(
|
||||||
|
|
@ -46,20 +51,39 @@ fun PreferenceCategory(
|
||||||
Text(
|
Text(
|
||||||
modifier = Modifier.padding(top = 8.dp, start = 56.dp),
|
modifier = Modifier.padding(top = 8.dp, start = 56.dp),
|
||||||
style = MaterialTheme.typography.titleSmall,
|
style = MaterialTheme.typography.titleSmall,
|
||||||
text = title
|
color = MaterialTheme.colorScheme.primary,
|
||||||
|
text = title,
|
||||||
)
|
)
|
||||||
content()
|
content()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
|
||||||
@Preview
|
@Preview
|
||||||
fun PreferenceCategoryPreview() {
|
@Composable
|
||||||
|
fun PreferenceCategoryLightPreview() = ElementPreviewLight { ContentToPreview() }
|
||||||
|
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
fun PreferenceCategoryDarkPreview() = ElementPreviewDark { ContentToPreview() }
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun ContentToPreview() {
|
||||||
PreferenceCategory(
|
PreferenceCategory(
|
||||||
title = "Category title",
|
title = "Category title",
|
||||||
) {
|
) {
|
||||||
PreferenceTextPreview()
|
PreferenceText(
|
||||||
PreferenceSwitchPreview()
|
title = "Title",
|
||||||
PreferenceSlidePreview()
|
icon = Icons.Default.BugReport,
|
||||||
|
)
|
||||||
|
PreferenceSwitch(
|
||||||
|
title = "Switch",
|
||||||
|
icon = Icons.Default.Announcement,
|
||||||
|
isChecked = true
|
||||||
|
)
|
||||||
|
PreferenceSlide(
|
||||||
|
title = "Slide",
|
||||||
|
summary = "Summary",
|
||||||
|
value = 0.75F
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -28,13 +28,10 @@ import androidx.compose.foundation.layout.systemBarsPadding
|
||||||
import androidx.compose.foundation.rememberScrollState
|
import androidx.compose.foundation.rememberScrollState
|
||||||
import androidx.compose.foundation.verticalScroll
|
import androidx.compose.foundation.verticalScroll
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.filled.Announcement
|
||||||
import androidx.compose.material.icons.filled.ArrowBack
|
import androidx.compose.material.icons.filled.ArrowBack
|
||||||
|
import androidx.compose.material.icons.filled.BugReport
|
||||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
import androidx.compose.material3.Icon
|
|
||||||
import androidx.compose.material3.IconButton
|
|
||||||
import androidx.compose.material3.Scaffold
|
|
||||||
import androidx.compose.material3.Text
|
|
||||||
import androidx.compose.material3.TopAppBar
|
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
|
@ -42,6 +39,13 @@ import androidx.compose.ui.text.font.FontWeight
|
||||||
import androidx.compose.ui.text.style.TextOverflow
|
import androidx.compose.ui.text.style.TextOverflow
|
||||||
import androidx.compose.ui.tooling.preview.Preview
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
import androidx.compose.ui.unit.sp
|
import androidx.compose.ui.unit.sp
|
||||||
|
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
|
||||||
|
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
|
||||||
|
import io.element.android.libraries.designsystem.theme.components.Icon
|
||||||
|
import io.element.android.libraries.designsystem.theme.components.IconButton
|
||||||
|
import io.element.android.libraries.designsystem.theme.components.Scaffold
|
||||||
|
import io.element.android.libraries.designsystem.theme.components.Text
|
||||||
|
import io.element.android.libraries.designsystem.theme.components.TopAppBar
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterial3Api::class)
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
@Composable
|
@Composable
|
||||||
|
|
@ -110,12 +114,36 @@ fun PreferenceTopAppBar(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
|
||||||
@Preview
|
@Preview
|
||||||
fun PreferenceScreenPreview() {
|
@Composable
|
||||||
|
fun PreferenceViewLightPreview() = ElementPreviewLight { ContentToPreview() }
|
||||||
|
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
fun PreferenceViewDarkPreview() = ElementPreviewDark { ContentToPreview() }
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun ContentToPreview() {
|
||||||
PreferenceView(
|
PreferenceView(
|
||||||
title = "Preference screen"
|
title = "Preference screen"
|
||||||
) {
|
) {
|
||||||
PreferenceCategoryPreview()
|
PreferenceCategory(
|
||||||
|
title = "Category title",
|
||||||
|
) {
|
||||||
|
PreferenceText(
|
||||||
|
title = "Title",
|
||||||
|
icon = Icons.Default.BugReport,
|
||||||
|
)
|
||||||
|
PreferenceSwitch(
|
||||||
|
title = "Switch",
|
||||||
|
icon = Icons.Default.Announcement,
|
||||||
|
isChecked = true
|
||||||
|
)
|
||||||
|
PreferenceSlide(
|
||||||
|
title = "Slide",
|
||||||
|
summary = "Summary",
|
||||||
|
value = 0.75F
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -24,14 +24,16 @@ import androidx.compose.foundation.layout.defaultMinSize
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.Slider
|
|
||||||
import androidx.compose.material3.Text
|
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.graphics.vector.ImageVector
|
import androidx.compose.ui.graphics.vector.ImageVector
|
||||||
import androidx.compose.ui.tooling.preview.Preview
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
import io.element.android.libraries.designsystem.components.preferences.components.PreferenceIcon
|
import io.element.android.libraries.designsystem.components.preferences.components.PreferenceIcon
|
||||||
|
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
|
||||||
|
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
|
||||||
|
import io.element.android.libraries.designsystem.theme.components.Slider
|
||||||
|
import io.element.android.libraries.designsystem.theme.components.Text
|
||||||
import io.element.android.libraries.designsystem.toEnabledColor
|
import io.element.android.libraries.designsystem.toEnabledColor
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
|
|
@ -84,9 +86,16 @@ fun PreferenceSlide(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
|
||||||
@Preview
|
@Preview
|
||||||
fun PreferenceSlidePreview() {
|
@Composable
|
||||||
|
fun PreferenceSlideLightPreview() = ElementPreviewLight { ContentToPreview() }
|
||||||
|
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
fun PreferenceSlideDarkPreview() = ElementPreviewDark { ContentToPreview() }
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun ContentToPreview() {
|
||||||
PreferenceSlide(
|
PreferenceSlide(
|
||||||
title = "Slide",
|
title = "Slide",
|
||||||
summary = "Summary",
|
summary = "Summary",
|
||||||
|
|
|
||||||
|
|
@ -24,15 +24,17 @@ import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.filled.Announcement
|
import androidx.compose.material.icons.filled.Announcement
|
||||||
import androidx.compose.material3.Checkbox
|
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.Text
|
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.graphics.vector.ImageVector
|
import androidx.compose.ui.graphics.vector.ImageVector
|
||||||
import androidx.compose.ui.tooling.preview.Preview
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
import io.element.android.libraries.designsystem.components.preferences.components.PreferenceIcon
|
import io.element.android.libraries.designsystem.components.preferences.components.PreferenceIcon
|
||||||
|
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
|
||||||
|
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
|
||||||
|
import io.element.android.libraries.designsystem.theme.components.Checkbox
|
||||||
|
import io.element.android.libraries.designsystem.theme.components.Text
|
||||||
import io.element.android.libraries.designsystem.toEnabledColor
|
import io.element.android.libraries.designsystem.toEnabledColor
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
|
|
@ -75,12 +77,20 @@ fun PreferenceSwitch(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
|
||||||
@Preview
|
@Preview
|
||||||
fun PreferenceSwitchPreview() {
|
@Composable
|
||||||
|
fun PreferenceSwitchLightPreview() = ElementPreviewLight { ContentToPreview() }
|
||||||
|
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
fun PreferenceSwitchDarkPreview() = ElementPreviewDark { ContentToPreview() }
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun ContentToPreview() {
|
||||||
PreferenceSwitch(
|
PreferenceSwitch(
|
||||||
title = "Switch",
|
title = "Switch",
|
||||||
icon = Icons.Default.Announcement,
|
icon = Icons.Default.Announcement,
|
||||||
|
enabled = true,
|
||||||
isChecked = true
|
isChecked = true
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -25,13 +25,15 @@ import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.filled.BugReport
|
import androidx.compose.material.icons.filled.BugReport
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.Text
|
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.graphics.vector.ImageVector
|
import androidx.compose.ui.graphics.vector.ImageVector
|
||||||
import androidx.compose.ui.tooling.preview.Preview
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
import io.element.android.libraries.designsystem.components.preferences.components.PreferenceIcon
|
import io.element.android.libraries.designsystem.components.preferences.components.PreferenceIcon
|
||||||
|
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
|
||||||
|
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
|
||||||
|
import io.element.android.libraries.designsystem.theme.components.Text
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun PreferenceText(
|
fun PreferenceText(
|
||||||
|
|
@ -57,15 +59,23 @@ fun PreferenceText(
|
||||||
.weight(1f)
|
.weight(1f)
|
||||||
.padding(end = preferencePaddingEnd),
|
.padding(end = preferencePaddingEnd),
|
||||||
style = MaterialTheme.typography.bodyLarge,
|
style = MaterialTheme.typography.bodyLarge,
|
||||||
text = title
|
text = title,
|
||||||
|
color = MaterialTheme.colorScheme.primary,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
|
||||||
@Preview
|
@Preview
|
||||||
fun PreferenceTextPreview() {
|
@Composable
|
||||||
|
fun PreferenceTextLightPreview() = ElementPreviewLight { ContentToPreview() }
|
||||||
|
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
fun PreferenceTextDarkPreview() = ElementPreviewDark { ContentToPreview() }
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun ContentToPreview() {
|
||||||
PreferenceText(
|
PreferenceText(
|
||||||
title = "Title",
|
title = "Title",
|
||||||
icon = Icons.Default.BugReport,
|
icon = Icons.Default.BugReport,
|
||||||
|
|
|
||||||
|
|
@ -19,11 +19,11 @@ package io.element.android.libraries.designsystem.components.preferences.compone
|
||||||
import androidx.compose.foundation.layout.Spacer
|
import androidx.compose.foundation.layout.Spacer
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.layout.width
|
import androidx.compose.foundation.layout.width
|
||||||
import androidx.compose.material3.Icon
|
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.graphics.vector.ImageVector
|
import androidx.compose.ui.graphics.vector.ImageVector
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
|
import io.element.android.libraries.designsystem.theme.components.Icon
|
||||||
import io.element.android.libraries.designsystem.toEnabledColor
|
import io.element.android.libraries.designsystem.toEnabledColor
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,66 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2023 New Vector Ltd
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.element.android.libraries.designsystem.preview
|
||||||
|
|
||||||
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import io.element.android.libraries.designsystem.theme.ElementTheme
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun ElementPreviewLight(
|
||||||
|
showBackground: Boolean = true,
|
||||||
|
content: @Composable () -> Unit
|
||||||
|
) {
|
||||||
|
ElementPreview(
|
||||||
|
darkTheme = false,
|
||||||
|
showBackground = showBackground,
|
||||||
|
content = content
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun ElementPreviewDark(
|
||||||
|
showBackground: Boolean = true,
|
||||||
|
content: @Composable () -> Unit
|
||||||
|
) {
|
||||||
|
ElementPreview(
|
||||||
|
darkTheme = true,
|
||||||
|
showBackground = showBackground,
|
||||||
|
content = content
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun ElementPreview(
|
||||||
|
darkTheme: Boolean,
|
||||||
|
showBackground: Boolean,
|
||||||
|
content: @Composable () -> Unit
|
||||||
|
) {
|
||||||
|
ElementTheme(darkTheme = darkTheme) {
|
||||||
|
if (showBackground) {
|
||||||
|
Box(modifier = Modifier.background(MaterialTheme.colorScheme.background)) {
|
||||||
|
content()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
content()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,68 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2023 New Vector Ltd
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.element.android.libraries.designsystem.theme
|
||||||
|
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
|
import io.element.android.libraries.designsystem.SystemGrey4Dark
|
||||||
|
import io.element.android.libraries.designsystem.SystemGrey6Light
|
||||||
|
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
|
||||||
|
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
|
||||||
|
import io.element.android.libraries.designsystem.theme.previews.ColorListPreview
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Room list.
|
||||||
|
*/
|
||||||
|
@Composable
|
||||||
|
fun MaterialTheme.roomListRoomName() = colorScheme.primary
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun MaterialTheme.roomListRoomMessage() = colorScheme.secondary
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun MaterialTheme.roomListRoomMessageDate() = colorScheme.secondary
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun MaterialTheme.roomListUnreadIndicator() = colorScheme.primary
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun ElementColors.roomListPlaceHolder() = if (isLight) SystemGrey6Light else SystemGrey4Dark
|
||||||
|
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
fun ColorAliasesLightPreview() = ElementPreviewLight { ContentToPreview() }
|
||||||
|
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
fun ColorAliasesDarkPreview() = ElementPreviewDark { ContentToPreview() }
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun ContentToPreview() {
|
||||||
|
ColorListPreview(
|
||||||
|
backgroundColor = Color.Black,
|
||||||
|
foregroundColor = Color.White,
|
||||||
|
colors = mapOf(
|
||||||
|
"roomListRoomName" to MaterialTheme.roomListRoomName(),
|
||||||
|
"roomListRoomMessage" to MaterialTheme.roomListRoomMessage(),
|
||||||
|
"roomListRoomMessageDate" to MaterialTheme.roomListRoomMessageDate(),
|
||||||
|
"roomListUnreadIndicator" to MaterialTheme.roomListUnreadIndicator(),
|
||||||
|
"roomListPlaceHolder" to ElementTheme.colors.roomListPlaceHolder(),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,75 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2023 New Vector Ltd
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.element.android.libraries.designsystem.theme
|
||||||
|
|
||||||
|
import androidx.compose.material3.darkColorScheme
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
|
import io.element.android.libraries.designsystem.Azure
|
||||||
|
import io.element.android.libraries.designsystem.DarkGrey
|
||||||
|
import io.element.android.libraries.designsystem.SystemGrey5Dark
|
||||||
|
import io.element.android.libraries.designsystem.SystemGrey6Dark
|
||||||
|
import io.element.android.libraries.designsystem.theme.previews.ColorsSchemePreview
|
||||||
|
|
||||||
|
fun elementColorsDark() = ElementColors(
|
||||||
|
messageFromMeBackground = SystemGrey5Dark,
|
||||||
|
messageFromOtherBackground = SystemGrey6Dark,
|
||||||
|
messageHighlightedBackground = Azure,
|
||||||
|
isLight = false,
|
||||||
|
)
|
||||||
|
|
||||||
|
// TODO Lots of colors are missing
|
||||||
|
val materialColorSchemeDark = darkColorScheme(
|
||||||
|
primary = Color.White,
|
||||||
|
// TODO onPrimary = ColorDarkTokens.OnPrimary,
|
||||||
|
// TODO primaryContainer = ColorDarkTokens.PrimaryContainer,
|
||||||
|
// TODO onPrimaryContainer = ColorDarkTokens.OnPrimaryContainer,
|
||||||
|
// TODO inversePrimary = ColorDarkTokens.InversePrimary,
|
||||||
|
secondary = DarkGrey,
|
||||||
|
// TODO onSecondary = ColorDarkTokens.OnSecondary,
|
||||||
|
// TODO secondaryContainer = ColorDarkTokens.SecondaryContainer,
|
||||||
|
// TODO onSecondaryContainer = ColorDarkTokens.OnSecondaryContainer,
|
||||||
|
tertiary = Color.White,
|
||||||
|
// TODO onTertiary = ColorDarkTokens.OnTertiary,
|
||||||
|
// TODO tertiaryContainer = ColorDarkTokens.TertiaryContainer,
|
||||||
|
// TODO onTertiaryContainer = ColorDarkTokens.OnTertiaryContainer,
|
||||||
|
background = Color.Black,
|
||||||
|
onBackground = Color.White,
|
||||||
|
surface = Color.Black,
|
||||||
|
onSurface = Color.White,
|
||||||
|
surfaceVariant = SystemGrey5Dark,
|
||||||
|
// TODO onSurfaceVariant = ColorDarkTokens.OnSurfaceVariant,
|
||||||
|
// TODO surfaceTint = primary,
|
||||||
|
// TODO inverseSurface = ColorDarkTokens.InverseSurface,
|
||||||
|
// TODO inverseOnSurface = ColorDarkTokens.InverseOnSurface,
|
||||||
|
// TODO error = ColorDarkTokens.Error,
|
||||||
|
// TODO onError = ColorDarkTokens.OnError,
|
||||||
|
// TODO errorContainer = ColorDarkTokens.ErrorContainer,
|
||||||
|
// TODO onErrorContainer = ColorDarkTokens.OnErrorContainer,
|
||||||
|
// TODO outline = ColorDarkTokens.Outline,
|
||||||
|
// TODO outlineVariant = ColorDarkTokens.OutlineVariant,
|
||||||
|
// TODO scrim = ColorDarkTokens.Scrim,
|
||||||
|
)
|
||||||
|
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
fun ColorsSchemePreviewDark() = ColorsSchemePreview(
|
||||||
|
Color.White,
|
||||||
|
Color.Black,
|
||||||
|
materialColorSchemeDark,
|
||||||
|
)
|
||||||
|
|
@ -0,0 +1,75 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2023 New Vector Ltd
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.element.android.libraries.designsystem.theme
|
||||||
|
|
||||||
|
import androidx.compose.material3.lightColorScheme
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
|
import io.element.android.libraries.designsystem.Azure
|
||||||
|
import io.element.android.libraries.designsystem.LightGrey
|
||||||
|
import io.element.android.libraries.designsystem.SystemGrey5Light
|
||||||
|
import io.element.android.libraries.designsystem.SystemGrey6Light
|
||||||
|
import io.element.android.libraries.designsystem.theme.previews.ColorsSchemePreview
|
||||||
|
|
||||||
|
fun elementColorsLight() = ElementColors(
|
||||||
|
messageFromMeBackground = SystemGrey5Light,
|
||||||
|
messageFromOtherBackground = SystemGrey6Light,
|
||||||
|
messageHighlightedBackground = Azure,
|
||||||
|
isLight = true,
|
||||||
|
)
|
||||||
|
|
||||||
|
// TODO Lots of colors are missing
|
||||||
|
val materialColorSchemeLight = lightColorScheme(
|
||||||
|
primary = Color.Black,
|
||||||
|
// TODO onPrimary = ColorLightTokens.OnPrimary,
|
||||||
|
// TODO primaryContainer = ColorLightTokens.PrimaryContainer,
|
||||||
|
// TODO onPrimaryContainer = ColorLightTokens.OnPrimaryContainer,
|
||||||
|
// TODO inversePrimary = ColorLightTokens.InversePrimary,
|
||||||
|
secondary = LightGrey,
|
||||||
|
// TODO onSecondary = ColorLightTokens.OnSecondary,
|
||||||
|
// TODO secondaryContainer = ColorLightTokens.SecondaryContainer,
|
||||||
|
// TODO onSecondaryContainer = ColorLightTokens.OnSecondaryContainer,
|
||||||
|
tertiary = Color.Black,
|
||||||
|
// TODO onTertiary = ColorLightTokens.OnTertiary,
|
||||||
|
// TODO tertiaryContainer = ColorLightTokens.TertiaryContainer,
|
||||||
|
// TODO onTertiaryContainer = ColorLightTokens.OnTertiaryContainer,
|
||||||
|
background = Color.White,
|
||||||
|
onBackground = Color.Black,
|
||||||
|
surface = Color.White,
|
||||||
|
onSurface = Color.Black,
|
||||||
|
surfaceVariant = SystemGrey5Light,
|
||||||
|
onSurfaceVariant = Color.Black,
|
||||||
|
// TODO surfaceTint = primary,
|
||||||
|
// TODO inverseSurface = ColorLightTokens.InverseSurface,
|
||||||
|
// TODO inverseOnSurface = ColorLightTokens.InverseOnSurface,
|
||||||
|
// TODO error = ColorLightTokens.Error,
|
||||||
|
// TODO onError = ColorLightTokens.OnError,
|
||||||
|
// TODO errorContainer = ColorLightTokens.ErrorContainer,
|
||||||
|
// TODO onErrorContainer = ColorLightTokens.OnErrorContainer,
|
||||||
|
// TODO outline = ColorLightTokens.Outline,
|
||||||
|
// TODO outlineVariant = ColorLightTokens.OutlineVariant,
|
||||||
|
// TODO scrim = ColorLightTokens.Scrim,
|
||||||
|
)
|
||||||
|
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
fun ColorsSchemePreviewLight() = ColorsSchemePreview(
|
||||||
|
Color.Black,
|
||||||
|
Color.White,
|
||||||
|
materialColorSchemeLight,
|
||||||
|
)
|
||||||
|
|
@ -0,0 +1,58 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2023 New Vector Ltd
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.element.android.libraries.designsystem.theme
|
||||||
|
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
|
||||||
|
class ElementColors(
|
||||||
|
messageFromMeBackground: Color,
|
||||||
|
messageFromOtherBackground: Color,
|
||||||
|
messageHighlightedBackground: Color,
|
||||||
|
isLight: Boolean,
|
||||||
|
) {
|
||||||
|
var messageFromMeBackground by mutableStateOf(messageFromMeBackground)
|
||||||
|
private set
|
||||||
|
var messageFromOtherBackground by mutableStateOf(messageFromOtherBackground)
|
||||||
|
private set
|
||||||
|
var messageHighlightedBackground by mutableStateOf(messageHighlightedBackground)
|
||||||
|
private set
|
||||||
|
|
||||||
|
var isLight by mutableStateOf(isLight)
|
||||||
|
private set
|
||||||
|
|
||||||
|
fun copy(
|
||||||
|
messageFromMeBackground: Color = this.messageFromMeBackground,
|
||||||
|
messageFromOtherBackground: Color = this.messageFromOtherBackground,
|
||||||
|
messageHighlightedBackground: Color = this.messageHighlightedBackground,
|
||||||
|
isLight: Boolean = this.isLight,
|
||||||
|
) = ElementColors(
|
||||||
|
messageFromMeBackground = messageFromMeBackground,
|
||||||
|
messageFromOtherBackground = messageFromOtherBackground,
|
||||||
|
messageHighlightedBackground = messageHighlightedBackground,
|
||||||
|
isLight = isLight,
|
||||||
|
)
|
||||||
|
|
||||||
|
fun updateColorsFrom(other: ElementColors) {
|
||||||
|
messageFromMeBackground = other.messageFromMeBackground
|
||||||
|
messageFromOtherBackground = other.messageFromOtherBackground
|
||||||
|
messageHighlightedBackground = other.messageHighlightedBackground
|
||||||
|
isLight = other.isLight
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -14,77 +14,58 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package io.element.android.libraries.designsystem
|
package io.element.android.libraries.designsystem.theme
|
||||||
|
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import androidx.compose.foundation.isSystemInDarkTheme
|
import androidx.compose.foundation.isSystemInDarkTheme
|
||||||
|
import androidx.compose.material3.ColorScheme
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.darkColorScheme
|
|
||||||
import androidx.compose.material3.dynamicDarkColorScheme
|
import androidx.compose.material3.dynamicDarkColorScheme
|
||||||
import androidx.compose.material3.dynamicLightColorScheme
|
import androidx.compose.material3.dynamicLightColorScheme
|
||||||
import androidx.compose.material3.lightColorScheme
|
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.CompositionLocalProvider
|
import androidx.compose.runtime.CompositionLocalProvider
|
||||||
|
import androidx.compose.runtime.ReadOnlyComposable
|
||||||
import androidx.compose.runtime.SideEffect
|
import androidx.compose.runtime.SideEffect
|
||||||
import androidx.compose.runtime.compositionLocalOf
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.runtime.staticCompositionLocalOf
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import com.google.accompanist.systemuicontroller.rememberSystemUiController
|
import com.google.accompanist.systemuicontroller.rememberSystemUiController
|
||||||
|
|
||||||
private val DarkColorScheme = darkColorScheme(
|
/**
|
||||||
primary = Color.White,
|
* Inspired from https://medium.com/@lucasyujideveloper/54cbcbde1ace
|
||||||
secondary = DarkGrey,
|
*/
|
||||||
tertiary = Color.White,
|
object ElementTheme {
|
||||||
background = Color.Black,
|
val colors: ElementColors
|
||||||
onBackground = Color.White,
|
@Composable
|
||||||
surface = Color.Black,
|
@ReadOnlyComposable
|
||||||
surfaceVariant = SystemGrey5Dark,
|
get() = LocalColors.current
|
||||||
onSurface = Color.White,
|
}
|
||||||
onSurfaceVariant = Color.White,
|
|
||||||
)
|
|
||||||
|
|
||||||
private val LightColorScheme = lightColorScheme(
|
/* Global variables (application level) */
|
||||||
primary = Color.Black,
|
val LocalColors = staticCompositionLocalOf { elementColorsLight() }
|
||||||
secondary = LightGrey,
|
|
||||||
tertiary = Color.Black,
|
|
||||||
background = Color.White,
|
|
||||||
onBackground = Color.Black,
|
|
||||||
surface = Color.White,
|
|
||||||
surfaceVariant = SystemGrey5Light,
|
|
||||||
onSurface = Color.Black,
|
|
||||||
onSurfaceVariant = Color.Black,
|
|
||||||
|
|
||||||
/* Other default colors to override
|
|
||||||
background = Color(0xFFFFFBFE),
|
|
||||||
surface = Color(0xFFFFFBFE),
|
|
||||||
onPrimary = Color.White,
|
|
||||||
onSecondary = Color.White,
|
|
||||||
onTertiary = Color.White,
|
|
||||||
onBackground = Color(0xFF1C1B1F),
|
|
||||||
onSurface = Color(0xFF1C1B1F),
|
|
||||||
*/
|
|
||||||
)
|
|
||||||
@Suppress("CompositionLocalAllowlist")
|
|
||||||
val LocalIsDarkTheme = compositionLocalOf<Boolean> { error("Not defined") }
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun ElementXTheme(
|
fun ElementTheme(
|
||||||
darkTheme: Boolean = isSystemInDarkTheme(),
|
darkTheme: Boolean = isSystemInDarkTheme(),
|
||||||
// Dynamic color is available on Android 12+
|
dynamicColor: Boolean = false, /* true to enable MaterialYou */
|
||||||
dynamicColor: Boolean = false,
|
lightColors: ElementColors = elementColorsLight(),
|
||||||
content: @Composable () -> Unit
|
darkColors: ElementColors = elementColorsDark(),
|
||||||
|
materialLightColors: ColorScheme = materialColorSchemeLight,
|
||||||
|
materialDarkColors: ColorScheme = materialColorSchemeDark,
|
||||||
|
content: @Composable () -> Unit,
|
||||||
) {
|
) {
|
||||||
|
val systemUiController = rememberSystemUiController()
|
||||||
|
val useDarkIcons = !darkTheme
|
||||||
|
val currentColor = remember { if (darkTheme) darkColors else lightColors }
|
||||||
val colorScheme = when {
|
val colorScheme = when {
|
||||||
dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> {
|
dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> {
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context)
|
if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context)
|
||||||
}
|
}
|
||||||
darkTheme -> DarkColorScheme
|
darkTheme -> materialDarkColors
|
||||||
else -> LightColorScheme
|
else -> materialLightColors
|
||||||
}
|
}
|
||||||
val systemUiController = rememberSystemUiController()
|
|
||||||
val useDarkIcons = !darkTheme
|
|
||||||
|
|
||||||
SideEffect {
|
SideEffect {
|
||||||
systemUiController.setStatusBarColor(
|
systemUiController.setStatusBarColor(
|
||||||
color = colorScheme.background
|
color = colorScheme.background
|
||||||
|
|
@ -94,11 +75,13 @@ fun ElementXTheme(
|
||||||
darkIcons = useDarkIcons
|
darkIcons = useDarkIcons
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
val rememberedColors = remember { currentColor.copy() }.apply { updateColorsFrom(currentColor) }
|
||||||
CompositionLocalProvider(LocalIsDarkTheme provides darkTheme) {
|
CompositionLocalProvider(
|
||||||
|
LocalColors provides rememberedColors,
|
||||||
|
) {
|
||||||
MaterialTheme(
|
MaterialTheme(
|
||||||
colorScheme = colorScheme,
|
colorScheme = colorScheme,
|
||||||
typography = Typography,
|
// TODO typography =
|
||||||
content = content
|
content = content
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -0,0 +1,109 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2023 New Vector Ltd
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.element.android.libraries.designsystem.theme
|
||||||
|
|
||||||
|
import androidx.compose.ui.text.TextStyle
|
||||||
|
import androidx.compose.ui.text.font.FontFamily
|
||||||
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
|
import androidx.compose.ui.unit.sp
|
||||||
|
import com.airbnb.android.showkase.annotation.ShowkaseTypography
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO Provide the typo to Material3 theme.
|
||||||
|
*/
|
||||||
|
@ShowkaseTypography(name = "H1", group = "Element")
|
||||||
|
val h1Default: TextStyle = TextStyle(
|
||||||
|
fontFamily = FontFamily.SansSerif,
|
||||||
|
fontWeight = FontWeight.Bold,
|
||||||
|
fontSize = 24.sp
|
||||||
|
)
|
||||||
|
|
||||||
|
@ShowkaseTypography(name = "Body1", group = "Element")
|
||||||
|
val body1Default: TextStyle = TextStyle(
|
||||||
|
fontFamily = FontFamily.SansSerif,
|
||||||
|
fontWeight = FontWeight.Normal,
|
||||||
|
fontSize = 16.sp
|
||||||
|
)
|
||||||
|
|
||||||
|
@ShowkaseTypography(name = "BodySmall", group = "Element")
|
||||||
|
val bodySmallDefault: TextStyle = TextStyle(
|
||||||
|
fontFamily = FontFamily.SansSerif,
|
||||||
|
fontWeight = FontWeight.Normal,
|
||||||
|
fontSize = 14.sp
|
||||||
|
)
|
||||||
|
|
||||||
|
@ShowkaseTypography(name = "bodyMedium", group = "Element")
|
||||||
|
val bodyMediumDefault: TextStyle = TextStyle(
|
||||||
|
fontFamily = FontFamily.SansSerif,
|
||||||
|
fontWeight = FontWeight.Normal,
|
||||||
|
fontSize = 18.sp
|
||||||
|
)
|
||||||
|
|
||||||
|
@ShowkaseTypography(name = "Body Large", group = "Element")
|
||||||
|
val bodyLargeDefault: TextStyle = TextStyle(
|
||||||
|
fontFamily = FontFamily.Default,
|
||||||
|
fontWeight = FontWeight.Normal,
|
||||||
|
fontSize = 16.sp,
|
||||||
|
lineHeight = 24.sp,
|
||||||
|
letterSpacing = 0.5.sp
|
||||||
|
)
|
||||||
|
|
||||||
|
@ShowkaseTypography(name = "Headline Small", group = "Element")
|
||||||
|
val headlineSmallDefault: TextStyle = TextStyle(
|
||||||
|
fontFamily = FontFamily.Default,
|
||||||
|
fontWeight = FontWeight.Bold,
|
||||||
|
fontSize = 24.sp,
|
||||||
|
lineHeight = 30.sp,
|
||||||
|
letterSpacing = 1.sp
|
||||||
|
)
|
||||||
|
|
||||||
|
@ShowkaseTypography(name = "Headline Medium", group = "Element")
|
||||||
|
val headlineMediumDefault: TextStyle = TextStyle(
|
||||||
|
fontFamily = FontFamily.Default,
|
||||||
|
fontWeight = FontWeight.Bold,
|
||||||
|
fontSize = 28.sp,
|
||||||
|
lineHeight = 34.sp,
|
||||||
|
letterSpacing = 1.sp
|
||||||
|
)
|
||||||
|
|
||||||
|
@ShowkaseTypography(name = "Headline Large", group = "Element")
|
||||||
|
val headlineLargeDefault: TextStyle = TextStyle(
|
||||||
|
fontFamily = FontFamily.Default,
|
||||||
|
fontWeight = FontWeight.Bold,
|
||||||
|
fontSize = 32.sp,
|
||||||
|
lineHeight = 38.sp,
|
||||||
|
letterSpacing = 1.sp
|
||||||
|
)
|
||||||
|
|
||||||
|
@ShowkaseTypography(name = "titleSmall", group = "Element")
|
||||||
|
val titleSmallDefault: TextStyle = TextStyle(
|
||||||
|
fontFamily = FontFamily.Default,
|
||||||
|
fontWeight = FontWeight.Normal,
|
||||||
|
fontSize = 14.sp,
|
||||||
|
lineHeight = 20.sp,
|
||||||
|
letterSpacing = 0.5.sp
|
||||||
|
)
|
||||||
|
|
||||||
|
@ShowkaseTypography(name = "titleMedium", group = "Element")
|
||||||
|
val titleMediumDefault: TextStyle = TextStyle(
|
||||||
|
fontFamily = FontFamily.Default,
|
||||||
|
fontWeight = FontWeight.Normal,
|
||||||
|
fontSize = 18.sp,
|
||||||
|
lineHeight = 24.sp,
|
||||||
|
letterSpacing = 0.5.sp
|
||||||
|
)
|
||||||
|
|
||||||
|
|
@ -0,0 +1,80 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2023 New Vector Ltd
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.element.android.libraries.designsystem.theme.components
|
||||||
|
|
||||||
|
import androidx.compose.foundation.BorderStroke
|
||||||
|
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.PaddingValues
|
||||||
|
import androidx.compose.foundation.layout.RowScope
|
||||||
|
import androidx.compose.material3.ButtonColors
|
||||||
|
import androidx.compose.material3.ButtonDefaults
|
||||||
|
import androidx.compose.material3.ButtonElevation
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.Shape
|
||||||
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
|
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
|
||||||
|
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun Button(
|
||||||
|
onClick: () -> Unit,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
enabled: Boolean = true,
|
||||||
|
shape: Shape = ButtonDefaults.shape,
|
||||||
|
colors: ButtonColors = ButtonDefaults.buttonColors(),
|
||||||
|
elevation: ButtonElevation? = ButtonDefaults.buttonElevation(),
|
||||||
|
border: BorderStroke? = null,
|
||||||
|
contentPadding: PaddingValues = ButtonDefaults.ContentPadding,
|
||||||
|
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
|
||||||
|
content: @Composable RowScope.() -> Unit
|
||||||
|
) {
|
||||||
|
androidx.compose.material3.Button(
|
||||||
|
onClick = onClick,
|
||||||
|
modifier = modifier,
|
||||||
|
enabled = enabled,
|
||||||
|
shape = shape,
|
||||||
|
colors = colors,
|
||||||
|
elevation = elevation,
|
||||||
|
border = border,
|
||||||
|
contentPadding = contentPadding,
|
||||||
|
interactionSource = interactionSource,
|
||||||
|
content = content,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
fun ButtonsLightPreview() = ElementPreviewLight { ContentToPreview() }
|
||||||
|
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
fun ButtonsDarkPreview() = ElementPreviewDark { ContentToPreview() }
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun ContentToPreview() {
|
||||||
|
Column {
|
||||||
|
Button(onClick = {}, enabled = true) {
|
||||||
|
Text(text = "Click me! - Enabled")
|
||||||
|
}
|
||||||
|
Button(onClick = {}, enabled = false) {
|
||||||
|
Text(text = "Click me! - Disabled")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,65 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2023 New Vector Ltd
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.element.android.libraries.designsystem.theme.components
|
||||||
|
|
||||||
|
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.material3.CheckboxColors
|
||||||
|
import androidx.compose.material3.CheckboxDefaults
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
|
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
|
||||||
|
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun Checkbox(
|
||||||
|
checked: Boolean,
|
||||||
|
onCheckedChange: ((Boolean) -> Unit)?,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
enabled: Boolean = true,
|
||||||
|
colors: CheckboxColors = CheckboxDefaults.colors(),
|
||||||
|
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() }
|
||||||
|
) {
|
||||||
|
androidx.compose.material3.Checkbox(
|
||||||
|
checked = checked,
|
||||||
|
onCheckedChange = onCheckedChange,
|
||||||
|
modifier = modifier,
|
||||||
|
enabled = enabled,
|
||||||
|
colors = colors,
|
||||||
|
interactionSource = interactionSource,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
fun CheckboxesLightPreview() = ElementPreviewLight { ContentToPreview() }
|
||||||
|
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
fun CheckboxesDarkPreview() = ElementPreviewDark { ContentToPreview() }
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun ContentToPreview() {
|
||||||
|
Column {
|
||||||
|
Checkbox(onCheckedChange = {}, enabled = true, checked = true)
|
||||||
|
Checkbox(onCheckedChange = {}, enabled = true, checked = false)
|
||||||
|
Checkbox(onCheckedChange = {}, enabled = false, checked = true)
|
||||||
|
Checkbox(onCheckedChange = {}, enabled = false, checked = false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,51 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2023 New Vector Ltd
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.element.android.libraries.designsystem.theme.components
|
||||||
|
|
||||||
|
import androidx.compose.material3.ProgressIndicatorDefaults
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.unit.Dp
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun CircularProgressIndicator(
|
||||||
|
progress: Float,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
color: Color = ProgressIndicatorDefaults.circularColor,
|
||||||
|
strokeWidth: Dp = ProgressIndicatorDefaults.CircularStrokeWidth
|
||||||
|
) {
|
||||||
|
androidx.compose.material3.CircularProgressIndicator(
|
||||||
|
modifier = modifier,
|
||||||
|
progress = progress,
|
||||||
|
color = color,
|
||||||
|
strokeWidth = strokeWidth,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun CircularProgressIndicator(
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
color: Color = ProgressIndicatorDefaults.circularColor,
|
||||||
|
strokeWidth: Dp = ProgressIndicatorDefaults.CircularStrokeWidth,
|
||||||
|
) {
|
||||||
|
androidx.compose.material3.CircularProgressIndicator(
|
||||||
|
modifier = modifier,
|
||||||
|
color = color,
|
||||||
|
strokeWidth = strokeWidth,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,52 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2023 New Vector Ltd
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.element.android.libraries.designsystem.theme.components
|
||||||
|
|
||||||
|
import androidx.compose.material3.DividerDefaults
|
||||||
|
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 io.element.android.libraries.designsystem.preview.ElementPreviewDark
|
||||||
|
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun Divider(
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
thickness: Dp = DividerDefaults.Thickness,
|
||||||
|
color: Color = DividerDefaults.color,
|
||||||
|
) {
|
||||||
|
androidx.compose.material3.Divider(
|
||||||
|
modifier = modifier,
|
||||||
|
thickness = thickness,
|
||||||
|
color = color,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
fun DividerLightPreview() = ElementPreviewLight { ContentToPreview() }
|
||||||
|
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
fun DividerDarkPreview() = ElementPreviewDark { ContentToPreview() }
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun ContentToPreview() {
|
||||||
|
Divider()
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,50 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2023 New Vector Ltd
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.element.android.libraries.designsystem.theme.components
|
||||||
|
|
||||||
|
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||||
|
import androidx.compose.material3.FloatingActionButtonDefaults
|
||||||
|
import androidx.compose.material3.FloatingActionButtonElevation
|
||||||
|
import androidx.compose.material3.contentColorFor
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.graphics.Shape
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun FloatingActionButton(
|
||||||
|
onClick: () -> Unit,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
shape: Shape = FloatingActionButtonDefaults.shape,
|
||||||
|
containerColor: Color = FloatingActionButtonDefaults.containerColor,
|
||||||
|
contentColor: Color = contentColorFor(containerColor),
|
||||||
|
elevation: FloatingActionButtonElevation = FloatingActionButtonDefaults.elevation(),
|
||||||
|
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
|
||||||
|
content: @Composable () -> Unit,
|
||||||
|
) {
|
||||||
|
androidx.compose.material3.FloatingActionButton(
|
||||||
|
onClick = onClick,
|
||||||
|
modifier = modifier,
|
||||||
|
shape = shape,
|
||||||
|
containerColor = containerColor,
|
||||||
|
contentColor = contentColor,
|
||||||
|
elevation = elevation,
|
||||||
|
interactionSource = interactionSource,
|
||||||
|
content = content,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,54 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2023 New Vector Ltd
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.element.android.libraries.designsystem.theme.components
|
||||||
|
|
||||||
|
import androidx.compose.material3.LocalContentColor
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.graphics.ImageBitmap
|
||||||
|
import androidx.compose.ui.graphics.vector.ImageVector
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun Icon(
|
||||||
|
imageVector: ImageVector,
|
||||||
|
contentDescription: String?,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
tint: Color = LocalContentColor.current
|
||||||
|
) {
|
||||||
|
androidx.compose.material3.Icon(
|
||||||
|
imageVector = imageVector,
|
||||||
|
contentDescription = contentDescription,
|
||||||
|
modifier = modifier,
|
||||||
|
tint = tint,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun Icon(
|
||||||
|
bitmap: ImageBitmap,
|
||||||
|
contentDescription: String?,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
tint: Color = LocalContentColor.current
|
||||||
|
) {
|
||||||
|
androidx.compose.material3.Icon(
|
||||||
|
bitmap = bitmap,
|
||||||
|
contentDescription = contentDescription,
|
||||||
|
modifier = modifier,
|
||||||
|
tint = tint,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,41 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2023 New Vector Ltd
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.element.android.libraries.designsystem.theme.components
|
||||||
|
|
||||||
|
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||||
|
import androidx.compose.material3.IconButtonDefaults
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun IconButton(
|
||||||
|
onClick: () -> Unit,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
enabled: Boolean = true,
|
||||||
|
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
|
||||||
|
content: @Composable () -> Unit
|
||||||
|
) {
|
||||||
|
androidx.compose.material3.IconButton(
|
||||||
|
onClick = onClick,
|
||||||
|
modifier = modifier,
|
||||||
|
enabled = enabled,
|
||||||
|
colors = IconButtonDefaults.iconButtonColors(),
|
||||||
|
interactionSource = interactionSource,
|
||||||
|
content = content,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,48 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2023 New Vector Ltd
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.element.android.libraries.designsystem.theme.components
|
||||||
|
|
||||||
|
import androidx.compose.foundation.layout.RowScope
|
||||||
|
import androidx.compose.foundation.layout.WindowInsets
|
||||||
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
|
import androidx.compose.material3.TopAppBarColors
|
||||||
|
import androidx.compose.material3.TopAppBarDefaults
|
||||||
|
import androidx.compose.material3.TopAppBarScrollBehavior
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
|
||||||
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
|
@Composable
|
||||||
|
fun MediumTopAppBar(
|
||||||
|
title: @Composable () -> Unit,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
navigationIcon: @Composable () -> Unit = {},
|
||||||
|
actions: @Composable RowScope.() -> Unit = {},
|
||||||
|
windowInsets: WindowInsets = TopAppBarDefaults.windowInsets,
|
||||||
|
colors: TopAppBarColors = TopAppBarDefaults.mediumTopAppBarColors(),
|
||||||
|
scrollBehavior: TopAppBarScrollBehavior? = null
|
||||||
|
) {
|
||||||
|
androidx.compose.material3.MediumTopAppBar(
|
||||||
|
title = title,
|
||||||
|
modifier = modifier,
|
||||||
|
navigationIcon = navigationIcon,
|
||||||
|
actions = actions,
|
||||||
|
windowInsets = windowInsets,
|
||||||
|
colors = colors,
|
||||||
|
scrollBehavior = scrollBehavior,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,57 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2023 New Vector Ltd
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.element.android.libraries.designsystem.theme.components
|
||||||
|
|
||||||
|
import androidx.compose.foundation.layout.ColumnScope
|
||||||
|
import androidx.compose.material.ExperimentalMaterialApi
|
||||||
|
import androidx.compose.material.MaterialTheme
|
||||||
|
import androidx.compose.material.ModalBottomSheetDefaults
|
||||||
|
import androidx.compose.material.ModalBottomSheetState
|
||||||
|
import androidx.compose.material.ModalBottomSheetValue
|
||||||
|
import androidx.compose.material.contentColorFor
|
||||||
|
import androidx.compose.material.rememberModalBottomSheetState
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.graphics.Shape
|
||||||
|
import androidx.compose.ui.unit.Dp
|
||||||
|
|
||||||
|
@OptIn(ExperimentalMaterialApi::class)
|
||||||
|
@Composable
|
||||||
|
fun ModalBottomSheetLayout(
|
||||||
|
sheetContent: @Composable ColumnScope.() -> Unit,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
sheetState: ModalBottomSheetState = rememberModalBottomSheetState(ModalBottomSheetValue.Hidden),
|
||||||
|
sheetShape: Shape = MaterialTheme.shapes.large,
|
||||||
|
sheetElevation: Dp = ModalBottomSheetDefaults.Elevation,
|
||||||
|
sheetBackgroundColor: Color = MaterialTheme.colors.surface,
|
||||||
|
sheetContentColor: Color = contentColorFor(sheetBackgroundColor),
|
||||||
|
scrimColor: Color = ModalBottomSheetDefaults.scrimColor,
|
||||||
|
content: @Composable () -> Unit = {}
|
||||||
|
) {
|
||||||
|
androidx.compose.material.ModalBottomSheetLayout(
|
||||||
|
sheetContent = sheetContent,
|
||||||
|
modifier = modifier,
|
||||||
|
sheetState = sheetState,
|
||||||
|
sheetShape = sheetShape,
|
||||||
|
sheetElevation = sheetElevation,
|
||||||
|
sheetBackgroundColor = sheetBackgroundColor,
|
||||||
|
sheetContentColor = sheetContentColor,
|
||||||
|
scrimColor = scrimColor,
|
||||||
|
content = content,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,105 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2023 New Vector Ltd
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.element.android.libraries.designsystem.theme.components
|
||||||
|
|
||||||
|
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.text.KeyboardActions
|
||||||
|
import androidx.compose.foundation.text.KeyboardOptions
|
||||||
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
|
import androidx.compose.material3.LocalTextStyle
|
||||||
|
import androidx.compose.material3.TextFieldColors
|
||||||
|
import androidx.compose.material3.TextFieldDefaults
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.Shape
|
||||||
|
import androidx.compose.ui.text.TextStyle
|
||||||
|
import androidx.compose.ui.text.input.VisualTransformation
|
||||||
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
|
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
|
||||||
|
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
|
||||||
|
|
||||||
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
|
@Composable
|
||||||
|
fun OutlinedTextField(
|
||||||
|
value: String,
|
||||||
|
onValueChange: (String) -> Unit,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
enabled: Boolean = true,
|
||||||
|
readOnly: Boolean = false,
|
||||||
|
textStyle: TextStyle = LocalTextStyle.current,
|
||||||
|
label: @Composable (() -> Unit)? = null,
|
||||||
|
placeholder: @Composable (() -> Unit)? = null,
|
||||||
|
leadingIcon: @Composable (() -> Unit)? = null,
|
||||||
|
trailingIcon: @Composable (() -> Unit)? = null,
|
||||||
|
supportingText: @Composable (() -> Unit)? = null,
|
||||||
|
isError: Boolean = false,
|
||||||
|
visualTransformation: VisualTransformation = VisualTransformation.None,
|
||||||
|
keyboardOptions: KeyboardOptions = KeyboardOptions.Default,
|
||||||
|
keyboardActions: KeyboardActions = KeyboardActions.Default,
|
||||||
|
singleLine: Boolean = false,
|
||||||
|
maxLines: Int = Int.MAX_VALUE,
|
||||||
|
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
|
||||||
|
shape: Shape = TextFieldDefaults.outlinedShape,
|
||||||
|
colors: TextFieldColors = TextFieldDefaults.outlinedTextFieldColors()
|
||||||
|
) {
|
||||||
|
androidx.compose.material3.OutlinedTextField(
|
||||||
|
value = value,
|
||||||
|
onValueChange = onValueChange,
|
||||||
|
modifier = modifier,
|
||||||
|
enabled = enabled,
|
||||||
|
readOnly = readOnly,
|
||||||
|
textStyle = textStyle,
|
||||||
|
label = label,
|
||||||
|
placeholder = placeholder,
|
||||||
|
leadingIcon = leadingIcon,
|
||||||
|
trailingIcon = trailingIcon,
|
||||||
|
supportingText = supportingText,
|
||||||
|
isError = isError,
|
||||||
|
visualTransformation = visualTransformation,
|
||||||
|
keyboardOptions = keyboardOptions,
|
||||||
|
keyboardActions = keyboardActions,
|
||||||
|
singleLine = singleLine,
|
||||||
|
maxLines = maxLines,
|
||||||
|
interactionSource = interactionSource,
|
||||||
|
shape = shape,
|
||||||
|
colors = colors,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
fun OutlinedTextFieldsLightPreview() = ElementPreviewLight { ContentToPreview() }
|
||||||
|
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
fun OutlinedTextFieldsDarkPreview() = ElementPreviewDark { ContentToPreview() }
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun ContentToPreview() {
|
||||||
|
Column {
|
||||||
|
OutlinedTextField(onValueChange = {}, value = "Content", isError = false, enabled = true, readOnly = true)
|
||||||
|
OutlinedTextField(onValueChange = {}, value = "Content", isError = false, enabled = true, readOnly = false)
|
||||||
|
OutlinedTextField(onValueChange = {}, value = "Content", isError = false, enabled = false, readOnly = true)
|
||||||
|
OutlinedTextField(onValueChange = {}, value = "Content", isError = false, enabled = false, readOnly = false)
|
||||||
|
OutlinedTextField(onValueChange = {}, value = "Content", isError = true, enabled = true, readOnly = true)
|
||||||
|
OutlinedTextField(onValueChange = {}, value = "Content", isError = true, enabled = true, readOnly = false)
|
||||||
|
OutlinedTextField(onValueChange = {}, value = "Content", isError = true, enabled = false, readOnly = true)
|
||||||
|
OutlinedTextField(onValueChange = {}, value = "Content", isError = true, enabled = false, readOnly = false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,56 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2023 New Vector Ltd
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.element.android.libraries.designsystem.theme.components
|
||||||
|
|
||||||
|
import androidx.compose.foundation.layout.PaddingValues
|
||||||
|
import androidx.compose.foundation.layout.WindowInsets
|
||||||
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
|
import androidx.compose.material3.FabPosition
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.material3.ScaffoldDefaults
|
||||||
|
import androidx.compose.material3.contentColorFor
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
|
||||||
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
|
@Composable
|
||||||
|
fun Scaffold(
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
topBar: @Composable () -> Unit = {},
|
||||||
|
bottomBar: @Composable () -> Unit = {},
|
||||||
|
snackbarHost: @Composable () -> Unit = {},
|
||||||
|
floatingActionButton: @Composable () -> Unit = {},
|
||||||
|
floatingActionButtonPosition: FabPosition = FabPosition.End,
|
||||||
|
containerColor: Color = MaterialTheme.colorScheme.background,
|
||||||
|
contentColor: Color = contentColorFor(containerColor),
|
||||||
|
contentWindowInsets: WindowInsets = ScaffoldDefaults.contentWindowInsets,
|
||||||
|
content: @Composable (PaddingValues) -> Unit
|
||||||
|
) {
|
||||||
|
androidx.compose.material3.Scaffold(
|
||||||
|
modifier = modifier,
|
||||||
|
topBar = topBar,
|
||||||
|
bottomBar = bottomBar,
|
||||||
|
snackbarHost = snackbarHost,
|
||||||
|
floatingActionButton = floatingActionButton,
|
||||||
|
floatingActionButtonPosition = floatingActionButtonPosition,
|
||||||
|
containerColor = containerColor,
|
||||||
|
contentColor = contentColor,
|
||||||
|
contentWindowInsets = contentWindowInsets,
|
||||||
|
content = content,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,70 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2023 New Vector Ltd
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.element.android.libraries.designsystem.theme.components
|
||||||
|
|
||||||
|
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.material3.SliderColors
|
||||||
|
import androidx.compose.material3.SliderDefaults
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
|
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
|
||||||
|
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun Slider(
|
||||||
|
value: Float,
|
||||||
|
onValueChange: (Float) -> Unit,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
enabled: Boolean = true,
|
||||||
|
valueRange: ClosedFloatingPointRange<Float> = 0f..1f,
|
||||||
|
/*@IntRange(from = 0)*/
|
||||||
|
steps: Int = 0,
|
||||||
|
onValueChangeFinished: (() -> Unit)? = null,
|
||||||
|
colors: SliderColors = SliderDefaults.colors(),
|
||||||
|
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() }
|
||||||
|
) {
|
||||||
|
androidx.compose.material3.Slider(
|
||||||
|
value = value,
|
||||||
|
onValueChange = onValueChange,
|
||||||
|
modifier = modifier,
|
||||||
|
enabled = enabled,
|
||||||
|
valueRange = valueRange,
|
||||||
|
steps = steps,
|
||||||
|
onValueChangeFinished = onValueChangeFinished,
|
||||||
|
colors = colors,
|
||||||
|
interactionSource = interactionSource,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
fun SlidersLightPreview() = ElementPreviewLight { ContentToPreview() }
|
||||||
|
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
fun SlidersDarkPreview() = ElementPreviewDark { ContentToPreview() }
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun ContentToPreview() {
|
||||||
|
Column {
|
||||||
|
Slider(onValueChange = {}, value = 0.33f, enabled = true)
|
||||||
|
Slider(onValueChange = {}, value = 0.33f, enabled = false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,51 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2023 New Vector Ltd
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.element.android.libraries.designsystem.theme.components
|
||||||
|
|
||||||
|
import androidx.compose.foundation.BorderStroke
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.material3.contentColorFor
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.graphics.RectangleShape
|
||||||
|
import androidx.compose.ui.graphics.Shape
|
||||||
|
import androidx.compose.ui.unit.Dp
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun Surface(
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
shape: Shape = RectangleShape,
|
||||||
|
color: Color = MaterialTheme.colorScheme.surface,
|
||||||
|
contentColor: Color = contentColorFor(color),
|
||||||
|
tonalElevation: Dp = 0.dp,
|
||||||
|
shadowElevation: Dp = 0.dp,
|
||||||
|
border: BorderStroke? = null,
|
||||||
|
content: @Composable () -> Unit
|
||||||
|
) {
|
||||||
|
androidx.compose.material3.Surface(
|
||||||
|
modifier = modifier,
|
||||||
|
shape = shape,
|
||||||
|
color = color,
|
||||||
|
contentColor = contentColor,
|
||||||
|
tonalElevation = tonalElevation,
|
||||||
|
shadowElevation = shadowElevation,
|
||||||
|
border = border,
|
||||||
|
content = content,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,178 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2023 New Vector Ltd
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.element.android.libraries.designsystem.theme.components
|
||||||
|
|
||||||
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.IntrinsicSize
|
||||||
|
import androidx.compose.foundation.layout.Spacer
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.height
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.layout.width
|
||||||
|
import androidx.compose.foundation.text.InlineTextContent
|
||||||
|
import androidx.compose.material3.LocalTextStyle
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.material3.contentColorFor
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.text.AnnotatedString
|
||||||
|
import androidx.compose.ui.text.TextLayoutResult
|
||||||
|
import androidx.compose.ui.text.TextStyle
|
||||||
|
import androidx.compose.ui.text.font.FontFamily
|
||||||
|
import androidx.compose.ui.text.font.FontStyle
|
||||||
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
|
import androidx.compose.ui.text.style.TextDecoration
|
||||||
|
import androidx.compose.ui.text.style.TextOverflow
|
||||||
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
|
import androidx.compose.ui.unit.TextUnit
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
|
||||||
|
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
|
||||||
|
import io.element.android.libraries.designsystem.utils.toHrf
|
||||||
|
import kotlinx.collections.immutable.ImmutableMap
|
||||||
|
import kotlinx.collections.immutable.persistentMapOf
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun Text(
|
||||||
|
text: String,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
color: Color = Color.Unspecified,
|
||||||
|
fontSize: TextUnit = TextUnit.Unspecified,
|
||||||
|
fontStyle: FontStyle? = null,
|
||||||
|
fontWeight: FontWeight? = null,
|
||||||
|
fontFamily: FontFamily? = null,
|
||||||
|
letterSpacing: TextUnit = TextUnit.Unspecified,
|
||||||
|
textDecoration: TextDecoration? = null,
|
||||||
|
textAlign: TextAlign? = null,
|
||||||
|
lineHeight: TextUnit = TextUnit.Unspecified,
|
||||||
|
overflow: TextOverflow = TextOverflow.Clip,
|
||||||
|
softWrap: Boolean = true,
|
||||||
|
maxLines: Int = Int.MAX_VALUE,
|
||||||
|
onTextLayout: (TextLayoutResult) -> Unit = {},
|
||||||
|
style: TextStyle = LocalTextStyle.current
|
||||||
|
) {
|
||||||
|
androidx.compose.material3.Text(
|
||||||
|
text = text,
|
||||||
|
modifier = modifier,
|
||||||
|
color = color,
|
||||||
|
fontSize = fontSize,
|
||||||
|
fontStyle = fontStyle,
|
||||||
|
fontWeight = fontWeight,
|
||||||
|
fontFamily = fontFamily,
|
||||||
|
letterSpacing = letterSpacing,
|
||||||
|
textDecoration = textDecoration,
|
||||||
|
textAlign = textAlign,
|
||||||
|
lineHeight = lineHeight,
|
||||||
|
overflow = overflow,
|
||||||
|
softWrap = softWrap,
|
||||||
|
maxLines = maxLines,
|
||||||
|
onTextLayout = onTextLayout,
|
||||||
|
style = style,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun Text(
|
||||||
|
text: AnnotatedString,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
color: Color = Color.Unspecified,
|
||||||
|
fontSize: TextUnit = TextUnit.Unspecified,
|
||||||
|
fontStyle: FontStyle? = null,
|
||||||
|
fontWeight: FontWeight? = null,
|
||||||
|
fontFamily: FontFamily? = null,
|
||||||
|
letterSpacing: TextUnit = TextUnit.Unspecified,
|
||||||
|
textDecoration: TextDecoration? = null,
|
||||||
|
textAlign: TextAlign? = null,
|
||||||
|
lineHeight: TextUnit = TextUnit.Unspecified,
|
||||||
|
overflow: TextOverflow = TextOverflow.Clip,
|
||||||
|
softWrap: Boolean = true,
|
||||||
|
maxLines: Int = Int.MAX_VALUE,
|
||||||
|
inlineContent: ImmutableMap<String, InlineTextContent> = persistentMapOf(),
|
||||||
|
onTextLayout: (TextLayoutResult) -> Unit = {},
|
||||||
|
style: TextStyle = LocalTextStyle.current
|
||||||
|
) {
|
||||||
|
androidx.compose.material3.Text(
|
||||||
|
text = text,
|
||||||
|
modifier = modifier,
|
||||||
|
color = color,
|
||||||
|
fontSize = fontSize,
|
||||||
|
fontStyle = fontStyle,
|
||||||
|
fontWeight = fontWeight,
|
||||||
|
fontFamily = fontFamily,
|
||||||
|
letterSpacing = letterSpacing,
|
||||||
|
textDecoration = textDecoration,
|
||||||
|
textAlign = textAlign,
|
||||||
|
lineHeight = lineHeight,
|
||||||
|
overflow = overflow,
|
||||||
|
softWrap = softWrap,
|
||||||
|
maxLines = maxLines,
|
||||||
|
inlineContent = inlineContent,
|
||||||
|
onTextLayout = onTextLayout,
|
||||||
|
style = style,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
fun TextLightPreview() = ElementPreviewLight { ContentToPreview() }
|
||||||
|
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
fun TextDarkPreview() = ElementPreviewDark { ContentToPreview() }
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun ContentToPreview() {
|
||||||
|
val colors = mapOf(
|
||||||
|
"primary" to MaterialTheme.colorScheme.primary,
|
||||||
|
"secondary" to MaterialTheme.colorScheme.secondary,
|
||||||
|
"tertiary" to MaterialTheme.colorScheme.tertiary,
|
||||||
|
"background" to MaterialTheme.colorScheme.background,
|
||||||
|
"error" to MaterialTheme.colorScheme.error,
|
||||||
|
"surface" to MaterialTheme.colorScheme.surface,
|
||||||
|
"surfaceVariant" to MaterialTheme.colorScheme.surfaceVariant,
|
||||||
|
"primaryContainer" to MaterialTheme.colorScheme.primaryContainer,
|
||||||
|
"secondaryContainer" to MaterialTheme.colorScheme.secondaryContainer,
|
||||||
|
"tertiaryContainer" to MaterialTheme.colorScheme.tertiaryContainer,
|
||||||
|
// "inversePrimary" to MaterialTheme.colorScheme.inversePrimary,
|
||||||
|
"errorContainer" to MaterialTheme.colorScheme.errorContainer,
|
||||||
|
"inverseSurface" to MaterialTheme.colorScheme.inverseSurface,
|
||||||
|
)
|
||||||
|
Column(
|
||||||
|
modifier = Modifier.width(IntrinsicSize.Max)
|
||||||
|
) {
|
||||||
|
colors.keys.forEach { name ->
|
||||||
|
val color = colors[name]!!
|
||||||
|
val textColor = contentColorFor(backgroundColor = color)
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.background(color = color)
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(2.dp)
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = "Text on $name\n${textColor.toHrf()} on ${color.toHrf()}",
|
||||||
|
color = textColor,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Spacer(modifier = Modifier.height(2.dp))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,79 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2023 New Vector Ltd
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.element.android.libraries.designsystem.theme.components
|
||||||
|
|
||||||
|
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||||
|
import androidx.compose.foundation.text.KeyboardActions
|
||||||
|
import androidx.compose.foundation.text.KeyboardOptions
|
||||||
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
|
import androidx.compose.material3.LocalTextStyle
|
||||||
|
import androidx.compose.material3.TextFieldColors
|
||||||
|
import androidx.compose.material3.TextFieldDefaults
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.Shape
|
||||||
|
import androidx.compose.ui.text.TextStyle
|
||||||
|
import androidx.compose.ui.text.input.VisualTransformation
|
||||||
|
|
||||||
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
|
@Composable
|
||||||
|
fun TextField(
|
||||||
|
value: String,
|
||||||
|
onValueChange: (String) -> Unit,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
enabled: Boolean = true,
|
||||||
|
readOnly: Boolean = false,
|
||||||
|
textStyle: TextStyle = LocalTextStyle.current,
|
||||||
|
label: @Composable (() -> Unit)? = null,
|
||||||
|
placeholder: @Composable (() -> Unit)? = null,
|
||||||
|
leadingIcon: @Composable (() -> Unit)? = null,
|
||||||
|
trailingIcon: @Composable (() -> Unit)? = null,
|
||||||
|
supportingText: @Composable (() -> Unit)? = null,
|
||||||
|
isError: Boolean = false,
|
||||||
|
visualTransformation: VisualTransformation = VisualTransformation.None,
|
||||||
|
keyboardOptions: KeyboardOptions = KeyboardOptions.Default,
|
||||||
|
keyboardActions: KeyboardActions = KeyboardActions.Default,
|
||||||
|
singleLine: Boolean = false,
|
||||||
|
maxLines: Int = Int.MAX_VALUE,
|
||||||
|
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
|
||||||
|
shape: Shape = TextFieldDefaults.filledShape,
|
||||||
|
colors: TextFieldColors = TextFieldDefaults.textFieldColors()
|
||||||
|
) {
|
||||||
|
androidx.compose.material3.TextField(
|
||||||
|
value = value,
|
||||||
|
onValueChange = onValueChange,
|
||||||
|
modifier = modifier,
|
||||||
|
enabled = enabled,
|
||||||
|
readOnly = readOnly,
|
||||||
|
textStyle = textStyle,
|
||||||
|
label = label,
|
||||||
|
placeholder = placeholder,
|
||||||
|
leadingIcon = leadingIcon,
|
||||||
|
trailingIcon = trailingIcon,
|
||||||
|
supportingText = supportingText,
|
||||||
|
isError = isError,
|
||||||
|
visualTransformation = visualTransformation,
|
||||||
|
keyboardOptions = keyboardOptions,
|
||||||
|
keyboardActions = keyboardActions,
|
||||||
|
singleLine = singleLine,
|
||||||
|
maxLines = maxLines,
|
||||||
|
interactionSource = interactionSource,
|
||||||
|
shape = shape,
|
||||||
|
colors = colors,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,48 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2023 New Vector Ltd
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.element.android.libraries.designsystem.theme.components
|
||||||
|
|
||||||
|
import androidx.compose.foundation.layout.RowScope
|
||||||
|
import androidx.compose.foundation.layout.WindowInsets
|
||||||
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
|
import androidx.compose.material3.TopAppBarColors
|
||||||
|
import androidx.compose.material3.TopAppBarDefaults
|
||||||
|
import androidx.compose.material3.TopAppBarScrollBehavior
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
|
||||||
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
|
@Composable
|
||||||
|
fun TopAppBar(
|
||||||
|
title: @Composable () -> Unit,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
navigationIcon: @Composable () -> Unit = {},
|
||||||
|
actions: @Composable RowScope.() -> Unit = {},
|
||||||
|
windowInsets: WindowInsets = TopAppBarDefaults.windowInsets,
|
||||||
|
colors: TopAppBarColors = TopAppBarDefaults.smallTopAppBarColors(),
|
||||||
|
scrollBehavior: TopAppBarScrollBehavior? = null
|
||||||
|
) {
|
||||||
|
androidx.compose.material3.TopAppBar(
|
||||||
|
title = title,
|
||||||
|
modifier = modifier,
|
||||||
|
navigationIcon = navigationIcon,
|
||||||
|
actions = actions,
|
||||||
|
windowInsets = windowInsets,
|
||||||
|
colors = colors,
|
||||||
|
scrollBehavior = scrollBehavior,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,47 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2023 New Vector Ltd
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.element.android.libraries.designsystem.theme.previews
|
||||||
|
|
||||||
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.Spacer
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.height
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
internal fun ColorListPreview(
|
||||||
|
backgroundColor: Color,
|
||||||
|
foregroundColor: Color,
|
||||||
|
colors: Map<String, Color>,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
) {
|
||||||
|
Column(
|
||||||
|
modifier = modifier
|
||||||
|
.background(color = backgroundColor)
|
||||||
|
.fillMaxWidth()
|
||||||
|
) {
|
||||||
|
colors.keys.forEach { name ->
|
||||||
|
val color = colors[name]!!
|
||||||
|
ColorPreview(backgroundColor = backgroundColor, foregroundColor = foregroundColor, name = name, color = color)
|
||||||
|
}
|
||||||
|
Spacer(modifier = Modifier.height(2.dp))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,64 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2023 New Vector Ltd
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.element.android.libraries.designsystem.theme.previews
|
||||||
|
|
||||||
|
import androidx.compose.foundation.background
|
||||||
|
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.runtime.Composable
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.Brush
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.compose.ui.unit.sp
|
||||||
|
import io.element.android.libraries.designsystem.theme.components.Text
|
||||||
|
import io.element.android.libraries.designsystem.utils.toHrf
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
internal fun ColorPreview(
|
||||||
|
backgroundColor: Color,
|
||||||
|
foregroundColor: Color,
|
||||||
|
name: String, color: Color,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
) {
|
||||||
|
Column(modifier = modifier.fillMaxWidth()) {
|
||||||
|
Text(text = name + " " + color.toHrf(), fontSize = 6.sp, color = foregroundColor)
|
||||||
|
val backgroundBrush = Brush.linearGradient(
|
||||||
|
listOf(
|
||||||
|
backgroundColor,
|
||||||
|
foregroundColor,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
Row(
|
||||||
|
modifier = Modifier.background(backgroundBrush)
|
||||||
|
) {
|
||||||
|
repeat(2) {
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(1.dp)
|
||||||
|
.background(color = color)
|
||||||
|
.height(10.dp)
|
||||||
|
.weight(1f)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,68 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2023 New Vector Ltd
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.element.android.libraries.designsystem.theme.previews
|
||||||
|
|
||||||
|
import androidx.compose.material3.ColorScheme
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
internal fun ColorsSchemePreview(
|
||||||
|
backgroundColor: Color,
|
||||||
|
foregroundColor: Color,
|
||||||
|
colorScheme: ColorScheme,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
) {
|
||||||
|
val colors = mapOf(
|
||||||
|
"primary" to colorScheme.primary,
|
||||||
|
"onPrimary" to colorScheme.onPrimary,
|
||||||
|
"primaryContainer" to colorScheme.primaryContainer,
|
||||||
|
"onPrimaryContainer" to colorScheme.onPrimaryContainer,
|
||||||
|
"inversePrimary" to colorScheme.inversePrimary,
|
||||||
|
"secondary" to colorScheme.secondary,
|
||||||
|
"onSecondary" to colorScheme.onSecondary,
|
||||||
|
"secondaryContainer" to colorScheme.secondaryContainer,
|
||||||
|
"onSecondaryContainer" to colorScheme.onSecondaryContainer,
|
||||||
|
"tertiary" to colorScheme.tertiary,
|
||||||
|
"onTertiary" to colorScheme.onTertiary,
|
||||||
|
"tertiaryContainer" to colorScheme.tertiaryContainer,
|
||||||
|
"onTertiaryContainer" to colorScheme.onTertiaryContainer,
|
||||||
|
"background" to colorScheme.background,
|
||||||
|
"onBackground" to colorScheme.onBackground,
|
||||||
|
"surface" to colorScheme.surface,
|
||||||
|
"onSurface" to colorScheme.onSurface,
|
||||||
|
"surfaceVariant" to colorScheme.surfaceVariant,
|
||||||
|
"onSurfaceVariant" to colorScheme.onSurfaceVariant,
|
||||||
|
"surfaceTint" to colorScheme.surfaceTint,
|
||||||
|
"inverseSurface" to colorScheme.inverseSurface,
|
||||||
|
"inverseOnSurface" to colorScheme.inverseOnSurface,
|
||||||
|
"error" to colorScheme.error,
|
||||||
|
"onError" to colorScheme.onError,
|
||||||
|
"errorContainer" to colorScheme.errorContainer,
|
||||||
|
"onErrorContainer" to colorScheme.onErrorContainer,
|
||||||
|
"outline" to colorScheme.outline,
|
||||||
|
"outlineVariant" to colorScheme.outlineVariant,
|
||||||
|
"scrim" to colorScheme.scrim,
|
||||||
|
)
|
||||||
|
ColorListPreview(
|
||||||
|
backgroundColor = backgroundColor,
|
||||||
|
foregroundColor = foregroundColor,
|
||||||
|
colors = colors,
|
||||||
|
modifier = modifier,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2022 New Vector Ltd
|
* Copyright (c) 2023 New Vector Ltd
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
@ -14,20 +14,13 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package io.element.android.libraries.designsystem.components
|
package io.element.android.libraries.designsystem.utils
|
||||||
|
|
||||||
import androidx.compose.material3.Button
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.material3.Text
|
|
||||||
import androidx.compose.runtime.Composable
|
|
||||||
import androidx.compose.ui.Modifier
|
|
||||||
|
|
||||||
@Composable
|
/**
|
||||||
fun VectorButton(text: String, enabled: Boolean, onClick: () -> Unit, modifier: Modifier = Modifier) {
|
* Convert color to Human Readable Format.
|
||||||
Button(
|
*/
|
||||||
onClick = onClick,
|
internal fun Color.toHrf(): String {
|
||||||
enabled = enabled,
|
return "0x" + value.toString(16).take(8).uppercase()
|
||||||
modifier = modifier
|
|
||||||
) {
|
|
||||||
Text(text = text)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
@ -23,5 +23,5 @@ android {
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation("com.google.android.material:material:1.7.0")
|
implementation(libs.androidx.material)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,6 @@ import io.element.android.libraries.core.coroutine.CoroutineDispatchers
|
||||||
import io.element.android.libraries.matrix.sync.roomListDiff
|
import io.element.android.libraries.matrix.sync.roomListDiff
|
||||||
import io.element.android.libraries.matrix.sync.state
|
import io.element.android.libraries.matrix.sync.state
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.FlowPreview
|
|
||||||
import kotlinx.coroutines.SupervisorJob
|
import kotlinx.coroutines.SupervisorJob
|
||||||
import kotlinx.coroutines.cancel
|
import kotlinx.coroutines.cancel
|
||||||
import kotlinx.coroutines.cancelChildren
|
import kotlinx.coroutines.cancelChildren
|
||||||
|
|
@ -29,7 +28,6 @@ import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
import kotlinx.coroutines.flow.launchIn
|
import kotlinx.coroutines.flow.launchIn
|
||||||
import kotlinx.coroutines.flow.onEach
|
import kotlinx.coroutines.flow.onEach
|
||||||
import kotlinx.coroutines.flow.sample
|
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import org.matrix.rustcomponents.sdk.RoomListEntry
|
import org.matrix.rustcomponents.sdk.RoomListEntry
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,6 @@ import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.height
|
import androidx.compose.foundation.layout.height
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.Text
|
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
|
@ -36,6 +35,9 @@ import androidx.compose.ui.unit.sp
|
||||||
import io.element.android.libraries.designsystem.components.avatar.Avatar
|
import io.element.android.libraries.designsystem.components.avatar.Avatar
|
||||||
import io.element.android.libraries.designsystem.components.avatar.AvatarData
|
import io.element.android.libraries.designsystem.components.avatar.AvatarData
|
||||||
import io.element.android.libraries.designsystem.components.avatar.AvatarSize
|
import io.element.android.libraries.designsystem.components.avatar.AvatarSize
|
||||||
|
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
|
||||||
|
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
|
||||||
|
import io.element.android.libraries.designsystem.theme.components.Text
|
||||||
import io.element.android.libraries.matrix.core.UserId
|
import io.element.android.libraries.matrix.core.UserId
|
||||||
import io.element.android.libraries.matrix.ui.model.MatrixUser
|
import io.element.android.libraries.matrix.ui.model.MatrixUser
|
||||||
import io.element.android.libraries.matrix.ui.model.getBestName
|
import io.element.android.libraries.matrix.ui.model.getBestName
|
||||||
|
|
@ -64,8 +66,9 @@ fun MatrixUserHeader(
|
||||||
fontWeight = FontWeight.SemiBold,
|
fontWeight = FontWeight.SemiBold,
|
||||||
text = matrixUser.getBestName(),
|
text = matrixUser.getBestName(),
|
||||||
maxLines = 1,
|
maxLines = 1,
|
||||||
overflow = TextOverflow.Ellipsis
|
overflow = TextOverflow.Ellipsis,
|
||||||
)
|
color = MaterialTheme.colorScheme.primary,
|
||||||
|
)
|
||||||
// Id
|
// Id
|
||||||
if (matrixUser.username.isNullOrEmpty().not()) {
|
if (matrixUser.username.isNullOrEmpty().not()) {
|
||||||
Spacer(modifier = Modifier.height(4.dp))
|
Spacer(modifier = Modifier.height(4.dp))
|
||||||
|
|
@ -82,7 +85,14 @@ fun MatrixUserHeader(
|
||||||
|
|
||||||
@Preview
|
@Preview
|
||||||
@Composable
|
@Composable
|
||||||
fun MatrixUserHeaderPreview() {
|
fun MatrixUserHeaderLightPreview() = ElementPreviewLight { ContentToPreview1() }
|
||||||
|
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
fun MatrixUserHeaderDarkPreview() = ElementPreviewDark { ContentToPreview1() }
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun ContentToPreview1() {
|
||||||
MatrixUserHeader(
|
MatrixUserHeader(
|
||||||
MatrixUser(
|
MatrixUser(
|
||||||
id = UserId("@alice:server.org"),
|
id = UserId("@alice:server.org"),
|
||||||
|
|
@ -94,7 +104,14 @@ fun MatrixUserHeaderPreview() {
|
||||||
|
|
||||||
@Preview
|
@Preview
|
||||||
@Composable
|
@Composable
|
||||||
fun MatrixUserHeaderNoUsernamePreview() {
|
fun MatrixUserHeaderNoUserNameLightPreview() = ElementPreviewLight { ContentToPreview2() }
|
||||||
|
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
fun MatrixUserHeaderNoUserNameDarkPreview() = ElementPreviewDark { ContentToPreview2() }
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun ContentToPreview2() {
|
||||||
MatrixUserHeader(
|
MatrixUserHeader(
|
||||||
MatrixUser(
|
MatrixUser(
|
||||||
id = UserId("@alice:server.org"),
|
id = UserId("@alice:server.org"),
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,6 @@ import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.height
|
import androidx.compose.foundation.layout.height
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.Text
|
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
|
@ -35,6 +34,9 @@ import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.unit.sp
|
import androidx.compose.ui.unit.sp
|
||||||
import io.element.android.libraries.designsystem.components.avatar.Avatar
|
import io.element.android.libraries.designsystem.components.avatar.Avatar
|
||||||
import io.element.android.libraries.designsystem.components.avatar.AvatarData
|
import io.element.android.libraries.designsystem.components.avatar.AvatarData
|
||||||
|
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
|
||||||
|
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
|
||||||
|
import io.element.android.libraries.designsystem.theme.components.Text
|
||||||
import io.element.android.libraries.matrix.core.UserId
|
import io.element.android.libraries.matrix.core.UserId
|
||||||
import io.element.android.libraries.matrix.ui.model.MatrixUser
|
import io.element.android.libraries.matrix.ui.model.MatrixUser
|
||||||
import io.element.android.libraries.matrix.ui.model.getBestName
|
import io.element.android.libraries.matrix.ui.model.getBestName
|
||||||
|
|
@ -68,7 +70,8 @@ fun MatrixUserRow(
|
||||||
fontWeight = FontWeight.SemiBold,
|
fontWeight = FontWeight.SemiBold,
|
||||||
text = matrixUser.getBestName(),
|
text = matrixUser.getBestName(),
|
||||||
maxLines = 1,
|
maxLines = 1,
|
||||||
overflow = TextOverflow.Ellipsis
|
overflow = TextOverflow.Ellipsis,
|
||||||
|
color = MaterialTheme.colorScheme.primary,
|
||||||
)
|
)
|
||||||
// Id
|
// Id
|
||||||
if (matrixUser.username.isNullOrEmpty().not()) {
|
if (matrixUser.username.isNullOrEmpty().not()) {
|
||||||
|
|
@ -86,7 +89,14 @@ fun MatrixUserRow(
|
||||||
|
|
||||||
@Preview
|
@Preview
|
||||||
@Composable
|
@Composable
|
||||||
fun MatrixUserRowPreview() {
|
fun MatrixUserRowLightPreview() = ElementPreviewLight { ContentToPreview() }
|
||||||
|
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
fun MatrixUserRowDarkPreview() = ElementPreviewDark { ContentToPreview() }
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun ContentToPreview() {
|
||||||
MatrixUserRow(
|
MatrixUserRow(
|
||||||
MatrixUser(
|
MatrixUser(
|
||||||
id = UserId("@alice:server.org"),
|
id = UserId("@alice:server.org"),
|
||||||
|
|
|
||||||
|
|
@ -35,8 +35,9 @@ dependencies {
|
||||||
implementation(projects.libraries.androidutils)
|
implementation(projects.libraries.androidutils)
|
||||||
implementation(projects.libraries.core)
|
implementation(projects.libraries.core)
|
||||||
implementation(projects.libraries.matrix)
|
implementation(projects.libraries.matrix)
|
||||||
|
implementation(projects.libraries.designsystem)
|
||||||
implementation(libs.wysiwyg)
|
implementation(libs.wysiwyg)
|
||||||
implementation(libs.androidx.constraintlayout)
|
implementation(libs.androidx.constraintlayout)
|
||||||
implementation("com.google.android.material:material:1.7.0")
|
implementation(libs.androidx.material)
|
||||||
ksp(libs.showkase.processor)
|
ksp(libs.showkase.processor)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ import android.net.Uri
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.height
|
import androidx.compose.foundation.layout.height
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
|
@ -33,6 +33,9 @@ import androidx.compose.ui.unit.sp
|
||||||
import androidx.compose.ui.viewinterop.AndroidView
|
import androidx.compose.ui.viewinterop.AndroidView
|
||||||
import androidx.core.view.isInvisible
|
import androidx.core.view.isInvisible
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
|
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
|
||||||
|
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
|
||||||
|
import io.element.android.libraries.designsystem.theme.components.Text
|
||||||
import io.element.android.libraries.ui.strings.R as StringR
|
import io.element.android.libraries.ui.strings.R as StringR
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
|
|
@ -123,7 +126,8 @@ private fun FakeComposer(
|
||||||
.align(Alignment.Center),
|
.align(Alignment.Center),
|
||||||
textAlign = TextAlign.Center,
|
textAlign = TextAlign.Center,
|
||||||
text = "Composer Preview",
|
text = "Composer Preview",
|
||||||
fontSize = 20.sp
|
fontSize = 20.sp,
|
||||||
|
color = MaterialTheme.colorScheme.secondary,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -145,7 +149,14 @@ private fun MessageComposerView.setup(isDarkMode: Boolean, composerMode: Message
|
||||||
|
|
||||||
@Preview
|
@Preview
|
||||||
@Composable
|
@Composable
|
||||||
fun TextComposerPreview() {
|
fun TextComposerLightPreview() = ElementPreviewLight { ContentToPreview() }
|
||||||
|
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
fun TextComposerDarkPreview() = ElementPreviewDark { ContentToPreview() }
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun ContentToPreview() {
|
||||||
TextComposer(
|
TextComposer(
|
||||||
onSendMessage = {},
|
onSendMessage = {},
|
||||||
fullscreen = false,
|
fullscreen = false,
|
||||||
|
|
|
||||||
|
|
@ -20,10 +20,6 @@ import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.layout.size
|
import androidx.compose.foundation.layout.size
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.filled.Close
|
import androidx.compose.material.icons.filled.Close
|
||||||
import androidx.compose.material3.Button
|
|
||||||
import androidx.compose.material3.Icon
|
|
||||||
import androidx.compose.material3.IconButton
|
|
||||||
import androidx.compose.material3.Text
|
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
|
@ -32,6 +28,12 @@ import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.tooling.preview.Preview
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
|
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
|
||||||
|
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
|
||||||
|
import io.element.android.libraries.designsystem.theme.components.Button
|
||||||
|
import io.element.android.libraries.designsystem.theme.components.Icon
|
||||||
|
import io.element.android.libraries.designsystem.theme.components.IconButton
|
||||||
|
import io.element.android.libraries.designsystem.theme.components.Text
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun ShowkaseButton(
|
fun ShowkaseButton(
|
||||||
|
|
@ -59,8 +61,15 @@ fun ShowkaseButton(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Preview(group = "Buttons", name = "Showkase button")
|
@Preview
|
||||||
@Composable
|
@Composable
|
||||||
fun ShowkaseButtonPreview() {
|
fun ShowkaseButtonLightPreview() = ElementPreviewLight { ContentToPreview() }
|
||||||
|
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
fun ShowkaseButtonDarkPreview() = ElementPreviewDark { ContentToPreview() }
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun ContentToPreview() {
|
||||||
ShowkaseButton()
|
ShowkaseButton()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,7 @@ import app.cash.paparazzi.Paparazzi
|
||||||
import com.airbnb.android.showkase.models.Showkase
|
import com.airbnb.android.showkase.models.Showkase
|
||||||
import com.google.testing.junit.testparameterinjector.TestParameter
|
import com.google.testing.junit.testparameterinjector.TestParameter
|
||||||
import com.google.testing.junit.testparameterinjector.TestParameterInjector
|
import com.google.testing.junit.testparameterinjector.TestParameterInjector
|
||||||
import io.element.android.libraries.designsystem.ElementXTheme
|
import io.element.android.libraries.designsystem.theme.ElementTheme
|
||||||
import org.junit.Rule
|
import org.junit.Rule
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.junit.runner.RunWith
|
import org.junit.runner.RunWith
|
||||||
|
|
@ -75,7 +75,6 @@ class ScreenshotTest {
|
||||||
@TestParameter(valuesProvider = PreviewProvider::class) componentTestPreview: TestPreview,
|
@TestParameter(valuesProvider = PreviewProvider::class) componentTestPreview: TestPreview,
|
||||||
@TestParameter baseDeviceConfig: BaseDeviceConfig,
|
@TestParameter baseDeviceConfig: BaseDeviceConfig,
|
||||||
@TestParameter(value = ["1.0"/*, "1.5"*/]) fontScale: Float,
|
@TestParameter(value = ["1.0"/*, "1.5"*/]) fontScale: Float,
|
||||||
@TestParameter(value = ["light", "dark"]) theme: String,
|
|
||||||
@TestParameter(value = ["en" /*"fr", "de", "ru"*/]) localeStr: String,
|
@TestParameter(value = ["en" /*"fr", "de", "ru"*/]) localeStr: String,
|
||||||
) {
|
) {
|
||||||
paparazzi.unsafeUpdateConfig(
|
paparazzi.unsafeUpdateConfig(
|
||||||
|
|
@ -101,7 +100,7 @@ class ScreenshotTest {
|
||||||
override fun getOnBackPressedDispatcher() = OnBackPressedDispatcher()
|
override fun getOnBackPressedDispatcher() = OnBackPressedDispatcher()
|
||||||
}
|
}
|
||||||
) {
|
) {
|
||||||
ElementXTheme(darkTheme = (theme == "dark")) {
|
ElementTheme {
|
||||||
Box(modifier = Modifier.background(MaterialTheme.colorScheme.background)) {
|
Box(modifier = Modifier.background(MaterialTheme.colorScheme.background)) {
|
||||||
componentTestPreview.Content()
|
componentTestPreview.Content()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:e60a495255bf6048af20f1cd7365caf6ca6f5d9e97bbf1519ce469f3cccec958
|
||||||
|
size 6064
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:3025338830e0e20781a727ef61751be208d2c633e271f42fe91dbf89df43dbf5
|
||||||
|
size 6681
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:5c68a348292da117047095d945c7b3fa764e4894fbc25354a88607af33378b90
|
||||||
|
size 4775
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:a8960ee49f84a98f0c309ea2d3cc208bfdf493c8843066830ee228e0c3b25634
|
||||||
|
size 9695
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:dcfab4f43c1a796c9166116285353c4351182db3d5417f657c8a48e9798c6e87
|
||||||
|
size 9589
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:12fdbd29d34a17ceec91dd37fddb46560a9047df5a4878491443e75c1fb2ad44
|
||||||
|
size 8214
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:5334cd5b273fc2e6ac65c730bc88adf74fa6b89fda0e76009d35a75bf2790559
|
||||||
|
size 7728
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:310e8dfa7d52b5ee835243b1025a7e20ec3fb7dafee62c230c870720e91cf897
|
||||||
|
size 7044
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:7c4cbc97971b8a1561c232f14cb8600fea59527e7315bca9d225dde13cb1edd9
|
||||||
|
size 6223
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:c434e7bb1316fdd1668c9d41675ff7fe1acc62dfdc6c64e96e485155a51befc4
|
||||||
|
size 27698
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:7393dde7da886bec54405dc602e6584eca8d8617f3f28d9b00e708b0381f3c2b
|
||||||
|
size 25315
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:155e39fcadcc8bc039267a8b0dca338a92bcb3b4b23ab55a0cd9f3ef91c729fc
|
||||||
|
size 8888
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:ef86e92ea3caad3687d66458e3b0832361808692783671db54dd321d61564792
|
||||||
|
size 5836
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:674265aa2728d2f1724abcf600a573307d69d8dd77212eaf269176e56dc82fd5
|
||||||
|
size 5610
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue