add button settings, and no sleep for devices
This commit is contained in:
parent
eb3fd7aca3
commit
30321e051c
|
|
@ -5,12 +5,14 @@ import android.os.Build
|
||||||
import android.os.VibrationEffect
|
import android.os.VibrationEffect
|
||||||
import android.os.Vibrator
|
import android.os.Vibrator
|
||||||
import android.os.VibratorManager
|
import android.os.VibratorManager
|
||||||
|
import android.view.WindowManager
|
||||||
import io.flutter.embedding.android.FlutterActivity
|
import io.flutter.embedding.android.FlutterActivity
|
||||||
import io.flutter.embedding.engine.FlutterEngine
|
import io.flutter.embedding.engine.FlutterEngine
|
||||||
import io.flutter.plugin.common.MethodChannel
|
import io.flutter.plugin.common.MethodChannel
|
||||||
|
|
||||||
class MainActivity : FlutterActivity() {
|
class MainActivity : FlutterActivity() {
|
||||||
private val vibrationChannel = "smart_vision_assist/vibration"
|
private val vibrationChannel = "smart_vision_assist/vibration"
|
||||||
|
private val screenChannel = "smart_vision_assist/screen"
|
||||||
|
|
||||||
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
|
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
|
||||||
super.configureFlutterEngine(flutterEngine)
|
super.configureFlutterEngine(flutterEngine)
|
||||||
|
|
@ -31,6 +33,30 @@ class MainActivity : FlutterActivity() {
|
||||||
else -> result.notImplemented()
|
else -> result.notImplemented()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MethodChannel(
|
||||||
|
flutterEngine.dartExecutor.binaryMessenger,
|
||||||
|
screenChannel
|
||||||
|
).setMethodCallHandler { call, result ->
|
||||||
|
when (call.method) {
|
||||||
|
"setKeepScreenOn" -> {
|
||||||
|
val enabled = call.argument<Boolean>("enabled") ?: false
|
||||||
|
setKeepScreenOn(enabled)
|
||||||
|
result.success(null)
|
||||||
|
}
|
||||||
|
else -> result.notImplemented()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setKeepScreenOn(enabled: Boolean) {
|
||||||
|
runOnUiThread {
|
||||||
|
if (enabled) {
|
||||||
|
window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
|
||||||
|
} else {
|
||||||
|
window.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun vibrate(milliseconds: Long): Boolean {
|
private fun vibrate(milliseconds: Long): Boolean {
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ import 'dart:ui' as ui;
|
||||||
|
|
||||||
import 'package:camera/camera.dart';
|
import 'package:camera/camera.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
import 'package:shared_preferences/shared_preferences.dart';
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
|
|
||||||
import '../services/tts_service.dart';
|
import '../services/tts_service.dart';
|
||||||
|
|
@ -19,7 +20,10 @@ class CameraScreen extends StatefulWidget {
|
||||||
State<CameraScreen> createState() => _CameraScreenState();
|
State<CameraScreen> createState() => _CameraScreenState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _CameraScreenState extends State<CameraScreen> {
|
class _CameraScreenState extends State<CameraScreen> with WidgetsBindingObserver {
|
||||||
|
static const MethodChannel _screenChannel =
|
||||||
|
MethodChannel("smart_vision_assist/screen");
|
||||||
|
|
||||||
CameraController? controller;
|
CameraController? controller;
|
||||||
List<CameraDescription>? cameras;
|
List<CameraDescription>? cameras;
|
||||||
|
|
||||||
|
|
@ -36,15 +40,31 @@ class _CameraScreenState extends State<CameraScreen> {
|
||||||
Timer? _vibrationTimer;
|
Timer? _vibrationTimer;
|
||||||
|
|
||||||
bool _isLoggingOut = false;
|
bool _isLoggingOut = false;
|
||||||
|
bool _isStatusActive = true;
|
||||||
String _lastSpokenMessage = "";
|
String _lastSpokenMessage = "";
|
||||||
DateTime? _lastSpokenAt;
|
DateTime? _lastSpokenAt;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
|
WidgetsBinding.instance.addObserver(this);
|
||||||
|
unawaited(_setKeepScreenOn(true));
|
||||||
initCamera();
|
initCamera();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> _setKeepScreenOn(bool enabled) async {
|
||||||
|
try {
|
||||||
|
await _screenChannel.invokeMethod<void>(
|
||||||
|
"setKeepScreenOn",
|
||||||
|
{"enabled": enabled},
|
||||||
|
);
|
||||||
|
} on MissingPluginException {
|
||||||
|
// Platform selain Android boleh mengabaikan fitur ini.
|
||||||
|
} catch (_) {
|
||||||
|
// Jangan sampai kegagalan wakelock mengganggu kamera.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Future<void> initCamera() async {
|
Future<void> initCamera() async {
|
||||||
try {
|
try {
|
||||||
cameras = await availableCameras();
|
cameras = await availableCameras();
|
||||||
|
|
@ -281,15 +301,91 @@ class _CameraScreenState extends State<CameraScreen> {
|
||||||
await _tts.speak(message);
|
await _tts.speak(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<bool> _confirmDeactivateAccount() async {
|
||||||
|
final bool? confirmed = await showDialog<bool>(
|
||||||
|
context: context,
|
||||||
|
builder: (BuildContext confirmationContext) {
|
||||||
|
return AlertDialog(
|
||||||
|
title: const Text("Konfirmasi"),
|
||||||
|
content: const Text("Apakah anda yakin menonaktifkan akun ini?"),
|
||||||
|
actions: [
|
||||||
|
TextButton(
|
||||||
|
onPressed: () => Navigator.of(confirmationContext).pop(false),
|
||||||
|
child: const Text("Tidak"),
|
||||||
|
),
|
||||||
|
TextButton(
|
||||||
|
onPressed: () => Navigator.of(confirmationContext).pop(true),
|
||||||
|
child: const Text("Ya"),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
return confirmed ?? false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void _showSettings() {
|
||||||
|
showDialog<void>(
|
||||||
|
context: context,
|
||||||
|
builder: (BuildContext dialogContext) {
|
||||||
|
return StatefulBuilder(
|
||||||
|
builder: (BuildContext context, StateSetter setDialogState) {
|
||||||
|
return AlertDialog(
|
||||||
|
title: const Text("Setting"),
|
||||||
|
content: SwitchListTile(
|
||||||
|
contentPadding: EdgeInsets.zero,
|
||||||
|
title: const Text("Status"),
|
||||||
|
subtitle: Text(_isStatusActive ? "Aktif" : "Nonaktif"),
|
||||||
|
value: _isStatusActive,
|
||||||
|
onChanged: (bool value) async {
|
||||||
|
if (!value) {
|
||||||
|
final bool isConfirmed =
|
||||||
|
await _confirmDeactivateAccount();
|
||||||
|
if (!isConfirmed || !mounted) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setState(() {
|
||||||
|
_isStatusActive = value;
|
||||||
|
});
|
||||||
|
setDialogState(() {});
|
||||||
|
},
|
||||||
|
),
|
||||||
|
actions: [
|
||||||
|
TextButton(
|
||||||
|
onPressed: () => Navigator.of(dialogContext).pop(),
|
||||||
|
child: const Text("Tutup"),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
_detectionTimer?.cancel();
|
_detectionTimer?.cancel();
|
||||||
_vibrationTimer?.cancel();
|
_vibrationTimer?.cancel();
|
||||||
|
WidgetsBinding.instance.removeObserver(this);
|
||||||
|
unawaited(_setKeepScreenOn(false));
|
||||||
unawaited(_vibrationService.stop());
|
unawaited(_vibrationService.stop());
|
||||||
controller?.dispose();
|
controller?.dispose();
|
||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void didChangeAppLifecycleState(AppLifecycleState state) {
|
||||||
|
if (state == AppLifecycleState.resumed) {
|
||||||
|
unawaited(_setKeepScreenOn(true));
|
||||||
|
} else {
|
||||||
|
unawaited(_setKeepScreenOn(false));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Widget buildCameraPreview() {
|
Widget buildCameraPreview() {
|
||||||
final Size? previewSize = controller?.value.previewSize;
|
final Size? previewSize = controller?.value.previewSize;
|
||||||
if (previewSize == null) {
|
if (previewSize == null) {
|
||||||
|
|
@ -421,6 +517,20 @@ class _CameraScreenState extends State<CameraScreen> {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
Positioned(
|
||||||
|
bottom: 40,
|
||||||
|
left: MediaQuery.of(context).size.width / 2 - 130,
|
||||||
|
child: Semantics(
|
||||||
|
label: "Buka setting",
|
||||||
|
button: true,
|
||||||
|
child: FloatingActionButton(
|
||||||
|
heroTag: "camera_settings",
|
||||||
|
backgroundColor: Colors.black,
|
||||||
|
onPressed: _showSettings,
|
||||||
|
child: const Icon(Icons.settings, color: Colors.white),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ class ApiConfig {
|
||||||
static const bool useAndroidEmulator = false;
|
static const bool useAndroidEmulator = false;
|
||||||
|
|
||||||
// Ganti IP ini dengan IP laptop/PC Anda saat menggunakan HP fisik (ADB).
|
// Ganti IP ini dengan IP laptop/PC Anda saat menggunakan HP fisik (ADB).
|
||||||
static const String deviceHost = "192.168.110.147:8000";
|
static const String deviceHost = "192.168.0.31:8000";
|
||||||
|
|
||||||
static String get baseUrl {
|
static String get baseUrl {
|
||||||
if (Platform.isAndroid && useAndroidEmulator) {
|
if (Platform.isAndroid && useAndroidEmulator) {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue