tangheem audio download feature added. & home icon added

development
Sikander Saleem 3 years ago
parent 1737d2541e
commit 63779374fa

@ -5,44 +5,42 @@
In most cases you can leave this as-is, but you if you want to provide
additional functionality it is fine to subclass or reimplement
FlutterApplication and put your custom class here. -->
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.ACCESS_MEDIA_LOCATION"/>
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_MEDIA_LOCATION" />
<application
android:icon="@mipmap/ic_launcher"
android:label="Tangheem"
android:roundIcon="@mipmap/ic_launcher_round"
android:usesCleartextTraffic="true"
android:requestLegacyExternalStorage="true"
android:icon="@mipmap/ic_launcher">
android:roundIcon="@mipmap/ic_launcher_round"
android:usesCleartextTraffic="true">
<activity
android:name=".MainActivity"
android:launchMode="singleTop"
android:theme="@style/LaunchTheme"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true"
android:launchMode="singleTop"
android:theme="@style/LaunchTheme"
android:windowSoftInputMode="adjustResize">
<!-- Specifies an Android theme to apply to this Activity as soon as
the Android process has started. This theme is visible to the user
while the Flutter UI initializes. After that, this theme continues
to determine the Window background behind the Flutter UI. -->
<meta-data
android:name="io.flutter.embedding.android.NormalTheme"
android:resource="@style/NormalTheme"
/>
android:name="io.flutter.embedding.android.NormalTheme"
android:resource="@style/NormalTheme" />
<!-- Displays an Android View that continues showing the launch screen
Drawable until Flutter paints its first frame, then this splash
screen fades out. A splash screen is useful to avoid any visual
gap between the end of Android's launch screen and the painting of
Flutter's first frame. -->
<meta-data
android:name="io.flutter.embedding.android.SplashScreenDrawable"
android:resource="@drawable/launch_background"
/>
android:name="io.flutter.embedding.android.SplashScreenDrawable"
android:resource="@drawable/launch_background" />
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<!-- Don't delete the meta-data below.

@ -84,6 +84,12 @@ class TangheemUserApiClient {
return await ApiClient().postJsonForObject((json) => AyatTangheemTypeMapped.fromJson(json), url, postParams);
}
Future<AyatTangheemTypeMapped> getAyaTangheemTypeMappedFor(int surahNo, String numberInSurahs, String tangheemTypeId) async {
String url = "${ApiConsts.tangheemUsers}AyatTangheemTypeMapped_Get";
var postParams = {"surahNo": surahNo, "numberInSurahs": numberInSurahs, "tangheemTypeId": tangheemTypeId};
return await ApiClient().postJsonForObject((json) => AyatTangheemTypeMapped.fromJson(json), url, postParams);
}
Future<AyatTangheemTypeMapped> ayahBaseTextGet(String tangheemTypeName, String ayaText, int itemsPerPage, int currentPageNo) async {
String url = "${ApiConsts.tangheemUsers}AyahBaseText_Get";
var postParams = {};
@ -139,9 +145,7 @@ class TangheemUserApiClient {
Future<DiscussionModel> getDiscussionByTangheemID(int pageNumber, String tangheemID) async {
String url = "${ApiConsts.tangheemUsers}Discussion_Get";
var postParams = {"itemsPerPage": 5, "currentPageNo": pageNumber, "ayaTangheemTypeId": tangheemID};
postParams["itemsPerPage"] = null;
postParams["currentPageNo"] = null;
var postParams = {"itemsPerPage": 5, "statusId": 2, "ayaTangheemTypeId": tangheemID};
return await ApiClient().postJsonForObject((json) => DiscussionModel.fromJson(json), url, postParams);
}

@ -15,6 +15,7 @@ import 'package:tangheem/models/quick_links_model.dart';
import 'package:tangheem/ui/dialogs/change_password_dialog.dart';
import 'package:tangheem/ui/screens/bookmark_screen.dart';
import 'package:tangheem/ui/screens/content_info_screen.dart';
import 'package:tangheem/ui/screens/home_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';
@ -134,6 +135,14 @@ class _CommonAppbarState extends State<CommonAppbar> {
}
},
),
if (!widget.showDrawer)
IconButton(
icon: Icon(widget.showDrawer ? Icons.home : Icons.home, color: ColorConsts.textGrey),
padding: EdgeInsets.only(left: 16),
onPressed: () {
Navigator.popUntil(context, ModalRoute.withName(HomeScreen.routeName));
},
),
Expanded(child: SizedBox()),
Hero(
tag: "logo",

@ -86,6 +86,19 @@ class _TangheemScreenState extends State<TangheemScreen> {
setState(() {});
}
void getTangheemDataForTangheem(int surahNo, String numberInSurahs, String tangheemTypeId, String ayaTangheemTypeId) async {
Utils.showLoading(context);
try {
AyatTangheemTypeMapped _ayatTangheemTypeMapped = await TangheemUserApiClient().getAyaTangheemTypeMappedFor(surahNo, numberInSurahs, tangheemTypeId);
TangheemDetailParams tangheem = TangheemDetailParams(selectedTangheemTypeId: ayaTangheemTypeId, ayatTangheemTypeMappedDataList: _ayatTangheemTypeMapped.data ?? []);
Utils.hideLoading(context);
Navigator.pushNamed(context, TangheemDetailScreen.routeName, arguments: tangheem);
} catch (ex) {
if (mounted) Utils.handleException(ex, null);
Utils.hideLoading(context);
}
}
@override
void dispose() {
super.dispose();
@ -108,13 +121,18 @@ class _TangheemScreenState extends State<TangheemScreen> {
itemBuilder: (context, index) {
return InkWell(
onTap: () {
List<AyatTangheemTypeMappedData> list = <AyatTangheemTypeMappedData>[] + _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);
if (widget.tangheemQuery == null) {
List<AyatTangheemTypeMappedData> list = <AyatTangheemTypeMappedData>[] + _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);
} else {
var removedData = _dataList[index];
getTangheemDataForTangheem(removedData.surahNo, removedData.ayatNumberInSurahs, removedData.tangheemTypeId, removedData.ayaTangheemTypeId);
}
},
borderRadius: BorderRadius.circular(4),
child: Container(

@ -1,14 +1,14 @@
import 'dart:convert';
import 'dart:io';
import 'dart:math' as math;
import 'dart:typed_data';
import 'dart:ui' as ui;
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/services.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:image_gallery_saver/image_gallery_saver.dart';
import 'package:http/http.dart' as http;
import 'package:just_audio/just_audio.dart';
import 'package:path_provider/path_provider.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:tangheem/classes/colors.dart';
import 'package:tangheem/classes/consts.dart';
@ -196,17 +196,14 @@ class _AyaPlayerWidgetState extends State<AyaPlayerWidget> {
],
),
),
commonIconButton("assets/icons/download_aya.svg", () async {
if (await _requestPermission()) {
if (await _saveAya()) {
Utils.showToast("تم حفظ الآية بنجاح");
if (widget.voiceNoteList?.isNotEmpty ?? false)
commonIconButton("assets/icons/download_aya.svg", () async {
if (await _requestPermission()) {
saveToPhoneStorage(widget.voiceNoteList[_player.currentIndex].exposeFilePath, widget.voiceNoteList[_player.currentIndex].userName ?? "");
} else {
Utils.showToast("خطأ في حفظ الآية");
Utils.showToast("يجب اعطاء الاذن لتنزيل الآية");
}
} else {
Utils.showToast("يجب اعطاء الاذن لتنزيل الآية");
}
}),
}),
],
),
SizedBox(height: 8),
@ -311,27 +308,82 @@ class _AyaPlayerWidgetState extends State<AyaPlayerWidget> {
}
Future<bool> _requestPermission() async {
Map<Permission, PermissionStatus> statuses = await [
Permission.storage,
].request();
Map<Permission, PermissionStatus> statuses = await [Permission.storage].request();
return statuses[Permission.storage].isGranted;
}
Future<bool> _saveAya() async {
void saveToPhoneStorage(String filePath, String name) async {
Directory storageDirectory;
if (Platform.isAndroid) {
storageDirectory = await getExternalStorageDirectory();
} else if (Platform.isIOS) {
storageDirectory = await getApplicationDocumentsDirectory();
} else {
return;
}
String storagePath = storageDirectory.path;
if (storagePath.contains("/Android/data")) {
storagePath = storagePath.substring(0, storagePath.indexOf("/Android/data"));
}
storagePath += "/Download/Tangheem/";
var d = Directory(storagePath);
if (!d.existsSync()) {
d.createSync(recursive: true);
}
storagePath += "Tangheem-$name-${DateTime.now().millisecondsSinceEpoch}${filePath.substring(filePath.lastIndexOf('.'), filePath.length)}";
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);
final result = await ImageGallerySaver.saveImage(byteData.buffer.asUint8List(), quality: 100);
downloadFile(ApiConsts.baseUrl + filePath, storagePath, onResponse: (isSuccess) {
Utils.hideLoading(context);
return result["isSuccess"];
} catch (ex) {
Future.delayed(Duration(seconds: 1), () {
Utils.hideLoading(context);
});
return false;
}
if (isSuccess) {
Utils.showToast("تم حفظ الآية بنجاح");
} else {
Utils.showToast("خطأ في حفظ الآية");
}
});
}
void downloadFile(String url, String path, {Function(bool) onResponse}) {
var httpClient = http.Client();
var request = http.Request('GET', Uri.parse(url));
var response = httpClient.send(request);
String dir = path;
List<List<int>> chunks = [];
int downloaded = 0;
int lastVal;
response.asStream().listen((http.StreamedResponse r) {
r.stream.listen((List<int> chunk) {
debugPrint('downloadPercentage: ${downloaded / r.contentLength * 100}');
lastVal = (downloaded / r.contentLength * 100).toInt();
chunks.add(chunk);
downloaded += chunk.length;
}, onDone: () async {
debugPrint('downloadPercentage: ${downloaded / r.contentLength * 100}');
if (lastVal == 0) {
onResponse(false);
return;
}
// Save the file
File file = new File('$dir');
final Uint8List bytes = Uint8List(r.contentLength);
int offset = 0;
for (List<int> chunk in chunks) {
bytes.setRange(offset, offset + chunk.length, chunk);
offset += chunk.length;
}
await file.writeAsBytes(bytes);
onResponse(true);
return;
}, onError: (ex) {
debugPrint("onError:$ex");
}, cancelOnError: true);
}).onError((ex) {
debugPrint("onError:$ex");
onResponse(false);
});
}
}

@ -279,9 +279,7 @@ class _AyaRecordWidgetState extends State<AyaRecordWidget> {
}
Future<bool> _requestStoragePermission() async {
Map<Permission, PermissionStatus> statuses = await [
Permission.storage,
].request();
Map<Permission, PermissionStatus> statuses = await [Permission.storage].request();
return statuses[Permission.storage].isGranted;
}
@ -310,12 +308,13 @@ class _AyaRecordWidgetState extends State<AyaRecordWidget> {
if (storagePath.contains("/Android/data")) {
storagePath = storagePath.substring(0, storagePath.indexOf("/Android/data"));
}
storagePath += "/tangheem/record/";
storagePath += "/Download/Tangheem/";
var d = Directory(storagePath);
if (!d.existsSync()) {
d.createSync(recursive: true);
}
storagePath += "Tangheem${DateTime.now().millisecondsSinceEpoch}.mp3";
print("storagePath:$storagePath");
await file.copy(storagePath);
Utils.showToast("تم التنزيل");
}

Loading…
Cancel
Save