1. Import

This commit is contained in:
Sven committed 2023-11-14 11:38:44 +01:00
commit cb4525a774
165 files changed
+14763

No files matched your search

+18
View File
@@ -0,0 +1,18 @@
import 'package:flutter/material.dart';
class ColoredSafeArea extends StatelessWidget {
final Widget child;
const ColoredSafeArea({required Key key, required this.child})
: super(key: key);
@override
Widget build(BuildContext context) {
return Container(
color: Theme.of(context).colorScheme.primaryContainer,
child: SafeArea(
child: child,
),
);
}
}
+10
View File
@@ -0,0 +1,10 @@
enum ConnectionStatusEnum {
notConnected,
connected
}
class ConnectionStatus {
ConnectionStatus({required this.status});
final ConnectionStatusEnum status;
}
+11
View File
@@ -0,0 +1,11 @@
class Constants {
static const String messageTopicConnectionStatusChanged = "connection_status_changed";
static const String messageTopicPushContentView = "push_content_view";
static const String messageTopicPopContentView = "pop_content_view";
static const String messageTopicReplaceContentView = "replace_content_view";
static const String messageTopicHideRightButton = "hide_right_button";
static const String messageShowPopup = "show_popup";
//static const String topicToServer = "/app/100/2/208738/to_server";
//static const String topicFromServer = "/app/100/2/208738/from_server";
}
+214
View File
@@ -0,0 +1,214 @@
import 'dart:async';
import 'dart:convert';
import 'dart:math';
import 'package:flutter_broadcast_receiver/flutter_broadcast_receiver.dart';
import 'package:mqtt_client/mqtt_client.dart';
import 'package:mqtt_client/mqtt_server_client.dart';
import 'package:stadtbote/model/bootstrap_request.dart';
import 'package:stadtbote/model/bootstrap_response_payload.dart';
import 'package:stadtbote/model/device_object.dart';
import 'package:stadtbote/model/job.dart';
import 'package:stadtbote/tools/connection_status.dart';
import 'package:typed_data/typed_buffers.dart';
import 'package:http/http.dart' as http;
import '../main.dart';
import '../model/status.dart';
import 'constants.dart';
import 'util.dart';
class MqttCore {
static late MqttCore instance;
late String _brokerUri;
late int _brokerPort;
late String _fromServerTopic;
late String _toServerTopic;
late MqttServerClient _mqttClient;
late int _reconnectDelay = 0;
MqttCore() {
_processBootstrap();
}
static setup() {
instance = MqttCore();
}
_connectToBroker() async {
try {
String clientId = await Util.getAppUuid();
Util.logInfo("client id: $clientId");
_mqttClient = MqttServerClient.withPort(_brokerUri, clientId, _brokerPort);
_mqttClient.logging(on: false);
_mqttClient.keepAlivePeriod = 20;
_mqttClient.autoReconnect = false;
_mqttClient.onDisconnected = _clientDisconnected;
_mqttClient.connectionMessage = MqttConnectMessage()
.withClientIdentifier('clientId')
.withWillQos(MqttQos.atMostOnce)
.withWillTopic('willTopic')
.withWillMessage('willMessage')
.authenticateAs("app", "apppwd");
await _mqttClient.connect();
if (_mqttClient.connectionStatus?.state == MqttConnectionState.connected) {
Util.logInfo('Verbunden mit dem MQTT-Broker!');
_reconnectDelay = 0;
_setupSubscriptions();
} else {
Util.logInfo('Verbindung zum MQTT-Broker fehlgeschlagen!');
BroadcastReceiver().publish<ConnectionStatus>(Constants.messageTopicConnectionStatusChanged, arguments: ConnectionStatus(status: ConnectionStatusEnum.notConnected));
_startReconnectTimer();
}
} catch (ex) {
_startReconnectTimer();
Util.logInfo('Verbindung zum MQTT-Broker fehlgeschlagen!: $ex');
BroadcastReceiver().publish<ConnectionStatus>(Constants.messageTopicConnectionStatusChanged, arguments: ConnectionStatus(status: ConnectionStatusEnum.notConnected));
}
}
publishText(String topic, String text) {
try {
var buffer = Uint8Buffer();
buffer.addAll(text.codeUnits);
_mqttClient.publishMessage(topic, MqttQos.exactlyOnce, buffer);
} catch (e) {
Util.logException(e.toString());
}
}
void _setupSubscriptions() async {
Util.logInfo('_setupSubscriptions called');
_mqttClient.updates?.listen((List<MqttReceivedMessage<MqttMessage>> c) {
try {
final MqttPublishMessage message = c[0].payload as MqttPublishMessage;
final payload = MqttPublishPayload.bytesToStringAsString(message.payload.message);
var topic = message.variableHeader?.topicName;
Util.logInfo('message received');
Util.logInfo('topic: $topic');
Util.logInfo('payload: $payload');
Map<String, dynamic> messageData = jsonDecode(payload);
for (var entry in messageData.keys) {
if (entry == 'payload') {
var payload = messageData[entry];
for (var payloadEntry in payload.keys) {
var payloadData = payload[payloadEntry];
switch(payloadEntry) {
case 'session':
_sessionMessageReceived(payloadData);
break;
case 'jobs':
_jobMessageReceived(payloadData);
break;
default:
Util.logInfo('Unknown topic: $payloadEntry');
break;
}
}
}
}
} catch(ex) {
Util.logException(ex.toString());
}
});
_mqttClient.subscribe(_fromServerTopic, MqttQos.exactlyOnce);
Util.logInfo('subscribed to topic: $_fromServerTopic');
BroadcastReceiver().publish<ConnectionStatus>(Constants.messageTopicConnectionStatusChanged, arguments: ConnectionStatus(status: ConnectionStatusEnum.connected));
}
void _sessionMessageReceived(payloadData) async {
var statusMessage = Status.fromJson(payloadData['status']);
await MyApp.isarInstance.writeTxn(() async {
await MyApp.isarInstance.status.put(statusMessage);
});
}
void _jobMessageReceived(payloadData) async {
for (var foundJobData in payloadData) {
var newJob = Job.fromJson(foundJobData);
await MyApp.isarInstance.writeTxn(() async {
await MyApp.isarInstance.jobs.put(newJob);
});
}
}
void _startReconnectTimer() {
Util.logInfo("_startReconnectTimer called");
_reconnectDelay = min(_reconnectDelay + 1, 30);
Timer(Duration(seconds: _reconnectDelay), () {
_processBootstrap();
});
}
void _clientDisconnected() {
Util.logInfo("_clientDisconnected called");
BroadcastReceiver().publish<ConnectionStatus>(Constants.messageTopicConnectionStatusChanged, arguments: ConnectionStatus(status: ConnectionStatusEnum.notConnected));
_startReconnectTimer();
}
void _processBootstrap() async {
try {
var deviceObject = DeviceObject();
deviceObject.manufacturer = "sven";
deviceObject.model = "emulator";
deviceObject.os = "hat es";
deviceObject.osVer = "0.0";
var handshakeMessage = BootstrapRequest();
handshakeMessage.app = "sb";
handshakeMessage.mqttClientId = "12345";
handshakeMessage.deviceObject = deviceObject;
handshakeMessage.ver = 200;
var jsonMap = handshakeMessage.toJson();
var json = jsonEncode(jsonMap);
var uri = "https://init-x.assecutor.de/bootstrap?get_mqtt_broker=$json";
print("Bootstrap request: $uri");
var response = await http.get(Uri.parse(uri));
var responseText = response.body;
var bootstrapResponsePayload = BootstrapResponsePayload.fromJson(jsonDecode(responseText)["payload"]);
var brokerUriAndPortArray = bootstrapResponsePayload.config.broker.replaceFirst("mqtt://", "").split(":");
_brokerUri = brokerUriAndPortArray[0];
_brokerPort = int.parse(brokerUriAndPortArray[1]);
_fromServerTopic = bootstrapResponsePayload.config.topics.fromServer;
_toServerTopic = bootstrapResponsePayload.config.topics.toServer;
_connectToBroker();
} catch (ex) {
_startReconnectTimer();
}
}
}
+5
View File
@@ -0,0 +1,5 @@
import 'package:flutter/cupertino.dart';
abstract class PageBase extends StatelessWidget {
const PageBase({super.key});
}
+178
View File
@@ -0,0 +1,178 @@
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.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 logInfo(String message) {
if (kDebugMode) {
print('Message: $message');
}
}
static logException(String message) {
if (kDebugMode) {
print('Exception: $message');
}
}
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;
});
}
}
Widget getDefaultButton(String text, Function() onPressed, {Image? image}) {
return SizedBox(
height: 60,
child: Stack(
children: [
Row(
children: [
Expanded(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: SizedBox(
height: 60,
child: ElevatedButton(
style: ButtonStyle(
shape: MaterialStateProperty.all<RoundedRectangleBorder>(
RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8.0),
side: const BorderSide(color: Colors.grey),
),
),
backgroundColor: MaterialStateProperty.all<Color>(const Color.fromARGB(255, 220, 220, 220)),
foregroundColor: MaterialStateProperty.all<Color>(Colors.black),
),
onPressed: () {
onPressed();
},
child: Text(text)
),
),
),
),
],
),
Positioned(
left: 20,
top: 15,
child: Center(
child: image
)
)
],
),
);
}
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;
}