You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
266 lines
9.6 KiB
Dart
266 lines
9.6 KiB
Dart
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: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/classes/colors.dart';
|
|
import 'package:tangheem/classes/utils.dart';
|
|
import 'package:volume_controller/volume_controller.dart';
|
|
|
|
class AyaPlayerWidget extends StatefulWidget {
|
|
final String surahName;
|
|
final GlobalKey globalKey;
|
|
AyaPlayerWidget({Key key, this.surahName, @required this.globalKey}) : super(key: key);
|
|
|
|
@override
|
|
_AyaPlayerWidgetState createState() {
|
|
return _AyaPlayerWidgetState();
|
|
}
|
|
}
|
|
|
|
class _AyaPlayerWidgetState extends State<AyaPlayerWidget> {
|
|
double sliderValue = 0.4;
|
|
bool isPlaying = false;
|
|
AudioPlayer _player;
|
|
bool _isAudioHaveError = false;
|
|
|
|
@override
|
|
void initState() {
|
|
super.initState();
|
|
_player = AudioPlayer();
|
|
try {
|
|
final _playlist = ConcatenatingAudioSource(children: [
|
|
AudioSource.uri(
|
|
Uri.parse("https://file-examples-com.github.io/uploads/2017/11/file_example_MP3_1MG.mp3"),
|
|
),
|
|
]);
|
|
_player.setAudioSource(_playlist, initialIndex: 0, initialPosition: Duration.zero).then((value) => () {});
|
|
} catch (e) {
|
|
_isAudioHaveError = true;
|
|
}
|
|
}
|
|
|
|
@override
|
|
void dispose() {
|
|
_player.dispose();
|
|
super.dispose();
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return Container(
|
|
margin: EdgeInsets.only(top: 8, bottom: 8),
|
|
decoration: BoxDecoration(
|
|
color: Colors.white,
|
|
borderRadius: BorderRadius.circular(8),
|
|
),
|
|
padding: EdgeInsets.all(8),
|
|
child: Column(
|
|
children: [
|
|
Row(
|
|
children: [
|
|
Transform.rotate(
|
|
angle: 180 * math.pi / 180,
|
|
child: SvgPicture.asset(
|
|
"assets/icons/drop_menu.svg",
|
|
// color: Const.secondaryOrange,
|
|
width: 16,
|
|
),
|
|
),
|
|
Container(
|
|
width: 50.0,
|
|
margin: EdgeInsets.only(left: 8, right: 8),
|
|
height: 50.0,
|
|
decoration: BoxDecoration(
|
|
image: DecorationImage(
|
|
fit: BoxFit.cover,
|
|
image: NetworkImage("https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcSgswb98Ga7aJjIaNvqUWBsjMkdR18xzp3pyg&usqp=CAU"),
|
|
),
|
|
borderRadius: BorderRadius.all(
|
|
Radius.circular(30.0),
|
|
),
|
|
),
|
|
),
|
|
Expanded(
|
|
child: Column(
|
|
mainAxisSize: MainAxisSize.min,
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Text(
|
|
widget.surahName ?? "سورة البقسورة",
|
|
maxLines: 1,
|
|
overflow: TextOverflow.ellipsis,
|
|
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 14, color: ColorConsts.primaryBlack, height: 1),
|
|
),
|
|
SizedBox(height: 4),
|
|
Text(
|
|
"الشيخ عبد الشيخ عبد العزيز الزهراني",
|
|
style: TextStyle(fontSize: 10, color: ColorConsts.textGrey1, height: 1),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
commonIconButton("assets/icons/download_aya.svg", () async {
|
|
if (await _requestPermission()) {
|
|
if (await _saveAya()) {
|
|
Utils.showToast("Aya saved successfully");
|
|
} else {
|
|
Utils.showToast("Failed to save aya");
|
|
}
|
|
} else {
|
|
Utils.showToast("you must granted permission to download aya.");
|
|
}
|
|
}),
|
|
commonIconButton("assets/icons/share_aya.svg", () {
|
|
_shareAya();
|
|
}),
|
|
commonIconButton("assets/icons/bookmark.svg", () {}),
|
|
commonIconButton("assets/icons/audio_level.svg", () async {
|
|
// var vol = await VolumeController.getVolume();
|
|
VolumeController.maxVolume();
|
|
}),
|
|
],
|
|
),
|
|
SizedBox(height: 8),
|
|
Row(
|
|
crossAxisAlignment: CrossAxisAlignment.center,
|
|
children: [
|
|
commonIconButton("assets/icons/next_aya.svg", () {}),
|
|
SizedBox(width: 4),
|
|
StreamBuilder<PlayerState>(
|
|
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() : _player.play();
|
|
});
|
|
},
|
|
),
|
|
SizedBox(width: 4),
|
|
commonIconButton("assets/icons/previous_aya.svg", () {}),
|
|
SizedBox(width: 16),
|
|
Expanded(
|
|
child: StreamBuilder<Duration>(
|
|
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<Duration>(
|
|
stream: _player.positionStream,
|
|
builder: (context, snapshot) {
|
|
final state = snapshot.data;
|
|
return Text(
|
|
_durationTime(state) ?? "",
|
|
style: TextStyle(color: ColorConsts.textGrey1, height: 1.1, fontFamily: "Roboto"),
|
|
);
|
|
},
|
|
),
|
|
],
|
|
)
|
|
],
|
|
),
|
|
);
|
|
}
|
|
|
|
String _durationTime(Duration duration) {
|
|
if (duration == null) {
|
|
return "00:00";
|
|
}
|
|
String twoDigits(int n) => n.toString().padLeft(2, "0");
|
|
String twoDigitMinutes = twoDigits(duration.inMinutes.remainder(60));
|
|
String twoDigitSeconds = twoDigits(duration.inSeconds.remainder(60));
|
|
return "$twoDigitMinutes:$twoDigitSeconds";
|
|
}
|
|
|
|
Widget commonIconButton(String icon, VoidCallback onPressed) {
|
|
return IconButton(
|
|
highlightColor: Colors.transparent,
|
|
splashColor: Colors.transparent,
|
|
constraints: BoxConstraints(),
|
|
padding: EdgeInsets.only(right: 2),
|
|
icon: SvgPicture.asset(icon, height: 16, width: 16),
|
|
onPressed: onPressed);
|
|
}
|
|
|
|
Future<bool> _requestPermission() async {
|
|
Map<Permission, PermissionStatus> statuses = await [
|
|
Permission.storage,
|
|
].request();
|
|
|
|
return statuses[Permission.storage].isGranted;
|
|
}
|
|
|
|
Future<bool> _saveAya() 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);
|
|
final result = await ImageGallerySaver.saveImage(byteData.buffer.asUint8List(), quality: 100);
|
|
Utils.hideLoading(context);
|
|
return result["isSuccess"];
|
|
} catch (ex) {
|
|
Utils.hideLoading(context);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
void _shareAya() 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);
|
|
Utils.hideLoading(context);
|
|
Share.shareFiles(['${file.path}']);
|
|
} catch (ex) {
|
|
Utils.hideLoading(context);
|
|
}
|
|
}
|
|
}
|