From d14ec42a923155e2be3261e3877a20b3a100af0d Mon Sep 17 00:00:00 2001 From: pi Date: Mon, 3 Nov 2025 18:17:10 +0100 Subject: [PATCH] fade out now exponential and optional when minutes set --- .../com/example/hairdryer/MainActivity.kt | 90 ++++++++++--------- app/src/main/res/layout/activity_main.xml | 11 +++ 2 files changed, 59 insertions(+), 42 deletions(-) diff --git a/app/src/main/java/com/example/hairdryer/MainActivity.kt b/app/src/main/java/com/example/hairdryer/MainActivity.kt index d09ff03..a883c25 100644 --- a/app/src/main/java/com/example/hairdryer/MainActivity.kt +++ b/app/src/main/java/com/example/hairdryer/MainActivity.kt @@ -10,6 +10,7 @@ import android.widget.EditText import android.widget.ProgressBar import android.widget.TextView import kotlin.math.pow +import kotlin.math.max class MainActivity : Activity() { @@ -18,11 +19,11 @@ class MainActivity : Activity() { private var streamId = 0 private val handler = Handler() private var isPlaying = false - private var remainingMinutes = 0 - private var countdownRunnable: Runnable? = null - private var fadeRunnable: Runnable? = null + private var fadeEnabled = false private var totalMillis: Long = 0 private var startTime: Long = 0 + private var fadeRunnable: Runnable? = null + private var countdownRunnable: Runnable? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -30,6 +31,7 @@ class MainActivity : Activity() { val status = findViewById(R.id.statusText) val input = findViewById(R.id.timerInput) + val fadeToggle = findViewById(R.id.fadeToggle) val volumeBar = findViewById(R.id.volumeBar) val attrs = AudioAttributes.Builder() @@ -44,14 +46,18 @@ class MainActivity : Activity() { soundId = soundPool.load(this, R.raw.sound, 1) - updateUI(status, volumeBar, "Ready", Color.LTGRAY, 1f) + updateUI(status, volumeBar, "Bereit", Color.LTGRAY, 1f) + fadeToggle.setOnClickListener { + fadeEnabled = !fadeEnabled + fadeToggle.text = "Fade-Out: " + if (fadeEnabled) "ON" else "OFF" + } status.setOnClickListener { if (isPlaying) { stopSound(status, volumeBar) } else { - val min = input.text.toString().toIntOrNull() ?: 0 - startSound(min, status, volumeBar) + val minutes = input.text.toString().toIntOrNull() ?: 0 + startSound(minutes, status, volumeBar) } } } @@ -63,59 +69,65 @@ class MainActivity : Activity() { startTime = System.currentTimeMillis() if (minutes > 0) { - remainingMinutes = minutes totalMillis = minutes * 60_000L - updateUI(status, volumeBar, "Runs for: $remainingMinutes min", Color.GREEN, 1f) - - // Countdown jede Minute + updateCountdown(minutes * 60, status) + // Countdown jede Sekunde countdownRunnable = object : Runnable { override fun run() { - remainingMinutes-- - if (remainingMinutes > 0) { - updateUI(status, volumeBar, "Runs for: $remainingMinutes min", Color.GREEN, currentVolume()) - handler.postDelayed(this, 60_000L) + val elapsedSec = ((System.currentTimeMillis() - startTime) / 1000).toInt() + val remainingSec = max(minutes * 60 - elapsedSec, 0) + updateCountdown(remainingSec, status) + if (remainingSec > 0) { + handler.postDelayed(this, 1000L) } else { stopSound(status, volumeBar) } } } - handler.postDelayed(countdownRunnable!!, 60_000L) + handler.postDelayed(countdownRunnable!!, 1000L) - // Exponentieller Fade-Out alle 200 ms - fadeRunnable = object : Runnable { - override fun run() { - if (!isPlaying) return - val elapsed = System.currentTimeMillis() - startTime - val progress = (elapsed.toFloat() / totalMillis).coerceIn(0f, 1f) - // exponentielles Absenken: volume = (1 - progress)^2 - val volume = (1 - progress).pow(2) - soundPool.setVolume(streamId, volume, volume) - volumeBar.progress = (volume * 100).toInt() - if (progress < 1f) { - handler.postDelayed(this, 200L) - } else { - stopSound(status, volumeBar) + // Fade-Out (optional) + if (fadeEnabled) { + fadeRunnable = object : Runnable { + override fun run() { + if (!isPlaying) return + val elapsed = System.currentTimeMillis() - startTime + val progress = (elapsed.toFloat() / totalMillis).coerceIn(0f, 1f) + val volume = (1 - progress).pow(2) // exponentielles Fade + soundPool.setVolume(streamId, volume, volume) + volumeBar.progress = (volume * 100).toInt() + if (progress < 1f) { + handler.postDelayed(this, 200L) + } } } + handler.postDelayed(fadeRunnable!!, 200L) + } else { + volumeBar.progress = 100 } - handler.postDelayed(fadeRunnable!!, 200L) - } else { // unendlich - updateUI(status, volumeBar, "Runs: ∞", Color.GREEN, 1f) + updateUI(status, volumeBar, "Läuft: ∞", Color.GREEN, 1f) volumeBar.progress = 100 } } + private fun updateCountdown(remainingSec: Int, status: TextView) { + val minutes = remainingSec / 60 + val seconds = remainingSec % 60 + status.text = String.format("Läuft: %02d:%02d", minutes, seconds) + status.setBackgroundColor(Color.GREEN) + status.setTextColor(Color.BLACK) + } + private fun stopSound(status: TextView, volumeBar: ProgressBar) { if (isPlaying) { soundPool.stop(streamId) isPlaying = false } - remainingMinutes = 0 - handler.removeCallbacks(countdownRunnable ?: Runnable { }) - handler.removeCallbacks(fadeRunnable ?: Runnable { }) - updateUI(status, volumeBar, "Stopped", Color.RED, 0f) + handler.removeCallbacks(countdownRunnable ?: Runnable {}) + handler.removeCallbacks(fadeRunnable ?: Runnable {}) + updateUI(status, volumeBar, "Gestoppt", Color.RED, 0f) volumeBar.progress = 0 } @@ -126,12 +138,6 @@ class MainActivity : Activity() { bar.progress = (volume * 100).toInt() } - private fun currentVolume(): Float { - val elapsed = System.currentTimeMillis() - startTime - val progress = (elapsed.toFloat() / totalMillis).coerceIn(0f, 1f) - return (1 - progress).pow(2) - } - override fun onDestroy() { super.onDestroy() soundPool.release() diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index a8c9cd5..d2ae2db 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -38,6 +38,17 @@ android:layout_height="wrap_content" android:layout_marginTop="20dp"/> + +