Skip to content

Commit

Permalink
feat: Added OrderScreen implementation
Browse files Browse the repository at this point in the history
Refactors `OrderFacade` to provide headers and set URL.
Updates `RequestView` to use mutable properties.
Introduces `OrderScreen`, `OrderScreenScaffold`, `WebView`, and `OrderViewModel` for handling web view and orders.
Modifies `PurchaseViewModel` and `Navigation` to integrate with the new components.
Removes redundant imports and adjusts code formatting.
  • Loading branch information
diareuse committed Jan 13, 2025
1 parent e6bfe3b commit cc93ae8
Show file tree
Hide file tree
Showing 9 changed files with 386 additions and 22 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@ import kotlinx.coroutines.flow.Flow

interface OrderFacade {

val url: String
val isCompleted: Flow<Boolean>

suspend fun getRequest(): Result<RequestView>
suspend fun getHeaders(): Map<String, String>
fun setUrl(url: String)

fun interface Factory {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,27 +1,20 @@
package movie.metropolis.app.presentation.order

import kotlinx.collections.immutable.toImmutableMap
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.map
import movie.cinema.city.CinemaCity

class OrderFacadeFromFeature(
private val url: String,
override val url: String,
private val cinemaCity: CinemaCity
) : OrderFacade {

private val currentUrl = MutableStateFlow("")

override val isCompleted = currentUrl.map { it.contains("OrderComplete", ignoreCase = true) }

override suspend fun getRequest(): Result<RequestView> {
val headers = buildMap {
put("access-token", cinemaCity.customers.getToken())
}
return RequestView(
url = url,
headers = headers.toImmutableMap()
).let(Result.Companion::success)
override suspend fun getHeaders() = buildMap {
put("access-token", cinemaCity.customers.getToken())
}

override fun setUrl(url: String) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
package movie.metropolis.app.presentation.order

import androidx.compose.runtime.*
import kotlinx.collections.immutable.ImmutableMap

@Stable
data class RequestView(
val url: String,
val headers: ImmutableMap<String, String>
)
class RequestView {
var url by mutableStateOf("")
val headers = mutableStateMapOf<String, String>()
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.flowOf
import movie.metropolis.app.presentation.order.OrderFacade
import movie.metropolis.app.presentation.order.RequestView
import movie.metropolis.app.screen.Route
import movie.metropolis.app.util.retainStateIn
import javax.inject.Inject
Expand All @@ -26,8 +26,8 @@ class PurchaseViewModel private constructor(
factory.create(Route.Order.Arguments(handle).url)
)

val request = flow { emit(facade.getRequest()) }
.map { it.getOrNull() }
val request = flowOf<RequestView?>()/*flow { emit(facade.getRequest()) }
.map { it.getOrNull() }*/
.retainStateIn(viewModelScope, null)

val isCompleted = facade.isCompleted
Expand Down
12 changes: 10 additions & 2 deletions app/src/main/java/movie/metropolis/app/ui/Navigation.kt
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ import movie.metropolis.app.ui.home.HomeScreen
import movie.metropolis.app.ui.home.HomeViewModel
import movie.metropolis.app.ui.movie.MovieScreen
import movie.metropolis.app.ui.movie.MovieViewModel
import movie.metropolis.app.ui.order.OrderScreen
import movie.metropolis.app.ui.order.OrderViewModel
import movie.metropolis.app.ui.profile.ProfileScreen
import movie.metropolis.app.ui.profile.ProfileViewModel
import movie.metropolis.app.ui.setup.SetupScreen
Expand Down Expand Up @@ -116,7 +118,6 @@ fun Navigation(
onConsentChange = vm::onConsentChange
)
}
composable(Route.UserEditor.route) { Text("UserEditor") }
composable(Route.Movie.route, arguments = Route.Movie.arguments) {
val vm = hiltViewModel<MovieViewModel>()
val state = vm.state
Expand Down Expand Up @@ -150,7 +151,14 @@ fun Navigation(
)
}
composable(Route.OrderComplete.route) { Text("OrderComplete") }
composable(Route.Order.route) { Text("Order") }
composable(Route.Order.route) {
val vm = hiltViewModel<OrderViewModel>()
OrderScreen(
state = vm.state,
onBackClick = navController::navigateUp,
onUrlChanged = vm::updateUrl
)
}
composable(Route.Settings.route) { Text("Settings") }
}
}
Expand Down
70 changes: 70 additions & 0 deletions app/src/main/java/movie/metropolis/app/ui/order/OrderScreen.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package movie.metropolis.app.ui.order

import androidx.compose.material.icons.*
import androidx.compose.material.icons.automirrored.filled.*
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.*
import androidx.compose.ui.graphics.*
import androidx.compose.ui.input.nestedscroll.*
import androidx.compose.ui.tooling.preview.*
import movie.metropolis.app.presentation.order.RequestView
import movie.metropolis.app.ui.order.component.WebView
import movie.style.layout.PreviewLayout

@OptIn(ExperimentalMaterial3Api::class, ExperimentalStdlibApi::class)
@Composable
fun OrderScreen(
state: RequestView,
onBackClick: () -> Unit,
onUrlChanged: (String?) -> Unit,
modifier: Modifier = Modifier,
) {
var title by remember { mutableStateOf("") }
val scrollBehavior = TopAppBarDefaults.exitUntilCollapsedScrollBehavior()
OrderScreenScaffold(
modifier = modifier,
title = { Text(title) },
website = {
val contentColor = LocalContentColor.current
WebView(
modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
url = state.url,
headers = state.headers,
onProgressChanged = {},
onEndReached = onBackClick,
onUrlChanged = onUrlChanged,
onTitleChanged = { title = it.orEmpty() },
contentPadding = it,
onPageVisible = {
val js = """
var ss = document.createElement("style");
ss.textContent = `table.ticketTable td { color: #${
(contentColor.toArgb().shl(8).or(0xFF)).toHexString()
} !important;} .orderForm .payuoptions .payuOpt { background-color: transparent !important; } .total-block { color: unset !important }`;
document.head.appendChild(ss);
""".trimIndent().replace("\n", "")
evaluateJavascript(js, null)
},
connection = scrollBehavior.nestedScrollConnection
)
},
navigationIcon = {
IconButton(onBackClick) {
Icon(Icons.AutoMirrored.Default.ArrowBack, null)
}
},
scrollBehavior = scrollBehavior
)
}

@PreviewLightDark
@PreviewFontScale
@Composable
private fun OrderScreenPreview() = PreviewLayout {
OrderScreen(
state = RequestView(),
onBackClick = {},
onUrlChanged = {}
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package movie.metropolis.app.ui.order

import androidx.compose.foundation.*
import androidx.compose.foundation.layout.*
import androidx.compose.material.icons.*
import androidx.compose.material.icons.automirrored.filled.*
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.*
import androidx.compose.ui.draw.*
import androidx.compose.ui.graphics.*
import androidx.compose.ui.tooling.preview.*
import movie.style.layout.PreviewLayout
import movie.style.util.pc

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun OrderScreenScaffold(
title: @Composable () -> Unit,
website: @Composable (PaddingValues) -> Unit,
navigationIcon: @Composable () -> Unit,
modifier: Modifier = Modifier,
scrollBehavior: TopAppBarScrollBehavior = TopAppBarDefaults.exitUntilCollapsedScrollBehavior()
) = Scaffold(
modifier = modifier,
topBar = {
LargeTopAppBar(
modifier = Modifier
.windowInsetsPadding(
WindowInsets.systemBars.only(WindowInsetsSides.Horizontal + WindowInsetsSides.Top)
)
.padding(1.pc)
.clip(MaterialTheme.shapes.medium),
windowInsets = WindowInsets(0),
scrollBehavior = scrollBehavior,
title = title,
navigationIcon = navigationIcon
)
}
) { padding ->
Box(
modifier = Modifier.fillMaxSize(),
propagateMinConstraints = true
) {
website(padding)
}
}

@OptIn(ExperimentalMaterial3Api::class)
@PreviewLightDark
@PreviewFontScale
@Composable
private fun OrderScreenScaffoldPreview() = PreviewLayout {
OrderScreenScaffold(
title = { Text("Title") },
website = { Box(Modifier.background(Color.Blue)) },
navigationIcon = {
IconButton({}) {
Icon(Icons.AutoMirrored.Default.ArrowBack, null)
}
}
)
}
43 changes: 43 additions & 0 deletions app/src/main/java/movie/metropolis/app/ui/order/OrderViewModel.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package movie.metropolis.app.ui.order

import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.launch
import movie.metropolis.app.presentation.order.OrderFacade
import movie.metropolis.app.presentation.order.RequestView
import movie.metropolis.app.screen.Route
import movie.metropolis.app.util.retainStateIn
import javax.inject.Inject

@HiltViewModel
class OrderViewModel private constructor(
private val facade: OrderFacade
) : ViewModel() {

@Inject
constructor(
handle: SavedStateHandle,
factory: OrderFacade.Factory
) : this(
factory.create(Route.Order.Arguments(handle).url)
)

val state = RequestView()

init {
viewModelScope.launch {
state.headers.putAll(facade.getHeaders())
state.url = facade.url
}
}

val isCompleted = facade.isCompleted
.retainStateIn(viewModelScope, false)

fun updateUrl(url: String?) {
facade.setUrl(url.orEmpty())
}

}
Loading

0 comments on commit cc93ae8

Please sign in to comment.