Skip to content

Instantly share code, notes, and snippets.

@guiathayde
Created March 26, 2026 17:12
Show Gist options
  • Select an option

  • Save guiathayde/ecbdea76cd2ee453d7f2b7b7dce31a60 to your computer and use it in GitHub Desktop.

Select an option

Save guiathayde/ecbdea76cd2ee453d7f2b7b7dce31a60 to your computer and use it in GitHub Desktop.
Basket Score
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/main"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:id="@+id/tv_score"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="32dp"
android:textSize="48sp"
android:textStyle="bold"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="0 - 0" />
<TextView
android:id="@+id/tv_team1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="32dp"
android:text="@string/team_1"
android:textSize="24sp"
app:layout_constraintEnd_toStartOf="@+id/guideline_center"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/tv_score" />
<TextView
android:id="@+id/tv_team2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="32dp"
android:text="@string/team_2"
android:textSize="24sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="@+id/guideline_center"
app:layout_constraintTop_toBottomOf="@+id/tv_score" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline_center"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_percent="0.5" />
<!-- Team 1 Buttons -->
<Button
android:id="@+id/btn_t1_free_throw"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginHorizontal="16dp"
android:layout_marginTop="16dp"
android:text="@string/free_throw"
app:layout_constraintEnd_toStartOf="@+id/guideline_center"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/tv_team1" />
<Button
android:id="@+id/btn_t1_two_points"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginHorizontal="16dp"
android:layout_marginTop="16dp"
android:text="@string/two_points"
app:layout_constraintEnd_toStartOf="@+id/guideline_center"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/btn_t1_free_throw" />
<Button
android:id="@+id/btn_t1_three_points"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginHorizontal="16dp"
android:layout_marginTop="16dp"
android:text="@string/three_points"
app:layout_constraintEnd_toStartOf="@+id/guideline_center"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/btn_t1_two_points" />
<!-- Team 2 Buttons -->
<Button
android:id="@+id/btn_t2_free_throw"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginHorizontal="16dp"
android:layout_marginTop="16dp"
android:text="@string/free_throw"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="@+id/guideline_center"
app:layout_constraintTop_toBottomOf="@+id/tv_team2" />
<Button
android:id="@+id/btn_t2_two_points"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginHorizontal="16dp"
android:layout_marginTop="16dp"
android:text="@string/two_points"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="@+id/guideline_center"
app:layout_constraintTop_toBottomOf="@+id/btn_t2_free_throw" />
<Button
android:id="@+id/btn_t2_three_points"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginHorizontal="16dp"
android:layout_marginTop="16dp"
android:text="@string/three_points"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="@+id/guideline_center"
app:layout_constraintTop_toBottomOf="@+id/btn_t2_two_points" />
<!-- Undo Button -->
<Button
android:id="@+id/btn_undo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="32dp"
android:layout_marginEnd="8dp"
android:text="@string/undo"
android:enabled="false"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/guideline_center" />
<!-- Reset Button -->
<Button
android:id="@+id/btn_reset"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="32dp"
android:layout_marginStart="8dp"
android:text="@string/reset_score"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toEndOf="@+id/guideline_center" />
</androidx.constraintlayout.widget.ConstraintLayout>
package com.guiathayde.basketscore;
import android.os.Bundle;
import android.widget.Button;
import android.widget.TextView;
import androidx.activity.EdgeToEdge;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;
import androidx.lifecycle.ViewModelProvider;
public class MainActivity extends AppCompatActivity {
private ScoreViewModel viewModel;
private TextView tvScore;
private Button btnUndo;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
EdgeToEdge.enable(this);
setContentView(R.layout.activity_main);
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main), (v, insets) -> {
Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom);
return insets;
});
viewModel = new ViewModelProvider(this).get(ScoreViewModel.class);
tvScore = findViewById(R.id.tv_score);
btnUndo = findViewById(R.id.btn_undo);
Button btnReset = findViewById(R.id.btn_reset);
Button btnT1FreeThrow = findViewById(R.id.btn_t1_free_throw);
Button btnT1TwoPoints = findViewById(R.id.btn_t1_two_points);
Button btnT1ThreePoints = findViewById(R.id.btn_t1_three_points);
Button btnT2FreeThrow = findViewById(R.id.btn_t2_free_throw);
Button btnT2TwoPoints = findViewById(R.id.btn_t2_two_points);
Button btnT2ThreePoints = findViewById(R.id.btn_t2_three_points);
// Team 1 actions
btnT1FreeThrow.setOnClickListener(v -> viewModel.addPoints(1, 1));
btnT1TwoPoints.setOnClickListener(v -> viewModel.addPoints(1, 2));
btnT1ThreePoints.setOnClickListener(v -> viewModel.addPoints(1, 3));
// Team 2 actions
btnT2FreeThrow.setOnClickListener(v -> viewModel.addPoints(2, 1));
btnT2TwoPoints.setOnClickListener(v -> viewModel.addPoints(2, 2));
btnT2ThreePoints.setOnClickListener(v -> viewModel.addPoints(2, 3));
// Undo action
btnUndo.setOnClickListener(v -> viewModel.undoLastAction());
// Reset action
btnReset.setOnClickListener(v -> viewModel.resetScore());
// Observe ViewModel
viewModel.getTeam1Score().observe(this, score -> updateScoreView());
viewModel.getTeam2Score().observe(this, score -> updateScoreView());
viewModel.getCanUndo().observe(this, canUndo -> btnUndo.setEnabled(canUndo));
}
private void updateScoreView() {
int score1 = viewModel.getTeam1Score().getValue() != null ? viewModel.getTeam1Score().getValue() : 0;
int score2 = viewModel.getTeam2Score().getValue() != null ? viewModel.getTeam2Score().getValue() : 0;
String scoreText = getString(R.string.score_format, score1, score2);
tvScore.setText(scoreText);
}
}
package com.guiathayde.basketscore;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;
public class ScoreViewModel extends ViewModel {
private final MutableLiveData<Integer> team1Score = new MutableLiveData<>(0);
private final MutableLiveData<Integer> team2Score = new MutableLiveData<>(0);
private final MutableLiveData<Boolean> canUndo = new MutableLiveData<>(false);
// Store the last action to be able to undo
private int lastTeam = 0; // 1 for team 1, 2 for team 2, 0 for none
private int lastPoints = 0;
public LiveData<Integer> getTeam1Score() {
return team1Score;
}
public LiveData<Integer> getTeam2Score() {
return team2Score;
}
public LiveData<Boolean> getCanUndo() {
return canUndo;
}
public void addPoints(int team, int points) {
if (team == 1) {
Integer currentScore = team1Score.getValue();
team1Score.setValue((currentScore != null ? currentScore : 0) + points);
} else if (team == 2) {
Integer currentScore = team2Score.getValue();
team2Score.setValue((currentScore != null ? currentScore : 0) + points);
}
lastTeam = team;
lastPoints = points;
canUndo.setValue(true);
}
public void undoLastAction() {
if (Boolean.TRUE.equals(canUndo.getValue())) {
if (lastTeam == 1) {
Integer currentScore = team1Score.getValue();
team1Score.setValue((currentScore != null ? currentScore : 0) - lastPoints);
} else if (lastTeam == 2) {
Integer currentScore = team2Score.getValue();
team2Score.setValue((currentScore != null ? currentScore : 0) - lastPoints);
}
lastTeam = 0;
lastPoints = 0;
canUndo.setValue(false);
}
}
public void resetScore() {
team1Score.setValue(0);
team2Score.setValue(0);
lastTeam = 0;
lastPoints = 0;
canUndo.setValue(false);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment