aboutsummaryrefslogtreecommitdiff
path: root/ui/compose
diff options
context:
space:
mode:
Diffstat (limited to 'ui/compose')
-rw-r--r--ui/compose/build.gradle.kts28
-rw-r--r--ui/compose/lint-baseline.xml4
-rw-r--r--ui/compose/src/main/AndroidManifest.xml6
-rw-r--r--ui/compose/src/main/kotlin/app/passwordstore/ui/APSAppBar.kt40
-rw-r--r--ui/compose/src/main/kotlin/app/passwordstore/ui/compose/PasswordField.kt82
-rw-r--r--ui/compose/src/main/kotlin/app/passwordstore/ui/compose/theme/Color.kt58
-rw-r--r--ui/compose/src/main/kotlin/app/passwordstore/ui/compose/theme/Theme.kt77
-rw-r--r--ui/compose/src/main/kotlin/app/passwordstore/ui/compose/theme/Type.kt144
-rw-r--r--ui/compose/src/main/kotlin/app/passwordstore/ui/compose/theme/utils.kt27
-rw-r--r--ui/compose/src/main/res/drawable/baseline_visibility_24.xml10
-rw-r--r--ui/compose/src/main/res/drawable/baseline_visibility_off_24.xml10
-rw-r--r--ui/compose/src/main/res/drawable/ic_content_copy.xml15
-rw-r--r--ui/compose/src/main/res/font/manrope.xml28
-rw-r--r--ui/compose/src/main/res/font/manrope_bold.ttfbin0 -> 92228 bytes
-rw-r--r--ui/compose/src/main/res/font/manrope_extrabold.ttfbin0 -> 93144 bytes
-rw-r--r--ui/compose/src/main/res/font/manrope_extralight.ttfbin0 -> 92272 bytes
-rw-r--r--ui/compose/src/main/res/font/manrope_light.ttfbin0 -> 92400 bytes
-rw-r--r--ui/compose/src/main/res/font/manrope_medium.ttfbin0 -> 92464 bytes
-rw-r--r--ui/compose/src/main/res/font/manrope_regular.ttfbin0 -> 92376 bytes
-rw-r--r--ui/compose/src/main/res/font/manrope_semibold.ttfbin0 -> 92380 bytes
20 files changed, 529 insertions, 0 deletions
diff --git a/ui/compose/build.gradle.kts b/ui/compose/build.gradle.kts
new file mode 100644
index 00000000..21f1e469
--- /dev/null
+++ b/ui/compose/build.gradle.kts
@@ -0,0 +1,28 @@
+/*
+ * Copyright © 2014-2021 The Android Password Store Authors. All Rights Reserved.
+ * SPDX-License-Identifier: GPL-3.0-only
+ */
+plugins {
+ id("com.github.android-password-store.android-library")
+ id("com.github.android-password-store.kotlin-android")
+}
+
+android {
+ buildFeatures {
+ compose = true
+ androidResources = true
+ }
+ composeOptions {
+ useLiveLiterals = false
+ kotlinCompilerExtensionVersion = libs.versions.composeCompiler.get()
+ }
+ namespace = "app.passwordstore.ui.compose"
+}
+
+dependencies {
+ api(platform(libs.compose.bom))
+ api(libs.compose.foundation.core)
+ api(libs.compose.foundation.layout)
+ api(libs.compose.material3)
+ api(libs.compose.ui.core)
+}
diff --git a/ui/compose/lint-baseline.xml b/ui/compose/lint-baseline.xml
new file mode 100644
index 00000000..2ed8a3bb
--- /dev/null
+++ b/ui/compose/lint-baseline.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<issues format="6" by="lint 8.2.0-alpha14" type="baseline" client="gradle" dependencies="false" name="AGP (8.2.0-alpha14)" variant="all" version="8.2.0-alpha14">
+
+</issues>
diff --git a/ui/compose/src/main/AndroidManifest.xml b/ui/compose/src/main/AndroidManifest.xml
new file mode 100644
index 00000000..e3cc34c8
--- /dev/null
+++ b/ui/compose/src/main/AndroidManifest.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ ~ Copyright © 2014-2021 The Android Password Store Authors. All Rights Reserved.
+ ~ SPDX-License-Identifier: LGPL-3.0-only WITH LGPL-3.0-linking-exception
+ -->
+
+<manifest />
diff --git a/ui/compose/src/main/kotlin/app/passwordstore/ui/APSAppBar.kt b/ui/compose/src/main/kotlin/app/passwordstore/ui/APSAppBar.kt
new file mode 100644
index 00000000..94b646b7
--- /dev/null
+++ b/ui/compose/src/main/kotlin/app/passwordstore/ui/APSAppBar.kt
@@ -0,0 +1,40 @@
+package app.passwordstore.ui
+
+import androidx.compose.material3.ExperimentalMaterial3Api
+import androidx.compose.material3.Icon
+import androidx.compose.material3.IconButton
+import androidx.compose.material3.Text
+import androidx.compose.material3.TopAppBar
+import androidx.compose.material3.TopAppBarDefaults
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.shadow
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.painter.Painter
+import androidx.compose.ui.unit.dp
+
+@Composable
+@OptIn(ExperimentalMaterial3Api::class)
+public fun APSAppBar(
+ title: String,
+ backgroundColor: Color,
+ navigationIcon: Painter?,
+ onNavigationIconClick: (() -> Unit)?,
+ modifier: Modifier = Modifier,
+) {
+ TopAppBar(
+ title = { Text(text = title) },
+ navigationIcon = {
+ if (navigationIcon != null) {
+ IconButton(onClick = { onNavigationIconClick?.invoke() }) {
+ Icon(
+ painter = navigationIcon,
+ contentDescription = null,
+ )
+ }
+ }
+ },
+ colors = TopAppBarDefaults.topAppBarColors(containerColor = backgroundColor),
+ modifier = modifier.shadow(8.dp),
+ )
+}
diff --git a/ui/compose/src/main/kotlin/app/passwordstore/ui/compose/PasswordField.kt b/ui/compose/src/main/kotlin/app/passwordstore/ui/compose/PasswordField.kt
new file mode 100644
index 00000000..d2a04777
--- /dev/null
+++ b/ui/compose/src/main/kotlin/app/passwordstore/ui/compose/PasswordField.kt
@@ -0,0 +1,82 @@
+package app.passwordstore.ui.compose
+
+import androidx.annotation.StringRes
+import androidx.compose.material3.Icon
+import androidx.compose.material3.IconButton
+import androidx.compose.material3.Text
+import androidx.compose.material3.TextField
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.platform.LocalClipboardManager
+import androidx.compose.ui.res.painterResource
+import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.text.AnnotatedString
+import androidx.compose.ui.text.input.PasswordVisualTransformation
+import androidx.compose.ui.text.input.VisualTransformation
+
+@Composable
+public fun PasswordField(
+ value: String,
+ label: String,
+ initialVisibility: Boolean,
+ modifier: Modifier = Modifier,
+ readOnly: Boolean = false,
+) {
+ var visible by remember { mutableStateOf(initialVisibility) }
+ TextField(
+ value = value,
+ onValueChange = {},
+ readOnly = readOnly,
+ label = { Text(label) },
+ visualTransformation =
+ if (visible) VisualTransformation.None else PasswordVisualTransformation(),
+ trailingIcon = {
+ ToggleButton(
+ visible = visible,
+ contentDescription = "Toggle password visibility",
+ onButtonClick = { visible = !visible },
+ )
+ },
+ modifier = modifier,
+ )
+}
+
+@Composable
+private fun ToggleButton(
+ visible: Boolean,
+ contentDescription: String,
+ onButtonClick: () -> Unit,
+ modifier: Modifier = Modifier,
+) {
+ IconButton(onClick = onButtonClick, modifier = modifier) {
+ val icon =
+ if (visible) painterResource(id = R.drawable.baseline_visibility_off_24)
+ else painterResource(id = R.drawable.baseline_visibility_24)
+ Icon(
+ painter = icon,
+ contentDescription = contentDescription,
+ )
+ }
+}
+
+@Composable
+public fun CopyButton(
+ textToCopy: String,
+ @StringRes buttonLabelRes: Int,
+ modifier: Modifier = Modifier,
+) {
+ val clipboard = LocalClipboardManager.current
+ IconButton(
+ onClick = { clipboard.setText(AnnotatedString(textToCopy)) },
+ modifier = modifier,
+ ) {
+ Icon(
+ painter = painterResource(R.drawable.ic_content_copy),
+ contentDescription = stringResource(buttonLabelRes),
+ )
+ }
+}
diff --git a/ui/compose/src/main/kotlin/app/passwordstore/ui/compose/theme/Color.kt b/ui/compose/src/main/kotlin/app/passwordstore/ui/compose/theme/Color.kt
new file mode 100644
index 00000000..7709d136
--- /dev/null
+++ b/ui/compose/src/main/kotlin/app/passwordstore/ui/compose/theme/Color.kt
@@ -0,0 +1,58 @@
+package app.passwordstore.ui.compose.theme
+
+import androidx.compose.ui.graphics.Color
+
+internal val md_theme_light_primary = Color(0xFF006591)
+internal val md_theme_light_onPrimary = Color(0xFFffffff)
+internal val md_theme_light_primaryContainer = Color(0xFFc7e6ff)
+internal val md_theme_light_onPrimaryContainer = Color(0xFF001e30)
+internal val md_theme_light_secondary = Color(0xFF4f606e)
+internal val md_theme_light_onSecondary = Color(0xFFffffff)
+internal val md_theme_light_secondaryContainer = Color(0xFFd3e5f5)
+internal val md_theme_light_onSecondaryContainer = Color(0xFF0b1d29)
+internal val md_theme_light_tertiary = Color(0xFF006494)
+internal val md_theme_light_onTertiary = Color(0xFFffffff)
+internal val md_theme_light_tertiaryContainer = Color(0xFFc8e6ff)
+internal val md_theme_light_onTertiaryContainer = Color(0xFF001e31)
+internal val md_theme_light_error = Color(0xFFba1b1b)
+internal val md_theme_light_errorContainer = Color(0xFFffdad4)
+internal val md_theme_light_onError = Color(0xFFffffff)
+internal val md_theme_light_onErrorContainer = Color(0xFF410001)
+internal val md_theme_light_background = Color(0xFFfcfcff)
+internal val md_theme_light_onBackground = Color(0xFF1a1c1e)
+internal val md_theme_light_surface = Color(0xFFfcfcff)
+internal val md_theme_light_onSurface = Color(0xFF1a1c1e)
+internal val md_theme_light_surfaceVariant = Color(0xFFdde3ea)
+internal val md_theme_light_onSurfaceVariant = Color(0xFF41474d)
+internal val md_theme_light_outline = Color(0xFF72787e)
+internal val md_theme_light_inverseOnSurface = Color(0xFFf0f0f3)
+internal val md_theme_light_inverseSurface = Color(0xFF2e3133)
+
+internal val md_theme_dark_primary = Color(0xFF85ceff)
+internal val md_theme_dark_onPrimary = Color(0xFF00344e)
+internal val md_theme_dark_primaryContainer = Color(0xFF004c6f)
+internal val md_theme_dark_onPrimaryContainer = Color(0xFFc7e6ff)
+internal val md_theme_dark_secondary = Color(0xFFb7c9d9)
+internal val md_theme_dark_onSecondary = Color(0xFF21323e)
+internal val md_theme_dark_secondaryContainer = Color(0xFF384956)
+internal val md_theme_dark_onSecondaryContainer = Color(0xFFd3e5f5)
+internal val md_theme_dark_tertiary = Color(0xFF8aceff)
+internal val md_theme_dark_onTertiary = Color(0xFF003450)
+internal val md_theme_dark_tertiaryContainer = Color(0xFF004b70)
+internal val md_theme_dark_onTertiaryContainer = Color(0xFFc8e6ff)
+internal val md_theme_dark_error = Color(0xFFffb4a9)
+internal val md_theme_dark_errorContainer = Color(0xFF930006)
+internal val md_theme_dark_onError = Color(0xFF680003)
+internal val md_theme_dark_onErrorContainer = Color(0xFFffdad4)
+internal val md_theme_dark_background = Color(0xFF1a1c1e)
+internal val md_theme_dark_onBackground = Color(0xFFe1e2e5)
+internal val md_theme_dark_surface = Color(0xFF1a1c1e)
+internal val md_theme_dark_onSurface = Color(0xFFe1e2e5)
+internal val md_theme_dark_surfaceVariant = Color(0xFF41474d)
+internal val md_theme_dark_onSurfaceVariant = Color(0xFFc1c7ce)
+internal val md_theme_dark_outline = Color(0xFF8b9197)
+internal val md_theme_dark_inverseOnSurface = Color(0xFF1a1c1e)
+internal val md_theme_dark_inverseSurface = Color(0xFFe1e2e5)
+
+internal val seed = Color(0xFF003e5b)
+internal val error = Color(0xFFba1b1b)
diff --git a/ui/compose/src/main/kotlin/app/passwordstore/ui/compose/theme/Theme.kt b/ui/compose/src/main/kotlin/app/passwordstore/ui/compose/theme/Theme.kt
new file mode 100644
index 00000000..b11aa7c1
--- /dev/null
+++ b/ui/compose/src/main/kotlin/app/passwordstore/ui/compose/theme/Theme.kt
@@ -0,0 +1,77 @@
+package app.passwordstore.ui.compose.theme
+
+import androidx.compose.material3.ColorScheme
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.darkColorScheme
+import androidx.compose.material3.lightColorScheme
+import androidx.compose.runtime.Composable
+
+internal val LightThemeColors =
+ lightColorScheme(
+ primary = md_theme_light_primary,
+ onPrimary = md_theme_light_onPrimary,
+ primaryContainer = md_theme_light_primaryContainer,
+ onPrimaryContainer = md_theme_light_onPrimaryContainer,
+ secondary = md_theme_light_secondary,
+ onSecondary = md_theme_light_onSecondary,
+ secondaryContainer = md_theme_light_secondaryContainer,
+ onSecondaryContainer = md_theme_light_onSecondaryContainer,
+ tertiary = md_theme_light_tertiary,
+ onTertiary = md_theme_light_onTertiary,
+ tertiaryContainer = md_theme_light_tertiaryContainer,
+ onTertiaryContainer = md_theme_light_onTertiaryContainer,
+ error = md_theme_light_error,
+ errorContainer = md_theme_light_errorContainer,
+ onError = md_theme_light_onError,
+ onErrorContainer = md_theme_light_onErrorContainer,
+ background = md_theme_light_background,
+ onBackground = md_theme_light_onBackground,
+ surface = md_theme_light_surface,
+ onSurface = md_theme_light_onSurface,
+ surfaceVariant = md_theme_light_surfaceVariant,
+ onSurfaceVariant = md_theme_light_onSurfaceVariant,
+ outline = md_theme_light_outline,
+ inverseOnSurface = md_theme_light_inverseOnSurface,
+ inverseSurface = md_theme_light_inverseSurface,
+ )
+internal val DarkThemeColors =
+ darkColorScheme(
+ primary = md_theme_dark_primary,
+ onPrimary = md_theme_dark_onPrimary,
+ primaryContainer = md_theme_dark_primaryContainer,
+ onPrimaryContainer = md_theme_dark_onPrimaryContainer,
+ secondary = md_theme_dark_secondary,
+ onSecondary = md_theme_dark_onSecondary,
+ secondaryContainer = md_theme_dark_secondaryContainer,
+ onSecondaryContainer = md_theme_dark_onSecondaryContainer,
+ tertiary = md_theme_dark_tertiary,
+ onTertiary = md_theme_dark_onTertiary,
+ tertiaryContainer = md_theme_dark_tertiaryContainer,
+ onTertiaryContainer = md_theme_dark_onTertiaryContainer,
+ error = md_theme_dark_error,
+ errorContainer = md_theme_dark_errorContainer,
+ onError = md_theme_dark_onError,
+ onErrorContainer = md_theme_dark_onErrorContainer,
+ background = md_theme_dark_background,
+ onBackground = md_theme_dark_onBackground,
+ surface = md_theme_dark_surface,
+ onSurface = md_theme_dark_onSurface,
+ surfaceVariant = md_theme_dark_surfaceVariant,
+ onSurfaceVariant = md_theme_dark_onSurfaceVariant,
+ outline = md_theme_dark_outline,
+ inverseOnSurface = md_theme_dark_inverseOnSurface,
+ inverseSurface = md_theme_dark_inverseSurface,
+ )
+
+@Composable
+public fun APSTheme(
+ colors: ColorScheme,
+ content: @Composable () -> Unit,
+) {
+ MaterialTheme(colorScheme = colors, typography = AppTypography, content = content)
+}
+
+@Composable
+public fun APSThemePreview(content: @Composable () -> Unit) {
+ MaterialTheme(colorScheme = LightThemeColors, typography = AppTypography, content = content)
+}
diff --git a/ui/compose/src/main/kotlin/app/passwordstore/ui/compose/theme/Type.kt b/ui/compose/src/main/kotlin/app/passwordstore/ui/compose/theme/Type.kt
new file mode 100644
index 00000000..b9a07d5d
--- /dev/null
+++ b/ui/compose/src/main/kotlin/app/passwordstore/ui/compose/theme/Type.kt
@@ -0,0 +1,144 @@
+package app.passwordstore.ui.compose.theme
+
+import androidx.compose.material3.Typography
+import androidx.compose.ui.text.TextStyle
+import androidx.compose.ui.text.font.Font
+import androidx.compose.ui.text.font.FontFamily
+import androidx.compose.ui.text.font.FontWeight
+import androidx.compose.ui.unit.sp
+import app.passwordstore.ui.compose.R
+
+internal val Manrope =
+ FontFamily(
+ Font(R.font.manrope_bold, FontWeight.Bold),
+ Font(R.font.manrope_extrabold, FontWeight.ExtraBold),
+ Font(R.font.manrope_extralight, FontWeight.ExtraLight),
+ Font(R.font.manrope_light, FontWeight.Light),
+ Font(R.font.manrope_medium, FontWeight.Medium),
+ Font(R.font.manrope_regular, FontWeight.Normal),
+ Font(R.font.manrope_semibold, FontWeight.SemiBold),
+ )
+
+internal val AppTypography =
+ Typography(
+ displayLarge =
+ TextStyle(
+ fontFamily = Manrope,
+ fontWeight = FontWeight.W400,
+ fontSize = 57.sp,
+ lineHeight = 64.sp,
+ letterSpacing = (-0.25).sp,
+ ),
+ displayMedium =
+ TextStyle(
+ fontFamily = Manrope,
+ fontWeight = FontWeight.W400,
+ fontSize = 45.sp,
+ lineHeight = 52.sp,
+ letterSpacing = 0.sp,
+ ),
+ displaySmall =
+ TextStyle(
+ fontFamily = Manrope,
+ fontWeight = FontWeight.W400,
+ fontSize = 36.sp,
+ lineHeight = 44.sp,
+ letterSpacing = 0.sp,
+ ),
+ headlineLarge =
+ TextStyle(
+ fontFamily = Manrope,
+ fontWeight = FontWeight.W400,
+ fontSize = 32.sp,
+ lineHeight = 40.sp,
+ letterSpacing = 0.sp,
+ ),
+ headlineMedium =
+ TextStyle(
+ fontFamily = Manrope,
+ fontWeight = FontWeight.W400,
+ fontSize = 28.sp,
+ lineHeight = 36.sp,
+ letterSpacing = 0.sp,
+ ),
+ headlineSmall =
+ TextStyle(
+ fontFamily = Manrope,
+ fontWeight = FontWeight.W400,
+ fontSize = 24.sp,
+ lineHeight = 32.sp,
+ letterSpacing = 0.sp,
+ ),
+ titleLarge =
+ TextStyle(
+ fontFamily = Manrope,
+ fontWeight = FontWeight.W400,
+ fontSize = 22.sp,
+ lineHeight = 28.sp,
+ letterSpacing = 0.sp,
+ ),
+ titleMedium =
+ TextStyle(
+ fontFamily = Manrope,
+ fontWeight = FontWeight.Medium,
+ fontSize = 16.sp,
+ lineHeight = 24.sp,
+ letterSpacing = 0.1.sp,
+ ),
+ titleSmall =
+ TextStyle(
+ fontFamily = Manrope,
+ fontWeight = FontWeight.Medium,
+ fontSize = 14.sp,
+ lineHeight = 20.sp,
+ letterSpacing = 0.1.sp,
+ ),
+ labelLarge =
+ TextStyle(
+ fontFamily = Manrope,
+ fontWeight = FontWeight.Medium,
+ fontSize = 14.sp,
+ lineHeight = 20.sp,
+ letterSpacing = 0.1.sp,
+ ),
+ bodyLarge =
+ TextStyle(
+ fontFamily = Manrope,
+ fontWeight = FontWeight.W400,
+ fontSize = 16.sp,
+ lineHeight = 24.sp,
+ letterSpacing = 0.5.sp,
+ ),
+ bodyMedium =
+ TextStyle(
+ fontFamily = Manrope,
+ fontWeight = FontWeight.W400,
+ fontSize = 14.sp,
+ lineHeight = 20.sp,
+ letterSpacing = 0.25.sp,
+ ),
+ bodySmall =
+ TextStyle(
+ fontFamily = Manrope,
+ fontWeight = FontWeight.W400,
+ fontSize = 12.sp,
+ lineHeight = 16.sp,
+ letterSpacing = 0.4.sp,
+ ),
+ labelMedium =
+ TextStyle(
+ fontFamily = Manrope,
+ fontWeight = FontWeight.Medium,
+ fontSize = 12.sp,
+ lineHeight = 16.sp,
+ letterSpacing = 0.5.sp,
+ ),
+ labelSmall =
+ TextStyle(
+ fontFamily = Manrope,
+ fontWeight = FontWeight.Medium,
+ fontSize = 11.sp,
+ lineHeight = 16.sp,
+ letterSpacing = 0.5.sp,
+ ),
+ )
diff --git a/ui/compose/src/main/kotlin/app/passwordstore/ui/compose/theme/utils.kt b/ui/compose/src/main/kotlin/app/passwordstore/ui/compose/theme/utils.kt
new file mode 100644
index 00000000..096862dc
--- /dev/null
+++ b/ui/compose/src/main/kotlin/app/passwordstore/ui/compose/theme/utils.kt
@@ -0,0 +1,27 @@
+package app.passwordstore.ui.compose.theme
+
+import android.content.Context
+import android.os.Build
+import androidx.compose.foundation.isSystemInDarkTheme
+import androidx.compose.material3.ColorScheme
+import androidx.compose.material3.dynamicDarkColorScheme
+import androidx.compose.material3.dynamicLightColorScheme
+import androidx.compose.runtime.Composable
+
+@Composable
+public fun decideColorScheme(context: Context): ColorScheme {
+ val isDarkTheme = isSystemInDarkTheme()
+ return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
+ if (isDarkTheme) {
+ dynamicDarkColorScheme(context)
+ } else {
+ dynamicLightColorScheme(context)
+ }
+ } else {
+ if (isDarkTheme) {
+ DarkThemeColors
+ } else {
+ LightThemeColors
+ }
+ }
+}
diff --git a/ui/compose/src/main/res/drawable/baseline_visibility_24.xml b/ui/compose/src/main/res/drawable/baseline_visibility_24.xml
new file mode 100644
index 00000000..e732f005
--- /dev/null
+++ b/ui/compose/src/main/res/drawable/baseline_visibility_24.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:tint="#000000"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M12,4.5C7,4.5 2.73,7.61 1,12c1.73,4.39 6,7.5 11,7.5s9.27,-3.11 11,-7.5c-1.73,-4.39 -6,-7.5 -11,-7.5zM12,17c-2.76,0 -5,-2.24 -5,-5s2.24,-5 5,-5 5,2.24 5,5 -2.24,5 -5,5zM12,9c-1.66,0 -3,1.34 -3,3s1.34,3 3,3 3,-1.34 3,-3 -1.34,-3 -3,-3z" />
+</vector>
diff --git a/ui/compose/src/main/res/drawable/baseline_visibility_off_24.xml b/ui/compose/src/main/res/drawable/baseline_visibility_off_24.xml
new file mode 100644
index 00000000..a5cad715
--- /dev/null
+++ b/ui/compose/src/main/res/drawable/baseline_visibility_off_24.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:tint="#000000"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M12,7c2.76,0 5,2.24 5,5 0,0.65 -0.13,1.26 -0.36,1.83l2.92,2.92c1.51,-1.26 2.7,-2.89 3.43,-4.75 -1.73,-4.39 -6,-7.5 -11,-7.5 -1.4,0 -2.74,0.25 -3.98,0.7l2.16,2.16C10.74,7.13 11.35,7 12,7zM2,4.27l2.28,2.28 0.46,0.46C3.08,8.3 1.78,10.02 1,12c1.73,4.39 6,7.5 11,7.5 1.55,0 3.03,-0.3 4.38,-0.84l0.42,0.42L19.73,22 21,20.73 3.27,3 2,4.27zM7.53,9.8l1.55,1.55c-0.05,0.21 -0.08,0.43 -0.08,0.65 0,1.66 1.34,3 3,3 0.22,0 0.44,-0.03 0.65,-0.08l1.55,1.55c-0.67,0.33 -1.41,0.53 -2.2,0.53 -2.76,0 -5,-2.24 -5,-5 0,-0.79 0.2,-1.53 0.53,-2.2zM11.84,9.02l3.15,3.15 0.02,-0.16c0,-1.66 -1.34,-3 -3,-3l-0.17,0.01z" />
+</vector>
diff --git a/ui/compose/src/main/res/drawable/ic_content_copy.xml b/ui/compose/src/main/res/drawable/ic_content_copy.xml
new file mode 100644
index 00000000..8afc9846
--- /dev/null
+++ b/ui/compose/src/main/res/drawable/ic_content_copy.xml
@@ -0,0 +1,15 @@
+<!--
+ ~ Copyright © 2014-2021 The Android Password Store Authors. All Rights Reserved.
+ ~ SPDX-License-Identifier: GPL-3.0-only
+ -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:tint="?attr/colorControlNormal"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+ <path
+ android:fillColor="#FFFFFF"
+ android:pathData="M16,1L4,1c-1.1,0 -2,0.9 -2,2v14h2L4,3h12L16,1zM15,5L8,5c-1.1,0 -1.99,0.9 -1.99,2L6,21c0,1.1 0.89,2 1.99,2L19,23c1.1,0 2,-0.9 2,-2L21,11l-6,-6zM8,21L8,7h6v5h5v9L8,21z" />
+</vector>
diff --git a/ui/compose/src/main/res/font/manrope.xml b/ui/compose/src/main/res/font/manrope.xml
new file mode 100644
index 00000000..c1ecac5c
--- /dev/null
+++ b/ui/compose/src/main/res/font/manrope.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ ~ Copyright © 2014-2021 The Android Password Store Authors. All Rights Reserved.
+ ~ SPDX-License-Identifier: GPL-3.0-only
+ -->
+
+<font-family xmlns:app="http://schemas.android.com/apk/res-auto">
+ <font
+ app:font="@font/manrope_extralight"
+ app:fontWeight="200" />
+ <font
+ app:font="@font/manrope_light"
+ app:fontWeight="300" />
+ <font
+ app:font="@font/manrope_regular"
+ app:fontWeight="400" />
+ <font
+ app:font="@font/manrope_medium"
+ app:fontWeight="500" />
+ <font
+ app:font="@font/manrope_semibold"
+ app:fontWeight="600" />
+ <font
+ app:font="@font/manrope_bold"
+ app:fontWeight="700" />
+ <font
+ app:font="@font/manrope_extrabold"
+ app:fontWeight="800" />
+</font-family>
diff --git a/ui/compose/src/main/res/font/manrope_bold.ttf b/ui/compose/src/main/res/font/manrope_bold.ttf
new file mode 100644
index 00000000..8bbf0bd1
--- /dev/null
+++ b/ui/compose/src/main/res/font/manrope_bold.ttf
Binary files differ
diff --git a/ui/compose/src/main/res/font/manrope_extrabold.ttf b/ui/compose/src/main/res/font/manrope_extrabold.ttf
new file mode 100644
index 00000000..3f68dffc
--- /dev/null
+++ b/ui/compose/src/main/res/font/manrope_extrabold.ttf
Binary files differ
diff --git a/ui/compose/src/main/res/font/manrope_extralight.ttf b/ui/compose/src/main/res/font/manrope_extralight.ttf
new file mode 100644
index 00000000..9d21d775
--- /dev/null
+++ b/ui/compose/src/main/res/font/manrope_extralight.ttf
Binary files differ
diff --git a/ui/compose/src/main/res/font/manrope_light.ttf b/ui/compose/src/main/res/font/manrope_light.ttf
new file mode 100644
index 00000000..f255257a
--- /dev/null
+++ b/ui/compose/src/main/res/font/manrope_light.ttf
Binary files differ
diff --git a/ui/compose/src/main/res/font/manrope_medium.ttf b/ui/compose/src/main/res/font/manrope_medium.ttf
new file mode 100644
index 00000000..c73d7741
--- /dev/null
+++ b/ui/compose/src/main/res/font/manrope_medium.ttf
Binary files differ
diff --git a/ui/compose/src/main/res/font/manrope_regular.ttf b/ui/compose/src/main/res/font/manrope_regular.ttf
new file mode 100644
index 00000000..c02b01be
--- /dev/null
+++ b/ui/compose/src/main/res/font/manrope_regular.ttf
Binary files differ
diff --git a/ui/compose/src/main/res/font/manrope_semibold.ttf b/ui/compose/src/main/res/font/manrope_semibold.ttf
new file mode 100644
index 00000000..30ee0310
--- /dev/null
+++ b/ui/compose/src/main/res/font/manrope_semibold.ttf
Binary files differ