tangheem audio download feature added. & home icon added

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

@ -5,23 +5,23 @@
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
@ -29,8 +29,7 @@
to determine the Window background behind the Flutter UI. -->
<meta-data
android:name="io.flutter.embedding.android.NormalTheme"
android:resource="@style/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
@ -38,11 +37,10 @@
Flutter's first frame. -->
<meta-data
android:name="io.flutter.embedding.android.SplashScreenDrawable"
android:resource="@drawable/launch_background"
/>
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,6 +121,7 @@ class _TangheemScreenState extends State<TangheemScreen> {
itemBuilder: (context, index) {
return InkWell(
onTap: () {
if (widget.tangheemQuery == null) {
List<AyatTangheemTypeMappedData> list = <AyatTangheemTypeMappedData>[] + _dataList;
var removedData = _dataList[index];
list.remove(removedData);
@ -115,6 +129,10 @@ class _TangheemScreenState extends State<TangheemScreen> {
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,13 +196,10 @@ class _AyaPlayerWidgetState extends State<AyaPlayerWidget> {
],
),
),
if (widget.voiceNoteList?.isNotEmpty ?? false)
commonIconButton("assets/icons/download_aya.svg", () async {
if (await _requestPermission()) {
if (await _saveAya()) {
Utils.showToast("تم حفظ الآية بنجاح");
} else {
Utils.showToast("خطأ في حفظ الآية");
}
saveToPhoneStorage(widget.voiceNoteList[_player.currentIndex].exposeFilePath, widget.voiceNoteList[_player.currentIndex].userName ?? "");
} else {
Utils.showToast("يجب اعطاء الاذن لتنزيل الآية");
}
@ -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);
Utils.hideLoading(context);
return result["isSuccess"];
} catch (ex) {
Future.delayed(Duration(seconds: 1), () {
downloadFile(ApiConsts.baseUrl + filePath, storagePath, onResponse: (isSuccess) {
Utils.hideLoading(context);
if (isSuccess) {
Utils.showToast("تم حفظ الآية بنجاح");
} else {
Utils.showToast("خطأ في حفظ الآية");
}
});
return false;
}
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