diff --git a/app/src/main/java/com/example/hairdryer/MainActivity.kt b/app/src/main/java/com/example/hairdryer/MainActivity.kt index 14ac650..d09ff03 100644 --- a/app/src/main/java/com/example/hairdryer/MainActivity.kt +++ b/app/src/main/java/com/example/hairdryer/MainActivity.kt @@ -7,7 +7,9 @@ import android.media.SoundPool import android.os.Bundle import android.os.Handler import android.widget.EditText +import android.widget.ProgressBar import android.widget.TextView +import kotlin.math.pow class MainActivity : Activity() { @@ -18,6 +20,9 @@ class MainActivity : Activity() { private var isPlaying = false private var remainingMinutes = 0 private var countdownRunnable: Runnable? = null + private var fadeRunnable: Runnable? = null + private var totalMillis: Long = 0 + private var startTime: Long = 0 override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -25,6 +30,7 @@ class MainActivity : Activity() { val status = findViewById(R.id.statusText) val input = findViewById(R.id.timerInput) + val volumeBar = findViewById(R.id.volumeBar) val attrs = AudioAttributes.Builder() .setUsage(AudioAttributes.USAGE_MEDIA) @@ -38,59 +44,92 @@ class MainActivity : Activity() { soundId = soundPool.load(this, R.raw.sound, 1) - // Anfangszustand - updateUI(status, "Ready", Color.LTGRAY) + updateUI(status, volumeBar, "Ready", Color.LTGRAY, 1f) - // Das Statusfeld ist jetzt klickbar status.setOnClickListener { if (isPlaying) { - stopSound(status) + stopSound(status, volumeBar) } else { val min = input.text.toString().toIntOrNull() ?: 0 - startSound(min, status) + startSound(min, status, volumeBar) } } } - private fun startSound(minutes: Int, status: TextView) { - stopSound(status) + private fun startSound(minutes: Int, status: TextView, volumeBar: ProgressBar) { + stopSound(status, volumeBar) streamId = soundPool.play(soundId, 1f, 1f, 1, -1, 1f) isPlaying = true + startTime = System.currentTimeMillis() if (minutes > 0) { remainingMinutes = minutes - updateUI(status, "Runs for: $remainingMinutes min", Color.GREEN) + totalMillis = minutes * 60_000L + updateUI(status, volumeBar, "Runs for: $remainingMinutes min", Color.GREEN, 1f) + + // Countdown jede Minute countdownRunnable = object : Runnable { override fun run() { remainingMinutes-- if (remainingMinutes > 0) { - updateUI(status, "Runs for: $remainingMinutes min", Color.GREEN) + updateUI(status, volumeBar, "Runs for: $remainingMinutes min", Color.GREEN, currentVolume()) handler.postDelayed(this, 60_000L) } else { - stopSound(status) + stopSound(status, volumeBar) } } } handler.postDelayed(countdownRunnable!!, 60_000L) + + // 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) + } + } + } + handler.postDelayed(fadeRunnable!!, 200L) + } else { - updateUI(status, "Runs: ∞", Color.GREEN) + // unendlich + updateUI(status, volumeBar, "Runs: ∞", Color.GREEN, 1f) + volumeBar.progress = 100 } } - private fun stopSound(status: TextView) { + private fun stopSound(status: TextView, volumeBar: ProgressBar) { if (isPlaying) { soundPool.stop(streamId) isPlaying = false } remainingMinutes = 0 handler.removeCallbacks(countdownRunnable ?: Runnable { }) - updateUI(status, "Stopped", Color.RED) + handler.removeCallbacks(fadeRunnable ?: Runnable { }) + updateUI(status, volumeBar, "Stopped", Color.RED, 0f) + volumeBar.progress = 0 } - private fun updateUI(view: TextView, text: String, color: Int) { + private fun updateUI(view: TextView, bar: ProgressBar, text: String, color: Int, volume: Float) { view.text = text view.setBackgroundColor(color) view.setTextColor(Color.BLACK) + 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() { diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index d05a818..a8c9cd5 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -37,4 +37,13 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="20dp"/> + +