9 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
10 changed files with 168 additions and 116 deletions

View File

@@ -1,89 +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: upload latest apk
image: vividboarder/drone-webdav
settings:
file: app/build/outputs/apk/release/app-release.apk
destination: https://nextcloud.zobrist.me/remote.php/dav/files/deploy/TichuCounter/latest/app-release.apk
username:
from_secret: NextCloudUser
password:
from_secret: NextCloudPassword
- name: upload latest bundle
image: vividboarder/drone-webdav
settings:
file: app/build/outputs/bundle/release/app-release.aab
destination: https://nextcloud.zobrist.me/remote.php/dav/files/deploy/TichuCounter/latest/app-release.aab
username:
from_secret: NextCloudUser
password:
from_secret: NextCloudPassword
- name: upload tagged apk
image: vividboarder/drone-webdav
settings:
file: app/build/outputs/apk/release/app-release.apk
destination: 'https://nextcloud.zobrist.me/remote.php/dav/files/deploy/TichuCounter/tagged/app-release$DRONE_TAG.apk'
username:
from_secret: NextCloudUser
password:
from_secret: NextCloudPassword
when:
event:
- tag
- name: upload tagged bundle
image: vividboarder/drone-webdav
settings:
file: app/build/outputs/bundle/release/app-release.aab
destination: 'https://nextcloud.zobrist.me/remote.php/dav/files/deploy/TichuCounter/tagged/app-release$DRONE_TAG.aab'
username:
from_secret: NextCloudUser
password:
from_secret: NextCloudPassword
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

@@ -37,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

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

@@ -52,6 +52,7 @@ fun Landscape(viewModel: ICounterViewModel) {
RoundListView( RoundListView(
viewModel.roundScoreList, viewModel.roundScoreList,
viewModel.sumUpScores,
Modifier.weight(1f) Modifier.weight(1f)
) )
} }
@@ -83,6 +84,7 @@ fun Portrait(viewModel: ICounterViewModel) {
RoundListView( RoundListView(
viewModel.roundScoreList, viewModel.roundScoreList,
viewModel.sumUpScores,
Modifier.weight(1f) Modifier.weight(1f)
) )
@@ -109,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

View File

@@ -11,9 +11,7 @@ import kotlinx.coroutines.Job
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
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
@@ -53,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>
@@ -64,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
@@ -80,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
@@ -181,6 +184,12 @@ class CounterViewModel @Inject constructor(
buildTeamNameSuggestions() buildTeamNameSuggestions()
} }
} }
settingsAdapter.registerOnChangeListener(this)
}
override fun onCleared() {
settingsAdapter.unregisterOnChangeListener(this)
} }
override fun focusLastInput() { override fun focusLastInput() {
@@ -362,4 +371,8 @@ class CounterViewModel @Inject constructor(
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

@@ -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

@@ -25,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
@@ -44,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) {
@@ -51,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
@@ -61,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(
@@ -82,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

@@ -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>