Initial implementation of Tilt-Shift Camera Android app
A dedicated camera app for tilt-shift photography with: - Real-time OpenGL ES 2.0 shader-based blur preview - Touch gesture controls (drag, rotate, pinch) for adjusting effect - CameraX integration for camera preview and high-res capture - EXIF metadata with GPS location support - MediaStore integration for saving to gallery - Jetpack Compose UI with haptic feedback Tech stack: Kotlin, CameraX, OpenGL ES 2.0, Jetpack Compose Min SDK: 26 (Android 8.0), Target SDK: 35 (Android 15) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
commit
07e10ac9c3
38 changed files with 3489 additions and 0 deletions
98
app/src/main/java/no/naiv/tiltshift/util/HapticFeedback.kt
Normal file
98
app/src/main/java/no/naiv/tiltshift/util/HapticFeedback.kt
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
package no.naiv.tiltshift.util
|
||||
|
||||
import android.content.Context
|
||||
import android.os.Build
|
||||
import android.os.VibrationEffect
|
||||
import android.os.Vibrator
|
||||
import android.os.VibratorManager
|
||||
import android.view.HapticFeedbackConstants
|
||||
import android.view.View
|
||||
|
||||
/**
|
||||
* Provides haptic feedback for user interactions.
|
||||
*/
|
||||
class HapticFeedback(private val context: Context) {
|
||||
|
||||
private val vibrator: Vibrator by lazy {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
||||
val vibratorManager = context.getSystemService(Context.VIBRATOR_MANAGER_SERVICE) as VibratorManager
|
||||
vibratorManager.defaultVibrator
|
||||
} else {
|
||||
@Suppress("DEPRECATION")
|
||||
context.getSystemService(Context.VIBRATOR_SERVICE) as Vibrator
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Light tick for UI feedback (button press, slider change).
|
||||
*/
|
||||
fun tick() {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||
vibrator.vibrate(VibrationEffect.createPredefined(VibrationEffect.EFFECT_TICK))
|
||||
} else {
|
||||
@Suppress("DEPRECATION")
|
||||
vibrator.vibrate(10L)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Click feedback for confirmations.
|
||||
*/
|
||||
fun click() {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||
vibrator.vibrate(VibrationEffect.createPredefined(VibrationEffect.EFFECT_CLICK))
|
||||
} else {
|
||||
@Suppress("DEPRECATION")
|
||||
vibrator.vibrate(20L)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Heavy click for important actions (photo capture).
|
||||
*/
|
||||
fun heavyClick() {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||
vibrator.vibrate(VibrationEffect.createPredefined(VibrationEffect.EFFECT_HEAVY_CLICK))
|
||||
} else {
|
||||
@Suppress("DEPRECATION")
|
||||
vibrator.vibrate(40L)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Success feedback pattern.
|
||||
*/
|
||||
fun success() {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||
val timings = longArrayOf(0, 30, 50, 30)
|
||||
val amplitudes = intArrayOf(0, 100, 0, 200)
|
||||
vibrator.vibrate(VibrationEffect.createWaveform(timings, amplitudes, -1))
|
||||
} else {
|
||||
@Suppress("DEPRECATION")
|
||||
vibrator.vibrate(longArrayOf(0, 30, 50, 30), -1)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Error feedback pattern.
|
||||
*/
|
||||
fun error() {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||
val timings = longArrayOf(0, 50, 30, 50, 30, 50)
|
||||
val amplitudes = intArrayOf(0, 150, 0, 150, 0, 150)
|
||||
vibrator.vibrate(VibrationEffect.createWaveform(timings, amplitudes, -1))
|
||||
} else {
|
||||
@Suppress("DEPRECATION")
|
||||
vibrator.vibrate(longArrayOf(0, 50, 30, 50, 30, 50), -1)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
/**
|
||||
* Use system haptic feedback on a View for standard interactions.
|
||||
*/
|
||||
fun performHapticFeedback(view: View, feedbackConstant: Int = HapticFeedbackConstants.VIRTUAL_KEY) {
|
||||
view.performHapticFeedback(feedbackConstant)
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue