diff --git a/README.md b/README.md index 5f6f161..12929f3 100644 --- a/README.md +++ b/README.md @@ -20,5 +20,5 @@ There are some important information regarding Project - Variable names should be very clear which conveys the proper meaning of its use, to make code reading fast and easy to read by everyone. - Variable naming should be camelCase e.g. variableName; - Define variable scope if it only uses in a limited class or function make it private to avoid conflicts. -- Make a personal git change list if you are working on a file for test purposes. (to avoid that test changes when you git push) +- Make a personal git change list if you are working on a file for test for your own purposes. (to avoid that test changes when you git push) - avoid using too many packages if only a few functionalities required (Copy that separate code from the package file and then use this code) diff --git a/android/app/build.gradle b/android/app/build.gradle index 7cf5766..6253c65 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -26,7 +26,7 @@ apply plugin: 'kotlin-android' apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" android { - compileSdkVersion 29 + compileSdkVersion 31 sourceSets { main.java.srcDirs += 'src/main/kotlin' @@ -40,7 +40,7 @@ android { // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). applicationId "com.cloudsolutions.tangheem" minSdkVersion 19 - targetSdkVersion 29 + targetSdkVersion 30 versionCode flutterVersionCode.toInteger() versionName flutterVersionName multiDexEnabled true diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index c4fd9d0..ab4ad56 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -11,7 +11,6 @@ addDiscussion(String discussionText, String ayaTangheemTypeId) async { String url = "${ApiConsts.adminConfiguration}Discussion_Add"; - var postParams = {"discussionText": discussionText, "ayaTangheemTypeId": ayaTangheemTypeId}; + var postParams = {"discussionText": discussionText, "ayaTangheemTypeId": ayaTangheemTypeId, "statusId": 1}; var _headers = {"Authorization": "Bearer ${AppState().token}"}; return await ApiClient().postJsonForObject((json) => GeneralResponseModel.fromJson(json), url, postParams, headers: _headers); } diff --git a/lib/api/api_client.dart b/lib/api/api_client.dart index 17b1781..89817ad 100644 --- a/lib/api/api_client.dart +++ b/lib/api/api_client.dart @@ -103,7 +103,7 @@ class ApiClient { var queryString = new Uri(queryParameters: queryParameters).query; url = url + '?' + queryString; } - var response = await _post(Uri.parse(url), body: requestBody, headers: _headers).timeout(Duration(seconds: 15)); + var response = await _post(Uri.parse(url), body: requestBody, headers: _headers).timeout(Duration(minutes: 2)); if (response.statusCode >= 200 && response.statusCode < 300) { return response; diff --git a/lib/api/tangheem_user_api_client.dart b/lib/api/tangheem_user_api_client.dart index 02e2e6c..d369dd6 100644 --- a/lib/api/tangheem_user_api_client.dart +++ b/lib/api/tangheem_user_api_client.dart @@ -30,9 +30,9 @@ class TangheemUserApiClient { return await ApiClient().postJsonForObject((json) => SurahModel.fromJson(json), url, postParams); } - Future getTangheemBySurah(int surahId) async { + Future getTangheemBySurah(int surahId, int numberInSurahs) async { String url = "${ApiConsts.tangheemUsers}AyatTangheemTypeMapped_Get"; - var postParams = {"surahNo": surahId}; + var postParams = {"surahNo": surahId, "numberInSurahs": numberInSurahs.toString()}; return await ApiClient().postJsonForObject((json) => AyatTangheemTypeMapped.fromJson(json), url, postParams); } @@ -84,6 +84,21 @@ class TangheemUserApiClient { return await ApiClient().postJsonForObject((json) => AyatTangheemTypeMapped.fromJson(json), url, postParams); } + Future ayahBaseTextGet(String tangheemTypeName, String ayaText, int itemsPerPage, int currentPageNo) async { + String url = "${ApiConsts.tangheemUsers}AyahBaseText_Get"; + var postParams = {}; + if (tangheemTypeName != null) { + postParams["tangheemTypeName"] = tangheemTypeName; + } + if (ayaText != null) { + postParams["ayahTextBase"] = ayaText; + } + postParams["itemsPerPage"] = itemsPerPage; + postParams["currentPageNo"] = currentPageNo; + + return await ApiClient().postJsonForObject((json) => AyatTangheemTypeMapped.fromJson(json), url, postParams); + } + Future getAyaTangheemType(int surahNo, String tangheemTypeName) async { String url = "${ApiConsts.tangheemUsers}AyaTangheemType_Get"; diff --git a/lib/classes/consts.dart b/lib/classes/consts.dart index 4654e95..a42d180 100644 --- a/lib/classes/consts.dart +++ b/lib/classes/consts.dart @@ -1,7 +1,8 @@ class ApiConsts { //static String baseUrl = "http://10.200.204.20:2801/"; // Local server // static String baseUrl = "http://20.203.25.82"; // production server - static String baseUrl = "http://18.221.16.125"; // new production server + // static String baseUrl = "http://18.221.16.125"; // new production server + static String baseUrl = "https://www.tangheemalquran.com"; // new production server Words static String baseUrlServices = baseUrl + "/services/"; // production server // static String baseUrlServices = "https://api.cssynapses.com/tangheem/"; // Live server static String authentication = baseUrlServices + "api/Authentication/"; @@ -15,7 +16,10 @@ class GlobalConsts { static String email = "email"; static String password = "password"; static String bookmark = "bookmark"; - static String fontZoomSize = "font_zoom_size"; + static String fontZoomSize = "fontZoomSize"; + static String fontZoomSizeQuran = "fontZoomSizeQuran"; + static String fontZoomSizeTangheem = "fontZoomSizeTangheem"; static String welcomeVideoUrl = "welcomeVideoUrl"; static String doNotShowWelcomeVideo = "doNotShowWelcomeVideo"; + static String userAuthData = "userAuthData"; } diff --git a/lib/models/aya_tangheem_type_mapped.dart b/lib/models/aya_tangheem_type_mapped.dart index 2a78743..609fd9c 100644 --- a/lib/models/aya_tangheem_type_mapped.dart +++ b/lib/models/aya_tangheem_type_mapped.dart @@ -165,7 +165,7 @@ class AyatTangheemTypeMappedData { String _reverseAyatNumber(String ayaText, String ayaLength) { String _ayaTemp = ayaText.substring(0, ayaText.length - ayaLength.toString().length); String _ayaNum = ayaText.substring(ayaText.length - ayaLength.toString().length, ayaText.length); - _ayaNum = _ayaNum.split('').reversed.join(''); + //_ayaNum = _ayaNum.split('').reversed.join(''); // commenting this line for temperating purpose return "$_ayaTemp $_ayaNum"; } } diff --git a/lib/ui/common_appbar.dart b/lib/ui/common_appbar.dart index fa25ea0..95d60b8 100644 --- a/lib/ui/common_appbar.dart +++ b/lib/ui/common_appbar.dart @@ -1,3 +1,5 @@ +import 'dart:convert'; + import 'package:flutter/material.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:shared_preferences/shared_preferences.dart'; @@ -7,6 +9,7 @@ import 'package:tangheem/app_state/app_state.dart'; import 'package:tangheem/classes/colors.dart'; import 'package:tangheem/classes/consts.dart'; import 'package:tangheem/classes/utils.dart'; +import 'package:tangheem/models/authentication_user_model.dart'; import 'package:tangheem/models/navigation_model.dart'; import 'package:tangheem/models/quick_links_model.dart'; import 'package:tangheem/ui/dialogs/change_password_dialog.dart'; @@ -90,6 +93,11 @@ class _CommonAppbarState extends State { void getPrefs() async { prefs = await SharedPreferences.getInstance(); fontSize = prefs.getInt(GlobalConsts.fontZoomSize) ?? 18; + String userAuth = prefs.getString(GlobalConsts.userAuthData); + if (userAuth != null) { + AuthenticationUserModel authenticationUserModel = AuthenticationUserModel.fromJson(jsonDecode(userAuth)); + AppState().setAuthenticationModel(authenticationUserModel); + } } @override @@ -153,7 +161,7 @@ class _CommonAppbarState extends State { try { await UserApiClient().updatePassword(email, oldPassword, password); } catch (ex) { - Utils.handleException(ex, null); + if (mounted) Utils.handleException(ex, null); Utils.hideLoading(context); return; } finally { @@ -288,30 +296,47 @@ class _CommonAppbarState extends State { Expanded( child: PopupMenuButton( padding: EdgeInsets.fromLTRB(0, 0, 0, 0), - onSelected: (int index) { - Navigator.pop(context); - Future.delayed(Duration(milliseconds: 200), () { - showDialog( - context: context, - barrierColor: ColorConsts.secondaryWhite.withOpacity(0.8), - builder: (BuildContext context) => ChangePasswordDialog( - onPassword: (oldPassword, password) => updatePassword(AppState().userEmail, oldPassword, password), - ), - ); - }); + onSelected: (int index) async { + if (index == 0) { + Navigator.pop(context); + Future.delayed(Duration(milliseconds: 200), () { + showDialog( + context: context, + barrierColor: ColorConsts.secondaryWhite.withOpacity(0.8), + builder: (BuildContext context) => ChangePasswordDialog( + onPassword: (oldPassword, password) => updatePassword(AppState().userEmail, oldPassword, password), + ), + ); + }); + } else { + SharedPreferences prefs = await SharedPreferences.getInstance(); + await prefs.remove(GlobalConsts.userAuthData); + AppState().setAuthenticationModel(null); + Utils.showToast("تسجيل خروج المستخدم"); + Navigator.pop(context); + } }, icon: SvgPicture.asset("assets/icons/fa_key.svg", height: 25, width: 30, color: ColorConsts.textGrey1), - - // Icon(Icons.settings, color: ColorConsts.textGrey1), itemBuilder: (_) => >[ PopupMenuItem( value: 1, padding: EdgeInsets.fromLTRB(0, 0, 0, 0), - height: 16, + height: 24, child: Center( child: Text( 'تغيير كلمة المرور', - style: TextStyle(color: ColorConsts.primaryBlack, fontSize: 12), + style: TextStyle(color: ColorConsts.primaryBlack, fontSize: 14), + ), + ), + ), + PopupMenuItem( + value: 1, + padding: EdgeInsets.fromLTRB(0, 0, 0, 0), + height: 24, + child: Center( + child: Text( + 'تسجيل خروج', + style: TextStyle(color: ColorConsts.primaryBlack, fontSize: 14), ), ), ), diff --git a/lib/ui/screens/contact_us_screen.dart b/lib/ui/screens/contact_us_screen.dart index f883cc9..955d06b 100644 --- a/lib/ui/screens/contact_us_screen.dart +++ b/lib/ui/screens/contact_us_screen.dart @@ -37,7 +37,7 @@ class _ContactUsScreenState extends State { Utils.hideLoading(context); Navigator.pop(context); } catch (ex) { - Utils.handleException(ex, null); + if (mounted) Utils.handleException(ex, null); Utils.hideLoading(context); } } diff --git a/lib/ui/screens/content_info_screen.dart b/lib/ui/screens/content_info_screen.dart index f2b78e2..4837804 100644 --- a/lib/ui/screens/content_info_screen.dart +++ b/lib/ui/screens/content_info_screen.dart @@ -33,7 +33,7 @@ class _ContentInfoScreenState extends State { contentList = membersData?.data ?? []; } catch (ex) { contentList = []; - Utils.handleException(ex, null); + if (mounted) Utils.handleException(ex, null); } finally { Utils.hideLoading(context); } diff --git a/lib/ui/screens/forgot_password_screen.dart b/lib/ui/screens/forgot_password_screen.dart index 8ccaf21..16a81a8 100644 --- a/lib/ui/screens/forgot_password_screen.dart +++ b/lib/ui/screens/forgot_password_screen.dart @@ -36,7 +36,7 @@ class _ForgotPasswordScreenState extends State { await UserApiClient().forgotPassword(email); Utils.showToast("تم إرسال رابط تغيير كلمة المرور إلى بريدك الإلكتروني"); } catch (ex) { - Utils.handleException(ex, null); + if (mounted) Utils.handleException(ex, null); Utils.hideLoading(context); return; } finally { @@ -50,7 +50,7 @@ class _ForgotPasswordScreenState extends State { try { await UserApiClient().verifyOTP(email, otp); } catch (ex) { - Utils.handleException(ex, null); + if (mounted) Utils.handleException(ex, null); Utils.hideLoading(context); return; } finally { @@ -65,7 +65,7 @@ class _ForgotPasswordScreenState extends State { try { //await UserApiClient().updatePassword(email, otp, password); } catch (ex) { - Utils.handleException(ex, null); + if (mounted) Utils.handleException(ex, null); Utils.hideLoading(context); return; } finally { diff --git a/lib/ui/screens/home_screen.dart b/lib/ui/screens/home_screen.dart index a5f091a..1c2fbe1 100644 --- a/lib/ui/screens/home_screen.dart +++ b/lib/ui/screens/home_screen.dart @@ -68,7 +68,7 @@ class _HomeScreenState extends State { Utils.hideLoading(context); } catch (ex) { Utils.hideLoading(context); - Utils.handleException(ex, null); + if (mounted) Utils.handleException(ex, null); } checkScreenMode(); } @@ -85,7 +85,7 @@ class _HomeScreenState extends State { if (showLoading) Utils.hideLoading(context); } catch (ex) { if (showLoading) Utils.hideLoading(context); - Utils.handleException(ex, null); + if (mounted) Utils.handleException(ex, null); } } @@ -98,7 +98,7 @@ class _HomeScreenState extends State { Utils.hideLoading(context); } catch (ex) { Utils.hideLoading(context); - Utils.handleException(ex, null); + if (mounted) Utils.handleException(ex, null); } } @@ -192,7 +192,7 @@ class _HomeScreenState extends State { SizedBox(height: 8), Text( Utils.getNotNullValue(_contentInfoModel?.data ?? [], 0)?.content ?? "", - style: TextStyle(fontSize: 14, color: ColorConsts.textGrey, height: 1), + style: TextStyle(fontSize: 14, color: ColorConsts.textGrey, height: 1.5), ), SizedBox(height: 32), Row( diff --git a/lib/ui/screens/login_screen.dart b/lib/ui/screens/login_screen.dart index ba90526..f29686c 100644 --- a/lib/ui/screens/login_screen.dart +++ b/lib/ui/screens/login_screen.dart @@ -1,3 +1,5 @@ +import 'dart:convert'; + import 'package:flutter/material.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:shared_preferences/shared_preferences.dart'; @@ -57,9 +59,9 @@ class _LoginScreenState extends State { Utils.showLoading(context); try { _authenticationUser = await AuthenticationApiClient().authenticateUser(_email, _password); - Utils.showToast("تسجيل الدخول بنجاح"); - AppState().setAuthenticationModel(_authenticationUser); SharedPreferences prefs = await SharedPreferences.getInstance(); + await prefs.setString(GlobalConsts.userAuthData, jsonEncode(_authenticationUser.toJson())); + AppState().setAuthenticationModel(_authenticationUser); if (!_isRemember) { _email = ""; _password = ""; @@ -67,10 +69,11 @@ class _LoginScreenState extends State { await prefs.setBool(GlobalConsts.isRememberMe, _isRemember); await prefs.setString(GlobalConsts.email, _email); await prefs.setString(GlobalConsts.password, _password); + Utils.showToast("تسجيل الدخول بنجاح"); Utils.hideLoading(context); Navigator.pop(context); } catch (ex) { - Utils.handleException(ex, null); + if (mounted) Utils.handleException(ex, null); Utils.hideLoading(context); } } diff --git a/lib/ui/screens/member_screen.dart b/lib/ui/screens/member_screen.dart index 192a33b..5156030 100644 --- a/lib/ui/screens/member_screen.dart +++ b/lib/ui/screens/member_screen.dart @@ -34,7 +34,7 @@ class _MemberScreenState extends State { membersList.sort((a, b) => a.orderNo.compareTo(b.orderNo)); } catch (ex) { membersList = []; - Utils.handleException(ex, null); + if (mounted) Utils.handleException(ex, null); } finally { Utils.hideLoading(context); } diff --git a/lib/ui/screens/pdf_viewer_screen.dart b/lib/ui/screens/pdf_viewer_screen.dart index 4f32035..92acd20 100644 --- a/lib/ui/screens/pdf_viewer_screen.dart +++ b/lib/ui/screens/pdf_viewer_screen.dart @@ -33,7 +33,7 @@ class _PdfListScreenState extends State { contentList = membersData?.data ?? []; } catch (ex) { contentList = []; - Utils.handleException(ex, null); + if (mounted) Utils.handleException(ex, null); } finally { Utils.hideLoading(context); } diff --git a/lib/ui/screens/quran_screen.dart b/lib/ui/screens/quran_screen.dart index c4caedd..f00511a 100644 --- a/lib/ui/screens/quran_screen.dart +++ b/lib/ui/screens/quran_screen.dart @@ -57,13 +57,13 @@ class _QuranScreenState extends State { getSurah(); } - double fontSize = 18; + int fontSize = 18; SharedPreferences prefs; void getPrefs() async { prefs = await SharedPreferences.getInstance(); - fontSize = (prefs.getInt(GlobalConsts.fontZoomSize) ?? 18) + 0.0; + fontSize = (prefs.getInt(GlobalConsts.fontZoomSize) ?? 18); setState(() {}); } @@ -81,7 +81,7 @@ class _QuranScreenState extends State { Utils.hideLoading(context); } catch (ex) { Utils.hideLoading(context); - Utils.handleException(ex, null); + if (mounted) Utils.handleException(ex, null); } setState(() {}); getQuranByPageNo(); @@ -111,38 +111,40 @@ class _QuranScreenState extends State { setState(() {}); } - Future getTangheemBySurahId() async { + Future> getTangheemBySurahId(int surahId, int numberInSurah) async { + Utils.showLoading(context); try { - _ayatTangheemTypeMapped = await TangheemUserApiClient().getTangheemBySurah(_selectedSurah + 1); - _tangheemWords = _ayatTangheemTypeMapped?.data?.map((e) => e.highlightText)?.toList() ?? []; + AyatTangheemTypeMapped _ayatTangheemTypeMapped = await TangheemUserApiClient().getTangheemBySurah(surahId, numberInSurah); + Utils.hideLoading(context); + return _ayatTangheemTypeMapped.data; } catch (ex) { - Utils.handleException(ex, null); - } finally {} - setState(() {}); + Utils.hideLoading(context); + // if (mounted) Utils.handleException(ex, null); + return []; + } } void getAyaByRange() async { Utils.showLoading(context); try { _ayaModel = await TangheemUserApiClient().getAyaByFilter(_selectedSurah + 1, _fromAyaList[_selectedFromAya], _toAyaList[_selectedToAya]); - await getTangheemBySurahId(); } catch (ex) { - Utils.handleException(ex, null); + if (mounted) Utils.handleException(ex, null); } finally { Utils.hideLoading(context); } - // getTangheemBySurahId(); + setState(() {}); } void getQuranByPageNo() async { Utils.showLoading(context); try { _ayaModel = await TangheemUserApiClient().getQuranByPageNo(_currentPage); - await getTangheemBySurahId(); + // await getTangheemBySurahId(); Utils.hideLoading(context); - // setState(() {}); + setState(() {}); } catch (ex) { - Utils.handleException(ex, null); + if (mounted) Utils.handleException(ex, null); Utils.hideLoading(context); } } @@ -256,6 +258,7 @@ class _QuranScreenState extends State { ), SizedBox(height: 8), Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ commonIconButton("عرض", "assets/icons/go_forward.svg", () { if (_selectedSurah < 0) { @@ -273,6 +276,29 @@ class _QuranScreenState extends State { } } }), + Row( + mainAxisSize: MainAxisSize.min, + children: [ + zoomButtons("assets/icons/reduce_size.svg", () { + if (fontSize <= 12) { + Utils.showToast("وصل حجم الخط إلى الحد الأدنى للحجم"); + return; + } + fontSize -= 2; + prefs.setInt(GlobalConsts.fontZoomSize, fontSize); + setState(() {}); + }), + zoomButtons("assets/icons/increase_size.svg", () { + if (fontSize >= 36) { + Utils.showToast("وصل حجم الخط إلى الحد الأقصى للحجم"); + return; + } + fontSize += 2; + prefs.setInt(GlobalConsts.fontZoomSize, fontSize); + setState(() {}); + }), + ], + ) ], ), SizedBox(height: 16), @@ -486,16 +512,15 @@ class _QuranScreenState extends State { List textSpanList = []; String _surahAya = ""; _ayaModel?.data?.forEach((element) { - var temp = element.numberInSurah == 1 - ? getBismillahWithSurahName(element.surahID, element.surahNameAR, element.surahID != 1, _surahAya.length <= 1) + element.reverseAyatNumber() - : element.reverseAyatNumber(); + var temp = + element.numberInSurah == 1 ? getBismillahWithSurahName(element.surahID, element.surahNameAR, element.surahID != 1, _surahAya.length <= 1) + element.reverseAyatNumber() : element.ayahText; textSpanList.add(TextSpan( text: temp + " ", style: TextStyle( backgroundColor: _selectedAyaForBookmark?.ayahID == element.ayahID ? ColorConsts.secondaryOrange.withOpacity(.4) : Colors.transparent, fontFamily: "UthmanicHafs", - fontSize: fontSize, + fontSize: fontSize.toDouble(), color: ColorConsts.primaryBlue, fontWeight: FontWeight.bold, ), @@ -504,7 +529,7 @@ class _QuranScreenState extends State { setState(() { if (_selectedAyaForBookmark == null) { _selectedAyaForBookmark = BookMarkModel.fromJson(element.toJson()); - showAyaOptions(); + showAyaOptions(element); return; } _selectedAyaForBookmark = null; @@ -520,7 +545,7 @@ class _QuranScreenState extends State { text: "\n" + "$_currentPage", style: TextStyle( fontFamily: "BArabics", - fontSize: fontSize, + fontSize: fontSize.toDouble(), color: ColorConsts.primaryBlue, fontWeight: FontWeight.bold, ), @@ -538,7 +563,7 @@ class _QuranScreenState extends State { ); } - void showAyaOptions() { + void showAyaOptions(AyaModelData ayaModelData) { showModalBottomSheet( context: context, backgroundColor: Colors.transparent, @@ -562,7 +587,7 @@ class _QuranScreenState extends State { onTap: () async { Navigator.pop(context); List list = []; - list = _ayatTangheemTypeMapped?.data?.where((element) => int.parse(element.ayahNos.split(",").last) == _selectedAyaForBookmark.ayahID)?.toList() ?? []; + list = await getTangheemBySurahId(ayaModelData.surahID, ayaModelData.numberInSurah); if (list.isEmpty) { Utils.showToast("لا توجد أساليب تنغيم في هذه الآية"); return; @@ -577,8 +602,7 @@ class _QuranScreenState extends State { var name = list.firstWhere((element) => element.tangheemTypeName == tempList.first, orElse: null); TangheemDetailParams tangheem = TangheemDetailParams(selectedTangheemTypeId: name?.ayaTangheemTypeId ?? "", ayatTangheemTypeMappedDataList: list); - - Navigator.pushNamed(context, TangheemDetailScreen.routeName, arguments: tangheem); + Navigator.pushNamed(this.context, TangheemDetailScreen.routeName, arguments: tangheem); }, child: Row( children: [Text("تفاصيل الأساليب")], @@ -607,6 +631,14 @@ class _QuranScreenState extends State { ); }); } + + Widget zoomButtons(String icon, VoidCallback onPressed, {double size, bool isAsset = true}) { + return IconButton( + padding: EdgeInsets.zero, + icon: SvgPicture.asset(icon, height: size ?? 24, width: size ?? 24), + onPressed: onPressed, + ); + } } class TangheemTemp { diff --git a/lib/ui/screens/registration_screen.dart b/lib/ui/screens/registration_screen.dart index 5d0b8a3..05b1d0c 100644 --- a/lib/ui/screens/registration_screen.dart +++ b/lib/ui/screens/registration_screen.dart @@ -49,7 +49,7 @@ class _RegistrationScreenState extends State { } setState(() {}); } catch (ex) { - Utils.handleException(ex, null); + if (mounted) Utils.handleException(ex, null); } finally { Utils.hideLoading(context); } @@ -68,7 +68,7 @@ class _RegistrationScreenState extends State { Utils.hideLoading(context); Navigator.pop(context); } catch (ex) { - Utils.handleException(ex, null); + if (mounted) Utils.handleException(ex, null); Utils.hideLoading(context); } } diff --git a/lib/ui/screens/tangheem_detail_screen.dart b/lib/ui/screens/tangheem_detail_screen.dart index 1fac97c..698cc4c 100644 --- a/lib/ui/screens/tangheem_detail_screen.dart +++ b/lib/ui/screens/tangheem_detail_screen.dart @@ -1,7 +1,14 @@ +import 'dart:io'; +import 'dart:typed_data'; +import 'dart:ui' as ui; + import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; import 'package:flutter_html/flutter_html.dart'; import 'package:flutter_svg/flutter_svg.dart'; +import 'package:path_provider/path_provider.dart'; +import 'package:share/share.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:tangheem/api/admin_configuration_api_client.dart'; import 'package:tangheem/api/tangheem_user_api_client.dart'; @@ -63,13 +70,13 @@ class _TangheemDetailScreenState extends State { getTangheemDiscussionAndRelatedData(); } - double fontSize = 18; + int fontSize = 18; SharedPreferences prefs; void getPrefs() async { prefs = await SharedPreferences.getInstance(); - fontSize = (prefs.getInt(GlobalConsts.fontZoomSize) ?? 18) + 0.0; + fontSize = (prefs.getInt(GlobalConsts.fontZoomSizeTangheem) ?? 18); setState(() {}); } @@ -98,8 +105,7 @@ class _TangheemDetailScreenState extends State { Utils.hideLoading(context); setState(() {}); } catch (ex) { - print(ex); - Utils.handleException(ex, null); + if (mounted) Utils.handleException(ex, null); Utils.hideLoading(context); } } @@ -132,14 +138,14 @@ class _TangheemDetailScreenState extends State { Utils.hideLoading(context); Navigator.pop(context); } catch (ex) { - Utils.handleException(ex, null); + if (mounted) Utils.handleException(ex, null); Utils.hideLoading(context); } } void filterVoiceListData() { ayatTangheemTypeMappedDataList.forEach((element) { - voiceNoteList.addAll(element.voiceNote); + voiceNoteList.addAll(element?.voiceNote ?? []); }); } @@ -163,14 +169,83 @@ class _TangheemDetailScreenState extends State { physics: BouncingScrollPhysics(), padding: EdgeInsets.only(bottom: 16, top: 16), children: [ - Text( - _ayatTangheemTypeMappedFirstData.tangheemTypeName ?? "", - style: TextStyle(fontWeight: FontWeight.bold, fontSize: 20, color: ColorConsts.primaryBlue, height: 1.5), + Text.rich( + TextSpan( + children: [ + TextSpan( + text: _ayatTangheemTypeMappedFirstData.tangheemTypeName ?? "", + style: TextStyle(fontWeight: FontWeight.bold, fontSize: 20, color: ColorConsts.primaryBlue, height: 1.5), + ), + WidgetSpan( + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + zoomButtons("assets/icons/reduce_size.svg", () { + if (fontSize <= 12) { + Utils.showToast("وصل حجم الخط إلى الحد الأدنى للحجم"); + return; + } + fontSize -= 2; + prefs.setInt(GlobalConsts.fontZoomSize, fontSize); + setState(() {}); + }), + SizedBox(width: 4), + zoomButtons("assets/icons/increase_size.svg", () { + if (fontSize >= 36) { + Utils.showToast("وصل حجم الخط إلى الحد الأقصى للحجم"); + return; + } + fontSize += 2; + prefs.setInt(GlobalConsts.fontZoomSize, fontSize); + setState(() {}); + }), + ], + ), + ), + WidgetSpan( + child: PopupMenuButton( + child: IconButton( + highlightColor: Colors.transparent, + splashColor: Colors.transparent, + constraints: BoxConstraints(), + padding: EdgeInsets.only(right: 2), + icon: SvgPicture.asset("assets/icons/share_aya.svg", height: 16, width: 16), + onPressed: null), + padding: EdgeInsets.fromLTRB(4, 4, 0, 4), + itemBuilder: (_) => >[ + PopupMenuItem( + value: 1, + child: Text( + "مشاركة رابط", + style: TextStyle(color: ColorConsts.primaryBlack), + ), + ), + PopupMenuItem( + value: 2, + child: Text( + "مشاركة صورة", + style: TextStyle(color: ColorConsts.primaryBlack), + ), + ) + ], + onSelected: (int value) { + if (value == 1) { + _shareAyaAsLink(); + } else { + _shareAyaAsImage(); + } + }, + ), + ), + + // TextSpan(text: ' world!'), + ], + ), ), SizedBox(height: 8), Text( _ayatTangheemTypeMappedFirstData.tangheemTypeDescription ?? "", - style: TextStyle(fontSize: 14, color: ColorConsts.textGrey, height: 1), + style: TextStyle(fontSize: 14, color: ColorConsts.textGrey, height: 1.5), ), SizedBox(height: 8), Container( @@ -191,14 +266,16 @@ class _TangheemDetailScreenState extends State { shrinkWrap: true, itemCount: ayatTangheemTypeMappedDataList.length > 5 ? 5 : ayatTangheemTypeMappedDataList.length, itemBuilder: (context, index) { - var _ayatTangheemTypeMappedData = ayatTangheemTypeMappedDataList[index]; + final _ayatTangheemTypeMappedData = ayatTangheemTypeMappedDataList[index]; + List _tangheemInsideTableList = []; List _tangheemAboveTableList = []; List _tangheemBelowTableList = []; List _tangheemWords = []; + List _tempPropertyList = [] + _ayatTangheemTypeMappedData?.property ?? []; - List _tempPropertyList = List() + _ayatTangheemTypeMappedData?.property ?? []; int firstIndex = _tempPropertyList.indexWhere((element) => element.isInsideTable); + if (firstIndex >= 0) { var _tempPropertyListTop = _tempPropertyList.take(firstIndex); _tempPropertyListTop = _tempPropertyListTop.where((element) => (element.propertyValue ?? "").isNotEmpty)?.toList() ?? []; @@ -254,8 +331,9 @@ class _TangheemDetailScreenState extends State { startIndex: _ayatTangheemTypeMappedData.startIndex, endIndex: _ayatTangheemTypeMappedData.endIndex, textAlign: TextAlign.start, + fontSize: fontSize.toDouble(), highlightAya: _ayatTangheemTypeMappedData.highlightText, - highlightAyaNos: _ayatTangheemTypeMappedData.highlightAyaNos??"", + highlightAyaNos: _ayatTangheemTypeMappedData.highlightAyaNos ?? "", ayahTextList: _ayatTangheemTypeMappedData.ayahTextList, ), // TextHighLightWidget( @@ -395,6 +473,8 @@ class _TangheemDetailScreenState extends State { var removedData = list[index]; list.remove(removedData); list.insert(0, removedData); + list = list?.where((element) => (element.ayahNos.contains(removedData.ayahNos)) && (element.tangheemTypeId == removedData.tangheemTypeId))?.toList() ?? []; + TangheemDetailParams tangheem = TangheemDetailParams(selectedTangheemTypeId: _dataList[index].ayaTangheemTypeId, ayatTangheemTypeMappedDataList: list); Navigator.pushNamed(context, TangheemDetailScreen.routeName, arguments: tangheem); }, @@ -416,8 +496,9 @@ class _TangheemDetailScreenState extends State { if (MediaQuery.of(context).orientation == Orientation.portrait) AyaPlayerWidget( surahName: _ayatTangheemTypeMappedFirstData?.surahNameAr ?? "", - ayaTangheemTypeId: _ayatTangheemTypeMappedFirstData?.ayaTangheemTypeId ?? "", + ayaTangheemTypeId: _ayatTangheemTypeMappedFirstData?.tangheemTypeId ?? "", globalKey: _globalKey, + numberInSurah: _ayatTangheemTypeMappedFirstData?.ayatNumberInSurahs, ayaNo: _ayatTangheemTypeMappedFirstData?.ayahNo, surahNo: _ayatTangheemTypeMappedFirstData?.surahNo, voiceNoteList: voiceNoteList), @@ -451,8 +532,9 @@ class _TangheemDetailScreenState extends State { if (showAyaPlayer) AyaPlayerWidget( surahName: _ayatTangheemTypeMappedFirstData?.surahNameAr ?? "", - ayaTangheemTypeId: _ayatTangheemTypeMappedFirstData?.ayaTangheemTypeId ?? "", + ayaTangheemTypeId: _ayatTangheemTypeMappedFirstData?.tangheemTypeId ?? "", ayaNo: _ayatTangheemTypeMappedFirstData?.ayahNo, + numberInSurah: _ayatTangheemTypeMappedFirstData?.ayatNumberInSurahs, surahNo: _ayatTangheemTypeMappedFirstData?.surahNo, globalKey: _globalKey, voiceNoteList: voiceNoteList), @@ -567,7 +649,8 @@ class _TangheemDetailScreenState extends State { return Container( color: Colors.white, padding: EdgeInsets.all(2), - child: Row(crossAxisAlignment: CrossAxisAlignment.start, + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, children: [ for (var property in tangheemPropertyList) Expanded( @@ -826,4 +909,42 @@ class _TangheemDetailScreenState extends State { ], ); } + + void _shareAyaAsLink() async { + String _url = + "${ApiConsts.baseUrl}/quran/tangheemtype?surahNo=${_ayatTangheemTypeMappedFirstData?.surahNo}&ayahNo=${_ayatTangheemTypeMappedFirstData?.ayahNo}&tanghemType=${_ayatTangheemTypeMappedFirstData?.tangheemTypeId}&numberinsurah=${_ayatTangheemTypeMappedFirstData?.ayatNumberInSurahs}"; + await Share.share(_url); + } + + void _shareAyaAsImage() async { + Utils.showLoading(context); + try { + RenderRepaintBoundary boundary = _globalKey.currentContext.findRenderObject(); + ui.Image image = await boundary.toImage(pixelRatio: 3.0); + ByteData byteData = await image.toByteData(format: ui.ImageByteFormat.png); + Uint8List pngBytes = byteData.buffer.asUint8List(); + + final tempDir = await getTemporaryDirectory(); + final file = await File('${tempDir.path}/${DateTime.now().toString()}.png').create(); + await file.writeAsBytes(pngBytes); + await TangheemUserApiClient().addStatistics(3); + await Share.shareFiles(['${file.path}']); + Utils.hideLoading(context); + } catch (ex) { + Future.delayed(Duration(seconds: 1), () { + Utils.hideLoading(context); + }); + } + } + + Widget zoomButtons(String icon, VoidCallback onPressed, {double size, bool isAsset = true}) { + return IconButton( + highlightColor: Colors.transparent, + splashColor: Colors.transparent, + constraints: BoxConstraints(), + padding: EdgeInsets.only(right: 2), + icon: SvgPicture.asset(icon, height: size ?? 20, width: size ?? 20), + onPressed: onPressed, + ); + } } diff --git a/lib/ui/screens/tangheem_screen.dart b/lib/ui/screens/tangheem_screen.dart index c223f61..1233f11 100644 --- a/lib/ui/screens/tangheem_screen.dart +++ b/lib/ui/screens/tangheem_screen.dart @@ -35,19 +35,42 @@ class _TangheemScreenState extends State { void initState() { super.initState(); _controller = new ScrollController()..addListener(_scrollListener); - getTangheemData(); + if (widget.tangheemQuery == null) { + getTangheemData(); + } else { + getTangheemDataByKeyword(); + } } _scrollListener() { if (_controller.position.extentAfter.toInt() <= 0 && canCallApi) { if (_dataList.length < _ayatTangheemTypeMapped.totalItemsCount) { currentPageNo++; - getTangheemData(); + if (widget.tangheemQuery == null) { + getTangheemData(); + } else { + getTangheemDataByKeyword(); + } } canCallApi = false; } } + void getTangheemDataByKeyword() async { + Utils.showLoading(context); + try { + _ayatTangheemTypeMapped = await TangheemUserApiClient().ayahBaseTextGet(widget.tangheemTypeName, widget.tangheemQuery, itemsPerPage, currentPageNo); + _dataList = (_dataList ?? []) + (_ayatTangheemTypeMapped?.data ?? []); + } catch (ex) { + _dataList = _dataList ?? []; + if (mounted) Utils.handleException(ex, null); + } finally { + Utils.hideLoading(context); + canCallApi = true; + } + setState(() {}); + } + void getTangheemData() async { Utils.showLoading(context); try { @@ -55,7 +78,7 @@ class _TangheemScreenState extends State { _dataList = (_dataList ?? []) + (_ayatTangheemTypeMapped?.data ?? []); } catch (ex) { _dataList = _dataList ?? []; - Utils.handleException(ex, null); + if (mounted) Utils.handleException(ex, null); } finally { Utils.hideLoading(context); canCallApi = true; @@ -116,6 +139,11 @@ class _TangheemScreenState extends State { " ${_dataList[index].ayatNumberInSurahs}", style: TextStyle(fontSize: 14, fontFamily: "BArabics", color: ColorConsts.secondaryOrange), ), + SizedBox(width: 4), + Text( + "(${_dataList[index].tangheemTypeName})", + style: TextStyle(fontSize: 12, color: ColorConsts.secondaryOrange), + ), ], ), TextHighLightLengthWidget( @@ -124,7 +152,7 @@ class _TangheemScreenState extends State { endIndex: _dataList[index].endIndex, textAlign: TextAlign.start, highlightAya: _dataList[index].highlightText, - highlightAyaNos: _dataList[index].highlightAyaNos??"", + highlightAyaNos: _dataList[index].highlightAyaNos ?? "", ayahTextList: _dataList[index].ayahTextList, ), // TextHighLightWidget( diff --git a/lib/widgets/aya_player_widget.dart b/lib/widgets/aya_player_widget.dart index 5b03422..ac1ddb9 100644 --- a/lib/widgets/aya_player_widget.dart +++ b/lib/widgets/aya_player_widget.dart @@ -1,5 +1,4 @@ import 'dart:convert'; -import 'dart:io'; import 'dart:math' as math; import 'dart:typed_data'; import 'dart:ui' as ui; @@ -10,10 +9,7 @@ import 'package:flutter/services.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:image_gallery_saver/image_gallery_saver.dart'; import 'package:just_audio/just_audio.dart'; -import 'package:path_provider/path_provider.dart'; import 'package:permission_handler/permission_handler.dart'; -import 'package:share/share.dart'; -import 'package:tangheem/api/tangheem_user_api_client.dart'; import 'package:tangheem/classes/colors.dart'; import 'package:tangheem/classes/consts.dart'; import 'package:tangheem/classes/utils.dart'; @@ -22,12 +18,13 @@ import 'package:tangheem/models/aya_tangheem_type_mapped.dart'; class AyaPlayerWidget extends StatefulWidget { final int surahNo; final int ayaNo; + final String numberInSurah; final String surahName; final String ayaTangheemTypeId; final GlobalKey globalKey; final List voiceNoteList; - AyaPlayerWidget({Key key, this.surahName, this.ayaTangheemTypeId, this.voiceNoteList, this.ayaNo, this.surahNo, @required this.globalKey}) : super(key: key); + AyaPlayerWidget({Key key, this.surahName, this.ayaTangheemTypeId, this.voiceNoteList, this.ayaNo, this.numberInSurah, this.surahNo, @required this.globalKey}) : super(key: key); @override _AyaPlayerWidgetState createState() { @@ -210,33 +207,6 @@ class _AyaPlayerWidgetState extends State { Utils.showToast("يجب اعطاء الاذن لتنزيل الآية"); } }), - PopupMenuButton( - child: commonIconButton("assets/icons/share_aya.svg", null), - padding: EdgeInsets.fromLTRB(4, 4, 0, 4), - itemBuilder: (_) => >[ - PopupMenuItem( - value: 1, - child: Text( - "مشاركة رابط", - style: TextStyle(color: ColorConsts.primaryBlack), - ), - ), - PopupMenuItem( - value: 2, - child: Text( - "مشاركة صورة", - style: TextStyle(color: ColorConsts.primaryBlack), - ), - ) - ], - onSelected: (int value) { - if (value == 1) { - _shareAyaAsLink(); - } else { - _shareAyaAsImage(); - } - }, - ) ], ), SizedBox(height: 8), @@ -364,30 +334,4 @@ class _AyaPlayerWidgetState extends State { return false; } } - - void _shareAyaAsLink() async { - String _url = "${ApiConsts.baseUrl}/quran/tangheemtype?surahNo=${widget.surahNo}&ayahNo=${widget.ayaNo}&tanghemType=${widget.ayaTangheemTypeId}"; - await Share.share(_url); - } - - void _shareAyaAsImage() async { - Utils.showLoading(context); - try { - RenderRepaintBoundary boundary = widget.globalKey.currentContext.findRenderObject(); - ui.Image image = await boundary.toImage(pixelRatio: 3.0); - ByteData byteData = await image.toByteData(format: ui.ImageByteFormat.png); - Uint8List pngBytes = byteData.buffer.asUint8List(); - - final tempDir = await getTemporaryDirectory(); - final file = await File('${tempDir.path}/${DateTime.now().toString()}.png').create(); - await file.writeAsBytes(pngBytes); - await TangheemUserApiClient().addStatistics(3); - await Share.shareFiles(['${file.path}']); - Utils.hideLoading(context); - } catch (ex) { - Future.delayed(Duration(seconds: 1), () { - Utils.hideLoading(context); - }); - } - } } diff --git a/lib/widgets/text_highlight_widget.dart b/lib/widgets/text_highlight_widget.dart index 614be39..04b994d 100644 --- a/lib/widgets/text_highlight_widget.dart +++ b/lib/widgets/text_highlight_widget.dart @@ -1,5 +1,3 @@ -import 'dart:math'; - import 'package:flutter/material.dart'; import 'package:tangheem/classes/colors.dart'; import 'package:tangheem/models/aya_tangheem_type_mapped.dart'; @@ -12,6 +10,7 @@ class TextHighLightLengthWidget extends StatelessWidget { final String highlightAyaNos; final String highlightAya; final List ayahTextList; + final double fontSize; final Color highLightColor; TextHighLightLengthWidget({ @@ -23,12 +22,13 @@ class TextHighLightLengthWidget extends StatelessWidget { this.highlightAyaNos = "", this.highlightAya = "", this.ayahTextList, + this.fontSize = 18, this.highLightColor = ColorConsts.secondaryOrange, }) : super(key: key); TextStyle textStyle = TextStyle( fontFamily: "UthmanicHafs", - fontSize: 16, + fontSize: 18, color: ColorConsts.primaryBlue, fontWeight: FontWeight.bold, ); @@ -57,6 +57,9 @@ class TextHighLightLengthWidget extends StatelessWidget { } } // print("startIndex:$startIndex"); + if (startIndex < 0) { + startIndex = 0; + } if (actualStartIndex != 0) { startIndex = actualStartIndex + startIndex; } @@ -82,14 +85,14 @@ class TextHighLightLengthWidget extends StatelessWidget { TextSpan _normalText(String text) { return TextSpan( text: text, - style: textStyle, + style: textStyle.copyWith(fontSize: fontSize), ); } TextSpan _highlightText(String text) { return TextSpan( text: text, - style: textStyle.copyWith(color: highLightColor), + style: textStyle.copyWith(color: highLightColor, fontSize: fontSize), ); } diff --git a/pubspec.yaml b/pubspec.yaml index 743e483..0b21189 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -34,7 +34,7 @@ dependencies: path_provider: ^2.0.1 permission_handler: ^6.1.1 share: ^2.0.4 - just_audio: ^0.7.2 + just_audio: ^0.9.24 intl: ^0.17.0 shared_preferences: ^2.0.5 url_launcher: ^6.0.3