Skip to content

Commit

Permalink
- Changes in updates dialog
Browse files Browse the repository at this point in the history
- Add url to edit/add screen
  • Loading branch information
DesarrolloAntonio committed Apr 12, 2024
1 parent 68e2f4e commit fd02473
Show file tree
Hide file tree
Showing 7 changed files with 225 additions and 34 deletions.
Expand Up @@ -82,6 +82,7 @@ fun BookmarkEditorScreen(
createArchive = createArchive,
makeArchivePublic = makeArchivePublic,
createEbook = createEbook,
url = bookmark.url
)

if (bookmarkUiState.data != null) {
Expand Down
Expand Up @@ -39,6 +39,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
Expand All @@ -50,6 +51,7 @@ enum class BookmarkEditorType { ADD, EDIT }
@Composable
fun BookmarkEditorView(
title: String,
url: String,
bookmarkEditorType: BookmarkEditorType,
newTag: MutableState<String>,
assignedTags: MutableState<List<Tag>>,
Expand Down Expand Up @@ -87,6 +89,16 @@ fun BookmarkEditorView(
Icon(Icons.Outlined.Save, contentDescription = "Save")
}
}
Text(
text = url,
color = MaterialTheme.colorScheme.onSurface,
modifier = Modifier
.fillMaxWidth()
.background(MaterialTheme.colorScheme.surfaceVariant)
.padding(8.dp),
maxLines = 3,
overflow = TextOverflow.Ellipsis //
)

if (bookmarkEditorType == BookmarkEditorType.ADD) {
Row(verticalAlignment = CenterVertically) {
Expand Down Expand Up @@ -227,6 +239,7 @@ fun BookmarkEditorPreview() {

BookmarkEditorView(
title = "Add",
url = "http://www.google.com",
bookmarkEditorType = BookmarkEditorType.ADD,
assignedTags = remember { mutableStateOf(generateRandomTags(100)) },
saveBookmark = {},
Expand Down
@@ -1,5 +1,8 @@
package com.desarrollodroide.pagekeeper.ui.components

import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
Expand All @@ -8,6 +11,7 @@ import androidx.compose.material.icons.filled.Error
import androidx.compose.material3.*
import androidx.compose.material3.AlertDialog
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
Expand Down Expand Up @@ -180,6 +184,7 @@ fun ErrorDialog(

@Composable
fun UpdateCacheDialog(
isLoading: Boolean,
showDialog: MutableState<Boolean>,
onConfirm: (keepOldTitle: Boolean, updateArchive: Boolean, updateEbook: Boolean) -> Unit,
) {
Expand All @@ -188,13 +193,22 @@ fun UpdateCacheDialog(
var updateArchiveChecked by remember { mutableStateOf(false) }
var updateEbookChecked by remember { mutableStateOf(false) }

val wasLoading = remember { mutableStateOf(isLoading) }
LaunchedEffect(isLoading) {
if (wasLoading.value && !isLoading) {
showDialog.value = false
}
wasLoading.value = isLoading
}

AlertDialog(
onDismissRequest = { },
title = { Text("Update cache for selected bookmark? This action is irreversible.") },
text = {
Column {
Row(verticalAlignment = Alignment.CenterVertically) {
Checkbox(
enabled = !isLoading,
checked = keepOldTitleChecked,
onCheckedChange = { keepOldTitleChecked = it })
Text(
Expand All @@ -204,31 +218,40 @@ fun UpdateCacheDialog(
}
Row(verticalAlignment = Alignment.CenterVertically) {
Checkbox(
enabled = !isLoading,
checked = updateArchiveChecked,
onCheckedChange = { updateArchiveChecked = it })
Text("Update archive as well", modifier = Modifier.padding(start = 8.dp))
}
Row(verticalAlignment = Alignment.CenterVertically) {
Checkbox(
enabled = !isLoading,
checked = updateEbookChecked,
onCheckedChange = { updateEbookChecked = it })
Text("Update Ebook as well", modifier = Modifier.padding(start = 8.dp))
}
}
},
confirmButton = {
Button(onClick = {
showDialog.value = false
onConfirm(keepOldTitleChecked, updateArchiveChecked, updateEbookChecked)
}) {
Text("Update")
}
LoadingButton(
text = "Update",
onClick = {
onConfirm(keepOldTitleChecked, updateArchiveChecked, updateEbookChecked)
},
loading = isLoading)
},

dismissButton = {
Button(onClick = {
showDialog.value = false
}) {
Text("Cancel")
AnimatedVisibility (
enter = fadeIn(),
exit = fadeOut(),
visible = !isLoading
){
Button(onClick = {
showDialog.value = false
}) {
Text("Cancel")
}
}
},
properties = DialogProperties(dismissOnBackPress = true, dismissOnClickOutside = true)
Expand Down
@@ -0,0 +1,152 @@
package com.desarrollodroide.pagekeeper.ui.components

import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.ExperimentalAnimationApi
import androidx.compose.animation.core.Spring
import androidx.compose.animation.core.Transition
import androidx.compose.animation.core.VisibilityThreshold
import androidx.compose.animation.core.animateDp
import androidx.compose.animation.core.spring
import androidx.compose.animation.core.updateTransition
import androidx.compose.animation.expandHorizontally
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.animation.shrinkHorizontally
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.defaultMinSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.material3.Button
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.LocalContentColor
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.StrokeCap
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.IntSize
import androidx.compose.ui.unit.dp

@Composable
fun LoadingButton(
text: String,
onClick: () -> Unit,
loading: Boolean,
) {
val transition = updateTransition(
targetState = loading,
label = "master transition",
)
val horizontalContentPadding by transition.animateDp(
transitionSpec = {
spring(
stiffness = SpringStiffness,
)
},
targetValueByState = { toLoading -> if (toLoading) 12.dp else 24.dp },
label = "button's content padding",
)
Button(
onClick = onClick,
modifier = Modifier.defaultMinSize(minWidth = 1.dp),
contentPadding = PaddingValues(
horizontal = horizontalContentPadding,
vertical = 8.dp,
),
) {
Box(contentAlignment = Alignment.Center) {
LoadingContent(
loadingStateTransition = transition,
)
PrimaryContent(
text = text,
loadingStateTransition = transition,
)
}
}
}

@OptIn(ExperimentalAnimationApi::class)
@Composable
private fun LoadingContent(
loadingStateTransition: Transition<Boolean>,
) {
loadingStateTransition.AnimatedVisibility(
visible = { loading -> loading },
enter = fadeIn(),
exit = fadeOut(
animationSpec = spring(
stiffness = SpringStiffness,
visibilityThreshold = 0.10f,
),
),
) {
CircularProgressIndicator(
modifier = Modifier.size(18.dp),
color = LocalContentColor.current,
strokeWidth = 1.5f.dp,
strokeCap = StrokeCap.Round,
)
}
}

@OptIn(ExperimentalAnimationApi::class)
@Composable
private fun PrimaryContent(
loadingStateTransition: Transition<Boolean>,
text: String,
) {
loadingStateTransition.AnimatedVisibility(
visible = { loading -> !loading },
enter = fadeIn() + expandHorizontally(
animationSpec = spring(
stiffness = SpringStiffness,
dampingRatio = Spring.DampingRatioMediumBouncy,
visibilityThreshold = IntSize.VisibilityThreshold,
),
expandFrom = Alignment.CenterHorizontally,
),
exit = fadeOut(
animationSpec = spring(
stiffness = SpringStiffness,
visibilityThreshold = 0.10f,
),
) + shrinkHorizontally(
animationSpec = spring(
stiffness = SpringStiffness,
// dampingRatio is not applicable here, size cannot become negative
visibilityThreshold = IntSize.VisibilityThreshold,
),
shrinkTowards = Alignment.CenterHorizontally,
),
) {
Text(
text = text,
modifier = Modifier
// so that bouncing button's width doesn't cut first and last letters
.padding(horizontal = 4.dp),
)
}
}

// use same spring stiffness so that all animations finish at about the same time
private val SpringStiffness = Spring.StiffnessMediumLow

@Preview
@Composable
private fun LoadingButtonPreview() {
Box(
modifier = Modifier.fillMaxWidth(),
contentAlignment = Alignment.Center,
) {
LoadingButton(
text = "Login",
onClick = {},
loading = false,
)
}
}
Expand Up @@ -4,32 +4,33 @@ import kotlinx.coroutines.flow.MutableStateFlow

data class UiState<T>(
val isLoading: Boolean = false,
val isUpdating: Boolean = false,
val error: String? = null,
val data: T? = null,
val idle: Boolean = true
)

fun <T> UiState<T>.success(data: T) = copy(isLoading = false, data = data, error = null, idle = false)
fun <T> UiState<T>.success(data: T) = copy(isLoading = false, data = data, error = null, idle = false, isUpdating = false)

fun <T> UiState<T>.error(error: String) = copy(isLoading = false, data = null, error = error, idle = false)
fun <T> UiState<T>.error(error: String) = copy(isLoading = false, data = null, error = error, idle = false, isUpdating = false)


fun <T> MutableStateFlow<UiState<T>>.success(data: T?) {
value = value.copy(isLoading = false, data = data, error = null, idle = false)
value = value.copy(isLoading = false, data = data, error = null, idle = false, isUpdating = false)
}

fun <T> MutableStateFlow<UiState<T>>.error(errorMessage: String) {
value = value.copy(isLoading = false, data = null, error = errorMessage, idle = false)
value = value.copy(isLoading = false, data = null, error = errorMessage, idle = false, isUpdating = false)
}

fun <T> MutableStateFlow<UiState<T>>.isLoading(isLoading: Boolean) {
value = value.copy(isLoading = isLoading, data = null, error = null, idle = false)
value = value.copy(isLoading = isLoading, data = null, error = null, idle = false, isUpdating = false)
}

fun <T> MutableStateFlow<UiState<T>>.idle(isIdle: Boolean) {
value = value.copy(isLoading = false, data = null, error = null, idle = isIdle)
value = value.copy(isLoading = false, data = null, error = null, idle = isIdle, isUpdating = false)
}

fun <T> MutableStateFlow<UiState<T>>.update(transform: (UiState<T>) -> UiState<T>) {
value = transform(value)
fun <T> MutableStateFlow<UiState<T>>.isUpdating(isUpdating: Boolean) {
value = value.copy(isLoading = false, data = value.data, error = null, idle = false, isUpdating = isUpdating)
}

0 comments on commit fd02473

Please sign in to comment.