12 Commits

Author SHA1 Message Date
4d37e77f55 Fix round index.
All checks were successful
continuous-integration/drone/push Build is passing
2023-01-21 16:40:00 +01:00
984afb610f Add counter again to navigation.
All checks were successful
continuous-integration/drone/push Build is passing
2023-01-21 16:32:07 +01:00
c3c6c253bc no message
All checks were successful
continuous-integration/drone/push Build is passing
2023-01-21 15:58:18 +01:00
9189d79982 Disable gesture navigation.
All checks were successful
continuous-integration/drone/push Build is passing
2023-01-21 15:55:49 +01:00
ad0236556e Add delete all history with confirm dialog.
All checks were successful
continuous-integration/drone/push Build is passing
2023-01-21 15:48:07 +01:00
52a73bf204 Simplify history card. Activate open for active game. 2023-01-21 14:47:36 +01:00
6d0192df18 Style game history. Add functionality to delete and open game from history.
All checks were successful
continuous-integration/drone/push Build is passing
2023-01-21 13:04:45 +01:00
63f213bc75 Add hide show keyboard function. Fix keyboard too big on small screens. Improve colors.
All checks were successful
continuous-integration/drone/push Build is passing
2023-01-21 11:30:20 +01:00
68a5d34e45 Add versions code to VersionName.
All checks were successful
continuous-integration/drone/push Build is passing
2023-01-21 10:21:51 +01:00
98ea66772f Fix warnings. Remove unused files.
Some checks are pending
continuous-integration/drone/push Build is running
2023-01-21 10:15:59 +01:00
84a63a2bcb Revert "Upload files to 'app'"
This reverts commit c5de57c416.
2023-01-21 09:02:20 +01:00
c5de57c416 Upload files to 'app'
All checks were successful
continuous-integration/drone/push Build is passing
2023-01-21 07:48:21 +01:00
40 changed files with 436 additions and 315 deletions

View File

@@ -15,6 +15,8 @@ def versionPropertiesFile = rootProject.file("version.properties")
def keystoreProperties = new Properties() def keystoreProperties = new Properties()
def versionProperties = new Properties() def versionProperties = new Properties()
def versionMajor = 2
def versionMinor = 0
// Load your keystore.properties file into the keystoreProperties object. // Load your keystore.properties file into the keystoreProperties object.
keystoreProperties.load(new FileInputStream(keystorePropertiesFile)) keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
@@ -29,13 +31,19 @@ android {
minSdkVersion 21 minSdkVersion 21
targetSdkVersion 33 targetSdkVersion 33
versionCode versionProperties["versionCode"].toInteger() versionCode versionProperties["versionCode"].toInteger()
versionName "1.1.0Beta1" versionName "${versionMajor}.${versionMinor}.${versionProperties["versionCode"].toInteger()}"
resConfigs 'de', 'en' resConfigs 'de', 'en'
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
multiDexEnabled true multiDexEnabled true
vectorDrawables { vectorDrawables {
useSupportLibrary true useSupportLibrary true
} }
javaCompileOptions {
annotationProcessorOptions {
arguments += ["room.schemaLocation": "$projectDir/schemas".toString()]
}
}
} }
signingConfigs { signingConfigs {
create("release") { create("release") {
@@ -86,7 +94,7 @@ dependencies {
implementation "androidx.compose.material3:material3:1.0.1" implementation "androidx.compose.material3:material3:1.0.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.android.play:core-ktx:1.8.1'
implementation 'com.google.code.gson:gson:2.8.9' implementation 'com.google.code.gson:gson:2.9.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4' implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
implementation 'androidx.navigation:navigation-fragment-ktx:2.5.3' implementation 'androidx.navigation:navigation-fragment-ktx:2.5.3'
implementation 'androidx.navigation:navigation-ui-ktx:2.5.3' implementation 'androidx.navigation:navigation-ui-ktx:2.5.3'

View File

@@ -0,0 +1,102 @@
{
"formatVersion": 1,
"database": {
"version": 1,
"identityHash": "f07e88c78e54c69c73890495a2121bf4",
"entities": [
{
"tableName": "Round",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`gameId` INTEGER NOT NULL, `scoreA` INTEGER NOT NULL, `scoreB` INTEGER NOT NULL, `uid` INTEGER PRIMARY KEY AUTOINCREMENT)",
"fields": [
{
"fieldPath": "gameId",
"columnName": "gameId",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "scoreA",
"columnName": "scoreA",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "scoreB",
"columnName": "scoreB",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "uid",
"columnName": "uid",
"affinity": "INTEGER",
"notNull": false
}
],
"primaryKey": {
"autoGenerate": true,
"columnNames": [
"uid"
]
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "Game",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`active` INTEGER NOT NULL, `nameA` TEXT NOT NULL, `nameB` TEXT NOT NULL, `created` INTEGER NOT NULL, `modified` INTEGER NOT NULL, `uid` INTEGER PRIMARY KEY AUTOINCREMENT)",
"fields": [
{
"fieldPath": "active",
"columnName": "active",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "nameA",
"columnName": "nameA",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "nameB",
"columnName": "nameB",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "created",
"columnName": "created",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "modified",
"columnName": "modified",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "uid",
"columnName": "uid",
"affinity": "INTEGER",
"notNull": false
}
],
"primaryKey": {
"autoGenerate": true,
"columnNames": [
"uid"
]
},
"indices": [],
"foreignKeys": []
}
],
"views": [],
"setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'f07e88c78e54c69c73890495a2121bf4')"
]
}
}

View File

@@ -75,7 +75,7 @@ abstract class BaseActivity : AppCompatActivity(),
private fun setLanguage(language: Language) { private fun setLanguage(language: Language) {
val currentLocale = AppCompatDelegate.getApplicationLocales()[0].toString() val currentLocale = AppCompatDelegate.getApplicationLocales()[0].toString()
if (language.value != null && language.value != currentLocale) { if (language.value != currentLocale) {
val newLocale = LocaleListCompat.forLanguageTags(language.value) val newLocale = LocaleListCompat.forLanguageTags(language.value)
AppCompatDelegate.setApplicationLocales(newLocale) AppCompatDelegate.setApplicationLocales(newLocale)
} }

View File

@@ -54,7 +54,7 @@ class MainActivity : BaseActivity() {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
setContent { setContent {
AppTheme() { AppTheme {
val systemUiController = rememberSystemUiController() val systemUiController = rememberSystemUiController()
systemUiController.setStatusBarColor(MaterialTheme.colorScheme.background) systemUiController.setStatusBarColor(MaterialTheme.colorScheme.background)
NavigationDrawer() NavigationDrawer()
@@ -67,10 +67,20 @@ class MainActivity : BaseActivity() {
fun MyScaffoldLayout( fun MyScaffoldLayout(
drawerState: DrawerState, drawerState: DrawerState,
scope: CoroutineScope, scope: CoroutineScope,
navController: NavHostController navController: NavHostController,
showFab: Boolean,
fabAction: () -> Unit
) { ) {
Scaffold( Scaffold(
floatingActionButton = {
if (showFab) {
FloatingActionButton(
onClick = { fabAction() }) {
Icon(Icons.Outlined.Keyboard, null)
}
}
},
topBar = { topBar = {
TopBar( TopBar(
mainViewModel.topBarTitle, mainViewModel.topBarTitle,
@@ -104,20 +114,35 @@ class MainActivity : BaseActivity() {
NavigationAction { scope.launch { drawerState.open() } } NavigationAction { scope.launch { drawerState.open() } }
} }
composable("history") { composable("history") {
HistoryList(historyViewModel)
mainViewModel.topBarActions = emptyList() var openDialog by remember { mutableStateOf(false) }
mainViewModel.topBarIcon = Icons.Outlined.ArrowBack
HistoryList(historyViewModel, openDialog, { deleteAll ->
if (deleteAll) {
mainViewModel.deleteAllInactiveGames()
}
openDialog = false
}) { navController.navigate("counter") }
mainViewModel.topBarActions = listOf(
TopBarAction(
Icons.Outlined.DeleteForever,
true
) {
openDialog = true
}
)
mainViewModel.topBarIcon = Icons.Outlined.Menu
mainViewModel.topBarTitle = stringResource(R.string.menu_history) mainViewModel.topBarTitle = stringResource(R.string.menu_history)
mainViewModel.topBarNavigationAction = mainViewModel.topBarNavigationAction =
NavigationAction { navController.navigate("counter") } NavigationAction { scope.launch { drawerState.open() } }
} }
composable("settings") { composable("settings") {
SettingsView(settingsViewModel) SettingsView(settingsViewModel)
mainViewModel.topBarActions = emptyList() mainViewModel.topBarActions = emptyList()
mainViewModel.topBarIcon = Icons.Outlined.ArrowBack mainViewModel.topBarIcon = Icons.Outlined.Menu
mainViewModel.topBarTitle = stringResource(R.string.menu_settings) mainViewModel.topBarTitle = stringResource(R.string.menu_settings)
mainViewModel.topBarNavigationAction = mainViewModel.topBarNavigationAction =
NavigationAction { navController.navigate("counter") } NavigationAction { scope.launch { drawerState.open() } }
} }
} }
} }
@@ -168,7 +193,9 @@ class MainActivity : BaseActivity() {
val navController = rememberNavController() val navController = rememberNavController()
val items = listOf( val items = listOf(
Screen("history", Icons.Outlined.List, R.string.menu_history),Screen("settings", Icons.Outlined.Settings, R.string.menu_settings) Screen("counter", Icons.Outlined.Calculate, R.string.app_name),
Screen("history", Icons.Outlined.List, R.string.menu_history),
Screen("settings", Icons.Outlined.Settings, R.string.menu_settings)
) )
val navBackStackEntry by navController.currentBackStackEntryAsState() val navBackStackEntry by navController.currentBackStackEntryAsState()
@@ -176,6 +203,7 @@ class MainActivity : BaseActivity() {
ModalNavigationDrawer( ModalNavigationDrawer(
drawerState = drawerState, drawerState = drawerState,
gesturesEnabled = false,
drawerContent = { drawerContent = {
ModalDrawerSheet { ModalDrawerSheet {
@@ -184,7 +212,7 @@ class MainActivity : BaseActivity() {
NavigationDrawerItem( NavigationDrawerItem(
icon = { Icon(Icons.Outlined.RestartAlt, contentDescription = null) }, icon = { Icon(Icons.Outlined.RestartAlt, contentDescription = null) },
colors = NavigationDrawerItemDefaults.colors( colors = NavigationDrawerItemDefaults.colors(
unselectedContainerColor = MaterialTheme.colorScheme.secondaryContainer unselectedContainerColor = MaterialTheme.colorScheme.primaryContainer
), ),
label = { Text(stringResource(R.string.newGame)) }, label = { Text(stringResource(R.string.newGame)) },
selected = false, selected = false,
@@ -192,25 +220,17 @@ class MainActivity : BaseActivity() {
scope.launch { drawerState.close() } scope.launch { drawerState.close() }
mainViewModel.newGame() mainViewModel.newGame()
navController.navigate("counter") { navController.navigate("counter") {
// Pop up to the start destination of the graph to
// avoid building up a large stack of destinations
// on the back stack as users select items
popUpTo(navController.graph.findStartDestination().id) { popUpTo(navController.graph.findStartDestination().id) {
saveState = true saveState = true
} }
// Avoid multiple copies of the same destination when
// reselecting the same item
launchSingleTop = true launchSingleTop = true
// Restore state when reselecting a previously selected item
restoreState = true restoreState = true
} }
}, },
modifier = Modifier.padding(NavigationDrawerItemDefaults.ItemPadding) modifier = Modifier.padding(NavigationDrawerItemDefaults.ItemPadding)
) )
Spacer(Modifier.height(20.dp)) Divider(Modifier.padding(top = 20.dp, bottom = 20.dp))
Divider()
items.forEach { screen -> items.forEach { screen ->
NavigationDrawerItem( NavigationDrawerItem(
@@ -237,9 +257,15 @@ class MainActivity : BaseActivity() {
) )
} }
} }
}, }
content = { MyScaffoldLayout(drawerState, scope, navController) } ) {
) MyScaffoldLayout(
drawerState,
scope,
navController,
counterViewModel.keyboardHidden
) { counterViewModel.keyboardHidden = false }
}
} }
private class Screen(val route: String, val icon: ImageVector, @StringRes val resourceId: Int) private class Screen(val route: String, val icon: ImageVector, @StringRes val resourceId: Int)

View File

@@ -16,4 +16,7 @@ interface DaoBase<T> {
@Delete @Delete
fun delete(entity: T) fun delete(entity: T)
@Delete
fun delete(entity: List<T>)
} }

View File

@@ -13,5 +13,4 @@ data class GameAndScore(
override var gameId: Long, override var gameId: Long,
override var scoreA: Int, override var scoreA: Int,
override var scoreB: Int, override var scoreB: Int,
) : IGame, IRound { ) : IGame, IRound
}

View File

@@ -6,6 +6,9 @@ import kotlinx.coroutines.flow.Flow
@Dao @Dao
interface RoundDao : DaoBase<Round> { interface RoundDao : DaoBase<Round> {
@Query("SELECT * FROM round")
fun getAll(): List<Round>
@Query("SELECT * FROM round WHERE gameId is :gameId") @Query("SELECT * FROM round WHERE gameId is :gameId")
fun getAllForGame(gameId: Long?): List<Round> fun getAllForGame(gameId: Long?): List<Round>
@@ -15,6 +18,7 @@ interface RoundDao : DaoBase<Round> {
"LEFT JOIN game ON game.uid = round.gameId " + "LEFT JOIN game ON game.uid = round.gameId " +
"WHERE game.active == 1" "WHERE game.active == 1"
) )
@SuppressWarnings(RoomWarnings.CURSOR_MISMATCH)
fun getRoundSumForActiveGame(): Flow<Round> fun getRoundSumForActiveGame(): Flow<Round>
@Query( @Query(

View File

@@ -1,7 +1,5 @@
package me.zobrist.tichucounter.domain package me.zobrist.tichucounter.domain
import kotlin.math.abs
fun Int.isMultipleOf5(): Boolean { fun Int.isMultipleOf5(): Boolean {
return (this % 5) == 0 return (this % 5) == 0
@@ -11,6 +9,3 @@ fun Int.isMultipleOf100(): Boolean {
return (this % 100) == 0 return (this % 100) == 0
} }
fun Int.getAbsoluteDifference(other: Int): Int {
return abs(this - other)
}

View File

@@ -1,3 +1,3 @@
package me.zobrist.tichucounter.domain package me.zobrist.tichucounter.domain
class NavigationAction(val aciton: () -> Unit) class NavigationAction(val action: () -> Unit)

View File

@@ -16,13 +16,14 @@ class SettingsAdapter @Inject constructor(@ApplicationContext private val contex
val language: Language val language: Language
get() { get() {
return try {
var setting = sharedPreferences.getString(Language::class.simpleName, null) var setting = sharedPreferences.getString(Language::class.simpleName, null)
if (setting == null) { enumValueOf(setting!!)
setCurrentLanguage() } catch (_: NullPointerException) {
setting = val current = getCurrentAppLanguage()
sharedPreferences.getString(Language::class.simpleName, Language.ENGLISH.name) setLanguage(current)
current
} }
return enumValueOf(setting!!)
} }
val theme: Theme val theme: Theme
@@ -36,30 +37,29 @@ class SettingsAdapter @Inject constructor(@ApplicationContext private val contex
return sharedPreferences.getBoolean("keep_screen_on", false) return sharedPreferences.getBoolean("keep_screen_on", false)
} }
private fun setCurrentLanguage() { private fun getCurrentAppLanguage(): Language {
var setting = when (getApplicationLocales()[0].toString()) { return when (getApplicationLocales()[0].toString()) {
"de" -> Language.GERMAN "de" -> Language.GERMAN
else -> Language.ENGLISH else -> Language.ENGLISH
} }
setLanguage(setting)
} }
fun setLanguage(language: Language) { fun setLanguage(language: Language) {
val editor = sharedPreferences.edit() val editor = sharedPreferences.edit()
editor.putString(Language::class.simpleName, language.name) editor.putString(Language::class.simpleName, language.name)
editor.commit() editor.apply()
} }
fun setTheme(theme: Theme) { fun setTheme(theme: Theme) {
val editor = sharedPreferences.edit() val editor = sharedPreferences.edit()
editor.putString(Theme::class.simpleName, theme.name) editor.putString(Theme::class.simpleName, theme.name)
editor.commit() editor.apply()
} }
fun setKeepScreenOn(setting: Boolean) { fun setKeepScreenOn(setting: Boolean) {
val editor = sharedPreferences.edit() val editor = sharedPreferences.edit()
editor.putBoolean("keep_screen_on", setting) editor.putBoolean("keep_screen_on", setting)
editor.commit() editor.apply()
} }
} }

View File

@@ -5,9 +5,6 @@ import javax.inject.Inject
class Tichu @Inject constructor() { class Tichu @Inject constructor() {
fun calculateOtherScore(score: Int): Int? { fun calculateOtherScore(score: Int): Int? {
if (score == null) {
return null
}
if (!score.isMultipleOf5()) { if (!score.isMultipleOf5()) {
return null return null
} }
@@ -24,6 +21,6 @@ class Tichu @Inject constructor() {
if (scoreA == null || scoreB == null) { if (scoreA == null || scoreB == null) {
return false return false
} }
return (scoreA!!.isMultipleOf5()) && scoreB!!.isMultipleOf5() && (scoreA!! + scoreB!!).isMultipleOf100() return (scoreA.isMultipleOf5()) && scoreB.isMultipleOf5() && (scoreA + scoreB).isMultipleOf100()
} }
} }

View File

@@ -1,55 +0,0 @@
package me.zobrist.tichucounter.framework
import android.util.Log
import androidx.annotation.MainThread
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.Observer
import java.util.concurrent.atomic.AtomicBoolean
/**
* A lifecycle-aware observable that sends only new updates after subscription, used for events like
* navigation and Snackbar messages.
*
*
* This avoids a common problem with events: on configuration change (like rotation) an update
* can be emitted if the observer is active. This LiveData only calls the observable if there's an
* explicit call to setValue() or call().
*
*
* Note that only one observer is going to be notified of changes.
*/
class SingleLiveEvent<T> : MutableLiveData<T>() {
private val pending = AtomicBoolean(false)
@MainThread
override fun observe(owner: LifecycleOwner, observer: Observer<in T>) {
if (hasActiveObservers()) {
Log.w(TAG, "Multiple observers registered but only one will be notified of changes.")
}
// Observe the internal MutableLiveData
super.observe(owner) { t ->
if (pending.compareAndSet(true, false)) {
observer.onChanged(t)
}
}
}
@MainThread
override fun setValue(t: T?) {
pending.set(true)
super.setValue(t)
}
/**
* Used for cases where T is Void, to make calls cleaner.
*/
@MainThread
fun call() {
value = null
}
companion object {
private const val TAG = "me.zobrist.tichucounter.framework.SingleLiveEvent"
}
}

View File

@@ -2,6 +2,7 @@ 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.take
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import me.zobrist.tichucounter.data.Game import me.zobrist.tichucounter.data.Game
@@ -50,7 +51,7 @@ class GameRepository @Inject constructor(
} }
} }
private suspend fun setActive(id: Long) { suspend fun setActive(id: Long) {
withContext(Dispatchers.IO) { withContext(Dispatchers.IO) {
gameDao.setActive(id) gameDao.setActive(id)
gameDao.setOthersInactive(id) gameDao.setOthersInactive(id)
@@ -85,4 +86,34 @@ class GameRepository @Inject constructor(
gameDao.update(active) gameDao.update(active)
} }
} }
suspend fun deleteGame(uid: Long) {
withContext(Dispatchers.IO) {
try {
gameDao.getGameById(uid).take(1).collect() {
gameDao.delete(it)
val rounds = roundDao.getAllForGame(it.uid)
roundDao.delete(rounds)
}
} catch (_: NullPointerException) {
}
}
}
suspend fun deleteAllInactive() {
withContext(Dispatchers.IO) {
try {
gameDao.getAll().take(1).collect() { games ->
val activeId = games.first { it.active }.uid
val gamesToDelete = games.filter { !it.active }
val roundsToDelete = roundDao.getAll().filter { it.gameId != activeId }
gameDao.delete(gamesToDelete)
roundDao.delete(roundsToDelete)
}
} catch (_: NullPointerException) {
}
}
}
} }

View File

@@ -1,3 +1,5 @@
@file:Suppress("unused", "unused", "unused")
package me.zobrist.tichucounter.ui package me.zobrist.tichucounter.ui
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color

View File

@@ -37,7 +37,7 @@ class MainViewModel @Inject constructor(
init { init {
viewModelScope.launch { viewModelScope.launch {
roundDao.getForActiveGame().collect() { roundDao.getForActiveGame().collect {
isUndoActionActive = it.isNotEmpty() isUndoActionActive = it.isNotEmpty()
if (expectedRoundCount != it.count()) { if (expectedRoundCount != it.count()) {
@@ -51,7 +51,7 @@ class MainViewModel @Inject constructor(
fun onNavigateClicked() { fun onNavigateClicked() {
topBarNavigationAction.aciton() topBarNavigationAction.action()
} }
fun undoLastRound() { fun undoLastRound() {
@@ -77,14 +77,16 @@ class MainViewModel @Inject constructor(
} }
} }
fun clearRedoList() {
redoRounds.clear()
}
fun newGame() { fun newGame() {
viewModelScope.launch { viewModelScope.launch {
redoRounds.clear() redoRounds.clear()
gameRepository.newGame() gameRepository.newGame()
} }
} }
fun deleteAllInactiveGames() {
viewModelScope.launch {
gameRepository.deleteAllInactive()
}
}
} }

View File

@@ -75,7 +75,7 @@ private val DarkColors = darkColorScheme(
@Composable @Composable
fun AppTheme( fun AppTheme(
useDarkTheme: Boolean = isSystemInDarkTheme(), useDarkTheme: Boolean = isSystemInDarkTheme(),
content: @Composable() () -> Unit content: @Composable () -> Unit
) { ) {
val dynamicColor = Build.VERSION.SDK_INT >= Build.VERSION_CODES.S val dynamicColor = Build.VERSION.SDK_INT >= Build.VERSION_CODES.S

View File

@@ -61,11 +61,11 @@ fun Landscape(viewModel: ICounterViewModel) {
{ viewModel.digitClicked(it) }, { viewModel.digitClicked(it) },
{ viewModel.addSub100Clicked(it) }, { viewModel.addSub100Clicked(it) },
{ viewModel.deleteClicked() }, { viewModel.deleteClicked() },
{ viewModel.negateClicked() } { viewModel.negateClicked() },
) { viewModel.submitClicked() } { viewModel.submitClicked() },
{ viewModel.keyboardHidden = true })
} }
} }
} }
@Composable @Composable
@@ -89,6 +89,7 @@ fun Portrait(viewModel: ICounterViewModel) {
Modifier.weight(1f) Modifier.weight(1f)
) )
if (!viewModel.keyboardHidden) {
KeyboardView( KeyboardView(
viewModel.currentScoreA, viewModel.currentScoreA,
viewModel.currentScoreB, viewModel.currentScoreB,
@@ -99,8 +100,10 @@ fun Portrait(viewModel: ICounterViewModel) {
{ viewModel.digitClicked(it) }, { viewModel.digitClicked(it) },
{ viewModel.addSub100Clicked(it) }, { viewModel.addSub100Clicked(it) },
{ viewModel.deleteClicked() }, { viewModel.deleteClicked() },
{ viewModel.negateClicked() } { viewModel.negateClicked() },
) { viewModel.submitClicked() } { viewModel.submitClicked() },
{ viewModel.keyboardHidden = true })
}
} }
} }
@@ -129,6 +132,7 @@ internal class PreviewViewModel : ICounterViewModel {
override var requestFocusA: FocusRequester = FocusRequester() override var requestFocusA: FocusRequester = FocusRequester()
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 fun giveFocusToAIfNone() { override fun giveFocusToAIfNone() {
} }

View File

@@ -29,6 +29,7 @@ interface ICounterViewModel {
var requestFocusA: FocusRequester var requestFocusA: FocusRequester
var activeValue: String var activeValue: String
var inactiveValue: String var inactiveValue: String
var keyboardHidden: Boolean
fun giveFocusToAIfNone() fun giveFocusToAIfNone()
fun updateOtherScore() fun updateOtherScore()
@@ -75,6 +76,8 @@ class CounterViewModel @Inject constructor(
override var requestFocusA by mutableStateOf(FocusRequester()) override var requestFocusA by mutableStateOf(FocusRequester())
override var keyboardHidden by mutableStateOf(false)
override var activeValue: String override var activeValue: String
get() { get() {
return if (isBFocused) { return if (isBFocused) {

View File

@@ -5,15 +5,16 @@ import androidx.compose.foundation.layout.*
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.Backspace import androidx.compose.material.icons.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.material3.* import androidx.compose.material3.*
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.ExperimentalComposeUiApi import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.scale
import androidx.compose.ui.focus.FocusRequester import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.focus.focusRequester import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.focus.onFocusChanged import androidx.compose.ui.focus.onFocusChanged
import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.platform.LocalConfiguration
import androidx.compose.ui.platform.LocalSoftwareKeyboardController import androidx.compose.ui.platform.LocalSoftwareKeyboardController
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
@@ -34,7 +35,8 @@ fun KeyboardView(
addSub100Clicked: (Int) -> Unit, addSub100Clicked: (Int) -> Unit,
deleteClicked: () -> Unit, deleteClicked: () -> Unit,
negateClicked: () -> Unit, negateClicked: () -> Unit,
submitClicked: () -> Unit submitClicked: () -> Unit,
hideKeyboardClicked: () -> Unit
) { ) {
val keyboardController = LocalSoftwareKeyboardController.current val keyboardController = LocalSoftwareKeyboardController.current
@@ -137,8 +139,8 @@ fun KeyboardView(
Row { Row {
Column(Modifier.weight(1f)) { Column(Modifier.weight(1f)) {
KeyboardTextButton("+/-") { KeyboardIconButton(Icons.Outlined.KeyboardHide) {
negateClicked() hideKeyboardClicked()
} }
} }
Column(Modifier.weight(1f)) { Column(Modifier.weight(1f)) {
@@ -146,7 +148,13 @@ fun KeyboardView(
digitClicked("0") digitClicked("0")
} }
} }
Column(Modifier.weight(2f)) {
Column(Modifier.weight(1f)) {
KeyboardTextButton("+/-") {
negateClicked()
}
}
Column(Modifier.weight(1f)) {
KeyboardIconButton(Icons.Outlined.Check, enableSubmit) { KeyboardIconButton(Icons.Outlined.Check, enableSubmit) {
submitClicked() submitClicked()
} }
@@ -157,10 +165,24 @@ fun KeyboardView(
@Composable @Composable
fun KeyboardTextButton(text: String, onClicked: () -> Unit) { fun KeyboardTextButton(text: String, onClicked: () -> Unit) {
val configuration = LocalConfiguration.current
val screenWidth = configuration.screenWidthDp.dp
val style = if (screenWidth < 350.dp) {
MaterialTheme.typography.labelSmall
} else {
MaterialTheme.typography.labelLarge
}
ElevatedButton( ElevatedButton(
modifier = Modifier.fillMaxWidth().height(50.dp).padding(2.dp), modifier = Modifier
.fillMaxWidth()
.height(50.dp)
.padding(2.dp),
onClick = { onClicked() }, onClick = { onClicked() },
) { Text(text) } ) { Text(text, style = style) }
} }
@Composable @Composable
@@ -168,7 +190,10 @@ fun KeyboardIconButton(icon: ImageVector, enabled: Boolean = true, onClicked: ()
ElevatedButton( ElevatedButton(
onClick = { onClicked() }, onClick = { onClicked() },
modifier = Modifier.fillMaxWidth().height(50.dp).padding(2.dp), modifier = Modifier
.fillMaxWidth()
.height(50.dp)
.padding(2.dp),
enabled = enabled, enabled = enabled,
) { ) {
Icon( Icon(
@@ -220,6 +245,7 @@ fun KeyboardViewPreview() {
{}, {},
{}, {},
{}, {},
{},
{}) {})
} }
} }

View File

@@ -5,7 +5,6 @@ import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
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.itemsIndexed import androidx.compose.foundation.lazy.itemsIndexed
import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
@@ -28,7 +27,7 @@ fun RoundListView(rounds: List<Round>, modifier: Modifier) {
LazyColumn(state = lazyListState, modifier = modifier) { LazyColumn(state = lazyListState, modifier = modifier) {
itemsIndexed(rounds) { index, item -> itemsIndexed(rounds) { index, item ->
RoundListItem(item, index, lazyListState) RoundListItem(item, index)
} }
scope.launch { scope.launch {
@@ -38,7 +37,7 @@ fun RoundListView(rounds: List<Round>, modifier: Modifier) {
} }
@Composable @Composable
private fun RoundListItem(round: Round, index: Int, lazyListState: LazyListState) { private fun RoundListItem(round: Round, index: Int) {
Row( Row(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
@@ -51,7 +50,7 @@ private fun RoundListItem(round: Round, index: Int, lazyListState: LazyListState
textAlign = TextAlign.Center textAlign = TextAlign.Center
) )
Text( Text(
text = index.toString(), text = (index + 1).toString(),
style = MaterialTheme.typography.bodyMedium, style = MaterialTheme.typography.bodyMedium,
modifier = Modifier.weight(1f), modifier = Modifier.weight(1f),
textAlign = TextAlign.Center textAlign = TextAlign.Center

View File

@@ -8,6 +8,7 @@ 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
import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import me.zobrist.tichucounter.ui.AppTheme import me.zobrist.tichucounter.ui.AppTheme
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@@ -18,13 +19,19 @@ fun TeamNamesView(
updateA: (String) -> Unit, updateA: (String) -> Unit,
updateB: (String) -> Unit updateB: (String) -> Unit
) { ) {
Row() {
val color = TextFieldDefaults.textFieldColors(
containerColor = MaterialTheme.colorScheme.surfaceColorAtElevation(1.dp)
)
Row {
TextField( TextField(
value = nameA, value = nameA,
textStyle = LocalTextStyle.current.copy(textAlign = TextAlign.Center), textStyle = LocalTextStyle.current.copy(textAlign = TextAlign.Center),
onValueChange = { updateA(it) }, onValueChange = { updateA(it) },
singleLine = true, singleLine = true,
modifier = Modifier.weight(1f) modifier = Modifier.weight(1f),
colors = color
) )
TextField( TextField(
@@ -32,7 +39,8 @@ fun TeamNamesView(
textStyle = LocalTextStyle.current.copy(textAlign = TextAlign.Center), textStyle = LocalTextStyle.current.copy(textAlign = TextAlign.Center),
onValueChange = { updateB(it) }, onValueChange = { updateB(it) },
singleLine = true, singleLine = true,
modifier = Modifier.weight(1f) modifier = Modifier.weight(1f),
colors = color
) )
} }
} }

View File

@@ -4,10 +4,7 @@ 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.ElevatedCard import androidx.compose.material3.*
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
@@ -19,8 +16,8 @@ import me.zobrist.tichucounter.ui.AppTheme
@Composable @Composable
fun TeamScoresView(scoreA: Int, scoreB: Int) { fun TeamScoresView(scoreA: Int, scoreB: Int) {
ElevatedCard() { ElevatedCard(elevation = CardDefaults.elevatedCardElevation(3.dp)) {
Row() { Row {
Text( Text(
style = MaterialTheme.typography.headlineSmall, style = MaterialTheme.typography.headlineSmall,
text = scoreA.toString(), text = scoreA.toString(),

View File

@@ -1,78 +1,142 @@
package me.zobrist.tichucounter.ui.history package me.zobrist.tichucounter.ui.history
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.*
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
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.material3.Card import androidx.compose.material.icons.Icons
import androidx.compose.material3.MaterialTheme import androidx.compose.material.icons.outlined.Delete
import androidx.compose.material3.Text import androidx.compose.material.icons.outlined.OpenInFull
import androidx.compose.material3.*
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
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.data.GameAndScore import me.zobrist.tichucounter.data.GameAndScore
import java.text.DateFormat import java.text.DateFormat
import java.util.* import java.util.*
@Composable @Composable
fun HistoryList(viewModel: HistoryViewModel) { fun HistoryList(
HistoryList(viewModel.gameAndHistory) viewModel: HistoryViewModel,
showDeleteDialog: Boolean,
onDialogExecuted: (Boolean) -> Unit,
navigateToCalculator: () -> Unit
) {
DeleteConfirmDialog(showDeleteDialog, onDialogExecuted)
HistoryList(viewModel.gameAndHistory,
{
viewModel.activateGame(it)
navigateToCalculator()
},
{ viewModel.deleteGame(it) })
}
@Preview
@Composable
fun DeleteConfirmDialog(show: Boolean = true, onExecuted: (Boolean) -> Unit = {}) {
if (show) {
AlertDialog(
onDismissRequest = { onExecuted(false) },
dismissButton = {
TextButton({ onExecuted(false) })
{
Text(stringResource(R.string.cancel))
}
},
confirmButton = {
TextButton({ onExecuted(true) })
{
Text(stringResource(R.string.ok))
}
},
title = { Text(stringResource(R.string.delete_inactive_title)) },
text = { Text(stringResource(R.string.delete_inactive_text)) },
)
}
} }
@Composable @Composable
fun HistoryList(games: List<GameAndScore>) { fun HistoryList(
games: List<GameAndScore>,
onOpenClicked: (GameId: Long) -> Unit,
onDeleteClicked: (GameId: Long) -> Unit
) {
Row {
LazyColumn { LazyColumn {
items(games) { items(games) {
HistoryListItem(it) HistoryListItem(it, onOpenClicked, onDeleteClicked)
}
} }
} }
} }
@Composable @Composable
fun HistoryListItem(game: GameAndScore) { fun HistoryListItem(
game: GameAndScore,
onOpenClicked: (GameId: Long) -> Unit,
onDeleteClicked: (GameId: Long) -> Unit
) {
val format = val format =
DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.SHORT, Locale.getDefault()) DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.SHORT, Locale.getDefault())
val cardColor = if (game.active) {
CardDefaults.cardColors(containerColor = MaterialTheme.colorScheme.secondaryContainer)
} else {
CardDefaults.cardColors()
}
Card( Card(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.padding(all = 4.dp), .padding(all = 4.dp),
colors = cardColor
) { ) {
Column( Row(
Modifier Modifier
.padding(all = 12.dp), .padding(all = 12.dp)
) { ) {
Row() { Column(Modifier.weight(4f)) {
Text( Text(
text = game.nameA, text = game.nameA + " vs " + game.nameB,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
style = MaterialTheme.typography.headlineSmall style = MaterialTheme.typography.headlineSmall
) )
Text( Text(
text = game.scoreA.toString(), text = game.scoreA.toString() + " : " + game.scoreB.toString(),
style = MaterialTheme.typography.headlineSmall style = MaterialTheme.typography.bodyLarge
) )
} Spacer(modifier = Modifier.padding(5.dp))
Row() {
Text(
text = game.nameB,
style = MaterialTheme.typography.headlineSmall
)
Text(
text = game.scoreB.toString(),
style = MaterialTheme.typography.headlineSmall
)
}
Row() {
Text( Text(
text = format.format(game.modified), text = format.format(game.modified),
style = MaterialTheme.typography.labelSmall style = MaterialTheme.typography.labelSmall
) )
} }
Column(
Modifier
.wrapContentSize()
.width(70.dp)
) {
ElevatedButton(onClick = { onOpenClicked(game.gameId) }, enabled = true) {
Icon(Icons.Outlined.OpenInFull, null)
}
ElevatedButton(
onClick = { onDeleteClicked(game.gameId) }, enabled = !game.active
) {
Icon(Icons.Outlined.Delete, null)
}
}
} }
} }
} }
@@ -80,12 +144,12 @@ fun HistoryListItem(game: GameAndScore) {
@Preview @Preview
@Composable @Composable
private fun HistoryListPreview() { private fun HistoryListPreview() {
val tempData = listOf<GameAndScore>( val tempData = listOf(
GameAndScore(false, "abc", "def", Date(), Date(), 1, 10, 50), GameAndScore(true, "abc", "def", Date(), Date(), 1, 10, 50),
GameAndScore(true, "ADTH", "dogfg", Date(), Date(), 2, 20, 60), GameAndScore(false, "ADTH", "dogfg", Date(), Date(), 2, 20, 60),
GameAndScore(false, "TeamA3", "TeamB3", Date(), Date(), 3, 30, 70), GameAndScore(false, "TeamA3 langer Name", "TeamB3", Date(), Date(), 3, 30, 70),
GameAndScore(false, "TeamA4", "TeamB4", Date(), Date(), 4, 40, 80), GameAndScore(false, "TeamA4", "TeamB4", Date(), Date(), 4, 40, 80),
GameAndScore(false, "TeamA5", "TeamB5", Date(), Date(), 5, 50, 90) GameAndScore(false, "TeamA5", "TeamB5", Date(), Date(), 5, 50, 90)
) )
HistoryList(tempData) HistoryList(tempData, {}) {}
} }

View File

@@ -9,12 +9,14 @@ import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import me.zobrist.tichucounter.data.GameAndScore import me.zobrist.tichucounter.data.GameAndScore
import me.zobrist.tichucounter.data.GameDao import me.zobrist.tichucounter.data.GameDao
import me.zobrist.tichucounter.repository.GameRepository
import javax.inject.Inject import javax.inject.Inject
@HiltViewModel @HiltViewModel
class HistoryViewModel @Inject constructor( class HistoryViewModel @Inject constructor(
private val gameDao: GameDao private val gameDao: GameDao,
private val gameRepository: GameRepository
) : ViewModel() { ) : ViewModel() {
var gameAndHistory by mutableStateOf(emptyList<GameAndScore>()) var gameAndHistory by mutableStateOf(emptyList<GameAndScore>())
@@ -27,4 +29,17 @@ class HistoryViewModel @Inject constructor(
} }
} }
} }
fun deleteGame(gameId: Long) {
viewModelScope.launch {
gameRepository.deleteGame(gameId)
}
}
fun activateGame(gameId: Long) {
viewModelScope.launch {
gameRepository.setActive(gameId)
}
}
} }

View File

@@ -2,7 +2,10 @@ package me.zobrist.tichucounter.ui.settings
import android.content.res.Configuration import android.content.res.Configuration
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.fillMaxWidth
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.material.icons.outlined.Check import androidx.compose.material.icons.outlined.Check
@@ -52,7 +55,7 @@ fun SettingsView(
updateLanguage: (Language) -> Unit = {}, updateLanguage: (Language) -> Unit = {},
updateTheme: (Theme) -> Unit = {} updateTheme: (Theme) -> Unit = {}
) { ) {
Column() { Column {
BooleanSetting( BooleanSetting(
stringResource(R.string.keep_screen_on), stringResource(R.string.keep_screen_on),
valueScreenOn valueScreenOn
@@ -72,7 +75,6 @@ fun SettingsView(
} }
} }
@OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
fun BooleanSetting(name: String, value: Boolean, updateValue: (Boolean) -> Unit) { fun BooleanSetting(name: String, value: Boolean, updateValue: (Boolean) -> Unit) {
@@ -153,8 +155,8 @@ fun <T> StringSetting(name: String, map: Map<T, Int>, selected: T, onSelected: (
@Composable @Composable
fun SettingsViewPreview() { fun SettingsViewPreview() {
AppTheme() { AppTheme {
Surface() { Surface {
SettingsView() SettingsView()
} }
} }

View File

@@ -1,12 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M12,12m-3.2,0a3.2,3.2 0,1 1,6.4 0a3.2,3.2 0,1 1,-6.4 0" />
<path
android:fillColor="#FF000000"
android:pathData="M9,2L7.17,4H4c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2V6c0,-1.1 -0.9,-2 -2,-2h-3.17L15,2H9zm3,15c-2.76,0 -5,-2.24 -5,-5s2.24,-5 5,-5 5,2.24 5,5 -2.24,5 -5,5z" />
</vector>

View File

@@ -1,9 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M22,16V4c0,-1.1 -0.9,-2 -2,-2H8c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2zm-11,-4l2.03,2.71L16,11l4,5H8l3,-4zM2,6v14c0,1.1 0.9,2 2,2h14v-2H4V6H2z" />
</vector>

View File

@@ -1,9 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M4,6H2v14c0,1.1 0.9,2 2,2h14v-2H4V6zm16,-4H8c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2V4c0,-1.1 -0.9,-2 -2,-2zm-8,12.5v-9l6,4.5 -6,4.5z" />
</vector>

View File

@@ -1,10 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="#FFFFFF"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@color/primaryColor"
android:pathData="M19,13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z" />
</vector>

View File

@@ -1,11 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:autoMirrored="true"
android:tint="#FFFFFF"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@color/primaryColor"
android:pathData="M12.5,8c-2.65,0 -5.05,0.99 -6.9,2.6L2,7v9h9l-3.62,-3.62c1.39,-1.16 3.16,-1.88 5.12,-1.88 3.54,0 6.55,2.31 7.6,5.5l2.37,-0.78C21.08,11.03 17.15,8 12.5,8z" />
</vector>

View File

@@ -1,9 +0,0 @@
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<gradient
android:angle="135"
android:centerColor="#009688"
android:endColor="#00695C"
android:startColor="#4DB6AC"
android:type="linear" />
</shape>

View File

@@ -1,29 +1,23 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources> <resources>
<string name="clear">Neues Spiel starten</string>
<string name="undo">Letzte Runde löschen</string>
<string name="choose_theme_text">Theme auswählen</string> <string name="choose_theme_text">Theme auswählen</string>
<string name="keep_screen_on">Bildschirm eingeschaltet lassen</string> <string name="keep_screen_on">Bildschirm eingeschaltet lassen</string>
<string name="confirmNew">Möchten Sie wirklich ein neues Spiel starten?</string>
<string name="yes">Ja</string>
<string name="no">Nein</string>
<string name="back">Zurück</string>
<string name="choose_language_text">Sprache wählen</string> <string name="choose_language_text">Sprache wählen</string>
<string name="android_default_text">Android Standard</string> <string name="android_default_text">Android Standard</string>
<string name="english">Englisch</string> <string name="english">Englisch</string>
<string name="german">Deutsch</string> <string name="german">Deutsch</string>
<string name="light">Hell</string> <string name="light">Hell</string>
<string name="dark">Dunkel</string> <string name="dark">Dunkel</string>
<string name="settings">Einstellungen</string>
<string name="display">Anzeige</string>
<string name="activate">Aktivieren</string>
<string name="delete">Löschen</string>
<string name="menu_history">Verlauf</string> <string name="menu_history">Verlauf</string>
<string name="menu_settings">Einstellungen</string> <string name="menu_settings">Einstellungen</string>
<string name="menu_counter">Counter</string>
<string name="submit">Übermitteln</string>
<string name="on">Ein</string> <string name="on">Ein</string>
<string name="off">Aus</string> <string name="off">Aus</string>
<string name="newGame">Neues Spiel</string> <string name="newGame">Neues Spiel</string>
<string name="created">"Erstellt: %s "</string>
<string name="modified">Bearbeitet: %s</string>
<string name="delete_inactive_title">Verlauf löschen</string>
<string name="delete_inactive_text">Wirklich den gesamten Verlauf löschen? Diese Aktion kann nicht rückgängig gemacht werden.</string>
<string name="cancel">Abbrechen</string>
<string name="ok">Ok</string>
</resources> </resources>

View File

@@ -1,3 +0,0 @@
<resources>
<dimen name="fab_margin">48dp</dimen>
</resources>

View File

@@ -1,3 +0,0 @@
<resources>
<dimen name="fab_margin">200dp</dimen>
</resources>

View File

@@ -1,3 +0,0 @@
<resources>
<dimen name="fab_margin">48dp</dimen>
</resources>

View File

@@ -1,12 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources> <resources>
<color name="primaryColor">#d50000</color> <color name="primaryColor">#d50000</color>
<color name="primaryLightColor">#ff5131</color>
<color name="primaryDarkColor">#9b0000</color>
<color name="secondaryColor">#ffccbc</color>
<color name="secondaryLightColor">#ffffee</color>
<color name="secondaryDarkColor">#cb9b8c</color>
<color name="primaryTextColor">#ffffff</color>
<color name="secondaryTextColor">#000000</color>
</resources> </resources>

View File

@@ -1,9 +0,0 @@
<resources>
<!-- Default screen margins, per the Android Design guidelines. -->
<dimen name="activity_horizontal_margin">16dp</dimen>
<dimen name="activity_vertical_margin">16dp</dimen>
<dimen name="nav_header_vertical_spacing">8dp</dimen>
<dimen name="nav_header_height">176dp</dimen>
<dimen name="fab_margin">16dp</dimen>
<dimen name="text_margin">16dp</dimen>
</resources>

View File

@@ -1,8 +0,0 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android">
<item name="ic_menu_camera" type="drawable">@android:drawable/ic_menu_camera</item>
<item name="ic_menu_gallery" type="drawable">@android:drawable/ic_menu_gallery</item>
<item name="ic_menu_slideshow" type="drawable">@android:drawable/ic_menu_slideshow</item>
<item name="ic_menu_manage" type="drawable">@android:drawable/ic_menu_manage</item>
<item name="ic_menu_share" type="drawable">@android:drawable/ic_menu_share</item>
<item name="ic_menu_send" type="drawable">@android:drawable/ic_menu_send</item>
</resources>

View File

@@ -1,34 +1,25 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources> <resources>
<string name="app_name" translatable="false">Tichu Counter</string> <string name="app_name" translatable="false">Tichu Counter</string>
<string name="team_a" translatable="false">Team A</string>
<string name="team_b" translatable="false">Team B</string>
<string name="title_activity_settings" translatable="false">SettingsActivity</string>
<string name="clear">Start new game</string>
<string name="undo">Undo last round</string>
<string name="choose_theme_text">Choose theme</string> <string name="choose_theme_text">Choose theme</string>
<string name="keep_screen_on">Keep screen on</string> <string name="keep_screen_on">Keep screen on</string>
<string name="confirmNew">Do you really want to start a new Game?</string>
<string name="yes">Yes</string>
<string name="no">No</string>
<string name="back">Back</string>
<string name="choose_language_text">Choose language</string> <string name="choose_language_text">Choose language</string>
<string name="android_default_text">Android Default</string> <string name="android_default_text">Android Default</string>
<string name="english">English</string> <string name="english">English</string>
<string name="german">German</string> <string name="german">German</string>
<string name="light">Light</string> <string name="light">Light</string>
<string name="dark">Dark</string> <string name="dark">Dark</string>
<string name="display">Display</string>
<string name="settings">Settings</string>
<string name="menu_counter">Counter</string>
<string name="menu_history">History</string> <string name="menu_history">History</string>
<string name="menu_settings">Settings</string> <string name="menu_settings">Settings</string>
<string name="activate">Activate</string>
<string name="delete">Delete</string>
<string name="submit">Submit</string>
<string name="on">On</string> <string name="on">On</string>
<string name="off">Off</string> <string name="off">Off</string>
<string name="newGame">New Game</string> <string name="newGame">New Game</string>
<string name="created">Created: %s</string>
<string name="modified">Modified: %s</string>
<string name="delete_inactive_title">Delete history</string>
<string name="delete_inactive_text">You really want to delete the the history? This action can\'t be undone.</string>
<string name="cancel">Cancel</string>
<string name="ok">Ok</string>
</resources> </resources>

View File

@@ -1,8 +1,5 @@
<resources> <resources>
<style name="AppTheme" parent="Theme.MaterialComponents.DayNight.NoActionBar"></style> <style name="AppTheme" parent="Theme.MaterialComponents.DayNight.NoActionBar" />
<style name="AppTheme.AppBarOverlay" parent="ThemeOverlay.MaterialComponents.Dark.ActionBar" />
<style name="AppTheme.PopupOverlay" parent="ThemeOverlay.MaterialComponents.Light" />
</resources> </resources>