Merge pull request #63 from vector-im/feature/bma/theme

Theme
This commit is contained in:
Benoit Marty 2023-02-03 16:30:58 +01:00 committed by GitHub
commit 795221f478
209 changed files with 2904 additions and 901 deletions

View file

@ -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(

View file

@ -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(

View file

@ -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 {

View file

@ -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

View file

@ -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

View file

@ -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 its 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 its 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"),
) )

View file

@ -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",

View file

@ -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())
} }

View file

@ -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

View file

@ -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,
) )
} }
) )

View file

@ -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)
} }

View file

@ -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
) )
} }

View file

@ -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(

View file

@ -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()

View file

@ -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

View file

@ -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
)
}

View file

@ -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(

View file

@ -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

View file

@ -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)
)
} }
} }
} }

View file

@ -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(),

View file

@ -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(),
) )

View file

@ -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()
) )

View file

@ -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()
} }

View file

@ -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))
} }

View file

@ -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")),

View file

@ -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(

View file

@ -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)

View file

@ -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(),
) )

View file

@ -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"

View file

@ -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)

View file

@ -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)
} }
} }

View file

@ -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 {

View file

@ -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,
) )
} }

View file

@ -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",

View file

@ -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")
} }

View file

@ -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,

View file

@ -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"))
} }

View file

@ -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",

View file

@ -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",
) )

View file

@ -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
)
} }
} }

View file

@ -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
)
}
} }
} }

View file

@ -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",

View file

@ -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
) )
} }

View file

@ -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,

View file

@ -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

View file

@ -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()
}
}
}

View file

@ -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(),
)
)
}

View file

@ -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,
)

View file

@ -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,
)

View file

@ -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
}
}

View file

@ -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
) )
} }

View file

@ -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
)

View file

@ -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")
}
}
}

View file

@ -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)
}
}

View file

@ -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,
)
}

View file

@ -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()
}

View file

@ -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,
)
}

View file

@ -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,
)
}

View file

@ -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,
)
}

View file

@ -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,
)
}

View file

@ -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,
)
}

View file

@ -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)
}
}

View file

@ -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,
)
}

View file

@ -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)
}
}

View file

@ -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,
)
}

View file

@ -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))
}
}
}

View file

@ -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,
)
}

View file

@ -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,
)
}

View file

@ -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))
}
}

View file

@ -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)
)
}
}
}
}

View file

@ -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,
)
}

View file

@ -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)
}
} }

View file

@ -23,5 +23,5 @@ android {
} }
dependencies { dependencies {
implementation("com.google.android.material:material:1.7.0") implementation(libs.androidx.material)
} }

View file

@ -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

View file

@ -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"),

View file

@ -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"),

View file

@ -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)
} }

View file

@ -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,

View file

@ -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()
} }

View file

@ -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()
} }

View file

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:e60a495255bf6048af20f1cd7365caf6ca6f5d9e97bbf1519ce469f3cccec958
size 6064

View file

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:3025338830e0e20781a727ef61751be208d2c633e271f42fe91dbf89df43dbf5
size 6681

View file

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:5c68a348292da117047095d945c7b3fa764e4894fbc25354a88607af33378b90
size 4775

View file

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:a8960ee49f84a98f0c309ea2d3cc208bfdf493c8843066830ee228e0c3b25634
size 9695

View file

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:dcfab4f43c1a796c9166116285353c4351182db3d5417f657c8a48e9798c6e87
size 9589

View file

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:12fdbd29d34a17ceec91dd37fddb46560a9047df5a4878491443e75c1fb2ad44
size 8214

View file

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:5334cd5b273fc2e6ac65c730bc88adf74fa6b89fda0e76009d35a75bf2790559
size 7728

View file

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:310e8dfa7d52b5ee835243b1025a7e20ec3fb7dafee62c230c870720e91cf897
size 7044

View file

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:7c4cbc97971b8a1561c232f14cb8600fea59527e7315bca9d225dde13cb1edd9
size 6223

View file

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:c434e7bb1316fdd1668c9d41675ff7fe1acc62dfdc6c64e96e485155a51befc4
size 27698

View file

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:7393dde7da886bec54405dc602e6584eca8d8617f3f28d9b00e708b0381f3c2b
size 25315

View file

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:155e39fcadcc8bc039267a8b0dca338a92bcb3b4b23ab55a0cd9f3ef91c729fc
size 8888

View file

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:ef86e92ea3caad3687d66458e3b0832361808692783671db54dd321d61564792
size 5836

View file

@ -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