Compare commits

..
2 Commits
Author SHA1 Message Date
kfj001 97b01437b2 bug fixes 2026-05-29 20:30:41 -07:00
kfj001 f87d23a922 removes unneeded file 2026-05-28 22:59:26 -07:00
6 changed files with 61 additions and 99 deletions
@@ -3,6 +3,9 @@ package com.example.countdowntimer
import android.content.Context import android.content.Context
import android.content.SharedPreferences import android.content.SharedPreferences
import android.os.Bundle import android.os.Bundle
import android.os.VibrationEffect
import android.os.Vibrator
import android.os.VibratorManager
import android.view.View import android.view.View
import android.view.inputmethod.InputMethodManager import android.view.inputmethod.InputMethodManager
import android.widget.Button import android.widget.Button
@@ -21,7 +24,9 @@ class MainActivity : AppCompatActivity() {
private lateinit var btnDurationLabel: Button private lateinit var btnDurationLabel: Button
private lateinit var hsvDurationOptions: View private lateinit var hsvDurationOptions: View
private lateinit var chipGroup: ChipGroup private lateinit var chipGroup: ChipGroup
private lateinit var vibrator: Vibrator
private var selectedDuration: Long = DEFAULT_DURATION private var selectedDuration: Long = DEFAULT_DURATION
private var lastSelectedChipId: Int = -1
private fun durationToChipId(duration: Long): Int = when (duration) { private fun durationToChipId(duration: Long): Int = when (duration) {
5000L -> R.id.chip5s 5000L -> R.id.chip5s
@@ -42,6 +47,16 @@ class MainActivity : AppCompatActivity() {
btnDurationLabel.text = "${selectedDuration / 1000}s" btnDurationLabel.text = "${selectedDuration / 1000}s"
} }
private fun onChipClicked(chipId: Int) {
if (chipId == lastSelectedChipId) {
// Re-selection: provide feedback so user knows the selection is registered
vibrator.vibrate(VibrationEffect.createOneShot(15, VibrationEffect.DEFAULT_AMPLITUDE))
val originalText = btnDurationLabel.text
btnDurationLabel.text = "${selectedDuration / 1000}s!"
btnDurationLabel.postDelayed({ btnDurationLabel.text = originalText }, 300)
}
}
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main) setContentView(R.layout.activity_main)
@@ -52,6 +67,8 @@ class MainActivity : AppCompatActivity() {
btnDurationLabel = findViewById(R.id.btnDurationLabel) btnDurationLabel = findViewById(R.id.btnDurationLabel)
hsvDurationOptions = findViewById(R.id.hsvDurationOptions) hsvDurationOptions = findViewById(R.id.hsvDurationOptions)
chipGroup = findViewById(R.id.chipGroup) chipGroup = findViewById(R.id.chipGroup)
val vibratorManager = getSystemService(Context.VIBRATOR_MANAGER_SERVICE) as VibratorManager
vibrator = vibratorManager.defaultVibrator
updateDurationLabel() updateDurationLabel()
@@ -72,15 +89,27 @@ class MainActivity : AppCompatActivity() {
} }
} }
chipGroup.setOnCheckedChangeListener { _, checkedId -> chipGroup.setOnCheckedStateChangeListener { _, checkedIds ->
val checkedId = if (checkedIds.size > 0) checkedIds[0].toInt() else -1
if (checkedId != -1) { if (checkedId != -1) {
if (checkedId != lastSelectedChipId) {
// New selection: update duration, save, and refresh label
selectedDuration = chipIdToDuration(checkedId) selectedDuration = chipIdToDuration(checkedId)
prefs.edit().putLong(KEY_SELECTED_DURATION, selectedDuration).apply() prefs.edit().putLong(KEY_SELECTED_DURATION, selectedDuration).apply()
updateDurationLabel() updateDurationLabel()
lastSelectedChipId = checkedId
}
// Always close the panel on any selection
hsvDurationOptions.visibility = View.GONE hsvDurationOptions.visibility = View.GONE
} }
} }
// Set individual click listeners to detect re-selection
findViewById<View>(R.id.chip5s).setOnClickListener { onChipClicked(R.id.chip5s) }
findViewById<View>(R.id.chip10s).setOnClickListener { onChipClicked(R.id.chip10s) }
findViewById<View>(R.id.chip15s).setOnClickListener { onChipClicked(R.id.chip15s) }
findViewById<View>(R.id.chip30s).setOnClickListener { onChipClicked(R.id.chip30s) }
findViewById<View>(R.id.btnStart).setOnClickListener { findViewById<View>(R.id.btnStart).setOnClickListener {
CountdownDialog(this, selectedDuration, prefs).show() CountdownDialog(this, selectedDuration, prefs).show()
} }
+2 -2
View File
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android"> <selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_checked="true" android:color="#81C784" /> <item android:state_checked="true" android:color="#2E7D32" />
<item android:color="#E8E8E8" /> <item android:color="#233024" />
</selector> </selector>
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_checked="true" android:color="#C8E6C9" />
<item android:color="#2E7D32" />
</selector>
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_checked="true" android:color="#FFFFFF" />
<item android:color="#C8E6C9" />
</selector>
+16 -5
View File
@@ -170,17 +170,22 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:minWidth="56dp" android:minWidth="56dp"
android:text="5s" android:text="5s"
app:chipBackgroundColor="@color/chip_duration_bg" /> app:chipBackgroundColor="@color/chip_duration_bg"
app:chipStrokeColor="@color/chip_duration_stroke"
app:chipStrokeWidth="2dp"
android:textColor="@color/chip_duration_text" />
<com.google.android.material.chip.Chip <com.google.android.material.chip.Chip
android:id="@+id/chip10s" android:id="@+id/chip10s"
style="@style/Widget.Material3.Chip.Suggestion.Elevated" style="@style/Widget.Material3.Chip.Suggestion.Elevated"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:checked="true"
android:minWidth="56dp" android:minWidth="56dp"
android:text="10s" android:text="10s"
app:chipBackgroundColor="@color/chip_duration_bg" /> app:chipBackgroundColor="@color/chip_duration_bg"
app:chipStrokeColor="@color/chip_duration_stroke"
app:chipStrokeWidth="2dp"
android:textColor="@color/chip_duration_text" />
<com.google.android.material.chip.Chip <com.google.android.material.chip.Chip
android:id="@+id/chip15s" android:id="@+id/chip15s"
@@ -189,7 +194,10 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:minWidth="56dp" android:minWidth="56dp"
android:text="15s" android:text="15s"
app:chipBackgroundColor="@color/chip_duration_bg" /> app:chipBackgroundColor="@color/chip_duration_bg"
app:chipStrokeColor="@color/chip_duration_stroke"
app:chipStrokeWidth="2dp"
android:textColor="@color/chip_duration_text" />
<com.google.android.material.chip.Chip <com.google.android.material.chip.Chip
android:id="@+id/chip30s" android:id="@+id/chip30s"
@@ -198,7 +206,10 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:minWidth="56dp" android:minWidth="56dp"
android:text="30s" android:text="30s"
app:chipBackgroundColor="@color/chip_duration_bg" /> app:chipBackgroundColor="@color/chip_duration_bg"
app:chipStrokeColor="@color/chip_duration_stroke"
app:chipStrokeWidth="2dp"
android:textColor="@color/chip_duration_text" />
</com.google.android.material.chip.ChipGroup> </com.google.android.material.chip.ChipGroup>
</HorizontalScrollView> </HorizontalScrollView>
-88
View File
@@ -1,88 +0,0 @@
# Goal: Redesign all buttons into bold, square, visually striking interactive elements
## Objective
Replace every basic/rectangular button in the app with larger, square-aspect-ratio buttons that have eye-catching visual design. The goal is to transform the UI from a generic Material 3 look into a distinctive, personality-rich interface that matches the playful "BONG HIT TIMER" brand.
## Current State
The app uses 4 visible buttons across 2 screens:
**MainActivity (home screen):**
- `btnDurationLabel` — outlined button showing selected duration (e.g. "10s") with a dropdown arrow. Uses `Widget.Material3.Button.OutlinedButton` with 20dp corners.
- `btnStart` — filled button labeled "Start Timer" with a play icon. Uses `Widget.Material3.Button` with 20dp corners.
**CountdownDialog (timer screen):**
- `btnStop` — plain Android `Button` labeled "Stop" (default styling, small)
- `btnRestart` — plain Android `Button` labeled "Restart" (default styling, small)
- `btnDismiss` — plain Android `Button` labeled "Dismiss" (currently gone, shows after timer completes)
## Design Requirements
### 1. Square Aspect Ratio
- Change all buttons from `wrap_content` rectangles to a fixed square size (e.g., `120dp` x `120dp` or `100dp` x `100dp`)
- Use `app:layout_constraintDimensionRatio="1:1"` where dynamic sizing is needed
- Buttons should feel substantial and tappable, not compact
### 2. Visual Interest — Each button should have its own personality
Create custom drawable backgrounds for each button type. Design ideas (pick the best approach):
- **Circular/spherical buttons** — Buttons that look like physical 3D balls or pucks. Use gradient fills with highlights/shadows to create a convex "pressable" look.
- **Neon/glow effect** — Since the app is a bong hit timer, a subtle neon glow that pulses or intensifies during countdown would be thematically appropriate.
- **Retro/gaming arcade style** — Bold colors, thick borders, pressed/active states that simulate physical button depression.
- **Gradient + icon centering** — For the timer screen, center the stop/restart icons prominently in the square buttons with bold gradient backgrounds.
### 3. Interactive States
Every button must have rich feedback:
- **Pressed/active state** — noticeable visual change (shrink, darker shade, or inner glow)
- **Default state** — visually engaging with gradients, shadows, or subtle animations
- **Disabled state** — reduced opacity but still recognizable
### 4. Icon Integration
Square buttons are perfect for icon-first design:
- **Stop button** — large centered pause/stop icon
- **Restart button** — large centered refresh/replay icon
- **Start button** — center the play icon, consider removing the text label since the icon is universal
- **Duration label** — consider a pill-shaped or circular chip that pulses when tapped
### 5. Color Palette
Stay within the existing green theme (`#2E7D32` primary, `#4C6842` secondary, `#E8F5E9`/`#C8E6C9` gradient) but push it further:
- Use the primary green for the start/positive actions
- A red/coral accent for stop
- A neutral or blue for restart/duration selection
- Consider gradient transitions within each button (e.g., green to darker green top-to-bottom for a 3D effect)
### 6. Shadow & Elevation
- Add drop shadows to all buttons for depth (use `app:strokeWidth="0dp"` and custom `rippleColor` for Material buttons)
- Create a `btn_square_default.xml` and `btn_square_pressed.xml` in `res/drawable/` for each button type
- The pressed state should visually simulate "pressing in" (reduced shadow, lighter/darker fill)
## Technical Implementation
### New drawable files to create (in `res/drawable/`):
- `btn_start_square.xml` — gradient + shadow drawable for start button
- `btn_start_square_pressed.xml` — pressed state variant
- `btn_stop_square.xml` — gradient + shadow drawable for stop button
- `btn_stop_square_pressed.xml` — pressed state variant
- `btn_restart_square.xml` — gradient + shadow drawable for restart button
- `btn_restart_square_pressed.xml` — pressed state variant
- `btn_duration_chip.xml` — drawable for duration selector
### Layout changes needed:
- `activity_main.xml`:
- `btnDurationLabel`: change to square dimensions, wrap text/icon in center, apply new drawable
- `btnStart`: change to square, center play icon, apply new drawable
- `dialog_countdown.xml`:
- `btnStop`: change from `Button` to `com.google.android.material.button.MaterialButton`, set square dimensions, apply drawable
- `btnRestart`: same treatment
- `btnDismiss`: same treatment, keep as gone by default
- Adjust the ConstraintLayout chain to accommodate square buttons (may need a horizontal chain with proper spacing)
### Code changes needed:
- `CountdownDialog.kt`: Set button backgrounds programmatically if needed, ensure clickable/pressable states work
- No changes to button click logic — only visual overhaul
## Constraints
- Use only Material 3 components already in the dependency (`com.google.android.material:material:1.11.0`)
- Traditional XML layouts — no Compose
- Minimum SDK 24 — no API 30+ features
- Keep the app's existing green aesthetic but make it bolder
- Maintain accessibility (minimum 48dp touch target, sufficient contrast)