Skip to content

Commit

Permalink
Merge branch 'release/5.2.0' into main
Browse files Browse the repository at this point in the history
  • Loading branch information
rafakob committed Dec 22, 2023
2 parents 3863bc6 + c18dfe8 commit c3f4d92
Show file tree
Hide file tree
Showing 100 changed files with 1,789 additions and 244 deletions.
4 changes: 2 additions & 2 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ android {

defaultConfig {
applicationId = "com.twofasapp"
versionName = "5.1.0"
versionCode = 5000009
versionName = "5.2.0"
versionCode = 5000012

val versionCodeOffset = 5000000

Expand Down
2 changes: 1 addition & 1 deletion app/src/debug/res/values/strings.xml
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
<resources>
<string name="android__app_name">2FAS.DEBUG</string>
<string name="android__app_name" translatable="false">2FAS.DEBUG</string>
</resources>
1 change: 1 addition & 0 deletions app/src/main/res/xml/locales_config.xml
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,5 @@
<locale android:name="pl" />
<locale android:name="id" />
<locale android:name="nl" />
<locale android:name="tr" />
</locale-config>
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
package com.twofasapp.designsystem.common

import androidx.activity.compose.BackHandler
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.foundation.layout.RowScope
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.OutlinedTextFieldDefaults
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.focus.onFocusChanged
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.platform.LocalSoftwareKeyboardController
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.twofasapp.designsystem.TwIcons
import com.twofasapp.designsystem.TwTheme

@Composable
fun TopAppBarWithSearch(
title: String,
searchHint: String = "",
modifier: Modifier = Modifier,
actions: @Composable RowScope.() -> Unit = {},
onSearchValueChanged: (String) -> Unit = {},
navigationClick: () -> Unit
) {
val showSearch = remember { mutableStateOf(false) }

TwTopAppBar(title = {
if (showSearch.value) {
SearchBar(hint = searchHint, showSearch = showSearch, onValueChanged = onSearchValueChanged)
} else {
Text(text = title, color = TwTheme.color.onSurfacePrimary)
}
}, navigationIcon = {
IconButton(onClick = {
if (showSearch.value) {
showSearch.value = false
onSearchValueChanged("")
} else {
navigationClick.invoke()
}
}) {
Icon(TwIcons.ArrowBack, null, tint = TwTheme.color.onSurfacePrimary)
}
}, actions = {
if (showSearch.value.not()) {
IconButton(onClick = { showSearch.value = true }) {
Icon(TwIcons.Search, null, tint = TwTheme.color.primary)
}
}
actions()
}, modifier = modifier
)
}

@Composable
fun SearchBar(
value: String = "",
hint: String = "",
showSearch: MutableState<Boolean>,
onValueChanged: (String) -> Unit = {},
onClearClick: () -> Unit = {},
) {
val textValue = remember { mutableStateOf(value) }
val showClearButton = remember { mutableStateOf(false) }
val keyboardController = LocalSoftwareKeyboardController.current
val focusRequester = remember { FocusRequester() }
val focusManager = LocalFocusManager.current

BackHandler(
enabled = showSearch.value
) {
if (textValue.value.isNotEmpty()) {
textValue.value = ""
onValueChanged("")
} else {
showClearButton.value = false
showSearch.value = false
focusManager.clearFocus()
keyboardController?.hide()
}

onClearClick()
}

if (showSearch.value) {
OutlinedTextField(
modifier = Modifier
.height(56.dp)
.fillMaxWidth()
.onFocusChanged { focusState ->
showClearButton.value = focusState.isFocused
}
.focusRequester(focusRequester),
value = textValue.value,
onValueChange = {
textValue.value = it
onValueChanged(it)
},
placeholder = {
Text(text = hint, style = MaterialTheme.typography.bodyMedium.copy(fontSize = 18.sp))
},
textStyle = MaterialTheme.typography.bodyMedium.copy(fontSize = 18.sp),
colors = OutlinedTextFieldDefaults.colors(
focusedTextColor = TwTheme.color.onSurfacePrimary,
disabledTextColor = Color.Black,
focusedBorderColor = Color.Transparent,
unfocusedBorderColor = Color.Transparent,
focusedLabelColor = TwTheme.color.onSurfaceSecondary,
unfocusedLabelColor = TwTheme.color.onSurfaceSecondary,
errorLabelColor = TwTheme.color.error,
),
trailingIcon = {
AnimatedVisibility(
visible = showClearButton.value,
enter = fadeIn(),
exit = fadeOut()
) {
IconButton(onClick = {
if (textValue.value.isNotEmpty()) {
textValue.value = ""
onValueChanged("")
} else {
showClearButton.value = false
showSearch.value = false
focusManager.clearFocus()
keyboardController?.hide()
}

onClearClick()
}) {
Icon(
painter = TwIcons.Close,
tint = TwTheme.color.onSurfacePrimary,
contentDescription = null
)
}
}
},
maxLines = 1,
singleLine = true,
keyboardOptions = KeyboardOptions.Default.copy(imeAction = ImeAction.Done),
keyboardActions = KeyboardActions(onDone = {
keyboardController?.hide()
}),
)

LaunchedEffect(Unit) {
focusRequester.requestFocus()
}
} else {
textValue.value = ""
onValueChanged("")
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,15 @@ package com.twofasapp.designsystem.dialog
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.ColumnScope
import androidx.compose.foundation.layout.IntrinsicSize
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Row
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.sizeIn
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.text.ClickableText
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
Expand Down Expand Up @@ -49,6 +48,7 @@ fun BaseDialog(
bodyAnnotated: AnnotatedString? = null,
positive: String? = null,
negative: String? = null,
onBodyClick: ((Int) -> Unit)? = null,
onPositiveClick: (() -> Unit)? = null,
onNegativeClick: (() -> Unit)? = null,
positiveEnabled: Boolean = true,
Expand Down Expand Up @@ -90,6 +90,7 @@ fun BaseDialog(
Body(
text = body,
textAnnotated = bodyAnnotated,
onBodyClick = onBodyClick,
)
}

Expand Down Expand Up @@ -138,6 +139,7 @@ private fun Title(
private fun ColumnScope.Body(
text: String?,
textAnnotated: AnnotatedString?,
onBodyClick: ((Int) -> Unit)? = null,
) {
if (text != null) {
Text(
Expand All @@ -151,14 +153,15 @@ private fun ColumnScope.Body(

)
} else if (textAnnotated != null) {
Text(
ClickableText(
text = textAnnotated,
style = MaterialTheme.typography.bodyMedium,
color = TwTheme.color.onSurfaceTertiary,
onClick = { onBodyClick?.invoke(it) },
style = MaterialTheme.typography.bodyMedium.copy(color = TwTheme.color.onSurfaceTertiary),
modifier = Modifier
.padding(horizontal = DialogPadding)
.padding(TitlePadding)
)
.padding(TitlePadding),

)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.DialogProperties
Expand All @@ -26,10 +27,12 @@ fun PasswordDialog(
onDismissRequest: () -> Unit,
title: String? = null,
body: String? = null,
bodyAnnotated: AnnotatedString? = null,
error: String? = null,
enabled: Boolean = true,
positive: String? = TwLocale.strings.commonSave,
negative: String? = TwLocale.strings.commonCancel,
onBodyClick: ((Int) -> Unit)? = null,
onPositive: ((String) -> Unit)? = null,
onNegative: (() -> Unit)? = null,
validation: ((String) -> Boolean)? = null,
Expand Down Expand Up @@ -57,8 +60,10 @@ fun PasswordDialog(
onDismissRequest = onDismissRequest,
title = title,
body = body,
bodyAnnotated = bodyAnnotated,
positive = positive,
negative = negative,
onBodyClick = onBodyClick,
onPositiveClick = { onPositive?.invoke(password.trim()) },
onNegativeClick = onNegative,
positiveEnabled = positiveEnabledState,
Expand Down
4 changes: 3 additions & 1 deletion core/locale/src/main/java/com/twofasapp/locale/Strings.kt
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,7 @@ class Strings(c: Context) {
val browserRequestSuggested = c.getString(R.string.extension__services_suggested_header)
val browserRequestAll = c.getString(R.string.extension__services_all_header)
val browserRequestOther = c.getString(R.string.extension__services_other_header)
val browserRequestEmpty = c.getString(R.string.tokens__service_not_found_search)

val settingsTheme = c.getString(R.string.settings__option_theme)
val settingsShowNextCode = c.getString(R.string.settings__show_next_token)
Expand Down Expand Up @@ -316,7 +317,8 @@ class Strings(c: Context) {
val backupRemoveCloudPasswordTitle = c.getString(R.string.backup__enter_password_dialog_title)
val backupRemoveCloudPasswordMsg = c.getString(R.string.backup__remove_password_msg)
val backupEnterCloudPasswordTitle = c.getString(R.string.backup__enter_password_dialog_title)
val backupEnterCloudPasswordMsg = c.getString(R.string.backup__enter_password_title)
val backupEnterCloudPasswordMsg1 = c.getString(R.string.backup__enter_password_google_drive_msg1)
val backupEnterCloudPasswordMsg2 = c.getString(R.string.backup__enter_password_google_drive_msg2)
val backupIncorrectPassword = c.getString(R.string.backup__incorrect_password)

val backupExportShareCta = c.getString(R.string.export_backup_share_cta)
Expand Down
Loading

0 comments on commit c3f4d92

Please sign in to comment.