12 Commits
2.3.1 ... 2.3.3

Author SHA1 Message Date
cf5c408464 Update dependencies to use newest Android SDK. Clean up.
All checks were successful
Build Android / build (pull_request) Successful in 2m52s
Build Android / build (push) Successful in 3m2s
2024-08-23 12:16:44 +02:00
fdf8c5c7df Update dependencies.
All checks were successful
Build Android / build (push) Successful in 2m57s
2024-08-23 12:02:58 +02:00
7ed3a29c5b Merge pull request 'feature/update-dependencies' (#55) from feature/update-dependencies into develop
All checks were successful
Build Android / build (push) Successful in 2m37s
Reviewed-on: #55
2024-06-06 13:43:27 +02:00
9434d1f1b9 Upload as gitea artifacts.
All checks were successful
Build Android / build (push) Successful in 2m36s
Build Android / build (pull_request) Successful in 2m39s
2024-05-31 16:24:06 +02:00
9abff51cb8 Update deprecated swipe to dismiss box. 2024-05-31 15:49:29 +02:00
93f51b9220 Update dependencies. 2024-05-31 14:55:38 +02:00
8bb2b9bf20 Merge tag '2.3.2' into develop
All checks were successful
Build Android / build (push) Successful in 2m29s
2023-11-02 22:34:48 +01:00
00569666be Improve delete multiple games in a row.
All checks were successful
Build Android / build (push) Successful in 4m33s
closes #53
2023-11-02 22:32:35 +01:00
2cf6578378 Update gradle. 2023-11-02 22:32:31 +01:00
fbcf9af761 Change deploy user. 2023-11-02 22:32:24 +01:00
80039a5f94 Merge tag '2.3.1' into develop
All checks were successful
Build Android / build (push) Successful in 2m32s
2023-10-01 07:45:09 +02:00
4c01fe13a8 Merge tag '2.3' into develop
All checks were successful
Build Android / build (push) Successful in 9m4s
2023-09-27 19:05:39 +02:00
17 changed files with 211 additions and 161 deletions

View File

@@ -30,15 +30,11 @@ jobs:
- name: Build abb - name: Build abb
run: ./gradlew bundleRelease run: ./gradlew bundleRelease
- name: Deploy latest to Nextcloud - uses: actions/upload-artifact@v3
run: | with:
curl -k -u "${{ secrets.NEXTCLOUD_USERNAME }}:${{ secrets.NEXTCLOUD_PASSWORD }}" -T "app/build/outputs/apk/release/app-release.apk" "https://nextcloud.zobrist.me/remote.php/dav/files/deploy/TichuCounter/latest/app-release.apk" name: app-release
curl -k -u "${{ secrets.NEXTCLOUD_USERNAME }}:${{ secrets.NEXTCLOUD_PASSWORD }}" -T "app/build/outputs/bundle/release/app-release.aab" "https://nextcloud.zobrist.me/remote.php/dav/files/deploy/TichuCounter/latest/app-release.aab" retention-days: 10
path: app/build/outputs/**/release/app-release.*
- name: Deploy tagged build to Nextcloud
run: |
curl -k -u "${{ secrets.NEXTCLOUD_USERNAME }}:${{ secrets.NEXTCLOUD_PASSWORD }}" -T "app/build/outputs/apk/release/app-release.apk" "https://nextcloud.zobrist.me/remote.php/dav/files/deploy/TichuCounter/tagged/app-release-${GITHUB_REF_NAME##*/}.apk"
curl -k -u "${{ secrets.NEXTCLOUD_USERNAME }}:${{ secrets.NEXTCLOUD_PASSWORD }}" -T "app/build/outputs/bundle/release/app-release.aab" "https://nextcloud.zobrist.me/remote.php/dav/files/deploy/TichuCounter/tagged/app-release-${GITHUB_REF_NAME##*/}.aab"
- uses: https://github.com/ravsamhq/notify-slack-action@v2 - uses: https://github.com/ravsamhq/notify-slack-action@v2
if: always() if: always()

1
.gitignore vendored
View File

@@ -15,3 +15,4 @@
.idea .idea
keystore.properties keystore.properties
version.properties version.properties
.vscode/

View File

@@ -3,6 +3,7 @@ plugins {
id 'kotlin-android' id 'kotlin-android'
id 'com.google.dagger.hilt.android' id 'com.google.dagger.hilt.android'
id 'kotlin-kapt' id 'kotlin-kapt'
id 'com.google.devtools.ksp'
} }
// Create a variable called keystorePropertiesFile, and initialize it to your // Create a variable called keystorePropertiesFile, and initialize it to your
@@ -67,7 +68,7 @@ android {
} }
composeOptions { composeOptions {
kotlinCompilerExtensionVersion = "1.4.8" kotlinCompilerExtensionVersion = "1.5.14"
} }
compileOptions { compileOptions {
@@ -88,44 +89,44 @@ android {
dependencies { dependencies {
implementation fileTree(dir: "libs", include: ["*.jar"]) implementation fileTree(dir: "libs", include: ["*.jar"])
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
implementation 'androidx.core:core-ktx:1.10.1' implementation 'androidx.core:core-ktx:1.13.1'
implementation 'androidx.appcompat:appcompat:1.6.1' implementation 'androidx.appcompat:appcompat:1.7.0'
implementation "androidx.compose.material3:material3:1.1.1" implementation "androidx.compose.material3:material3:1.2.1"
implementation 'com.google.android.play:core-ktx:1.8.1' implementation 'com.google.android.play:review:2.0.1'
implementation 'com.google.android.play:core-ktx:1.8.1' implementation 'com.google.android.play:review-ktx:2.0.1'
implementation 'com.google.code.gson:gson:2.9.0' implementation 'com.google.code.gson:gson:2.10.1'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4' implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
implementation 'androidx.navigation:navigation-fragment-ktx:2.7.1' implementation 'androidx.navigation:navigation-fragment-ktx:2.7.7'
implementation 'androidx.navigation:navigation-ui-ktx:2.7.1' implementation 'androidx.navigation:navigation-ui-ktx:2.7.7'
implementation 'androidx.legacy:legacy-support-v4:1.0.0' implementation 'androidx.legacy:legacy-support-v4:1.0.0'
implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.6.1' implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.8.4'
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.1' implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.4'
implementation 'androidx.fragment:fragment-ktx:1.6.1' implementation 'androidx.fragment:fragment-ktx:1.8.2'
implementation 'androidx.preference:preference-ktx:1.2.1' implementation 'androidx.preference:preference-ktx:1.2.1'
implementation 'androidx.recyclerview:recyclerview:1.3.1' implementation 'androidx.recyclerview:recyclerview:1.3.2'
implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.6.1' implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.8.4'
implementation 'androidx.compose.material:material-icons-extended:1.5.0' implementation 'androidx.compose.material:material-icons-extended:1.6.8'
implementation "com.google.accompanist:accompanist-systemuicontroller:0.27.0" implementation "com.google.accompanist:accompanist-systemuicontroller:0.27.0"
implementation 'androidx.activity:activity-compose:1.7.2' implementation 'androidx.activity:activity-compose:1.9.1'
implementation "androidx.compose.ui:ui:1.5.0" implementation "androidx.compose.ui:ui:1.6.8"
implementation "androidx.compose.ui:ui-tooling-preview:1.5.0" implementation "androidx.compose.ui:ui-tooling-preview:1.6.8"
implementation "androidx.compose.runtime:runtime-livedata:1.5.0" implementation "androidx.compose.runtime:runtime-livedata:1.6.8"
implementation "androidx.navigation:navigation-compose:2.7.1" implementation "androidx.navigation:navigation-compose:2.7.7"
implementation "androidx.lifecycle:lifecycle-viewmodel-compose:2.6.1" implementation "androidx.lifecycle:lifecycle-viewmodel-compose:2.8.4"
testImplementation 'junit:junit:4.13.2' testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.5' androidTestImplementation 'androidx.test.ext:junit:1.2.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1' androidTestImplementation 'androidx.test.espresso:espresso-core:3.6.1'
implementation "com.google.dagger:hilt-android:2.44" implementation "com.google.dagger:hilt-android:2.51.1"
androidTestImplementation "androidx.compose.ui:ui-test-junit4:1.5.0" androidTestImplementation "androidx.compose.ui:ui-test-junit4:1.6.8"
debugImplementation "androidx.compose.ui:ui-tooling:1.5.0" debugImplementation "androidx.compose.ui:ui-tooling:1.6.8"
debugImplementation "androidx.compose.ui:ui-test-manifest:1.5.0" debugImplementation "androidx.compose.ui:ui-test-manifest:1.6.8"
kapt "com.google.dagger:hilt-compiler:2.44" kapt "com.google.dagger:hilt-compiler:2.51.1"
implementation "androidx.room:room-runtime:2.5.2" annotationProcessor "androidx.room:room-compiler:2.6.1"
annotationProcessor "androidx.room:room-compiler:2.5.2" implementation "androidx.room:room-runtime:2.6.1"
kapt "androidx.room:room-compiler:2.5.2" ksp "androidx.room:room-compiler:2.6.1"
implementation "androidx.room:room-ktx:2.5.2" implementation "androidx.room:room-ktx:2.6.1"
implementation "androidx.multidex:multidex:2.0.1" implementation "androidx.multidex:multidex:2.0.1"
api "androidx.navigation:navigation-fragment-ktx:2.7.1" api "androidx.navigation:navigation-fragment-ktx:2.7.7"
} }
// Allow references to generated code // Allow references to generated code

View File

@@ -8,14 +8,14 @@ import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.app.AppCompatDelegate import androidx.appcompat.app.AppCompatDelegate
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.outlined.List
import androidx.compose.material.icons.automirrored.outlined.Redo
import androidx.compose.material.icons.automirrored.outlined.Undo
import androidx.compose.material.icons.outlined.Calculate import androidx.compose.material.icons.outlined.Calculate
import androidx.compose.material.icons.outlined.Info import androidx.compose.material.icons.outlined.Info
import androidx.compose.material.icons.outlined.Keyboard import androidx.compose.material.icons.outlined.Keyboard
import androidx.compose.material.icons.outlined.List
import androidx.compose.material.icons.outlined.MoreVert import androidx.compose.material.icons.outlined.MoreVert
import androidx.compose.material.icons.outlined.Redo
import androidx.compose.material.icons.outlined.Settings import androidx.compose.material.icons.outlined.Settings
import androidx.compose.material.icons.outlined.Undo
import androidx.compose.material3.DrawerState import androidx.compose.material3.DrawerState
import androidx.compose.material3.DrawerValue import androidx.compose.material3.DrawerValue
import androidx.compose.material3.FloatingActionButton import androidx.compose.material3.FloatingActionButton
@@ -166,7 +166,11 @@ class MainActivity : AppCompatActivity() {
Icons.Outlined.Calculate, Icons.Outlined.Calculate,
stringResource(R.string.menu_counter) stringResource(R.string.menu_counter)
), ),
DrawerItem(Route.HISTORY, Icons.Outlined.List, stringResource(R.string.menu_history)), DrawerItem(
Route.HISTORY,
Icons.AutoMirrored.Outlined.List,
stringResource(R.string.menu_history)
),
DrawerItem( DrawerItem(
Route.SETTINGS, Route.SETTINGS,
Icons.Outlined.Settings, Icons.Outlined.Settings,
@@ -217,7 +221,7 @@ class MainActivity : AppCompatActivity() {
) { ) {
var topBarState by remember { mutableStateOf(TopBarState()) } var topBarState by remember { mutableStateOf(TopBarState()) }
var snackbarHostState by remember { mutableStateOf(SnackbarHostState()) } val snackbarHostState by remember { mutableStateOf(SnackbarHostState()) }
Scaffold( Scaffold(
snackbarHost = { SnackbarHost(snackbarHostState) }, snackbarHost = { SnackbarHost(snackbarHostState) },
@@ -236,7 +240,7 @@ class MainActivity : AppCompatActivity() {
startDestination = Route.COUNTER.name, startDestination = Route.COUNTER.name,
modifier = Modifier.padding(paddings) modifier = Modifier.padding(paddings)
) { ) {
this.composable(Route.COUNTER.name.toString()) { this.composable(Route.COUNTER.name) {
var expanded by remember { mutableStateOf(false) } var expanded by remember { mutableStateOf(false) }
@@ -244,11 +248,11 @@ class MainActivity : AppCompatActivity() {
title = stringResource(R.string.app_name), title = stringResource(R.string.app_name),
actions = (listOf( actions = (listOf(
TopBarAction( TopBarAction(
Icons.Outlined.Undo, Icons.AutoMirrored.Outlined.Undo,
mainViewModel.isUndoActionActive, mainViewModel.isUndoActionActive,
{ mainViewModel.undoLastRound() }), { mainViewModel.undoLastRound() }),
TopBarAction( TopBarAction(
Icons.Outlined.Redo, Icons.AutoMirrored.Outlined.Redo,
mainViewModel.isRedoActionActive, mainViewModel.isRedoActionActive,
{ mainViewModel.redoLastRound() }), { mainViewModel.redoLastRound() }),
TopBarAction( TopBarAction(

View File

@@ -1,6 +1,8 @@
package me.zobrist.tichucounter.data package me.zobrist.tichucounter.data
import androidx.room.* import androidx.room.Dao
import androidx.room.Query
import androidx.room.Transaction
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import me.zobrist.tichucounter.data.entity.Game import me.zobrist.tichucounter.data.entity.Game

View File

@@ -1,6 +1,7 @@
package me.zobrist.tichucounter.data package me.zobrist.tichucounter.data
import androidx.room.* import androidx.room.Dao
import androidx.room.Query
import me.zobrist.tichucounter.data.entity.Round import me.zobrist.tichucounter.data.entity.Round
@Dao @Dao

View File

@@ -47,7 +47,6 @@ class ReviewService @Inject constructor(@ActivityContext private val appContext:
val reviewInfo = task.result val reviewInfo = task.result
manager.launchReviewFlow(appContext as Activity, reviewInfo) manager.launchReviewFlow(appContext as Activity, reviewInfo)
} else {
} }
} }
} }

View File

@@ -22,11 +22,12 @@ class GameRepository @Inject constructor(
private val roundDao: RoundDao private val roundDao: RoundDao
) { ) {
var activeGame: Game = Game(true, "TeamA", "TeamB", Date(), Date()) private var activeGame: Game = Game(true, "TeamA", "TeamB", Date(), Date())
private set
private val newGameFlow = MutableStateFlow(Game()) private val newGameFlow = MutableStateFlow(Game())
private var deletedGame: GameWithScores? = null
init { init {
CoroutineScope(Dispatchers.IO).launch { CoroutineScope(Dispatchers.IO).launch {
gameDao.getActiveAsFlow().collect { gameDao.getActiveAsFlow().collect {
@@ -104,14 +105,33 @@ class GameRepository @Inject constructor(
withContext(Dispatchers.IO) { withContext(Dispatchers.IO) {
try { try {
val game = gameDao.getGameById(uid) val game = gameDao.getGameById(uid)
gameDao.delete(game)
val rounds = roundDao.getAllForGame(game.uid) val rounds = roundDao.getAllForGame(game.uid)
deletedGame = GameWithScores(game, rounds)
gameDao.delete(game)
roundDao.delete(rounds) roundDao.delete(rounds)
} catch (_: NullPointerException) { } catch (_: NullPointerException) {
} }
} }
} }
suspend fun restoreLastDeletedGame() {
if (deletedGame == null) {
return
}
val revert = deletedGame!!
deletedGame = null
withContext(Dispatchers.IO) {
gameDao.insert(revert.game)
revert.rounds.forEach {
roundDao.insert(it)
}
}
}
suspend fun deleteAllInactive() { suspend fun deleteAllInactive() {
withContext(Dispatchers.IO) { withContext(Dispatchers.IO) {
try { try {

View File

@@ -11,10 +11,10 @@ import androidx.compose.material3.TextField
import androidx.compose.material3.TextFieldColors import androidx.compose.material3.TextFieldColors
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.onFocusChanged import androidx.compose.ui.focus.onFocusChanged
import androidx.compose.ui.input.key.Key import androidx.compose.ui.input.key.Key
@@ -26,7 +26,7 @@ import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.input.ImeAction import androidx.compose.ui.text.input.ImeAction
@OptIn(ExperimentalMaterial3Api::class, ExperimentalComposeUiApi::class) @OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
fun TypeaheadTextField( fun TypeaheadTextField(
value: String, value: String,
@@ -46,7 +46,7 @@ fun TypeaheadTextField(
onExpandedChange = {} onExpandedChange = {}
) { ) {
var dropDownWidth by remember { mutableStateOf(0) } var dropDownWidth by remember { mutableIntStateOf(0) }
TextField( TextField(
value = value, value = value,

View File

@@ -12,7 +12,7 @@ import androidx.compose.material3.Text
import androidx.compose.material3.TextButton import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
@@ -28,7 +28,7 @@ import me.zobrist.tichucounter.ui.AppTheme
@Composable @Composable
fun Counter(viewModel: ICounterViewModel = PreviewViewModel()) { fun Counter(viewModel: ICounterViewModel = PreviewViewModel()) {
var orientation by remember { mutableStateOf(Configuration.ORIENTATION_PORTRAIT) } var orientation by remember { mutableIntStateOf(Configuration.ORIENTATION_PORTRAIT) }
orientation = LocalConfiguration.current.orientation orientation = LocalConfiguration.current.orientation
if (viewModel.showVictoryDialog) { if (viewModel.showVictoryDialog) {
@@ -122,7 +122,7 @@ fun CounterViewPreview() {
} }
} }
@Preview() @Preview
@Composable @Composable
fun GameVictoryDialog( fun GameVictoryDialog(
pointsA: Int = 2000, pointsA: Int = 2000,

View File

@@ -19,12 +19,12 @@ import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width import androidx.compose.foundation.layout.width
import androidx.compose.foundation.layout.wrapContentWidth import androidx.compose.foundation.layout.wrapContentWidth
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.Backspace import androidx.compose.material.icons.automirrored.outlined.Backspace
import androidx.compose.material.icons.outlined.Check import androidx.compose.material.icons.outlined.Check
import androidx.compose.material.icons.outlined.KeyboardHide import androidx.compose.material.icons.outlined.KeyboardHide
import androidx.compose.material.icons.outlined.SwapHoriz import androidx.compose.material.icons.outlined.SwapHoriz
import androidx.compose.material3.Divider
import androidx.compose.material3.ElevatedButton import androidx.compose.material3.ElevatedButton
import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton import androidx.compose.material3.IconButton
import androidx.compose.material3.LocalTextStyle import androidx.compose.material3.LocalTextStyle
@@ -198,7 +198,7 @@ fun KeyboardView(
deleteButtonPressedState(deletePressed) deleteButtonPressedState(deletePressed)
KeyboardIconButton( KeyboardIconButton(
icon = Icons.Outlined.Backspace, icon = Icons.AutoMirrored.Outlined.Backspace,
interactionSource = interactionSource interactionSource = interactionSource
) {} ) {}
} }
@@ -330,7 +330,7 @@ fun CenteredTextField(
Row { Row {
Text(text = value, color = cursorColor.copy(alpha = 0f)) Text(text = value, color = cursorColor.copy(alpha = 0f))
Divider( HorizontalDivider(
modifier = Modifier modifier = Modifier
.padding(start = 3.dp, top = 15.dp, bottom = 15.dp) .padding(start = 3.dp, top = 15.dp, bottom = 15.dp)
.width(1.dp) .width(1.dp)

View File

@@ -12,6 +12,7 @@ import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.LazyListState import androidx.compose.foundation.lazy.LazyListState
@@ -25,18 +26,17 @@ import androidx.compose.material3.AlertDialog
import androidx.compose.material3.Badge import androidx.compose.material3.Badge
import androidx.compose.material3.Button import androidx.compose.material3.Button
import androidx.compose.material3.Card import androidx.compose.material3.Card
import androidx.compose.material3.DismissDirection
import androidx.compose.material3.DismissValue
import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.SnackbarDuration import androidx.compose.material3.SnackbarDuration
import androidx.compose.material3.SnackbarHostState import androidx.compose.material3.SnackbarHostState
import androidx.compose.material3.SnackbarResult import androidx.compose.material3.SnackbarResult
import androidx.compose.material3.SwipeToDismiss import androidx.compose.material3.SwipeToDismissBox
import androidx.compose.material3.SwipeToDismissBoxValue
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.material3.TextButton import androidx.compose.material3.TextButton
import androidx.compose.material3.rememberDismissState import androidx.compose.material3.rememberSwipeToDismissBoxState
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
@@ -95,6 +95,7 @@ fun HistoryList(
viewModel.activateGame(it) viewModel.activateGame(it)
lazyListState.animateScrollToItem(0) lazyListState.animateScrollToItem(0)
snackbarHostState.currentSnackbarData?.dismiss()
val result = snackbarHostState.showSnackbar( val result = snackbarHostState.showSnackbar(
message = activatedMessage, message = activatedMessage,
actionLabel = activatedActionLabel, actionLabel = activatedActionLabel,
@@ -108,7 +109,9 @@ fun HistoryList(
}, },
onDeleteClicked = { onDeleteClicked = {
scope.launch { scope.launch {
viewModel.markToDelete(it) viewModel.deleteGame(it)
snackbarHostState.currentSnackbarData?.dismiss()
val result = snackbarHostState.showSnackbar( val result = snackbarHostState.showSnackbar(
message = deletedMessage, message = deletedMessage,
actionLabel = deletedActionLabel, actionLabel = deletedActionLabel,
@@ -118,7 +121,7 @@ fun HistoryList(
if (result == SnackbarResult.Dismissed) { if (result == SnackbarResult.Dismissed) {
viewModel.deleteGame(it) viewModel.deleteGame(it)
} else { } else {
viewModel.unmarkToDelete(it) viewModel.restoreLastDeletedGame()
} }
} }
}, },
@@ -210,89 +213,113 @@ fun DismissibleHistoryListItem(
val density = LocalDensity.current val density = LocalDensity.current
val dismissState = val dismissState =
rememberDismissState(positionalThreshold = { with(density) { 100.dp.toPx() } }, rememberSwipeToDismissBoxState(positionalThreshold = { with(density) { 100.dp.toPx() } },
confirmValueChange = { confirmValueChange = {
if (it == DismissValue.DismissedToStart) { if (it == SwipeToDismissBoxValue.EndToStart) {
onDeleteClicked(game.game.uid) onDeleteClicked(game.game.uid)
} }
if (it == DismissValue.DismissedToEnd) { if (it == SwipeToDismissBoxValue.StartToEnd) {
onOpenClicked(game.game.uid) onOpenClicked(game.game.uid)
} }
true true
}) })
val directions = if (game.game.active) { SwipeToDismissBox(
setOf()
} else {
setOf(DismissDirection.EndToStart, DismissDirection.StartToEnd)
}
SwipeToDismiss(
modifier = modifier, modifier = modifier,
state = dismissState, state = dismissState,
directions = directions, enableDismissFromEndToStart = true,
background = { enableDismissFromStartToEnd = true,
val direction = dismissState.dismissDirection ?: return@SwipeToDismiss backgroundContent = {
val color by animateColorAsState( ItemBackground(dismissState.targetValue)
when (dismissState.targetValue) { }, content = {
DismissValue.DismissedToStart -> MaterialTheme.colorScheme.error HistoryListItem(game = game, modifier = Modifier.padding(2.dp))
DismissValue.DismissedToEnd -> MaterialTheme.colorScheme.primary })
}
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun ItemBackground(
dismissBoxValue: SwipeToDismissBoxValue
) {
val backgroundColor by animateColorAsState(
when (dismissBoxValue) {
SwipeToDismissBoxValue.EndToStart -> MaterialTheme.colorScheme.error
SwipeToDismissBoxValue.StartToEnd -> MaterialTheme.colorScheme.primary
else -> MaterialTheme.colorScheme.background else -> MaterialTheme.colorScheme.background
}, label = "" }, label = ""
) )
val textColor by animateColorAsState( val textColor by animateColorAsState(
when (dismissState.targetValue) { when (dismissBoxValue) {
DismissValue.DismissedToStart -> MaterialTheme.colorScheme.onError SwipeToDismissBoxValue.EndToStart -> MaterialTheme.colorScheme.onError
DismissValue.DismissedToEnd -> MaterialTheme.colorScheme.onPrimary SwipeToDismissBoxValue.StartToEnd -> MaterialTheme.colorScheme.onPrimary
else -> MaterialTheme.colorScheme.onBackground else -> MaterialTheme.colorScheme.onBackground
}, label = "" }, label = ""
) )
val alignment = when (direction) {
DismissDirection.StartToEnd -> Alignment.CenterStart
DismissDirection.EndToStart -> Alignment.CenterEnd
}
val icon = when (direction) {
DismissDirection.StartToEnd -> Icons.Outlined.RestartAlt
DismissDirection.EndToStart -> Icons.Outlined.Delete
}
val text = when (direction) {
DismissDirection.StartToEnd -> stringResource(id = R.string.continue_play)
DismissDirection.EndToStart -> stringResource(id = R.string.delete)
}
val scale by animateFloatAsState( val scale by animateFloatAsState(
if (dismissState.targetValue == DismissValue.Default) 0.75f else 1f, label = "" if (dismissBoxValue == SwipeToDismissBoxValue.Settled) 0.75f else 1f, label = ""
) )
Box( Box(
Modifier Modifier
.fillMaxSize() .fillMaxSize()
.padding(top = 2.dp, bottom = 2.dp) .padding(top = 2.dp, bottom = 2.dp)
.background(color) .background(backgroundColor)
.padding(horizontal = 10.dp), .padding(horizontal = 10.dp),
contentAlignment = alignment
) { ) {
Column( Column(
verticalArrangement = Arrangement.Center, verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier.align(Alignment.CenterStart)
) { ) {
Icon( Icon(
icon, Icons.Outlined.RestartAlt,
contentDescription = null, contentDescription = null,
tint = textColor,
modifier = Modifier.scale(scale), modifier = Modifier.scale(scale),
tint = textColor
) )
Text(text = text, color = textColor) Text(text = stringResource(id = R.string.continue_play), color = textColor)
}
Column(
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier.align(Alignment.CenterEnd)
) {
Icon(
Icons.Outlined.Delete,
contentDescription = null,
tint = textColor,
modifier = Modifier.scale(scale),
)
Text(text = stringResource(id = R.string.delete), color = textColor)
} }
} }
}, dismissContent = {
HistoryListItem(game = game, modifier = Modifier.padding(2.dp))
})
} }
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@Preview
@Composable
private fun BackgroundPreview() {
Column {
Box(modifier = Modifier.height(60.dp))
{
ItemBackground(SwipeToDismissBoxValue.Settled)
}
Box(modifier = Modifier.height(60.dp))
{
ItemBackground(SwipeToDismissBoxValue.EndToStart)
}
Box(modifier = Modifier.height(60.dp))
{
ItemBackground(SwipeToDismissBoxValue.StartToEnd)
}
}
}
@Composable @Composable
fun HistoryListItem( fun HistoryListItem(
game: GameWithScores, modifier: Modifier = Modifier game: GameWithScores, modifier: Modifier = Modifier

View File

@@ -33,20 +33,18 @@ class HistoryViewModel @Inject constructor(
} }
} }
fun markToDelete(gameId: Long) {
gameAndHistory = fullList.filter { it.game.uid != gameId }
}
fun unmarkToDelete(gameId: Long) {
gameAndHistory = fullList
}
fun deleteGame(gameId: Long) { fun deleteGame(gameId: Long) {
viewModelScope.launch { viewModelScope.launch {
gameRepository.deleteGame(gameId) gameRepository.deleteGame(gameId)
} }
} }
fun restoreLastDeletedGame() {
viewModelScope.launch {
gameRepository.restoreLastDeletedGame()
}
}
fun activateGame(gameId: Long) { fun activateGame(gameId: Long) {
viewModelScope.launch { viewModelScope.launch {
gameRepository.setActive(gameId) gameRepository.setActive(gameId)

View File

@@ -3,10 +3,10 @@ package me.zobrist.tichucounter.ui.layout
import android.content.res.Configuration import android.content.res.Configuration
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.outlined.List
import androidx.compose.material.icons.outlined.Calculate import androidx.compose.material.icons.outlined.Calculate
import androidx.compose.material.icons.outlined.List
import androidx.compose.material.icons.outlined.Settings import androidx.compose.material.icons.outlined.Settings
import androidx.compose.material3.Divider import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.ModalDrawerSheet import androidx.compose.material3.ModalDrawerSheet
@@ -38,7 +38,7 @@ fun DrawerContent(
text = stringResource(R.string.app_name), text = stringResource(R.string.app_name),
style = MaterialTheme.typography.headlineSmall style = MaterialTheme.typography.headlineSmall
) )
Divider(modifier = Modifier.padding(10.dp)) HorizontalDivider(modifier = Modifier.padding(10.dp))
drawerItems.forEach { screen -> drawerItems.forEach { screen ->
NavigationDrawerItem( NavigationDrawerItem(
@@ -58,7 +58,7 @@ fun DrawerContent(
fun DrawerContentPreview() { fun DrawerContentPreview() {
val counter = DrawerItem(Route.COUNTER, Icons.Outlined.Calculate, "Counter") val counter = DrawerItem(Route.COUNTER, Icons.Outlined.Calculate, "Counter")
val history = DrawerItem(Route.HISTORY, Icons.Outlined.List, "History") val history = DrawerItem(Route.HISTORY, Icons.AutoMirrored.Outlined.List, "History")
val settings = DrawerItem(Route.SETTINGS, Icons.Outlined.Settings, "Settings") val settings = DrawerItem(Route.SETTINGS, Icons.Outlined.Settings, "Settings")
AppTheme { AppTheme {
Surface { Surface {

View File

@@ -1,6 +1,10 @@
package me.zobrist.tichucounter.ui.layout package me.zobrist.tichucounter.ui.layout
import androidx.compose.material3.* import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.text.style.TextOverflow

View File

@@ -1,12 +1,12 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules. // Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript { buildscript {
ext.kotlin_version = "1.8.22" ext.kotlin_version = "1.9.24"
repositories { repositories {
google() google()
mavenCentral() mavenCentral()
} }
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:8.1.1' classpath 'com.android.tools.build:gradle:8.5.2'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
// NOTE: Do not place your application dependencies here; they belong // NOTE: Do not place your application dependencies here; they belong
@@ -15,8 +15,9 @@ buildscript {
} }
plugins { plugins {
id 'com.google.dagger.hilt.android' version '2.44' apply false id 'com.google.dagger.hilt.android' version '2.51.1' apply false
id 'org.jetbrains.kotlin.android' version '1.7.20' apply false id 'org.jetbrains.kotlin.android' version '1.7.20' apply false
id 'com.google.devtools.ksp' version '1.9.24-1.0.20' apply false
} }
allprojects { allprojects {
@@ -25,7 +26,3 @@ allprojects {
mavenCentral() mavenCentral()
} }
} }
tasks.register('clean', Delete) {
delete rootProject.buildDir
}

View File

@@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.0-all.zip distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-all.zip