Skip to content

Instantly share code, notes, and snippets.

private val ddMMMMyyyyRegex = "([0-9]{1,2})\\s+([A-Za-z]{3,4})\\s+([0-9]{4})".toRegex()
private val monthMapping = mapOf(
"Jan" to Month.JANUARY,
...
"Sep" to Month.SEPTEMBER,
"Sept" to Month.SEPTEMBER,
...
"Dec" to Month.DECEMBER
)
public class PostListViewModelStateObject : ObservableObject {
@Published public private(set) var state: PostListState
init(viewModel: PostListViewModel) {
self.state = viewModel.container.stateFlow.value as! PostListState
(viewModel.container.stateFlow.asPublisher() as AnyPublisher<PostListState, Never>)
.receive(on: RunLoop.main)
.assign(to: &$state)
@mattmook
mattmook / Publisher.swift
Created September 8, 2021 06:04
OrbitMultiplatform-Publisher.swift
import Foundation
import Combine
import shared
public extension Kotlinx_coroutines_coreFlow {
func asPublisher<T: AnyObject>() -> AnyPublisher<T, Never> {
(FlowPublisher(flow: self) as FlowPublisher<T>).eraseToAnyPublisher()
}
}
@mattmook
mattmook / subscribe.kt
Created September 8, 2021 06:01
OrbitMultiplatform-subscribe.kt
fun Flow<*>.subscribe(onEach: (item: Any) -> Unit, onComplete: () -> Unit, onThrow: (error: Throwable) -> Unit): Job =
this.onEach { onEach(it as Any) }
.catch { onThrow(it) }
.onCompletion { onComplete() }
.launchIn(CoroutineScope(Job() + Dispatchers.Main))
class PostListViewModel(
private val postRepository: PostRepository,
) : ViewModel(), ContainerHost<PostListState, NavigationEvent> {
override val container = viewModelScope.container<PostListState, NavigationEvent>(
initialState = PostListState()
) {
loadOverviews()
}
@Composable
fun Screen() {
val lazyListState = rememberLazyListState()
Column {
AppBar(stringResource(id = R.string.app_name), elevation = lazyListState.elevation)
LazyColumn(state = lazyListState) {
...
}
val lazyListState = rememberLazyListState()
LazyColumn(state = lazyListState) {
...
}
val LazyListState.elevation: Dp
get() = if (firstVisibleItemIndex == 0) {
// For the first element, use the minimum of scroll offset and default elevation
// i.e. a value between 0 and 4.dp
minOf(firstVisibleItemScrollOffset.toFloat().dp, AppBarDefaults.TopAppBarElevation)
} else {
// If not the first element, always set elevation and show the shadow
AppBarDefaults.TopAppBarElevation
}
class ShadowScrollBehavior(context: Context, attrs: AttributeSet) : AppBarLayout.ScrollingViewBehavior(context, attrs) {
@SuppressLint("PrivateResource")
private val maxElevation = context.resources.getDimensionPixelSize(R.dimen.design_appbar_elevation).toFloat()
override fun onDependentViewChanged(parent: CoordinatorLayout, child: View, dependency: View):
Boolean {
if (dependency is AppBarLayout) {
when (child) {
is NestedScrollView -> {
@mattmook
mattmook / Orbit-PostListFragment.kt
Last active July 20, 2021 18:26
The state of MVI on Android - Orbit - PostListFragment
lifecycleScope.launch {
// See https://medium.com/androiddevelopers/a-safer-way-to-collect-flows-from-android-uis-23080b1f8bda
lifecycleOwner.lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) {
launch { viewModel.container.stateFlow.collect(::reduce)
launch { viewModel.container.sideEffectFlow.collect(::sideEffect)
}
}