Files
stadtbote-app/lib/tools/util.dart
T
2024-06-21 13:34:43 +02:00

458 lines
11 KiB
Dart

import 'dart:io';
import 'package:audioplayers/audioplayers.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:image_picker/image_picker.dart';
import 'package:package_info_plus/package_info_plus.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:stadtbote/main.dart';
import 'package:stadtbote/model/job.dart';
import 'package:stadtbote/model/log_entry.dart';
import 'package:stadtbote/tools/constants.dart';
import 'package:url_launcher/url_launcher.dart';
import 'package:uuid/uuid.dart';
import '../Tools/colored_safe_area.dart';
class Util {
static Future<bool> preferencesContainsKey(String key) async {
var prefs = await SharedPreferences.getInstance();
return prefs.containsKey(key);
}
static void preferencesSaveString(String key, String value) async {
var prefs = await SharedPreferences.getInstance();
await prefs.setString(key, value);
}
static Future<String?> preferencesGetString(String key, String? defaultValue) async {
if (await preferencesContainsKey(key)) {
var prefs = await SharedPreferences.getInstance();
return prefs.getString(key);
}
return defaultValue;
}
static void preferencesSaveInt(String key, int value) async {
var prefs = await SharedPreferences.getInstance();
await prefs.setInt(key, value);
}
static Future<int?> preferencesGetInt(String key, int? defaultValue) async {
if (await preferencesContainsKey(key)) {
var prefs = await SharedPreferences.getInstance();
return prefs.getInt(key);
}
return defaultValue;
}
static void preferencesSaveBool(String key, bool value) async {
var prefs = await SharedPreferences.getInstance();
await prefs.setBool(key, value);
}
static Future<bool> preferencesGetBool(String key, bool defaultValue) async {
if (await preferencesContainsKey(key)) {
var prefs = await SharedPreferences.getInstance();
return prefs.getBool(key) as bool;
}
return defaultValue;
}
static Future<String> getAppUuid() async {
var currentUuid = await preferencesGetString('uuid', null);
if (currentUuid == null) {
currentUuid ??= const Uuid().v4();
preferencesSaveString("uuid", currentUuid);
}
return currentUuid;
}
static Future<int> getAppVersion() async {
PackageInfo packageInfo = await PackageInfo.fromPlatform();
return int.parse(packageInfo.version.replaceAll(".0.0", ""));
}
static _printLongText(String text) {
final pattern = RegExp('.{1,800}'); // 800 is the size of each chunk
pattern.allMatches(text).forEach((match) => debugPrint(match.group(0)));
}
static void _persistLogMessage(String text, LogEntrySeverityEnum severity) async {
var logEntry = LogEntry();
logEntry.time = DateTime.now();
logEntry.text = text;
logEntry.severity = severity;
await MyApp.isarInstance.writeTxn(() async {
await MyApp.isarInstance.logEntrys.put(logEntry);
});
}
static logInfo(String message) {
_printLongText(message);
_persistLogMessage(message, LogEntrySeverityEnum.info);
}
static logDebug(String message) {
_printLongText(message);
_persistLogMessage(message, LogEntrySeverityEnum.debug);
}
static logException(String message) {
_printLongText(message);
_persistLogMessage(message, LogEntrySeverityEnum.error);
}
static int fastHash(String string) {
var hash = 0xcbf29ce484222325;
var i = 0;
while (i < string.length) {
final codeUnit = string.codeUnitAt(i++);
hash ^= codeUnit >> 8;
hash *= 0x100000001b3;
hash ^= codeUnit & 0xFF;
hash *= 0x100000001b3;
}
return hash;
}
static Widget getWaitWidget(context) {
return ColoredSafeArea(
key: const Key('value'),
child: Container(
width: 10,
height: 10,
color: Colors.white,
),
);
}
static Future<Widget> fetchFutureIcon(icon) {
return Future.delayed(const Duration(seconds: 0), () async {
return icon;
});
}
static TextField getDefaultTextField(String hint,
{TextEditingController? controller,
FocusNode? focusNode,
IconButton? iconButton,
int? maxLines = 1,
TextInputType? textInputType,
List<TextInputFormatter>? formatter,
Function()? onTap,
bool? autofocus}) {
iconButton ??= IconButton(
icon: const Icon(Icons.clear),
onPressed: () {
if (controller != null) {
controller.text = "";
}
},
);
return TextField(
controller: controller,
focusNode: focusNode,
maxLines: maxLines,
onTap: onTap,
keyboardType: textInputType,
inputFormatters: formatter,
autofocus: (autofocus != null) ? autofocus : false,
decoration: InputDecoration(
hintText: hint,
contentPadding: const EdgeInsets.all(10),
border: Util.getDefaultBorder(),
errorBorder: Util.getDefaultBorder(),
disabledBorder: Util.getDefaultBorder(),
focusedBorder: Util.getDefaultFocusedBorder(),
focusedErrorBorder: Util.getDefaultBorder(),
suffixIcon: iconButton,
labelText: hint),
);
}
static OutlineInputBorder getDefaultBorder() {
return const OutlineInputBorder(borderRadius: BorderRadius.all(Radius.circular(20.0)));
}
static OutlineInputBorder getDefaultFocusedBorder() {
return const OutlineInputBorder(
borderSide: BorderSide(color: Constants.colorPrimary),
borderRadius: BorderRadius.all(Radius.circular(20.0)),
);
}
static Future<File?> capturePhoto() async {
final imagePicker = ImagePicker();
final pickedFile = await imagePicker.pickImage(source: ImageSource.camera);
if (pickedFile != null) {
return File(pickedFile.path);
}
return null;
}
static Future<void> startBrowser(String websiteUrl) async {
if (!await launchUrl(Uri.parse(websiteUrl))) {
throw Exception('Could not launch $websiteUrl');
}
}
static Future<void> playMp3(String name) async {
final player = AudioPlayer();
await player.play(AssetSource('sounds/$name'), volume: 1);
}
}
Widget getDefaultButton(String text, Function() onPressed, {Image? image, double? buttonHeight, bool enabledTimerActive = true, int enabledTimerDelay = 0}) {
bool enabledState = enabledTimerActive;
return StatefulBuilder(builder: (BuildContext context, StateSetter setState) {
if (!enabledState) {
Future.delayed(Duration(seconds: enabledTimerDelay), () {
enabledState = true;
if (context.mounted) {
setState(() {});
}
});
}
return SizedBox(
height: buttonHeight ?? 50,
child: MaterialButton(
color: const Color.fromARGB(255, 220, 220, 220),
disabledColor: const Color.fromARGB(255, 220, 220, 220),
disabledElevation: 5,
elevation: 5,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.all(
Radius.circular(15),
),
),
onPressed: () {
if (enabledState) {
Util.logInfo("Button \"$text\" clicked");
onPressed();
}
},
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Visibility(
visible: image != null,
child: CircleAvatar(
backgroundColor: Colors.transparent,
child: image,
),
),
Expanded(
child: Opacity(
opacity: enabledState ? 1.0 : 0.3,
child: Text(
text,
style: const TextStyle(color: Colors.black, fontSize: 14.0),
textAlign: TextAlign.center,
),
),
),
],
),
),
);
});
}
String mapVehicleTypeToImageName(int vehType)
{
switch (vehType) {
case 1:
return "fahrrad.png";
case 2:
return "pkw.png";
case 3:
return "kombi.png";
case 4:
return "kasten.png";
case 5:
return "bus.png";
case 6:
return "grbus.png";
case 7:
return "lkw.png";
case 8:
return "lkw_12.png";
case 10:
return "lkw_8.png";
case 11:
return "lkw_10.png";
case 12:
return "lkw_15.png";
case 13:
return "lkw_20.png";
case 999:
return "service.png";
}
return "unbekannt.png";
}
String mapVehicleTypeToText(int vehType) {
switch (vehType) {
case 1:
return "Fahrrad";
case 2:
return "Pkw";
case 3:
return "Kombi";
case 4:
return "Kasten";
case 5:
return "Bus";
case 6:
return "GrBus";
case 7:
case 8:
case 10:
case 11:
case 12:
case 13:
case 14:
return "Lkw";
case 999:
return "Service";
}
return "!?????!";
}
String mapTourMode(String mode) {
var text = "";
switch (mode) {
case "pu":
text += "/ Abholung";
break;
case "del":
text += "/ Auslieferung";
break;
case "pudel":
text += "/ Abholung/Auslieferung";
break;
}
return text;
}
Future<void> showQuestionDialog(BuildContext context, String title, String message, List<Widget> actions) async {
await showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: Text(title),
content: Text(message),
actions: actions,
);
}
);
}
Future<void> showAlertDialog(BuildContext context, String title, String message) async {
await showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: Text(title),
content: Text(message),
actions: [
TextButton(
onPressed: () => Navigator.pop(context),
child: const Text('OK'),
),
],
);
}
);
}
class DecimalTextInputFormatter extends TextInputFormatter {
int maxLength;
int decimalPlaces;
DecimalTextInputFormatter({required this.maxLength, required this.decimalPlaces});
@override
TextEditingValue formatEditUpdate(TextEditingValue oldValue, TextEditingValue newValue) {
var text = newValue.text;
String? filteredText = "";
if (text != "") {
RegExp regExp;
if (decimalPlaces > 0) {
regExp = RegExp(r'[0-9]+[,]{0,1}[0-9]{0,' + decimalPlaces.toString() + '}');
} else {
regExp = RegExp(r'[0-9]{0,' + maxLength.toString() +'}');
}
filteredText = regExp.stringMatch(text);
}
return TextEditingValue(text: filteredText ?? oldValue.text);
}
}
bool isJobInFuture(Job job) {
return DateTime.parse(job.ordertime).add(Duration(minutes: job.offsWarn)).toUtc().millisecondsSinceEpoch > DateTime.now().toUtc().millisecondsSinceEpoch;
}
Future<bool> taskDialogSecurityException(BuildContext context) async {
bool close = false;
await showQuestionDialog(context, "Achtung", "Wenn Sie den Dialog jetzt schließen gehen erfasste Daten verloren und die Aufgabe oder Station bleibt unerledigt.", [
TextButton(onPressed: () => {Navigator.of(context).pop(), close = true}, child: const Text('Schließen')),
TextButton(onPressed: () => {Navigator.of(context).pop(), close = false}, child: const Text('Zurück')),
]);
if (close) {
Navigator.of(context).pop();
}
return close;
}