diff --git a/lib/api/mhsl/server/feedback/addFeedbackParams.dart b/lib/api/mhsl/server/feedback/addFeedbackParams.dart index 4f3e8b0..3ed0c55 100644 --- a/lib/api/mhsl/server/feedback/addFeedbackParams.dart +++ b/lib/api/mhsl/server/feedback/addFeedbackParams.dart @@ -6,12 +6,14 @@ part 'addFeedbackParams.g.dart'; class AddFeedbackParams { String user; String feedback; + String? screenshot; int appVersion; AddFeedbackParams({ required this.user, required this.feedback, + this.screenshot, required this.appVersion, }); diff --git a/lib/api/mhsl/server/feedback/addFeedbackParams.g.dart b/lib/api/mhsl/server/feedback/addFeedbackParams.g.dart index 47f2105..f401495 100644 --- a/lib/api/mhsl/server/feedback/addFeedbackParams.g.dart +++ b/lib/api/mhsl/server/feedback/addFeedbackParams.g.dart @@ -10,6 +10,7 @@ AddFeedbackParams _$AddFeedbackParamsFromJson(Map json) => AddFeedbackParams( user: json['user'] as String, feedback: json['feedback'] as String, + screenshot: json['screenshot'] as String?, appVersion: json['appVersion'] as int, ); @@ -17,5 +18,6 @@ Map _$AddFeedbackParamsToJson(AddFeedbackParams instance) => { 'user': instance.user, 'feedback': instance.feedback, + 'screenshot': instance.screenshot, 'appVersion': instance.appVersion, }; diff --git a/lib/view/pages/more/feedback/feedbackDialog.dart b/lib/view/pages/more/feedback/feedbackDialog.dart index 69c1746..3f63e26 100644 --- a/lib/view/pages/more/feedback/feedbackDialog.dart +++ b/lib/view/pages/more/feedback/feedbackDialog.dart @@ -1,10 +1,19 @@ +import 'dart:convert'; +import 'dart:typed_data'; + import 'package:flutter/material.dart'; +import 'package:image_picker/image_picker.dart'; +import 'package:loader_overlay/loader_overlay.dart'; import 'package:package_info/package_info.dart'; +import 'package:provider/provider.dart'; +import 'package:badges/badges.dart' as badges; import '../../../../api/mhsl/server/feedback/addFeedback.dart'; import '../../../../api/mhsl/server/feedback/addFeedbackParams.dart'; import '../../../../model/accountData.dart'; +import '../../../../storage/base/settingsProvider.dart'; +import '../../../../widget/filePick.dart'; import '../../../../widget/infoDialog.dart'; class FeedbackDialog extends StatefulWidget { @@ -15,64 +24,150 @@ class FeedbackDialog extends StatefulWidget { } class _FeedbackDialogState extends State { + final ImagePicker picker = ImagePicker(); + final TextEditingController _feedbackInput = TextEditingController(); + Uint8List? _image; String? _error; + bool _textFieldEmpty = false; + + @override + void initState() { + super.initState(); + _feedbackInput.addListener(() { + setState(() { + _textFieldEmpty = _feedbackInput.text.isEmpty; + _error = null; + }); + }); + } @override Widget build(BuildContext context) { - return AlertDialog( - - title: const Text('Feedback'), - content: Column( - mainAxisSize: MainAxisSize.min, + return Scaffold( + appBar: AppBar( + title: const Text('Feedback'), + ), + body: Column( + mainAxisSize: MainAxisSize.max, 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') + const SizedBox(height: 5), + const Text('Feedback, Anregungen, Ideen, Fehler und Verbesserungen', textAlign: TextAlign.center), + const SizedBox(height: 15), + const Text('Bitte gib keine geheimen Daten wie z.B. Passwörter weiter.', textAlign: TextAlign.center, style: TextStyle(fontSize: 11)), + const SizedBox(height: 20), + Padding( + padding: const EdgeInsets.all(10), + child: TextField( + controller: _feedbackInput, + autofocus: true, + decoration: InputDecoration( + border: const OutlineInputBorder(), + label: const Text('Feedback und Verbesserungen'), + errorText: _textFieldEmpty ? 'Bitte gib eine Beschreibung an' : null, + ), + minLines: 4, + maxLines: 7, ), - // style: TextStyle(), - // expands: true, - minLines: 3, - maxLines: 5, ), - Visibility( - visible: _error != null, - child: Text('Senden fehlgeschlagen: $_error', style: const TextStyle(color: Colors.red)) + const SizedBox(height: 10), + if(_image != null) Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + badges.Badge( + badgeContent: const Icon(Icons.close_outlined, size: 17), + badgeStyle: const badges.BadgeStyle( + padding: EdgeInsets.all(2), + ), + child: Container( + decoration: BoxDecoration( + borderRadius: const BorderRadius.all(Radius.circular(5)), + border: Border.all( + width: 3, + color: Theme.of(context).primaryColor, + ), + ), + height: 150, + child: Image( + image: Image.memory(_image!).image, + fit: BoxFit.contain, + ), + ), + onTap: () async { + setState(() { + _image = null; + }); + }, + ), + ], + ), + Padding( + padding: const EdgeInsets.all(5), + child: Visibility( + visible: _error != null, + child: Visibility( + visible: Provider.of(context, listen: false).val().devToolsEnabled, + replacement: const Text('Senden fehlgeschlagen, bitte überprüfe die Internetverbindung.', textAlign: TextAlign.center, style: TextStyle(color: Colors.red)), + child: Text('Senden fehlgeschlagen: \n $_error', textAlign: TextAlign.center, style: const TextStyle(color: Colors.red)), + ), + ), + ), + Padding( + padding: const EdgeInsets.only(right: 20, left: 10), + child: Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + Visibility( + visible: _image == null, + child: IconButton( + onPressed: () async { + context.loaderOverlay.show(); + var imageData = await (await FilePick.galleryPick())?.readAsBytes(); + context.loaderOverlay.hide(); + setState(() { + _image = imageData; + }); + }, + icon: const Icon(Icons.attach_file_outlined), + ), + ), + const Expanded(child: SizedBox.shrink()), + TextButton( + onPressed: () async { + if(_feedbackInput.text.isEmpty){ + setState(() { + _textFieldEmpty = true; + }); + return; + } + context.loaderOverlay.show(); + AddFeedback( + AddFeedbackParams( + user: AccountData().getUserSecret(), + feedback: _feedbackInput.text, + screenshot: _image != null ? base64Encode(_image!) : null, + appVersion: int.parse((await PackageInfo.fromPlatform()).buildNumber), + ) + ).run().then((value) { + Navigator.of(context).pop(); + InfoDialog.show(context, 'Danke für dein Feedback!'); + context.loaderOverlay.hide(); + }).catchError((error, trace) { + setState(() { + _error = error.toString(); + }); + context.loaderOverlay.hide(); + }); + }, + child: const Text('Senden'), + ) + ] + ) ) + ], ), - actions: [ - TextButton(onPressed: () => Navigator.of(context).pop(), child: const Text('Abbrechen')), - TextButton( - onPressed: () async { - AddFeedback( - AddFeedbackParams( - user: AccountData().getUserSecret(), - feedback: _feedbackInput.text, - appVersion: int.parse((await PackageInfo.fromPlatform()).buildNumber) - ) - ) - .run() - .then((value) { - Navigator.of(context).pop(); - InfoDialog.show(context, 'Danke für dein Feedback!'); - }) - .catchError((error, trace) { - setState(() { - _error = error.toString(); - }); - }); - }, - child: const Text('Senden'), - ) - ], ); + } } diff --git a/lib/view/pages/overhang.dart b/lib/view/pages/overhang.dart index 020207e..4ed82c0 100644 --- a/lib/view/pages/overhang.dart +++ b/lib/view/pages/overhang.dart @@ -74,7 +74,7 @@ class Overhang extends StatelessWidget { 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()), + onTap: () => pushScreen(context, withNavBar: false, screen: const FeedbackDialog()), ), ], ),