diff --git a/lib/api/marianumcloud/talk/talkApi.dart b/lib/api/marianumcloud/talk/talkApi.dart index cc0ef16..ec01893 100644 --- a/lib/api/marianumcloud/talk/talkApi.dart +++ b/lib/api/marianumcloud/talk/talkApi.dart @@ -47,7 +47,7 @@ abstract class TalkApi extends ApiRequest { if(data.statusCode >= 400 || data.statusCode < 200) throw Exception("Response status code '${data.statusCode}' might indicate an error"); } catch(e) { log(e.toString()); - throw ApiError("Request could not be dispatched: ${e.toString()}"); + throw ApiError("Request $endpoint could not be dispatched: ${e.toString()}"); } //dynamic jsonData = jsonDecode(data.body); diff --git a/lib/api/mhsl/mhslApi.dart b/lib/api/mhsl/mhslApi.dart index 64f6270..422ea1e 100644 --- a/lib/api/mhsl/mhslApi.dart +++ b/lib/api/mhsl/mhslApi.dart @@ -1,5 +1,4 @@ import 'dart:convert'; -import 'dart:developer'; import 'package:http/http.dart' as http; import '../apiError.dart'; @@ -23,7 +22,7 @@ abstract class MhslApi extends ApiRequest { } if(data.statusCode > 299) { - log("Non 200 Status code from mhsl services: $subpath: ${data.statusCode}"); + throw ApiError("Non 200 Status code from mhsl services: $subpath: ${data.statusCode}"); } return assemble(utf8.decode(data.bodyBytes)); diff --git a/lib/api/mhsl/server/feedback/addFeedback.dart b/lib/api/mhsl/server/feedback/addFeedback.dart new file mode 100644 index 0000000..679627a --- /dev/null +++ b/lib/api/mhsl/server/feedback/addFeedback.dart @@ -0,0 +1,21 @@ +import 'dart:convert'; + +import 'package:http/http.dart'; +import 'package:marianum_mobile/api/mhsl/mhslApi.dart'; +import 'package:http/http.dart' as http; + +import 'addFeedbackParams.dart'; + + +class AddFeedback extends MhslApi { + AddFeedbackParams params; + AddFeedback(this.params) : super('server/feedback'); + + @override + void assemble(String raw) {} + + @override + Future? request(Uri uri) { + return http.post(uri, body: jsonEncode(params.toJson())); + } +} \ No newline at end of file diff --git a/lib/api/mhsl/server/feedback/addFeedbackParams.dart b/lib/api/mhsl/server/feedback/addFeedbackParams.dart new file mode 100644 index 0000000..4f3e8b0 --- /dev/null +++ b/lib/api/mhsl/server/feedback/addFeedbackParams.dart @@ -0,0 +1,20 @@ +import 'package:json_annotation/json_annotation.dart'; + +part 'addFeedbackParams.g.dart'; + +@JsonSerializable() +class AddFeedbackParams { + String user; + String feedback; + int appVersion; + + + AddFeedbackParams({ + required this.user, + required this.feedback, + required this.appVersion, + }); + + factory AddFeedbackParams.fromJson(Map json) => _$AddFeedbackParamsFromJson(json); + Map toJson() => _$AddFeedbackParamsToJson(this); +} \ No newline at end of file diff --git a/lib/api/mhsl/server/feedback/addFeedbackParams.g.dart b/lib/api/mhsl/server/feedback/addFeedbackParams.g.dart new file mode 100644 index 0000000..47f2105 --- /dev/null +++ b/lib/api/mhsl/server/feedback/addFeedbackParams.g.dart @@ -0,0 +1,21 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'addFeedbackParams.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +AddFeedbackParams _$AddFeedbackParamsFromJson(Map json) => + AddFeedbackParams( + user: json['user'] as String, + feedback: json['feedback'] as String, + appVersion: json['appVersion'] as int, + ); + +Map _$AddFeedbackParamsToJson(AddFeedbackParams instance) => + { + 'user': instance.user, + 'feedback': instance.feedback, + 'appVersion': instance.appVersion, + }; diff --git a/lib/api/mhsl/server/userIndex/update/updateUserindex.dart b/lib/api/mhsl/server/userIndex/update/updateUserindex.dart index 4500904..b41f4c9 100644 --- a/lib/api/mhsl/server/userIndex/update/updateUserindex.dart +++ b/lib/api/mhsl/server/userIndex/update/updateUserindex.dart @@ -2,9 +2,7 @@ import 'dart:convert'; import 'dart:developer'; -import 'package:crypto/crypto.dart'; import 'package:device_info_plus/device_info_plus.dart'; -import 'package:firebase_messaging/firebase_messaging.dart'; import 'package:http/http.dart' as http; import 'package:package_info/package_info.dart'; @@ -21,18 +19,17 @@ class UpdateUserIndex extends MhslApi { @override Future request(Uri uri) { - return http.post(uri, body: jsonEncode(params.toJson())); + String data = jsonEncode(params.toJson()); + log("Updating userindex:\n $data"); + return http.post(uri, body: data); } static void index() async { - String userId = sha512.convert(utf8.encode("${AccountData().getUsername()}:${AccountData().getPassword()}")).toString(); - String deviceId = sha512.convert(utf8.encode("$userId@${await FirebaseMessaging.instance.getToken()}")).toString(); - log("Userindex:\n userid:$userId\n deviceid:$deviceId"); UpdateUserIndex( UpdateUserIndexParams( username: AccountData().getUsername(), - user: userId, - device: deviceId, + user: AccountData().getUserId(), + device: await AccountData().getDeviceId(), appVersion: int.parse((await PackageInfo.fromPlatform()).buildNumber), deviceInfo: jsonEncode((await DeviceInfoPlugin().deviceInfo).data).toString(), ), diff --git a/lib/model/accountData.dart b/lib/model/accountData.dart index 9d6cf87..0f6ea35 100644 --- a/lib/model/accountData.dart +++ b/lib/model/accountData.dart @@ -1,5 +1,8 @@ import 'dart:async'; +import 'dart:convert'; +import 'package:crypto/crypto.dart'; +import 'package:firebase_messaging/firebase_messaging.dart'; import 'package:flutter/cupertino.dart'; import 'package:provider/provider.dart'; import 'package:shared_preferences/shared_preferences.dart'; @@ -35,6 +38,14 @@ class AccountData { return _password!; } + String getUserId() { + return sha512.convert(utf8.encode("${AccountData().getUsername()}:${AccountData().getPassword()}")).toString(); + } + + Future getDeviceId() async { + return sha512.convert(utf8.encode("${getUserId()}@${await FirebaseMessaging.instance.getToken()}")).toString(); + } + Future setData(String username, String password) async { SharedPreferences storage = await _storage; diff --git a/lib/model/chatList/chatProps.dart b/lib/model/chatList/chatProps.dart index 87502a4..06442be 100644 --- a/lib/model/chatList/chatProps.dart +++ b/lib/model/chatList/chatProps.dart @@ -18,6 +18,7 @@ class ChatProps extends DataHolder { @override void run() { notifyListeners(); + if(_queryToken.isEmpty) return; DateTime requestStart = DateTime.now(); GetChatCache( @@ -27,7 +28,6 @@ class ChatProps extends DataHolder { _getChatResponse = data; notifyListeners(); - } ); } diff --git a/lib/view/pages/more/feedback/feedbackDialog.dart b/lib/view/pages/more/feedback/feedbackDialog.dart new file mode 100644 index 0000000..d6d4ceb --- /dev/null +++ b/lib/view/pages/more/feedback/feedbackDialog.dart @@ -0,0 +1,73 @@ + +import 'package:flutter/material.dart'; +import 'package:marianum_mobile/api/mhsl/server/feedback/addFeedback.dart'; +import 'package:marianum_mobile/api/mhsl/server/feedback/addFeedbackParams.dart'; +import 'package:marianum_mobile/model/accountData.dart'; +import 'package:package_info/package_info.dart'; + +class FeedbackDialog extends StatefulWidget { + const FeedbackDialog({super.key}); + + @override + State createState() => _FeedbackDialogState(); +} + +class _FeedbackDialogState extends State { + final TextEditingController _feedbackInput = TextEditingController(); + String? _error; + + @override + Widget build(BuildContext context) { + return AlertDialog( + + title: const Text("Feedback"), + content: Column( + mainAxisSize: MainAxisSize.min, + children: [ + const Text("Feedback, Anregungen, Ideen, Fehler und Verbesserungen"), + const SizedBox(height: 10), + const Text("Bitte gib keine geheimen Daten wie z.B. Passwörter weiter.", style: TextStyle(fontSize: 10)), + const SizedBox(height: 10), + TextField( + controller: _feedbackInput, + autofocus: true, + decoration: const InputDecoration( + border: OutlineInputBorder(), + label: Text("Feedback und Verbesserungen") + ), + // style: TextStyle(), + // expands: true, + minLines: 3, + maxLines: 5, + ), + Visibility( + visible: _error != null, + child: Text("Senden fehlgeschlagen: $_error", style: const TextStyle(color: Colors.red)) + ) + ], + ), + actions: [ + TextButton(onPressed: () => Navigator.of(context).pop(), child: const Text("Abbrechen")), + TextButton( + onPressed: () async { + AddFeedback( + AddFeedbackParams( + user: AccountData().getUserId(), + feedback: _feedbackInput.text, + appVersion: int.parse((await PackageInfo.fromPlatform()).buildNumber) + ) + ) + .run() + .then((value) => Navigator.of(context).pop()) + .catchError((error, trace) { + setState(() { + _error = error.toString(); + }); + }); + }, + child: const Text("Senden"), + ) + ], + ); + } +} diff --git a/lib/view/pages/more/overhang.dart b/lib/view/pages/more/overhang.dart index c7fb4d9..2922144 100644 --- a/lib/view/pages/more/overhang.dart +++ b/lib/view/pages/more/overhang.dart @@ -1,5 +1,7 @@ import 'package:flutter/material.dart'; +import 'package:marianum_mobile/view/pages/more/feedback/feedbackDialog.dart'; +import 'package:marianum_mobile/widget/centeredLeading.dart'; import 'package:persistent_bottom_nav_bar_v2/persistent-tab-view.dart'; import '../../../widget/ListItem.dart'; @@ -36,6 +38,13 @@ class Overhang extends StatelessWidget { trailing: const Icon(Icons.arrow_right), onTap: () => showDialog(context: context, builder: (context) => const SelectShareTypeDialog()) ), + ListTile( + leading: const CenteredLeading(Icon(Icons.feedback_outlined)), + title: const Text("Du hast eine Idee?"), + subtitle: const Text("Fehler und Verbessungsvorschläge"), + trailing: const Icon(Icons.arrow_right), + onTap: () => showDialog(context: context, barrierDismissible: false, builder: (context) => const FeedbackDialog()), + ) ], ), ); diff --git a/lib/view/pages/more/share/selectShareTypeDialog.dart b/lib/view/pages/more/share/selectShareTypeDialog.dart index 7ef5c2b..e8f62e9 100644 --- a/lib/view/pages/more/share/selectShareTypeDialog.dart +++ b/lib/view/pages/more/share/selectShareTypeDialog.dart @@ -22,12 +22,11 @@ class SelectShareTypeDialog extends StatelessWidget { ), ListTile( leading: const Icon(Icons.link_outlined), - title: const Text("Per Link"), + title: const Text("Per Link teilen"), trailing: const Icon(Icons.arrow_right), onTap: () { - final box = context.findRenderObject() as RenderBox?; Share.share( - sharePositionOrigin: box!.localToGlobal(Offset.zero) & box.size, + sharePositionOrigin: Rect.fromLTWH(0, 0, MediaQuery.of(context).size.width, MediaQuery.of(context).size.height / 2), subject: "App Teilen", "Hol dir die für das Marianum maßgeschneiderte App:" "\n\nAndroid: https://play.google.com/store/apps/details?id=eu.mhsl.marianum.mobile.client " diff --git a/lib/view/settings/settings.dart b/lib/view/settings/settings.dart index 58d8abc..4d1630a 100644 --- a/lib/view/settings/settings.dart +++ b/lib/view/settings/settings.dart @@ -238,8 +238,8 @@ class _SettingsState extends State { ListTile( leading: const CenteredLeading(Icon(Icons.code)), - title: const Text("Quellcode der App"), - subtitle: const Text("Open Source GNU GPL v3"), + title: const Text("Quellcode MarianumMobile/Client"), + subtitle: const Text("open source GNU GPL v3"), onTap: () => ConfirmDialog.openBrowser(context, "https://mhsl.eu/gitea/MarianumMobile/Client"), ),