diff --git a/assets/icons/no_data.svg b/assets/icons/no_data.svg new file mode 100644 index 0000000..9ca76f4 --- /dev/null +++ b/assets/icons/no_data.svg @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/classes/utils.dart b/lib/classes/utils.dart index 26a0d33..2349075 100644 --- a/lib/classes/utils.dart +++ b/lib/classes/utils.dart @@ -6,6 +6,7 @@ import 'colors.dart'; class Utils { static bool _isLoadingVisible = false; + static bool get isLoading => _isLoadingVisible; static void showToast(String message) { Fluttertoast.showToast( msg: message, toastLength: Toast.LENGTH_SHORT, gravity: ToastGravity.BOTTOM, timeInSecForIosWeb: 1, backgroundColor: Colors.black54, textColor: Colors.white, fontSize: 16.0); diff --git a/lib/main.dart b/lib/main.dart index 962fe91..6f7d0d9 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -2,6 +2,7 @@ import 'dart:io'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; +import 'package:tangheem/ui/screens/contact_us_screen.dart'; import 'ui/common_appbar.dart'; import 'ui/screens/forgot_password_screen.dart'; import 'ui/screens/home_screen.dart'; @@ -39,6 +40,9 @@ class Application extends StatelessWidget { case HomeScreen.routeName: className = CommonAppbar(showDrawer: true, child: HomeScreen()); break; + case ContactUsScreen.routeName: + className = CommonAppbar(child: ContactUsScreen()); + break; case TangheemScreen.routeName: Map data = settings.arguments; className = CommonAppbar( diff --git a/lib/ui/common_appbar.dart b/lib/ui/common_appbar.dart index e9ee280..ff9c081 100644 --- a/lib/ui/common_appbar.dart +++ b/lib/ui/common_appbar.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:tangheem/classes/colors.dart'; +import 'package:tangheem/ui/screens/contact_us_screen.dart'; import 'package:tangheem/ui/screens/login_screen.dart'; import 'package:tangheem/ui/screens/quran_screen.dart'; @@ -217,7 +218,9 @@ class _CommonAppbarState extends State { await Navigator.pushNamed(context, QuranScreen.routeName, arguments: ""); }), SizedBox(height: 2), - myListItem("assets/icons/contact.svg", "الاتصال بنا", false), + myListItem("assets/icons/contact.svg", "الاتصال بنا", false, onTap: () { + Navigator.pushNamed(context, ContactUsScreen.routeName, arguments: ""); + }), ], ), ), diff --git a/lib/ui/misc/no_data_ui.dart b/lib/ui/misc/no_data_ui.dart new file mode 100644 index 0000000..2d5c010 --- /dev/null +++ b/lib/ui/misc/no_data_ui.dart @@ -0,0 +1,26 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_svg/svg.dart'; +import 'package:tangheem/classes/colors.dart'; + +class NoDataUI extends StatelessWidget { + NoDataUI({Key key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return Container( + alignment: Alignment.center, + padding: EdgeInsets.only(top: 100), + child: Column( + children: [ + SvgPicture.asset("assets/icons/no_data.svg", width: 75, height: 75), + SizedBox(height: 8), + Text( + "آسف! لا تتوافر بيانات", + style: TextStyle(fontSize: 16, color: ColorConsts.primaryBlue.withOpacity(0.7), fontWeight: FontWeight.w600), + ), + SizedBox(height: 16), + ], + ), + ); + } +} diff --git a/lib/ui/screens/contact_us_screen.dart b/lib/ui/screens/contact_us_screen.dart new file mode 100644 index 0000000..75ee31c --- /dev/null +++ b/lib/ui/screens/contact_us_screen.dart @@ -0,0 +1,154 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_svg/svg.dart'; +import 'package:tangheem/api/tangheem_user_api_client.dart'; +import 'package:tangheem/classes/colors.dart'; +import 'package:tangheem/classes/utils.dart'; +import 'package:tangheem/extensions/email_validator.dart'; +import 'package:tangheem/widgets/common_textfield_widget.dart'; + +class ContactUsScreen extends StatefulWidget { + static const String routeName = "/contact_us"; + ContactUsScreen({Key key}) : super(key: key); + + @override + _ContactUsScreenState createState() { + return _ContactUsScreenState(); + } +} + +class _ContactUsScreenState extends State { + TextEditingController _firstNameController = TextEditingController(); + TextEditingController _lastNameController = TextEditingController(); + TextEditingController _emailController = TextEditingController(); + TextEditingController _mobileNumberController = TextEditingController(); + TextEditingController _descriptionController = TextEditingController(); + + @override + void initState() { + super.initState(); + } + + void sendFeedback(String _firstName, String _lastName, String _email, String _phone, String _description) async { + Utils.showLoading(context); + try { + await TangheemUserApiClient().contactUs(_firstName, _lastName, _email, _phone, _description); + Utils.showToast("شكرا لك على مراسلتنا ، نحن نقدر كلماتك."); + Utils.hideLoading(context); + Navigator.pop(context); + } catch (ex, tr) { + Utils.handleException(ex, null); + Utils.hideLoading(context); + } + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: ColorConsts.secondaryWhite, + body: SingleChildScrollView( + padding: EdgeInsets.all(32.0), + physics: BouncingScrollPhysics(), + child: Container( + width: MediaQuery.of(context).size.width, + decoration: BoxDecoration(borderRadius: BorderRadius.circular(8.0), color: Colors.white), + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisSize: MainAxisSize.min, + children: [ + Padding( + padding: EdgeInsets.only(top: 24, bottom: 24), + child: SvgPicture.asset("assets/logos/tangheem_logo.svg", width: 100, height: 100), + ), + Text( + "اتصل بنا", + style: TextStyle(fontSize: 22, color: ColorConsts.primaryBlue), + ), + Padding( + padding: EdgeInsets.all(8), + child: Text( + "لا تتردد في الاتصال بنا ، يسعدنا أن نسمع منك", + textAlign: TextAlign.center, + style: TextStyle(fontSize: 14, color: ColorConsts.primaryBlue, height: 1), + ), + ), + Container( + margin: EdgeInsets.only(top: 16), + width: double.infinity, + padding: EdgeInsets.all(32.0), + decoration: BoxDecoration( + color: ColorConsts.primaryBlue, + borderRadius: BorderRadius.only( + bottomLeft: Radius.circular(8), + bottomRight: Radius.circular(8), + ), + ), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + CommonTextFieldWidget(hint: "الاسم الاول", controller: _firstNameController), + SizedBox(height: 8), + CommonTextFieldWidget(hint: "اسم النهاية", controller: _lastNameController), + SizedBox(height: 8), + CommonTextFieldWidget(hint: "الايميل", controller: _emailController), + SizedBox(height: 8), + CommonTextFieldWidget(hint: " رقم الجوال${" (" + ("9xx") + " xxxxxxxxx)"}", controller: _mobileNumberController), + SizedBox(height: 8), + CommonTextFieldWidget(hint: "اكتب لنا", controller: _descriptionController, maxLines: 4), + SizedBox(height: 12), + SizedBox( + width: double.infinity, + height: 50, + child: TextButton( + onPressed: () { + if (_firstNameController.text.length < 1) { + Utils.showToast("الاسم الأول فارغ"); + return; + } + if (_lastNameController.text.length < 1) { + Utils.showToast("الاسم الأخير فارغ"); + return; + } + if (_emailController.text.length < 1) { + Utils.showToast("البريد الإلكتروني فارغ"); + return; + } + if (_mobileNumberController.text.length < 1) { + Utils.showToast("رقم الهاتف فارغ"); + return; + } + if (_descriptionController.text.length < 1) { + Utils.showToast("يجب أن تكتب لنا كلمات قليلة"); + return; + } + if (!_emailController.text.isValidEmail()) { + Utils.showToast("بريد إلكتروني خاطئ"); + return; + } + sendFeedback(_firstNameController.text, _lastNameController.text, _emailController.text, _mobileNumberController.text, _descriptionController.text); + }, + style: TextButton.styleFrom( + primary: Colors.white, + backgroundColor: ColorConsts.secondaryPink, + textStyle: TextStyle(fontSize: 16, fontFamily: "DroidKufi"), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(6.0), + ), + ), + child: Text("ارسل رأيك"), + ), + ), + ], + ), + ), + ], + ), + ), + ), + ); + } +} diff --git a/lib/ui/screens/home_screen.dart b/lib/ui/screens/home_screen.dart index 9845354..2d78933 100644 --- a/lib/ui/screens/home_screen.dart +++ b/lib/ui/screens/home_screen.dart @@ -30,8 +30,8 @@ class _HomeScreenState extends State { List _surahList = []; List _tangheemList = []; - int _selectedSurah = 0; - int _selectedTangheemType = 0; + int _selectedSurah = -1; + int _selectedTangheemType = -1; SurahModel _surahModel; TangheemType _tangheemType; @@ -92,7 +92,7 @@ class _HomeScreenState extends State { Row( children: [ Expanded( - child: CommonDropDownButton(_selectedTangheemType, list: _tangheemList, onSelect: (index) { + child: CommonDropDownButton(_selectedTangheemType, hintText: "الأسلوب اللغوي", list: _tangheemList, onSelect: (index) { if (_selectedTangheemType != index) { setState(() { _selectedTangheemType = index; @@ -102,7 +102,7 @@ class _HomeScreenState extends State { ), SizedBox(width: 8), Expanded( - child: CommonDropDownButton(_selectedSurah, list: _surahList, onSelect: (index) { + child: CommonDropDownButton(_selectedSurah, hintText: "السورة", list: _surahList, onSelect: (index) { if (_selectedSurah != index) { setState(() { _selectedSurah = index; @@ -117,6 +117,14 @@ class _HomeScreenState extends State { splashColor: Colors.transparent, highlightColor: Colors.transparent, onTap: () async { + if (_selectedTangheemType < 0) { + Utils.showToast("الرجاء اختيار نوع تنغيم"); + return; + } + if (_selectedSurah < 0) { + Utils.showToast("الرجاء اختيار السورة"); + return; + } _searchFocusNode.unfocus(); _searchFocusNode.canRequestFocus = false; var data = {"tangheemTypeName": _tangheemList[_selectedTangheemType], "surahData": _surahModel.data[_selectedSurah]}; diff --git a/lib/ui/screens/quran_screen.dart b/lib/ui/screens/quran_screen.dart index e959fc8..2767712 100644 --- a/lib/ui/screens/quran_screen.dart +++ b/lib/ui/screens/quran_screen.dart @@ -219,32 +219,43 @@ class _QuranScreenState extends State { shrinkWrap: true, padding: EdgeInsets.only(top: 16, bottom: 8), children: [ - Text( - "بسم الله الرحمن الرحيم", - textAlign: TextAlign.center, - style: TextStyle(fontWeight: FontWeight.bold, fontSize: 20, color: ColorConsts.primaryBlue, height: 1), - ), - SizedBox(height: 8), + // Text( + // "بسم الله الرحمن الرحيم", + // textAlign: TextAlign.center, + // style: TextStyle(fontWeight: FontWeight.bold, fontSize: 20, color: ColorConsts.primaryBlue, height: 1), + // ), + // SizedBox(height: 8), Container( padding: EdgeInsets.only(left: 4, right: 4), - child: TextHighLightWidget( - text: _surahAya, - valueColor: ColorConsts.primaryBlue, - highlights: _tangheemWords, - onTap: (value) { - List _ayatList = _ayatTangheemTypeMapped.data?.where((element) => element.highlightText == value)?.toList() ?? []; - if (_ayatList.length > 1) { - _selectTangheemType(_ayatList); - } else { - Navigator.pushNamed(context, TangheemDetailScreen.routeName, arguments: _ayatList.first); - } - }, + child: Text( + _surahAya, + textAlign: TextAlign.center, style: TextStyle( fontFamily: "UthmanicHafs", fontSize: 18, + color: ColorConsts.primaryBlue, fontWeight: FontWeight.bold, ), ), + // todo "sikander" : lines commented for future + // TextHighLightWidget( + // text: _surahAya, + // valueColor: ColorConsts.primaryBlue, + // highlights: _tangheemWords, + // onTap: (value) { + // List _ayatList = _ayatTangheemTypeMapped.data?.where((element) => element.highlightText == value)?.toList() ?? []; + // if (_ayatList.length > 1) { + // _selectTangheemType(_ayatList); + // } else { + // Navigator.pushNamed(context, TangheemDetailScreen.routeName, arguments: _ayatList.first); + // } + // }, + // style: TextStyle( + // fontFamily: "UthmanicHafs", + // fontSize: 18, + // fontWeight: FontWeight.bold, + // ), + // ), ), ], ), diff --git a/lib/ui/screens/tangheem_detail_screen.dart b/lib/ui/screens/tangheem_detail_screen.dart index a24af0a..cf943d4 100644 --- a/lib/ui/screens/tangheem_detail_screen.dart +++ b/lib/ui/screens/tangheem_detail_screen.dart @@ -52,9 +52,9 @@ class _TangheemDetailScreenState extends State { void filterData() { _ayatTangheemTypeMappedData = widget.ayatTangheemTypeMappedData; _tangheemWords.add(_ayatTangheemTypeMappedData.highlightText ?? ""); - _tangheemInsideTableTrueList = _ayatTangheemTypeMappedData?.property?.where((element) => element.isInsideTable)?.toList() ?? []; + _tangheemInsideTableTrueList = _ayatTangheemTypeMappedData?.property?.where((element) => (element.isInsideTable) && (element.propertyValue ?? "").isNotEmpty)?.toList() ?? []; _tangheemInsideTableValueList = _ayatTangheemTypeMappedData?.property?.where((element) => (!element.isInsideTable) && (element.propertyValue ?? "").isNotEmpty)?.toList() ?? []; - _tangheemInsideTableEmptyList = _ayatTangheemTypeMappedData?.property?.where((element) => (!element.isInsideTable) && (element.propertyValue ?? "").isEmpty)?.toList() ?? []; + // _tangheemInsideTableEmptyList = _ayatTangheemTypeMappedData?.property?.where((element) => (!element.isInsideTable) && (element.propertyValue ?? "").isEmpty)?.toList() ?? []; } @override diff --git a/lib/ui/screens/tangheem_screen.dart b/lib/ui/screens/tangheem_screen.dart index 0b90225..2700ca8 100644 --- a/lib/ui/screens/tangheem_screen.dart +++ b/lib/ui/screens/tangheem_screen.dart @@ -5,6 +5,7 @@ import 'package:tangheem/classes/colors.dart'; import 'package:tangheem/classes/utils.dart'; import 'package:tangheem/models/aya_tangheem_type_mapped.dart'; import 'package:tangheem/models/surah_model.dart'; +import 'package:tangheem/ui/misc/no_data_ui.dart'; import 'package:tangheem/ui/screens/tangheem_detail_screen.dart'; import 'package:tangheem/widgets/text_highlight_widget.dart'; @@ -33,7 +34,9 @@ class _TangheemScreenState extends State { Utils.showLoading(context); try { _ayatTangheemTypeMapped = await TangheemUserApiClient().getAyaTangheemTypeMapped(widget.surah.surahID, widget.tangheemTypeName); + _dataList = _ayatTangheemTypeMapped?.data ?? []; } catch (ex, tr) { + _dataList = []; Utils.handleException(ex, null); } finally { Utils.hideLoading(context); @@ -46,65 +49,68 @@ class _TangheemScreenState extends State { super.dispose(); } + List _dataList; + @override Widget build(BuildContext context) { - var _dataList = _ayatTangheemTypeMapped?.data ?? []; - return _dataList.isEmpty + return _dataList == null ? SizedBox() - : ListView.separated( - physics: BouncingScrollPhysics(), - padding: EdgeInsets.all(16), - itemCount: _dataList.length, - separatorBuilder: (context, index) { - return SizedBox(height: 8); - }, - itemBuilder: (context, index) { - return InkWell( - onTap: () { - Navigator.pushNamed(context, TangheemDetailScreen.routeName, arguments: _dataList[index]); + : _dataList.isEmpty + ? NoDataUI() + : ListView.separated( + physics: BouncingScrollPhysics(), + padding: EdgeInsets.all(16), + itemCount: _dataList.length, + separatorBuilder: (context, index) { + return SizedBox(height: 8); }, - borderRadius: BorderRadius.circular(4), - child: Container( - padding: EdgeInsets.fromLTRB(12, 8, 12, 8), - decoration: BoxDecoration( - color: Colors.white, + itemBuilder: (context, index) { + return InkWell( + onTap: () { + Navigator.pushNamed(context, TangheemDetailScreen.routeName, arguments: _dataList[index]); + }, borderRadius: BorderRadius.circular(4), - ), - child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Row( + child: Container( + padding: EdgeInsets.fromLTRB(12, 8, 12, 8), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(4), + ), + child: Column( mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.center, children: [ - Text( - _dataList[index].surahNameAr + ":", - style: TextStyle(fontSize: 12, color: ColorConsts.primaryBlue), + Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + _dataList[index].surahNameAr + ":", + style: TextStyle(fontSize: 12, color: ColorConsts.primaryBlue), + ), + Text( + " ${_dataList[index].ayahNo}", + style: TextStyle(fontSize: 14, color: ColorConsts.secondaryOrange), + ), + ], ), - Text( - " ${_dataList[index].ayahNo}", - style: TextStyle(fontSize: 14, color: ColorConsts.secondaryOrange), + TextHighLightWidget( + text: _dataList[index].ayahText, + valueColor: ColorConsts.secondaryOrange, + highlights: [_dataList[index].highlightText], + textAlign: TextAlign.start, + style: TextStyle( + fontFamily: "UthmanicHafs", + fontSize: 16, + color: ColorConsts.primaryBlue, + fontWeight: FontWeight.bold, + ), ), ], ), - TextHighLightWidget( - text: _dataList[index].ayahText, - valueColor: ColorConsts.secondaryOrange, - highlights: [_dataList[index].highlightText], - textAlign: TextAlign.start, - style: TextStyle( - fontFamily: "UthmanicHafs", - fontSize: 16, - color: ColorConsts.primaryBlue, - fontWeight: FontWeight.bold, - ), - ), - ], - ), - ), + ), + ); + }, ); - }, - ); } } diff --git a/lib/widgets/aya_player_widget.dart b/lib/widgets/aya_player_widget.dart index 7a5a7d9..365924b 100644 --- a/lib/widgets/aya_player_widget.dart +++ b/lib/widgets/aya_player_widget.dart @@ -128,7 +128,7 @@ class _AyaPlayerWidgetState extends State { builder: (context, snapshot) { final state = snapshot.data; return Text( - state == null ? "" : widget.voiceNoteList?.elementAt(state)?.userName ?? "", + (state == null || widget.voiceNoteList.isEmpty) ? "" : widget.voiceNoteList?.elementAt(state)?.userName ?? "", style: TextStyle(fontSize: 10, color: ColorConsts.textGrey1, height: 1), ); }, @@ -151,10 +151,10 @@ class _AyaPlayerWidgetState extends State { _shareAya(); }), commonIconButton("assets/icons/bookmark.svg", () {}), - commonIconButton("assets/icons/audio_level.svg", () async { - // var vol = await VolumeController.getVolume(); - VolumeController.maxVolume(); - }), + // commonIconButton("assets/icons/audio_level.svg", () async { + // // var vol = await VolumeController.getVolume(); + // VolumeController.maxVolume(); + // }), ], ), SizedBox(height: 8), diff --git a/lib/widgets/common_dropdown_button.dart b/lib/widgets/common_dropdown_button.dart index 52b8257..33f5c18 100644 --- a/lib/widgets/common_dropdown_button.dart +++ b/lib/widgets/common_dropdown_button.dart @@ -4,7 +4,7 @@ import 'package:tangheem/classes/colors.dart'; class CommonDropDownButton extends StatelessWidget { final int index; - final String text; + final String hintText; final String icon; final Color iconColor; final Color color; @@ -14,7 +14,7 @@ class CommonDropDownButton extends StatelessWidget { final double widthHeight; final List list; - CommonDropDownButton(this.index, {Key key, this.onPressed, this.isDropDown = true, this.text = "", this.color, this.icon, this.widthHeight, this.iconColor, this.onSelect, this.list}) + CommonDropDownButton(this.index, {Key key, this.onPressed, this.isDropDown = true, this.hintText = "", this.color, this.icon, this.widthHeight, this.iconColor, this.onSelect, this.list}) : super(key: key); @override @@ -41,7 +41,7 @@ class CommonDropDownButton extends StatelessWidget { color: iconColor ?? ColorConsts.secondaryOrange, ), hint: Text( - list.isNotEmpty ? list[index] : text, + (list.isEmpty || index < 0) ? hintText : list[index], maxLines: 1, overflow: TextOverflow.ellipsis, style: TextStyle(fontSize: 12, color: Colors.white), diff --git a/lib/widgets/common_textfield_widget.dart b/lib/widgets/common_textfield_widget.dart index 562db4a..916534f 100644 --- a/lib/widgets/common_textfield_widget.dart +++ b/lib/widgets/common_textfield_widget.dart @@ -10,13 +10,14 @@ class CommonTextFieldWidget extends StatelessWidget { final String prefixIcon; final Widget suffixWidget; final Function onTap; + final int maxLines; - CommonTextFieldWidget({Key key, @required this.hint, @required this.controller, this.isPassword = false, this.prefixIcon, this.suffixWidget, this.onTap}) : super(key: key); + CommonTextFieldWidget({Key key, @required this.hint, @required this.controller, this.maxLines = 1, this.isPassword = false, this.prefixIcon, this.suffixWidget, this.onTap}) : super(key: key); @override Widget build(BuildContext context) { return SizedBox( - height: 50, + // height: 50, child: TextField( textAlignVertical: TextAlignVertical.center, controller: controller, @@ -25,7 +26,9 @@ class CommonTextFieldWidget extends StatelessWidget { style: TextStyle(color: ColorConsts.primaryBlack, fontSize: 14), cursorColor: ColorConsts.primaryBlue, readOnly: onTap != null, + maxLines: maxLines, onTap: onTap, + scrollPhysics: BouncingScrollPhysics(), decoration: InputDecoration( contentPadding: EdgeInsets.fromLTRB(4, 4, 8, 4), alignLabelWithHint: true,