Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found
Select Git revision

Target

Select target project
  • jonas.broeckmann/kaffeekasse
1 result
Select Git revision
Show changes
Commits on Source (3)
Showing
with 206 additions and 369 deletions
import com.android.build.api.dsl.ApplicationBuildType
plugins {
alias(libs.plugins.gradle.versions)
alias(libs.plugins.android.application)
alias(libs.plugins.kotlin.android)
alias(libs.plugins.compose.compiler)
alias(libs.plugins.kotlinx.serialization)
alias(libs.plugins.dokka)
}
......@@ -33,6 +33,10 @@ android {
useSupportLibrary = true
}
}
buildFeatures {
compose = true
buildConfig = true
}
buildTypes {
fun ApplicationBuildType.debugCredentials(
portalUsername: Any?,
......@@ -89,25 +93,6 @@ android {
sourceCompatibility = JavaVersion.VERSION_19
targetCompatibility = JavaVersion.VERSION_19
}
kotlinOptions {
jvmTarget = "19"
freeCompilerArgs += "-Xcontext-receivers"
// freeCompilerArgs += "-opt-in=kotlin.ExperimentalStdlibApi"
// freeCompilerArgs += "-opt-in=kotlin.time.ExperimentalTime"
// freeCompilerArgs += "-opt-in=kotlinx.coroutines.ExperimentalCoroutinesApi"
freeCompilerArgs += "-opt-in=androidx.compose.ui.ExperimentalComposeUiApi"
freeCompilerArgs += "-opt-in=androidx.compose.foundation.ExperimentalFoundationApi"
// freeCompilerArgs += "-opt-in=androidx.compose.foundation.layout.ExperimentalLayoutApi"
// freeCompilerArgs += "-opt-in=androidx.compose.animation.ExperimentalAnimationApi"
freeCompilerArgs += "-opt-in=androidx.compose.material3.ExperimentalMaterial3Api"
}
buildFeatures {
compose = true
buildConfig = true
}
composeOptions {
kotlinCompilerExtensionVersion = libs.versions.compose.compiler.get()
}
packaging {
resources {
excludes += "/META-INF/{AL2.0,LGPL2.1}"
......@@ -117,22 +102,30 @@ android {
}
}
kotlin {
compilerOptions {
freeCompilerArgs.addAll(
"-Xcontext-receivers",
"-opt-in=androidx.compose.ui.ExperimentalComposeUiApi",
"-opt-in=androidx.compose.foundation.ExperimentalFoundationApi",
"-opt-in=androidx.compose.material3.ExperimentalMaterial3Api",
)
}
}
dependencies {
implementation(libs.androidx.core)
implementation(libs.androidx.credentials)
implementation(libs.androidx.datastore)
implementation(libs.androidx.lifecycle.runtime)
implementation(libs.androidx.lifecycle.viewmodel.compose)
implementation(libs.androidx.activity.compose)
implementation(libs.androidx.navigation.compose)
implementation(libs.compose.bom)
implementation(libs.compose.animation)
implementation(libs.compose.foundation)
implementation(libs.compose.material.icons.extended)
implementation(libs.compose.material3)
implementation(libs.compose.runtime)
implementation(libs.compose.ui)
implementation(libs.compose.ui.graphics)
implementation(libs.compose.ui.tooling.preview)
implementation(libs.compose.ui.text.google.fonts)
implementation(libs.compose.material3)
implementation(libs.compose.material.icons.extended)
implementation(libs.compose.grid)
implementation(libs.kotlinx.datetime)
......@@ -164,23 +157,9 @@ dependencies {
implementation(libs.commonutils)
dokkaPlugin(libs.dokka.android)
testImplementation("junit:junit:4.13.2")
// androidTestImplementation("androidx.test.ext:junit:1.1.5")
// androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1")
// androidTestImplementation(platform("androidx.compose:compose-bom:2023.10.01"))
// androidTestImplementation("androidx.compose.ui:ui-test-junit4")
debugImplementation("androidx.compose.ui:ui-tooling")
debugImplementation("androidx.compose.ui:ui-test-manifest")
}
tasks.withType<com.github.benmanes.gradle.versions.updates.DependencyUpdatesTask> {
rejectVersionIf { isUnstable(candidate.version) }
}
fun isUnstable(version: String): Boolean {
val normalizedVersion = version.lowercase()
return listOf("snapshot", "alpha", "beta", "rc", "m", "dev").any { it in normalizedVersion }
testImplementation(libs.junit4)
androidTestImplementation(libs.compose.ui.test.junit4)
debugImplementation(libs.compose.ui.test.manifest)
}
......@@ -37,6 +37,7 @@ import androidx.compose.material3.OutlinedCard
import androidx.compose.material3.ProvideTextStyle
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.material3.pulltorefresh.PullToRefreshBox
import androidx.compose.material3.rememberModalBottomSheetState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
......@@ -106,7 +107,6 @@ import net.novagamestudios.kaffeekasse.ui.theme.disabled
import net.novagamestudios.kaffeekasse.ui.util.HorizontalKeyedPager
import net.novagamestudios.kaffeekasse.ui.util.HorizontalPagedLayout
import net.novagamestudios.kaffeekasse.ui.util.KeyedPagerState
import net.novagamestudios.kaffeekasse.ui.util.PullToRefreshBox
import net.novagamestudios.kaffeekasse.ui.util.navigation.BackNavigationHandler
import net.novagamestudios.kaffeekasse.ui.util.onClickComingSoon
import net.novagamestudios.kaffeekasse.ui.util.screenmodel.ScreenModelFactory
......@@ -240,7 +240,7 @@ private fun Overview(
model: OverviewScreenModel,
modifier: Modifier = Modifier
) = PullToRefreshBox(
refreshing = { false },
isRefreshing = false,
onRefresh = { model.refreshMonth(model.currentMonth) },
modifier.fillMaxSize()
) {
......
......@@ -90,7 +90,7 @@ private fun Account(
model: AccountScreenModel,
modifier: Modifier = Modifier
) = PullToRefreshBox(
state = model.account,
data = model.account,
modifier.fillMaxSize()
) {
RichDataContent(
......
......@@ -118,7 +118,7 @@ private fun Transactions(
model: TransactionsScreenModel,
modifier: Modifier = Modifier
) = PullToRefreshBox(
state = model.transactions,
data = model.transactions,
modifier.fillMaxSize()
) {
RichDataContent(
......
......@@ -14,6 +14,7 @@ import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
......@@ -95,9 +96,13 @@ fun CategorizedItems(
label = "ItemGroupSelection"
) { category ->
if (category == null) LazyCategoryCardGrid(
itemsByCategory = state.categoriesWithItems,
cart = cart,
onClick = { state.select(it) },
state = remember(state, cart) {
CategoryCardGridState(
itemsByCategory = state.categoriesWithItems,
cart = cart,
onClick = { state.select(it) },
)
},
spacerForFAB = true
) else LazyItemCardGrid(
items = state.itemsByCategory[category] ?: emptyList(),
......@@ -107,24 +112,32 @@ fun CategorizedItems(
}
}
private data class CategoryCardGridState(
val itemsByCategory: List<Pair<ItemCategory, List<Item>>>,
val cart: Cart,
private val onClick: (ItemCategory) -> Unit,
) {
fun click(category: ItemCategory) {
onClick(category)
}
}
@Composable
private fun LazyCategoryCardGrid(
itemsByCategory: List<Pair<ItemCategory, List<Item>>>,
cart: Cart,
onClick: (ItemCategory) -> Unit,
state: CategoryCardGridState,
modifier: Modifier = Modifier,
scrollable: Boolean = true,
spacerForFAB: Boolean = false
) = LazyBasicCardGrid(
items = itemsByCategory,
items = state.itemsByCategory,
modifier,
scrollable = scrollable,
spacerForFAB = spacerForFAB
) { (category, items) ->
CategoryCard(
category = category,
highlighted = items.any { it in cart },
onClick = { onClick(category) }
highlighted = items.any { it in state.cart },
onClick = { state.click(category) }
)
}
......
......@@ -37,7 +37,7 @@ import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.ProvideTextStyle
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.material3.pulltorefresh.PullToRefreshContainer
import androidx.compose.material3.pulltorefresh.rememberPullToRefreshState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
......@@ -52,7 +52,6 @@ import androidx.compose.ui.draw.clip
import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.graphics.RectangleShape
import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.platform.LocalConfiguration
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.font.FontWeight
......@@ -62,7 +61,6 @@ import androidx.compose.ui.text.input.PasswordVisualTransformation
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.compose.ui.zIndex
import cafe.adriel.voyager.core.model.ScreenModel
import cafe.adriel.voyager.core.model.screenModelScope
import cafe.adriel.voyager.navigator.Navigator
......@@ -91,6 +89,7 @@ import net.novagamestudios.kaffeekasse.ui.navigation.ScaffoldContentWithModel
import net.novagamestudios.kaffeekasse.ui.util.AlphabetSelectionChar
import net.novagamestudios.kaffeekasse.ui.util.FailureRetryScreen
import net.novagamestudios.kaffeekasse.ui.util.HorizontalSelectionBar
import net.novagamestudios.kaffeekasse.ui.util.PullToRefreshIndicator
import net.novagamestudios.kaffeekasse.ui.util.RichDataContent
import net.novagamestudios.kaffeekasse.ui.util.Toasts
import net.novagamestudios.kaffeekasse.ui.util.ToastsState
......@@ -99,7 +98,7 @@ import net.novagamestudios.kaffeekasse.ui.util.TopBarSearchField
import net.novagamestudios.kaffeekasse.ui.util.TopBarSearchFieldState
import net.novagamestudios.kaffeekasse.ui.util.VerticalSelectionBar
import net.novagamestudios.kaffeekasse.ui.util.navigation.BackNavigationHandler
import net.novagamestudios.kaffeekasse.ui.util.rememberPullToRefreshState
import net.novagamestudios.kaffeekasse.ui.util.pullToRefresh
import net.novagamestudios.kaffeekasse.ui.util.screenmodel.ScreenModelFactory
import net.novagamestudios.kaffeekasse.ui.util.screenmodel.ScreenModelProvider
import net.novagamestudios.kaffeekasse.util.richdata.asRichDataFlow
......@@ -222,12 +221,12 @@ private fun UserSelection(
model: UserSelectionScreenModel,
modifier: Modifier = Modifier
) {
val pullToRefreshState = rememberPullToRefreshState(model.users)
val pullToRefreshState = rememberPullToRefreshState()
Box(
modifier
.fillMaxSize()
.clip(RectangleShape)
.nestedScroll(pullToRefreshState.nestedScrollConnection),
.pullToRefresh(model.users, pullToRefreshState),
contentAlignment = Alignment.TopCenter
) {
// UserSearchBar(
......@@ -243,7 +242,6 @@ private fun UserSelection(
// .padding(8.dp)
// .align(Alignment.TopCenter)
// )
RichDataContent(
source = model.filteredUsers,
errorContent = { error ->
......@@ -271,7 +269,11 @@ private fun UserSelection(
)
}
)
PullToRefreshContainer(pullToRefreshState, Modifier.zIndex(2f))
PullToRefreshIndicator(
data = model.users,
state = pullToRefreshState,
Modifier.align(Alignment.TopCenter)
)
}
model.userAuthDialog?.let { state ->
UserAuthDialog(
......
......@@ -8,9 +8,10 @@ import cafe.adriel.voyager.navigator.Navigator
import cafe.adriel.voyager.navigator.currentOrThrow
import net.novagamestudios.kaffeekasse.ui.util.navigation.BackNavigationHandler
import net.novagamestudios.kaffeekasse.ui.util.screenmodel.ScreenModelProvider
import java.io.Serializable
abstract class ScaffoldContent {
abstract class ScaffoldContent : Serializable {
@Composable
abstract fun Content(navigator: Navigator)
@Composable
......
package net.novagamestudios.kaffeekasse.ui.util
import android.annotation.SuppressLint
import androidx.compose.animation.core.AnimationSpec
import androidx.compose.animation.core.spring
import androidx.compose.foundation.gestures.Orientation
import androidx.compose.foundation.gestures.TargetedFlingBehavior
import androidx.compose.foundation.gestures.snapping.SnapFlingBehavior
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.pager.PageSize
import androidx.compose.foundation.pager.PagerDefaults
......@@ -12,7 +12,6 @@ import androidx.compose.foundation.pager.PagerScope
import androidx.compose.foundation.pager.PagerState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.input.nestedscroll.NestedScrollConnection
......@@ -88,6 +87,7 @@ fun <K : Any> HorizontalKeyedPager(
}
}
@SuppressLint("ComposableNaming")
@Composable
fun <K : Any> synchronizePagerState(
pagerState: KeyedPagerState<K>,
......@@ -102,6 +102,7 @@ fun <K : Any> synchronizePagerState(
}
}
@SuppressLint("ComposableNaming")
@Composable
fun <K : Any> synchronizePagerState(
pagerState: KeyedPagerState<K>,
......
package net.novagamestudios.kaffeekasse.ui.util
import androidx.compose.animation.core.animate
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.BoxScope
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.pulltorefresh.PullToRefreshContainer
import androidx.compose.material3.pulltorefresh.PullToRefreshDefaults
import androidx.compose.material3.pulltorefresh.PullToRefreshState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableFloatStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.runtime.snapshotFlow
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.input.nestedscroll.NestedScrollConnection
import androidx.compose.ui.input.nestedscroll.NestedScrollSource
import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.unit.Velocity
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
import kotlin.math.abs
import kotlin.math.pow
@Composable
fun PullToRefreshBox(
refreshing: () -> Boolean,
onRefresh: () -> Unit,
modifier: Modifier = Modifier,
content: @Composable BoxScope.() -> Unit
) {
val state = rememberPullToRefreshState(refreshing, onRefresh)
Box(modifier.nestedScroll(state.nestedScrollConnection)) {
content()
PullToRefreshContainer(state, Modifier.align(Alignment.TopCenter))
}
}
@Composable
fun rememberPullToRefreshState(
refreshing: () -> Boolean,
onRefresh: () -> Unit
): PullToRefreshState {
val syncScope = rememberCoroutineScope()
val positionalThresholdPx = with(LocalDensity.current) {
PullToRefreshDefaults.PositionalThreshold.toPx()
}
return remember(refreshing, onRefresh, positionalThresholdPx) {
PullToRefreshStateImpl(
syncScope = syncScope,
refreshing = refreshing,
positionalThreshold = positionalThresholdPx,
enabled = { true },
onRefresh = onRefresh
)
}
}
@ExperimentalMaterial3Api
internal class PullToRefreshStateImpl(
syncScope: CoroutineScope,
private val refreshing: () -> Boolean,
override val positionalThreshold: Float,
enabled: () -> Boolean,
private val onRefresh: () -> Unit
) : PullToRefreshState {
override val progress get() = adjustedDistancePulled / positionalThreshold
override val verticalOffset: Float get() = _verticalOffset
override val isRefreshing get() = refreshing()
override fun startRefresh() {
onRefresh()
}
override fun endRefresh() {
// _verticalOffset = 0f
}
init {
syncScope.launch {
snapshotFlow { isRefreshing }
.collect { refreshing ->
if (!refreshing) {
animateTo(0f)
} else {
animateTo(positionalThreshold)
}
}
}
}
override var nestedScrollConnection = object : NestedScrollConnection {
override fun onPreScroll(
available: Offset,
source: NestedScrollSource,
): Offset = when {
!enabled() -> Offset.Zero
// Swiping up
source == NestedScrollSource.UserInput && available.y < 0 -> {
consumeAvailableOffset(available)
}
else -> Offset.Zero
}
override fun onPostScroll(
consumed: Offset,
available: Offset,
source: NestedScrollSource
): Offset = when {
!enabled() -> Offset.Zero
// Swiping down
source == NestedScrollSource.UserInput && available.y > 0 -> {
consumeAvailableOffset(available)
}
else -> Offset.Zero
}
override suspend fun onPreFling(available: Velocity): Velocity {
return Velocity(0f, onRelease(available.y))
}
}
/** Helper method for nested scroll connection */
fun consumeAvailableOffset(available: Offset): Offset {
val y = if (isRefreshing) 0f else {
val newOffset = (distancePulled + available.y).coerceAtLeast(0f)
val dragConsumed = newOffset - distancePulled
distancePulled = newOffset
_verticalOffset = calculateVerticalOffset()
dragConsumed
}
return Offset(0f, y)
}
/** Helper method for nested scroll connection. Calls onRefresh callback when triggered */
suspend fun onRelease(velocity: Float): Float {
if (isRefreshing) return 0f // Already refreshing, do nothing
// Trigger refresh
if (adjustedDistancePulled > positionalThreshold) {
startRefresh()
} else {
animateTo(0f)
}
val consumed = when {
// We are flinging without having dragged the pull refresh (for example a fling inside
// a list) - don't consume
distancePulled == 0f -> 0f
// If the velocity is negative, the fling is upwards, and we don't want to prevent the
// the list from scrolling
velocity < 0f -> 0f
// We are showing the indicator, and the fling is downwards - consume everything
else -> velocity
}
distancePulled = 0f
return consumed
}
suspend fun animateTo(offset: Float) {
animate(initialValue = verticalOffset, targetValue = offset) { value, _ ->
_verticalOffset = value
}
}
/** Provides custom vertical offset behavior for [PullToRefreshContainer] */
fun calculateVerticalOffset(): Float = when {
// If drag hasn't gone past the threshold, the position is the adjustedDistancePulled.
adjustedDistancePulled <= positionalThreshold -> adjustedDistancePulled
else -> {
// How far beyond the threshold pull has gone, as a percentage of the threshold.
val overshootPercent = abs(progress) - 1.0f
// Limit the overshoot to 200%. Linear between 0 and 200.
val linearTension = overshootPercent.coerceIn(0f, 2f)
// Non-linear tension. Increases with linearTension, but at a decreasing rate.
val tensionPercent = linearTension - linearTension.pow(2) / 4
// The additional offset beyond the threshold.
val extraOffset = positionalThreshold * tensionPercent
positionalThreshold + extraOffset
}
}
companion object {
}
internal var distancePulled by mutableFloatStateOf(0f)
private val adjustedDistancePulled: Float get() = distancePulled * DragMultiplier
private var _verticalOffset by mutableFloatStateOf(0f)
}
private const val DragMultiplier = 0.5f
package net.novagamestudios.kaffeekasse.ui.util
import androidx.compose.foundation.layout.BoxScope
import androidx.compose.material3.pulltorefresh.PullToRefreshBox
import androidx.compose.material3.pulltorefresh.PullToRefreshDefaults
import androidx.compose.material3.pulltorefresh.PullToRefreshState
import androidx.compose.material3.pulltorefresh.pullToRefresh
import androidx.compose.material3.pulltorefresh.rememberPullToRefreshState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.composed
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.Dp
import kotlinx.coroutines.launch
import net.novagamestudios.common_utils.compose.components.Progress
import net.novagamestudios.kaffeekasse.ui.kaffeekasse.components.FailureRetryScreen
......@@ -19,42 +27,66 @@ import net.novagamestudios.kaffeekasse.util.richdata.collectAsRichState
@Composable
fun <T : Any> PullToRefreshBox(
source: RichDataSource<T>,
modifier: Modifier = Modifier,
content: @Composable BoxScope.() -> Unit
) = PullToRefreshBox(
state = source.collectAsRichState(),
modifier = modifier,
content = content
)
@Composable
fun <T : Any> PullToRefreshBox(
state: RichDataStateWithFunctions<T>,
data: RichDataStateWithFunctions<T>,
modifier: Modifier = Modifier,
state: PullToRefreshState = rememberPullToRefreshState(),
indicator: @Composable (BoxScope.() -> Unit) = {
PullToRefreshDefaults.Indicator(
modifier = Modifier.align(Alignment.TopCenter),
isRefreshing = data.isLoading,
state = state
)
},
content: @Composable BoxScope.() -> Unit
) {
val coroutineScope = rememberCoroutineScope()
PullToRefreshBox(
refreshing = { state.isLoading },
onRefresh = { coroutineScope.launch { state.refresh() } },
isRefreshing = data.isLoading,
onRefresh = { coroutineScope.launch { data.refresh() } },
modifier,
state = state,
indicator = indicator,
content = content
)
}
@Composable
fun <T : Any> rememberPullToRefreshState(
fun <T : Any> Modifier.pullToRefresh(
data: RichDataSource<T>,
): PullToRefreshState {
state: PullToRefreshState,
enabled: () -> Boolean = { true },
threshold: Dp = PullToRefreshDefaults.PositionalThreshold
): Modifier = composed {
val dataState = data.collectAsRichState()
val coroutineScope = rememberCoroutineScope()
return rememberPullToRefreshState(
refreshing = { dataState.isLoading },
pullToRefresh(
isRefreshing = dataState.isLoading,
state = state,
enabled = enabled,
threshold = threshold,
onRefresh = { coroutineScope.launch { data.refresh() } }
)
}
@Composable
fun <T : Any> PullToRefreshIndicator(
data: RichDataSource<T>,
state: PullToRefreshState,
modifier: Modifier = Modifier,
containerColor: Color = PullToRefreshDefaults.containerColor,
color: Color = PullToRefreshDefaults.indicatorColor,
threshold: Dp = PullToRefreshDefaults.PositionalThreshold
) {
val dataState = data.collectAsRichState()
PullToRefreshDefaults.Indicator(
state = state,
isRefreshing = dataState.isLoading,
modifier = modifier,
containerColor = containerColor,
color = color,
threshold = threshold
)
}
@Composable
inline fun <T : Any> RichDataContent(
source: RichDataSource<T>,
......
// Top-level build file where you can add configuration options common to all sub-projects/modules.
plugins {
alias(libs.plugins.gradle.versions) apply false
alias(libs.plugins.android.application) apply false
alias(libs.plugins.kotlin.android) apply false
alias(libs.plugins.compose.compiler) apply false
alias(libs.plugins.kotlinx.serialization) apply false
alias(libs.plugins.dokka) apply false
}
\ No newline at end of file
......@@ -15,6 +15,9 @@ android.nonTransitiveRClass=true
#kotlin.experimental.tryK2=true
#android.lint.useK2Uast=true
# See https://kotlinlang.org/docs/k2-compiler-migration-guide.html#use-kotlin-build-reports-with-gradle
#kotlin.build.report.output=file
# See https://github.com/ben-manes/gradle-versions-plugin/issues/859
# Remove when version of AGP >= 8.3.1
systemProp.javax.xml.parsers.SAXParserFactory=com.sun.org.apache.xerces.internal.jaxp.SAXParserFactoryImpl
......
[versions]
kotlin = "2.0.0"
dokka = "1.9.20"
compose-bom = "2024.05.00"
compose = "1.7.0-beta01"
material3 = "1.3.0-beta01"
ktor = "2.3.10"
vico = "2.0.0-alpha.8"
voyager = "1.0.0"
coil = "2.6.0"
acra = "5.11.3"
junit4 = "4.13.2"
[plugins]
android-application = { id = "com.android.application", version = "8.2.2" }
kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
compose-compiler = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" }
kotlinx-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" }
dokka = { id = "org.jetbrains.dokka", version.ref = "dokka" }
[libraries]
dokka-android = { group = "org.jetbrains.dokka", name = "android-documentation-plugin", version.ref = "dokka" }
androidx-core = { group = "androidx.core", name = "core-ktx", version = "1.13.1" }
androidx-credentials = { group = "androidx.credentials", name = "credentials", version = "1.3.0-alpha04" }
androidx-datastore = { group = "androidx.datastore", name = "datastore-preferences-android", version = "1.1.1" }
androidx-activity-compose = { group = "androidx.activity", name = "activity-compose", version = "1.9.0" }
compose-bom = { group = "androidx.compose", name = "compose-bom", version.ref = "compose-bom" }
compose-animation = { group = "androidx.compose.animation", name = "animation", version.ref = "compose" }
compose-compiler = { group = "androidx.compose.compiler", name = "compiler", version.ref = "compose" }
compose-foundation = { group = "androidx.compose.foundation", name = "foundation", version.ref = "compose" }
compose-material = { group = "androidx.compose.material", name = "material", version.ref = "compose" }
compose-material-icons-extended = { group = "androidx.compose.material", name = "material-icons-extended", version.ref = "compose" }
compose-material3 = { group = "androidx.compose.material3", name = "material3", version.ref = "material3" }
compose-runtime = { group = "androidx.compose.runtime", name = "runtime", version.ref = "compose" }
compose-ui = { group = "androidx.compose.ui", name = "ui", version.ref = "compose" }
compose-ui-graphics = { group = "androidx.compose.ui", name = "ui-graphics", version.ref = "compose" }
compose-ui-test-junit4 = { group = "androidx.compose.ui", name = "ui-test-junit4", version.ref = "compose" }
compose-ui-test-manifest = { group = "androidx.compose.ui", name = "ui-test-manifest", version.ref = "compose" }
compose-ui-tooling = { group = "androidx.compose.ui", name = "ui-tooling", version.ref = "compose" }
compose-ui-tooling-preview = { group = "androidx.compose.ui", name = "ui-tooling-preview", version.ref = "compose" }
compose-ui-text-google-fonts = { group = "androidx.compose.ui", name = "ui-text-google-fonts", version.ref = "compose" }
compose-grid = { group = "io.woong.compose.grid", name = "grid", version = "1.2.2" }
kotlinx-datetime = { group = "org.jetbrains.kotlinx", name = "kotlinx-datetime", version = "0.6.0-RC.2" }
kotlinx-serialization-json = { group = "org.jetbrains.kotlinx", name = "kotlinx-serialization-json", version = "1.6.3" }
ktor-client-core = { group = "io.ktor", name = "ktor-client-core", version.ref = "ktor" }
ktor-client-okhttp = { group = "io.ktor", name = "ktor-client-okhttp", version.ref = "ktor" }
ktor-client-contentnegotiation = { group = "io.ktor", name = "ktor-client-content-negotiation", version.ref = "ktor" }
ktor-serialization-kotlinx-json = { group = "io.ktor", name = "ktor-serialization-kotlinx-json", version.ref = "ktor" }
skrapeit = { group = "it.skrape", name = "skrapeit", version = "1.2.2" }
skrapeit-ktor = { group = "it.skrape", name = "skrapeit-ktor-extension", version = "1.2.2" }
vico-core = { group = "com.patrykandpatrick.vico", name = "core", version.ref = "vico" }
vico-compose = { group = "com.patrykandpatrick.vico", name = "compose", version.ref = "vico" }
vico-compose-m2 = { group = "com.patrykandpatrick.vico", name = "compose-m2", version.ref = "vico" }
vico-compose-m3 = { group = "com.patrykandpatrick.vico", name = "compose-m3", version.ref = "vico" }
voyager-navigator = { group = "cafe.adriel.voyager", name = "voyager-navigator", version.ref = "voyager" }
voyager-screenmodel = { group = "cafe.adriel.voyager", name = "voyager-screenmodel", version.ref = "voyager" }
voyager-bottomsheetnavigator = { group = "cafe.adriel.voyager", name = "voyager-bottom-sheet-navigator", version.ref = "voyager" }
voyager-tabnavigator = { group = "cafe.adriel.voyager", name = "voyager-tab-navigator", version.ref = "voyager" }
voyager-transitions = { group = "cafe.adriel.voyager", name = "voyager-transitions", version.ref = "voyager" }
coil = { group = "io.coil-kt", name = "coil", version.ref = "coil" }
coil-compose = { group = "io.coil-kt", name = "coil-compose", version.ref = "coil" }
acra-http = { group = "ch.acra", name = "acra-http", version.ref = "acra" }
acra-mail = { group = "ch.acra", name = "acra-mail", version.ref = "acra" }
acra-core = { group = "ch.acra", name = "acra-core", version.ref = "acra" }
acra-dialog = { group = "ch.acra", name = "acra-dialog", version.ref = "acra" }
acra-notification = { group = "ch.acra", name = "acra-notification", version.ref = "acra" }
acra-toast = { group = "ch.acra", name = "acra-toast", version.ref = "acra" }
acra-limiter = { group = "ch.acra", name = "acra-limiter", version.ref = "acra" }
acra-advancedscheduler = { group = "ch.acra", name = "acra-advanced-scheduler", version.ref = "acra" }
commonutils = { group = "com.gitlab.JojoIV", name = "common_utils", version = "ee87e097c5" }
junit4 = { group = "junit", name = "junit", version.ref = "junit4" }
......@@ -15,86 +15,6 @@ dependencyResolutionManagement {
mavenLocal()
maven { setUrl("https://jitpack.io") }
}
versionCatalogs {
create("libs") {
version("kotlin", "1.9.20")
version("dokka", "1.9.20")
version("compose-compiler", "1.5.5")
version("compose-bom", "2024.05.00")
version("material3", "1.3.0-alpha05")
version("androidx-lifecycle", "2.8.0-rc01")
version("ktor", "2.3.8")
version("vico", "2.0.0-alpha.8")
version("voyager", "1.0.0")
version("coil", "2.6.0")
version("acra", "5.11.3")
plugin("gradle-versions", "com.github.ben-manes.versions").version("0.51.0")
plugin("android-application", "com.android.application").version("8.2.0")
plugin("kotlin-android", "org.jetbrains.kotlin.android").versionRef("kotlin")
plugin("kotlinx-serialization", "org.jetbrains.kotlin.plugin.serialization").versionRef("kotlin")
plugin("dokka", "org.jetbrains.dokka").versionRef("dokka")
library("dokka-android", "org.jetbrains.dokka", "android-documentation-plugin").versionRef("dokka")
library("androidx-core", "androidx.core", "core-ktx").version("1.13.1")
library("androidx-lifecycle-runtime", "androidx.lifecycle", "lifecycle-runtime-ktx").versionRef("androidx-lifecycle")
library("androidx-lifecycle-viewmodel-compose", "androidx.lifecycle", "lifecycle-viewmodel-compose").versionRef("androidx-lifecycle")
library("androidx-navigation-compose", "androidx.navigation", "navigation-compose").version("2.7.7")
library("androidx-activity-compose", "androidx.activity", "activity-compose").version("1.9.0")
library("compose-bom", "androidx.compose", "compose-bom").versionRef("compose-bom")
library("compose-ui", "androidx.compose.ui", "ui").withoutVersion()
library("compose-ui-graphics", "androidx.compose.ui", "ui-graphics").withoutVersion()
library("compose-ui-tooling-preview", "androidx.compose.ui", "ui-tooling-preview").withoutVersion()
library("compose-ui-text-google-fonts", "androidx.compose.ui", "ui-text-google-fonts").withoutVersion()
library("compose-material-icons-extended", "androidx.compose.material", "material-icons-extended").version("1.6.7")
library("compose-material3", "androidx.compose.material3", "material3").versionRef("material3")
library("compose-grid", "io.woong.compose.grid", "grid").version("1.2.2")
library("androidx-credentials", "androidx.credentials", "credentials").version("1.3.0-alpha03")
library("androidx-datastore", "androidx.datastore", "datastore-preferences-android").version("1.1.1")
library("kotlinx-datetime", "org.jetbrains.kotlinx", "kotlinx-datetime").version("0.6.0-RC.2")
library("kotlinx-serialization-json", "org.jetbrains.kotlinx", "kotlinx-serialization-json").version("1.6.3")
library("ktor-client-core", "io.ktor", "ktor-client-core").versionRef("ktor")
library("ktor-client-okhttp", "io.ktor", "ktor-client-okhttp").versionRef("ktor")
library("ktor-client-contentnegotiation", "io.ktor", "ktor-client-content-negotiation").versionRef("ktor")
library("ktor-serialization-kotlinx-json", "io.ktor", "ktor-serialization-kotlinx-json").versionRef("ktor")
library("skrapeit", "it.skrape", "skrapeit").version("1.2.2")
library("skrapeit-ktor", "it.skrape", "skrapeit-ktor-extension").version("1.2.2")
library("vico-core", "com.patrykandpatrick.vico", "core").versionRef("vico")
library("vico-compose", "com.patrykandpatrick.vico", "compose").versionRef("vico")
library("vico-compose-m2", "com.patrykandpatrick.vico", "compose-m2").versionRef("vico")
library("vico-compose-m3", "com.patrykandpatrick.vico", "compose-m3").versionRef("vico")
library("voyager-navigator", "cafe.adriel.voyager", "voyager-navigator").versionRef("voyager")
library("voyager-screenmodel", "cafe.adriel.voyager", "voyager-screenmodel").versionRef("voyager")
library("voyager-bottomsheetnavigator", "cafe.adriel.voyager", "voyager-bottom-sheet-navigator").versionRef("voyager")
library("voyager-tabnavigator", "cafe.adriel.voyager", "voyager-tab-navigator").versionRef("voyager")
library("voyager-transitions", "cafe.adriel.voyager", "voyager-transitions").versionRef("voyager")
library("coil", "io.coil-kt", "coil").versionRef("coil")
library("coil-compose", "io.coil-kt", "coil-compose").versionRef("coil")
library("acra-http", "ch.acra", "acra-http").versionRef("acra")
library("acra-mail", "ch.acra", "acra-mail").versionRef("acra")
library("acra-core", "ch.acra", "acra-core").versionRef("acra")
library("acra-dialog", "ch.acra", "acra-dialog").versionRef("acra")
library("acra-notification", "ch.acra", "acra-notification").versionRef("acra")
library("acra-toast", "ch.acra", "acra-toast").versionRef("acra")
library("acra-limiter", "ch.acra", "acra-limiter").versionRef("acra")
library("acra-advancedscheduler", "ch.acra", "acra-advanced-scheduler").versionRef("acra")
library("commonutils", "com.gitlab.JojoIV", "common_utils").version("ee87e097c5")
}
}
}
rootProject.name = "Kaffeekasse"
......