Skip to content

Commit

Permalink
Remove composeMaterialDialogsCore 3rd party, add native dialog compos…
Browse files Browse the repository at this point in the history
…e 1.5.0
  • Loading branch information
mbakgun committed Aug 30, 2023
1 parent 0ba3f6d commit fad4e3c
Show file tree
Hide file tree
Showing 8 changed files with 79 additions and 69 deletions.
1 change: 0 additions & 1 deletion README-de.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ Die Anwendung wurde im MVVM-Konzept mit Kotlin und Jetpack Compose entwickelt. E
- [Kotlinx Coroutines](https://kotlinlang.org/docs/coroutines-overview.html)
- [Compose ImageLoader](https://github.com/qdsfdhvh/compose-imageloader)
- [KMM-ViewModel](https://github.com/rickclephas/KMM-ViewModel)
- [Compose Material Dialogs](https://github.com/vanpra/compose-material-dialogs)
- [Multiplatform Settings](https://github.com/russhwolf/multiplatform-settings)

<div style="text-align: center;"><img src="image-assets/venn.png" alt="decisions"></div>
Expand Down
1 change: 0 additions & 1 deletion README-tr.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ Kotlin ve Jetpack Compose kullanılarak MVVM konseptinde geliştirtirildi. Netwo
- [Kotlinx Coroutines](https://kotlinlang.org/docs/coroutines-overview.html)
- [Compose ImageLoader](https://github.com/qdsfdhvh/compose-imageloader)
- [KMM-ViewModel](https://github.com/rickclephas/KMM-ViewModel)
- [Compose Material Dialogs](https://github.com/vanpra/compose-material-dialogs)
- [Multiplatform Settings](https://github.com/russhwolf/multiplatform-settings)

<div style="text-align: center;"><img src="image-assets/venn.png" alt="decisions"></div>
Expand Down
1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ Application developed in the MVVM concept using Kotlin and Jetpack Compose. Netw
- [Kotlinx Coroutines](https://kotlinlang.org/docs/coroutines-overview.html)
- [Compose ImageLoader](https://github.com/qdsfdhvh/compose-imageloader)
- [KMM-ViewModel](https://github.com/rickclephas/KMM-ViewModel)
- [Compose Material Dialogs](https://github.com/vanpra/compose-material-dialogs)
- [Multiplatform Settings](https://github.com/russhwolf/multiplatform-settings)

<div style="text-align: center;"><img src="image-assets/venn.png" alt="decisions"></div>
Expand Down
1 change: 0 additions & 1 deletion gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ ktorSerializationKotlinxJson = { module = "io.ktor:ktor-serialization-kotlinx-js
kotlinxCoroutinesCore = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref="kotlinxCoroutines" }
kotlinxCoroutinesTest = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-test", version.ref="kotlinxCoroutines" }
kotlinxSerializationCore = { module = "org.jetbrains.kotlinx:kotlinx-serialization-core", version="1.6.0" }
composeMaterialDialogsCore = { module = "ca.gosyer:compose-material-dialogs-core", version="0.9.3" }
multiplatformSettings = { module = "com.russhwolf:multiplatform-settings-no-arg", version="1.0.0" }


Expand Down
3 changes: 0 additions & 3 deletions shared/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,6 @@ kotlin {
//imageloading
implementation(libs.imageLoader)

// KMP Dialogs
implementation(libs.composeMaterialDialogsCore)

//coroutines
implementation(libs.kotlinxCoroutinesCore)

Expand Down
10 changes: 4 additions & 6 deletions shared/detekt-baseline.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@
<ID>FunctionNaming:MjImagesApp.kt$@Composable fun DraggableThemeSelection( useDarkTheme: Boolean, onClick: (Boolean) -&gt; Unit )</ID>
<ID>FunctionNaming:MjImagesApp.kt$@Composable fun EmptyScreen( onRefresh: () -&gt; Unit )</ID>
<ID>FunctionNaming:MjImagesApp.kt$@Composable fun ErrorScreen( onRefresh: () -&gt; Unit )</ID>
<ID>FunctionNaming:MjImagesApp.kt$@Composable fun MjImageItem( image: MjImage, height: Dp, contentScale: ContentScale, onPreviewVisibilityChanged: @Composable (isVisible: Boolean, imageUrl: String) -&gt; Unit, )</ID>
<ID>FunctionNaming:MjImagesApp.kt$@Composable fun MjImagesList( images: MjImages, state: LazyStaggeredGridState, onLoadMore: () -&gt; Unit, onPreviewVisibilityChanged: @Composable (isVisible: Boolean, imageUrl: String) -&gt; Unit, )</ID>
<ID>FunctionNaming:MjImagesApp.kt$@Composable fun PreviewDialog( isPreviewVisible: Boolean, imageUrl: String, dialogState: MaterialDialogState = rememberMaterialDialogState() )</ID>
<ID>FunctionNaming:MjImagesApp.kt$@Composable fun MjImagesList( images: MjImages, state: LazyStaggeredGridState, onLoadMore: () -&gt; Unit, showPreviewDialog: (imageUrl: String) -&gt; Unit, )</ID>
<ID>FunctionNaming:MjImagesApp.kt$@Composable fun PlatformSpecificMjImagesGrid( state: LazyStaggeredGridState, images: MjImages, showPreviewDialog: (imageUrl: String) -&gt; Unit, onLoadMore: () -&gt; Unit, modifier: Modifier = Modifier, )</ID>
<ID>FunctionNaming:MjImagesApp.kt$@Composable fun PreviewDialog( imageUrl: String, onDismissed: () -&gt; Unit, )</ID>
<ID>FunctionNaming:MjImagesApp.kt$@Composable fun PreviewImage(imageUrl: String)</ID>
<ID>FunctionNaming:MjImagesApp.kt$@Composable fun ScrollToTopButton( onClick: () -&gt; Unit, modifier: Modifier = Modifier )</ID>
<ID>FunctionNaming:MjImagesApp.kt$@OptIn(ExperimentalFoundationApi::class) @Composable fun PlatformSpecificMjImagesGrid( state: LazyStaggeredGridState, images: MjImages, onPreviewVisibilityChanged: @Composable (isVisible: Boolean, imageUrl: String) -&gt; Unit, onLoadMore: () -&gt; Unit, modifier: Modifier = Modifier, )</ID>
<ID>FunctionNaming:MjImagesApp.kt$@OptIn(ExperimentalFoundationApi::class) @Composable fun MjImageItem( image: MjImage, height: Dp, contentScale: ContentScale, showPreviewDialog: (imageUrl: String) -&gt; Unit, )</ID>
<ID>FunctionNaming:MjImagesApp.kt$@OptIn(ExperimentalMaterialApi::class) @Composable fun MjImagesApp( viewModel: MjImagesViewModel )</ID>
<ID>FunctionNaming:Theme.kt$@Composable fun AppTheme( useDarkTheme: Boolean = isSystemInDarkTheme(), content: @Composable () -&gt; Unit )</ID>
<ID>FunctionNaming:main.ios.kt$fun MainViewController(viewModel: MjImagesViewModel): UIViewController</ID>
Expand All @@ -35,8 +35,6 @@
<ID>MagicNumber:ImageLoader.kt$1024</ID>
<ID>MagicNumber:MjImagesApp.kt$.2f</ID>
<ID>MagicNumber:MjImagesApp.kt$.8f</ID>
<ID>MagicNumber:MjImagesApp.kt$180</ID>
<ID>MagicNumber:MjImagesApp.kt$200</ID>
<ID>MagicNumber:MjImagesApp.kt$230f</ID>
<ID>MagicNumber:MjImagesApp.kt$24f</ID>
<ID>UnusedPrivateProperty:build.gradle.kts$val androidInstrumentedTest by getting { dependencies { implementation(libs.androidxUiTestJunit4) implementation(libs.androidxUiTestManifest) } }</ID>
Expand Down
109 changes: 56 additions & 53 deletions shared/src/commonMain/kotlin/ui/MjImagesApp.kt
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ import androidx.compose.animation.fadeOut
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.Image
import androidx.compose.foundation.clickable
import androidx.compose.foundation.combinedClickable
import androidx.compose.foundation.gestures.detectDragGestures
import androidx.compose.foundation.gestures.detectTapGestures
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
Expand Down Expand Up @@ -38,6 +38,7 @@ import androidx.compose.material.ScaffoldState
import androidx.compose.material.Surface
import androidx.compose.material.Text
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Close
import androidx.compose.material.icons.filled.KeyboardArrowUp
import androidx.compose.material.icons.rounded.DarkMode
import androidx.compose.material.icons.rounded.LightMode
Expand All @@ -61,7 +62,6 @@ import androidx.compose.ui.draw.clip
import androidx.compose.ui.draw.rotate
import androidx.compose.ui.draw.shadow
import androidx.compose.ui.graphics.BlurEffect
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.layout.ContentScale
Expand All @@ -70,19 +70,16 @@ import androidx.compose.ui.platform.testTag
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.Popup
import androidx.compose.ui.window.PopupProperties
import com.seiko.imageloader.LocalImageLoader
import com.seiko.imageloader.model.ImageResult
import com.seiko.imageloader.rememberImageAction
import com.seiko.imageloader.rememberImageActionPainter
import com.vanpra.composematerialdialogs.MaterialDialog
import com.vanpra.composematerialdialogs.MaterialDialogProperties
import com.vanpra.composematerialdialogs.MaterialDialogState
import com.vanpra.composematerialdialogs.rememberMaterialDialogState
import domain.model.MjImage
import domain.model.MjImages
import domain.model.State
import kotlin.math.roundToInt
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import ui.theme.AppTheme
import util.OnBottomReached
Expand All @@ -101,6 +98,7 @@ fun MjImagesApp(

val images: MjImages by viewModel.images.collectAsState()
val state: State by viewModel.state.collectAsState()
val previewUrl by viewModel.dialogPreviewUrl.collectAsState()
val onRefresh = viewModel::refreshImages

val scaffoldState: ScaffoldState = rememberScaffoldState()
Expand Down Expand Up @@ -136,8 +134,8 @@ fun MjImagesApp(
onLoadMore = viewModel::loadMore,
images = images,
state = listState,
) { isPreviewVisible, imageUrl ->
PreviewDialog(isPreviewVisible, imageUrl)
) { imageUrl ->
viewModel.showPreviewDialog(imageUrl)
}
}
PullRefreshIndicator(
Expand All @@ -163,6 +161,13 @@ fun MjImagesApp(
useDarkTheme,
viewModel::setDarkMode
)

if (previewUrl.isNotEmpty()) {
PreviewDialog(
imageUrl = previewUrl,
onDismissed = viewModel::dismissPreviewDialog
)
}
}
}
}
Expand All @@ -174,23 +179,22 @@ fun MjImagesList(
images: MjImages,
state: LazyStaggeredGridState,
onLoadMore: () -> Unit,
onPreviewVisibilityChanged: @Composable (isVisible: Boolean, imageUrl: String) -> Unit,
showPreviewDialog: (imageUrl: String) -> Unit,
) {
PlatformSpecificMjImagesGrid(
onLoadMore = onLoadMore,
images = images,
modifier = Modifier.fillMaxSize().testTag("imagesGrid"),
onPreviewVisibilityChanged = onPreviewVisibilityChanged,
showPreviewDialog = showPreviewDialog,
state = state,
)
}

@OptIn(ExperimentalFoundationApi::class)
@Composable
fun PlatformSpecificMjImagesGrid(
state: LazyStaggeredGridState,
images: MjImages,
onPreviewVisibilityChanged: @Composable (isVisible: Boolean, imageUrl: String) -> Unit,
showPreviewDialog: (imageUrl: String) -> Unit,
onLoadMore: () -> Unit,
modifier: Modifier = Modifier,
) {
Expand All @@ -204,49 +208,34 @@ fun PlatformSpecificMjImagesGrid(
key = MjImage::imageUrl
) { image ->
MjImageItem(
image,
(180 * image.ratio).dp,
ContentScale.Crop,
onPreviewVisibilityChanged,
image = image,
height = (180 * image.ratio).dp,
contentScale = ContentScale.Crop,
showPreviewDialog = showPreviewDialog,
)
}
}
}


@OptIn(ExperimentalFoundationApi::class)
@Composable
fun MjImageItem(
image: MjImage,
height: Dp,
contentScale: ContentScale,
onPreviewVisibilityChanged: @Composable (isVisible: Boolean, imageUrl: String) -> Unit,
showPreviewDialog: (imageUrl: String) -> Unit,
) {
val uriHandler = LocalUriHandler.current
var isLongPressed by remember { mutableStateOf(false) }

if (isLongPressed) {
onPreviewVisibilityChanged.invoke(true, image.imageUrl)
} else {
onPreviewVisibilityChanged.invoke(false, image.imageUrl)
}

Surface(
modifier = Modifier
.padding(4.dp)
.fillMaxWidth()
.pointerInput(Unit) {
detectTapGestures(
onTap = {
if (!isLongPressed)
uriHandler.openUri(image.imageUrl)
},
onPress = {
delay(200)
isLongPressed = true
tryAwaitRelease()
isLongPressed = false
})
},
.combinedClickable(
onClick = { uriHandler.openUri(image.imageUrl) },
onLongClick = { showPreviewDialog.invoke(image.imageUrl) },
),
elevation = 8.dp,
shape = RoundedCornerShape(8.dp)
) {
Expand Down Expand Up @@ -332,23 +321,36 @@ fun ErrorScreen(

@Composable
fun PreviewDialog(
isPreviewVisible: Boolean,
imageUrl: String,
dialogState: MaterialDialogState = rememberMaterialDialogState()
onDismissed: () -> Unit,
) {
if (isPreviewVisible) {
MaterialDialog(
dialogState = dialogState,
backgroundColor = Color.Transparent,
elevation = 0.dp,
properties = MaterialDialogProperties(
resizable = false
)
) { PreviewImage(imageUrl) }
LaunchedEffect(imageUrl) {
dialogState.show()
Popup(
onDismissRequest = {
onDismissed()
},
properties = PopupProperties(
focusable = true
),
content = {
Box(contentAlignment = Alignment.TopEnd) {
PreviewImage(imageUrl)
Button(
onClick = { onDismissed() },
modifier = Modifier
.padding(24.dp)
.shadow(10.dp, shape = CircleShape)
.clip(shape = CircleShape)
.size(50.dp),
colors = ButtonDefaults.buttonColors(
backgroundColor = MaterialTheme.colors.background,
contentColor = MaterialTheme.colors.onSurface,
)
) {
Icon(Icons.Filled.Close, "close")
}
}
}
}
)
}

@Composable
Expand All @@ -365,6 +367,7 @@ fun PreviewImage(imageUrl: String) {
Image(
painter = painter,
contentDescription = null,
contentScale = ContentScale.Crop,
modifier = Modifier.graphicsLayer {
val animatedValue: Float = .8f + (.2f * transition)
val blurValue: Float =
Expand All @@ -373,7 +376,7 @@ fun PreviewImage(imageUrl: String) {
scaleY = animatedValue
alpha = animatedValue
renderEffect = BlurEffect(blurValue, blurValue)
}.padding(24.dp).fillMaxSize()
}.fillMaxSize()
)
}

Expand Down
22 changes: 19 additions & 3 deletions shared/src/commonMain/kotlin/ui/MjImagesViewModel.kt
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import domain.usecase.MjImagesFetchUseCase
import domain.usecase.MjImagesUseCase
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
Expand All @@ -20,13 +21,16 @@ class MjImagesViewModel(
) : KMMViewModel() {

private val _state = MutableStateFlow(State.LOADING)
val state: StateFlow<State> = _state
val state: StateFlow<State> = _state.asStateFlow()

private val _images = MutableStateFlow(MjImages())
val images: StateFlow<MjImages> = _images
val images: StateFlow<MjImages> = _images.asStateFlow()

private val _useDarkTheme: MutableStateFlow<Boolean> = MutableStateFlow(false)
val useDarkTheme: StateFlow<Boolean> = _useDarkTheme
val useDarkTheme: StateFlow<Boolean> = _useDarkTheme.asStateFlow()

private val _dialogPreviewUrl: MutableStateFlow<String> = MutableStateFlow("")
val dialogPreviewUrl: StateFlow<String> = _dialogPreviewUrl.asStateFlow()

init {
checkTheme()
Expand Down Expand Up @@ -84,4 +88,16 @@ class MjImagesViewModel(
_useDarkTheme.emit(useCase.isDarkModeEnabled())
}
}

fun showPreviewDialog(imageUrl: String) {
viewModelScope.coroutineScope.launch {
_dialogPreviewUrl.emit(imageUrl)
}
}

fun dismissPreviewDialog() {
viewModelScope.coroutineScope.launch {
_dialogPreviewUrl.emit("")
}
}
}

0 comments on commit fad4e3c

Please sign in to comment.