tsacdop-podcast-app-android/lib/episodes/episode_detail.dart

331 lines
15 KiB
Dart
Raw Normal View History

2020-10-28 13:10:43 +01:00
import 'dart:developer' as developer;
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/services.dart';
import 'package:provider/provider.dart';
2022-06-03 16:03:21 +02:00
import 'package:tsacdop/episodes/menu_bar.dart';
import 'package:tsacdop/episodes/shownote.dart';
import 'package:tsacdop/util/helpers.dart';
2020-10-28 13:10:43 +01:00
import 'package:tuple/tuple.dart';
import '../home/audioplayer.dart';
import '../local_storage/sqflite_localpodcast.dart';
import '../state/audio_state.dart';
import '../type/episodebrief.dart';
import '../type/play_histroy.dart';
2021-01-02 15:50:44 +01:00
import '../util/extension_helper.dart';
2020-10-30 13:35:02 +01:00
import '../widgets/audiopanel.dart';
import '../widgets/custom_widget.dart';
2020-10-28 13:10:43 +01:00
class EpisodeDetail extends StatefulWidget {
2022-04-30 17:16:19 +02:00
final EpisodeBrief? episodeItem;
2020-10-28 13:10:43 +01:00
final String heroTag;
final bool hide;
EpisodeDetail(
2022-04-30 17:16:19 +02:00
{this.episodeItem, this.heroTag = '', this.hide = false, Key? key})
2020-10-28 13:10:43 +01:00
: super(key: key);
@override
_EpisodeDetailState createState() => _EpisodeDetailState();
}
class _EpisodeDetailState extends State<EpisodeDetail> {
final textstyle = TextStyle(fontSize: 15.0, color: Colors.black);
final GlobalKey<AudioPanelState> _playerKey = GlobalKey<AudioPanelState>();
2022-04-30 17:16:19 +02:00
double? downloadProgress;
2020-10-28 13:10:43 +01:00
/// Show page title.
2022-04-30 17:16:19 +02:00
late bool _showTitle;
late bool _showMenu;
String? path;
2020-10-28 13:10:43 +01:00
Future<PlayHistory> _getPosition(EpisodeBrief episode) async {
2022-05-15 18:18:19 +02:00
final dbHelper = DBHelper();
2020-10-28 13:10:43 +01:00
return await dbHelper.getPosition(episode);
}
2022-06-03 16:03:21 +02:00
late ScrollController _controller;
2020-10-28 13:10:43 +01:00
_scrollListener() {
2022-06-03 16:03:21 +02:00
if (_controller.position.userScrollDirection == ScrollDirection.reverse) {
2020-10-28 13:10:43 +01:00
if (_showMenu && mounted) {
setState(() {
_showMenu = false;
});
}
}
2022-06-03 16:03:21 +02:00
if (_controller.position.userScrollDirection == ScrollDirection.forward) {
2020-10-28 13:10:43 +01:00
if (!_showMenu && mounted) {
setState(() {
_showMenu = true;
});
}
}
2022-06-03 16:03:21 +02:00
if (_controller.offset > context.textTheme.headline5!.fontSize!) {
2020-10-28 13:10:43 +01:00
if (!_showTitle) setState(() => _showTitle = true);
} else if (_showTitle) setState(() => _showTitle = false);
}
@override
void initState() {
super.initState();
_showMenu = true;
_showTitle = false;
_controller = ScrollController();
2022-06-03 16:03:21 +02:00
_controller.addListener(_scrollListener);
2020-10-28 13:10:43 +01:00
}
@override
void dispose() {
2022-06-03 16:03:21 +02:00
_controller.dispose();
2020-10-28 13:10:43 +01:00
super.dispose();
}
@override
Widget build(BuildContext context) {
2022-06-03 16:03:21 +02:00
final s = context.s;
final audio = context.watch<AudioPlayerNotifier>();
return AnnotatedRegion<SystemUiOverlayStyle>(
value: SystemUiOverlayStyle(
statusBarColor: widget.episodeItem!.cardColor(context),
systemNavigationBarColor: widget.episodeItem!.cardColor(context),
2022-05-15 18:18:19 +02:00
systemNavigationBarContrastEnforced: false,
systemNavigationBarIconBrightness: context.iconBrightness,
statusBarBrightness: context.brightness,
statusBarIconBrightness: context.iconBrightness),
2022-06-03 16:03:21 +02:00
child: WillPopScope(
onWillPop: () async {
if (_playerKey.currentState != null &&
_playerKey.currentState!.initSize! > 100) {
_playerKey.currentState!.backToMini();
return false;
} else {
return true;
}
},
child: Scaffold(
backgroundColor: context.onPrimary,
2022-06-03 16:03:21 +02:00
body: SafeArea(
child: Stack(
children: <Widget>[
StretchingOverscrollIndicator(
axisDirection: AxisDirection.down,
child: NestedScrollView(
scrollDirection: Axis.vertical,
controller: _controller,
headerSliverBuilder: (context, innerBoxScrolled) {
return <Widget>[
SliverAppBar(
backgroundColor:
widget.episodeItem!.cardColor(context),
2022-06-03 16:03:21 +02:00
floating: true,
pinned: true,
title: _showTitle
? Text(
widget.episodeItem?.title ?? '',
maxLines: 1,
overflow: TextOverflow.ellipsis,
)
: Text(
widget.episodeItem!.feedTitle!,
maxLines: 1,
style: TextStyle(
fontSize: 15,
color:
context.textColor.withOpacity(0.7)),
),
leading: CustomBackButton(),
elevation: 0,
),
];
},
body: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: const EdgeInsets.symmetric(
horizontal: 20, vertical: 10),
child: Align(
alignment: Alignment.centerLeft,
child: Text(
widget.episodeItem!.title!,
textAlign: TextAlign.left,
style:
Theme.of(context).textTheme.headlineSmall,
2021-02-05 19:19:37 +01:00
),
2021-01-17 16:02:30 +01:00
),
2020-10-28 13:10:43 +01:00
),
2022-06-03 16:03:21 +02:00
Padding(
padding: const EdgeInsets.fromLTRB(20, 10, 20, 10),
child: Row(
children: [
Text(
s.published(formateDate(
widget.episodeItem!.pubDate!)),
style:
TextStyle(color: context.accentColor)),
SizedBox(width: 10),
if (widget.episodeItem!.explicit == 1)
Text('E',
style: TextStyle(
fontWeight: FontWeight.bold,
color: context.error)),
Spacer(),
],
),
2021-01-17 16:02:30 +01:00
),
2022-06-03 16:03:21 +02:00
Padding(
padding: EdgeInsets.symmetric(
horizontal: 20, vertical: 5),
child: Row(
children: <Widget>[
if (widget.episodeItem!.duration != 0)
Container(
decoration: BoxDecoration(
color: context.secondary,
borderRadius: BorderRadius.all(
Radius.circular(16.0))),
height: 30.0,
margin: EdgeInsets.only(right: 12.0),
padding: EdgeInsets.symmetric(
horizontal: 10.0),
alignment: Alignment.center,
child: Text(
s.minsCount(
widget.episodeItem!.duration! ~/ 60,
),
style:
TextStyle(color: context.onPrimary),
)),
if (widget.episodeItem!.enclosureLength !=
null &&
widget.episodeItem!.enclosureLength != 0)
Container(
2021-01-17 16:02:30 +01:00
decoration: BoxDecoration(
2022-06-03 16:03:21 +02:00
color: context.tertiary,
2021-01-17 16:02:30 +01:00
borderRadius: BorderRadius.all(
Radius.circular(16.0))),
2022-06-03 16:03:21 +02:00
height: 30.0,
margin: EdgeInsets.only(right: 12.0),
2022-06-03 10:18:29 +02:00
padding:
EdgeInsets.symmetric(horizontal: 10.0),
2021-01-17 16:02:30 +01:00
alignment: Alignment.center,
child: Text(
2022-06-03 16:03:21 +02:00
'${widget.episodeItem!.enclosureLength! ~/ 1000000}MB',
style:
TextStyle(color: context.onPrimary),
),
2021-01-17 16:02:30 +01:00
),
2022-06-03 16:03:21 +02:00
FutureBuilder<PlayHistory>(
future: _getPosition(widget.episodeItem!),
builder: (context, snapshot) {
if (snapshot.hasError) {
developer.log(snapshot.error as String);
}
if (snapshot.hasData &&
snapshot.data!.seekValue! < 0.9 &&
snapshot.data!.seconds! > 10) {
return ButtonTheme(
height: 28,
padding: EdgeInsets.symmetric(
horizontal: 0),
child: OutlinedButton(
style: OutlinedButton.styleFrom(
shape: RoundedRectangleBorder(
borderRadius:
BorderRadius.circular(
100.0),
side: BorderSide(
color:
context.accentColor)),
),
onPressed: () => audio.episodeLoad(
widget.episodeItem,
startPosition:
(snapshot.data!.seconds! *
1000)
.toInt()),
child: Row(
children: [
SizedBox(
width: 20,
height: 20,
child: CustomPaint(
painter: ListenedPainter(
context.textColor,
stroke: 2.0),
),
2021-02-05 19:19:37 +01:00
),
2022-06-03 16:03:21 +02:00
SizedBox(width: 5),
Text(
snapshot
.data!.seconds!.toTime,
),
],
),
2021-01-17 16:02:30 +01:00
),
2022-06-03 16:03:21 +02:00
);
} else {
return Center();
}
}),
],
),
2021-01-17 16:02:30 +01:00
),
2022-06-03 16:03:21 +02:00
ShowNote(episode: widget.episodeItem),
Selector<AudioPlayerNotifier,
Tuple2<bool, PlayerHeight?>>(
selector: (_, audio) => Tuple2(
audio.playerRunning, audio.playerHeight),
builder: (_, data, __) {
final height =
kMinPlayerHeight[data.item2!.index];
return SizedBox(
height: data.item1 ? height : 0,
);
}),
],
2020-10-28 13:10:43 +01:00
),
),
),
2022-06-03 16:03:21 +02:00
),
Selector<AudioPlayerNotifier, Tuple2<bool, PlayerHeight?>>(
selector: (_, audio) =>
Tuple2(audio.playerRunning, audio.playerHeight),
builder: (_, data, __) {
final height = kMinPlayerHeight[data.item2!.index];
return Container(
alignment: Alignment.bottomCenter,
padding: EdgeInsets.only(bottom: data.item1 ? height : 0),
child: AnimatedContainer(
duration: Duration(milliseconds: 400),
height: _showMenu ? 50 : 0,
child: SingleChildScrollView(
scrollDirection: Axis.vertical,
child: MenuBar(
episodeItem: widget.episodeItem,
heroTag: widget.heroTag,
hide: widget.hide),
2020-10-28 13:10:43 +01:00
),
),
);
},
),
2022-06-03 16:03:21 +02:00
Selector<AudioPlayerNotifier, EpisodeBrief?>(
selector: (_, audio) => audio.episode,
builder: (_, data, __) => Container(
child: PlayerWidget(
playerKey: _playerKey,
isPlayingPage: data == widget.episodeItem),
),
),
2022-06-03 16:03:21 +02:00
],
),
2020-10-28 13:10:43 +01:00
),
2022-06-03 16:03:21 +02:00
),
2020-10-28 13:10:43 +01:00
),
);
}
}