diff --git a/android/app/build.gradle b/android/app/build.gradle index 669d9d6..7cf5766 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -39,10 +39,11 @@ android { defaultConfig { // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). applicationId "com.cloudsolutions.tangheem" - minSdkVersion 16 + minSdkVersion 19 targetSdkVersion 29 versionCode flutterVersionCode.toInteger() versionName flutterVersionName + multiDexEnabled true } buildTypes { diff --git a/assets/fonts/B-Arabics.ttf b/assets/fonts/B-Arabics.ttf new file mode 100644 index 0000000..c44adaa Binary files /dev/null and b/assets/fonts/B-Arabics.ttf differ diff --git a/lib/api/authentication_api_client.dart b/lib/api/authentication_api_client.dart index a390c40..0644747 100644 --- a/lib/api/authentication_api_client.dart +++ b/lib/api/authentication_api_client.dart @@ -11,7 +11,7 @@ class AuthenticationApiClient { factory AuthenticationApiClient() => _instance; Future authenticateUser(String email, String password) async { - String url = "${ApiConsts.authentication}Login"; + String url = "${ApiConsts.authentication}MobileLogin"; var postParams = {"email": email, "password": password}; return await ApiClient().postJsonForObject((json) => AuthenticationUserModel.fromJson(json), url, postParams); } diff --git a/lib/api/tangheem_user_api_client.dart b/lib/api/tangheem_user_api_client.dart index b3252f0..02e2e6c 100644 --- a/lib/api/tangheem_user_api_client.dart +++ b/lib/api/tangheem_user_api_client.dart @@ -60,6 +60,12 @@ class TangheemUserApiClient { return await ApiClient().postJsonForObject((json) => TangheemType.fromJson(json), url, postParams); } + Future getAyaTangheemTypeMappedRelated(int surahNo, String ayatNumberInSurahs) async { + String url = "${ApiConsts.tangheemUsers}AyatTangheemTypeMapped_Get"; + var postParams = {"surahNo": surahNo, "numberInSurahs": ayatNumberInSurahs}; + return await ApiClient().postJsonForObject((json) => AyatTangheemTypeMapped.fromJson(json), url, postParams); + } + Future getAyaTangheemTypeMapped(int surahNo, String tangheemTypeName, String ayaText, int itemsPerPage, int currentPageNo) async { String url = "${ApiConsts.tangheemUsers}AyatTangheemTypeMapped_Get"; var postParams = {}; @@ -78,9 +84,17 @@ class TangheemUserApiClient { return await ApiClient().postJsonForObject((json) => AyatTangheemTypeMapped.fromJson(json), url, postParams); } - Future getAyaTangheemType(int currentPage, int surahNo, String tangheemTypeName) async { + Future getAyaTangheemType(int surahNo, String tangheemTypeName) async { String url = "${ApiConsts.tangheemUsers}AyaTangheemType_Get"; - var postParams = {"itemsPerPage": 5, "currentPageNo": currentPage, "surahNo": surahNo, "tangheemTypeName": tangheemTypeName}; + + var postParams = {}; + if (surahNo != null) { + postParams["surahNo"] = surahNo; + } + if (tangheemTypeName != null) { + postParams["tangheemTypeName"] = tangheemTypeName; + } + return await ApiClient().postJsonForObject((json) => AyaTangheemType.fromJson(json), url, postParams); } diff --git a/lib/api/user_api_client.dart b/lib/api/user_api_client.dart index 858cb3f..80c638b 100644 --- a/lib/api/user_api_client.dart +++ b/lib/api/user_api_client.dart @@ -19,7 +19,7 @@ class UserApiClient { String _countryCode, String _phone, ) async { - String url = "${ApiConsts.user}UserRegistration_Add"; + String url = "${ApiConsts.user}MobileUserRegistration_Add"; var postParams = { "password": _password, "email": _email, @@ -53,7 +53,7 @@ class UserApiClient { } Future updatePassword(String _email, int _otp, String _password) async { - String url = "${ApiConsts.user}UpdatePassword"; + String url = "${ApiConsts.user}MobileUpdatePassword"; var postParams = {"email": _email, "opt": _otp, "newPassword": _password, "confirmPassword": _password}; return await ApiClient().postJsonForObject((json) => GeneralResponseModel.fromJson(json), url, postParams); } diff --git a/lib/classes/consts.dart b/lib/classes/consts.dart index e1f1e94..479ff60 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"; // Live server - static String baseUrlServices = baseUrl + "/services/"; // Live server + static String baseUrl = "http://20.203.25.82"; // production server + // static String baseUrlServices = baseUrl + "/services/"; // production server + static String baseUrlServices = "https://api.cssynapses.com/tangheem/"; // Live server static String authentication = baseUrlServices + "api/Authentication/"; static String tangheemUsers = baseUrlServices + "api/TangheemUsers/"; static String adminConfiguration = baseUrlServices + "api/AdminConfiguration/"; @@ -14,4 +15,6 @@ class GlobalConsts { static String password = "password"; static String bookmark = "bookmark"; static String fontZoomSize = "font_zoom_size"; + static String welcomeVideoUrl = "welcomeVideoUrl"; + static String doNotShowWelcomeVideo = "doNotShowWelcomeVideo"; } diff --git a/lib/extensions/string_extensions.dart b/lib/extensions/string_extensions.dart index b56d98b..a565faa 100644 --- a/lib/extensions/string_extensions.dart +++ b/lib/extensions/string_extensions.dart @@ -6,9 +6,38 @@ extension EmailValidator on String { } String toFormattedDate() { - DateFormat inputFormat = DateFormat('yyyy-mm-ddThh:mm:ss'); - DateTime inputDate = inputFormat.parse(this); - DateFormat outputFormat = DateFormat('DD MMMM yyyy hh:mm a'); - return outputFormat.format(inputDate); + String date = this.split("T")[0]; + String time = this.split("T")[1]; + var dates = date.split("-"); + return "${dates[2]} ${getMonth(int.parse(dates[1]))} ${dates[0]} ${DateFormat('hh:mm a').format(DateFormat('hh:mm:ss').parse(time))}"; + } + + getMonth(int month) { + switch (month) { + case 1: + return "January"; + case 2: + return "February"; + case 3: + return "March"; + case 4: + return "April"; + case 5: + return "May"; + case 6: + return "June"; + case 7: + return "July"; + case 8: + return "August"; + case 9: + return "September"; + case 10: + return "October"; + case 11: + return "November"; + case 12: + return "December"; + } } } diff --git a/lib/main.dart b/lib/main.dart index a515c78..1ba33e8 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -63,8 +63,11 @@ class Application extends StatelessWidget { case MemberScreen.routeName: className = CommonAppbar(child: MemberScreen()); break; + case PdfListScreen.routeName: + className = CommonAppbar(child: PdfListScreen()); + break; case PdfViewerScreen.routeName: - className = CommonAppbar(child: PdfViewerScreen()); + className = CommonAppbar(child: PdfViewerScreen(settings.arguments)); break; case ContentInfoScreen.routeName: var index = settings.arguments; @@ -97,11 +100,12 @@ class Application extends StatelessWidget { eventName = eventName.replaceAll("/", ""); if (eventName.isEmpty) eventName = "home"; try { - analytics.setCurrentScreen( - screenName: eventName, - screenClassOverride: eventName, - ).then((value) => print("EventSent:$eventName")); - + analytics + .setCurrentScreen( + screenName: eventName, + screenClassOverride: eventName, + ) + .then((value) => print("EventSent:$eventName")); } catch (ex) { print("Analytics:$ex"); } diff --git a/lib/models/aya_tangheem_type_mapped.dart b/lib/models/aya_tangheem_type_mapped.dart index 21e86f6..3e7691c 100644 --- a/lib/models/aya_tangheem_type_mapped.dart +++ b/lib/models/aya_tangheem_type_mapped.dart @@ -44,6 +44,8 @@ class AyatTangheemTypeMappedData { String highlightText; String userId; String ayahTextBase; + String ayahNos; + String ayatNumberInSurahs; List property; List voiceNote; @@ -61,6 +63,8 @@ class AyatTangheemTypeMappedData { this.highlightText, this.userId, this.ayahTextBase, + this.ayahNos, + this.ayatNumberInSurahs, this.property, this.voiceNote}); @@ -78,6 +82,8 @@ class AyatTangheemTypeMappedData { highlightText = json['highlightText']; userId = json['userId']; ayahTextBase = json['ayahTextBase']; + ayahNos = json['ayahNos']; + ayatNumberInSurahs = json['ayatNumberInSurahs']; if (json['property'] != null) { property = []; json['property'].forEach((v) { @@ -107,6 +113,8 @@ class AyatTangheemTypeMappedData { data['highlightText'] = this.highlightText; data['userId'] = this.userId; data['ayahTextBase'] = this.ayahTextBase; + data['ayahNos'] = this.ayahNos; + data['ayatNumberInSurahs'] = this.ayatNumberInSurahs; if (this.property != null) { data['property'] = this.property.map((v) => v.toJson()).toList(); } @@ -133,7 +141,7 @@ class TangheemProperty { String ayaTangheemTypePropertyId; String propertyValue; - TangheemProperty({this.tangheemTypePropertyId, this.propertyText, this.isInsideTable, this.textColor,this.orderNo, this.ayaTangheemTypePropertyId, this.propertyValue}); + TangheemProperty({this.tangheemTypePropertyId, this.propertyText, this.isInsideTable, this.textColor, this.orderNo, this.ayaTangheemTypePropertyId, this.propertyValue}); TangheemProperty.fromJson(Map json) { tangheemTypePropertyId = json['tangheemTypePropertyId']; diff --git a/lib/models/tangheem_type_model.dart b/lib/models/tangheem_type_model.dart index 8b4cb72..26f4ade 100644 --- a/lib/models/tangheem_type_model.dart +++ b/lib/models/tangheem_type_model.dart @@ -34,6 +34,9 @@ class TangheemTypeData { String tangheemTypeId; String tangheemTypeName; bool isActive; + int orderNo; + String tangheemTypeDescription; + int numberOfAyaTangheemType; TangheemTypeData({this.tangheemTypeId, this.tangheemTypeName, this.isActive}); @@ -41,6 +44,9 @@ class TangheemTypeData { tangheemTypeId = json['tangheemTypeId']; tangheemTypeName = json['tangheemTypeName']; isActive = json['isActive']; + orderNo = json['orderNo']; + tangheemTypeDescription = json['tangheemTypeDescription']; + numberOfAyaTangheemType = json['numberOfAyaTangheemType']; } Map toJson() { @@ -48,6 +54,9 @@ class TangheemTypeData { data['tangheemTypeId'] = this.tangheemTypeId; data['tangheemTypeName'] = this.tangheemTypeName; data['isActive'] = this.isActive; + data['orderNo'] = this.orderNo; + data['tangheemTypeDescription'] = this.tangheemTypeDescription; + data['numberOfAyaTangheemType'] = this.numberOfAyaTangheemType; return data; } } diff --git a/lib/ui/common_appbar.dart b/lib/ui/common_appbar.dart index 74867ef..93343d1 100644 --- a/lib/ui/common_appbar.dart +++ b/lib/ui/common_appbar.dart @@ -6,12 +6,12 @@ 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/content_info_model.dart'; import 'package:tangheem/models/navigation_model.dart'; import 'package:tangheem/models/quick_links_model.dart'; import 'package:tangheem/ui/screens/bookmark_screen.dart'; import 'package:tangheem/ui/screens/content_info_screen.dart'; import 'package:tangheem/ui/screens/login_screen.dart'; +import 'package:tangheem/ui/screens/pdf_viewer_screen.dart'; import 'package:url_launcher/url_launcher.dart'; class CommonAppbar extends StatefulWidget { @@ -198,6 +198,9 @@ class _CommonAppbarState extends State { } else if (subItem.mobileNavigationUrl == "/encyclopedia") { url = ContentInfoScreen.routeName; contentId = 1; + } else if (subItem.mobileNavigationUrl == "/tangheempdf") { + url = PdfListScreen.routeName; + contentId = 8; } Navigator.pushNamed(context, url, arguments: contentId); }), @@ -274,7 +277,8 @@ class _CommonAppbarState extends State { child: Row( children: [ for (QuickLinksData _quickLink in quickLinks) - commonIconButton(ApiConsts.baseUrl + _quickLink.exposeFilePath, () { + // commonIconButton(ApiConsts.baseUrl + _quickLink.exposeFilePath, () { for live produciton server + commonIconButton( _quickLink.exposeFilePath, () { _launchURL(_quickLink.imageUrl); }, size: 35, isAsset: false), ], diff --git a/lib/ui/screens/bookmark_screen.dart b/lib/ui/screens/bookmark_screen.dart index 3d5379c..b449898 100644 --- a/lib/ui/screens/bookmark_screen.dart +++ b/lib/ui/screens/bookmark_screen.dart @@ -99,7 +99,7 @@ class _BookmarkScreenState extends State { ), Text( " ${_bookMarkList[index].numberInSurah}", - style: TextStyle(fontSize: 14, color: ColorConsts.secondaryOrange), + style: TextStyle(fontSize: 14, fontFamily: "BArabics", color: ColorConsts.secondaryOrange), ), ], ), diff --git a/lib/ui/screens/home_screen.dart b/lib/ui/screens/home_screen.dart index a4b456f..73abdc8 100644 --- a/lib/ui/screens/home_screen.dart +++ b/lib/ui/screens/home_screen.dart @@ -4,20 +4,25 @@ import 'package:flutter/material.dart'; import 'package:flutter/painting.dart'; import 'package:flutter/services.dart'; import 'package:flutter_svg/flutter_svg.dart'; +import 'package:shared_preferences/shared_preferences.dart'; import 'package:tangheem/api/tangheem_user_api_client.dart'; 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/aya_tangheem_type.dart'; import 'package:tangheem/models/content_info_model.dart'; import 'package:tangheem/models/surah_model.dart'; import 'package:tangheem/models/tangheem_type_model.dart'; import 'package:tangheem/ui/dialogs/general_dialog.dart'; import 'package:tangheem/ui/screens/tangheem_screen.dart'; import 'package:tangheem/widgets/common_dropdown_button.dart'; +import 'package:tangheem/widgets/video_player_widget.dart'; class HomeScreen extends StatefulWidget { static const String routeName = "/"; final FirebaseAnalytics analytics; + HomeScreen(this.analytics, {Key key}) : super(key: key); @override @@ -68,22 +73,94 @@ class _HomeScreenState extends State { checkScreenMode(); } + void filterTangheemTypesListBySurah(int surahNo, {bool showLoading = true}) async { + if (showLoading) Utils.showLoading(context); + try { + AyaTangheemType ayaTangheemType = await TangheemUserApiClient().getAyaTangheemType(surahNo, null); + + var tangheemType = _tangheemType?.data?.where((element) => element.isActive)?.toList() ?? []; + var ayaTangheem = ayaTangheemType?.data?.where((element) => element.isActive)?.toList() ?? []; + var result = tangheemType.where((tangheem) => ayaTangheem.any((element) => tangheem.tangheemTypeId == element.tangheemTypeId)).toList() ?? []; + _tangheemListNotifier.value = result?.map((element) => element.tangheemTypeName)?.toList() ?? []; + if (showLoading) Utils.hideLoading(context); + } catch (ex) { + if (showLoading) Utils.hideLoading(context); + Utils.handleException(ex, null); + } + } + + void filterSurahListByTangheemType(String tangheemName) async { + Utils.showLoading(context); + try { + AyaTangheemType ayaTangheemType = await TangheemUserApiClient().getAyaTangheemType(null, tangheemName); + _surahList = _surahModel.data.where((surah) => ayaTangheemType.data.any((element) => surah.id == element.surahNo)).toList().map((element) => element.nameAR).toList(); + setState(() {}); + Utils.hideLoading(context); + } catch (ex) { + Utils.hideLoading(context); + Utils.handleException(ex, null); + } + } + void checkScreenMode() { - WidgetsBinding.instance.addPostFrameCallback((_) { + WidgetsBinding.instance.addPostFrameCallback((_) async { if (MediaQuery.of(context).orientation == Orientation.portrait) { - showDialog( + await showDialog( context: context, barrierColor: ColorConsts.secondaryWhite.withOpacity(0.8), builder: (BuildContext context) => GeneralDialog(), ); } + showWelcomeVideoDialog(); }); } + SharedPreferences prefs; + + void showWelcomeVideoDialog() async { + prefs = await SharedPreferences.getInstance(); + String permLink = "aAmP-WcI6dg"; + String link = prefs.getString(GlobalConsts.welcomeVideoUrl) ?? permLink; + if (permLink == link) { + await prefs.setString(GlobalConsts.welcomeVideoUrl, permLink); + bool showDialog = prefs.getBool(GlobalConsts.doNotShowWelcomeVideo) ?? false; + if (showDialog) { + return; + } + } else { + await prefs.setString(GlobalConsts.welcomeVideoUrl, permLink); + } + await prefs.setBool(GlobalConsts.doNotShowWelcomeVideo, false); + showDialog( + context: context, + barrierColor: ColorConsts.secondaryWhite.withOpacity(0.8), + builder: (BuildContext context) => VideoPlayerWidget(permLink), + ); + } + Future getTangheemTypes() async { try { _tangheemType = await TangheemUserApiClient().getTangheemType(); + if ((_tangheemType?.data?.length ?? 0) > 0) { + _tangheemType.data.sort((a, b) => a.orderNo.compareTo(b.orderNo)); + } _tangheemListNotifier.value = _tangheemType?.data?.where((element) => element.isActive)?.toList()?.map((element) => element.tangheemTypeName)?.toList() ?? []; + return; + + // enable these lines if in future need to filter types too + if (_surahModel.data.map((element) => element.nameAR).toList().length == _surahList.length && _selectedSurah >= 0) { + setState(() { + _selectedTangheemType = -1; + }); + // filterTangheemTypesListBySurah(_surahModel.data[_selectedSurah].id, showLoading: false); + } else { + if (_surahModel.data.map((element) => element.nameAR).toList().length != _surahList.length && _selectedSurah >= 0) { + setState(() { + _selectedSurah = -1; + }); + } + _tangheemListNotifier.value = _tangheemType?.data?.where((element) => element.isActive)?.toList()?.map((element) => element.tangheemTypeName)?.toList() ?? []; + } } catch (ex) {} } @@ -126,9 +203,14 @@ class _HomeScreenState extends State { builder: (context, value, child) { return CommonDropDownButton(_selectedTangheemType, hintText: "اختر الأسلوب اللغوي", list: value, onSelect: (index) { if (_selectedTangheemType != index) { - setState(() { + setState((){ + _selectedSurah = -1; _selectedTangheemType = index; }); + if (_selectedSurah >= 0) { + return; + } + filterSurahListByTangheemType(_tangheemListNotifier.value[_selectedTangheemType]); } }); }, @@ -141,64 +223,64 @@ class _HomeScreenState extends State { setState(() { _selectedSurah = index; }); + if (_selectedTangheemType >= 0) { + return; + } + // filterTangheemTypesListBySurah(_surahModel.data[_selectedSurah].id); } }), ) ], ), SizedBox(height: 16), - InkWell( - 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": _tangheemListNotifier.value[_selectedTangheemType], "surahData": _surahModel.data[_selectedSurah]}; - try { - await widget.analytics.logEvent( - name: 'tangheem_by_selection', - parameters: { - "tangheemTypeName": _tangheemListNotifier.value[_selectedTangheemType], - "surahName": _surahModel.data[_selectedSurah].nameAR, - }, - ); - } catch (ex) { - print("tangheemTypeName:$ex"); - } - await Navigator.pushNamed(context, TangheemScreen.routeName, arguments: data); - _searchFocusNode.canRequestFocus = true; - getTangheemTypes(); - }, - child: Container( - height: 36, - decoration: BoxDecoration( - color: ColorConsts.secondaryPink, - borderRadius: BorderRadius.circular(6), - ), - padding: EdgeInsets.fromLTRB(8, 2, 8, 2), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisSize: MainAxisSize.min, - children: [ - Text( - "بحث", - maxLines: 1, - style: TextStyle(fontSize: 12, color: Colors.white), - ), - SizedBox(width: 12), - SvgPicture.asset("assets/icons/go_forward.svg", width: 20, height: 20, color: Colors.white), - ], - ), - ), + Row( + children: [ + iconButton("بحث", "assets/icons/go_forward.svg", () async { + // if (_selectedTangheemType < 0) { + // Utils.showToast("الرجائ تعبئة جميع القوائم"); + // return; + // } + if (_selectedSurah < 0) { + Utils.showToast("يرجى اختيار السورة"); + return; + } + _searchFocusNode.unfocus(); + _searchFocusNode.canRequestFocus = false; + var surah = _surahModel.data.firstWhere((surah) => surah.nameAR == _surahList[_selectedSurah], orElse: null); + Map data = {}; + data["surahData"] = surah; + if (_selectedTangheemType >= 0) { + data["tangheemTypeName"] = _tangheemListNotifier.value[_selectedTangheemType].toString(); + } + try { + await widget.analytics.logEvent( + name: 'tangheem_by_selection', + parameters: { + "tangheemTypeName": _tangheemListNotifier.value[_selectedTangheemType], + "surahName": _surahModel.data[_selectedSurah].nameAR, + }, + ); + } catch (ex) { + print("tangheemTypeName:$ex"); + } + await Navigator.pushNamed(context, TangheemScreen.routeName, arguments: data); + _searchFocusNode.canRequestFocus = true; + await getTangheemTypes(); + }), + SizedBox(width: 8), + iconButton( + "إلغاء", + "assets/icons/cancel.svg", + (_selectedSurah == -1 && _selectedTangheemType == -1) + ? null + : () { + _selectedSurah = -1; + _selectedTangheemType = -1; + _surahList = _surahModel.data.map((element) => element.nameAR).toList(); + _tangheemListNotifier.value = _tangheemType?.data?.where((element) => element.isActive)?.toList()?.map((element) => element.tangheemTypeName)?.toList() ?? []; + setState(() {}); + }), + ], ), SizedBox(height: 16), Container( @@ -236,7 +318,7 @@ class _HomeScreenState extends State { ); await Navigator.pushNamed(context, TangheemScreen.routeName, arguments: data); _searchFocusNode.canRequestFocus = true; - getTangheemTypes(); + await getTangheemTypes(); }, splashColor: Colors.transparent, highlightColor: Colors.transparent, @@ -265,4 +347,34 @@ class _HomeScreenState extends State { ), ); } + + Widget iconButton(String title, String icon, VoidCallback callback) { + return InkWell( + splashColor: Colors.transparent, + highlightColor: Colors.transparent, + onTap: callback, + child: Container( + height: 36, + decoration: BoxDecoration( + color: callback == null ? ColorConsts.textHintGrey : ColorConsts.secondaryPink, + borderRadius: BorderRadius.circular(6), + ), + padding: EdgeInsets.fromLTRB(8, 2, 8, 2), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisSize: MainAxisSize.min, + children: [ + Text( + title, + maxLines: 1, + style: TextStyle(fontSize: 12, color: Colors.white), + ), + SizedBox(width: 12), + SvgPicture.asset(icon, width: 20, height: 20, color: Colors.white), + ], + ), + ), + ); + } } diff --git a/lib/ui/screens/pdf_viewer_screen.dart b/lib/ui/screens/pdf_viewer_screen.dart index 537021a..4f32035 100644 --- a/lib/ui/screens/pdf_viewer_screen.dart +++ b/lib/ui/screens/pdf_viewer_screen.dart @@ -1,10 +1,88 @@ import 'package:flutter/material.dart'; import 'package:syncfusion_flutter_pdfviewer/pdfviewer.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/models/content_info_model.dart'; +import 'package:tangheem/ui/misc/no_data_ui.dart'; -class PdfViewerScreen extends StatefulWidget { +class PdfListScreen extends StatefulWidget { static const String routeName = "/tangheem_pdf"; - PdfViewerScreen({Key key}) : super(key: key); + PdfListScreen({Key key}) : super(key: key); + + @override + _PdfListScreenState createState() { + return _PdfListScreenState(); + } +} + +class _PdfListScreenState extends State { + List contentList; + + @override + void initState() { + super.initState(); + getPdfs(); + } + + void getPdfs() async { + Utils.showLoading(context); + try { + var membersData = await TangheemUserApiClient().getContentInfo(8); + contentList = membersData?.data ?? []; + } catch (ex) { + contentList = []; + Utils.handleException(ex, null); + } finally { + Utils.hideLoading(context); + } + setState(() {}); + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return contentList == null + ? SizedBox() + : contentList.isEmpty + ? NoDataUI() + : ListView.separated( + physics: BouncingScrollPhysics(), + padding: EdgeInsets.all(16), + itemCount: contentList.length, + separatorBuilder: (context, index) { + return SizedBox(height: 8); + }, + itemBuilder: (context, index) { + return ListTile( + tileColor: Colors.white, + onTap: () { + Navigator.pushNamed(context, PdfViewerScreen.routeName, arguments: contentList[index]); + }, + title: Text( + contentList[index].fileName?.trim() ?? "", + style: TextStyle(fontSize: 14, color: ColorConsts.primaryBlue), + ), + subtitle: Text( + contentList[index].contentTypeNameAr?.trim() ?? "", + style: TextStyle(fontSize: 12, color: ColorConsts.primaryBlue), + ), + ); + }, + ); + } +} + +class PdfViewerScreen extends StatefulWidget { + static const String routeName = "/tangheem_pdf_view"; + final ContentInfoDataModel pdfDetail; + + PdfViewerScreen(this.pdfDetail, {Key key}) : super(key: key); @override _PdfViewerScreenState createState() { @@ -27,8 +105,8 @@ class _PdfViewerScreenState extends State { @override Widget build(BuildContext context) { - return SfPdfViewer.asset( - 'assets/files/tangheem.pdf', + return SfPdfViewer.network( + widget.pdfDetail.exposeFilePath, key: _pdfViewerKey, canShowScrollHead: false, enableTextSelection: false, diff --git a/lib/ui/screens/quran_screen.dart b/lib/ui/screens/quran_screen.dart index 2d1efca..0089768 100644 --- a/lib/ui/screens/quran_screen.dart +++ b/lib/ui/screens/quran_screen.dart @@ -85,7 +85,7 @@ class _QuranScreenState extends State { } setState(() {}); getQuranByPageNo(); - getTangheemBySurahId(); + // getTangheemBySurahId(); } List _bookMark = []; @@ -111,7 +111,7 @@ class _QuranScreenState extends State { setState(() {}); } - void getTangheemBySurahId() async { + Future getTangheemBySurahId() async { try { _ayatTangheemTypeMapped = await TangheemUserApiClient().getTangheemBySurah(_selectedSurah + 1); _tangheemWords = _ayatTangheemTypeMapped?.data?.map((e) => e.highlightText)?.toList() ?? []; @@ -125,20 +125,22 @@ class _QuranScreenState extends State { Utils.showLoading(context); try { _ayaModel = await TangheemUserApiClient().getAyaByFilter(_selectedSurah + 1, _fromAyaList[_selectedFromAya], _toAyaList[_selectedToAya]); + await getTangheemBySurahId(); } catch (ex) { Utils.handleException(ex, null); } finally { Utils.hideLoading(context); } - getTangheemBySurahId(); + // getTangheemBySurahId(); } void getQuranByPageNo() async { Utils.showLoading(context); try { _ayaModel = await TangheemUserApiClient().getQuranByPageNo(_currentPage); + await getTangheemBySurahId(); Utils.hideLoading(context); - setState(() {}); + // setState(() {}); } catch (ex) { Utils.handleException(ex, null); Utils.hideLoading(context); @@ -322,29 +324,30 @@ class _QuranScreenState extends State { ), quranTextView, SizedBox(height: 4), - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - nextOptionButton( - "assets/icons/prev_single.svg", - "الصفحة السابقة", - _currentPage <= 1 - ? null - : (value) { - _currentPage = _currentPage - 1; - _clearFilterAndRefreshData(); - }), - previousOptionButton( - "assets/icons/next_single.svg", - "الصفحة التالية", - _currentPage == 604 - ? null - : (value) { - _currentPage = _currentPage + 1; - _clearFilterAndRefreshData(); - }), - ], - ), + if (_selectedFromAya == -1 && _selectedToAya == -1) + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + nextOptionButton( + "assets/icons/prev_single.svg", + "الصفحة السابقة", + _currentPage <= 1 + ? null + : (value) { + _currentPage = _currentPage - 1; + _clearFilterAndRefreshData(); + }), + previousOptionButton( + "assets/icons/next_single.svg", + "الصفحة التالية", + _currentPage == 604 + ? null + : (value) { + _currentPage = _currentPage + 1; + _clearFilterAndRefreshData(); + }), + ], + ), ], ), ); @@ -516,7 +519,7 @@ class _QuranScreenState extends State { TextSpan( text: "\n" + "$_currentPage", style: TextStyle( - fontFamily: "UthmanicHafs", + fontFamily: "BArabics", fontSize: fontSize, color: ColorConsts.primaryBlue, fontWeight: FontWeight.bold, @@ -559,8 +562,7 @@ class _QuranScreenState extends State { onTap: () async { Navigator.pop(context); List list = []; - - list = _ayatTangheemTypeMapped?.data?.where((element) => element.ayahNo == _selectedAyaForBookmark.ayahID)?.toList() ?? []; + list = _ayatTangheemTypeMapped?.data?.where((element) => int.parse(element.ayahNos.split(",")[0]) == _selectedAyaForBookmark.ayahID)?.toList() ?? []; if (list.isEmpty) { Utils.showToast("لا توجد أساليب تنغيم في هذه الآية"); return; @@ -610,5 +612,6 @@ class _QuranScreenState extends State { class TangheemTemp { final String tangheemName; final String ayaTangheemId; + TangheemTemp(this.tangheemName, this.ayaTangheemId); } diff --git a/lib/ui/screens/tangheem_detail_screen.dart b/lib/ui/screens/tangheem_detail_screen.dart index bbc4a9d..9d87935 100644 --- a/lib/ui/screens/tangheem_detail_screen.dart +++ b/lib/ui/screens/tangheem_detail_screen.dart @@ -1,5 +1,6 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_html/flutter_html.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:tangheem/api/admin_configuration_api_client.dart'; @@ -21,6 +22,7 @@ import 'login_screen.dart'; class TangheemDetailParams { final String selectedTangheemTypeId; final List ayatTangheemTypeMappedDataList; + TangheemDetailParams({@required this.selectedTangheemTypeId, @required this.ayatTangheemTypeMappedDataList}); } @@ -43,6 +45,8 @@ class _TangheemDetailScreenState extends State { List ayatTangheemTypeMappedDataList = []; + List _dataList = []; + int _discussionPage = -1; AyatTangheemTypeMappedData _ayatTangheemTypeMappedFirstData; DiscussionModel _discussionModel; @@ -52,12 +56,11 @@ class _TangheemDetailScreenState extends State { @override void initState() { super.initState(); - ayatTangheemTypeMappedDataList = widget.tangheemDetailParams.ayatTangheemTypeMappedDataList; _ayatTangheemTypeMappedFirstData = ayatTangheemTypeMappedDataList.first; filterVoiceListData(); getPrefs(); - getTangheemDiscussion(); + getTangheemDiscussionAndRelatedData(); } double fontSize = 18; @@ -85,18 +88,42 @@ class _TangheemDetailScreenState extends State { return ""; } - void getTangheemDiscussion() async { + void getTangheemDiscussionAndRelatedData() async { Utils.showLoading(context); try { _discussionModel = await TangheemUserApiClient().getDiscussionByTangheemID(_discussionPage, widget.tangheemDetailParams.selectedTangheemTypeId); + if (!_ayatTangheemTypeMappedFirstData.ayatNumberInSurahs.contains(",")) { + _dataList = await getTangheemRelatedData(); + } Utils.hideLoading(context); setState(() {}); } catch (ex) { + print(ex); Utils.handleException(ex, null); Utils.hideLoading(context); } } + Future> getTangheemRelatedData() async { + _dataList = []; + AyatTangheemTypeMapped _ayatTangheemTypeMapped = + await TangheemUserApiClient().getAyaTangheemTypeMappedRelated(_ayatTangheemTypeMappedFirstData.surahNo, _ayatTangheemTypeMappedFirstData.ayatNumberInSurahs); + _dataList = _ayatTangheemTypeMapped?.data ?? []; + if (_dataList.isNotEmpty) { + _dataList = _dataList.where((element) => element.tangheemTypeId != _ayatTangheemTypeMappedFirstData.tangheemTypeId)?.toList() ?? []; + var _tempList = _dataList.map((e) => e.tangheemTypeId).toList().toSet().toList(); + var _dataTempList = []; + _tempList.forEach((_tempElement) { + _dataTempList.add(_dataList.firstWhere((element) { + return !element.ayatNumberInSurahs.contains(",") && (element.tangheemTypeId == _tempElement); + }, orElse: null)); + }); + _dataList = _dataTempList; + } + + return _dataList; + } + void sendComment(String discussionText) async { Utils.showLoading(context); try { @@ -264,19 +291,29 @@ class _TangheemDetailScreenState extends State { SizedBox(width: 4), Expanded( child: Container( - height: 40, - padding: EdgeInsets.only(left: 4, right: 8), - alignment: Alignment.centerRight, - child: Text( - _tangheemAboveTableList[index].propertyValue, - maxLines: 1, - style: TextStyle( - color: Color( - Utils.stringToHex(_tangheemAboveTableList[index].textColor), - ), + color: ColorConsts.secondaryWhite, + padding: EdgeInsets.all(4), + child: Container( + color: Colors.white, + padding: EdgeInsets.only(left: 4, right: 8), + // alignment: Alignment.centerRight, + child: Html( + data: _tangheemAboveTableList[index]?.propertyValue ?? "", + style: { + 'html': Style(textAlign: TextAlign.left), + }, ), + + // Text( + // _tangheemAboveTableList[index].propertyValue, + // maxLines: 1, + // style: TextStyle( + // color: Color( + // Utils.stringToHex(_tangheemAboveTableList[index].textColor), + // ), + // ), + // ), ), - color: ColorConsts.secondaryWhite, ), ) ], @@ -308,6 +345,60 @@ class _TangheemDetailScreenState extends State { ), SizedBox(height: 8), discussionView(_discussionModel?.data ?? []), + if (_dataList.isNotEmpty) + Container( + margin: EdgeInsets.only(top: 8), + padding: EdgeInsets.only(bottom: 20), + width: double.infinity, + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(8), + ), + child: Column( + children: [ + Container( + height: 60, + width: double.infinity, + margin: EdgeInsets.only(bottom: 8), + alignment: Alignment.center, + decoration: BoxDecoration( + color: ColorConsts.primaryBlue, + borderRadius: BorderRadius.only( + topLeft: Radius.circular(8), + topRight: Radius.circular(8), + ), + ), + child: Text( + "قائمة الأساليب اللغوية في هذه الآية", + style: TextStyle(fontSize: 16, color: Colors.white), + ), + ), + ListView.separated( + padding: EdgeInsets.fromLTRB(4, 8, 4, 4), + shrinkWrap: true, + physics: NeverScrollableScrollPhysics(), + itemCount: _dataList.length, + separatorBuilder: (context, index) => SizedBox(height: 16), + itemBuilder: (context, index) { + return InkWell( + onTap: () { + List list = _dataList; + var removedData = list[index]; + list.remove(removedData); + list.insert(0, removedData); + TangheemDetailParams tangheem = TangheemDetailParams(selectedTangheemTypeId: _dataList[index].ayaTangheemTypeId, ayatTangheemTypeMappedDataList: list); + Navigator.pushNamed(context, TangheemDetailScreen.routeName, arguments: tangheem); + }, + child: Text( + _dataList[index].tangheemTypeName, + style: TextStyle(fontWeight: FontWeight.bold, fontSize: 16, color: ColorConsts.secondaryOrange, height: 1.5), + ), + ); + }, + ), + ], + ), + ), SizedBox(height: 16), AyaRecordWidget() ], @@ -434,19 +525,28 @@ class _TangheemDetailScreenState extends State { SizedBox(width: 4), Expanded( child: Container( - height: 40, - padding: EdgeInsets.only(left: 4, right: 8), - alignment: Alignment.centerRight, - child: Text( - tangheemPropertyList[index].propertyValue, - maxLines: 1, - style: TextStyle( - color: Color( - Utils.stringToHex(tangheemPropertyList[index].textColor), - ), + color: ColorConsts.secondaryWhite, + padding: EdgeInsets.all(4), + child: Container( + color: Colors.white, + padding: EdgeInsets.only(left: 4, right: 8), + // alignment: Alignment.centerRight, + child: Html( + data: tangheemPropertyList[index]?.propertyValue ?? "", + style: { + 'html': Style(textAlign: TextAlign.left), + }, ), + // Text( + // tangheemPropertyList[index].propertyValue, + // maxLines: 1, + // style: TextStyle( + // color: Color( + // Utils.stringToHex(tangheemPropertyList[index].textColor), + // ), + // ), + // ), ), - color: ColorConsts.secondaryWhite, ), ) ], @@ -473,32 +573,41 @@ class _TangheemDetailScreenState extends State { children: [ Container( color: ColorConsts.secondaryWhite, - height: 30, - alignment: Alignment.centerRight, + //height: 30, + alignment: Alignment.center, padding: EdgeInsets.only(left: 2, right: 4), width: double.infinity, child: Text( property.propertyText ?? "", - maxLines: 1, + // maxLines: 1, style: TextStyle(fontWeight: FontWeight.bold, fontSize: 12, color: ColorConsts.secondaryOrange), ), ), Container(width: double.infinity, height: 4, color: Colors.white), Container( color: ColorConsts.secondaryWhite, - height: 30, - padding: EdgeInsets.only(left: 2, right: 4), - alignment: Alignment.centerRight, - width: double.infinity, - child: Text( - property.propertyValue ?? "", - maxLines: 1, - style: TextStyle( - fontSize: 12, - color: Color( - Utils.stringToHex(property.textColor), - ), + padding: EdgeInsets.all(4), + child: Container( + color: Colors.white, + padding: EdgeInsets.only(left: 2, right: 4), + width: double.infinity, + child: Html( + data: property.propertyValue ?? "", + style: { + 'html': Style(textAlign: TextAlign.left), + }, ), + + // Text( + // property.propertyValue ?? "", + // maxLines: 1, + // style: TextStyle( + // fontSize: 12, + // color: Color( + // Utils.stringToHex(property.textColor), + // ), + // ), + // ), ), ), ], @@ -553,6 +662,7 @@ class _TangheemDetailScreenState extends State { } Widget discussionView(List _discussionList) { + _discussionList = _discussionList.where((element) => element.status.toLowerCase() == "Accept".toLowerCase()).toList(); return Stack( alignment: Alignment.bottomCenter, children: [ @@ -589,7 +699,7 @@ class _TangheemDetailScreenState extends State { mainAxisAlignment: MainAxisAlignment.center, children: [ Text( - "تعليق على الآية ${_ayatTangheemTypeMappedFirstData.ayatNumberInSurah}", + "تعليق على الآية ${_ayatTangheemTypeMappedFirstData.ayatNumberInSurahs}", style: TextStyle(fontWeight: FontWeight.bold, fontSize: 16, color: ColorConsts.primaryBlue, height: 1.5), ), SizedBox(height: 4), diff --git a/lib/ui/screens/tangheem_screen.dart b/lib/ui/screens/tangheem_screen.dart index 194b4d8..bd3d5fd 100644 --- a/lib/ui/screens/tangheem_screen.dart +++ b/lib/ui/screens/tangheem_screen.dart @@ -85,9 +85,12 @@ class _TangheemScreenState extends State { itemBuilder: (context, index) { return InkWell( onTap: () { - List list = []; - list = _dataList?.where((element) => (element.ayahNo == _dataList[index].ayahNo) && (element.tangheemTypeId == _dataList[index].tangheemTypeId))?.toList() ?? []; - TangheemDetailParams tangheem = TangheemDetailParams(selectedTangheemTypeId: _dataList[index].ayaTangheemTypeId, ayatTangheemTypeMappedDataList: list); + List list = [] + _dataList; + var removedData = _dataList[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: removedData.ayaTangheemTypeId, ayatTangheemTypeMappedDataList: list); Navigator.pushNamed(context, TangheemDetailScreen.routeName, arguments: tangheem); }, borderRadius: BorderRadius.circular(4), @@ -110,8 +113,8 @@ class _TangheemScreenState extends State { style: TextStyle(fontSize: 12, color: ColorConsts.primaryBlue), ), Text( - " ${_dataList[index].ayatNumberInSurah}", - style: TextStyle(fontSize: 14, color: ColorConsts.secondaryOrange), + " ${_dataList[index].ayatNumberInSurahs.split(",").toList().reversed.join(",")}", + style: TextStyle(fontSize: 14, fontFamily: "BArabics", color: ColorConsts.secondaryOrange), ), ], ), diff --git a/lib/widgets/aya_player_widget.dart b/lib/widgets/aya_player_widget.dart index c9f248c..05c8638 100644 --- a/lib/widgets/aya_player_widget.dart +++ b/lib/widgets/aya_player_widget.dart @@ -85,12 +85,12 @@ class _AyaPlayerWidgetState extends State { if (_tempIndex == null || _tempIndex != index) { _tempIndex = index; String encodedImage = widget.voiceNoteList.elementAt(index).profilePicture; - if (encodedImage.contains("data:image/png;base64,")) { + if (encodedImage?.contains("data:image/png;base64,") ?? false) { encodedImage = encodedImage.replaceAll("data:image/png;base64,", ""); - } + } if (encodedImage == null) return null; temp = base64Decode(encodedImage); } - + if (temp == null) return null; return DecorationImage( fit: BoxFit.cover, image: MemoryImage(temp), @@ -139,35 +139,36 @@ class _AyaPlayerWidgetState extends State { }); }, ), - StreamBuilder( - stream: _player.currentIndexStream, - builder: (context, snapshot) { - int state = snapshot.data; - if (state == null) return SizedBox(); - return Container( - width: 50.0, - margin: EdgeInsets.only(left: 8, right: 8), - height: 50.0, - decoration: BoxDecoration( - image: widget.voiceNoteList.length < 1 ? null : getDecodedImage(state), - borderRadius: BorderRadius.all( - Radius.circular(30.0), + if ((widget.voiceNoteList?.length ?? 0) > 0) + StreamBuilder( + stream: _player.currentIndexStream, + builder: (context, snapshot) { + int state = snapshot.data; + if (state == null) return SizedBox(); + return Container( + width: 50.0, + margin: EdgeInsets.only(left: 8, right: 8), + height: 50.0, + decoration: BoxDecoration( + image: widget.voiceNoteList.length < 1 ? null : getDecodedImage(state), + borderRadius: BorderRadius.all( + Radius.circular(30.0), + ), ), - ), - child: widget.voiceNoteList.length < 1 - ? ClipRRect( - borderRadius: BorderRadius.all( - Radius.circular(30.0), - ), - child: SvgPicture.asset( - "assets/icons/chat_user.svg", - clipBehavior: Clip.antiAlias, - ), - ) - : null, - ); - }, - ), + child: widget.voiceNoteList.length < 1 + ? ClipRRect( + borderRadius: BorderRadius.all( + Radius.circular(30.0), + ), + child: SvgPicture.asset( + "assets/icons/chat_user.svg", + clipBehavior: Clip.antiAlias, + ), + ) + : null, + ); + }, + ), Expanded( child: Column( mainAxisSize: MainAxisSize.min, @@ -180,16 +181,17 @@ class _AyaPlayerWidgetState extends State { style: TextStyle(fontWeight: FontWeight.bold, fontSize: 14, color: ColorConsts.primaryBlack, height: 1), ), SizedBox(height: 4), - StreamBuilder( - stream: _player.currentIndexStream, - builder: (context, snapshot) { - final state = snapshot.data; - return Text( - (state == null || widget.voiceNoteList.isEmpty) ? "" : widget.voiceNoteList?.elementAt(state)?.userName ?? "", - style: TextStyle(fontSize: 10, color: ColorConsts.textGrey1, height: 1), - ); - }, - ), + if ((widget.voiceNoteList?.length ?? 0) > 0) + StreamBuilder( + stream: _player.currentIndexStream, + builder: (context, snapshot) { + final state = snapshot.data; + return Text( + (state == null || widget.voiceNoteList.isEmpty) ? "" : widget.voiceNoteList?.elementAt(state)?.userName ?? "", + style: TextStyle(fontSize: 10, color: ColorConsts.textGrey1, height: 1), + ); + }, + ), ], ), ), @@ -234,80 +236,81 @@ class _AyaPlayerWidgetState extends State { ], ), SizedBox(height: 8), - Row( - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - commonIconButton("assets/icons/next_aya.svg", () { - _player.seekToNext(); - }), - SizedBox(width: 4), - StreamBuilder( - stream: _player.playerStateStream, - builder: (context, snapshot) { - final state = snapshot.data?.playing ?? false; - if (state) { - if (_player?.duration?.inSeconds == _player?.position?.inSeconds) { - _player.pause(); - _player.seek(Duration.zero); + if ((widget.voiceNoteList?.length ?? 0) > 0) + Row( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + commonIconButton("assets/icons/next_aya.svg", () { + _player.seekToNext(); + }), + SizedBox(width: 4), + StreamBuilder( + stream: _player.playerStateStream, + builder: (context, snapshot) { + final state = snapshot.data?.playing ?? false; + if (state) { + if (_player?.duration?.inSeconds == _player?.position?.inSeconds) { + _player.pause(); + _player.seek(Duration.zero); + } } - } - return commonIconButton(state ? "assets/icons/pause.svg" : "assets/icons/play_aya.svg", () { - state - ? _player.pause() - : _isAudioHaveError - ? Utils.showToast("خطأ في تحميل ملف الصوت") - : _player.play(); - }); - }, - ), - SizedBox(width: 4), - commonIconButton("assets/icons/previous_aya.svg", () { - _player.seekToPrevious(); - }), - SizedBox(width: 16), - Expanded( - child: StreamBuilder( + return commonIconButton(state ? "assets/icons/pause.svg" : "assets/icons/play_aya.svg", () { + state + ? _player.pause() + : _isAudioHaveError + ? Utils.showToast("خطأ في تحميل ملف الصوت") + : _player.play(); + }); + }, + ), + SizedBox(width: 4), + commonIconButton("assets/icons/previous_aya.svg", () { + _player.seekToPrevious(); + }), + SizedBox(width: 16), + Expanded( + child: StreamBuilder( + stream: _player.positionStream, + builder: (context, snapshot) { + final state = snapshot.data; + return SliderTheme( + data: SliderTheme.of(context).copyWith( + inactiveTrackColor: ColorConsts.sliderBackground, + activeTrackColor: ColorConsts.secondaryOrange, + trackHeight: 8.0, + thumbColor: ColorConsts.primaryBlack, + thumbShape: RoundSliderThumbShape(enabledThumbRadius: 10.0), + overlayColor: ColorConsts.primaryBlack.withAlpha(32), + overlayShape: RoundSliderOverlayShape(overlayRadius: 12.0), + ), + child: Directionality( + textDirection: TextDirection.ltr, + child: Slider( + value: (state?.inSeconds ?? 0) + 0.0, + min: 0, + max: (_player?.duration?.inSeconds ?? 0) + 0.0, + onChanged: (value) { + _player.seek(Duration(seconds: value.round())); + }, + ), + ), + ); + }, + ), + ), + SizedBox(width: 8), + StreamBuilder( stream: _player.positionStream, builder: (context, snapshot) { final state = snapshot.data; - return SliderTheme( - data: SliderTheme.of(context).copyWith( - inactiveTrackColor: ColorConsts.sliderBackground, - activeTrackColor: ColorConsts.secondaryOrange, - trackHeight: 8.0, - thumbColor: ColorConsts.primaryBlack, - thumbShape: RoundSliderThumbShape(enabledThumbRadius: 10.0), - overlayColor: ColorConsts.primaryBlack.withAlpha(32), - overlayShape: RoundSliderOverlayShape(overlayRadius: 12.0), - ), - child: Directionality( - textDirection: TextDirection.ltr, - child: Slider( - value: (state?.inSeconds ?? 0) + 0.0, - min: 0, - max: (_player?.duration?.inSeconds ?? 0) + 0.0, - onChanged: (value) { - _player.seek(Duration(seconds: value.round())); - }, - ), - ), + return Text( + _durationTime(state) ?? "", + style: TextStyle(color: ColorConsts.textGrey1, height: 1.1, fontFamily: "Roboto"), ); }, ), - ), - SizedBox(width: 8), - StreamBuilder( - stream: _player.positionStream, - builder: (context, snapshot) { - final state = snapshot.data; - return Text( - _durationTime(state) ?? "", - style: TextStyle(color: ColorConsts.textGrey1, height: 1.1, fontFamily: "Roboto"), - ); - }, - ), - ], - ) + ], + ) ], ), ); diff --git a/lib/widgets/aya_record_widget.dart b/lib/widgets/aya_record_widget.dart index 3dd7ab7..9bdf9d2 100644 --- a/lib/widgets/aya_record_widget.dart +++ b/lib/widgets/aya_record_widget.dart @@ -155,84 +155,86 @@ class _AyaRecordWidgetState extends State { height: 60, ), ), - Container( - height: 50, - margin: EdgeInsets.all(16), - padding: EdgeInsets.only(left: 12, right: 12), - decoration: BoxDecoration( - color: ColorConsts.secondaryWhite, - borderRadius: BorderRadius.circular(30), - ), - child: Row( - children: [ - Expanded( - child: StreamBuilder( + if (!(recordFilePath != null && File(recordFilePath).existsSync())) SizedBox(height: 16), + if (recordFilePath != null && File(recordFilePath).existsSync()) + Container( + height: 50, + margin: EdgeInsets.all(16), + padding: EdgeInsets.only(left: 12, right: 12), + decoration: BoxDecoration( + color: ColorConsts.secondaryWhite, + borderRadius: BorderRadius.circular(30), + ), + child: Row( + children: [ + Expanded( + child: StreamBuilder( + stream: _audioPlayer.positionStream, + builder: (context, snapshot) { + final state = snapshot.data; + return SliderTheme( + data: SliderTheme.of(context).copyWith( + inactiveTrackColor: ColorConsts.sliderBackground, + activeTrackColor: ColorConsts.secondaryOrange, + trackHeight: 3.0, + thumbColor: ColorConsts.primaryBlack, + thumbShape: RoundSliderThumbShape(enabledThumbRadius: 6.0), + overlayColor: ColorConsts.primaryBlack.withAlpha(32), + overlayShape: RoundSliderOverlayShape(overlayRadius: 6.0), + ), + child: Directionality( + textDirection: TextDirection.ltr, + child: Slider( + value: (state?.inSeconds ?? 0) + 0.0, + min: 0, + max: (_audioPlayer?.duration?.inSeconds ?? 0) + 0.0, + onChanged: (value) {}, + ), + ), + ); + }, + ), + ), + SizedBox(width: 8), + StreamBuilder( stream: _audioPlayer.positionStream, builder: (context, snapshot) { final state = snapshot.data; - return SliderTheme( - data: SliderTheme.of(context).copyWith( - inactiveTrackColor: ColorConsts.sliderBackground, - activeTrackColor: ColorConsts.secondaryOrange, - trackHeight: 3.0, - thumbColor: ColorConsts.primaryBlack, - thumbShape: RoundSliderThumbShape(enabledThumbRadius: 6.0), - overlayColor: ColorConsts.primaryBlack.withAlpha(32), - overlayShape: RoundSliderOverlayShape(overlayRadius: 6.0), - ), - child: Directionality( - textDirection: TextDirection.ltr, - child: Slider( - value: (state?.inSeconds ?? 0) + 0.0, - min: 0, - max: (_audioPlayer?.duration?.inSeconds ?? 0) + 0.0, - onChanged: (value) {}, - ), - ), + return Text( + _durationTime(state) ?? "", + style: TextStyle(color: ColorConsts.textGrey1, height: 1.1, fontFamily: "Roboto", fontSize: 16), ); }, ), - ), - SizedBox(width: 8), - StreamBuilder( - stream: _audioPlayer.positionStream, - builder: (context, snapshot) { - final state = snapshot.data; - return Text( - _durationTime(state) ?? "", - style: TextStyle(color: ColorConsts.textGrey1, height: 1.1, fontFamily: "Roboto", fontSize: 16), - ); - }, - ), - SizedBox(width: 8), - StreamBuilder( - stream: _audioPlayer.playerStateStream, - builder: (context, snapshot) { - final state = snapshot.data?.playing ?? false; - if (state) { - if (_audioPlayer?.duration?.inSeconds == _audioPlayer?.position?.inSeconds) { - _audioPlayer.pause(); - _audioPlayer.seek(Duration.zero); + SizedBox(width: 8), + StreamBuilder( + stream: _audioPlayer.playerStateStream, + builder: (context, snapshot) { + final state = snapshot.data?.playing ?? false; + if (state) { + if (_audioPlayer?.duration?.inSeconds == _audioPlayer?.position?.inSeconds) { + _audioPlayer.pause(); + _audioPlayer.seek(Duration.zero); + } } - } - return IconButton( - highlightColor: Colors.transparent, - splashColor: Colors.transparent, - constraints: BoxConstraints(), - padding: EdgeInsets.only(right: 0), - icon: SvgPicture.asset(state ? "assets/icons/pause.svg" : "assets/icons/play_aya.svg", height: 16, width: 16), - onPressed: () { - state - ? _audioPlayer.pause() - : _isAudioHaveError - ? Utils.showToast("خطأ في تحميل ملف الصوت") - : play(); - }); - }, - ), - ], - ), - ) + return IconButton( + highlightColor: Colors.transparent, + splashColor: Colors.transparent, + constraints: BoxConstraints(), + padding: EdgeInsets.only(right: 0), + icon: SvgPicture.asset(state ? "assets/icons/pause.svg" : "assets/icons/play_aya.svg", height: 16, width: 16), + onPressed: () { + state + ? _audioPlayer.pause() + : _isAudioHaveError + ? Utils.showToast("خطأ في تحميل ملف الصوت") + : play(); + }); + }, + ), + ], + ), + ) ], ), ), diff --git a/lib/widgets/video_player_widget.dart b/lib/widgets/video_player_widget.dart new file mode 100644 index 0000000..e9636de --- /dev/null +++ b/lib/widgets/video_player_widget.dart @@ -0,0 +1,122 @@ +import 'package:flutter/material.dart'; +import 'package:shared_preferences/shared_preferences.dart'; +import 'package:tangheem/classes/colors.dart'; +import 'package:tangheem/classes/consts.dart'; +import 'package:youtube_player_flutter/youtube_player_flutter.dart'; + +class VideoPlayerWidget extends StatefulWidget { + final String link; + + VideoPlayerWidget(this.link, {Key key}) : super(key: key); + + @override + _VideoPlayerWidgetState createState() { + return _VideoPlayerWidgetState(); + } +} + +class _VideoPlayerWidgetState extends State { + bool doNotShowAgain = false; + YoutubePlayerController _controller; + + @override + void initState() { + super.initState(); + _controller = YoutubePlayerController( + initialVideoId: widget.link, + flags: YoutubePlayerFlags( + autoPlay: true, + mute: true, + ), + ); + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Dialog( + insetPadding: EdgeInsets.symmetric(horizontal: 24.0, vertical: 24.0), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12), + ), + elevation: 0, + backgroundColor: Colors.transparent, + child: Container( + width: double.infinity, + decoration: BoxDecoration( + color: ColorConsts.primaryBlue, + borderRadius: BorderRadius.circular(16), + ), + padding: EdgeInsets.symmetric(vertical: MediaQuery.of(context).orientation == Orientation.portrait ? 32 : 16, horizontal: 16), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + MediaQuery.of(context).orientation == Orientation.portrait ? videoPlayer() : Expanded(child: videoPlayer()), + SizedBox(height: 8), + Row( + children: [ + Expanded( + child: Text( + "لا تظهر مرة أخرى", + textAlign: TextAlign.right, + style: TextStyle(color: Colors.white), + ), + ), + SizedBox(width: 16), + SizedBox( + width: 12, + height: 12, + child: Checkbox( + value: doNotShowAgain, + side: BorderSide(color: Colors.white), + activeColor: ColorConsts.secondaryPink, + onChanged: (value) { + setState(() { + doNotShowAgain = value; + }); + }, + ), + ), + ], + ), + SizedBox(height: 16), + SizedBox( + width: double.infinity, + height: 40, + child: TextButton( + onPressed: () async { + if (doNotShowAgain) { + SharedPreferences prefs = await SharedPreferences.getInstance(); + await prefs.setBool(GlobalConsts.doNotShowWelcomeVideo, doNotShowAgain); + } + Navigator.pop(context); + }, + style: TextButton.styleFrom( + primary: Colors.white, + padding: EdgeInsets.all(2), + backgroundColor: ColorConsts.secondaryPink, + textStyle: TextStyle(fontSize: 14, fontFamily: "DroidKufi"), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(6.0), + ), + ), + child: Text("أغلق"), + ), + ), + ], + ), + ), + ); + } + + Widget videoPlayer() { + return YoutubePlayer( + controller: _controller, + showVideoProgressIndicator: true, + ); + } +} diff --git a/pubspec.yaml b/pubspec.yaml index 3e6c39b..743e483 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -27,13 +27,13 @@ dependencies: # The following adds the Cupertino Icons font to your application. # Use with the CupertinoIcons class for iOS style icons. cupertino_icons: ^1.0.2 - flutter_svg: ^0.19.3 + flutter_svg: ^0.23.0+1 fluttertoast: ^7.1.8 http: ^0.13.0 - image_gallery_saver: ^1.6.8 + image_gallery_saver: ^1.7.1 path_provider: ^2.0.1 permission_handler: ^6.1.1 - share: ^2.0.1 + share: ^2.0.4 just_audio: ^0.7.2 intl: ^0.17.0 shared_preferences: ^2.0.5 @@ -43,6 +43,8 @@ dependencies: syncfusion_flutter_pdfviewer: ^19.1.59-beta firebase_core: ^1.3.0 firebase_analytics: ^8.1.2 + youtube_player_flutter: ^8.0.0 + flutter_html: ^2.1.5 dev_dependencies: flutter_test: @@ -87,6 +89,9 @@ flutter: - asset: assets/fonts/UthmanicHafs-Regular.ttf - asset: assets/fonts/UthmanicHafs-Bold.ttf weight: 700 + - family: BArabics + fonts: + - asset: assets/fonts/B-Arabics.ttf # # For details regarding fonts from package dependencies, # see https://flutter.dev/custom-fonts/#from-packages