session added
@ -15,12 +15,12 @@ if (localPropertiesFile.exists()) {
|
|||||||
|
|
||||||
def flutterVersionCode = localProperties.getProperty("flutter.versionCode")
|
def flutterVersionCode = localProperties.getProperty("flutter.versionCode")
|
||||||
if (flutterVersionCode == null) {
|
if (flutterVersionCode == null) {
|
||||||
flutterVersionCode = "9"
|
flutterVersionCode = "10"
|
||||||
}
|
}
|
||||||
|
|
||||||
def flutterVersionName = localProperties.getProperty("flutter.versionName")
|
def flutterVersionName = localProperties.getProperty("flutter.versionName")
|
||||||
if (flutterVersionName == null) {
|
if (flutterVersionName == null) {
|
||||||
flutterVersionName = "1.0.8"
|
flutterVersionName = "1.0.9"
|
||||||
}
|
}
|
||||||
|
|
||||||
def keystorePropertiesFile = rootProject.file("key.properties")
|
def keystorePropertiesFile = rootProject.file("key.properties")
|
||||||
|
|||||||
BIN
assets/feedback/disappointed.png
Normal file
|
After Width: | Height: | Size: 1.0 KiB |
BIN
assets/feedback/errorfb.png
Normal file
|
After Width: | Height: | Size: 716 B |
BIN
assets/feedback/frowning.png
Normal file
|
After Width: | Height: | Size: 832 B |
BIN
assets/feedback/neutral.png
Normal file
|
After Width: | Height: | Size: 767 B |
BIN
assets/feedback/smiling.png
Normal file
|
After Width: | Height: | Size: 879 B |
BIN
assets/feedback/smilingopenface.png
Normal file
|
After Width: | Height: | Size: 1004 B |
BIN
assets/feedback/thumbfb.png
Normal file
|
After Width: | Height: | Size: 826 B |
@ -0,0 +1,14 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
abstract class FeedBackAssetPath {
|
||||||
|
static const _basePath = 'assets/feedback';
|
||||||
|
|
||||||
|
static const disappointedfb = '$_basePath/disappointed.png';
|
||||||
|
static const frowningfb = '$_basePath/frowning.png';
|
||||||
|
static const neutralfb = '$_basePath/neutral.png';
|
||||||
|
static const smilingfb = '$_basePath/smiling.png';
|
||||||
|
static const smilingFacefb = '$_basePath/smilingopenface.png';
|
||||||
|
static const thumbfb = '$_basePath/thumbfb.png';
|
||||||
|
static const errorfb = '$_basePath/errorfb.png';
|
||||||
|
|
||||||
|
}
|
||||||
@ -1,8 +1,8 @@
|
|||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
"feedback_title": "FeedBack",
|
"feedback_title": "Feedback",
|
||||||
"feedback_failed_msg": "Your feedback could not be submitted. Please try again",
|
"feedback_failed_msg": "Your feedback could not be \n submitted. Please try again",
|
||||||
|
|
||||||
"register_title": "Register",
|
"register_title": "Register",
|
||||||
"register_details": "Please enter your details",
|
"register_details": "Please enter your details",
|
||||||
|
|||||||
@ -241,6 +241,13 @@ class LoginRoute extends HookConsumerWidget {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
style: TextButton.styleFrom(
|
||||||
|
padding: EdgeInsets.zero,
|
||||||
|
// maximumSize: Size.zero,
|
||||||
|
tapTargetSize: MaterialTapTargetSize.shrinkWrap,
|
||||||
|
visualDensity: VisualDensity.compact,
|
||||||
|
overlayColor: Colors.white
|
||||||
|
),
|
||||||
child: Text(
|
child: Text(
|
||||||
context.translate(
|
context.translate(
|
||||||
'Forgot Password?',
|
'Forgot Password?',
|
||||||
@ -547,7 +554,7 @@ class LoginRoute extends HookConsumerWidget {
|
|||||||
children: [
|
children: [
|
||||||
TextSpan(
|
TextSpan(
|
||||||
text: context.translate(
|
text: context.translate(
|
||||||
'Don\'t have an account? ',
|
'Don\'t have an account?',
|
||||||
'ليس لديك حساب؟',
|
'ليس لديك حساب؟',
|
||||||
),
|
),
|
||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
@ -637,7 +644,7 @@ class LoginRoute extends HookConsumerWidget {
|
|||||||
horizontal: listViewHorizontalPadding.toDouble(),
|
horizontal: listViewHorizontalPadding.toDouble(),
|
||||||
),
|
),
|
||||||
children: [
|
children: [
|
||||||
36.verticalSpace,
|
3.verticalSpace,
|
||||||
Align(
|
Align(
|
||||||
alignment: AlignmentDirectional.topEnd,
|
alignment: AlignmentDirectional.topEnd,
|
||||||
child: MyToggle(
|
child: MyToggle(
|
||||||
@ -651,7 +658,7 @@ class LoginRoute extends HookConsumerWidget {
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
16.verticalSpace,
|
36.verticalSpace,
|
||||||
helloAndPleaseLoginTexts,
|
helloAndPleaseLoginTexts,
|
||||||
42.verticalSpace,
|
42.verticalSpace,
|
||||||
form,
|
form,
|
||||||
|
|||||||
@ -8,6 +8,8 @@ import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
|||||||
import 'package:pocketbase/pocketbase.dart';
|
import 'package:pocketbase/pocketbase.dart';
|
||||||
import 'package:shared_preferences/shared_preferences.dart';
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
import 'package:uae_stat/domain/use_cases/language.dart';
|
import 'package:uae_stat/domain/use_cases/language.dart';
|
||||||
|
import 'package:uae_stat/infrastructure/services/img_asset_paths/feedback_asset_path.dart';
|
||||||
|
|
||||||
import 'package:uae_stat/infrastructure/services/packages/go_router.dart';
|
import 'package:uae_stat/infrastructure/services/packages/go_router.dart';
|
||||||
import 'package:uae_stat/presentation/components/my_drawer.dart';
|
import 'package:uae_stat/presentation/components/my_drawer.dart';
|
||||||
import 'package:mailer/mailer.dart';
|
import 'package:mailer/mailer.dart';
|
||||||
@ -28,7 +30,7 @@ class FeedbackForm extends StatefulWidget {
|
|||||||
class _FeedbackFormState extends State<FeedbackForm>
|
class _FeedbackFormState extends State<FeedbackForm>
|
||||||
with WidgetsBindingObserver {
|
with WidgetsBindingObserver {
|
||||||
final _pb =
|
final _pb =
|
||||||
PocketBase('https://pb.venbait.in'); // Initialize PocketBase client
|
PocketBase('https://pb.venbait.in'); // Initialize PocketBase client
|
||||||
// final _pb =
|
// final _pb =
|
||||||
// PocketBase('http://127.0.0.1:8090'); // Initialize PocketBase client
|
// PocketBase('http://127.0.0.1:8090'); // Initialize PocketBase client
|
||||||
|
|
||||||
@ -46,32 +48,55 @@ class _FeedbackFormState extends State<FeedbackForm>
|
|||||||
dynamic userId;
|
dynamic userId;
|
||||||
|
|
||||||
List<Map<String, dynamic>> get _emojiOptions => [
|
List<Map<String, dynamic>> get _emojiOptions => [
|
||||||
{
|
{
|
||||||
"icon": Icons.sentiment_very_dissatisfied,
|
// "icon": Icons.emoji_emotions_rounded,
|
||||||
"label": context.translate("Terrible", "سئ جدا"), // Translate here
|
'icon': Image.asset(
|
||||||
"value": 1,
|
FeedBackAssetPath.disappointedfb,
|
||||||
},
|
width: 25,
|
||||||
{
|
height: 25,
|
||||||
"icon": Icons.sentiment_dissatisfied,
|
),
|
||||||
"label": context.translate("Bad", "سيء"), // Translate here
|
"label": context.translate("Terrible", "سئ جدا"), // Translate here
|
||||||
"value": 2,
|
"value": 1,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"icon": Icons.sentiment_neutral,
|
// "icon": Icons.sentiment_dissatisfied,
|
||||||
"label": context.translate("Okay", "مقبول"), // Translate here
|
'icon': Image.asset(
|
||||||
"value": 3,
|
FeedBackAssetPath.frowningfb,
|
||||||
},
|
width: 25,
|
||||||
{
|
height: 25,
|
||||||
"icon": Icons.sentiment_satisfied,
|
),
|
||||||
"label": context.translate("Good", "جيد"), // Translate here
|
"label": context.translate("Bad", "سيء"), // Translate here
|
||||||
"value": 4,
|
"value": 2,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"icon": Icons.sentiment_very_satisfied,
|
'icon': Image.asset(
|
||||||
"label": context.translate("Amazing", "مذهل"), // Translate here
|
FeedBackAssetPath.neutralfb,
|
||||||
"value": 5,
|
width: 25,
|
||||||
},
|
height: 25,
|
||||||
];
|
),
|
||||||
|
"label": context.translate("Okay", "مقبول"), // Translate here
|
||||||
|
"value": 3,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'icon': Image.asset(
|
||||||
|
FeedBackAssetPath.smilingfb,
|
||||||
|
width: 25,
|
||||||
|
height: 25,
|
||||||
|
),
|
||||||
|
"label": context.translate("Good", "جيد"), // Translate here
|
||||||
|
"value": 4,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// "icon": Icons.sentiment_very_satisfied,
|
||||||
|
'icon': Image.asset(
|
||||||
|
FeedBackAssetPath.smilingFacefb,
|
||||||
|
width: 25,
|
||||||
|
height: 25,
|
||||||
|
),
|
||||||
|
"label": context.translate("Amazing", "مذهل"), // Translate here
|
||||||
|
"value": 5,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
static const int _characterLimit = 1200;
|
static const int _characterLimit = 1200;
|
||||||
final RegExp _allowedCharacters = RegExp(r'^[a-zA-Z0-9 .,!?-]*$');
|
final RegExp _allowedCharacters = RegExp(r'^[a-zA-Z0-9 .,!?-]*$');
|
||||||
@ -208,9 +233,17 @@ class _FeedbackFormState extends State<FeedbackForm>
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
// final uri = Uri.parse(GoRouterState.of(context).uri.toString());
|
||||||
|
// final userName = uri.queryParameters['userName'] ?? 'Guest User';
|
||||||
|
|
||||||
|
final userName = GoRouterState.of(context).extra as String? ?? 'Guest User';
|
||||||
return BaseScaffold(
|
return BaseScaffold(
|
||||||
// title: Text("Feedback"),
|
// title: Text("Feedback"),
|
||||||
title: Text(AppLocalizations.of(context)!.feedback_title),
|
title: Text(
|
||||||
|
AppLocalizations.of(context)!.feedback_title,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 24, fontFamily: 'Roboto', fontWeight: FontWeight.w500),
|
||||||
|
),
|
||||||
// appBar: AppBar(
|
// appBar: AppBar(
|
||||||
// backgroundColor: const Color(0xFFf8f9ff),
|
// backgroundColor: const Color(0xFFf8f9ff),
|
||||||
// title: Text(AppLocalizations.of(context)!.feedback_title),
|
// title: Text(AppLocalizations.of(context)!.feedback_title),
|
||||||
@ -230,13 +263,14 @@ class _FeedbackFormState extends State<FeedbackForm>
|
|||||||
// ],
|
// ],
|
||||||
// ),
|
// ),
|
||||||
body: Padding(
|
body: Padding(
|
||||||
padding: const EdgeInsets.all(16.0),
|
padding: const EdgeInsets.only(
|
||||||
|
top: 8.0, bottom: 16.0, left: 23.0, right: 23.0),
|
||||||
child: SingleChildScrollView(
|
child: SingleChildScrollView(
|
||||||
child: _isFeedbackSubmitted
|
child: _isFeedbackSubmitted
|
||||||
? _buildThankYouMessage()
|
? _buildThankYouMessage(userName)
|
||||||
: _isFeedbackFailed
|
: _isFeedbackFailed
|
||||||
? _buildFailureMessage()
|
? _buildFailureMessage()
|
||||||
: _buildFeedbackForm(),
|
: _buildFeedbackForm(),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@ -260,26 +294,33 @@ class _FeedbackFormState extends State<FeedbackForm>
|
|||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
),
|
),
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 20),
|
||||||
Text(
|
Center(
|
||||||
context.translate('How was your experience with us today?',
|
child: FittedBox(
|
||||||
'كيف كانت تجربتك معنا اليوم؟'),
|
fit: BoxFit
|
||||||
style: const TextStyle(
|
.scaleDown, // This will make the text smaller to fit within the available space
|
||||||
fontSize: 18,
|
child: Text(
|
||||||
fontFamily: 'Roboto',
|
context.translate('How was your experience with us today?',
|
||||||
fontWeight: FontWeight.w400,
|
'كيف كانت تجربتك معنا اليوم؟'),
|
||||||
color: Color(0xFF898C81),
|
style: const TextStyle(
|
||||||
|
fontSize: 18,
|
||||||
|
fontFamily: 'Roboto',
|
||||||
|
fontWeight: FontWeight.w400,
|
||||||
|
color: Color(0xff898C81),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),),
|
||||||
const SizedBox(height: 10),
|
const SizedBox(height: 15),
|
||||||
Container(
|
Container(
|
||||||
|
width: double.infinity,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
border: Border.all(
|
border: Border.all(
|
||||||
color: _isSmileySelected ? Colors.transparent : Colors.red,
|
color:
|
||||||
|
_isSmileySelected ? Colors.transparent : Colors.transparent,
|
||||||
width: 1.5,
|
width: 1.5,
|
||||||
),
|
),
|
||||||
borderRadius: BorderRadius.circular(8),
|
borderRadius: BorderRadius.circular(8),
|
||||||
),
|
),
|
||||||
padding: const EdgeInsets.all(8),
|
padding: const EdgeInsets.all(0.0),
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
Row(
|
Row(
|
||||||
@ -287,6 +328,8 @@ class _FeedbackFormState extends State<FeedbackForm>
|
|||||||
children: List.generate(_emojiOptions.length, (index) {
|
children: List.generate(_emojiOptions.length, (index) {
|
||||||
return _buildEmojiButton(
|
return _buildEmojiButton(
|
||||||
icon: _emojiOptions[index]["icon"],
|
icon: _emojiOptions[index]["icon"],
|
||||||
|
|
||||||
|
// icon: _emojiOptions[index]["icon"],
|
||||||
label: _emojiOptions[index]["label"],
|
label: _emojiOptions[index]["label"],
|
||||||
index: index,
|
index: index,
|
||||||
);
|
);
|
||||||
@ -300,28 +343,31 @@ class _FeedbackFormState extends State<FeedbackForm>
|
|||||||
'Please rate your experience before submitting your feedback.',
|
'Please rate your experience before submitting your feedback.',
|
||||||
'يرجى تقييم تجربتك قبل تقديم ملاحظاتك.',
|
'يرجى تقييم تجربتك قبل تقديم ملاحظاتك.',
|
||||||
),
|
),
|
||||||
style: TextStyle(color: Colors.red, fontSize: 14),
|
style: TextStyle(color: Color(0xFFD83731), fontSize: 14),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 30),
|
const SizedBox(height: 15),
|
||||||
Text(
|
FittedBox(
|
||||||
context.translate('How good did we do in these aspects?',
|
fit: BoxFit
|
||||||
'ما مدى جودة أدائنا في هذه الجوانب؟'),
|
.scaleDown, // This will make the text smaller to fit within the available space
|
||||||
style: const TextStyle(
|
child: Text(
|
||||||
fontSize: 18,
|
context.translate('How good did we do in these aspects?',
|
||||||
fontFamily: 'Roboto',
|
'ما مدى جودة أدائنا في هذه الجوانب؟'),
|
||||||
fontWeight: FontWeight.w400,
|
style: const TextStyle(
|
||||||
color: Color(0xFF898C81),
|
fontSize: 18,
|
||||||
),
|
fontFamily: 'Roboto',
|
||||||
),
|
fontWeight: FontWeight.w400,
|
||||||
const SizedBox(height: 20),
|
color: Color(0xFF898C81),
|
||||||
|
),
|
||||||
|
)),
|
||||||
|
const SizedBox(height: 15),
|
||||||
_buildRatingRow(
|
_buildRatingRow(
|
||||||
context.translate('Ease of use', 'سهولة الاستخدام'),
|
context.translate('Ease of use', 'سهولة الاستخدام'),
|
||||||
_easeOfUseRating,
|
_easeOfUseRating,
|
||||||
(rating) {
|
(rating) {
|
||||||
setState(() {
|
setState(() {
|
||||||
_easeOfUseRating = rating;
|
_easeOfUseRating = rating;
|
||||||
});
|
});
|
||||||
@ -330,7 +376,7 @@ class _FeedbackFormState extends State<FeedbackForm>
|
|||||||
_buildRatingRow(
|
_buildRatingRow(
|
||||||
context.translate('Quality', 'الجودة'),
|
context.translate('Quality', 'الجودة'),
|
||||||
_qualityRating,
|
_qualityRating,
|
||||||
(rating) {
|
(rating) {
|
||||||
setState(() {
|
setState(() {
|
||||||
_qualityRating = rating;
|
_qualityRating = rating;
|
||||||
});
|
});
|
||||||
@ -339,7 +385,7 @@ class _FeedbackFormState extends State<FeedbackForm>
|
|||||||
_buildRatingRow(
|
_buildRatingRow(
|
||||||
context.translate('Design', 'التصميم'),
|
context.translate('Design', 'التصميم'),
|
||||||
_designRating,
|
_designRating,
|
||||||
(rating) {
|
(rating) {
|
||||||
setState(() {
|
setState(() {
|
||||||
_designRating = rating;
|
_designRating = rating;
|
||||||
});
|
});
|
||||||
@ -348,7 +394,7 @@ class _FeedbackFormState extends State<FeedbackForm>
|
|||||||
_buildRatingRow(
|
_buildRatingRow(
|
||||||
context.translate('Redundant', 'مكرر'),
|
context.translate('Redundant', 'مكرر'),
|
||||||
_redundancyRating,
|
_redundancyRating,
|
||||||
(rating) {
|
(rating) {
|
||||||
setState(() {
|
setState(() {
|
||||||
_redundancyRating = rating;
|
_redundancyRating = rating;
|
||||||
});
|
});
|
||||||
@ -360,23 +406,43 @@ class _FeedbackFormState extends State<FeedbackForm>
|
|||||||
minLines: 5, // Start with 5 lines
|
minLines: 5, // Start with 5 lines
|
||||||
maxLines: null, // Allows the field to expand automatically
|
maxLines: null, // Allows the field to expand automatically
|
||||||
maxLength: _characterLimit,
|
maxLength: _characterLimit,
|
||||||
|
style: TextStyle(color: Color(0xFF898C81)),
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
hintText: context.translate(
|
hintText: context.translate(
|
||||||
'Tell us how we can improve', 'أخبرنا كيف يمكننا التحسين'),
|
'Tell us how we can improve', 'أخبرنا كيف يمكننا التحسين'),
|
||||||
|
hintStyle: TextStyle(color: Color(0xFF898C81)),
|
||||||
border: OutlineInputBorder(
|
border: OutlineInputBorder(
|
||||||
borderSide: BorderSide(
|
borderRadius: BorderRadius.circular(10.0),
|
||||||
color: _hasError ? Colors.red : Color(0xFF7296BE),
|
borderSide: BorderSide(color: Color(0xFF7296BE), width: 1),
|
||||||
),
|
|
||||||
),
|
),
|
||||||
|
|
||||||
|
// Border when the TextField is enabled but not focused
|
||||||
|
enabledBorder: OutlineInputBorder(
|
||||||
|
borderRadius: BorderRadius.circular(10.0),
|
||||||
|
borderSide: BorderSide(color: Color(0xFF7296BE), width: 1),
|
||||||
|
),
|
||||||
|
|
||||||
|
// Border when there is an error
|
||||||
|
errorBorder: OutlineInputBorder(
|
||||||
|
borderRadius: BorderRadius.circular(10.0),
|
||||||
|
borderSide: BorderSide(color: Color(0xFFD83731), width: 1),
|
||||||
|
),
|
||||||
|
|
||||||
|
// Border when focused and there is an error
|
||||||
|
focusedErrorBorder: OutlineInputBorder(
|
||||||
|
borderRadius: BorderRadius.circular(10.0),
|
||||||
|
borderSide: BorderSide(color: Color(0xFFD83731), width: 1),
|
||||||
|
),
|
||||||
|
|
||||||
errorText:
|
errorText:
|
||||||
_hasError ? _errorMessage : null, // Show error below field
|
_hasError ? _errorMessage : null, // Show error below field
|
||||||
),
|
),
|
||||||
onChanged: (text) {
|
onChanged: (text) {
|
||||||
// Trigger re-validation and character limit on each change
|
// Trigger re-validation and character limit on each change
|
||||||
_handleTextChange();
|
_handleTextChange();
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 15),
|
||||||
Center(
|
Center(
|
||||||
child: ElevatedButton(
|
child: ElevatedButton(
|
||||||
onPressed: _submitFeedback,
|
onPressed: _submitFeedback,
|
||||||
@ -416,7 +482,10 @@ class _FeedbackFormState extends State<FeedbackForm>
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
6.horizontalSpace,
|
6.horizontalSpace,
|
||||||
const Icon(Icons.chevron_right_outlined),
|
const Icon(
|
||||||
|
Icons.chevron_right_outlined,
|
||||||
|
color: Colors.white,
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -425,30 +494,66 @@ class _FeedbackFormState extends State<FeedbackForm>
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildThankYouMessage() {
|
Widget _buildThankYouMessage(String userName) {
|
||||||
|
double screenHeight = MediaQuery.of(context).size.height;
|
||||||
return Center(
|
return Center(
|
||||||
child: Column(
|
child: Column(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
Icon(Icons.thumb_up, size: 80, color: Color(0xFF7DAFBC)),
|
SizedBox(height: screenHeight / 5),
|
||||||
|
Container(
|
||||||
|
padding: EdgeInsets.all(20),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Color(0xFFF9F9F9), // Circle background color
|
||||||
|
shape: BoxShape.circle, // Make it a circle
|
||||||
|
boxShadow: [
|
||||||
|
BoxShadow(
|
||||||
|
color: Color.fromRGBO(0, 0, 0, 0.2),
|
||||||
|
blurRadius: 5,
|
||||||
|
spreadRadius: 2,
|
||||||
|
offset: Offset(0, 3), // Shadow position
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
child: Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
Image.asset(
|
||||||
|
FeedBackAssetPath.thumbfb,
|
||||||
|
width: 40,
|
||||||
|
height: 40,
|
||||||
|
)
|
||||||
|
// Icon(
|
||||||
|
// Icons.thumb,
|
||||||
|
// size: 80,
|
||||||
|
// color: Color(0xFF7DAFBC), // Icon color
|
||||||
|
// ),
|
||||||
|
// const SizedBox(height: 20),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
|
// Icon(Icons.thumb_up, size: 80, color: Color(0xFF7DAFBC)),
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 20),
|
||||||
Text(
|
Text(
|
||||||
"Thank You",
|
// "Thank you",
|
||||||
|
|
||||||
|
'Thank you $userName !',
|
||||||
style: const TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
|
style: const TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 10),
|
const SizedBox(height: 15),
|
||||||
const Text(
|
const Text(
|
||||||
"For your valuable feedback, we truly appreciate your input!",
|
"For your valuable feedback, we truly \n appreciate your input!",
|
||||||
style: TextStyle(fontSize: 16),
|
style: TextStyle(fontSize: 16, color: Color(0xFF898C81)),
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
),
|
),
|
||||||
const SizedBox(height: 30),
|
// const SizedBox(height: 30),
|
||||||
ElevatedButton(
|
// ElevatedButton(
|
||||||
onPressed: () => context.go('/myhomepage'),
|
// onPressed: () => context.go('/myhomepage'),
|
||||||
//context.go('/${context.language}/${BottomNavBarItem.home.routePath}'),
|
// //context.go('/${context.language}/${BottomNavBarItem.home.routePath}'),
|
||||||
child: const Text("Go to Home"),
|
// child: const Text("Go to Home"),
|
||||||
),
|
// ),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@ -456,69 +561,143 @@ class _FeedbackFormState extends State<FeedbackForm>
|
|||||||
|
|
||||||
// New widget for failure message
|
// New widget for failure message
|
||||||
Widget _buildFailureMessage() {
|
Widget _buildFailureMessage() {
|
||||||
|
double screenHeight = MediaQuery.of(context).size.height;
|
||||||
|
double screenWidth = MediaQuery.of(context).size.width;
|
||||||
return Center(
|
return Center(
|
||||||
child: Column(
|
child: Column(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
Icon(Icons.error, size: 80, color: Colors.red),
|
SizedBox(height: screenHeight / 5),
|
||||||
|
Container(
|
||||||
|
padding: EdgeInsets.all(20),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Color(0xFFF9F9F9), // Circle background color
|
||||||
|
shape: BoxShape.circle, // Make it a circle
|
||||||
|
boxShadow: [
|
||||||
|
BoxShadow(
|
||||||
|
color: Color.fromRGBO(0, 0, 0, 0.2),
|
||||||
|
blurRadius: 5,
|
||||||
|
spreadRadius: 2,
|
||||||
|
offset: Offset(0, 3), // Shadow position
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
child: Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
Image.asset(
|
||||||
|
FeedBackAssetPath.errorfb,
|
||||||
|
width: 40,
|
||||||
|
height: 40,
|
||||||
|
),])),
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Icon(Icons.error, size: 80, color: Colors.red),
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 20),
|
||||||
const Text("Failed to Share Feedback",
|
const Text("Failed to Share Feedback",
|
||||||
style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold)),
|
style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold,
|
||||||
|
color: Color(0xFF414042)),),
|
||||||
const SizedBox(height: 10),
|
const SizedBox(height: 10),
|
||||||
Text(AppLocalizations.of(context)!.feedback_failed_msg,
|
Text(AppLocalizations.of(context)!.feedback_failed_msg,
|
||||||
style: const TextStyle(fontSize: 16),
|
style: const TextStyle(fontSize: 16, color: Color(0xFF898C81)),
|
||||||
textAlign: TextAlign.center),
|
textAlign: TextAlign.center),
|
||||||
const SizedBox(height: 30),
|
// const SizedBox(height: 30),
|
||||||
ElevatedButton(
|
// ElevatedButton(
|
||||||
onPressed: () {
|
// onPressed: () {
|
||||||
setState(() {
|
// setState(() {
|
||||||
_isFeedbackFailed = false; // Reset failure state
|
// _isFeedbackFailed = false; // Reset failure state
|
||||||
});
|
// });
|
||||||
},
|
// },
|
||||||
child: const Text("Retry"),
|
// child: const Text("Retry"),
|
||||||
),
|
// ),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildEmojiButton({
|
Widget _buildEmojiButton({
|
||||||
required IconData icon,
|
// required IconData icon,
|
||||||
|
required Widget icon,
|
||||||
required String label,
|
required String label,
|
||||||
required int index,
|
required int index,
|
||||||
}) {
|
}) {
|
||||||
bool isSelected = _selectedEmojiIndex == index;
|
bool isSelected = _selectedEmojiIndex == index;
|
||||||
|
return GestureDetector(
|
||||||
return Column(
|
onTap: () {
|
||||||
children: [
|
setState(() {
|
||||||
IconButton(
|
_selectedEmojiIndex = index;
|
||||||
icon: Icon(icon, size: 40),
|
_isSmileySelected = true; // Hide error when a smiley is selected
|
||||||
color: isSelected ? Colors.green : Colors.amber,
|
});
|
||||||
onPressed: () {
|
},
|
||||||
setState(() {
|
child: Container(
|
||||||
_selectedEmojiIndex = index;
|
padding: EdgeInsets.symmetric(vertical: 8, horizontal: 8),
|
||||||
_isSmileySelected = true; // Hide error when a smiley is selected
|
decoration: BoxDecoration(
|
||||||
});
|
border: Border.all(
|
||||||
},
|
color: isSelected ? Color(0xFF8E8E8E) : Colors.transparent,
|
||||||
),
|
width: 2,
|
||||||
Text(
|
|
||||||
label,
|
|
||||||
style: TextStyle(
|
|
||||||
fontWeight: FontWeight.w400,
|
|
||||||
color: isSelected ? Colors.green : Color(0xFF000000),
|
|
||||||
),
|
),
|
||||||
|
borderRadius: BorderRadius.circular(12), // Rounded corners
|
||||||
),
|
),
|
||||||
],
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
|
||||||
|
children: [
|
||||||
|
icon, // Assuming `icon` is an Icon widget
|
||||||
|
SizedBox(height: 3),
|
||||||
|
|
||||||
|
FittedBox(
|
||||||
|
fit: BoxFit
|
||||||
|
.scaleDown, // This will make the text smaller to fit within the available space
|
||||||
|
child: Text(
|
||||||
|
label,
|
||||||
|
style: TextStyle(
|
||||||
|
fontFamily: 'Roboto',
|
||||||
|
fontWeight: FontWeight.w400,
|
||||||
|
fontSize: 14,
|
||||||
|
color: Colors.black,
|
||||||
|
// color: isSelected ? Colors.green : Colors.black,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// return Column(
|
||||||
|
// children: [
|
||||||
|
//
|
||||||
|
// IconButton(
|
||||||
|
// // icon: Icon(icon, size: 40),
|
||||||
|
// icon: icon,
|
||||||
|
// color: isSelected ? Colors.green : Colors.amber,
|
||||||
|
// onPressed: () {
|
||||||
|
// setState(() {
|
||||||
|
// _selectedEmojiIndex = index;
|
||||||
|
// _isSmileySelected = true; // Hide error when a smiley is selected
|
||||||
|
// });
|
||||||
|
// },
|
||||||
|
// ),
|
||||||
|
// Text(
|
||||||
|
// label,
|
||||||
|
// style: TextStyle(
|
||||||
|
// fontWeight: FontWeight.w400,
|
||||||
|
// color: isSelected ? Colors.green : Color(0xFF000000),
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// ],
|
||||||
|
// );
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildRatingRow(
|
Widget _buildRatingRow(
|
||||||
String label,
|
String label,
|
||||||
double rating,
|
double rating,
|
||||||
Function(double) onRatingUpdate,
|
Function(double) onRatingUpdate,
|
||||||
) {
|
) {
|
||||||
return Row(
|
return Row(
|
||||||
|
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: [
|
children: [
|
||||||
Text(label,
|
Text(label,
|
||||||
@ -535,10 +714,14 @@ class _FeedbackFormState extends State<FeedbackForm>
|
|||||||
allowHalfRating: true,
|
allowHalfRating: true,
|
||||||
itemCount: 5,
|
itemCount: 5,
|
||||||
itemSize: 30,
|
itemSize: 30,
|
||||||
itemBuilder: (context, _) => const Icon(
|
itemBuilder: (context, index) => Icon(
|
||||||
Icons.star,
|
index < rating ? Icons.star : Icons.star_border,
|
||||||
color: Colors.amber,
|
color: Colors.amber,
|
||||||
),
|
),
|
||||||
|
// itemBuilder: (context, _) => const Icon(
|
||||||
|
// Icons.star,
|
||||||
|
// color: Colors.amber,
|
||||||
|
// ),
|
||||||
onRatingUpdate: onRatingUpdate,
|
onRatingUpdate: onRatingUpdate,
|
||||||
unratedColor: Color(0xFF8E8E8E),
|
unratedColor: Color(0xFF8E8E8E),
|
||||||
),
|
),
|
||||||
@ -573,7 +756,7 @@ class _FeedbackFormState extends State<FeedbackForm>
|
|||||||
"design": _designRating,
|
"design": _designRating,
|
||||||
"redundancy": _redundancyRating,
|
"redundancy": _redundancyRating,
|
||||||
"emoji_rating": _emojiOptions[_selectedEmojiIndex!]
|
"emoji_rating": _emojiOptions[_selectedEmojiIndex!]
|
||||||
["label"], // Emoji rating
|
["label"], // Emoji rating
|
||||||
"feedback": _feedbackController.text,
|
"feedback": _feedbackController.text,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -783,7 +966,7 @@ class LangToggle extends ConsumerWidget {
|
|||||||
|
|
||||||
ref.read(preferencesUseCaseProvider.notifier).updatePreferences(
|
ref.read(preferencesUseCaseProvider.notifier).updatePreferences(
|
||||||
(prefs) => prefs.copyWith(language: languageAfter),
|
(prefs) => prefs.copyWith(language: languageAfter),
|
||||||
);
|
);
|
||||||
|
|
||||||
await onLoadFeedback(); // Reload feedback text after toggling language
|
await onLoadFeedback(); // Reload feedback text after toggling language
|
||||||
},
|
},
|
||||||
@ -793,4 +976,4 @@ class LangToggle extends ConsumerWidget {
|
|||||||
pathColorWhenOff: Colors.grey.shade300,
|
pathColorWhenOff: Colors.grey.shade300,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -622,9 +622,10 @@ class _BaseScaffoldState extends ConsumerState<BaseScaffold> {
|
|||||||
double mywidth = MediaQuery.of(context).size.width;
|
double mywidth = MediaQuery.of(context).size.width;
|
||||||
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
|
backgroundColor: Colors.white,
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: widget.title,
|
title: widget.title,
|
||||||
backgroundColor: widget.appbarColor,
|
backgroundColor: Colors.white,
|
||||||
leadingWidth: widget.showBackButton ? mywidth * 0.25 : null,
|
leadingWidth: widget.showBackButton ? mywidth * 0.25 : null,
|
||||||
bottom: widget.showDivider
|
bottom: widget.showDivider
|
||||||
? PreferredSize(
|
? PreferredSize(
|
||||||
@ -762,13 +763,13 @@ class _BaseScaffoldState extends ConsumerState<BaseScaffold> {
|
|||||||
ListTile(
|
ListTile(
|
||||||
leading: Image.asset(
|
leading: Image.asset(
|
||||||
DrawerAssetIconPath.feedback,
|
DrawerAssetIconPath.feedback,
|
||||||
color: Colors.black,
|
color: Colors.black ,
|
||||||
width: 20,
|
width: 20,
|
||||||
height: 20,
|
height: 20,
|
||||||
),
|
),
|
||||||
// title: const Text('Feedback'),
|
// title: const Text('Feedback'),
|
||||||
title: Text(AppLocalizations.of(context)!.feedback_title),
|
title: Text(AppLocalizations.of(context)!.feedback_title),
|
||||||
onTap: () => context.go('/feedback'),
|
onTap: () => context.go('/feedback', extra: userName),
|
||||||
),
|
),
|
||||||
if (role == 'admin')
|
if (role == 'admin')
|
||||||
ListTile(
|
ListTile(
|
||||||
@ -785,7 +786,7 @@ class _BaseScaffoldState extends ConsumerState<BaseScaffold> {
|
|||||||
onTap: () => context.go('/manageuser'),
|
onTap: () => context.go('/manageuser'),
|
||||||
),
|
),
|
||||||
ListTile(
|
ListTile(
|
||||||
leading: Icon(Icons.collections_bookmark_rounded),
|
leading: Icon(Icons.bookmarks_outlined),
|
||||||
title: const Text('Bookmark'),
|
title: const Text('Bookmark'),
|
||||||
onTap: () => context.go('/bookmark'),
|
onTap: () => context.go('/bookmark'),
|
||||||
),
|
),
|
||||||
|
|||||||
18
pubspec.yaml
@ -1,7 +1,7 @@
|
|||||||
name: uae_stat
|
name: uae_stat
|
||||||
description: "View statistics about the UAE from the Federal Center for Statistics and Competitiveness."
|
description: "View statistics about the UAE from the Federal Center for Statistics and Competitiveness."
|
||||||
publish_to: "none"
|
publish_to: "none"
|
||||||
version: 0.5.10
|
version: 1.0.9+10
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
sdk: ">=3.2.3 <4.0.0"
|
sdk: ">=3.2.3 <4.0.0"
|
||||||
@ -112,6 +112,22 @@ flutter:
|
|||||||
- assets/cached_responses/sharepoint/country_leader_imgs/
|
- assets/cached_responses/sharepoint/country_leader_imgs/
|
||||||
- assets/edit_profile/
|
- assets/edit_profile/
|
||||||
- assets/splash_screen/
|
- assets/splash_screen/
|
||||||
|
- assets/icons/uae_numbers/bookmarks.png
|
||||||
|
- assets/icons/uae_numbers/share.png
|
||||||
|
- assets/icons/misc/vector.png
|
||||||
|
- assets/icons/misc/visible_on.png
|
||||||
|
- assets/icons/misc/visibility_off.png
|
||||||
|
- assets/icons/misc/save.png
|
||||||
|
- assets/icons/drawer/guide.png
|
||||||
|
- assets/icons/drawer/feedback.png
|
||||||
|
- assets/icons/drawer/manageusr.png
|
||||||
|
- assets/feedback/disappointed.png
|
||||||
|
- assets/feedback/frowning.png
|
||||||
|
- assets/feedback/neutral.png
|
||||||
|
- assets/feedback/smiling.png
|
||||||
|
- assets/feedback/smilingopenface.png
|
||||||
|
- assets/feedback/errorfb.png
|
||||||
|
- assets/feedback/thumbfb.png
|
||||||
|
|
||||||
fonts:
|
fonts:
|
||||||
- family: Segoe
|
- family: Segoe
|
||||||
|
|||||||