Fat square interesting buttons #3

Merged
kfj001 merged 12 commits from fat_square_interesting_buttons into main 2026-05-26 13:24:59 -07:00
21 changed files with 374 additions and 45 deletions
Showing only changes of commit 6de400753c - Show all commits
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<size android:width="120dp" android:height="120dp" />
<gradient
android:angle="270"
android:startColor="#81C784"
android:endColor="#4CAF50"
android:type="linear" />
<stroke
android:width="3dp"
android:color="#A5D6A7" />
</shape>
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<size android:width="120dp" android:height="120dp" />
<gradient
android:angle="270"
android:startColor="#C8E6C9"
android:endColor="#A5D6A7"
android:type="linear" />
<stroke
android:width="3dp"
android:color="#E8F5E9" />
</shape>
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<size android:width="120dp" android:height="120dp" />
<gradient
android:angle="270"
android:startColor="#66BB6A"
android:endColor="#388E3C"
android:type="linear" />
<stroke
android:width="3dp"
android:color="#81C784" />
</shape>
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/btn_duration_disabled" android:state_enabled="false" />
<item android:drawable="@drawable/btn_duration_pressed" android:state_pressed="true" />
<item android:drawable="@drawable/btn_duration_pressed" android:state_activated="true" />
<item android:drawable="@drawable/btn_duration_default" />
</selector>
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<size android:width="120dp" android:height="120dp" />
<gradient
android:angle="270"
android:startColor="#42A5F5"
android:endColor="#1565C0"
android:type="linear" />
<stroke
android:width="3dp"
android:color="#90CAF9" />
</shape>
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<size android:width="120dp" android:height="120dp" />
<gradient
android:angle="270"
android:startColor="#90CAF9"
android:endColor="#64B5F6"
android:type="linear" />
<stroke
android:width="3dp"
android:color="#BBDEFB" />
</shape>
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<size android:width="120dp" android:height="120dp" />
<gradient
android:angle="270"
android:startColor="#1E88E5"
android:endColor="#0D47A1"
android:type="linear" />
<stroke
android:width="3dp"
android:color="#42A5F5" />
</shape>
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/btn_restart_disabled" android:state_enabled="false" />
<item android:drawable="@drawable/btn_restart_pressed" android:state_pressed="true" />
<item android:drawable="@drawable/btn_restart_pressed" android:state_activated="true" />
<item android:drawable="@drawable/btn_restart_default" />
</selector>
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<size android:width="120dp" android:height="120dp" />
<gradient
android:angle="270"
android:startColor="#4CAF50"
android:endColor="#2E7D32"
android:type="linear" />
<stroke
android:width="3dp"
android:color="#66BB6A" />
</shape>
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<size android:width="120dp" android:height="120dp" />
<gradient
android:angle="270"
android:startColor="#A5D6A7"
android:endColor="#81C784"
android:type="linear" />
<stroke
android:width="3dp"
android:color="#C8E6C9" />
</shape>
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<size android:width="120dp" android:height="120dp" />
<gradient
android:angle="270"
android:startColor="#388E3C"
android:endColor="#1B5E20"
android:type="linear" />
<stroke
android:width="3dp"
android:color="#4CAF50" />
</shape>
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/btn_start_disabled" android:state_enabled="false" />
<item android:drawable="@drawable/btn_start_pressed" android:state_pressed="true" />
<item android:drawable="@drawable/btn_start_pressed" android:state_activated="true" />
<item android:drawable="@drawable/btn_start_default" />
</selector>
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<size android:width="120dp" android:height="120dp" />
<gradient
android:angle="270"
android:startColor="#EF5350"
android:endColor="#C62828"
android:type="linear" />
<stroke
android:width="3dp"
android:color="#EF9A9A" />
</shape>
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<size android:width="120dp" android:height="120dp" />
<gradient
android:angle="270"
android:startColor="#EF9A9A"
android:endColor="#E57373"
android:type="linear" />
<stroke
android:width="3dp"
android:color="#FFCDD2" />
</shape>
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<size android:width="120dp" android:height="120dp" />
<gradient
android:angle="270"
android:startColor="#E53935"
android:endColor="#B71C1C"
android:type="linear" />
<stroke
android:width="3dp"
android:color="#EF5350" />
</shape>
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/btn_stop_disabled" android:state_enabled="false" />
<item android:drawable="@drawable/btn_stop_pressed" android:state_pressed="true" />
<item android:drawable="@drawable/btn_stop_pressed" android:state_activated="true" />
<item android:drawable="@drawable/btn_stop_default" />
</selector>
@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="48dp"
android:height="48dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#FFFFFF"
android:pathData="M17.65,6.35C16.2,4.9 14.21,4 12,4c-4.42,0 -7.99,3.58 -7.99,8s3.57,8 7.99,8c3.73,0 6.84,-2.55 7.73,-6h-2.08c-0.82,2.33 -3.04,4 -5.65,4 -3.31,0 -6,-2.69 -6,-6s2.69,-6 6,-6c1.66,0 3.14,0.69 4.22,1.78L13,11h7V4L17.65,6.35z"
android:strokeWidth="0" />
</vector>
@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="48dp"
android:height="48dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#FFFFFF"
android:pathData="M6,6h12v12H6z"
android:strokeWidth="0" />
</vector>
+22 -11
View File
@@ -110,15 +110,22 @@
</LinearLayout>
</LinearLayout>
<com.google.android.material.button.MaterialButton
<Button
android:id="@+id/btnDurationLabel"
style="@style/Widget.Material3.Button.OutlinedButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_width="120dp"
android:layout_height="120dp"
android:layout_marginTop="32dp"
android:background="@drawable/btn_duration_selector"
android:text="@string/start_timer"
android:drawableEnd="@drawable/ic_keyboard_arrow_down"
app:cornerRadius="20dp" />
android:drawablePadding="8dp"
android:paddingStart="16dp"
android:paddingEnd="16dp"
android:textColor="#FFFFFF"
android:textSize="18sp"
android:textStyle="bold"
android:gravity="center"
android:includeFontPadding="false" />
<HorizontalScrollView
android:id="@+id/hsvDurationOptions"
@@ -165,15 +172,19 @@
</com.google.android.material.chip.ChipGroup>
</HorizontalScrollView>
<com.google.android.material.button.MaterialButton
<Button
android:id="@+id/btnStart"
style="@style/Widget.Material3.Button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_width="120dp"
android:layout_height="120dp"
android:layout_marginTop="16dp"
android:background="@drawable/btn_start_selector"
android:drawableTop="@drawable/ic_play_arrow"
android:gravity="center"
android:padding="16dp"
android:text="@string/start_timer"
app:cornerRadius="20dp"
app:icon="@drawable/ic_play_arrow" />
android:textColor="#FFFFFF"
android:textSize="16sp"
android:textStyle="bold" />
</LinearLayout>
</com.google.android.material.card.MaterialCardView>
+58 -34
View File
@@ -5,47 +5,71 @@
android:layout_height="match_parent"
android:background="#80000000">
<com.example.countdowntimer.CountdownCanvasView
android:id="@+id/cvCountdown"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toTopOf="@id/buttonRow"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<LinearLayout
android:id="@+id/buttonRow"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginBottom="48dp"
android:gravity="center"
android:orientation="horizontal"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent">
<Button
android:id="@+id/btnStop"
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_marginEnd="16dp"
android:background="@drawable/btn_stop_selector"
android:drawableTop="@drawable/ic_stop_square"
android:gravity="center"
android:padding="16dp"
android:text="Stop"
android:textColor="#FFFFFF"
android:textSize="14sp"
android:textStyle="bold" />
<Button
android:id="@+id/btnRestart"
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_marginStart="16dp"
android:background="@drawable/btn_restart_selector"
android:drawableTop="@drawable/ic_refresh_square"
android:gravity="center"
android:padding="16dp"
android:text="Restart"
android:textColor="#FFFFFF"
android:textSize="14sp"
android:textStyle="bold" />
</LinearLayout>
<Button
android:id="@+id/btnDismiss"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_width="100dp"
android:layout_height="100dp"
android:background="@drawable/btn_duration_selector"
android:gravity="center"
android:padding="16dp"
android:text="Dismiss"
android:textColor="#FFFFFF"
android:textSize="14sp"
android:textStyle="bold"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
<com.example.countdowntimer.CountdownCanvasView
android:id="@+id/cvCountdown"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toTopOf="@id/btnStop"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:layout_margin="16dp" />
<Button
android:id="@+id/btnStop"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Stop"
android:layout_marginTop="16dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toStartOf="@id/btnRestart"
app:layout_constraintHorizontal_chainStyle="spread" />
<Button
android:id="@+id/btnRestart"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Restart"
android:layout_marginTop="16dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toEndOf="@id/btnStop"
app:layout_constraintEnd_toEndOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
+88
View File
@@ -0,0 +1,88 @@
# 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)