Compare commits

..

6 Commits

3 changed files with 142 additions and 15 deletions

1
.idea/gradle.xml generated
View File

@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project version="4"> <project version="4">
<component name="GradleMigrationSettings" migrationVersion="1" />
<component name="GradleSettings"> <component name="GradleSettings">
<option name="linkedExternalProjectsSettings"> <option name="linkedExternalProjectsSettings">
<GradleProjectSettings> <GradleProjectSettings>

View File

@@ -1,25 +1,38 @@
package com.example.hairdryer package com.example.hairdryer
import android.app.Activity import android.app.Activity
import android.graphics.Color
import android.media.AudioAttributes import android.media.AudioAttributes
import android.media.SoundPool import android.media.SoundPool
import android.os.Bundle import android.os.Bundle
import android.os.Handler import android.os.Handler
import android.widget.Button
import android.widget.EditText import android.widget.EditText
import android.widget.ProgressBar
import android.widget.TextView
import kotlin.math.pow
import kotlin.math.max
class MainActivity : Activity() { class MainActivity : Activity() {
private lateinit var soundPool: SoundPool private lateinit var soundPool: SoundPool
private var soundId = 0 private var soundId = 0
private var streamId = 0 private var streamId = 0
private val handler = Handler() private val handler = Handler()
private var isPlaying = false
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?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main) setContentView(R.layout.activity_main)
val status = findViewById<TextView>(R.id.statusText)
val input = findViewById<EditText>(R.id.timerInput) val input = findViewById<EditText>(R.id.timerInput)
val btn = findViewById<Button>(R.id.startBtn) val fadeToggle = findViewById<TextView>(R.id.fadeToggle)
val volumeBar = findViewById<ProgressBar>(R.id.volumeBar)
val attrs = AudioAttributes.Builder() val attrs = AudioAttributes.Builder()
.setUsage(AudioAttributes.USAGE_MEDIA) .setUsage(AudioAttributes.USAGE_MEDIA)
@@ -33,22 +46,97 @@ class MainActivity : Activity() {
soundId = soundPool.load(this, R.raw.sound, 1) soundId = soundPool.load(this, R.raw.sound, 1)
btn.setOnClickListener { updateUI(status, volumeBar, "Bereit", Color.LTGRAY, 1f)
val min = input.text.toString().toIntOrNull() ?: 0 fadeToggle.setOnClickListener {
startLoopingSound(min) fadeEnabled = !fadeEnabled
fadeToggle.text = "Fade-Out: " + if (fadeEnabled) "ON" else "OFF"
}
status.setOnClickListener {
if (isPlaying) {
stopSound(status, volumeBar)
} else {
val minutes = input.text.toString().toIntOrNull() ?: 0
startSound(minutes, status, volumeBar)
}
} }
} }
private fun startLoopingSound(minutes: Int) { private fun startSound(minutes: Int, status: TextView, volumeBar: ProgressBar) {
// Starte Sound in Schleife stopSound(status, volumeBar)
streamId = soundPool.play(soundId, 1f, 1f, 1, -1, 1f) // -1 = loop unendlich streamId = soundPool.play(soundId, 1f, 1f, 1, -1, 1f)
isPlaying = true
startTime = System.currentTimeMillis()
if (minutes > 0) { if (minutes > 0) {
handler.postDelayed({ totalMillis = minutes * 60_000L
soundPool.stop(streamId) updateCountdown(minutes * 60, status)
}, minutes * 60_000L) // Countdown jede Sekunde
countdownRunnable = object : Runnable {
override fun run() {
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!!, 1000L)
// 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
}
} else {
// unendlich
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
}
handler.removeCallbacks(countdownRunnable ?: Runnable {})
handler.removeCallbacks(fadeRunnable ?: Runnable {})
updateUI(status, volumeBar, "Gestoppt", Color.RED, 0f)
volumeBar.progress = 0
}
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()
}
override fun onDestroy() { override fun onDestroy() {
super.onDestroy() super.onDestroy()

View File

@@ -6,17 +6,55 @@
android:orientation="vertical" android:orientation="vertical"
android:padding="20dp"> android:padding="20dp">
<TextView
android:id="@+id/parentDeviceTitle"
android:gravity="center_horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="top|center_vertical"
android:text="Dunstabzugshaube/Hairdryer"
android:textSize="25dp" />
<Space
android:layout_width="match_parent"
android:layout_height="50dp" />
<TextView
android:id="@+id/statusText"
android:text="Bereit"
android:textSize="26sp"
android:gravity="center"
android:textColor="#000000"
android:padding="24dp"
android:background="#CCCCCC"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<EditText <EditText
android:id="@+id/timerInput" android:id="@+id/timerInput"
android:hint="Sleep Timer (Minuten)" android:hint="Sleep Timer (Minuten)"
android:inputType="number" android:inputType="number"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content"/> android:layout_height="wrap_content"
android:layout_marginTop="20dp"/>
<Button <TextView
android:id="@+id/startBtn" android:id="@+id/fadeToggle"
android:text="Start" android:text="Fade-Out: OFF"
android:gravity="center"
android:padding="12dp"
android:layout_marginTop="20dp"
android:background="#AAAAAA"
android:textColor="#000000"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content"/> android:layout_height="wrap_content"/>
<ProgressBar
android:id="@+id/volumeBar"
style="@android:style/Widget.ProgressBar.Horizontal"
android:layout_width="match_parent"
android:layout_height="24dp"
android:layout_marginTop="20dp"
android:max="100"
android:progress="100"/>
</LinearLayout> </LinearLayout>