1. Import
This commit is contained in:
commit
cb4525a774
165 files changed
+14763
No files matched your search
@@ -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,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
|
||||
enum ConnectionStatusEnum {
|
||||
notConnected,
|
||||
connected
|
||||
}
|
||||
class ConnectionStatus {
|
||||
ConnectionStatus({required this.status});
|
||||
|
||||
final ConnectionStatusEnum status;
|
||||
}
|
||||
@@ -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";
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
|
||||
abstract class PageBase extends StatelessWidget {
|
||||
const PageBase({super.key});
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
Reference in new issue
Block a user