Compare commits

..

7 Commits

Author SHA1 Message Date
pi
82276868c4 drehen und weiterspielen funktioniert jetzt
fixes #1
closes #1
resolves #1
2025-11-29 16:23:27 +01:00
pi
d14ec42a92 fade out now exponential and optional when minutes set 2025-11-03 18:17:10 +01:00
pi
0d5561feaf fade out enabled for set minutes and added volumen bar in ui 2025-11-03 18:07:44 +01:00
pi
fa671d6fc4 integrated start/stop button to ready or stopped button 2025-11-03 17:44:37 +01:00
pi
a16fd1e995 added colors 2025-10-29 14:02:00 +01:00
pi
1ca9f10658 changed to start/stopp 2025-10-29 13:47:08 +01:00
pi
6c3a36efe3 added stop button and info to put in minutes 2025-10-29 13:20:31 +01:00
4 changed files with 145 additions and 17 deletions

1
.idea/gradle.xml generated
View File

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

View File

@@ -8,9 +8,10 @@
android:supportsRtl="true"
android:theme="@android:style/Theme.Light.NoTitleBar">
<activity android:name=".MainActivity"
android:exported="true">
android:exported="true"
android:configChanges="orientation|screenSize|keyboardHidden"
>
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>

View File

@@ -1,25 +1,38 @@
package com.example.hairdryer
import android.app.Activity
import android.graphics.Color
import android.media.AudioAttributes
import android.media.SoundPool
import android.os.Bundle
import android.os.Handler
import android.widget.Button
import android.widget.EditText
import android.widget.ProgressBar
import android.widget.TextView
import kotlin.math.pow
import kotlin.math.max
class MainActivity : Activity() {
private lateinit var soundPool: SoundPool
private var soundId = 0
private var streamId = 0
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?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val status = findViewById<TextView>(R.id.statusText)
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()
.setUsage(AudioAttributes.USAGE_MEDIA)
@@ -33,23 +46,98 @@ class MainActivity : Activity() {
soundId = soundPool.load(this, R.raw.sound, 1)
btn.setOnClickListener {
val min = input.text.toString().toIntOrNull() ?: 0
startLoopingSound(min)
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 minutes = input.text.toString().toIntOrNull() ?: 0
startSound(minutes, status, volumeBar)
}
}
}
private fun startLoopingSound(minutes: Int) {
// Starte Sound in Schleife
streamId = soundPool.play(soundId, 1f, 1f, 1, -1, 1f) // -1 = loop unendlich
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) {
handler.postDelayed({
soundPool.stop(streamId)
}, minutes * 60_000L)
totalMillis = minutes * 60_000L
updateCountdown(minutes * 60, status)
// 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() {
super.onDestroy()
soundPool.release()

View File

@@ -6,17 +6,55 @@
android:orientation="vertical"
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
android:id="@+id/timerInput"
android:hint="Sleep Timer (Minuten)"
android:inputType="number"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
android:layout_height="wrap_content"
android:layout_marginTop="20dp"/>
<Button
android:id="@+id/startBtn"
android:text="Start"
<TextView
android:id="@+id/fadeToggle"
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_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>