Merge pull request #1884 from FunkyMuse/feat/more_dialogs

feat: more dialog stuff
This commit is contained in:
Tibor Kaputa 2023-10-15 13:32:40 +02:00 committed by GitHub
commit 7076fbaf6e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
37 changed files with 1258 additions and 166 deletions

View file

@ -136,18 +136,17 @@ class AboutActivity : ComponentActivity() {
DialogMember {
ConfirmationAdvancedAlertDialog(
alertDialogState = this,
callback = { success ->
message = "${getString(R.string.before_asking_question_read_faq)}\n\n${getString(R.string.make_sure_latest)}",
messageId = null,
positive = R.string.read_faq,
negative = R.string.skip
) { success ->
if (success) {
launchFAQActivity()
} else {
launchEmailIntent()
}
},
message = "${getString(R.string.before_asking_question_read_faq)}\n\n${getString(R.string.make_sure_latest)}",
messageId = null,
positive = R.string.read_faq,
negative = R.string.skip
)
}
}
}
@ -157,18 +156,17 @@ class AboutActivity : ComponentActivity() {
DialogMember {
ConfirmationAdvancedAlertDialog(
alertDialogState = this,
callback = { success ->
message = "${getString(R.string.before_asking_question_read_faq)}\n\n${getString(R.string.make_sure_latest)}",
messageId = null,
positive = R.string.read_faq,
negative = R.string.skip
) { success ->
if (success) {
launchFAQActivity()
} else {
launchRateUsPrompt(showRateStarsDialog)
}
},
message = "${getString(R.string.before_asking_question_read_faq)}\n\n${getString(R.string.make_sure_latest)}",
messageId = null,
positive = R.string.read_faq,
negative = R.string.skip
)
}
}
}

View file

@ -80,18 +80,17 @@ class ManageBlockedNumbersActivity : BaseSimpleActivity() {
addBlockedNumberDialogState.DialogMember {
AddOrEditBlockedNumberAlertDialog(
blockedNumber = clickedBlockedNumber,
alertDialogState = addBlockedNumberDialogState,
blockedNumber = clickedBlockedNumber,
deleteBlockedNumber = { blockedNumber ->
deleteBlockedNumber(blockedNumber)
updateBlockedNumbers()
},
addBlockedNumber = { blockedNumber ->
}
) { blockedNumber ->
addBlockedNumber(blockedNumber)
clickedBlockedNumber = null
updateBlockedNumbers()
}
)
}
ManageBlockedNumbersScreen(

View file

@ -1,4 +1,4 @@
package com.simplemobiletools.commons.dialogs
package com.simplemobiletools.commons.compose.alert_dialog
import androidx.compose.foundation.background
import androidx.compose.foundation.border

View file

@ -0,0 +1,118 @@
package com.simplemobiletools.commons.compose.bottom_sheet
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.material3.BottomSheetDefaults
import androidx.compose.material3.ModalBottomSheet
import androidx.compose.material3.SheetValue
import androidx.compose.material3.rememberModalBottomSheetState
import androidx.compose.runtime.*
import androidx.compose.runtime.saveable.mapSaver
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.ui.Modifier
import com.simplemobiletools.commons.compose.alert_dialog.dialogContainerColor
import com.simplemobiletools.commons.compose.alert_dialog.dialogElevation
@Composable
fun rememberBottomSheetDialogState(
openBottomSheet: Boolean = false,
skipPartiallyExpanded: Boolean = false,
edgeToEdgeEnabled: Boolean = false,
confirmValueChange: (SheetValue) -> Boolean = { true },
) = remember {
BottomSheetDialogState(
openBottomSheet = openBottomSheet,
skipPartiallyExpanded = skipPartiallyExpanded,
edgeToEdgeEnabled = edgeToEdgeEnabled,
confirmValueChange = confirmValueChange
)
}
@Composable
fun rememberBottomSheetDialogStateSaveable(
openBottomSheet: Boolean = false,
skipPartiallyExpanded: Boolean = false,
edgeToEdgeEnabled: Boolean = false,
confirmValueChange: (SheetValue) -> Boolean = { true },
) = rememberSaveable(stateSaver = mapSaver(save = {
mapOf(
"skipPartiallyExpanded" to skipPartiallyExpanded,
"edgeToEdgeEnabled" to edgeToEdgeEnabled,
"openBottomSheet" to openBottomSheet,
)
}, restore = {
BottomSheetDialogState(
openBottomSheet = it["openBottomSheet"] as Boolean,
skipPartiallyExpanded = it["openBottomSheet"] as Boolean,
edgeToEdgeEnabled = it["openBottomSheet"] as Boolean,
)
})) {
mutableStateOf(
BottomSheetDialogState(
skipPartiallyExpanded = skipPartiallyExpanded,
edgeToEdgeEnabled = edgeToEdgeEnabled,
confirmValueChange = confirmValueChange
)
)
}
@Stable
class BottomSheetDialogState(
openBottomSheet: Boolean = false,
private val skipPartiallyExpanded: Boolean = false,
private val edgeToEdgeEnabled: Boolean = false,
private val confirmValueChange: (SheetValue) -> Boolean = { true },
) {
@Composable
private fun rememberWindowInsets(
defaultInsets: WindowInsets = BottomSheetDefaults.windowInsets
) = remember { if (edgeToEdgeEnabled) WindowInsets(0) else defaultInsets }
@Composable
private fun rememberSheetState() = rememberModalBottomSheetState(
skipPartiallyExpanded = skipPartiallyExpanded,
confirmValueChange = confirmValueChange
)
var isOpen by mutableStateOf(openBottomSheet)
private set
fun close() {
isOpen = false
}
fun open() {
isOpen = true
}
@Composable
fun BottomSheetContent(
modifier: Modifier = Modifier,
content: @Composable () -> Unit
) {
val bottomSheetState = rememberSheetState()
val windowInsets = rememberWindowInsets()
LaunchedEffect(isOpen) {
if (isOpen && !bottomSheetState.isVisible) {
bottomSheetState.show()
} else {
bottomSheetState.hide()
}
}
if (isOpen) {
ModalBottomSheet(
modifier = modifier,
onDismissRequest = ::close,
sheetState = bottomSheetState,
windowInsets = windowInsets,
dragHandle = {}, //leave empty as we provide our own dialog surfaces
shape = bottomSheetDialogShape,
containerColor = dialogContainerColor,
tonalElevation = dialogElevation,
) {
content()
}
}
}
}

View file

@ -0,0 +1,93 @@
package com.simplemobiletools.commons.compose.bottom_sheet
import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.CornerSize
import androidx.compose.material3.Surface
import androidx.compose.runtime.Composable
import androidx.compose.runtime.ReadOnlyComposable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
import com.simplemobiletools.commons.compose.alert_dialog.dialogContainerColor
import com.simplemobiletools.commons.compose.alert_dialog.dialogElevation
import com.simplemobiletools.commons.compose.theme.LocalTheme
import com.simplemobiletools.commons.compose.theme.Shapes
import com.simplemobiletools.commons.compose.theme.light_grey_stroke
import com.simplemobiletools.commons.compose.theme.model.Theme
val bottomSheetDialogShape = Shapes.extraLarge.copy(
bottomEnd = CornerSize(0f),
bottomStart = CornerSize(0f)
)
val Modifier.bottomSheetDialogBorder: Modifier
@ReadOnlyComposable
@Composable get() =
when (LocalTheme.current) {
is Theme.BlackAndWhite -> then(Modifier.border(2.dp, light_grey_stroke, bottomSheetDialogShape))
else -> Modifier
}
@Composable
fun BottomSheetSpacerEdgeToEdge() {
Spacer(modifier = Modifier.padding(bottom = 42.dp))
}
@Composable
fun BottomSheetColumnDialogSurface(
modifier: Modifier = Modifier,
content: @Composable ColumnScope.() -> Unit
) {
Surface(
modifier = modifier
.fillMaxSize()
.bottomSheetDialogBorder,
shape = bottomSheetDialogShape,
color = dialogContainerColor,
tonalElevation = dialogElevation,
) {
Column(modifier = Modifier.background(dialogContainerColor)) {
content()
}
}
}
@Composable
fun BottomSheetBoxDialogSurface(
modifier: Modifier = Modifier,
content: @Composable BoxScope.() -> Unit
) {
Surface(
modifier = modifier
.fillMaxSize()
.bottomSheetDialogBorder,
shape = bottomSheetDialogShape,
color = dialogContainerColor,
tonalElevation = dialogElevation,
) {
Box(modifier = Modifier.background(dialogContainerColor)) {
content()
}
}
}
@Composable
fun BottomSheetDialogSurface(
modifier: Modifier = Modifier,
content: @Composable (backgroundColor: Color) -> Unit
) {
Surface(
modifier = modifier
.fillMaxSize()
.bottomSheetDialogBorder,
shape = bottomSheetDialogShape,
color = dialogContainerColor,
tonalElevation = dialogElevation,
) {
content(dialogContainerColor)
}
}

View file

@ -10,11 +10,11 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import com.simplemobiletools.commons.compose.alert_dialog.dialogTextColor
import com.simplemobiletools.commons.compose.extensions.MyDevices
import com.simplemobiletools.commons.compose.extensions.rememberMutableInteractionSource
import com.simplemobiletools.commons.compose.theme.AppThemeSurface
import com.simplemobiletools.commons.compose.theme.SimpleTheme
import com.simplemobiletools.commons.dialogs.dialogTextColor
@Composable
fun RadioButtonDialogComponent(

View file

@ -15,9 +15,9 @@ fun FakeVersionCheck() {
DialogMember {
ConfirmationAlertDialog(
alertDialogState = this,
message = FAKE_VERSION_APP_LABEL,
positive = R.string.ok,
negative = null,
message = FAKE_VERSION_APP_LABEL
negative = null
) {
context.getActivity().launchViewIntent(DEVELOPER_PLAY_STORE_URL)
}
@ -35,9 +35,9 @@ fun CheckAppOnSdCard() {
DialogMember {
ConfirmationAlertDialog(
alertDialogState = this,
messageId = R.string.app_on_sd_card,
positive = R.string.ok,
negative = null,
messageId = R.string.app_on_sd_card
negative = null
) {}
}
}

View file

@ -25,14 +25,14 @@ import androidx.compose.ui.semantics.Role
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.simplemobiletools.commons.R
import com.simplemobiletools.commons.compose.alert_dialog.dialogBorder
import com.simplemobiletools.commons.compose.alert_dialog.dialogContainerColor
import com.simplemobiletools.commons.compose.components.SimpleDropDownMenuItem
import com.simplemobiletools.commons.compose.extensions.MyDevices
import com.simplemobiletools.commons.compose.extensions.rememberMutableInteractionSource
import com.simplemobiletools.commons.compose.theme.AppThemeSurface
import com.simplemobiletools.commons.compose.theme.Shapes
import com.simplemobiletools.commons.compose.theme.SimpleTheme
import com.simplemobiletools.commons.dialogs.dialogBorder
import com.simplemobiletools.commons.dialogs.dialogContainerColor
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.toImmutableList

View file

@ -11,24 +11,32 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.TextRange
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.text.input.TextFieldValue
import com.simplemobiletools.commons.R
import com.simplemobiletools.commons.compose.alert_dialog.AlertDialogState
import com.simplemobiletools.commons.compose.alert_dialog.rememberAlertDialogState
import com.simplemobiletools.commons.compose.alert_dialog.*
import com.simplemobiletools.commons.compose.extensions.MyDevices
import com.simplemobiletools.commons.compose.theme.AppThemeSurface
import com.simplemobiletools.commons.models.BlockedNumber
@Composable
fun AddOrEditBlockedNumberAlertDialog(
modifier: Modifier = Modifier,
blockedNumber: BlockedNumber?,
alertDialogState: AlertDialogState,
blockedNumber: BlockedNumber?,
modifier: Modifier = Modifier,
deleteBlockedNumber: (String) -> Unit,
addBlockedNumber: (String) -> Unit
) {
val focusRequester = remember { FocusRequester() }
var textFieldValue by remember { mutableStateOf(blockedNumber?.number.orEmpty()) }
var textFieldValue by remember {
mutableStateOf(
TextFieldValue(
text = blockedNumber?.number.orEmpty(),
selection = TextRange(blockedNumber?.number?.length ?: 0)
)
)
}
AlertDialog(
containerColor = dialogContainerColor,
@ -37,11 +45,10 @@ fun AddOrEditBlockedNumberAlertDialog(
onDismissRequest = alertDialogState::hide,
confirmButton = {
TextButton(onClick = {
var newBlockedNumber = textFieldValue
var newBlockedNumber = textFieldValue.text
if (blockedNumber != null && newBlockedNumber != blockedNumber.number) {
deleteBlockedNumber(blockedNumber.number)
}
if (newBlockedNumber.isNotEmpty()) {
// in case the user also added a '.' in the pattern, remove it
if (newBlockedNumber.contains(".*")) {
@ -93,10 +100,9 @@ fun AddOrEditBlockedNumberAlertDialog(
private fun AddOrEditBlockedNumberAlertDialogPreview() {
AppThemeSurface {
AddOrEditBlockedNumberAlertDialog(
alertDialogState = rememberAlertDialogState(),
blockedNumber = null,
deleteBlockedNumber = {},
addBlockedNumber = {},
alertDialogState = rememberAlertDialogState()
)
deleteBlockedNumber = {}
) {}
}
}

View file

@ -16,8 +16,7 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.sp
import com.simplemobiletools.commons.R
import com.simplemobiletools.commons.compose.alert_dialog.AlertDialogState
import com.simplemobiletools.commons.compose.alert_dialog.rememberAlertDialogState
import com.simplemobiletools.commons.compose.alert_dialog.*
import com.simplemobiletools.commons.compose.components.LinkifyTextComponent
import com.simplemobiletools.commons.compose.extensions.MyDevices
import com.simplemobiletools.commons.compose.theme.AppThemeSurface
@ -61,8 +60,8 @@ class AppSideloadedDialog(val activity: Activity, val callback: () -> Unit) {
@Composable
fun AppSideLoadedAlertDialog(
alertDialogState: AlertDialogState,
modifier: Modifier = Modifier,
alertDialogState: AlertDialogState = rememberAlertDialogState(),
onDownloadClick: (url: String) -> Unit,
onCancelClick: () -> Unit
) {
@ -113,6 +112,6 @@ fun AppSideLoadedAlertDialog(
@MyDevices
private fun AppSideLoadedAlertDialogPreview() {
AppThemeSurface {
AppSideLoadedAlertDialog(alertDialogState = rememberAlertDialogState(), onDownloadClick = {}, onCancelClick = {})
AppSideLoadedAlertDialog(alertDialogState = rememberAlertDialogState(), onDownloadClick = {}) {}
}
}

View file

@ -2,11 +2,37 @@ package com.simplemobiletools.commons.dialogs
import android.os.Bundle
import android.view.ViewGroup
import androidx.compose.foundation.Image
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.ListItem
import androidx.compose.material3.ListItemDefaults
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.ColorFilter
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.sp
import androidx.fragment.app.FragmentManager
import com.simplemobiletools.commons.R
import com.simplemobiletools.commons.adapters.setupSimpleListItem
import com.simplemobiletools.commons.compose.alert_dialog.dialogContainerColor
import com.simplemobiletools.commons.compose.alert_dialog.dialogTextColor
import com.simplemobiletools.commons.compose.bottom_sheet.BottomSheetColumnDialogSurface
import com.simplemobiletools.commons.compose.bottom_sheet.BottomSheetDialogState
import com.simplemobiletools.commons.compose.bottom_sheet.BottomSheetSpacerEdgeToEdge
import com.simplemobiletools.commons.compose.bottom_sheet.rememberBottomSheetDialogState
import com.simplemobiletools.commons.compose.extensions.MyDevices
import com.simplemobiletools.commons.compose.theme.AppThemeSurface
import com.simplemobiletools.commons.compose.theme.SimpleTheme
import com.simplemobiletools.commons.databinding.ItemSimpleListBinding
import com.simplemobiletools.commons.fragments.BaseBottomSheetDialogFragment
import com.simplemobiletools.commons.models.SimpleListItem
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.toImmutableList
open class BottomSheetChooserDialog : BaseBottomSheetDialogFragment() {
@ -52,3 +78,71 @@ open class BottomSheetChooserDialog : BaseBottomSheetDialogFragment() {
}
}
}
@Composable
fun ChooserBottomSheetDialog(
bottomSheetDialogState: BottomSheetDialogState,
items: ImmutableList<SimpleListItem>,
modifier: Modifier = Modifier,
onItemClicked: (SimpleListItem) -> Unit
) {
BottomSheetColumnDialogSurface(modifier) {
Text(
text = stringResource(id = R.string.please_select_destination),
color = dialogTextColor,
fontSize = 21.sp,
fontWeight = FontWeight.Bold,
modifier = Modifier
.padding(SimpleTheme.dimens.padding.extraLarge)
.padding(top = SimpleTheme.dimens.padding.large)
)
for (item in items) {
val color = if (item.selected) SimpleTheme.colorScheme.primary else SimpleTheme.colorScheme.onSurface
ListItem(
modifier = Modifier
.clickable {
onItemClicked(item)
bottomSheetDialogState.close()
},
headlineContent = {
Text(stringResource(id = item.textRes), color = color)
},
leadingContent = {
if (item.imageRes != null) {
Image(
painter = painterResource(id = item.imageRes),
contentDescription = stringResource(id = item.textRes),
colorFilter = ColorFilter.tint(color)
)
}
},
trailingContent = {
if (item.selected) {
Image(
painter = painterResource(id = R.drawable.ic_check_circle_vector),
contentDescription = null,
colorFilter = ColorFilter.tint(color)
)
}
},
colors = ListItemDefaults.colors(containerColor = dialogContainerColor)
)
}
BottomSheetSpacerEdgeToEdge()
}
}
@MyDevices
@Composable
private fun ChooserBottomSheetDialogPreview() {
AppThemeSurface {
val list = remember {
listOf(
SimpleListItem(1, R.string.record_video, R.drawable.ic_camera_vector),
SimpleListItem(2, R.string.record_audio, R.drawable.ic_microphone_vector, selected = true),
SimpleListItem(4, R.string.choose_contact, R.drawable.ic_add_person_vector)
).toImmutableList()
}
ChooserBottomSheetDialog(bottomSheetDialogState = rememberBottomSheetDialogState(), items = list, onItemClicked = {})
}
}

View file

@ -27,8 +27,7 @@ import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.simplemobiletools.commons.R
import com.simplemobiletools.commons.activities.BaseSimpleActivity
import com.simplemobiletools.commons.compose.alert_dialog.AlertDialogState
import com.simplemobiletools.commons.compose.alert_dialog.rememberAlertDialogState
import com.simplemobiletools.commons.compose.alert_dialog.*
import com.simplemobiletools.commons.compose.extensions.MyDevices
import com.simplemobiletools.commons.compose.theme.AppThemeSurface
import com.simplemobiletools.commons.databinding.DialogCallConfirmationBinding
@ -61,9 +60,9 @@ class CallConfirmationDialog(val activity: BaseSimpleActivity, val callee: Strin
@Composable
fun CallConfirmationAlertDialog(
modifier: Modifier = Modifier,
alertDialogState: AlertDialogState,
callee: String,
modifier: Modifier = Modifier,
callback: () -> Unit
) {
androidx.compose.material3.AlertDialog(
@ -140,6 +139,7 @@ private fun CallConfirmationAlertDialogPreview() {
AppThemeSurface {
CallConfirmationAlertDialog(
alertDialogState = rememberAlertDialogState(),
callee = "Simple Mobile Tools", callback = {})
callee = "Simple Mobile Tools"
) {}
}
}

View file

@ -22,6 +22,7 @@ import androidx.compose.ui.unit.LayoutDirection
import androidx.compose.ui.unit.dp
import com.simplemobiletools.commons.R
import com.simplemobiletools.commons.compose.alert_dialog.AlertDialogState
import com.simplemobiletools.commons.compose.alert_dialog.DialogSurface
import com.simplemobiletools.commons.compose.alert_dialog.rememberAlertDialogState
import com.simplemobiletools.commons.compose.components.RadioGroupDialogComponent
import com.simplemobiletools.commons.compose.extensions.MyDevices
@ -104,8 +105,8 @@ class ChangeDateTimeFormatDialog(val activity: Activity, val callback: () -> Uni
@Composable
fun ChangeDateTimeFormatAlertDialog(
alertDialogState: AlertDialogState,
modifier: Modifier = Modifier,
is24HourChecked: Boolean,
modifier: Modifier = Modifier,
callback: (selectedFormat: String, is24HourChecked: Boolean) -> Unit
) {
val context = LocalContext.current
@ -153,7 +154,7 @@ fun ChangeDateTimeFormatAlertDialog(
SettingsHorizontalDivider()
CompositionLocalProvider(LocalLayoutDirection provides LayoutDirection.Rtl) {
DialogCheckBoxChangeDateTimeFormatComponent(
DialogCheckBoxWithRadioAlignmentComponent(
label = stringResource(id = R.string.use_24_hour_time_format),
initialValue = is24HoursSelected,
onChange = { is24HoursSelected = it },
@ -197,7 +198,7 @@ private fun formatDateSample(format: String): String {
}
@Composable
private fun DialogCheckBoxChangeDateTimeFormatComponent(
internal fun DialogCheckBoxWithRadioAlignmentComponent(
modifier: Modifier = Modifier,
label: String,
initialValue: Boolean = false,
@ -253,6 +254,6 @@ private fun DialogCheckBoxChangeDateTimeFormatComponent(
@MyDevices
private fun ChangeDateTimeFormatAlertDialogPreview() {
AppThemeSurface {
ChangeDateTimeFormatAlertDialog(alertDialogState = rememberAlertDialogState(), callback = { _, _ -> }, is24HourChecked = true)
ChangeDateTimeFormatAlertDialog(alertDialogState = rememberAlertDialogState(), is24HourChecked = true) { _, _ -> }
}
}

View file

@ -15,6 +15,7 @@ import androidx.compose.ui.unit.dp
import com.simplemobiletools.commons.R
import com.simplemobiletools.commons.activities.BaseSimpleActivity
import com.simplemobiletools.commons.compose.alert_dialog.AlertDialogState
import com.simplemobiletools.commons.compose.alert_dialog.DialogSurface
import com.simplemobiletools.commons.compose.alert_dialog.rememberAlertDialogState
import com.simplemobiletools.commons.compose.components.RadioGroupDialogComponent
import com.simplemobiletools.commons.compose.extensions.MyDevices
@ -68,8 +69,8 @@ data class ViewType(val title: String, val type: Int)
@Composable
fun ChangeViewTypeAlertDialog(
alertDialogState: AlertDialogState,
modifier: Modifier = Modifier,
selectedViewType: Int,
modifier: Modifier = Modifier,
onTypeChosen: (type: Int) -> Unit
) {
val context = LocalContext.current
@ -136,6 +137,6 @@ private fun getSelectedValue(
@Composable
private fun ChangeViewTypeAlertDialogPreview() {
AppThemeSurface {
ChangeViewTypeAlertDialog(alertDialogState = rememberAlertDialogState(), onTypeChosen = {}, selectedViewType = VIEW_TYPE_GRID)
ChangeViewTypeAlertDialog(alertDialogState = rememberAlertDialogState(), selectedViewType = VIEW_TYPE_GRID) {}
}
}

View file

@ -33,6 +33,8 @@ import androidx.core.view.children
import androidx.core.view.updateLayoutParams
import com.simplemobiletools.commons.R
import com.simplemobiletools.commons.compose.alert_dialog.AlertDialogState
import com.simplemobiletools.commons.compose.alert_dialog.DialogSurface
import com.simplemobiletools.commons.compose.alert_dialog.dialogBorder
import com.simplemobiletools.commons.compose.alert_dialog.rememberAlertDialogState
import com.simplemobiletools.commons.compose.extensions.MyDevices
import com.simplemobiletools.commons.compose.extensions.config
@ -143,9 +145,8 @@ class ColorPickerDialog(
@Composable
fun ColorPickerAlertDialog(
alertDialogState: AlertDialogState,
@ColorInt color: Int,
modifier: Modifier = Modifier,
@ColorInt
color: Int,
removeDimmedBackground: Boolean = false,
addDefaultColorButton: Boolean = false,
onActiveColorChange: (color: Int) -> Unit,
@ -416,7 +417,7 @@ private fun ColorPickerAlertDialogPreview() {
ColorPickerAlertDialog(
alertDialogState = rememberAlertDialogState(),
color = colorResource(id = R.color.color_primary).toArgb(),
onActiveColorChange = {},
onButtonPressed = { _, _ -> })
onActiveColorChange = {}
) { _, _ -> }
}
}

View file

@ -11,8 +11,7 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.sp
import androidx.compose.ui.window.DialogProperties
import com.simplemobiletools.commons.R
import com.simplemobiletools.commons.compose.alert_dialog.AlertDialogState
import com.simplemobiletools.commons.compose.alert_dialog.rememberAlertDialogState
import com.simplemobiletools.commons.compose.alert_dialog.*
import com.simplemobiletools.commons.compose.extensions.MyDevices
import com.simplemobiletools.commons.compose.theme.AppThemeSurface
import com.simplemobiletools.commons.databinding.DialogMessageBinding
@ -61,8 +60,8 @@ class ConfirmationAdvancedDialog(
@Composable
fun ConfirmationAdvancedAlertDialog(
modifier: Modifier = Modifier,
alertDialogState: AlertDialogState,
modifier: Modifier = Modifier,
message: String = "",
messageId: Int? = R.string.proceed_with_deletion,
positive: Int? = R.string.yes,
@ -117,7 +116,8 @@ fun ConfirmationAdvancedAlertDialog(
@MyDevices
private fun ConfirmationAdvancedAlertDialogPreview() {
AppThemeSurface {
ConfirmationAdvancedAlertDialog(alertDialogState = rememberAlertDialogState(),
callback = {})
ConfirmationAdvancedAlertDialog(
alertDialogState = rememberAlertDialogState()
) {}
}
}

View file

@ -12,8 +12,7 @@ import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.sp
import androidx.compose.ui.window.DialogProperties
import com.simplemobiletools.commons.R
import com.simplemobiletools.commons.compose.alert_dialog.AlertDialogState
import com.simplemobiletools.commons.compose.alert_dialog.rememberAlertDialogState
import com.simplemobiletools.commons.compose.alert_dialog.*
import com.simplemobiletools.commons.compose.extensions.MyDevices
import com.simplemobiletools.commons.compose.theme.AppThemeSurface
import com.simplemobiletools.commons.databinding.DialogMessageBinding
@ -67,8 +66,8 @@ class ConfirmationDialog(
@Composable
fun ConfirmationAlertDialog(
modifier: Modifier = Modifier,
alertDialogState: AlertDialogState,
modifier: Modifier = Modifier,
message: String = "",
messageId: Int? = R.string.proceed_with_deletion,
positive: Int? = R.string.yes,
@ -134,7 +133,8 @@ fun ConfirmationAlertDialog(
@MyDevices
private fun ConfirmationAlertDialogPreview() {
AppThemeSurface {
ConfirmationAlertDialog(alertDialogState = rememberAlertDialogState(),
callback = {})
ConfirmationAlertDialog(
alertDialogState = rememberAlertDialogState()
) {}
}
}

View file

@ -2,8 +2,26 @@ package com.simplemobiletools.commons.dialogs
import android.view.View
import androidx.appcompat.app.AlertDialog
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalView
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.sp
import com.simplemobiletools.commons.R
import com.simplemobiletools.commons.activities.BaseSimpleActivity
import com.simplemobiletools.commons.compose.alert_dialog.*
import com.simplemobiletools.commons.compose.extensions.MyDevices
import com.simplemobiletools.commons.compose.theme.AppThemeSurface
import com.simplemobiletools.commons.compose.theme.SimpleTheme
import com.simplemobiletools.commons.databinding.DialogCreateNewFolderBinding
import com.simplemobiletools.commons.extensions.*
import com.simplemobiletools.commons.helpers.isRPlus
@ -33,6 +51,7 @@ class CreateNewFolderDialog(val activity: BaseSimpleActivity, val path: String,
createFolder("$path/$name", alertDialog)
}
else -> activity.toast(R.string.invalid_name)
}
})
@ -49,6 +68,7 @@ class CreateNewFolderDialog(val activity: BaseSimpleActivity, val path: String,
sendSuccess(alertDialog, path)
}
}
activity.needsStupidWritePermissions(path) -> activity.handleSAFDialog(path) {
if (it) {
try {
@ -64,12 +84,14 @@ class CreateNewFolderDialog(val activity: BaseSimpleActivity, val path: String,
}
}
}
File(path).mkdirs() -> sendSuccess(alertDialog, path)
isRPlus() && activity.isAStorageRootFolder(path.getParentPath()) -> activity.handleSAFCreateDocumentDialogSdk30(path) {
if (it) {
sendSuccess(alertDialog, path)
}
}
else -> activity.toast(activity.getString(R.string.could_not_create_folder, path.getFilenameFromPath()))
}
} catch (e: Exception) {
@ -82,3 +104,112 @@ class CreateNewFolderDialog(val activity: BaseSimpleActivity, val path: String,
alertDialog.dismiss()
}
}
@Composable
fun CreateNewFolderAlertDialog(
alertDialogState: AlertDialogState,
path: String,
modifier: Modifier = Modifier,
callback: (path: String) -> Unit
) {
val focusRequester = remember { FocusRequester() }
val context = LocalContext.current
val view = LocalView.current
var title by remember { mutableStateOf("") }
AlertDialog(
modifier = modifier.dialogBorder,
shape = dialogShape,
containerColor = dialogContainerColor,
tonalElevation = dialogElevation,
onDismissRequest = alertDialogState::hide,
confirmButton = {
TextButton(
onClick = {
alertDialogState.hide()
//add callback
val name = title
when {
name.isEmpty() -> context.toast(R.string.empty_name)
name.isAValidFilename() -> {
val file = File(path, name)
if (file.exists()) {
context.toast(R.string.name_taken)
return@TextButton
}
callback("$path/$name")
}
else -> context.toast(R.string.invalid_name)
}
}
) {
Text(text = stringResource(id = R.string.ok))
}
},
dismissButton = {
TextButton(
onClick = alertDialogState::hide
) {
Text(text = stringResource(id = R.string.cancel))
}
},
title = {
Text(
text = stringResource(id = R.string.create_new_folder),
color = dialogTextColor,
fontSize = 21.sp,
fontWeight = FontWeight.Bold,
)
},
text = {
Column(
Modifier.fillMaxWidth(),
) {
OutlinedTextField(
modifier = Modifier
.fillMaxWidth(),
value = if (!view.isInEditMode) "${context.humanizePath(path).trimEnd('/')}/" else path,
onValueChange = {},
label = {
Text(text = stringResource(id = R.string.folder))
},
enabled = false,
colors = OutlinedTextFieldDefaults.colors(
disabledTextColor = dialogTextColor,
disabledBorderColor = SimpleTheme.colorScheme.primary,
disabledLabelColor = SimpleTheme.colorScheme.primary,
)
)
Spacer(modifier = Modifier.padding(vertical = SimpleTheme.dimens.padding.medium))
OutlinedTextField(
modifier = Modifier
.fillMaxWidth()
.focusRequester(focusRequester),
value = title,
onValueChange = {
title = it
},
label = {
Text(text = stringResource(id = R.string.title))
},
)
}
}
)
ShowKeyboardWhenDialogIsOpenedAndRequestFocus(focusRequester = focusRequester)
}
@MyDevices
@Composable
private fun CreateNewFolderAlertDialogPreview() {
AppThemeSurface {
CreateNewFolderAlertDialog(
alertDialogState = rememberAlertDialogState(),
path = "Internal/"
) {}
}
}

View file

@ -1,16 +1,46 @@
package com.simplemobiletools.commons.dialogs
import android.app.Activity
import android.content.Context
import android.content.DialogInterface
import android.view.KeyEvent
import android.view.View
import androidx.appcompat.app.AlertDialog
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.TextRange
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.text.input.TextFieldValue
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.DialogProperties
import com.simplemobiletools.commons.R
import com.simplemobiletools.commons.compose.alert_dialog.AlertDialogState
import com.simplemobiletools.commons.compose.alert_dialog.DialogSurface
import com.simplemobiletools.commons.compose.alert_dialog.ShowKeyboardWhenDialogIsOpenedAndRequestFocus
import com.simplemobiletools.commons.compose.alert_dialog.rememberAlertDialogState
import com.simplemobiletools.commons.compose.components.RadioGroupDialogComponent
import com.simplemobiletools.commons.compose.extensions.MyDevices
import com.simplemobiletools.commons.compose.theme.AppThemeSurface
import com.simplemobiletools.commons.compose.theme.SimpleTheme
import com.simplemobiletools.commons.databinding.DialogCustomIntervalPickerBinding
import com.simplemobiletools.commons.extensions.*
import com.simplemobiletools.commons.helpers.DAY_SECONDS
import com.simplemobiletools.commons.helpers.HOUR_SECONDS
import com.simplemobiletools.commons.helpers.MINUTE_SECONDS
import kotlinx.collections.immutable.toImmutableList
class CustomIntervalPickerDialog(val activity: Activity, val selectedSeconds: Int = 0, val showSeconds: Boolean = false, val callback: (minutes: Int) -> Unit) {
private var dialog: AlertDialog? = null
@ -35,14 +65,17 @@ class CustomIntervalPickerDialog(val activity: Activity, val selectedSeconds: In
dialogRadioView.check(R.id.dialog_radio_days)
dialogCustomIntervalValue.setText((selectedSeconds / DAY_SECONDS).toString())
}
selectedSeconds % HOUR_SECONDS == 0 -> {
dialogRadioView.check(R.id.dialog_radio_hours)
dialogCustomIntervalValue.setText((selectedSeconds / HOUR_SECONDS).toString())
}
selectedSeconds % MINUTE_SECONDS == 0 -> {
dialogRadioView.check(R.id.dialog_radio_minutes)
dialogCustomIntervalValue.setText((selectedSeconds / MINUTE_SECONDS).toString())
}
else -> {
dialogRadioView.check(R.id.dialog_radio_seconds)
dialogCustomIntervalValue.setText(selectedSeconds.toString())
@ -78,3 +111,172 @@ class CustomIntervalPickerDialog(val activity: Activity, val selectedSeconds: In
else -> 1
}
}
@Composable
fun CustomIntervalPickerAlertDialog(
alertDialogState: AlertDialogState,
modifier: Modifier = Modifier,
selectedSeconds: Int = 0,
showSeconds: Boolean = false,
callback: (minutes: Int) -> Unit
) {
val focusRequester = remember { FocusRequester() }
var textFieldValue by remember {
mutableStateOf(initialTextFieldValue(selectedSeconds))
}
val context = LocalContext.current
val selections = remember {
buildCustomIntervalEntries(context, showSeconds)
}
val initiallySelected = remember {
initialSelection(selectedSeconds, context)
}
val (selected, setSelected) = remember { mutableStateOf(initiallySelected) }
AlertDialog(
modifier = modifier.fillMaxWidth(0.95f),
onDismissRequest = alertDialogState::hide,
properties = DialogProperties(usePlatformDefaultWidth = false)
) {
DialogSurface {
Box {
Column(
modifier = modifier
.padding(bottom = 64.dp)
.verticalScroll(rememberScrollState())
) {
OutlinedTextField(
modifier = Modifier
.fillMaxWidth()
.padding(
top = SimpleTheme.dimens.padding.extraLarge,
start = SimpleTheme.dimens.padding.extraLarge,
end = SimpleTheme.dimens.padding.extraLarge
)
.focusRequester(focusRequester),
value = textFieldValue,
onValueChange = { newValue ->
if (newValue.text.length <= 5) textFieldValue = newValue
},
label = {
Text(text = stringResource(id = R.string.value))
},
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number),
maxLines = 1
)
RadioGroupDialogComponent(
items = selections,
selected = selected,
setSelected = setSelected,
modifier = Modifier.padding(
vertical = SimpleTheme.dimens.padding.extraLarge,
)
)
}
Row(
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.End,
modifier = Modifier
.fillMaxWidth()
.padding(
top = SimpleTheme.dimens.padding.extraLarge,
bottom = SimpleTheme.dimens.padding.extraLarge,
end = SimpleTheme.dimens.padding.extraLarge
)
.align(Alignment.BottomStart)
) {
TextButton(onClick = alertDialogState::hide) {
Text(text = stringResource(id = R.string.cancel))
}
TextButton(onClick = {
val multiplier = getMultiplier(context, selected)
val minutes = Integer.valueOf(textFieldValue.text.ifEmpty { "0" })
callback(minutes * multiplier)
alertDialogState.hide()
}) {
Text(text = stringResource(id = R.string.ok))
}
}
}
}
}
ShowKeyboardWhenDialogIsOpenedAndRequestFocus(focusRequester = focusRequester)
}
private fun initialSelection(selectedSeconds: Int, context: Context) = requireNotNull(
when {
selectedSeconds == 0 -> minutesRaw(context)
selectedSeconds % DAY_SECONDS == 0 -> daysRaw(context)
selectedSeconds % HOUR_SECONDS == 0 -> hoursRaw(context)
selectedSeconds % MINUTE_SECONDS == 0 -> minutesRaw(context)
else -> secondsRaw(context)
}
) {
"Incorrect format, please check selections"
}
private fun initialTextFieldValue(selectedSeconds: Int) = when {
selectedSeconds == 0 -> TextFieldValue("")
selectedSeconds % DAY_SECONDS == 0 -> {
val text = (selectedSeconds / DAY_SECONDS).toString()
textFieldValueAndSelection(text)
}
selectedSeconds % HOUR_SECONDS == 0 -> {
val text = (selectedSeconds / HOUR_SECONDS).toString()
textFieldValueAndSelection(text)
}
selectedSeconds % MINUTE_SECONDS == 0 -> {
val text = (selectedSeconds / MINUTE_SECONDS).toString()
textFieldValueAndSelection(text)
}
else -> {
val text = selectedSeconds.toString()
textFieldValueAndSelection(text)
}
}
private fun textFieldValueAndSelection(text: String) = TextFieldValue(text = text, selection = TextRange(text.length))
fun buildCustomIntervalEntries(context: Context, showSeconds: Boolean) =
buildList {
if (showSeconds) {
add(secondsRaw(context))
}
add(minutesRaw(context))
add(hoursRaw(context))
add(daysRaw(context))
}.toImmutableList()
private fun daysRaw(context: Context) = context.getString(R.string.days_raw)
private fun hoursRaw(context: Context) = context.getString(R.string.hours_raw)
private fun secondsRaw(context: Context) = context.getString(R.string.seconds_raw)
private fun minutesRaw(context: Context) = context.getString(R.string.minutes_raw)
private fun getMultiplier(context: Context, text: String) = when (text) {
daysRaw(context) -> DAY_SECONDS
hoursRaw(context) -> HOUR_SECONDS
minutesRaw(context) -> MINUTE_SECONDS
else -> 1
}
@Composable
@MyDevices
private fun CustomIntervalPickerAlertDialogPreview() {
AppThemeSurface {
CustomIntervalPickerAlertDialog(alertDialogState = rememberAlertDialogState(),
selectedSeconds = 0,
showSeconds = true,
callback = {}
)
}
}

View file

@ -22,8 +22,7 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.sp
import androidx.compose.ui.window.DialogProperties
import com.simplemobiletools.commons.R
import com.simplemobiletools.commons.compose.alert_dialog.AlertDialogState
import com.simplemobiletools.commons.compose.alert_dialog.rememberAlertDialogState
import com.simplemobiletools.commons.compose.alert_dialog.*
import com.simplemobiletools.commons.compose.components.LinkifyTextComponent
import com.simplemobiletools.commons.compose.extensions.MyDevices
import com.simplemobiletools.commons.compose.extensions.getActivity

View file

@ -1,8 +1,29 @@
package com.simplemobiletools.commons.dialogs
import androidx.appcompat.app.AlertDialog
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Visibility
import androidx.compose.material.icons.filled.VisibilityOff
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.text.input.PasswordVisualTransformation
import androidx.compose.ui.text.input.VisualTransformation
import androidx.compose.ui.unit.sp
import com.simplemobiletools.commons.R
import com.simplemobiletools.commons.activities.BaseSimpleActivity
import com.simplemobiletools.commons.compose.alert_dialog.*
import com.simplemobiletools.commons.compose.extensions.MyDevices
import com.simplemobiletools.commons.compose.extensions.andThen
import com.simplemobiletools.commons.compose.theme.AppThemeSurface
import com.simplemobiletools.commons.databinding.DialogEnterPasswordBinding
import com.simplemobiletools.commons.extensions.*
@ -52,3 +73,95 @@ class EnterPasswordDialog(
view.password.text?.clear()
}
}
@Composable
fun EnterPasswordAlertDialog(
alertDialogState: AlertDialogState,
modifier: Modifier = Modifier,
callback: (password: String) -> Unit,
cancelCallback: () -> Unit
) {
val localContext = LocalContext.current
val focusRequester = remember { FocusRequester() }
var password by remember { mutableStateOf("") }
var passwordVisible by remember { mutableStateOf(false) }
val visualTransformation by remember {
derivedStateOf {
if (passwordVisible) VisualTransformation.None else PasswordVisualTransformation()
}
}
AlertDialog(
modifier = modifier.dialogBorder,
shape = dialogShape,
containerColor = dialogContainerColor,
tonalElevation = dialogElevation,
onDismissRequest = alertDialogState::hide andThen cancelCallback,
confirmButton = {
TextButton(
onClick = {
if (password.isEmpty()) {
localContext.toast(R.string.empty_password)
} else {
alertDialogState.hide()
callback(password)
}
}
) {
Text(text = stringResource(id = R.string.ok))
}
},
dismissButton = {
TextButton(
onClick = alertDialogState::hide
) {
Text(text = stringResource(id = R.string.cancel))
}
},
title = {
Text(
text = stringResource(id = R.string.enter_password),
color = dialogTextColor,
fontSize = 21.sp,
fontWeight = FontWeight.Bold,
)
},
text = {
OutlinedTextField(
visualTransformation = visualTransformation,
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Password),
trailingIcon = {
val image = passwordImageVector(passwordVisible)
IconButton(onClick = { passwordVisible = !passwordVisible }) {
Icon(imageVector = image, null)
}
},
modifier = Modifier
.fillMaxWidth()
.focusRequester(focusRequester),
value = password,
onValueChange = {
password = it
},
label = {
Text(text = stringResource(id = R.string.password))
},
singleLine = true
)
}
)
ShowKeyboardWhenDialogIsOpenedAndRequestFocus(focusRequester = focusRequester)
}
private fun passwordImageVector(passwordVisible: Boolean) = if (passwordVisible) {
Icons.Filled.Visibility
} else {
Icons.Filled.VisibilityOff
}
@MyDevices
@Composable
private fun EnterPasswordAlertDialogPreview() {
AppThemeSurface {
EnterPasswordAlertDialog(rememberAlertDialogState(), callback = {}, cancelCallback = {})
}
}

View file

@ -22,8 +22,7 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.sp
import androidx.compose.ui.window.DialogProperties
import com.simplemobiletools.commons.R
import com.simplemobiletools.commons.compose.alert_dialog.AlertDialogState
import com.simplemobiletools.commons.compose.alert_dialog.rememberAlertDialogState
import com.simplemobiletools.commons.compose.alert_dialog.*
import com.simplemobiletools.commons.compose.components.LinkifyTextComponent
import com.simplemobiletools.commons.compose.extensions.MyDevices
import com.simplemobiletools.commons.compose.extensions.composeDonateIntent

View file

@ -1,7 +1,32 @@
package com.simplemobiletools.commons.dialogs
import android.app.Activity
import android.content.Context
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalLayoutDirection
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.LayoutDirection
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.simplemobiletools.commons.R
import com.simplemobiletools.commons.compose.alert_dialog.AlertDialogState
import com.simplemobiletools.commons.compose.alert_dialog.DialogSurface
import com.simplemobiletools.commons.compose.alert_dialog.dialogTextColor
import com.simplemobiletools.commons.compose.alert_dialog.rememberAlertDialogState
import com.simplemobiletools.commons.compose.components.RadioGroupDialogComponent
import com.simplemobiletools.commons.compose.extensions.MyDevices
import com.simplemobiletools.commons.compose.settings.SettingsHorizontalDivider
import com.simplemobiletools.commons.compose.theme.AppThemeSurface
import com.simplemobiletools.commons.compose.theme.SimpleTheme
import com.simplemobiletools.commons.databinding.DialogFileConflictBinding
import com.simplemobiletools.commons.extensions.baseConfig
import com.simplemobiletools.commons.extensions.beVisibleIf
@ -12,6 +37,9 @@ import com.simplemobiletools.commons.helpers.CONFLICT_MERGE
import com.simplemobiletools.commons.helpers.CONFLICT_OVERWRITE
import com.simplemobiletools.commons.helpers.CONFLICT_SKIP
import com.simplemobiletools.commons.models.FileDirItem
import com.simplemobiletools.commons.models.FileDirItemReadOnly
import com.simplemobiletools.commons.models.asReadOnly
import kotlinx.collections.immutable.toImmutableList
class FileConflictDialog(
val activity: Activity, val fileDirItem: FileDirItem, val showApplyToAllCheckbox: Boolean,
@ -61,3 +89,125 @@ class FileConflictDialog(
callback(resolution, applyToAll)
}
}
@Composable
fun FileConflictAlertDialog(
alertDialogState: AlertDialogState,
fileDirItem: FileDirItemReadOnly,
showApplyToAll: Boolean,
modifier: Modifier = Modifier,
callback: (resolution: Int, applyForAll: Boolean) -> Unit
) {
val context = LocalContext.current
var isShowApplyForAllChecked by remember { mutableStateOf(context.baseConfig.lastConflictApplyToAll) }
val selections = remember {
buildFileConflictEntries(context, fileDirItem.isDirectory)
}
val kinds = remember {
selections.values.toImmutableList()
}
val initiallySelected = remember {
requireNotNull(selections[context.baseConfig.lastConflictResolution]) {
"Incorrect format, please check selections"
}
}
val (selected, setSelected) = remember { mutableStateOf(initiallySelected) }
AlertDialog(
onDismissRequest = alertDialogState::hide
) {
DialogSurface {
Box {
Column(
modifier = modifier
.padding(bottom = 64.dp)
.verticalScroll(rememberScrollState())
) {
Text(
text = String.format(
stringResource(id = if (fileDirItem.isDirectory) R.string.folder_already_exists else R.string.file_already_exists),
fileDirItem.name
),
modifier = Modifier
.fillMaxWidth()
.padding(top = 24.dp, bottom = SimpleTheme.dimens.padding.medium)
.padding(horizontal = 24.dp),
color = dialogTextColor,
fontSize = 21.sp
)
RadioGroupDialogComponent(
items = kinds, selected = selected,
setSelected = setSelected,
modifier = Modifier.padding(
vertical = SimpleTheme.dimens.padding.extraLarge,
)
)
if (showApplyToAll) {
SettingsHorizontalDivider()
CompositionLocalProvider(LocalLayoutDirection provides LayoutDirection.Rtl) {
DialogCheckBoxWithRadioAlignmentComponent(
label = stringResource(id = R.string.apply_to_all),
initialValue = isShowApplyForAllChecked,
onChange = { isShowApplyForAllChecked = it },
modifier = Modifier.padding(horizontal = SimpleTheme.dimens.padding.medium)
)
}
}
}
Row(
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.End,
modifier = Modifier
.fillMaxWidth()
.padding(
top = SimpleTheme.dimens.padding.extraLarge,
bottom = SimpleTheme.dimens.padding.extraLarge,
end = SimpleTheme.dimens.padding.extraLarge
)
.align(Alignment.BottomStart)
) {
TextButton(onClick = {
alertDialogState.hide()
}) {
Text(text = stringResource(id = R.string.cancel))
}
TextButton(onClick = {
alertDialogState.hide()
callback(selections.filterValues { it == selected }.keys.first(), isShowApplyForAllChecked)
}) {
Text(text = stringResource(id = R.string.ok))
}
}
}
}
}
}
private fun buildFileConflictEntries(context: Context, directory: Boolean) =
buildMap {
this[CONFLICT_SKIP] = context.getString(R.string.skip)
if (directory) {
this[CONFLICT_SKIP] = context.getString(R.string.merge)
}
this[CONFLICT_OVERWRITE] = context.getString(R.string.overwrite)
this[CONFLICT_KEEP_BOTH] = context.getString(R.string.keep_both)
}
@MyDevices
@Composable
private fun FileConflictAlertDialogPreview() {
AppThemeSurface {
FileConflictAlertDialog(
alertDialogState = rememberAlertDialogState(),
fileDirItem = FileDirItem("", name = "test", children = 1).asReadOnly(),
showApplyToAll = true
) { _, _ -> }
}
}

View file

@ -1,7 +1,19 @@
package com.simplemobiletools.commons.dialogs
import android.app.Activity
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.sp
import com.simplemobiletools.commons.R
import com.simplemobiletools.commons.compose.alert_dialog.*
import com.simplemobiletools.commons.compose.extensions.MyDevices
import com.simplemobiletools.commons.compose.extensions.andThen
import com.simplemobiletools.commons.compose.theme.AppThemeSurface
import com.simplemobiletools.commons.databinding.DialogTextviewBinding
import com.simplemobiletools.commons.extensions.baseConfig
import com.simplemobiletools.commons.extensions.getAlertDialogBuilder
@ -26,3 +38,57 @@ class FolderLockingNoticeDialog(val activity: Activity, val callback: () -> Unit
callback()
}
}
@Composable
fun FolderLockingNoticeAlertDialog(
alertDialogState: AlertDialogState,
modifier: Modifier = Modifier,
callback: () -> Unit
) {
AlertDialog(
modifier = modifier.dialogBorder,
shape = dialogShape,
containerColor = dialogContainerColor,
tonalElevation = dialogElevation,
onDismissRequest = alertDialogState::hide,
confirmButton = {
TextButton(
onClick = alertDialogState::hide andThen callback
) {
Text(text = stringResource(id = R.string.ok))
}
},
dismissButton = {
TextButton(
onClick = alertDialogState::hide
) {
Text(text = stringResource(id = R.string.cancel))
}
},
title = {
Text(
text = stringResource(id = R.string.disclaimer),
color = dialogTextColor,
fontSize = 21.sp,
fontWeight = FontWeight.Bold,
)
},
text = {
Text(
text = stringResource(id = R.string.lock_folder_notice),
color = dialogTextColor,
)
}
)
}
@Composable
@MyDevices
private fun FolderLockingNoticeAlertDialogPreview() {
AppThemeSurface {
FolderLockingNoticeAlertDialog(
alertDialogState = rememberAlertDialogState(),
callback = {},
)
}
}

View file

@ -25,6 +25,8 @@ import com.google.android.material.appbar.MaterialToolbar
import com.simplemobiletools.commons.R
import com.simplemobiletools.commons.activities.BaseSimpleActivity
import com.simplemobiletools.commons.compose.alert_dialog.AlertDialogState
import com.simplemobiletools.commons.compose.alert_dialog.DialogSurface
import com.simplemobiletools.commons.compose.alert_dialog.dialogTextColor
import com.simplemobiletools.commons.compose.alert_dialog.rememberAlertDialogState
import com.simplemobiletools.commons.compose.extensions.MyDevices
import com.simplemobiletools.commons.compose.theme.AppThemeSurface
@ -166,9 +168,9 @@ class LineColorPickerDialog(
@Composable
fun LineColorPickerAlertDialog(
alertDialogState: AlertDialogState,
modifier: Modifier = Modifier,
@ColorInt color: Int,
isPrimaryColorPicker: Boolean,
modifier: Modifier = Modifier,
primaryColors: Int = R.array.md_primary_colors,
appIconIDs: ArrayList<Int>? = null,
onActiveColorChange: (color: Int) -> Unit,
@ -328,7 +330,7 @@ private fun LineColorPickerAlertDialogPreview() {
LineColorPickerAlertDialog(alertDialogState = rememberAlertDialogState(),
color = R.color.color_primary,
isPrimaryColorPicker = true,
onActiveColorChange = {},
onButtonPressed = { _, _ -> })
onActiveColorChange = {}
) { _, _ -> }
}
}

View file

@ -10,8 +10,7 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.sp
import com.simplemobiletools.commons.R
import com.simplemobiletools.commons.activities.BaseSimpleActivity
import com.simplemobiletools.commons.compose.alert_dialog.AlertDialogState
import com.simplemobiletools.commons.compose.alert_dialog.rememberAlertDialogState
import com.simplemobiletools.commons.compose.alert_dialog.*
import com.simplemobiletools.commons.compose.extensions.MyDevices
import com.simplemobiletools.commons.compose.theme.AppThemeSurface
import com.simplemobiletools.commons.databinding.DialogOpenDeviceSettingsBinding
@ -39,8 +38,8 @@ class OpenDeviceSettingsDialog(val activity: BaseSimpleActivity, message: String
@Composable
fun OpenDeviceSettingsAlertDialog(
alertDialogState: AlertDialogState,
modifier: Modifier = Modifier,
message: String
message: String,
modifier: Modifier = Modifier
) {
val context = LocalContext.current
@ -59,9 +58,7 @@ fun OpenDeviceSettingsAlertDialog(
)
},
dismissButton = {
TextButton(onClick = {
alertDialogState.hide()
}) {
TextButton(onClick = alertDialogState::hide) {
Text(text = stringResource(id = R.string.close))
}
},

View file

@ -11,8 +11,7 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.sp
import com.simplemobiletools.commons.R
import com.simplemobiletools.commons.compose.alert_dialog.AlertDialogState
import com.simplemobiletools.commons.compose.alert_dialog.rememberAlertDialogState
import com.simplemobiletools.commons.compose.alert_dialog.*
import com.simplemobiletools.commons.compose.extensions.MyDevices
import com.simplemobiletools.commons.compose.theme.AppThemeSurface
import com.simplemobiletools.commons.databinding.DialogMessageBinding
@ -45,10 +44,10 @@ class PermissionRequiredDialog(
@Composable
fun PermissionRequiredAlertDialog(
alertDialogState: AlertDialogState,
modifier: Modifier = Modifier,
text: String,
positiveActionCallback: () -> Unit,
negativeActionCallback: (() -> Unit)? = null
modifier: Modifier = Modifier,
negativeActionCallback: (() -> Unit)? = null,
positiveActionCallback: () -> Unit
) {
AlertDialog(
containerColor = dialogContainerColor,
@ -96,8 +95,7 @@ private fun PermissionRequiredAlertDialogPreview() {
PermissionRequiredAlertDialog(
alertDialogState = rememberAlertDialogState(),
text = "Test",
positiveActionCallback = {},
negativeActionCallback = {}
)
) {}
}
}

View file

@ -14,8 +14,7 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.sp
import androidx.compose.ui.window.DialogProperties
import com.simplemobiletools.commons.R
import com.simplemobiletools.commons.compose.alert_dialog.AlertDialogState
import com.simplemobiletools.commons.compose.alert_dialog.rememberAlertDialogState
import com.simplemobiletools.commons.compose.alert_dialog.*
import com.simplemobiletools.commons.compose.components.LinkifyTextComponent
import com.simplemobiletools.commons.compose.extensions.MyDevices
import com.simplemobiletools.commons.compose.extensions.composeDonateIntent

View file

@ -24,6 +24,8 @@ import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.simplemobiletools.commons.R
import com.simplemobiletools.commons.compose.alert_dialog.AlertDialogState
import com.simplemobiletools.commons.compose.alert_dialog.DialogSurface
import com.simplemobiletools.commons.compose.alert_dialog.dialogTextColor
import com.simplemobiletools.commons.compose.alert_dialog.rememberAlertDialogState
import com.simplemobiletools.commons.compose.components.RadioGroupDialogComponent
import com.simplemobiletools.commons.compose.extensions.BooleanPreviewParameterProvider
@ -101,8 +103,8 @@ class RadioGroupDialog(
@Composable
fun RadioGroupAlertDialog(
alertDialogState: AlertDialogState,
modifier: Modifier = Modifier,
items: ImmutableList<RadioItem>,
modifier: Modifier = Modifier,
selectedItemId: Int = -1,
titleId: Int = 0,
showOKButton: Boolean = false,
@ -186,11 +188,10 @@ private fun RadioGroupDialogAlertDialogPreview(@PreviewParameter(BooleanPreviewP
RadioItem(2, "Test 2"),
RadioItem(3, "Test 3"),
).toImmutableList(),
callback = {},
cancelCallback = {},
showOKButton = showOKButton,
selectedItemId = 1,
titleId = R.string.title,
selectedItemId = 1
)
showOKButton = showOKButton,
cancelCallback = {}
) {}
}
}

View file

@ -26,6 +26,8 @@ import androidx.compose.ui.unit.sp
import androidx.compose.ui.window.DialogProperties
import com.simplemobiletools.commons.R
import com.simplemobiletools.commons.compose.alert_dialog.AlertDialogState
import com.simplemobiletools.commons.compose.alert_dialog.DialogSurface
import com.simplemobiletools.commons.compose.alert_dialog.dialogTextColor
import com.simplemobiletools.commons.compose.alert_dialog.rememberAlertDialogState
import com.simplemobiletools.commons.compose.extensions.MyDevices
import com.simplemobiletools.commons.compose.theme.AppThemeSurface

View file

@ -17,8 +17,7 @@ import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.sp
import androidx.compose.ui.window.DialogProperties
import com.simplemobiletools.commons.R
import com.simplemobiletools.commons.compose.alert_dialog.AlertDialogState
import com.simplemobiletools.commons.compose.alert_dialog.rememberAlertDialogState
import com.simplemobiletools.commons.compose.alert_dialog.*
import com.simplemobiletools.commons.compose.extensions.MyDevices
import com.simplemobiletools.commons.compose.extensions.andThen
import com.simplemobiletools.commons.compose.theme.AppThemeSurface

View file

@ -16,8 +16,7 @@ import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.sp
import androidx.compose.ui.window.DialogProperties
import com.simplemobiletools.commons.R
import com.simplemobiletools.commons.compose.alert_dialog.AlertDialogState
import com.simplemobiletools.commons.compose.alert_dialog.rememberAlertDialogState
import com.simplemobiletools.commons.compose.alert_dialog.*
import com.simplemobiletools.commons.compose.extensions.MyDevices
import com.simplemobiletools.commons.compose.settings.SettingsHorizontalDivider
import com.simplemobiletools.commons.compose.theme.AppThemeSurface

View file

@ -32,6 +32,8 @@ import com.bumptech.glide.request.transition.DrawableCrossFadeFactory
import com.simplemobiletools.commons.R
import com.simplemobiletools.commons.activities.BaseSimpleActivity
import com.simplemobiletools.commons.compose.alert_dialog.AlertDialogState
import com.simplemobiletools.commons.compose.alert_dialog.DialogSurface
import com.simplemobiletools.commons.compose.alert_dialog.dialogTextColor
import com.simplemobiletools.commons.compose.alert_dialog.rememberAlertDialogState
import com.simplemobiletools.commons.compose.components.LinkifyTextComponent
import com.simplemobiletools.commons.compose.extensions.MyDevices
@ -136,8 +138,8 @@ class WritePermissionDialog(activity: Activity, val writePermissionDialogMode: W
@Composable
fun WritePermissionAlertDialog(
alertDialogState: AlertDialogState,
modifier: Modifier = Modifier,
writePermissionDialogMode: WritePermissionDialog.WritePermissionDialogMode,
modifier: Modifier = Modifier,
callback: () -> Unit,
onCancelCallback: () -> Unit
) {
@ -314,8 +316,7 @@ private fun WritePermissionAlertDialogPreview(@PreviewParameter(WritePermissionD
WritePermissionAlertDialog(
alertDialogState = rememberAlertDialogState(),
writePermissionDialogMode = WritePermissionDialog.WritePermissionDialogMode.OpenDocumentTreeSDK30("."),
callback = {},
onCancelCallback = {}
)
callback = {}
) {}
}
}

View file

@ -4,18 +4,19 @@ import android.content.Context
import android.content.res.Configuration
import android.os.Environment
import android.text.format.DateFormat
import androidx.core.content.ContextCompat
import com.simplemobiletools.commons.R
import com.simplemobiletools.commons.extensions.getInternalStoragePath
import com.simplemobiletools.commons.extensions.getSDCardPath
import com.simplemobiletools.commons.extensions.getSharedPrefs
import com.simplemobiletools.commons.extensions.sharedPreferencesCallback
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.filterNotNull
import java.text.SimpleDateFormat
import java.util.Calendar
import java.util.LinkedList
import java.util.Locale
import kotlin.reflect.KProperty0
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.filterNotNull
open class BaseConfig(val context: Context) {
protected val prefs = context.getSharedPrefs()
@ -85,19 +86,19 @@ open class BaseConfig(val context: Context) {
private fun getDefaultInternalPath() = if (prefs.contains(INTERNAL_STORAGE_PATH)) "" else context.getInternalStoragePath()
var textColor: Int
get() = prefs.getInt(TEXT_COLOR, context.resources.getColor(R.color.default_text_color))
get() = prefs.getInt(TEXT_COLOR, ContextCompat.getColor(context, R.color.default_text_color))
set(textColor) = prefs.edit().putInt(TEXT_COLOR, textColor).apply()
var backgroundColor: Int
get() = prefs.getInt(BACKGROUND_COLOR, context.resources.getColor(R.color.default_background_color))
get() = prefs.getInt(BACKGROUND_COLOR, ContextCompat.getColor(context, R.color.default_background_color))
set(backgroundColor) = prefs.edit().putInt(BACKGROUND_COLOR, backgroundColor).apply()
var primaryColor: Int
get() = prefs.getInt(PRIMARY_COLOR, context.resources.getColor(R.color.default_primary_color))
get() = prefs.getInt(PRIMARY_COLOR, ContextCompat.getColor(context, R.color.default_primary_color))
set(primaryColor) = prefs.edit().putInt(PRIMARY_COLOR, primaryColor).apply()
var accentColor: Int
get() = prefs.getInt(ACCENT_COLOR, context.resources.getColor(R.color.default_accent_color))
get() = prefs.getInt(ACCENT_COLOR, ContextCompat.getColor(context, R.color.default_accent_color))
set(accentColor) = prefs.edit().putInt(ACCENT_COLOR, accentColor).apply()
var lastHandledShortcutColor: Int
@ -105,14 +106,14 @@ open class BaseConfig(val context: Context) {
set(lastHandledShortcutColor) = prefs.edit().putInt(LAST_HANDLED_SHORTCUT_COLOR, lastHandledShortcutColor).apply()
var appIconColor: Int
get() = prefs.getInt(APP_ICON_COLOR, context.resources.getColor(R.color.default_app_icon_color))
get() = prefs.getInt(APP_ICON_COLOR, ContextCompat.getColor(context, R.color.default_app_icon_color))
set(appIconColor) {
isUsingModifiedAppIcon = appIconColor != context.resources.getColor(R.color.color_primary)
isUsingModifiedAppIcon = appIconColor != ContextCompat.getColor(context, R.color.color_primary)
prefs.edit().putInt(APP_ICON_COLOR, appIconColor).apply()
}
var lastIconColor: Int
get() = prefs.getInt(LAST_ICON_COLOR, context.resources.getColor(R.color.color_primary))
get() = prefs.getInt(LAST_ICON_COLOR, ContextCompat.getColor(context, R.color.color_primary))
set(lastIconColor) = prefs.edit().putInt(LAST_ICON_COLOR, lastIconColor).apply()
var customTextColor: Int
@ -136,11 +137,11 @@ open class BaseConfig(val context: Context) {
set(customAppIconColor) = prefs.edit().putInt(CUSTOM_APP_ICON_COLOR, customAppIconColor).apply()
var widgetBgColor: Int
get() = prefs.getInt(WIDGET_BG_COLOR, context.resources.getColor(R.color.default_widget_bg_color))
get() = prefs.getInt(WIDGET_BG_COLOR, ContextCompat.getColor(context, R.color.default_widget_bg_color))
set(widgetBgColor) = prefs.edit().putInt(WIDGET_BG_COLOR, widgetBgColor).apply()
var widgetTextColor: Int
get() = prefs.getInt(WIDGET_TEXT_COLOR, context.resources.getColor(R.color.default_widget_text_color))
get() = prefs.getInt(WIDGET_TEXT_COLOR, ContextCompat.getColor(context, R.color.default_widget_text_color))
set(widgetTextColor) = prefs.edit().putInt(WIDGET_TEXT_COLOR, widgetTextColor).apply()
// hidden folder visibility protection
@ -493,11 +494,11 @@ open class BaseConfig(val context: Context) {
var colorPickerRecentColors: LinkedList<Int>
get(): LinkedList<Int> {
val defaultList = arrayListOf(
context.resources.getColor(R.color.md_red_700),
context.resources.getColor(R.color.md_blue_700),
context.resources.getColor(R.color.md_green_700),
context.resources.getColor(R.color.md_yellow_700),
context.resources.getColor(R.color.md_orange_700)
ContextCompat.getColor(context, R.color.md_red_700),
ContextCompat.getColor(context, R.color.md_blue_700),
ContextCompat.getColor(context, R.color.md_green_700),
ContextCompat.getColor(context, R.color.md_yellow_700),
ContextCompat.getColor(context, R.color.md_orange_700)
)
return LinkedList(prefs.getString(COLOR_PICKER_RECENT_COLORS, null)?.lines()?.map { it.toInt() } ?: defaultList)
}

View file

@ -3,6 +3,7 @@ package com.simplemobiletools.commons.models
import android.content.Context
import android.net.Uri
import android.provider.MediaStore
import androidx.compose.runtime.Immutable
import com.bumptech.glide.signature.ObjectKey
import com.simplemobiletools.commons.extensions.*
import com.simplemobiletools.commons.helpers.*
@ -35,16 +36,18 @@ open class FileDirItem(
when {
sorting and SORT_BY_NAME != 0 -> {
result = if (sorting and SORT_USE_NUMERIC_VALUE != 0) {
AlphanumericComparator().compare(name.normalizeString().toLowerCase(), other.name.normalizeString().toLowerCase())
AlphanumericComparator().compare(name.normalizeString().lowercase(), other.name.normalizeString().lowercase())
} else {
name.normalizeString().toLowerCase().compareTo(other.name.normalizeString().toLowerCase())
name.normalizeString().lowercase().compareTo(other.name.normalizeString().lowercase())
}
}
sorting and SORT_BY_SIZE != 0 -> result = when {
size == other.size -> 0
size > other.size -> 1
else -> -1
}
sorting and SORT_BY_DATE_MODIFIED != 0 -> {
result = when {
modified == other.modified -> 0
@ -52,8 +55,9 @@ open class FileDirItem(
else -> -1
}
}
else -> {
result = getExtension().toLowerCase().compareTo(other.getExtension().toLowerCase())
result = getExtension().lowercase().compareTo(other.getExtension().lowercase())
}
}
@ -69,7 +73,7 @@ open class FileDirItem(
fun getBubbleText(context: Context, dateFormat: String? = null, timeFormat: String? = null) = when {
sorting and SORT_BY_SIZE != 0 -> size.formatSize()
sorting and SORT_BY_DATE_MODIFIED != 0 -> modified.formatDate(context, dateFormat, timeFormat)
sorting and SORT_BY_EXTENSION != 0 -> getExtension().toLowerCase()
sorting and SORT_BY_EXTENSION != 0 -> getExtension().lowercase()
else -> name
}
@ -84,6 +88,7 @@ open class FileDirItem(
context.getSizeFromContentUri(Uri.parse(path))
}
}
else -> File(path).getProperSize(countHidden)
}
}
@ -101,6 +106,7 @@ open class FileDirItem(
context.isRestrictedSAFOnlyRoot(path) -> context.getAndroidSAFDirectChildrenCount(path, countHiddenItems)
context.isPathOnOTG(path) -> context.getDocumentFile(path)?.listFiles()?.filter { if (countHiddenItems) true else !it.name!!.startsWith(".") }?.size
?: 0
else -> File(path).getDirectChildrenCount(context, countHiddenItems)
}
}
@ -156,3 +162,34 @@ open class FileDirItem(
return Uri.withAppendedPath(uri, mediaStoreId.toString())
}
}
fun FileDirItem.asReadOnly() = FileDirItemReadOnly(
path = path,
name = name,
isDirectory = isDirectory,
children = children,
size = size,
modified = modified,
mediaStoreId = mediaStoreId
)
fun FileDirItemReadOnly.asFileDirItem() = FileDirItem(
path = path,
name = name,
isDirectory = isDirectory,
children = children,
size = size,
modified = modified,
mediaStoreId = mediaStoreId
)
@Immutable
class FileDirItemReadOnly(
path: String,
name: String = "",
isDirectory: Boolean = false,
children: Int = 0,
size: Long = 0L,
modified: Long = 0L,
mediaStoreId: Long = 0L
) : FileDirItem(path, name, isDirectory, children, size, modified, mediaStoreId)

View file

@ -1,9 +1,11 @@
package com.simplemobiletools.commons.models
import android.os.Parcelable
import androidx.compose.runtime.Immutable
import kotlinx.parcelize.Parcelize
@Parcelize
@Immutable
data class SimpleListItem(val id: Int, val textRes: Int, val imageRes: Int? = null, val selected: Boolean = false) : Parcelable {
companion object {

View file

@ -1,6 +1,7 @@
package com.simplemobiletools.commons.samples.activities
import android.os.Bundle
import android.os.Environment
import android.util.Log
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
@ -8,7 +9,6 @@ import androidx.compose.foundation.layout.*
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.Button
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
@ -18,16 +18,14 @@ import androidx.compose.ui.unit.dp
import com.simplemobiletools.commons.R
import com.simplemobiletools.commons.compose.alert_dialog.AlertDialogState
import com.simplemobiletools.commons.compose.alert_dialog.rememberAlertDialogState
import com.simplemobiletools.commons.compose.bottom_sheet.BottomSheetDialogState
import com.simplemobiletools.commons.compose.bottom_sheet.rememberBottomSheetDialogState
import com.simplemobiletools.commons.compose.extensions.config
import com.simplemobiletools.commons.compose.extensions.rateStarsRedirectAndThankYou
import com.simplemobiletools.commons.compose.theme.AppThemeSurface
import com.simplemobiletools.commons.dialogs.*
import com.simplemobiletools.commons.extensions.baseConfig
import com.simplemobiletools.commons.extensions.launchUpgradeToProIntent
import com.simplemobiletools.commons.extensions.launchViewIntent
import com.simplemobiletools.commons.extensions.toHex
import com.simplemobiletools.commons.models.RadioItem
import com.simplemobiletools.commons.models.Release
import com.simplemobiletools.commons.extensions.*
import com.simplemobiletools.commons.models.*
import kotlinx.collections.immutable.toImmutableList
class TestDialogActivity : ComponentActivity() {
@ -36,7 +34,6 @@ class TestDialogActivity : ComponentActivity() {
super.onCreate(savedInstanceState)
setContent {
AppThemeSurface {
MaterialTheme
Column(
Modifier
.fillMaxSize()
@ -45,7 +42,7 @@ class TestDialogActivity : ComponentActivity() {
verticalArrangement = Arrangement.spacedBy(16.dp)
) {
Spacer(modifier = Modifier.padding(top = 16.dp))
ShowButton(getAppSideLoadedDialogState(), text = "App side loaded dialog")
ShowButton(getAppSideLoadedDialogState(), text = "App side loaded")
ShowButton(getAddBlockedNumberDialogState(), text = "Add blocked number")
ShowButton(getConfirmationAlertDialogState(), text = "Confirmation normal")
ShowButton(getConfirmationAdvancedAlertDialogState(), text = "Confirmation advanced")
@ -63,22 +60,97 @@ class TestDialogActivity : ComponentActivity() {
ShowButton(getUpgradeToProAlertDialogState(), text = "Upgrade to pro")
ShowButton(getWhatsNewAlertDialogState(), text = "What's new")
ShowButton(getChangeViewTypeAlertDialogState(), text = "Change view type")
ShowButton(getWritePermissionAlertDialogState(), text = "Write permission dialog")
ShowButton(getWritePermissionAlertDialogState(), text = "Write permission")
ShowButton(getCreateNewFolderAlertDialogState(), text = "Create new folder")
ShowButton(getEnterPasswordAlertDialogState(), text = "Enter password")
ShowButton(getFolderLockingNoticeAlertDialogState(), text = "Folder locking notice")
ShowButton(getChooserBottomSheetDialogState(), text = "Bottom sheet chooser")
ShowButton(getFileConflictAlertDialogState(), text = "File conflict")
ShowButton(getCustomIntervalPickerAlertDialogState(), text = "Custom interval picker")
Spacer(modifier = Modifier.padding(bottom = 16.dp))
}
}
}
}
@Composable
private fun getCustomIntervalPickerAlertDialogState() = rememberAlertDialogState().apply {
DialogMember {
CustomIntervalPickerAlertDialog(alertDialogState = this, selectedSeconds = 3, showSeconds = true) {
Log.d("CustomIntervalPickerAlertDialog", it.toString())
}
}
}
@Composable
private fun getFileConflictAlertDialogState() = rememberAlertDialogState().apply {
DialogMember {
FileConflictAlertDialog(
alertDialogState = this, fileDirItem = FileDirItem(
path = filesDir.path,
name = "Test", children = 2
).asReadOnly(), showApplyToAll = false
) { resolution, applyForAll ->
baseConfig.apply {
lastConflictApplyToAll = applyForAll
lastConflictResolution = resolution
}
}
}
}
@Composable
private fun getChooserBottomSheetDialogState() = rememberBottomSheetDialogState().apply {
BottomSheetContent {
val list = remember {
listOf(
SimpleListItem(1, R.string.record_video, R.drawable.ic_camera_vector),
SimpleListItem(2, R.string.record_audio, R.drawable.ic_microphone_vector, selected = true),
SimpleListItem(4, R.string.choose_contact, R.drawable.ic_add_person_vector)
).toImmutableList()
}
ChooserBottomSheetDialog(
bottomSheetDialogState = this@apply,
items = list
) {
toast("Selected ${getString(it.textRes)}")
}
}
}
@Composable
private fun getFolderLockingNoticeAlertDialogState() = rememberAlertDialogState().apply {
DialogMember {
FolderLockingNoticeAlertDialog(alertDialogState = this) {
}
}
}
@Composable
private fun getEnterPasswordAlertDialogState() = rememberAlertDialogState().apply {
DialogMember {
EnterPasswordAlertDialog(alertDialogState = this, callback = {}, cancelCallback = {})
}
}
@Composable
private fun getCreateNewFolderAlertDialogState() = rememberAlertDialogState().apply {
DialogMember {
CreateNewFolderAlertDialog(this, path = Environment.getExternalStorageDirectory().toString()) {
//todo create helper for private fun createFolder(path: String, alertDialog: AlertDialog) to extract bundled logic
}
}
}
@Composable
private fun getWritePermissionAlertDialogState() = rememberAlertDialogState().apply {
DialogMember {
WritePermissionAlertDialog(
alertDialogState = this,
writePermissionDialogMode = WritePermissionDialog.WritePermissionDialogMode.OpenDocumentTreeSDK30("."),
callback = {},
onCancelCallback = {}
)
callback = {}
) {}
}
}
@ -131,16 +203,15 @@ class TestDialogActivity : ComponentActivity() {
RadioItem(6, "Test 6"),
RadioItem(6, "Test 7"),
).toImmutableList(),
showOKButton = true,
selectedItemId = 2,
titleId = R.string.title,
showOKButton = true,
cancelCallback = {
Log.d("getRadioGroupDialogAlertDialogState", "cancelCallback")
},
callback = {
}
) {
Log.d("getRadioGroupDialogAlertDialogState", "Selected $it")
},
titleId = R.string.title
)
}
}
}
@ -169,11 +240,11 @@ class TestDialogActivity : ComponentActivity() {
alertDialogState = this,
color = baseConfig.customPrimaryColor,
isPrimaryColorPicker = true,
onButtonPressed = { wasPositivePressed, color ->
Log.d("getLineColorPickerAlertDialogState", "wasPositivePressed=$wasPositivePressed color=${color.toHex()}")
}, onActiveColorChange = { color ->
onActiveColorChange = { color ->
Log.d("getLineColorPickerAlertDialogState", "onActiveColorChange=${color.toHex()}")
})
}) { wasPositivePressed, color ->
Log.d("getLineColorPickerAlertDialogState", "wasPositivePressed=$wasPositivePressed color=${color.toHex()}")
}
}
}
@ -194,11 +265,11 @@ class TestDialogActivity : ComponentActivity() {
alertDialogState = this,
color = config.customTextColor,
removeDimmedBackground = true,
onButtonPressed = { wasPositivePressed, color ->
Log.d("getColorPickerAlertDialogState", "wasPositivePressed=$wasPositivePressed color=${color.toHex()}")
}, onActiveColorChange = { color ->
onActiveColorChange = { color ->
Log.d("getColorPickerAlertDialogState", "onActiveColorChange=${color.toHex()}")
})
}) { wasPositivePressed, color ->
Log.d("getColorPickerAlertDialogState", "wasPositivePressed=$wasPositivePressed color=${color.toHex()}")
}
}
}
@ -212,7 +283,7 @@ class TestDialogActivity : ComponentActivity() {
@Composable
private fun getCallConfirmationAlertDialogState() = rememberAlertDialogState().apply {
DialogMember {
CallConfirmationAlertDialog(alertDialogState = this, callee = "Simple Mobile Tools", callback = {})
CallConfirmationAlertDialog(alertDialogState = this, callee = "Simple Mobile Tools") {}
}
}
@ -235,7 +306,7 @@ class TestDialogActivity : ComponentActivity() {
@Composable
private fun getConfirmationAlertDialogState() = rememberAlertDialogState().apply {
DialogMember {
ConfirmationAlertDialog(alertDialogState = this, callback = {}, dialogTitle = "Some fancy title")
ConfirmationAlertDialog(alertDialogState = this, dialogTitle = "Some fancy title") {}
}
}
@ -243,7 +314,7 @@ class TestDialogActivity : ComponentActivity() {
private fun getAppSideLoadedDialogState() =
rememberAlertDialogState().apply {
DialogMember {
AppSideLoadedAlertDialog(onDownloadClick = {}, onCancelClick = {}, alertDialogState = this)
AppSideLoadedAlertDialog(alertDialogState = this, onDownloadClick = {}) {}
}
}
@ -251,7 +322,7 @@ class TestDialogActivity : ComponentActivity() {
private fun getAddBlockedNumberDialogState() =
rememberAlertDialogState().apply {
DialogMember {
AddOrEditBlockedNumberAlertDialog(blockedNumber = null, deleteBlockedNumber = {}, addBlockedNumber = {}, alertDialogState = this)
AddOrEditBlockedNumberAlertDialog(alertDialogState = this, blockedNumber = null, deleteBlockedNumber = {}) {}
}
}
@ -259,7 +330,7 @@ class TestDialogActivity : ComponentActivity() {
private fun getConfirmationAdvancedAlertDialogState() =
rememberAlertDialogState().apply {
DialogMember {
ConfirmationAdvancedAlertDialog(alertDialogState = this, callback = {})
ConfirmationAdvancedAlertDialog(alertDialogState = this) {}
}
}
@ -269,15 +340,14 @@ class TestDialogActivity : ComponentActivity() {
DialogMember {
PermissionRequiredAlertDialog(
alertDialogState = this,
text = "Test permission",
positiveActionCallback = {}
)
text = "Test permission"
) {}
}
}
@Composable
private fun ShowButton(appSideLoadedDialogState: AlertDialogState, text: String) {
Button(onClick = appSideLoadedDialogState::show) {
private fun ShowButton(alertDialogState: AlertDialogState, text: String) {
Button(onClick = alertDialogState::show) {
Text(
text = text,
modifier = Modifier
@ -286,4 +356,18 @@ class TestDialogActivity : ComponentActivity() {
)
}
}
@Composable
private fun ShowButton(appSideLoadedDialogState: BottomSheetDialogState, text: String) {
Button(onClick = appSideLoadedDialogState::open) {
Text(
text = text,
modifier = Modifier
.fillMaxWidth(),
textAlign = TextAlign.Center
)
}
}
}