Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions build.gradle
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.

buildscript {
ext.kotlin_version = '1.6.10'
ext.kotlin_version = '1.7.20'
ext.lifecycle_version = '2.5.1'
ext.compose_version = '1.3.3'
repositories {
google()
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:7.3.0'
classpath 'com.android.tools.build:gradle:7.4.1'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"

// NOTE: Do not place your application dependencies here; they belong
Expand Down
3 changes: 2 additions & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,5 @@
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true
android.enableJetifier=true
android.useAndroidX=true
android.useAndroidX=true
android.enableR8.fullMode=true
2 changes: 1 addition & 1 deletion gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-all.zip
36 changes: 23 additions & 13 deletions mobile/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,9 @@ android {
applicationId "es.hegocre.scorecounter"
minSdkVersion 24
targetSdkVersion 33
versionCode 311050000
versionName "1.0.5"
versionCode 311100001
versionName "1.1.0"
resConfigs 'ca', 'es', 'en'
}

buildTypes {
Expand All @@ -24,28 +25,37 @@ android {
}

buildFeatures {
viewBinding true
dataBinding true
compose true
}

compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
sourceCompatibility JavaVersion.VERSION_11
targetCompatibility JavaVersion.VERSION_11
}

composeOptions {
kotlinCompilerExtensionVersion '1.3.2'
}

kotlinOptions {
jvmTarget = '1.8'
jvmTarget = '11'
}
namespace 'es.hegocre.scorecounter'
}

dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation 'androidx.preference:preference-ktx:1.2.0'
testImplementation 'junit:junit:4.13.2'
implementation 'androidx.appcompat:appcompat:1.5.1'

//Android dependencies
implementation 'androidx.core:core-ktx:1.9.0'
//noinspection KtxExtensionAvailable
implementation "androidx.lifecycle:lifecycle-viewmodel:$lifecycle_version"
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version"

//Compose
implementation 'androidx.activity:activity-compose:1.6.1'
implementation 'androidx.compose.material3:material3:1.0.1'
implementation "androidx.compose.ui:ui:$compose_version"

testImplementation 'junit:junit:4.13.2'
androidTestImplementation "androidx.compose.ui:ui-test-junit4:$compose_version"
debugImplementation "androidx.compose.ui:ui-tooling:$compose_version"
debugImplementation "androidx.compose.ui:ui-test-manifest:$compose_version"
}
9 changes: 6 additions & 3 deletions mobile/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -1,19 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<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_descriptor"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@android:style/Theme.Light.NoTitleBar.Fullscreen">
android:theme="@android:style/Theme.Material.Light.NoActionBar"
tools:targetApi="s">
<activity
android:name="es.hegocre.scorecounter.MainActivity"
android:configChanges="orientation|screenSize|keyboardHidden"
android:exported="true"
android:screenOrientation="sensorLandscape"
android:theme="@style/Theme.AppCompat.Light.NoActionBar">
android:theme="@android:style/Theme.Material.Light.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
Expand Down
Binary file modified mobile/src/main/ic_launcher-playstore.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed mobile/src/main/ic_launcher-web.png
Binary file not shown.
180 changes: 128 additions & 52 deletions mobile/src/main/java/es/hegocre/scorecounter/MainActivity.kt
Original file line number Diff line number Diff line change
@@ -1,76 +1,152 @@
package es.hegocre.scorecounter

import android.content.Context
import android.os.Build
import android.os.Bundle
import android.view.View
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.viewModels
import androidx.compose.foundation.background
import androidx.compose.foundation.gestures.detectTapGestures
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.foundation.layout.*
import androidx.compose.material3.*
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.core.view.WindowCompat
import androidx.core.view.WindowInsetsCompat
import androidx.core.view.WindowInsetsControllerCompat
import androidx.databinding.DataBindingUtil
import androidx.preference.PreferenceManager
import es.hegocre.scorecounter.data.Score
import es.hegocre.scorecounter.databinding.ActivityScoreBinding

class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityScoreBinding

class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = DataBindingUtil.setContentView(this, R.layout.activity_score)

Score.setSharedPreferences(PreferenceManager.getDefaultSharedPreferences(this).also {
if (it.getBoolean("firstRun", true)) {
showTutorialDialog()
it.edit().putBoolean("firstRun", false).apply()
val scoreViewModel by viewModels<ScoreViewModel>()

WindowCompat.setDecorFitsSystemWindows(window, false)

setContent {
val darkTheme = isSystemInDarkTheme()
val colorScheme = when {
Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> {
val context = LocalContext.current
if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(
context
)
}
darkTheme -> darkColorScheme()
else -> lightColorScheme()
}
MaterialTheme(colorScheme = colorScheme) {
Surface(color = if (darkTheme) Color.Black else MaterialTheme.colorScheme.surface) {
val context = LocalContext.current

var showTutorialDialog by rememberSaveable {
mutableStateOf(
context.getSharedPreferences("preferences", Context.MODE_PRIVATE)
.getBoolean("isFirstLaunch", true)
)
}

Row {
ScoreView(
score = scoreViewModel.score1,
onScoreAdd = { scoreViewModel.score1++ },
onScoreSub = { scoreViewModel.score1-- },
onScoreReset = { scoreViewModel.score1 = 0 },
modifier = Modifier
.weight(1f)
.fillMaxHeight()
)
Spacer(
modifier = Modifier
.fillMaxHeight()
.width(4.dp)
.background(MaterialTheme.colorScheme.onSurface)
)
ScoreView(
score = scoreViewModel.score2,
onScoreAdd = { scoreViewModel.score2++ },
onScoreSub = { scoreViewModel.score2-- },
onScoreReset = { scoreViewModel.score2 = 0 },
modifier = Modifier
.weight(1f)
.fillMaxHeight()
)
}

if (showTutorialDialog) {
context.getSharedPreferences("preferences", Context.MODE_PRIVATE)
.edit().putBoolean("isFirstLaunch", false).apply()

AlertDialog(
onDismissRequest = { showTutorialDialog = false },
confirmButton = {
TextButton(onClick = { showTutorialDialog = false }) {
Text(text = stringResource(id = android.R.string.ok))
}
},
title = { Text(text = stringResource(id = R.string.dialog_tutorial_title)) },
text = { Text(text = stringResource(id = R.string.dialog_tutorial_message)) }
)
}
}
}
})
Score("score1").let { score ->
binding.score1 = score
loadScore(score, binding.add1Layout, binding.sub1Layout)
}
Score("score2").let { score ->
binding.score2 = score
loadScore(score, binding.add2Layout, binding.sub2Layout)
}
}

private fun hideSystemUI() {
override fun onResume() {
super.onResume()
WindowCompat.setDecorFitsSystemWindows(window, false)
WindowInsetsControllerCompat(window, binding.root).let { controller ->
WindowInsetsControllerCompat(window, window.decorView).let { controller ->
controller.hide(WindowInsetsCompat.Type.statusBars() or WindowInsetsCompat.Type.navigationBars())
controller.systemBarsBehavior =
WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
}
}
}

override fun onResume() {
hideSystemUI()
super.onResume()
}

private fun loadScore(score: Score, addLayout: View, subLayout: View) {
addLayout.setOnClickListener {
score.inc()
@Composable
fun ScoreView(
score: Int,
onScoreAdd: (Offset) -> Unit,
onScoreSub: (Offset) -> Unit,
onScoreReset: (Offset) -> Unit,
modifier: Modifier = Modifier
) {
Box(modifier = modifier, contentAlignment = Alignment.Center) {
Text(
text = "$score",
fontSize = 70.sp,
color = MaterialTheme.colorScheme.onSurface
)
Column(modifier = Modifier.fillMaxSize()) {
Box(modifier = Modifier
.fillMaxWidth()
.weight(1f)
.pointerInput(Unit) {
detectTapGestures(onTap = onScoreAdd, onLongPress = onScoreReset)
}
)
Box(modifier = Modifier
.fillMaxWidth()
.weight(1f)
.pointerInput(Unit) {
detectTapGestures(onTap = onScoreSub, onLongPress = onScoreReset)
}
)
}
addLayout.setOnLongClickListener {
score.reset()
true
}
subLayout.setOnClickListener {
score.dec()
}
subLayout.setOnLongClickListener {
score.reset()
true
}
}

private fun showTutorialDialog() {
AlertDialog.Builder(this)
.setTitle(R.string.dialog_tutorial_title)
.setMessage(R.string.dialog_tutorial_message)
.setPositiveButton(android.R.string.ok, null)
.show()
}
}
26 changes: 26 additions & 0 deletions mobile/src/main/java/es/hegocre/scorecounter/ScoreViewModel.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package es.hegocre.scorecounter

import android.app.Application
import android.content.Context
import androidx.compose.runtime.mutableStateOf
import androidx.lifecycle.AndroidViewModel

class ScoreViewModel(application: Application) : AndroidViewModel(application) {
private val _preferencesManager =
application.getSharedPreferences("scores", Context.MODE_PRIVATE)

private val _score1 = mutableStateOf(_preferencesManager.getInt("score1", 0))
var score1: Int
get() = _score1.value
set(value) {
_score1.value = value
_preferencesManager.edit().putInt("score1", value).apply()
}
private val _score2 = mutableStateOf(_preferencesManager.getInt("score2", 0))
var score2: Int
get() = _score2.value
set(value) {
_score2.value = value
_preferencesManager.edit().putInt("score2", value).apply()
}
}
35 changes: 0 additions & 35 deletions mobile/src/main/java/es/hegocre/scorecounter/data/Score.kt

This file was deleted.

Loading