This commit is contained in:
2025-11-25 14:20:32 +01:00
commit 3d642622f2
52 changed files with 1643 additions and 0 deletions

View File

@@ -0,0 +1,24 @@
package com.petrovv.gogameclock
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.ext.junit.runners.AndroidJUnit4
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.Assert.*
/**
* Instrumented test, which will execute on an Android device.
*
* See [testing documentation](http://d.android.com/tools/testing).
*/
@RunWith(AndroidJUnit4::class)
class ExampleInstrumentedTest {
@Test
fun useAppContext() {
// Context of the app under test.
val appContext = InstrumentationRegistry.getInstrumentation().targetContext
assertEquals("com.petrovv.gogameclock", appContext.packageName)
}
}

View File

@@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<application
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.GoGameClock">
<activity
android:name=".MainActivity"
android:exported="true"
android:label="@string/app_name"
android:theme="@style/Theme.GoGameClock">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>

View File

@@ -0,0 +1,52 @@
package com.petrovv.gogameclock
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.compose.ui.graphics.Color
class AbsoluteTiming(initialTime: Long = 1200) : IClock {
val byoyomiTime : Long = 5 * 1000
override var timedOut by mutableStateOf(false)
val timer = Timer(initialTime) {
timedOut = true
}
override fun start() {
timer.start()
}
override fun stop() {
timer.stop()
}
override fun updateMoviesAndStop() {
if(!timer.isRunning()) return
timer.stop()
}
override fun reset() {
timer.reset()
timedOut = false
}
override fun isRunning(): Boolean {
return timer.isRunning()
}
override fun update() {
timer.update()
}
override fun color(): Color {
if(timedOut){ return Colors.loss}
if(!timer.isRunning()) return Colors.stopped
if(timer.timeMillis < byoyomiTime) return Colors.byoyomi
return Colors.running
}
override fun display(): String {
return timer.toString()
}
}

View File

@@ -0,0 +1,76 @@
package com.petrovv.gogameclock
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.compose.ui.graphics.Color
class CanadianTiming(
private val initialTime: Long = 1200,
private val byoyomiTime : Long = 600,
private val maxByoyomiMoves: Long = 25
) : IClock {
var mainTime by mutableStateOf(true)
var byoyomi by mutableStateOf(false)
var byoyomiC : Long = 0
override var timedOut by mutableStateOf(false)
val timer: Timer = Timer(initialTime) {
if(mainTime){
byoyomi = true
mainTime = false
timer.reset(byoyomiTime)
timer.start()
return@Timer
}
timedOut = true
}
override fun start() {
timer.start()
}
override fun stop() {
timer.stop()
}
override fun updateMoviesAndStop() {
if(!timer.isRunning()) return
timer.stop()
if(byoyomi){
byoyomiC += 1
if(byoyomiC == maxByoyomiMoves){
timer.reset()
byoyomiC = 0
}
}
}
override fun reset() {
timer.reset(initialTime)
timedOut = false
byoyomiC = 0
mainTime = true
byoyomi = false
}
override fun isRunning(): Boolean {
return timer.isRunning()
}
override fun update() {
timer.update()
}
override fun color(): Color {
if(timedOut){ return Colors.loss}
if(!timer.isRunning()) return Colors.stopped
if(byoyomi) return Colors.byoyomi
return Colors.running
}
override fun display(): String {
val timerS = timer.toString()
return "%s\n%02d".format(timerS, maxByoyomiMoves - byoyomiC)
}
}

View File

@@ -0,0 +1,11 @@
package com.petrovv.gogameclock
import androidx.compose.ui.graphics.Color
object Colors {
val stopped = Color.Gray
val running = Color.Green
val byoyomi = Color.hsv(35f, 1f, 1f)
val loss = Color.Red
val win = Color.Green
}

View File

@@ -0,0 +1,57 @@
package com.petrovv.gogameclock
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.compose.ui.graphics.Color
class FischerTiming(
initialTime: Long = 600,
private val fischerIncrement: Long = 10
) : IClock {
val fischerIncrementMillis: Long = fischerIncrement * 1000
override var timedOut by mutableStateOf(false)
val timer = Timer(initialTime) {
timedOut = true
}
override fun start() {
timer.start()
}
override fun stop() {
timer.stop()
}
override fun updateMoviesAndStop() {
if(!timer.isRunning()) return
timer.stop()
timer.addTime(fischerIncrement)
}
override fun reset() {
timer.reset()
timedOut = false
}
override fun isRunning(): Boolean {
return timer.isRunning()
}
override fun update() {
timer.update()
}
override fun color(): Color {
if(timedOut){ return Colors.loss}
if(!timer.isRunning()) return Colors.stopped
if(timer.timeMillis < fischerIncrementMillis) return Colors.byoyomi
return Colors.running
}
override fun display(): String {
val timerS = timer.toString()
return "%s\n+%02d".format(timerS, fischerIncrement)
}
}

View File

@@ -0,0 +1,17 @@
package com.petrovv.gogameclock
import androidx.compose.ui.graphics.Color
interface IClock {
fun start()
fun stop()
fun reset()
fun isRunning(): Boolean
fun update()
fun display(): String
fun updateMoviesAndStop()
val timedOut: Boolean
fun color(): Color
}

View File

@@ -0,0 +1,79 @@
package com.petrovv.gogameclock
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.compose.ui.graphics.Color
class JapanTiming(
private val initialTime: Long = 1200,
byoyomiTime : Long = 30,
private val maxByoyomi: Long = 5
) : IClock {
var mainTime by mutableStateOf(true)
var byoyomi by mutableStateOf(false)
var byoyomiC = maxByoyomi
override var timedOut by mutableStateOf(false)
val timer: Timer = Timer(initialTime) {
if(mainTime){
byoyomi = true
mainTime = false
}
if (byoyomi) {
timer.reset(byoyomiTime)
timer.start()
byoyomiC -= 1
if(byoyomiC == 0L){
byoyomi = false
}
return@Timer
}
timedOut = true
}
override fun start() {
timer.start()
}
override fun stop() {
timer.stop()
}
override fun updateMoviesAndStop() {
if(!timer.isRunning()) return
timer.stop()
if(byoyomi){
timer.reset()
}
}
override fun reset() {
timer.reset(initialTime)
timedOut = false
byoyomiC = maxByoyomi
mainTime = true
byoyomi = false
}
override fun isRunning(): Boolean {
return timer.isRunning()
}
override fun update() {
timer.update()
}
override fun color(): Color {
if(timedOut){ return Colors.loss}
if(!timer.isRunning()) return Colors.stopped
if(byoyomiC < maxByoyomi) return Colors.byoyomi
return Colors.running
}
override fun display(): String {
val timerS = timer.toString()
return "%s\n%02d".format(timerS, byoyomiC)
}
}

View File

@@ -0,0 +1,168 @@
package com.petrovv.gogameclock
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.material3.Button
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.navigation.NavController
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.rememberNavController
import kotlinx.coroutines.delay
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
setContent {
var player1Clock : IClock = remember { CanadianTiming() }
var player2Clock : IClock = remember { CanadianTiming() }
val navController = rememberNavController()
NavHost(navController = navController, startDestination = "clock") {
composable("clock") {
Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding ->
ChessClock(
navController = navController,
modifier = Modifier.padding(innerPadding),
player1Clock = player1Clock,
player2Clock = player2Clock,
)
}
}
composable("settings") {
SettingsScreen(
onTimingChange = { clock1, clock2 ->
player1Clock = clock1
player2Clock = clock2
navController.popBackStack()
}
)
}
}
}
}
}
@Composable
fun ChessClock(
navController: NavController,
modifier: Modifier = Modifier,
player1Clock : IClock,
player2Clock : IClock,
) {
LaunchedEffect(Unit) {
while (true) {
delay(50) // for UI update
player1Clock.update()
player2Clock.update()
}
}
fun player1() {
if(player1Clock.timedOut) return
player1Clock.updateMoviesAndStop()
player2Clock.start()
}
fun player2() {
if(player2Clock.timedOut) return
player2Clock.updateMoviesAndStop()
player1Clock.start()
}
Column(
modifier = modifier.fillMaxSize(),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center
) {
PlayerClock(
time = player1Clock.display(),
color = player1Clock.color(),
onSwitch = ::player1,
rotation = 180f,
modifier = Modifier.weight(1f)
)
Spacer(modifier = Modifier.height(64.dp))
Row(horizontalArrangement = Arrangement.Center) {
Button(onClick = {
player1Clock.stop()
player2Clock.stop()
}) {
Text(text = "Stop")
}
Spacer(modifier = Modifier.width(16.dp))
Button(onClick = {
player1Clock.reset()
player2Clock.reset()
}) {
Text(text = "Reset")
}
Spacer(modifier = Modifier.width(16.dp))
Button(onClick = {
navController.navigate("settings")
player1Clock.stop()
player2Clock.stop()
}) {
Text(text = "Settings")
}
}
Spacer(modifier = Modifier.height(64.dp))
PlayerClock(
time = player2Clock.display(),
color = player2Clock.color(),
onSwitch = ::player2,
modifier = Modifier.weight(1f)
)
}
}
@Composable
fun PlayerClock(
time: String,
color: Color,
onSwitch: () -> Unit,
modifier: Modifier = Modifier,
rotation: Float = 0f
) {
Box(
modifier = modifier
.fillMaxSize()
.graphicsLayer(rotationZ = rotation)
.background(color)
.clickable(
interactionSource = remember { MutableInteractionSource() },
indication = null,
onClick = onSwitch
)
.padding(16.dp),
contentAlignment = Alignment.Center
) {
Text(text = time, fontSize = 96.sp)
}
}

View File

@@ -0,0 +1,162 @@
package com.petrovv.gogameclock
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.selection.selectable
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material3.Button
import androidx.compose.material3.RadioButton
import androidx.compose.material3.Text
import androidx.compose.material3.TextField
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
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.unit.dp
enum class TimingOption(val displayName: String) {
Absolute("Absolute Timing"),
Fischer("Fischer Timing"),
Canadian("Canadian Timing"),
Japan("Japan Timing"),
}
@Composable
fun SettingsScreen(
modifier: Modifier = Modifier,
onTimingChange: (IClock, IClock) -> Unit
) {
var t1 by remember { mutableStateOf("1200") }
var t2 by remember { mutableStateOf("60") }
var t3 by remember { mutableStateOf("25") }
val timingOptions = remember { TimingOption.entries }
var selectedTiming by remember { mutableStateOf(TimingOption.Absolute) }
Column(
modifier = modifier.fillMaxSize(),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
Text(text = "Settings")
Spacer(modifier = Modifier.height(16.dp))
TextField(
value = t1,
onValueChange = { t1 = it },
label = { Text("Main time (s)") },
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number),
)
Column {
timingOptions.forEach { timingType ->
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier
.selectable(
selected = (timingType == selectedTiming),
onClick = { selectedTiming = timingType }
)
.padding(horizontal = 16.dp)
) {
RadioButton(
selected = (timingType == selectedTiming),
onClick = { selectedTiming = timingType }
)
Text(
text = timingType.displayName,
modifier = Modifier.padding(start = 16.dp)
)
}
}
}
var text1 = ""
var text2 = ""
var show1 = false
var show2 = false
when (selectedTiming) {
TimingOption.Absolute -> {}
TimingOption.Fischer -> {
text1 = "Increment (s)"
show1 = true
}
TimingOption.Canadian -> {
text1 = "byo-yomi time (s)"
text2 = "byo-yomi stones"
show1 = true
show2 = true
}
TimingOption.Japan -> {
text1 = "byo-yomi time (s)"
text2 = "byo-yomi periods"
show1 = true
show2 = true
}
}
if (show1) {
Spacer(modifier = Modifier.height(8.dp))
TextField(
value = t2,
onValueChange = { t2 = it },
label = { Text(text1) },
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number)
)
}
if (show2) {
Spacer(modifier = Modifier.height(8.dp))
TextField(
value = t3,
onValueChange = { t3 = it },
label = { Text(text2) },
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number)
)
}
Spacer(modifier = Modifier.height(16.dp))
Button(onClick = {
val v1 = t1.toLongOrNull() ?: 25
val v2 = t2.toLongOrNull() ?: 25
val v3 = t3.toLongOrNull() ?: 25
when (selectedTiming) {
TimingOption.Absolute -> onTimingChange(AbsoluteTiming(v1), AbsoluteTiming(v1))
TimingOption.Fischer -> {
onTimingChange(
FischerTiming(v1, v2),
FischerTiming(v1, v2)
)
}
TimingOption.Canadian -> {
onTimingChange(
CanadianTiming(v1, v2, v3),
CanadianTiming(v1, v2, v3)
)
}
TimingOption.Japan -> {
onTimingChange(
JapanTiming(v1, v2, v3),
JapanTiming(v1, v2, v3)
)
}
}
}) {
Text(text = "Start Game")
}
}
}

View File

@@ -0,0 +1,67 @@
package com.petrovv.gogameclock
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableLongStateOf
import androidx.compose.runtime.setValue
class Timer(initialTime: Long = 60, private val onTimeOut: () -> Unit = {}) {
private var initialTimeMs: Long = initialTime * 1000
var timeMillis by mutableLongStateOf(initialTimeMs)
private var running = false
private var startTime = 0L
private var timeAtStart = 0L
fun start() {
if (!running && timeMillis > 0) {
running = true
startTime = System.currentTimeMillis()
timeAtStart = timeMillis
}
}
fun stop() {
if (running) {
update()
running = false
}
}
fun addTime(time: Long) {
if (running) {
update()
}
timeMillis += time * 1000
}
fun reset(time: Long = 0) {
if(time != 0L){
initialTimeMs = time * 1000
}
timeMillis = initialTimeMs
running = false
}
fun isRunning(): Boolean {
return running
}
fun update() {
if (running) {
val elapsed = System.currentTimeMillis() - startTime
timeMillis = (timeAtStart - elapsed).coerceAtLeast(0L)
if (timeMillis == 0L) {
running = false
onTimeOut()
}
}
}
override fun toString() : String {
val seconds = timeMillis / 1000
val minutes = seconds / 60
val remainingSeconds = seconds % 60
return "%02d:%02d".format(minutes, remainingSeconds)
}
}

View File

@@ -0,0 +1,170 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<path
android:fillColor="#3DDC84"
android:pathData="M0,0h108v108h-108z" />
<path
android:fillColor="#00000000"
android:pathData="M9,0L9,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,0L19,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M29,0L29,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M39,0L39,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M49,0L49,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M59,0L59,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M69,0L69,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M79,0L79,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M89,0L89,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M99,0L99,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,9L108,9"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,19L108,19"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,29L108,29"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,39L108,39"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,49L108,49"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,59L108,59"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,69L108,69"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,79L108,79"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,89L108,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,99L108,99"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,29L89,29"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,39L89,39"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,49L89,49"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,59L89,59"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,69L89,69"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,79L89,79"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M29,19L29,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M39,19L39,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M49,19L49,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M59,19L59,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M69,19L69,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M79,19L79,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
</vector>

View File

@@ -0,0 +1,30 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<path android:pathData="M31,63.928c0,0 6.4,-11 12.1,-13.1c7.2,-2.6 26,-1.4 26,-1.4l38.1,38.1L107,108.928l-32,-1L31,63.928z">
<aapt:attr name="android:fillColor">
<gradient
android:endX="85.84757"
android:endY="92.4963"
android:startX="42.9492"
android:startY="49.59793"
android:type="linear">
<item
android:color="#44000000"
android:offset="0.0" />
<item
android:color="#00000000"
android:offset="1.0" />
</gradient>
</aapt:attr>
</path>
<path
android:fillColor="#FFFFFF"
android:fillType="nonZero"
android:pathData="M65.3,45.828l3.8,-6.6c0.2,-0.4 0.1,-0.9 -0.3,-1.1c-0.4,-0.2 -0.9,-0.1 -1.1,0.3l-3.9,6.7c-6.3,-2.8 -13.4,-2.8 -19.7,0l-3.9,-6.7c-0.2,-0.4 -0.7,-0.5 -1.1,-0.3C38.8,38.328 38.7,38.828 38.9,39.228l3.8,6.6C36.2,49.428 31.7,56.028 31,63.928h46C76.3,56.028 71.8,49.428 65.3,45.828zM43.4,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2c-0.3,-0.7 -0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C45.3,56.528 44.5,57.328 43.4,57.328L43.4,57.328zM64.6,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2s-0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C66.5,56.528 65.6,57.328 64.6,57.328L64.6,57.328z"
android:strokeWidth="1"
android:strokeColor="#00000000" />
</vector>

View File

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

View File

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 982 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="purple_200">#FFBB86FC</color>
<color name="purple_500">#FF6200EE</color>
<color name="purple_700">#FF3700B3</color>
<color name="teal_200">#FF03DAC5</color>
<color name="teal_700">#FF018786</color>
<color name="black">#FF000000</color>
<color name="white">#FFFFFFFF</color>
</resources>

View File

@@ -0,0 +1,3 @@
<resources>
<string name="app_name">GoGameClock</string>
</resources>

View File

@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="Theme.GoGameClock" parent="android:Theme.Material.Light.NoActionBar" />
</resources>

View File

@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?><!--
Sample backup rules file; uncomment and customize as necessary.
See https://developer.android.com/guide/topics/data/autobackup
for details.
Note: This file is ignored for devices older than API 31
See https://developer.android.com/about/versions/12/backup-restore
-->
<full-backup-content>
<!--
<include domain="sharedpref" path="."/>
<exclude domain="sharedpref" path="device.xml"/>
-->
</full-backup-content>

View File

@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?><!--
Sample data extraction rules file; uncomment and customize as necessary.
See https://developer.android.com/about/versions/12/backup-restore#xml-changes
for details.
-->
<data-extraction-rules>
<cloud-backup>
<!-- TODO: Use <include> and <exclude> to control what is backed up.
<include .../>
<exclude .../>
-->
</cloud-backup>
<!--
<device-transfer>
<include .../>
<exclude .../>
</device-transfer>
-->
</data-extraction-rules>

View File

@@ -0,0 +1,17 @@
package com.petrovv.gogameclock
import org.junit.Test
import org.junit.Assert.*
/**
* Example local unit test, which will execute on the development machine (host).
*
* See [testing documentation](http://d.android.com/tools/testing).
*/
class ExampleUnitTest {
@Test
fun addition_isCorrect() {
assertEquals(4, 2 + 2)
}
}