15 Commits

Author SHA1 Message Date
d1b4ab1e8c WIP: Add setting for counter mode.
All checks were successful
Build Android / build (push) Successful in 7m57s
2023-07-01 11:37:10 +02:00
ff5495249f Merge pull request 'feature/act_runner' (#43) from feature/act_runner into develop
All checks were successful
Build Android / build (push) Successful in 7m41s
Reviewed-on: #43
2023-07-01 11:28:47 +02:00
217370079d Publish tagged builds.
All checks were successful
Build Android / build (push) Successful in 7m58s
Build Android / build (pull_request) Has been cancelled
2023-06-30 16:21:13 +02:00
add100146d Notify on slack.
All checks were successful
Build Android / build (push) Successful in 8m40s
2023-06-30 12:06:24 +02:00
ceebe92f8b Deploy latest to nextcloud.
All checks were successful
Build Android / build (push) Successful in 7m46s
2023-06-30 10:47:19 +02:00
4f87321e2c Use android build box iamge.
All checks were successful
Build Android / build (push) Successful in 7m25s
2023-06-30 10:33:02 +02:00
81c540c2a5 Add signing and version code.
Some checks failed
Build Android / build (push) Failing after 10m19s
2023-06-25 20:02:44 +02:00
a45043424e Use act runner
All checks were successful
Build Android / build (push) Has been cancelled
2023-06-25 19:48:31 +02:00
18326e952f Merge pull request 'release/2.2' (#40) from release/2.2 into develop
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #40
2023-06-16 11:11:33 +02:00
a099659b2c Try to make DRONE_TAG work.
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2023-06-02 22:16:40 +02:00
61745c95a4 Fix tagged upload url
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/tag Build is passing
2023-06-02 16:58:36 +02:00
164cf6900f fix tagged upload link
All checks were successful
continuous-integration/drone/push Build is passing
2023-06-02 15:03:13 +02:00
89ab0afaf5 upload to nextcloud instead of seafile
Some checks failed
continuous-integration/drone/push Build is passing
continuous-integration/drone/tag Build is failing
fix nextcloud upload
2023-06-02 14:40:23 +02:00
9d8de2dd3c Update dependencies. Code clean up.
Some checks failed
continuous-integration/drone/push Build is failing
continuous-integration/drone/tag Build is passing
2023-05-25 18:09:16 +02:00
fcb8c12454 [#39] Case insensitive team name suggestions.
Some checks failed
continuous-integration/drone Build is failing
closes #39
2023-05-25 17:37:30 +02:00
29 changed files with 391 additions and 267 deletions

View File

@@ -1,75 +0,0 @@
---
kind: pipeline
type: docker
name: Android
steps:
- name: prepare signing
image: busybox
environment:
STOREPASSWORD:
from_secret: StorePassword
KEYPASSWORD:
from_secret: KeyPassword
commands:
- touch keystore.properties
- echo "storePassword=$STOREPASSWORD" >> keystore.properties
- echo "keyPassword=$KEYPASSWORD" >> keystore.properties
- echo "keyAlias=key0" >> keystore.properties
- echo "storeFile=../AndroidKey" >> keystore.properties
- name: generate versionCode
image: busybox
commands:
- touch version.properties
- let timestamp=$(date +%s)/10
- echo "versionCode=$timestamp" >> version.properties
- name: build
image: mingc/android-build-box
commands:
- ./gradlew test
- ./gradlew assembleRelease
- ./gradlew bundleRelease
- name: deploy latest build
image: curlimages/curl
environment:
SEAFILE_API_KEY:
from_secret: SeafileApiKey
APK_FILE: app/build/outputs/apk/release/app-release.apk
BUNDLE_FILE: app/build/outputs/bundle/release/app-release.aab
SEAFILE_REPO: 6debeef9-121e-46ba-acc7-81e109fdcbdd
commands:
- 'UPLOAD_URL=$(curl -H "Authorization: Token $SEAFILE_API_KEY" https://seafile.zobrist.me/api2/repos/$SEAFILE_REPO/upload-link/ | tr -d "\"")'
- echo $UPLOAD_URL
- 'curl -H "Authorization: Token $SEAFILE_API_KEY" -F file=@$APK_FILE -F parent_dir=/ -F relative_path=latest/ -F replace=1 "$UPLOAD_URL"'
- 'curl -H "Authorization: Token $SEAFILE_API_KEY" -F file=@$BUNDLE_FILE -F parent_dir=/ -F relative_path=latest/ -F replace=1 "$UPLOAD_URL"'
- name: deploy tagged build
image: curlimages/curl
environment:
SEAFILE_API_KEY:
from_secret: SeafileApiKey
APK_FILE: app/build/outputs/apk/release/app-release.apk
BUNDLE_FILE: app/build/outputs/bundle/release/app-release.aab
SEAFILE_REPO: 6debeef9-121e-46ba-acc7-81e109fdcbdd
commands:
- 'UPLOAD_URL=$(curl -H "Authorization: Token $SEAFILE_API_KEY" https://seafile.zobrist.me/api2/repos/$SEAFILE_REPO/upload-link/ | tr -d "\"")'
- 'curl -H "Authorization: Token $SEAFILE_API_KEY" -F file=@$APK_FILE -F parent_dir=/ -F relative_path=tagged/$DRONE_TAG/ -F replace=1 "$UPLOAD_URL"'
- 'curl -H "Authorization: Token $SEAFILE_API_KEY" -F file=@$BUNDLE_FILE -F parent_dir=/ -F relative_path=tagged/$DRONE_TAG/ -F replace=1 "$UPLOAD_URL"'
- 'curl -d "operation=rename&newname=app-release$DRONE_TAG.apk" -H "Authorization: Token $SEAFILE_API_KEY" https://seafile.zobrist.me/api2/repos/$SEAFILE_REPO/file/?p=/tagged/$DRONE_TAG/app-release.apk'
- 'curl -d "operation=rename&newname=app-release$DRONE_TAG.aab" -H "Authorization: Token $SEAFILE_API_KEY" https://seafile.zobrist.me/api2/repos/$SEAFILE_REPO/file/?p=/tagged/$DRONE_TAG/app-release.aab'
when:
event:
- tag
- name: slack notification
image: plugins/slack
settings:
webhook:
from_secret: SlackWebhook
when:
status:
- failure
- success

View File

@@ -0,0 +1,48 @@
name: Build Android
on: [pull_request, push]
jobs:
build:
runs-on: ubuntu-latest-android
steps:
- name: Checkout the code
uses: actions/checkout@v2
- name: Prepare signing
run: |
touch keystore.properties
echo "storePassword=${{ secrets.STOREPASSWORD }}" >> keystore.properties
echo "keyPassword=${{ secrets.KEYPASSWORD }}" >> keystore.properties
echo "keyAlias=key0" >> keystore.properties
echo "storeFile=../AndroidKey" >> keystore.properties
- name: Generate versionCode
run: |
touch version.properties
let timestamp=$(date +%s)/10
echo "versionCode=$timestamp" >> version.properties
- name: Test the app
run: ./gradlew test
- name: Build apk
run: ./gradlew assembleRelease
- name: Build abb
run: ./gradlew bundleRelease
- name: Deploy latest 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/latest/app-release.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/latest/app-release.aab"
- 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
if: always()
with:
status: ${{ job.status }} # required
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }} # required

View File

@@ -89,9 +89,9 @@ 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.0' implementation 'androidx.core:core-ktx:1.10.1'
implementation 'androidx.appcompat:appcompat:1.6.0-rc01' implementation 'androidx.appcompat:appcompat:1.6.1'
implementation "androidx.compose.material3:material3:1.0.1" implementation "androidx.compose.material3:material3:1.1.0"
implementation 'com.google.android.play:core-ktx:1.8.1' implementation 'com.google.android.play:core-ktx:1.8.1'
implementation 'com.google.android.play:core-ktx:1.8.1' implementation 'com.google.android.play:core-ktx:1.8.1'
implementation 'com.google.code.gson:gson:2.9.0' implementation 'com.google.code.gson:gson:2.9.0'
@@ -107,7 +107,7 @@ dependencies {
implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.6.1' implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.6.1'
implementation 'androidx.compose.material:material-icons-extended:1.4.3' implementation 'androidx.compose.material:material-icons-extended:1.4.3'
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.1' implementation 'androidx.activity:activity-compose:1.7.2'
implementation "androidx.compose.ui:ui:1.4.3" implementation "androidx.compose.ui:ui:1.4.3"
implementation "androidx.compose.ui:ui-tooling-preview:1.4.3" implementation "androidx.compose.ui:ui-tooling-preview:1.4.3"
implementation "androidx.compose.runtime:runtime-livedata:1.4.3" implementation "androidx.compose.runtime:runtime-livedata:1.4.3"

View File

@@ -12,9 +12,7 @@ import androidx.compose.material.icons.filled.*
import androidx.compose.material.icons.outlined.* import androidx.compose.material.icons.outlined.*
import androidx.compose.material3.* import androidx.compose.material3.*
import androidx.compose.runtime.* import androidx.compose.runtime.*
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalSoftwareKeyboardController
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.navigation.NavHostController import androidx.navigation.NavHostController
import androidx.navigation.compose.NavHost import androidx.navigation.compose.NavHost
@@ -39,7 +37,7 @@ import me.zobrist.tichucounter.ui.settings.SettingsViewModel
import javax.inject.Inject import javax.inject.Inject
@AndroidEntryPoint @AndroidEntryPoint
class MainActivity : AppCompatActivity(), ISettingsChangeListener { class MainActivity : AppCompatActivity(), ISystemSettingsChangeListener {
@Inject @Inject
lateinit var settingsAdapter: SettingsAdapter lateinit var settingsAdapter: SettingsAdapter
@@ -90,7 +88,6 @@ class MainActivity : AppCompatActivity(), ISettingsChangeListener {
} }
} }
@OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
private fun NavigationDrawer() { private fun NavigationDrawer() {
val drawerState = rememberDrawerState(DrawerValue.Closed) val drawerState = rememberDrawerState(DrawerValue.Closed)
@@ -144,7 +141,6 @@ class MainActivity : AppCompatActivity(), ISettingsChangeListener {
} }
} }
@OptIn(ExperimentalMaterial3Api::class, ExperimentalComposeUiApi::class)
@Composable @Composable
fun MyScaffoldLayout( fun MyScaffoldLayout(
drawerState: DrawerState, drawerState: DrawerState,
@@ -207,10 +203,12 @@ class MainActivity : AppCompatActivity(), ISettingsChangeListener {
}, },
)) ))
) { scope.launch { ) {
scope.launch {
currentFocus?.clearFocus() currentFocus?.clearFocus()
drawerState.open() drawerState.open()
} } }
}
Counter(counterViewModel) Counter(counterViewModel)
} }

View File

@@ -2,7 +2,7 @@ package me.zobrist.tichucounter.data
import androidx.room.ProvidedTypeConverter import androidx.room.ProvidedTypeConverter
import androidx.room.TypeConverter import androidx.room.TypeConverter
import java.util.* import java.util.Date
@ProvidedTypeConverter @ProvidedTypeConverter
object DateConverter { object DateConverter {

View File

@@ -2,7 +2,7 @@ package me.zobrist.tichucounter.data.entity
import androidx.room.Entity import androidx.room.Entity
import androidx.room.PrimaryKey import androidx.room.PrimaryKey
import java.util.* import java.util.Date
@Entity @Entity
data class Game( data class Game(

View File

@@ -1,7 +1,11 @@
package me.zobrist.tichucounter.domain package me.zobrist.tichucounter.domain
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.navigation.* import androidx.navigation.NamedNavArgument
import androidx.navigation.NavBackStackEntry
import androidx.navigation.NavController
import androidx.navigation.NavDeepLink
import androidx.navigation.NavGraphBuilder
import androidx.navigation.compose.composable import androidx.navigation.compose.composable
fun NavController.navigate(route: Route) { fun NavController.navigate(route: Route) {

View File

@@ -16,17 +16,26 @@ enum class Language(val value: LocaleListCompat) {
enum class KeepScreenOn(val value: Boolean) { ON(true), OFF(false) } enum class KeepScreenOn(val value: Boolean) { ON(true), OFF(false) }
interface ISettingsChangeListener { enum class CounterListView { BY_ROUND, CONTINUOUS }
interface ISystemSettingsChangeListener {
fun onLanguageChanged(language: Language) fun onLanguageChanged(language: Language)
fun onThemeChanged(theme: Theme) fun onThemeChanged(theme: Theme)
fun onScreenOnChanged(keepOn: KeepScreenOn) fun onScreenOnChanged(keepOn: KeepScreenOn)
} }
interface IDisplaySettingsChangeListener {
fun onCounterListViewChanged(listView: CounterListView)
}
@Singleton @Singleton
class SettingsAdapter @Inject constructor(@ApplicationContext private val context: Context) { class SettingsAdapter @Inject constructor(@ApplicationContext private val context: Context) {
private val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context) private val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context)
private var listenerList = mutableListOf<ISettingsChangeListener>() private var systemListenerList = mutableListOf<ISystemSettingsChangeListener>()
private var displayListenerList = mutableListOf<IDisplaySettingsChangeListener>()
var language: Language var language: Language
private set private set
@@ -37,6 +46,9 @@ class SettingsAdapter @Inject constructor(@ApplicationContext private val contex
var keepScreenOn: KeepScreenOn var keepScreenOn: KeepScreenOn
private set private set
var counterListView: CounterListView
private set
init { init {
language = try { language = try {
enumValueOf(sharedPreferences.getString(Language::class.simpleName, null)!!) enumValueOf(sharedPreferences.getString(Language::class.simpleName, null)!!)
@@ -55,19 +67,37 @@ class SettingsAdapter @Inject constructor(@ApplicationContext private val contex
} catch (_: java.lang.Exception) { } catch (_: java.lang.Exception) {
KeepScreenOn.OFF KeepScreenOn.OFF
} }
counterListView = try {
enumValueOf(sharedPreferences.getString(CounterListView::class.simpleName, null)!!)
} catch (_: java.lang.Exception) {
CounterListView.BY_ROUND
}
} }
fun registerOnChangeListener(listener: ISettingsChangeListener) { fun registerOnChangeListener(listener: ISystemSettingsChangeListener) {
listenerList.add(listener) systemListenerList.add(listener)
listener.onThemeChanged(theme) listener.onThemeChanged(theme)
listener.onLanguageChanged(language) listener.onLanguageChanged(language)
listener.onScreenOnChanged(keepScreenOn) listener.onScreenOnChanged(keepScreenOn)
} }
fun unregisterOnChangeListener(listener: ISettingsChangeListener?) { fun registerOnChangeListener(listener: IDisplaySettingsChangeListener) {
displayListenerList.add(listener)
listener.onCounterListViewChanged(counterListView)
}
fun unregisterOnChangeListener(listener: ISystemSettingsChangeListener?) {
if (listener != null) { if (listener != null) {
listenerList.remove(listener) systemListenerList.remove(listener)
}
}
fun unregisterOnChangeListener(listener: IDisplaySettingsChangeListener?) {
if (listener != null) {
displayListenerList.remove(listener)
} }
} }
@@ -89,6 +119,12 @@ class SettingsAdapter @Inject constructor(@ApplicationContext private val contex
notifyListeners(setting) notifyListeners(setting)
} }
fun setCounterViewList(setting: CounterListView) {
this.counterListView = setting
updatePreference(CounterListView::class.simpleName, setting.name)
notifyListeners(setting)
}
private fun updatePreference(name: String?, value: String) { private fun updatePreference(name: String?, value: String) {
val editor = sharedPreferences.edit() val editor = sharedPreferences.edit()
editor.putString(name, value) editor.putString(name, value)
@@ -96,21 +132,27 @@ class SettingsAdapter @Inject constructor(@ApplicationContext private val contex
} }
private fun notifyListeners(language: Language) { private fun notifyListeners(language: Language) {
listenerList.forEach { systemListenerList.forEach {
it.onLanguageChanged(language) it.onLanguageChanged(language)
} }
} }
private fun notifyListeners(theme: Theme) { private fun notifyListeners(theme: Theme) {
listenerList.forEach { systemListenerList.forEach {
it.onThemeChanged(theme) it.onThemeChanged(theme)
} }
} }
private fun notifyListeners(keepScreenOn: KeepScreenOn) { private fun notifyListeners(keepScreenOn: KeepScreenOn) {
listenerList.forEach { systemListenerList.forEach {
it.onScreenOnChanged(keepScreenOn) it.onScreenOnChanged(keepScreenOn)
} }
} }
private fun notifyListeners(counterListView: CounterListView) {
displayListenerList.forEach {
it.onCounterListViewChanged(counterListView)
}
}
} }

View File

@@ -2,7 +2,10 @@ package me.zobrist.tichucounter.repository
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.* import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.take
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import me.zobrist.tichucounter.data.GameDao import me.zobrist.tichucounter.data.GameDao
@@ -10,7 +13,7 @@ import me.zobrist.tichucounter.data.GameWithScores
import me.zobrist.tichucounter.data.RoundDao import me.zobrist.tichucounter.data.RoundDao
import me.zobrist.tichucounter.data.entity.Game import me.zobrist.tichucounter.data.entity.Game
import me.zobrist.tichucounter.data.entity.Round import me.zobrist.tichucounter.data.entity.Round
import java.util.* import java.util.Date
import javax.inject.Inject import javax.inject.Inject
class GameRepository @Inject constructor( class GameRepository @Inject constructor(
@@ -20,8 +23,6 @@ class GameRepository @Inject constructor(
private var activeGame: Game = Game(true, "TeamA", "TeamB", Date(), Date()) private var activeGame: Game = Game(true, "TeamA", "TeamB", Date(), Date())
private var distinctTeamNames: List<String> = listOf()
init { init {
CoroutineScope(Dispatchers.IO).launch { CoroutineScope(Dispatchers.IO).launch {
gameDao.getActiveAsFlow().collect { gameDao.getActiveAsFlow().collect {

View File

@@ -2,7 +2,11 @@ package me.zobrist.tichucounter.ui
import android.os.Build import android.os.Build
import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.material3.* import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.darkColorScheme
import androidx.compose.material3.dynamicDarkColorScheme
import androidx.compose.material3.dynamicLightColorScheme
import androidx.compose.material3.lightColorScheme
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext

View File

@@ -3,11 +3,20 @@ package me.zobrist.tichucounter.ui.about
import android.content.res.Configuration import android.content.res.Configuration
import androidx.compose.foundation.Image import androidx.compose.foundation.Image
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.layout.* import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.Mail import androidx.compose.material.icons.outlined.Mail
import androidx.compose.material.icons.outlined.Shop import androidx.compose.material.icons.outlined.Shop
import androidx.compose.material3.* import androidx.compose.material3.Button
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.ShapeDefaults
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment.Companion.Top import androidx.compose.ui.Alignment.Companion.Top
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
@@ -39,7 +48,7 @@ fun AboutView() {
) { ) {
Row() { Row {
Image( Image(
modifier = Modifier modifier = Modifier
.padding(end = 10.dp) .padding(end = 10.dp)
@@ -92,7 +101,7 @@ fun AboutView() {
@Preview(name = "Dark Mode", uiMode = Configuration.UI_MODE_NIGHT_YES, showBackground = true) @Preview(name = "Dark Mode", uiMode = Configuration.UI_MODE_NIGHT_YES, showBackground = true)
@Composable @Composable
fun AboutViewPreview() { fun AboutViewPreview() {
AppTheme() { AppTheme {
Surface { Surface {
AboutView() AboutView()
} }

View File

@@ -3,8 +3,17 @@ package me.zobrist.tichucounter.ui.composables
import androidx.compose.foundation.layout.width import androidx.compose.foundation.layout.width
import androidx.compose.foundation.text.KeyboardActions import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material3.* import androidx.compose.material3.DropdownMenuItem
import androidx.compose.runtime.* import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.ExposedDropdownMenuBox
import androidx.compose.material3.Text
import androidx.compose.material3.TextField
import androidx.compose.material3.TextFieldColors
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.ExperimentalComposeUiApi 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
@@ -64,15 +73,16 @@ fun TypeaheadTextField(
if (event.key == Key.Back || event.key == Key.Enter) { if (event.key == Key.Back || event.key == Key.Enter) {
focusManager.clearFocus() focusManager.clearFocus()
true true
} } else {
false false
}
}, },
colors = colors colors = colors
) )
ExposedDropdownMenu( ExposedDropdownMenu(
expanded = isFocused && items.isNotEmpty(), expanded = isFocused && items.isNotEmpty(),
modifier = Modifier modifier = Modifier
.width(with(LocalDensity.current){dropDownWidth.toDp()}), .width(with(LocalDensity.current) { dropDownWidth.toDp() }),
onDismissRequest = { } onDismissRequest = { }
) { ) {

View File

@@ -4,7 +4,11 @@ import android.content.res.Configuration
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
import androidx.compose.material3.Surface import androidx.compose.material3.Surface
import androidx.compose.runtime.* import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.FocusRequester import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.platform.LocalConfiguration import androidx.compose.ui.platform.LocalConfiguration
@@ -48,6 +52,7 @@ fun Landscape(viewModel: ICounterViewModel) {
RoundListView( RoundListView(
viewModel.roundScoreList, viewModel.roundScoreList,
viewModel.sumUpScores,
Modifier.weight(1f) Modifier.weight(1f)
) )
} }
@@ -79,6 +84,7 @@ fun Portrait(viewModel: ICounterViewModel) {
RoundListView( RoundListView(
viewModel.roundScoreList, viewModel.roundScoreList,
viewModel.sumUpScores,
Modifier.weight(1f) Modifier.weight(1f)
) )
@@ -105,6 +111,7 @@ internal class PreviewViewModel : ICounterViewModel {
override var totalScoreB: Int = 750 override var totalScoreB: Int = 750
override var teamNameA: String = "Team A" override var teamNameA: String = "Team A"
override var teamNameB: String = "Team B" override var teamNameB: String = "Team B"
override val sumUpScores: Boolean = false
override var currentScoreA: String = "" override var currentScoreA: String = ""
override var currentScoreB: String = "45" override var currentScoreB: String = "45"
override var isValidRound: Boolean = false override var isValidRound: Boolean = false
@@ -115,8 +122,10 @@ internal class PreviewViewModel : ICounterViewModel {
override var activeValue: String = currentScoreA override var activeValue: String = currentScoreA
override var inactiveValue: String = currentScoreB override var inactiveValue: String = currentScoreB
override var keyboardHidden: Boolean = false override var keyboardHidden: Boolean = false
override val teamNameSuggestionsA: List<String> = listOf("TeamA", "asdffd", "TeamB", "really really long Team Name that is way too long") override val teamNameSuggestionsA: List<String> =
override val teamNameSuggestionsB: List<String> = listOf("TeamA", "asdffd", "TeamB", "really really long Team Name that is way too long") listOf("TeamA", "asdffd", "TeamB", "really really long Team Name that is way too long")
override val teamNameSuggestionsB: List<String> =
listOf("TeamA", "asdffd", "TeamB", "really really long Team Name that is way too long")
override fun focusLastInput() { override fun focusLastInput() {
} }

View File

@@ -1,7 +1,6 @@
package me.zobrist.tichucounter.ui.counter package me.zobrist.tichucounter.ui.counter
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import androidx.compose.ui.focus.FocusRequester import androidx.compose.ui.focus.FocusRequester
@@ -10,13 +9,9 @@ import androidx.lifecycle.viewModelScope
import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.Job import kotlinx.coroutines.Job
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.take
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import me.zobrist.tichucounter.data.entity.Round import me.zobrist.tichucounter.data.entity.Round
import me.zobrist.tichucounter.domain.Tichu import me.zobrist.tichucounter.domain.*
import me.zobrist.tichucounter.domain.digitCount
import me.zobrist.tichucounter.domain.getTotalPoints
import me.zobrist.tichucounter.repository.GameRepository import me.zobrist.tichucounter.repository.GameRepository
import javax.inject.Inject import javax.inject.Inject
@@ -56,6 +51,7 @@ interface ICounterViewModel : IKeyBoardViewModel {
val roundScoreList: List<Round> val roundScoreList: List<Round>
val totalScoreA: Int val totalScoreA: Int
val totalScoreB: Int val totalScoreB: Int
val sumUpScores: Boolean
val teamNameA: String val teamNameA: String
val teamNameB: String val teamNameB: String
val teamNameSuggestionsA: List<String> val teamNameSuggestionsA: List<String>
@@ -67,9 +63,10 @@ interface ICounterViewModel : IKeyBoardViewModel {
@HiltViewModel @HiltViewModel
class CounterViewModel @Inject constructor( class CounterViewModel @Inject constructor(
private val gameRepository: GameRepository private val gameRepository: GameRepository,
private val settingsAdapter: SettingsAdapter
) : ) :
ViewModel(), ICounterViewModel { ViewModel(), ICounterViewModel, IDisplaySettingsChangeListener {
override var roundScoreList by mutableStateOf(emptyList<Round>()) override var roundScoreList by mutableStateOf(emptyList<Round>())
private set private set
@@ -83,6 +80,9 @@ class CounterViewModel @Inject constructor(
override var teamNameA by mutableStateOf("") override var teamNameA by mutableStateOf("")
private set private set
override var sumUpScores by mutableStateOf(false)
private set
override var teamNameB by mutableStateOf("") override var teamNameB by mutableStateOf("")
private set private set
@@ -178,12 +178,18 @@ class CounterViewModel @Inject constructor(
} }
viewModelScope.launch { viewModelScope.launch {
gameRepository.getDistinctTeamNames().collect() { gameRepository.getDistinctTeamNames().collect {
distinctTeamNames = it distinctTeamNames = it
buildTeamNameSuggestions() buildTeamNameSuggestions()
} }
} }
settingsAdapter.registerOnChangeListener(this)
}
override fun onCleared() {
settingsAdapter.unregisterOnChangeListener(this)
} }
override fun focusLastInput() { override fun focusLastInput() {
@@ -351,19 +357,22 @@ class CounterViewModel @Inject constructor(
} }
} }
private fun buildTeamNameSuggestions(){ private fun buildTeamNameSuggestions() {
teamNameSuggestionsA = buildTypeaheadList(distinctTeamNames, teamNameA) teamNameSuggestionsA = buildTypeaheadList(distinctTeamNames, teamNameA)
teamNameSuggestionsB = buildTypeaheadList(distinctTeamNames, teamNameB) teamNameSuggestionsB = buildTypeaheadList(distinctTeamNames, teamNameB)
} }
private fun buildTypeaheadList(rawList: List<String>, currentInput: String ): List<String> { private fun buildTypeaheadList(rawList: List<String>, currentInput: String): List<String> {
var filtered = rawList.filter { it.isNotEmpty() && it != currentInput } var filtered = rawList.filter { it.isNotEmpty() && it != currentInput }
if(currentInput.isNotEmpty()) if (currentInput.isNotEmpty()) {
{ filtered = filtered.filter { it.contains(currentInput, ignoreCase = true) }
filtered = filtered.filter { it.contains(currentInput) }
} }
return filtered.sorted().sortedBy { it.length }.take(10) return filtered.sorted().sortedBy { it.length }.take(10)
} }
override fun onCounterListViewChanged(listView: CounterListView) {
sumUpScores = listView == CounterListView.CONTINUOUS
}
} }

View File

@@ -251,7 +251,6 @@ fun KeyboardIconButton(
} }
} }
@OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
fun CenteredTextField( fun CenteredTextField(
value: String, value: String,

View File

@@ -21,13 +21,22 @@ import me.zobrist.tichucounter.data.entity.Round
import me.zobrist.tichucounter.ui.AppTheme import me.zobrist.tichucounter.ui.AppTheme
@Composable @Composable
fun RoundListView(rounds: List<Round>, modifier: Modifier) { fun RoundListView(rounds: List<Round>, sumUpRounds: Boolean = false, modifier: Modifier) {
val lazyListState = rememberLazyListState() val lazyListState = rememberLazyListState()
val scope = rememberCoroutineScope() val scope = rememberCoroutineScope()
var sumA = 0
var sumB = 0
LazyColumn(state = lazyListState, modifier = modifier) { LazyColumn(state = lazyListState, modifier = modifier) {
itemsIndexed(rounds) { index, item -> itemsIndexed(rounds) { index, item ->
RoundListItem(item, index) if (sumUpRounds) {
sumA += item.scoreA
sumB += item.scoreB
RoundListItem(sumA, sumB, index)
} else {
RoundListItem(item.scoreA, item.scoreB, index)
}
} }
scope.launch { scope.launch {
@@ -37,14 +46,14 @@ fun RoundListView(rounds: List<Round>, modifier: Modifier) {
} }
@Composable @Composable
private fun RoundListItem(round: Round, index: Int) { private fun RoundListItem(scoreA: Int, scoreB: Int, index: Int) {
Row( Row(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.padding(all = 4.dp) .padding(all = 4.dp)
) { ) {
Text( Text(
text = round.scoreA.toString(), text = scoreA.toString(),
style = MaterialTheme.typography.bodyMedium, style = MaterialTheme.typography.bodyMedium,
modifier = Modifier.weight(5f), modifier = Modifier.weight(5f),
textAlign = TextAlign.Center textAlign = TextAlign.Center
@@ -56,7 +65,7 @@ private fun RoundListItem(round: Round, index: Int) {
textAlign = TextAlign.Center textAlign = TextAlign.Center
) )
Text( Text(
text = round.scoreB.toString(), text = scoreB.toString(),
style = MaterialTheme.typography.bodyMedium, style = MaterialTheme.typography.bodyMedium,
modifier = Modifier.weight(5f), modifier = Modifier.weight(5f),
textAlign = TextAlign.Center textAlign = TextAlign.Center
@@ -78,7 +87,7 @@ fun RoundListViewPreview() {
AppTheme { AppTheme {
Surface { Surface {
RoundListView(rounds, Modifier) RoundListView(rounds, true, Modifier)
} }
} }
} }

View File

@@ -2,19 +2,15 @@ package me.zobrist.tichucounter.ui.counter
import android.content.res.Configuration import android.content.res.Configuration
import androidx.compose.foundation.layout.* import androidx.compose.foundation.layout.*
import androidx.compose.material3.* import androidx.compose.material3.*
import androidx.compose.runtime.* import androidx.compose.runtime.*
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.onFocusChanged
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import me.zobrist.tichucounter.ui.AppTheme import me.zobrist.tichucounter.ui.AppTheme
import me.zobrist.tichucounter.ui.composables.TypeaheadTextField import me.zobrist.tichucounter.ui.composables.TypeaheadTextField
@OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
fun TeamNamesView( fun TeamNamesView(
nameA: String, nameA: String,
@@ -25,8 +21,11 @@ fun TeamNamesView(
updateB: (String) -> Unit updateB: (String) -> Unit
) { ) {
val color = TextFieldDefaults.textFieldColors( val containerColor = MaterialTheme.colorScheme.surfaceColorAtElevation(1.dp)
containerColor = MaterialTheme.colorScheme.surfaceColorAtElevation(1.dp) val color = TextFieldDefaults.colors(
focusedContainerColor = containerColor,
unfocusedContainerColor = containerColor,
disabledContainerColor = containerColor,
) )
Row { Row {

View File

@@ -4,7 +4,11 @@ import android.content.res.Configuration
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.material3.* import androidx.compose.material3.CardDefaults
import androidx.compose.material3.ElevatedCard
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextAlign

View File

@@ -2,14 +2,31 @@ package me.zobrist.tichucounter.ui.history
import androidx.compose.foundation.clickable import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.* import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.layout.wrapContentSize
import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items import androidx.compose.foundation.lazy.items
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.DeleteForever import androidx.compose.material.icons.outlined.DeleteForever
import androidx.compose.material.icons.outlined.MoreVert import androidx.compose.material.icons.outlined.MoreVert
import androidx.compose.material3.* import androidx.compose.material3.AlertDialog
import androidx.compose.runtime.* import androidx.compose.material3.Button
import androidx.compose.material3.Card
import androidx.compose.material3.CardDefaults
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment.Companion.CenterVertically import androidx.compose.ui.Alignment.Companion.CenterVertically
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
@@ -23,7 +40,8 @@ import me.zobrist.tichucounter.data.entity.Round
import me.zobrist.tichucounter.domain.getTotalPoints import me.zobrist.tichucounter.domain.getTotalPoints
import me.zobrist.tichucounter.ui.composables.DropDownMenu import me.zobrist.tichucounter.ui.composables.DropDownMenu
import java.text.DateFormat import java.text.DateFormat
import java.util.* import java.util.Date
import java.util.Locale
@Composable @Composable

View File

@@ -16,7 +16,6 @@ import me.zobrist.tichucounter.domain.*
import me.zobrist.tichucounter.ui.AppTheme import me.zobrist.tichucounter.ui.AppTheme
import me.zobrist.tichucounter.ui.counter.* import me.zobrist.tichucounter.ui.counter.*
@OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
fun DrawerContent( fun DrawerContent(
drawerItems: List<DrawerItem>, drawerItems: List<DrawerItem>,

View File

@@ -8,8 +8,16 @@ import androidx.compose.foundation.layout.fillMaxWidth
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.outlined.ArrowDropDown import androidx.compose.material.icons.outlined.ArrowDropDown
import androidx.compose.material3.* import androidx.compose.material3.Icon
import androidx.compose.runtime.* import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Switch
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment.Companion.End import androidx.compose.ui.Alignment.Companion.End
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
@@ -17,6 +25,7 @@ import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import me.zobrist.tichucounter.R import me.zobrist.tichucounter.R
import me.zobrist.tichucounter.domain.CounterListView
import me.zobrist.tichucounter.domain.KeepScreenOn import me.zobrist.tichucounter.domain.KeepScreenOn
import me.zobrist.tichucounter.domain.Language import me.zobrist.tichucounter.domain.Language
import me.zobrist.tichucounter.domain.Theme import me.zobrist.tichucounter.domain.Theme
@@ -36,6 +45,11 @@ val themeMap = mapOf(
Theme.LIGHT to R.string.light Theme.LIGHT to R.string.light
) )
val counterListViewMap = mapOf(
CounterListView.BY_ROUND to R.string.by_round,
CounterListView.CONTINUOUS to R.string.continuous,
)
@Composable @Composable
fun SettingsView(viewModel: SettingsViewModel) { fun SettingsView(viewModel: SettingsViewModel) {
@@ -43,9 +57,11 @@ fun SettingsView(viewModel: SettingsViewModel) {
viewModel.screenOn.value, viewModel.screenOn.value,
viewModel.language, viewModel.language,
viewModel.theme, viewModel.theme,
viewModel.counterListView,
{ viewModel.updateScreenOn(it) }, { viewModel.updateScreenOn(it) },
{ viewModel.updateLanguage(it) }, { viewModel.updateLanguage(it) },
{ viewModel.updateTheme(it) }) { viewModel.updateTheme(it) },
{ viewModel.updateCounterListView(it) })
} }
@Composable @Composable
@@ -53,9 +69,11 @@ fun SettingsView(
valueScreenOn: Boolean = true, valueScreenOn: Boolean = true,
valueLanguage: Language = Language.ENGLISH, valueLanguage: Language = Language.ENGLISH,
valueTheme: Theme = Theme.DARK, valueTheme: Theme = Theme.DARK,
valueCounterListView: CounterListView = CounterListView.BY_ROUND,
updateScreenOn: (KeepScreenOn) -> Unit = {}, updateScreenOn: (KeepScreenOn) -> Unit = {},
updateLanguage: (Language) -> Unit = {}, updateLanguage: (Language) -> Unit = {},
updateTheme: (Theme) -> Unit = {} updateTheme: (Theme) -> Unit = {},
updateCounterListView: (CounterListView) -> Unit = {}
) { ) {
Column { Column {
BooleanSetting( BooleanSetting(
@@ -74,6 +92,14 @@ fun SettingsView(
themeMap, themeMap,
valueTheme, valueTheme,
) { updateTheme(it) } ) { updateTheme(it) }
StringSetting(
stringResource(R.string.counter_mode),
counterListViewMap,
valueCounterListView,
) { updateCounterListView(it) }
} }
} }

View File

@@ -5,10 +5,7 @@ import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.lifecycle.HiltViewModel
import me.zobrist.tichucounter.domain.KeepScreenOn import me.zobrist.tichucounter.domain.*
import me.zobrist.tichucounter.domain.Language
import me.zobrist.tichucounter.domain.SettingsAdapter
import me.zobrist.tichucounter.domain.Theme
import javax.inject.Inject import javax.inject.Inject
@HiltViewModel @HiltViewModel
@@ -24,6 +21,9 @@ class SettingsViewModel @Inject constructor(private val settings: SettingsAdapte
var screenOn by mutableStateOf(settings.keepScreenOn) var screenOn by mutableStateOf(settings.keepScreenOn)
private set private set
var counterListView by mutableStateOf(settings.counterListView)
private set
fun updateLanguage(language: Language) { fun updateLanguage(language: Language) {
settings.setLanguage(language) settings.setLanguage(language)
this.language = settings.language this.language = settings.language
@@ -39,4 +39,9 @@ class SettingsViewModel @Inject constructor(private val settings: SettingsAdapte
screenOn = settings.keepScreenOn screenOn = settings.keepScreenOn
} }
fun updateCounterListView(value: CounterListView) {
settings.setCounterViewList(value)
counterListView = settings.counterListView
}
} }

View File

@@ -3,51 +3,52 @@
android:height="108dp" android:height="108dp"
android:viewportWidth="50.684" android:viewportWidth="50.684"
android:viewportHeight="39.77"> android:viewportHeight="39.77">
<group android:scaleX="0.46444446" <group
android:scaleX="0.46444446"
android:scaleY="0.36443365" android:scaleY="0.36443365"
android:translateX="13.572049" android:translateX="13.572049"
android:translateY="12.638237"> android:translateY="12.638237">
<path <path
android:fillColor="#ffff00"
android:pathData="m25.885,0.371 l-25.752,0.047 0.094,9.167 8.174,0.094 -0.094,29.957 9.592,-0.094 -0.047,-29.957h8.08z" android:pathData="m25.885,0.371 l-25.752,0.047 0.094,9.167 8.174,0.094 -0.094,29.957 9.592,-0.094 -0.047,-29.957h8.08z"
android:strokeLineJoin="miter"
android:strokeWidth="0.26458300000000001" android:strokeWidth="0.26458300000000001"
android:fillColor="#ffff00"
android:strokeColor="#000000" android:strokeColor="#000000"
android:strokeLineCap="butt"/> android:strokeLineCap="butt"
android:strokeLineJoin="miter" />
<path <path
android:fillColor="#ffff00"
android:pathData="m50.503,39.494 l-0.047,-9.214h-10.773c-0.738,-0.009 -2.147,-0.64 -2.139,-1.95 0.009,-1.415 0.012,-16.903 0.012,-16.903 -0.001,-1.41 1.227,-2.055 1.89,-2.079l11.009,-0.142 0.094,-9.072 -11.86,0.189c-2.609,0.059 -10.536,2.804 -10.537,13.23 -0,10.079 0.218,15.921 0.218,15.921 0.223,4.386 5.741,9.979 10.125,9.99l12.006,0.03z" android:pathData="m50.503,39.494 l-0.047,-9.214h-10.773c-0.738,-0.009 -2.147,-0.64 -2.139,-1.95 0.009,-1.415 0.012,-16.903 0.012,-16.903 -0.001,-1.41 1.227,-2.055 1.89,-2.079l11.009,-0.142 0.094,-9.072 -11.86,0.189c-2.609,0.059 -10.536,2.804 -10.537,13.23 -0,10.079 0.218,15.921 0.218,15.921 0.223,4.386 5.741,9.979 10.125,9.99l12.006,0.03z"
android:strokeLineJoin="miter"
android:strokeWidth="0.26458300000000001" android:strokeWidth="0.26458300000000001"
android:fillColor="#ffff00"
android:strokeColor="#000000" android:strokeColor="#000000"
android:strokeLineCap="butt"/> android:strokeLineCap="butt"
android:strokeLineJoin="miter" />
<path <path
android:fillColor="#000000"
android:pathData="m8.403,10.083c0.049,-0.713 -0.112,-0.88 -0.029,-2.095 0.366,-1.278 9.609,-5.62 16.985,-2.65 0.403,0.162 0.5,-0.375 0.299,-0.467 -2.964,-2.692 -13.318,-8.128 -25.314,0.286l8.059,4.521" android:pathData="m8.403,10.083c0.049,-0.713 -0.112,-0.88 -0.029,-2.095 0.366,-1.278 9.609,-5.62 16.985,-2.65 0.403,0.162 0.5,-0.375 0.299,-0.467 -2.964,-2.692 -13.318,-8.128 -25.314,0.286l8.059,4.521"
android:strokeLineJoin="miter"
android:strokeWidth="0.264583" android:strokeWidth="0.264583"
android:fillColor="#000000"
android:strokeColor="#000000" android:strokeColor="#000000"
android:strokeLineCap="butt"/> android:strokeLineCap="butt"
android:strokeLineJoin="miter" />
<path <path
android:fillColor="#000000"
android:pathData="m13.09,39.45 l-4.651,-7.072 1.436,-0.155c1.716,-3.55 8.698,-15.304 2.46,-24.75 -0.307,-0.496 0.802,-2.297 1.512,-0.563 5.772,10.547 5.161,23.028 -0.757,32.54z" android:pathData="m13.09,39.45 l-4.651,-7.072 1.436,-0.155c1.716,-3.55 8.698,-15.304 2.46,-24.75 -0.307,-0.496 0.802,-2.297 1.512,-0.563 5.772,10.547 5.161,23.028 -0.757,32.54z"
android:strokeLineJoin="miter"
android:strokeWidth="0.264583" android:strokeWidth="0.264583"
android:fillColor="#000000"
android:strokeColor="#000000" android:strokeColor="#000000"
android:strokeLineCap="butt"/> android:strokeLineCap="butt"
android:strokeLineJoin="miter" />
<path <path
android:fillColor="#000000"
android:pathData="m42.812,9.194 l7.51,-4.144c-4.938,-5.973 -14.39,-7.27 -20.302,4.385 -0.2,0.447 0.901,0.888 1.106,0.649 5.387,-7.535 11.325,-3.968 11.686,-2.476 0.158,0.461 0.006,1.054 0.001,1.585z" android:pathData="m42.812,9.194 l7.51,-4.144c-4.938,-5.973 -14.39,-7.27 -20.302,4.385 -0.2,0.447 0.901,0.888 1.106,0.649 5.387,-7.535 11.325,-3.968 11.686,-2.476 0.158,0.461 0.006,1.054 0.001,1.585z"
android:strokeLineJoin="miter"
android:strokeWidth="0.264583" android:strokeWidth="0.264583"
android:fillColor="#000000"
android:strokeColor="#000000" android:strokeColor="#000000"
android:strokeLineCap="butt"/> android:strokeLineCap="butt"
android:strokeLineJoin="miter" />
<path <path
android:pathData="m42.429,30.41 l7.935,4.743c-13.982,13.838 -26.059,-8.724 -21.01,-24.194 0.143,-0.438 1.306,-0.12 1.201,0.408 -1.411,6.97 1.621,22.234 11.726,20.975z"
android:strokeLineJoin="miter"
android:strokeWidth="0.264583"
android:fillColor="#000000" android:fillColor="#000000"
android:pathData="m42.429,30.41 l7.935,4.743c-13.982,13.838 -26.059,-8.724 -21.01,-24.194 0.143,-0.438 1.306,-0.12 1.201,0.408 -1.411,6.97 1.621,22.234 11.726,20.975z"
android:strokeWidth="0.264583"
android:strokeColor="#000000" android:strokeColor="#000000"
android:strokeLineCap="butt"/> android:strokeLineCap="butt"
android:strokeLineJoin="miter" />
</group> </group>
</vector> </vector>

View File

@@ -4,45 +4,45 @@
android:viewportWidth="50.684" android:viewportWidth="50.684"
android:viewportHeight="39.77"> android:viewportHeight="39.77">
<path <path
android:fillColor="#ffff00"
android:pathData="m25.885,0.371 l-25.752,0.047 0.094,9.167 8.174,0.094 -0.094,29.957 9.592,-0.094 -0.047,-29.957h8.08z" android:pathData="m25.885,0.371 l-25.752,0.047 0.094,9.167 8.174,0.094 -0.094,29.957 9.592,-0.094 -0.047,-29.957h8.08z"
android:strokeLineJoin="miter"
android:strokeWidth="0.26458300000000001" android:strokeWidth="0.26458300000000001"
android:fillColor="#ffff00"
android:strokeColor="#000000" android:strokeColor="#000000"
android:strokeLineCap="butt"/> android:strokeLineCap="butt"
android:strokeLineJoin="miter" />
<path <path
android:fillColor="#ffff00"
android:pathData="m50.503,39.494 l-0.047,-9.214h-10.773c-0.738,-0.009 -2.147,-0.64 -2.139,-1.95 0.009,-1.415 0.012,-16.903 0.012,-16.903 -0.001,-1.41 1.227,-2.055 1.89,-2.079l11.009,-0.142 0.094,-9.072 -11.86,0.189c-2.609,0.059 -10.536,2.804 -10.537,13.23 -0,10.079 0.218,15.921 0.218,15.921 0.223,4.386 5.741,9.979 10.125,9.99l12.006,0.03z" android:pathData="m50.503,39.494 l-0.047,-9.214h-10.773c-0.738,-0.009 -2.147,-0.64 -2.139,-1.95 0.009,-1.415 0.012,-16.903 0.012,-16.903 -0.001,-1.41 1.227,-2.055 1.89,-2.079l11.009,-0.142 0.094,-9.072 -11.86,0.189c-2.609,0.059 -10.536,2.804 -10.537,13.23 -0,10.079 0.218,15.921 0.218,15.921 0.223,4.386 5.741,9.979 10.125,9.99l12.006,0.03z"
android:strokeLineJoin="miter"
android:strokeWidth="0.26458300000000001" android:strokeWidth="0.26458300000000001"
android:fillColor="#ffff00"
android:strokeColor="#000000" android:strokeColor="#000000"
android:strokeLineCap="butt"/> android:strokeLineCap="butt"
android:strokeLineJoin="miter" />
<path <path
android:fillColor="#000000"
android:pathData="m8.403,10.083c0.049,-0.713 -0.112,-0.88 -0.029,-2.095 0.366,-1.278 9.609,-5.62 16.985,-2.65 0.403,0.162 0.5,-0.375 0.299,-0.467 -2.964,-2.692 -13.318,-8.128 -25.314,0.286l8.059,4.521" android:pathData="m8.403,10.083c0.049,-0.713 -0.112,-0.88 -0.029,-2.095 0.366,-1.278 9.609,-5.62 16.985,-2.65 0.403,0.162 0.5,-0.375 0.299,-0.467 -2.964,-2.692 -13.318,-8.128 -25.314,0.286l8.059,4.521"
android:strokeLineJoin="miter"
android:strokeWidth="0.264583" android:strokeWidth="0.264583"
android:fillColor="#000000"
android:strokeColor="#000000" android:strokeColor="#000000"
android:strokeLineCap="butt"/> android:strokeLineCap="butt"
android:strokeLineJoin="miter" />
<path <path
android:fillColor="#000000"
android:pathData="m13.09,39.45 l-4.651,-7.072 1.436,-0.155c1.716,-3.55 8.698,-15.304 2.46,-24.75 -0.307,-0.496 0.802,-2.297 1.512,-0.563 5.772,10.547 5.161,23.028 -0.757,32.54z" android:pathData="m13.09,39.45 l-4.651,-7.072 1.436,-0.155c1.716,-3.55 8.698,-15.304 2.46,-24.75 -0.307,-0.496 0.802,-2.297 1.512,-0.563 5.772,10.547 5.161,23.028 -0.757,32.54z"
android:strokeLineJoin="miter"
android:strokeWidth="0.264583" android:strokeWidth="0.264583"
android:fillColor="#000000"
android:strokeColor="#000000" android:strokeColor="#000000"
android:strokeLineCap="butt"/> android:strokeLineCap="butt"
android:strokeLineJoin="miter" />
<path <path
android:fillColor="#000000"
android:pathData="m42.812,9.194 l7.51,-4.144c-4.938,-5.973 -14.39,-7.27 -20.302,4.385 -0.2,0.447 0.901,0.888 1.106,0.649 5.387,-7.535 11.325,-3.968 11.686,-2.476 0.158,0.461 0.006,1.054 0.001,1.585z" android:pathData="m42.812,9.194 l7.51,-4.144c-4.938,-5.973 -14.39,-7.27 -20.302,4.385 -0.2,0.447 0.901,0.888 1.106,0.649 5.387,-7.535 11.325,-3.968 11.686,-2.476 0.158,0.461 0.006,1.054 0.001,1.585z"
android:strokeLineJoin="miter"
android:strokeWidth="0.264583" android:strokeWidth="0.264583"
android:fillColor="#000000"
android:strokeColor="#000000" android:strokeColor="#000000"
android:strokeLineCap="butt"/> android:strokeLineCap="butt"
android:strokeLineJoin="miter" />
<path <path
android:pathData="m42.429,30.41 l7.935,4.743c-13.982,13.838 -26.059,-8.724 -21.01,-24.194 0.143,-0.438 1.306,-0.12 1.201,0.408 -1.411,6.97 1.621,22.234 11.726,20.975z"
android:strokeLineJoin="miter"
android:strokeWidth="0.264583"
android:fillColor="#000000" android:fillColor="#000000"
android:pathData="m42.429,30.41 l7.935,4.743c-13.982,13.838 -26.059,-8.724 -21.01,-24.194 0.143,-0.438 1.306,-0.12 1.201,0.408 -1.411,6.97 1.621,22.234 11.726,20.975z"
android:strokeWidth="0.264583"
android:strokeColor="#000000" android:strokeColor="#000000"
android:strokeLineCap="butt"/> android:strokeLineCap="butt"
android:strokeLineJoin="miter" />
</vector> </vector>

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android"> <adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@color/ic_launcher_background"/> <background android:drawable="@color/ic_launcher_background" />
<foreground android:drawable="@drawable/ic_launcher_foreground"/> <foreground android:drawable="@drawable/ic_launcher_foreground" />
<monochrome android:drawable="@drawable/ic_launcher_foreground" /> <monochrome android:drawable="@drawable/ic_launcher_foreground" />
</adaptive-icon> </adaptive-icon>

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android"> <adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@color/ic_launcher_background"/> <background android:drawable="@color/ic_launcher_background" />
<foreground android:drawable="@drawable/ic_launcher_foreground"/> <foreground android:drawable="@drawable/ic_launcher_foreground" />
</adaptive-icon> </adaptive-icon>

View File

@@ -26,6 +26,9 @@
<string name="inactive">Old Games</string> <string name="inactive">Old Games</string>
<string name="menu_counter">Counter</string> <string name="menu_counter">Counter</string>
<string name="menu_about">About</string> <string name="menu_about">About</string>
<string name="by_round">Display Single Round</string>
<string name="continuous">Sum up rounds</string>
<string name="counter_mode">Counter Mode</string>
<string name="contact_us">Contact us</string> <string name="contact_us">Contact us</string>
<string name="play_store" translatable="false">Play Store</string> <string name="play_store" translatable="false">Play Store</string>
</resources> </resources>

View File

@@ -1,7 +1,9 @@
package me.zobrist.tichucounter package me.zobrist.tichucounter
import me.zobrist.tichucounter.domain.Tichu import me.zobrist.tichucounter.domain.Tichu
import org.junit.Assert.* import org.junit.Assert.assertEquals
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
import org.junit.Test import org.junit.Test
/** /**

View File

@@ -6,7 +6,7 @@ buildscript {
mavenCentral() mavenCentral()
} }
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:8.0.1' classpath 'com.android.tools.build:gradle:8.0.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