Skip to content

Instantly share code, notes, and snippets.

@mattmook
mattmook / EncryptedSharedPreferencesTest.kt
Last active January 15, 2024 08:30
Testing EncryptedSharedPreferences from Android Jetpack Security with Robolectric
/*
* Copyright 2020 Appmattus Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
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()
}
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
}
@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) {
...
}
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 -> {