mirror of
https://github.com/stonega/tsacdop
synced 2025-02-03 08:57:33 +01:00
Minor change.
This commit is contained in:
parent
631b03609a
commit
8563f24140
BIN
assets/avatar_backup.png
Normal file
BIN
assets/avatar_backup.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 13 KiB |
@ -41,42 +41,8 @@ class _EpisodeDetailState extends State<EpisodeDetail> {
|
||||
|
||||
/// Show page title.
|
||||
bool _showTitle;
|
||||
|
||||
/// Load shownote.
|
||||
bool _loaddes;
|
||||
bool _showMenu;
|
||||
String path;
|
||||
String _description;
|
||||
|
||||
Future _getSDescription(String url) async {
|
||||
var dbHelper = DBHelper();
|
||||
_description = (await dbHelper.getDescription(url))
|
||||
.replaceAll(RegExp(r'\s?<p>(<br>)?</p>\s?'), '')
|
||||
.replaceAll('\r', '')
|
||||
.trim();
|
||||
if (!_description.contains('<')) {
|
||||
final linkList = linkify(_description,
|
||||
options: LinkifyOptions(humanize: false),
|
||||
linkifiers: [UrlLinkifier(), EmailLinkifier()]);
|
||||
for (var element in linkList) {
|
||||
if (element is UrlElement) {
|
||||
_description = _description.replaceAll(element.url,
|
||||
'<a rel="nofollow" href = ${element.url}>${element.text}</a>');
|
||||
}
|
||||
if (element is EmailElement) {
|
||||
final address = element.emailAddress;
|
||||
_description = _description.replaceAll(address,
|
||||
'<a rel="nofollow" href = "mailto:$address">$address</a>');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
_loaddes = true;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Future<PlayHistory> _getPosition(EpisodeBrief episode) async {
|
||||
var dbHelper = DBHelper();
|
||||
@ -104,33 +70,9 @@ class _EpisodeDetailState extends State<EpisodeDetail> {
|
||||
} else if (_showTitle) setState(() => _showTitle = false);
|
||||
}
|
||||
|
||||
_markListened(EpisodeBrief episode) async {
|
||||
var dbHelper = DBHelper();
|
||||
var marked = await dbHelper.checkMarked(episode);
|
||||
if (!marked) {
|
||||
final history = PlayHistory(episode.title, episode.enclosureUrl, 0, 1);
|
||||
await dbHelper.saveHistory(history);
|
||||
}
|
||||
}
|
||||
|
||||
int _getTimeStamp(String url) {
|
||||
final time = url.substring(7);
|
||||
final data = time.split(':');
|
||||
var seconds;
|
||||
if (data.length == 3) {
|
||||
seconds = int.tryParse(data[0]) * 3600 +
|
||||
int.tryParse(data[1]) * 60 +
|
||||
int.tryParse(data[2]);
|
||||
} else if (data.length == 2) {
|
||||
seconds = int.tryParse(data[0]) * 60 + int.tryParse(data[1]);
|
||||
}
|
||||
return seconds;
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_loaddes = false;
|
||||
_showMenu = true;
|
||||
_showTitle = false;
|
||||
//_getSDescription(widget.episodeItem.enclosureUrl);
|
||||
@ -569,8 +511,8 @@ class __MenuBarState extends State<_MenuBar> {
|
||||
? Center()
|
||||
: CircleAvatar(
|
||||
radius: 15,
|
||||
backgroundImage: FileImage(
|
||||
File("${widget.episodeItem.imagePath}"))),
|
||||
backgroundImage:
|
||||
widget.episodeItem.avatarImage),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
@ -59,7 +59,7 @@ class PlayerWidget extends StatelessWidget {
|
||||
selector: (_, audio) =>
|
||||
Tuple2(audio.episode?.primaryColor, audio.seekSliderValue),
|
||||
builder: (_, data, __) {
|
||||
var c = context.brightness == Brightness.light
|
||||
final c = context.brightness == Brightness.light
|
||||
? data.item1.colorizedark()
|
||||
: data.item1.colorizeLight();
|
||||
return SizedBox(
|
||||
@ -127,9 +127,10 @@ class PlayerWidget extends StatelessWidget {
|
||||
),
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: Selector<AudioPlayerNotifier, Tuple2<bool, bool>>(
|
||||
child: Selector<AudioPlayerNotifier,
|
||||
Tuple3<bool, bool, EpisodeBrief>>(
|
||||
selector: (_, audio) =>
|
||||
Tuple2(audio.buffering, audio.playing),
|
||||
Tuple3(audio.buffering, audio.playing, audio.episode),
|
||||
builder: (_, data, __) {
|
||||
return Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
@ -142,12 +143,15 @@ class PlayerWidget extends StatelessWidget {
|
||||
padding: const EdgeInsets.symmetric(
|
||||
vertical: 10.0),
|
||||
child: SizedBox(
|
||||
height: 30.0,
|
||||
width: 30.0,
|
||||
child: CircleAvatar(
|
||||
backgroundImage: FileImage(File(
|
||||
"${audio.episode.imagePath}")),
|
||||
)),
|
||||
height: 30.0,
|
||||
width: 30.0,
|
||||
child: CircleAvatar(
|
||||
backgroundColor: data.item3
|
||||
.backgroudColor(context),
|
||||
backgroundImage:
|
||||
data.item3.avatarImage,
|
||||
),
|
||||
),
|
||||
),
|
||||
Container(
|
||||
height: 40.0,
|
||||
@ -161,9 +165,8 @@ class PlayerWidget extends StatelessWidget {
|
||||
onTap: data.item2
|
||||
? () => audio.pauseAduio()
|
||||
: null,
|
||||
child: ImageRotate(
|
||||
title: audio.episode?.title,
|
||||
path: audio.episode?.imagePath),
|
||||
child:
|
||||
ImageRotate(episodeItem: data.item3),
|
||||
)
|
||||
: InkWell(
|
||||
onTap: data.item2
|
||||
@ -176,12 +179,15 @@ class PlayerWidget extends StatelessWidget {
|
||||
padding: EdgeInsets.symmetric(
|
||||
vertical: 10.0),
|
||||
child: SizedBox(
|
||||
height: 30.0,
|
||||
width: 30.0,
|
||||
child: CircleAvatar(
|
||||
backgroundImage: FileImage(File(
|
||||
"${audio.episode.imagePath}")),
|
||||
)),
|
||||
height: 30.0,
|
||||
width: 30.0,
|
||||
child: CircleAvatar(
|
||||
backgroundColor: data.item3
|
||||
.backgroudColor(context),
|
||||
backgroundImage:
|
||||
data.item3.avatarImage,
|
||||
),
|
||||
),
|
||||
),
|
||||
Container(
|
||||
height: 40.0,
|
||||
@ -384,71 +390,6 @@ class LastPosition extends StatelessWidget {
|
||||
}
|
||||
}
|
||||
|
||||
class ImageRotate extends StatefulWidget {
|
||||
final String title;
|
||||
final String path;
|
||||
ImageRotate({this.title, this.path, Key key}) : super(key: key);
|
||||
@override
|
||||
_ImageRotateState createState() => _ImageRotateState();
|
||||
}
|
||||
|
||||
class _ImageRotateState extends State<ImageRotate>
|
||||
with SingleTickerProviderStateMixin {
|
||||
Animation _animation;
|
||||
AnimationController _controller;
|
||||
double _value;
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_value = 0;
|
||||
_controller = AnimationController(
|
||||
vsync: this,
|
||||
duration: Duration(milliseconds: 2000),
|
||||
);
|
||||
_animation = Tween(begin: 0.0, end: 1.0).animate(_controller)
|
||||
..addListener(() {
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
_value = _animation.value;
|
||||
});
|
||||
}
|
||||
});
|
||||
_controller.forward();
|
||||
_controller.addStatusListener((status) {
|
||||
if (status == AnimationStatus.completed) {
|
||||
_controller.reset();
|
||||
} else if (status == AnimationStatus.dismissed) {
|
||||
_controller.forward();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_controller.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Transform.rotate(
|
||||
angle: 2 * math.pi * _value,
|
||||
child: Container(
|
||||
padding: EdgeInsets.symmetric(vertical: 10.0),
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.all(Radius.circular(15.0)),
|
||||
child: Container(
|
||||
height: 30.0,
|
||||
width: 30.0,
|
||||
color: Colors.white,
|
||||
child: Image.file(File("${widget.path}")),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class PlaylistWidget extends StatefulWidget {
|
||||
const PlaylistWidget({Key key}) : super(key: key);
|
||||
|
||||
@ -500,7 +441,6 @@ class _PlaylistWidgetState extends State<PlaylistWidget> {
|
||||
miniPlaylistKey.currentState.removeItem(
|
||||
index,
|
||||
(context, animation) => Center());
|
||||
miniPlaylistKey.currentState.insertItem(0);
|
||||
},
|
||||
child: Container(
|
||||
height: 60,
|
||||
@ -586,7 +526,7 @@ class _PlaylistWidgetState extends State<PlaylistWidget> {
|
||||
),
|
||||
],
|
||||
),
|
||||
Divider(height: 2),
|
||||
Divider(height: 1),
|
||||
],
|
||||
),
|
||||
),
|
||||
@ -638,7 +578,10 @@ class _PlaylistWidgetState extends State<PlaylistWidget> {
|
||||
onTap: () {
|
||||
Navigator.push(
|
||||
context,
|
||||
SlideLeftRoute(page: PlaylistPage()),
|
||||
SlideLeftRoute(
|
||||
page: PlaylistPage(
|
||||
initPage: InitPage.playlist,
|
||||
)),
|
||||
);
|
||||
},
|
||||
child: SizedBox(
|
||||
@ -1382,8 +1325,8 @@ class _ControlPanelState extends State<ControlPanel>
|
||||
height: 30.0,
|
||||
width: 30.0,
|
||||
child: CircleAvatar(
|
||||
backgroundImage: FileImage(File(
|
||||
"${data.item1.imagePath}")),
|
||||
backgroundImage:
|
||||
data.item1.avatarImage,
|
||||
),
|
||||
),
|
||||
SizedBox(width: 5),
|
||||
|
@ -118,9 +118,7 @@ class _DownloadListState extends State<DownloadList> {
|
||||
),
|
||||
),
|
||||
leading: CircleAvatar(
|
||||
backgroundImage: FileImage(
|
||||
File("${tasks[index].episode.imagePath}")),
|
||||
),
|
||||
backgroundImage: tasks[index].episode.avatarImage),
|
||||
trailing: _downloadButton(tasks[index], context),
|
||||
);
|
||||
},
|
||||
|
@ -614,10 +614,9 @@ class PlaylistButtonState extends State<PlaylistButton> {
|
||||
alignment: Alignment.center,
|
||||
children: <Widget>[
|
||||
CircleAvatar(
|
||||
radius: 20,
|
||||
backgroundImage: FileImage(File(
|
||||
"${data.item2.playlist.first.imagePath}")),
|
||||
),
|
||||
radius: 20,
|
||||
backgroundImage: data
|
||||
.item2.playlist.first.avatarImage),
|
||||
Container(
|
||||
height: 40.0,
|
||||
width: 40.0,
|
||||
@ -678,12 +677,42 @@ class PlaylistButtonState extends State<PlaylistButton> {
|
||||
),
|
||||
),
|
||||
),
|
||||
PopupMenuItem(
|
||||
value: 2,
|
||||
child: Container(
|
||||
padding: EdgeInsets.only(left: 10),
|
||||
child: Row(
|
||||
children: <Widget>[
|
||||
Icon(Icons.history),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 5.0),
|
||||
),
|
||||
Text(s.settingsHistory),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
onSelected: (value) {
|
||||
if (value == 0) {
|
||||
Navigator.push(
|
||||
context, MaterialPageRoute(builder: (context) => PlaylistPage()));
|
||||
} else if (value == 1) {}
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) => PlaylistPage(
|
||||
initPage: InitPage.playlist,
|
||||
),
|
||||
),
|
||||
);
|
||||
} else if (value == 2) {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) => PlaylistPage(
|
||||
initPage: InitPage.history,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
@ -314,12 +314,8 @@ class _ScrollPodcastsState extends State<ScrollPodcasts> {
|
||||
tabs: groups[_groupIndex]
|
||||
.podcasts
|
||||
.map<Widget>((podcastLocal) {
|
||||
var color = (Theme.of(context).brightness ==
|
||||
Brightness.light)
|
||||
? podcastLocal.primaryColor
|
||||
.colorizedark()
|
||||
: podcastLocal.primaryColor
|
||||
.colorizeLight();
|
||||
final color =
|
||||
podcastLocal.backgroudColor(context);
|
||||
return Tab(
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.all(
|
||||
@ -331,11 +327,10 @@ class _ScrollPodcastsState extends State<ScrollPodcasts> {
|
||||
maxHeight: 50,
|
||||
maxWidth: 50,
|
||||
child: CircleAvatar(
|
||||
backgroundColor:
|
||||
color.withOpacity(0.5),
|
||||
backgroundImage: FileImage(File(
|
||||
"${podcastLocal.imagePath}")),
|
||||
),
|
||||
backgroundColor:
|
||||
color.withOpacity(0.5),
|
||||
backgroundImage:
|
||||
podcastLocal.avatarImage),
|
||||
),
|
||||
FutureBuilder<int>(
|
||||
future: getPodcastUpdateCounts(
|
||||
@ -418,9 +413,7 @@ class PodcastPreview extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
var _c = (Theme.of(context).brightness == Brightness.light)
|
||||
? podcastLocal.primaryColor.colorizedark()
|
||||
: podcastLocal.primaryColor.colorizeLight();
|
||||
final c = podcastLocal.backgroudColor(context);
|
||||
return Column(
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
@ -454,7 +447,7 @@ class PodcastPreview extends StatelessWidget {
|
||||
child: Text(podcastLocal.title,
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.visible,
|
||||
style: TextStyle(fontWeight: FontWeight.bold, color: _c)),
|
||||
style: TextStyle(fontWeight: FontWeight.bold, color: c)),
|
||||
),
|
||||
Expanded(
|
||||
flex: 1,
|
||||
@ -595,9 +588,7 @@ class ShowEpisode extends StatelessWidget {
|
||||
),
|
||||
delegate: SliverChildBuilderDelegate(
|
||||
(context, index) {
|
||||
var _c = (Theme.of(context).brightness == Brightness.light)
|
||||
? podcastLocal.primaryColor.colorizedark()
|
||||
: podcastLocal.primaryColor.colorizeLight();
|
||||
final c = podcastLocal.backgroudColor(context);
|
||||
return Selector<AudioPlayerNotifier,
|
||||
Tuple2<EpisodeBrief, List<String>>>(
|
||||
selector: (_, audio) => Tuple2(
|
||||
@ -809,8 +800,8 @@ class ShowEpisode extends StatelessWidget {
|
||||
height: _width / 18,
|
||||
width: _width / 18,
|
||||
child: CircleAvatar(
|
||||
backgroundImage: FileImage(File(
|
||||
"${podcastLocal.imagePath}")),
|
||||
backgroundImage:
|
||||
podcastLocal.avatarImage,
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -882,7 +873,7 @@ class ShowEpisode extends StatelessWidget {
|
||||
overflow: TextOverflow.visible,
|
||||
style: TextStyle(
|
||||
fontSize: _width / 35,
|
||||
color: _c,
|
||||
color: c,
|
||||
fontStyle: FontStyle.italic,
|
||||
),
|
||||
),
|
||||
|
@ -16,7 +16,11 @@ import '../type/playlist.dart';
|
||||
import '../util/custom_widget.dart';
|
||||
import '../util/extension_helper.dart';
|
||||
|
||||
enum InitPage { playlist, history }
|
||||
|
||||
class PlaylistPage extends StatefulWidget {
|
||||
final InitPage initPage;
|
||||
PlaylistPage({this.initPage, Key key}) : super(key: key);
|
||||
@override
|
||||
_PlaylistPageState createState() => _PlaylistPageState();
|
||||
}
|
||||
@ -47,7 +51,12 @@ class _PlaylistPageState extends State<PlaylistPage> {
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_loadList = _ReorderablePlaylist();
|
||||
if (widget.initPage == InitPage.playlist) {
|
||||
_loadList = _ReorderablePlaylist();
|
||||
} else {
|
||||
_loadHistory = true;
|
||||
_loadList = _HistoryList();
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
@ -213,41 +222,15 @@ class _PlaylistPageState extends State<PlaylistPage> {
|
||||
)
|
||||
: BoxDecoration(color: Colors.transparent),
|
||||
child: data.item2
|
||||
// ? _topHeight < 90
|
||||
// ? Row(
|
||||
// mainAxisAlignment:
|
||||
// MainAxisAlignment.center,
|
||||
// crossAxisAlignment:
|
||||
// CrossAxisAlignment.center,
|
||||
// children: <Widget>[
|
||||
// CircleAvatar(
|
||||
// radius: 12,
|
||||
// backgroundImage: FileImage(File(
|
||||
// "${episodes.first.imagePath}")),
|
||||
// ),
|
||||
// Padding(
|
||||
// padding: EdgeInsets.symmetric(
|
||||
// horizontal: 15),
|
||||
// child: SizedBox(
|
||||
// width: 20,
|
||||
// height: 15,
|
||||
// child: WaveLoader(
|
||||
// color: context.accentColor,
|
||||
// )),
|
||||
// ),
|
||||
// ],
|
||||
// )
|
||||
? Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment:
|
||||
CrossAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
CircleAvatar(
|
||||
radius: 15,
|
||||
//backgroundColor: _c.withOpacity(0.5),
|
||||
backgroundImage: FileImage(
|
||||
File("${data.item4.imagePath}")),
|
||||
),
|
||||
radius: 15,
|
||||
backgroundImage:
|
||||
data.item4.avatarImage),
|
||||
Container(
|
||||
width: 150,
|
||||
alignment: Alignment.center,
|
||||
@ -380,11 +363,9 @@ class __DismissibleContainerState extends State<_DismissibleContainer> {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
var audio = Provider.of<AudioPlayerNotifier>(context, listen: false);
|
||||
final audio = Provider.of<AudioPlayerNotifier>(context, listen: false);
|
||||
final s = context.s;
|
||||
var c = (Theme.of(context).brightness == Brightness.light)
|
||||
? widget.episode.primaryColor.colorizedark()
|
||||
: widget.episode.primaryColor.colorizeLight();
|
||||
final c = widget.episode.backgroudColor(context);
|
||||
return AnimatedContainer(
|
||||
duration: Duration(milliseconds: 300),
|
||||
alignment: Alignment.center,
|
||||
@ -475,10 +456,8 @@ class __DismissibleContainerState extends State<_DismissibleContainer> {
|
||||
children: [
|
||||
Icon(Icons.unfold_more, color: c),
|
||||
CircleAvatar(
|
||||
backgroundColor: c.withOpacity(0.5),
|
||||
backgroundImage:
|
||||
FileImage(File(widget.episode.imagePath)),
|
||||
),
|
||||
backgroundColor: c.withOpacity(0.5),
|
||||
backgroundImage: widget.episode.avatarImage),
|
||||
],
|
||||
),
|
||||
subtitle: Container(
|
||||
@ -595,10 +574,8 @@ class __HistoryListState extends State<_HistoryList> {
|
||||
EdgeInsets.fromLTRB(24, 8, 20, 8),
|
||||
onTap: () => audio.episodeLoad(episode),
|
||||
leading: CircleAvatar(
|
||||
backgroundColor: c.withOpacity(0.5),
|
||||
backgroundImage:
|
||||
FileImage(File(episode.imagePath)),
|
||||
),
|
||||
backgroundColor: c.withOpacity(0.5),
|
||||
backgroundImage: episode.avatarImage),
|
||||
title: Padding(
|
||||
padding:
|
||||
EdgeInsets.symmetric(vertical: 5.0),
|
||||
@ -741,7 +718,7 @@ class __HistoryListState extends State<_HistoryList> {
|
||||
),
|
||||
),
|
||||
),
|
||||
Divider(height: 2)
|
||||
Divider(height: 1)
|
||||
],
|
||||
),
|
||||
);
|
||||
|
@ -1,5 +1,6 @@
|
||||
import 'dart:async';
|
||||
import 'dart:developer' as developer;
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:flutter_downloader/flutter_downloader.dart';
|
||||
@ -1170,6 +1171,12 @@ class DBHelper {
|
||||
list.first['is_new'],
|
||||
mediaId: list.first['media_id'],
|
||||
skipSeconds: list.first['skip_seconds']);
|
||||
if (episode.enclosureUrl != episode.mediaId &&
|
||||
!File(episode.mediaId.substring(7)).existsSync()) {
|
||||
final url = episode.enclosureUrl;
|
||||
await delDownloaded(url);
|
||||
episode = episode.copyWith(mediaId: url);
|
||||
}
|
||||
return episode;
|
||||
}
|
||||
}
|
||||
@ -1198,6 +1205,12 @@ class DBHelper {
|
||||
list.first['is_new'],
|
||||
mediaId: list.first['media_id'],
|
||||
skipSeconds: list.first['skip_seconds']);
|
||||
if (episode.enclosureUrl != episode.mediaId &&
|
||||
!File(episode.mediaId.substring(7)).existsSync()) {
|
||||
final url = episode.enclosureUrl;
|
||||
await delDownloaded(url);
|
||||
episode = episode.copyWith(mediaId: url);
|
||||
}
|
||||
return episode;
|
||||
}
|
||||
}
|
||||
|
@ -161,9 +161,7 @@ class __PodcastCardState extends State<_PodcastCard>
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final c = (Theme.of(context).brightness == Brightness.light)
|
||||
? widget.podcastLocal.primaryColor.colorizedark()
|
||||
: widget.podcastLocal.primaryColor.colorizeLight();
|
||||
final c = widget.podcastLocal.backgroudColor(context);
|
||||
final s = context.s;
|
||||
var width = context.width;
|
||||
var groupList = context.watch<GroupList>();
|
||||
|
@ -320,9 +320,9 @@ class _DownloadsManageState extends State<DownloadsManage> {
|
||||
}
|
||||
},
|
||||
leading: CircleAvatar(
|
||||
backgroundImage: FileImage(File(
|
||||
"${_episodes[index].imagePath}")),
|
||||
),
|
||||
backgroundImage:
|
||||
_episodes[index]
|
||||
.avatarImage),
|
||||
title: Text(
|
||||
_episodes[index].title,
|
||||
maxLines: 1,
|
||||
|
@ -190,7 +190,7 @@ class _LayoutSettingState extends State<LayoutSetting> {
|
||||
title: Text(s.settingsPopupMenu),
|
||||
subtitle: Text(s.settingsPopupMenuDes),
|
||||
),
|
||||
Divider(height: 2),
|
||||
Divider(height: 1),
|
||||
Padding(
|
||||
padding: EdgeInsets.all(10.0),
|
||||
),
|
||||
@ -226,7 +226,7 @@ class _LayoutSettingState extends State<LayoutSetting> {
|
||||
audio.setPlayerHeight = PlayerHeight.values[index]),
|
||||
),
|
||||
),
|
||||
Divider(height: 2),
|
||||
Divider(height: 1),
|
||||
Padding(
|
||||
padding: EdgeInsets.all(10.0),
|
||||
),
|
||||
@ -258,7 +258,7 @@ class _LayoutSettingState extends State<LayoutSetting> {
|
||||
text: s.settingsDefaultGridDownload,
|
||||
key: downloadLayoutKey),
|
||||
]),
|
||||
Divider(height: 2),
|
||||
Divider(height: 1),
|
||||
],
|
||||
),
|
||||
)),
|
||||
|
@ -247,7 +247,7 @@ class PlaySetting extends StatelessWidget {
|
||||
),
|
||||
),
|
||||
),
|
||||
Divider(height: 2),
|
||||
Divider(height: 1),
|
||||
],
|
||||
),
|
||||
Padding(
|
||||
@ -415,7 +415,7 @@ class PlaySetting extends StatelessWidget {
|
||||
trailing: context.width > 360
|
||||
? _scheduleWidget(context)
|
||||
: null),
|
||||
Divider(height: 2)
|
||||
Divider(height: 1)
|
||||
],
|
||||
),
|
||||
SizedBox(height: 20)
|
||||
|
@ -145,7 +145,7 @@ class _StorageSettingState extends State<StorageSetting>
|
||||
);
|
||||
},
|
||||
),
|
||||
Divider(height: 2),
|
||||
Divider(height: 1),
|
||||
FutureBuilder<bool>(
|
||||
future: _getAutoDownloadNetwork(),
|
||||
initialData: false,
|
||||
@ -172,7 +172,7 @@ class _StorageSettingState extends State<StorageSetting>
|
||||
),
|
||||
);
|
||||
}),
|
||||
Divider(height: 2),
|
||||
Divider(height: 1),
|
||||
],
|
||||
),
|
||||
]),
|
||||
@ -207,7 +207,7 @@ class _StorageSettingState extends State<StorageSetting>
|
||||
title: Text(s.download),
|
||||
subtitle: Text(s.settingsManageDownloadDes),
|
||||
),
|
||||
Divider(height: 2),
|
||||
Divider(height: 1),
|
||||
FutureBuilder<int>(
|
||||
future: _getAutoDeleteDays(),
|
||||
initialData: 30,
|
||||
@ -238,7 +238,7 @@ class _StorageSettingState extends State<StorageSetting>
|
||||
);
|
||||
},
|
||||
),
|
||||
Divider(height: 2),
|
||||
Divider(height: 1),
|
||||
ListTile(
|
||||
contentPadding: EdgeInsets.only(left: 70.0, right: 25),
|
||||
// leading: Icon(Icons.colorize),
|
||||
@ -281,7 +281,7 @@ class _StorageSettingState extends State<StorageSetting>
|
||||
}),
|
||||
),
|
||||
),
|
||||
Divider(height: 2),
|
||||
Divider(height: 1),
|
||||
],
|
||||
),
|
||||
],
|
||||
|
@ -110,7 +110,7 @@ class SyncingSetting extends StatelessWidget {
|
||||
value: e, child: Text(s.hoursCount(e)));
|
||||
}).toList()),
|
||||
),
|
||||
Divider(height: 2),
|
||||
Divider(height: 1),
|
||||
],
|
||||
),
|
||||
],
|
||||
|
@ -168,7 +168,7 @@ class ThemeSetting extends StatelessWidget {
|
||||
fontWeight: FontWeight.bold,
|
||||
color: context.accentColor))
|
||||
])),
|
||||
content: ColorPicker(
|
||||
content: _ColorPicker(
|
||||
onColorChanged: (value) =>
|
||||
settings.setAccentColor = value,
|
||||
),
|
||||
@ -183,7 +183,7 @@ class ThemeSetting extends StatelessWidget {
|
||||
shape: BoxShape.circle, color: context.accentColor),
|
||||
),
|
||||
),
|
||||
Divider(height: 2),
|
||||
Divider(height: 1),
|
||||
],
|
||||
),
|
||||
],
|
||||
@ -193,14 +193,14 @@ class ThemeSetting extends StatelessWidget {
|
||||
}
|
||||
}
|
||||
|
||||
class ColorPicker extends StatefulWidget {
|
||||
class _ColorPicker extends StatefulWidget {
|
||||
final ValueChanged<Color> onColorChanged;
|
||||
ColorPicker({Key key, this.onColorChanged}) : super(key: key);
|
||||
_ColorPicker({Key key, this.onColorChanged}) : super(key: key);
|
||||
@override
|
||||
_ColorPickerState createState() => _ColorPickerState();
|
||||
__ColorPickerState createState() => __ColorPickerState();
|
||||
}
|
||||
|
||||
class _ColorPickerState extends State<ColorPicker>
|
||||
class __ColorPickerState extends State<_ColorPicker>
|
||||
with SingleTickerProviderStateMixin {
|
||||
TabController _controller;
|
||||
int _index;
|
||||
@ -284,9 +284,9 @@ class _ColorPickerState extends State<ColorPicker>
|
||||
behavior: NoGrowBehavior(),
|
||||
child: GridView.count(
|
||||
primary: false,
|
||||
padding: const EdgeInsets.all(10),
|
||||
crossAxisSpacing: 10,
|
||||
mainAxisSpacing: 10,
|
||||
padding: const EdgeInsets.fromLTRB(2, 10, 2, 10),
|
||||
crossAxisSpacing: 4,
|
||||
mainAxisSpacing: 4,
|
||||
crossAxisCount: 3,
|
||||
children: <Widget>[
|
||||
_colorCircle(color.shade100),
|
||||
|
@ -1,6 +1,10 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:equatable/equatable.dart';
|
||||
|
||||
import 'package:audio_service/audio_service.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import '../util/extension_helper.dart';
|
||||
|
||||
class EpisodeBrief extends Equatable {
|
||||
final String title;
|
||||
@ -49,6 +53,29 @@ class EpisodeBrief extends Equatable {
|
||||
extras: {'skip': skipSeconds});
|
||||
}
|
||||
|
||||
ImageProvider get avatarImage {
|
||||
return File(imagePath).existsSync()
|
||||
? FileImage(File(imagePath))
|
||||
: const AssetImage('assets/avatar_backup.png');
|
||||
}
|
||||
|
||||
Color backgroudColor(BuildContext context) {
|
||||
return context.brightness == Brightness.light
|
||||
? primaryColor.colorizedark()
|
||||
: primaryColor.colorizeLight();
|
||||
}
|
||||
|
||||
EpisodeBrief copyWith({
|
||||
String mediaId,
|
||||
}) =>
|
||||
EpisodeBrief(title, enclosureUrl, enclosureLength, pubDate, feedTitle,
|
||||
primaryColor, duration, explicit, imagePath, isNew,
|
||||
mediaId: mediaId ?? this.mediaId,
|
||||
downloaded: downloaded,
|
||||
skipSeconds: skipSeconds,
|
||||
description: description,
|
||||
downloadDate: downloadDate);
|
||||
|
||||
@override
|
||||
List<Object> get props => [enclosureUrl, title];
|
||||
}
|
||||
|
@ -1,4 +1,9 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:equatable/equatable.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../util/extension_helper.dart';
|
||||
|
||||
class PodcastLocal extends Equatable {
|
||||
final String title;
|
||||
@ -29,6 +34,18 @@ class PodcastLocal extends Equatable {
|
||||
_episodeCount = episodeCount ?? 0,
|
||||
_upateCount = upateCount ?? 0;
|
||||
|
||||
ImageProvider get avatarImage {
|
||||
return File(imagePath).existsSync()
|
||||
? FileImage(File(imagePath))
|
||||
: const AssetImage('assets/avatar_backup.png');
|
||||
}
|
||||
|
||||
Color backgroudColor(BuildContext context) {
|
||||
return context.brightness == Brightness.light
|
||||
? primaryColor.colorizedark()
|
||||
: primaryColor.colorizeLight();
|
||||
}
|
||||
|
||||
@override
|
||||
List<Object> get props => [id, rssUrl];
|
||||
}
|
||||
|
@ -122,6 +122,10 @@ class AudioPanelState extends State<AudioPanel> with TickerProviderStateMixin {
|
||||
: Container(
|
||||
decoration: BoxDecoration(
|
||||
color: context.primaryColor,
|
||||
// borderRadius: BorderRadius.only(
|
||||
// topLeft: Radius.circular(20.0),
|
||||
// topRight: Radius.circular(20.0)),
|
||||
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
offset: Offset(0, -1),
|
||||
|
@ -1113,6 +1113,7 @@ class MyDropdownButton<T> extends StatefulWidget {
|
||||
class _MyDropdownButtonState<T> extends State<MyDropdownButton<T>>
|
||||
// ignore: prefer_mixin
|
||||
with
|
||||
// ignore: prefer_mixin
|
||||
WidgetsBindingObserver {
|
||||
int _selectedIndex;
|
||||
_DropdownRoute<T> _dropdownRoute;
|
||||
|
@ -105,14 +105,12 @@ class _TimePickerHeader extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
assert(debugCheckHasMediaQuery(context));
|
||||
final ThemeData themeData = Theme.of(context);
|
||||
final TimeOfDayFormat timeOfDayFormat =
|
||||
MaterialLocalizations.of(context).timeOfDayFormat(
|
||||
final themeData = Theme.of(context);
|
||||
final timeOfDayFormat = MaterialLocalizations.of(context).timeOfDayFormat(
|
||||
alwaysUse24HourFormat: MediaQuery.of(context).alwaysUse24HourFormat,
|
||||
);
|
||||
|
||||
final _TimePickerFragmentContext fragmentContext =
|
||||
_TimePickerFragmentContext(
|
||||
final fragmentContext = _TimePickerFragmentContext(
|
||||
selectedTime: selectedTime,
|
||||
mode: mode,
|
||||
onTimeChange: onChanged,
|
||||
@ -241,26 +239,26 @@ class _HourMinuteControl extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final ThemeData themeData = Theme.of(context);
|
||||
final TimePickerThemeData timePickerTheme = TimePickerTheme.of(context);
|
||||
final bool isDark = themeData.colorScheme.brightness == Brightness.dark;
|
||||
final Color textColor = timePickerTheme.hourMinuteTextColor ??
|
||||
MaterialStateColor.resolveWith((Set<MaterialState> states) {
|
||||
final themeData = Theme.of(context);
|
||||
final timePickerTheme = TimePickerTheme.of(context);
|
||||
final isDark = themeData.colorScheme.brightness == Brightness.dark;
|
||||
final textColor = timePickerTheme.hourMinuteTextColor ??
|
||||
MaterialStateColor.resolveWith((states) {
|
||||
return states.contains(MaterialState.selected)
|
||||
? themeData.accentColor
|
||||
: themeData.colorScheme.onSurface;
|
||||
});
|
||||
final Color backgroundColor = timePickerTheme.hourMinuteColor ??
|
||||
MaterialStateColor.resolveWith((Set<MaterialState> states) {
|
||||
final backgroundColor = timePickerTheme.hourMinuteColor ??
|
||||
MaterialStateColor.resolveWith((states) {
|
||||
return states.contains(MaterialState.selected)
|
||||
? themeData.accentColor.withOpacity(isDark ? 0.24 : 0.12)
|
||||
: themeData.colorScheme.onSurface.withOpacity(0.12);
|
||||
});
|
||||
final TextStyle style =
|
||||
final style =
|
||||
timePickerTheme.hourMinuteTextStyle ?? themeData.textTheme.headline2;
|
||||
final ShapeBorder shape = timePickerTheme.hourMinuteShape ?? _kDefaultShape;
|
||||
final shape = timePickerTheme.hourMinuteShape ?? _kDefaultShape;
|
||||
|
||||
final Set<MaterialState> states = isSelected
|
||||
final states = isSelected
|
||||
? <MaterialState>{MaterialState.selected}
|
||||
: <MaterialState>{};
|
||||
return Container(
|
||||
@ -298,38 +296,36 @@ class _HourControl extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
assert(debugCheckHasMediaQuery(context));
|
||||
final bool alwaysUse24HourFormat =
|
||||
MediaQuery.of(context).alwaysUse24HourFormat;
|
||||
final MaterialLocalizations localizations =
|
||||
MaterialLocalizations.of(context);
|
||||
final String formattedHour = localizations.formatHour(
|
||||
final alwaysUse24HourFormat = MediaQuery.of(context).alwaysUse24HourFormat;
|
||||
final localizations = MaterialLocalizations.of(context);
|
||||
final formattedHour = localizations.formatHour(
|
||||
fragmentContext.selectedTime,
|
||||
alwaysUse24HourFormat: alwaysUse24HourFormat,
|
||||
);
|
||||
|
||||
TimeOfDay hoursFromSelected(int hoursToAdd) {
|
||||
if (fragmentContext.use24HourDials) {
|
||||
final int selectedHour = fragmentContext.selectedTime.hour;
|
||||
final selectedHour = fragmentContext.selectedTime.hour;
|
||||
return fragmentContext.selectedTime.replacing(
|
||||
hour: (selectedHour + hoursToAdd) % TimeOfDay.hoursPerDay,
|
||||
);
|
||||
} else {
|
||||
// Cycle 1 through 12 without changing day period.
|
||||
final int periodOffset = fragmentContext.selectedTime.periodOffset;
|
||||
final int hours = fragmentContext.selectedTime.hourOfPeriod;
|
||||
final periodOffset = fragmentContext.selectedTime.periodOffset;
|
||||
final hours = fragmentContext.selectedTime.hourOfPeriod;
|
||||
return fragmentContext.selectedTime.replacing(
|
||||
hour: periodOffset + (hours + hoursToAdd) % TimeOfDay.hoursPerPeriod,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
final TimeOfDay nextHour = hoursFromSelected(1);
|
||||
final String formattedNextHour = localizations.formatHour(
|
||||
final nextHour = hoursFromSelected(1);
|
||||
final formattedNextHour = localizations.formatHour(
|
||||
nextHour,
|
||||
alwaysUse24HourFormat: alwaysUse24HourFormat,
|
||||
);
|
||||
final TimeOfDay previousHour = hoursFromSelected(-1);
|
||||
final String formattedPreviousHour = localizations.formatHour(
|
||||
final previousHour = hoursFromSelected(-1);
|
||||
final formattedPreviousHour = localizations.formatHour(
|
||||
previousHour,
|
||||
alwaysUse24HourFormat: alwaysUse24HourFormat,
|
||||
);
|
||||
@ -381,11 +377,11 @@ class _StringFragment extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final ThemeData theme = Theme.of(context);
|
||||
final TimePickerThemeData timePickerTheme = TimePickerTheme.of(context);
|
||||
final TextStyle hourMinuteStyle =
|
||||
final theme = Theme.of(context);
|
||||
final timePickerTheme = TimePickerTheme.of(context);
|
||||
final hourMinuteStyle =
|
||||
timePickerTheme.hourMinuteTextStyle ?? theme.textTheme.headline2;
|
||||
final Color textColor =
|
||||
final textColor =
|
||||
timePickerTheme.hourMinuteTextColor ?? theme.colorScheme.onSurface;
|
||||
|
||||
return ExcludeSemantics(
|
||||
@ -417,21 +413,19 @@ class _MinuteControl extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final MaterialLocalizations localizations =
|
||||
MaterialLocalizations.of(context);
|
||||
final String formattedMinute =
|
||||
final localizations = MaterialLocalizations.of(context);
|
||||
final formattedMinute =
|
||||
localizations.formatMinute(fragmentContext.selectedTime);
|
||||
final TimeOfDay nextMinute = fragmentContext.selectedTime.replacing(
|
||||
final nextMinute = fragmentContext.selectedTime.replacing(
|
||||
minute:
|
||||
(fragmentContext.selectedTime.minute + 1) % TimeOfDay.minutesPerHour,
|
||||
);
|
||||
final String formattedNextMinute = localizations.formatMinute(nextMinute);
|
||||
final TimeOfDay previousMinute = fragmentContext.selectedTime.replacing(
|
||||
final formattedNextMinute = localizations.formatMinute(nextMinute);
|
||||
final previousMinute = fragmentContext.selectedTime.replacing(
|
||||
minute:
|
||||
(fragmentContext.selectedTime.minute - 1) % TimeOfDay.minutesPerHour,
|
||||
);
|
||||
final String formattedPreviousMinute =
|
||||
localizations.formatMinute(previousMinute);
|
||||
final formattedPreviousMinute = localizations.formatMinute(previousMinute);
|
||||
|
||||
return Semantics(
|
||||
excludeSemantics: true,
|
||||
@ -470,9 +464,9 @@ class _DayPeriodControl extends StatelessWidget {
|
||||
final ValueChanged<TimeOfDay> onChanged;
|
||||
|
||||
void _togglePeriod() {
|
||||
final int newHour =
|
||||
final newHour =
|
||||
(selectedTime.hour + TimeOfDay.hoursPerPeriod) % TimeOfDay.hoursPerDay;
|
||||
final TimeOfDay newTime = selectedTime.replacing(hour: newHour);
|
||||
final newTime = selectedTime.replacing(hour: newHour);
|
||||
onChanged(newTime);
|
||||
}
|
||||
|
||||
@ -516,19 +510,18 @@ class _DayPeriodControl extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final MaterialLocalizations materialLocalizations =
|
||||
MaterialLocalizations.of(context);
|
||||
final ColorScheme colorScheme = Theme.of(context).colorScheme;
|
||||
final TimePickerThemeData timePickerTheme = TimePickerTheme.of(context);
|
||||
final bool isDark = colorScheme.brightness == Brightness.dark;
|
||||
final Color textColor = timePickerTheme.dayPeriodTextColor ??
|
||||
MaterialStateColor.resolveWith((Set<MaterialState> states) {
|
||||
final materialLocalizations = MaterialLocalizations.of(context);
|
||||
final colorScheme = Theme.of(context).colorScheme;
|
||||
final timePickerTheme = TimePickerTheme.of(context);
|
||||
final isDark = colorScheme.brightness == Brightness.dark;
|
||||
final textColor = timePickerTheme.dayPeriodTextColor ??
|
||||
MaterialStateColor.resolveWith((states) {
|
||||
return states.contains(MaterialState.selected)
|
||||
? colorScheme.primary
|
||||
: colorScheme.onSurface.withOpacity(0.60);
|
||||
});
|
||||
final Color backgroundColor = timePickerTheme.dayPeriodColor ??
|
||||
MaterialStateColor.resolveWith((Set<MaterialState> states) {
|
||||
final backgroundColor = timePickerTheme.dayPeriodColor ??
|
||||
MaterialStateColor.resolveWith((states) {
|
||||
// The unselected day period should match the overall picker dialog
|
||||
// color. Making it transparent enables that without being redundant
|
||||
// and allows the optional elevation overlay for dark mode to be
|
||||
@ -537,25 +530,25 @@ class _DayPeriodControl extends StatelessWidget {
|
||||
? colorScheme.primary.withOpacity(isDark ? 0.24 : 0.12)
|
||||
: Colors.transparent;
|
||||
});
|
||||
final bool amSelected = selectedTime.period == DayPeriod.am;
|
||||
final Set<MaterialState> amStates = amSelected
|
||||
final amSelected = selectedTime.period == DayPeriod.am;
|
||||
final amStates = amSelected
|
||||
? <MaterialState>{MaterialState.selected}
|
||||
: <MaterialState>{};
|
||||
final bool pmSelected = !amSelected;
|
||||
final Set<MaterialState> pmStates = pmSelected
|
||||
final pmSelected = !amSelected;
|
||||
final pmStates = pmSelected
|
||||
? <MaterialState>{MaterialState.selected}
|
||||
: <MaterialState>{};
|
||||
final TextStyle textStyle = timePickerTheme.dayPeriodTextStyle ??
|
||||
final textStyle = timePickerTheme.dayPeriodTextStyle ??
|
||||
Theme.of(context).textTheme.subtitle1;
|
||||
final TextStyle amStyle = textStyle.copyWith(
|
||||
final amStyle = textStyle.copyWith(
|
||||
color: MaterialStateProperty.resolveAs(textColor, amStates),
|
||||
);
|
||||
final TextStyle pmStyle = textStyle.copyWith(
|
||||
final pmStyle = textStyle.copyWith(
|
||||
color: MaterialStateProperty.resolveAs(textColor, pmStates),
|
||||
);
|
||||
OutlinedBorder shape = timePickerTheme.dayPeriodShape ??
|
||||
var shape = timePickerTheme.dayPeriodShape ??
|
||||
const RoundedRectangleBorder(borderRadius: _kDefaultBorderRadius);
|
||||
final BorderSide borderSide = timePickerTheme.dayPeriodBorderSide ??
|
||||
final borderSide = timePickerTheme.dayPeriodBorderSide ??
|
||||
BorderSide(
|
||||
color: Color.alphaBlend(
|
||||
colorScheme.onBackground.withOpacity(0.38), colorScheme.surface),
|
||||
@ -565,7 +558,7 @@ class _DayPeriodControl extends StatelessWidget {
|
||||
side: borderSide,
|
||||
);
|
||||
|
||||
final double buttonTextScaleFactor =
|
||||
final buttonTextScaleFactor =
|
||||
math.min(MediaQuery.of(context).textScaleFactor, 2.0);
|
||||
|
||||
final Widget amButton = Material(
|
||||
@ -605,7 +598,7 @@ class _DayPeriodControl extends StatelessWidget {
|
||||
Widget result;
|
||||
switch (orientation) {
|
||||
case Orientation.portrait:
|
||||
const double width = 52.0;
|
||||
const width = 52.0;
|
||||
result = _DayPeriodInputPadding(
|
||||
minSize: const Size(width, kMinInteractiveDimension * 2),
|
||||
orientation: orientation,
|
||||
@ -737,10 +730,10 @@ class _RenderInputPadding extends RenderShiftedBox {
|
||||
void performLayout() {
|
||||
if (child != null) {
|
||||
child.layout(constraints, parentUsesSize: true);
|
||||
final double width = math.max(child.size.width, minSize.width);
|
||||
final double height = math.max(child.size.height, minSize.height);
|
||||
final width = math.max(child.size.width, minSize.width);
|
||||
final height = math.max(child.size.height, minSize.height);
|
||||
size = constraints.constrain(Size(width, height));
|
||||
final BoxParentData childParentData = child.parentData as BoxParentData;
|
||||
final childParentData = child.parentData as BoxParentData;
|
||||
childParentData.offset =
|
||||
Alignment.center.alongOffset(size - child.size as Offset);
|
||||
} else {
|
||||
@ -761,7 +754,7 @@ class _RenderInputPadding extends RenderShiftedBox {
|
||||
return false;
|
||||
}
|
||||
|
||||
Offset newPosition = child.size.center(Offset.zero);
|
||||
var newPosition = child.size.center(Offset.zero);
|
||||
switch (orientation) {
|
||||
case Orientation.portrait:
|
||||
if (position.dy > newPosition.dy) {
|
||||
@ -782,7 +775,7 @@ class _RenderInputPadding extends RenderShiftedBox {
|
||||
return result.addWithRawTransform(
|
||||
transform: MatrixUtils.forceToPoint(newPosition),
|
||||
position: newPosition,
|
||||
hitTest: (BoxHitTestResult result, Offset position) {
|
||||
hitTest: (result, position) {
|
||||
assert(position == newPosition);
|
||||
return child.hitTest(result, position: newPosition);
|
||||
},
|
||||
@ -832,12 +825,12 @@ class _DialPainter extends CustomPainter {
|
||||
|
||||
@override
|
||||
void paint(Canvas canvas, Size size) {
|
||||
final double radius = size.shortestSide / 2.0;
|
||||
final Offset center = Offset(size.width / 2.0, size.height / 2.0);
|
||||
final Offset centerPoint = center;
|
||||
final radius = size.shortestSide / 2.0;
|
||||
final center = Offset(size.width / 2.0, size.height / 2.0);
|
||||
final centerPoint = center;
|
||||
canvas.drawCircle(centerPoint, radius, Paint()..color = backgroundColor);
|
||||
|
||||
final double labelRadius = radius - _labelPadding;
|
||||
final labelRadius = radius - _labelPadding;
|
||||
Offset getOffsetForTheta(double theta) {
|
||||
return center +
|
||||
Offset(labelRadius * math.cos(theta), -labelRadius * math.sin(theta));
|
||||
@ -845,12 +838,12 @@ class _DialPainter extends CustomPainter {
|
||||
|
||||
void paintLabels(List<_TappableLabel> labels) {
|
||||
if (labels == null) return;
|
||||
final double labelThetaIncrement = -_kTwoPi / labels.length;
|
||||
double labelTheta = math.pi / 2.0;
|
||||
final labelThetaIncrement = -_kTwoPi / labels.length;
|
||||
var labelTheta = math.pi / 2.0;
|
||||
|
||||
for (final _TappableLabel label in labels) {
|
||||
final TextPainter labelPainter = label.painter;
|
||||
final Offset labelOffset =
|
||||
for (final label in labels) {
|
||||
final labelPainter = label.painter;
|
||||
final labelOffset =
|
||||
Offset(-labelPainter.width / 2.0, -labelPainter.height / 2.0);
|
||||
labelPainter.paint(canvas, getOffsetForTheta(labelTheta) + labelOffset);
|
||||
labelTheta += labelThetaIncrement;
|
||||
@ -859,9 +852,9 @@ class _DialPainter extends CustomPainter {
|
||||
|
||||
paintLabels(primaryLabels);
|
||||
|
||||
final Paint selectorPaint = Paint()..color = accentColor;
|
||||
final Offset focusedPoint = getOffsetForTheta(theta);
|
||||
const double focusedRadius = _labelPadding - 4.0;
|
||||
final selectorPaint = Paint()..color = accentColor;
|
||||
final focusedPoint = getOffsetForTheta(theta);
|
||||
const focusedRadius = _labelPadding - 4.0;
|
||||
canvas.drawCircle(centerPoint, 4.0, selectorPaint);
|
||||
canvas.drawCircle(focusedPoint, focusedRadius, selectorPaint);
|
||||
selectorPaint.strokeWidth = 2.0;
|
||||
@ -871,13 +864,13 @@ class _DialPainter extends CustomPainter {
|
||||
// This checks that the selector's theta is between two labels. A remainder
|
||||
// between 0.1 and 0.45 indicates that the selector is roughly not above any
|
||||
// labels. The values were derived by manually testing the dial.
|
||||
final double labelThetaIncrement = -_kTwoPi / primaryLabels.length;
|
||||
final labelThetaIncrement = -_kTwoPi / primaryLabels.length;
|
||||
if (theta % labelThetaIncrement > 0.1 &&
|
||||
theta % labelThetaIncrement < 0.45) {
|
||||
canvas.drawCircle(focusedPoint, 2.0, selectorPaint..color = dotColor);
|
||||
}
|
||||
|
||||
final Rect focusedRect = Rect.fromCircle(
|
||||
final focusedRect = Rect.fromCircle(
|
||||
center: focusedPoint,
|
||||
radius: focusedRadius,
|
||||
);
|
||||
@ -972,8 +965,8 @@ class _DialState extends State<_Dial> with SingleTickerProviderStateMixin {
|
||||
}
|
||||
|
||||
void _animateTo(double targetTheta) {
|
||||
final double currentTheta = _theta.value;
|
||||
double beginTheta =
|
||||
final currentTheta = _theta.value;
|
||||
var beginTheta =
|
||||
_nearest(targetTheta, currentTheta, currentTheta + _kTwoPi);
|
||||
beginTheta = _nearest(targetTheta, beginTheta, currentTheta - _kTwoPi);
|
||||
_thetaTween
|
||||
@ -985,17 +978,17 @@ class _DialState extends State<_Dial> with SingleTickerProviderStateMixin {
|
||||
}
|
||||
|
||||
double _getThetaForTime(TimeOfDay time) {
|
||||
final int hoursFactor = widget.use24HourDials
|
||||
final hoursFactor = widget.use24HourDials
|
||||
? TimeOfDay.hoursPerDay
|
||||
: TimeOfDay.hoursPerPeriod;
|
||||
final double fraction = widget.mode == _TimePickerMode.hour
|
||||
final fraction = widget.mode == _TimePickerMode.hour
|
||||
? (time.hour / hoursFactor) % hoursFactor
|
||||
: (time.minute / TimeOfDay.minutesPerHour) % TimeOfDay.minutesPerHour;
|
||||
return (math.pi / 2.0 - fraction * _kTwoPi) % _kTwoPi;
|
||||
}
|
||||
|
||||
TimeOfDay _getTimeForTheta(double theta, {bool roundMinutes = false}) {
|
||||
final double fraction = (0.25 - (theta % _kTwoPi) / _kTwoPi) % 1.0;
|
||||
final fraction = (0.25 - (theta % _kTwoPi) / _kTwoPi) % 1.0;
|
||||
if (widget.mode == _TimePickerMode.hour) {
|
||||
int newHour;
|
||||
if (widget.use24HourDials) {
|
||||
@ -1008,7 +1001,7 @@ class _DialState extends State<_Dial> with SingleTickerProviderStateMixin {
|
||||
}
|
||||
return widget.selectedTime.replacing(hour: newHour);
|
||||
} else {
|
||||
int minute = (fraction * TimeOfDay.minutesPerHour).round() %
|
||||
var minute = (fraction * TimeOfDay.minutesPerHour).round() %
|
||||
TimeOfDay.minutesPerHour;
|
||||
if (roundMinutes) {
|
||||
// Round the minutes to nearest 5 minute interval.
|
||||
@ -1019,8 +1012,7 @@ class _DialState extends State<_Dial> with SingleTickerProviderStateMixin {
|
||||
}
|
||||
|
||||
TimeOfDay _notifyOnChangedIfNeeded({bool roundMinutes = false}) {
|
||||
final TimeOfDay current =
|
||||
_getTimeForTheta(_theta.value, roundMinutes: roundMinutes);
|
||||
final current = _getTimeForTheta(_theta.value, roundMinutes: roundMinutes);
|
||||
if (widget.onChanged == null) return current;
|
||||
if (current != widget.selectedTime) widget.onChanged(current);
|
||||
return current;
|
||||
@ -1028,9 +1020,8 @@ class _DialState extends State<_Dial> with SingleTickerProviderStateMixin {
|
||||
|
||||
void _updateThetaForPan({bool roundMinutes = false}) {
|
||||
setState(() {
|
||||
final Offset offset = _position - _center;
|
||||
double angle =
|
||||
(math.atan2(offset.dx, offset.dy) - math.pi / 2.0) % _kTwoPi;
|
||||
final offset = _position - _center;
|
||||
var angle = (math.atan2(offset.dx, offset.dy) - math.pi / 2.0) % _kTwoPi;
|
||||
if (roundMinutes) {
|
||||
angle = _getThetaForTime(
|
||||
_getTimeForTheta(angle, roundMinutes: roundMinutes));
|
||||
@ -1047,7 +1038,7 @@ class _DialState extends State<_Dial> with SingleTickerProviderStateMixin {
|
||||
void _handlePanStart(DragStartDetails details) {
|
||||
assert(!_dragging);
|
||||
_dragging = true;
|
||||
final RenderBox box = context.findRenderObject() as RenderBox;
|
||||
final box = context.findRenderObject() as RenderBox;
|
||||
_position = box.globalToLocal(details.globalPosition);
|
||||
_center = box.size.center(Offset.zero);
|
||||
_updateThetaForPan();
|
||||
@ -1074,11 +1065,11 @@ class _DialState extends State<_Dial> with SingleTickerProviderStateMixin {
|
||||
}
|
||||
|
||||
void _handleTapUp(TapUpDetails details) {
|
||||
final RenderBox box = context.findRenderObject() as RenderBox;
|
||||
final box = context.findRenderObject() as RenderBox;
|
||||
_position = box.globalToLocal(details.globalPosition);
|
||||
_center = box.size.center(Offset.zero);
|
||||
_updateThetaForPan(roundMinutes: true);
|
||||
final TimeOfDay newTime = _notifyOnChangedIfNeeded(roundMinutes: true);
|
||||
final newTime = _notifyOnChangedIfNeeded(roundMinutes: true);
|
||||
if (widget.mode == _TimePickerMode.hour) {
|
||||
if (widget.use24HourDials) {
|
||||
_announceToAccessibility(
|
||||
@ -1115,7 +1106,7 @@ class _DialState extends State<_Dial> with SingleTickerProviderStateMixin {
|
||||
minute: widget.selectedTime.minute);
|
||||
}
|
||||
}
|
||||
final double angle = _getThetaForTime(time);
|
||||
final angle = _getThetaForTime(time);
|
||||
_thetaTween
|
||||
..begin = angle
|
||||
..end = angle;
|
||||
@ -1124,11 +1115,11 @@ class _DialState extends State<_Dial> with SingleTickerProviderStateMixin {
|
||||
|
||||
void _selectMinute(int minute) {
|
||||
_announceToAccessibility(context, localizations.formatDecimal(minute));
|
||||
final TimeOfDay time = TimeOfDay(
|
||||
final time = TimeOfDay(
|
||||
hour: widget.selectedTime.hour,
|
||||
minute: minute,
|
||||
);
|
||||
final double angle = _getThetaForTime(time);
|
||||
final angle = _getThetaForTime(time);
|
||||
_thetaTween
|
||||
..begin = angle
|
||||
..end = angle;
|
||||
@ -1167,8 +1158,8 @@ class _DialState extends State<_Dial> with SingleTickerProviderStateMixin {
|
||||
|
||||
_TappableLabel _buildTappableLabel(TextTheme textTheme, Color color,
|
||||
int value, String label, VoidCallback onTap) {
|
||||
final TextStyle style = textTheme.subtitle1.copyWith(color: color);
|
||||
final double labelScaleFactor =
|
||||
final style = textTheme.subtitle1.copyWith(color: color);
|
||||
final labelScaleFactor =
|
||||
math.min(MediaQuery.of(context).textScaleFactor, 2.0);
|
||||
return _TappableLabel(
|
||||
value: value,
|
||||
@ -1212,7 +1203,7 @@ class _DialState extends State<_Dial> with SingleTickerProviderStateMixin {
|
||||
];
|
||||
|
||||
List<_TappableLabel> _buildMinutes(TextTheme textTheme, Color color) {
|
||||
const List<TimeOfDay> _minuteMarkerValues = <TimeOfDay>[
|
||||
const _minuteMarkerValues = <TimeOfDay>[
|
||||
TimeOfDay(hour: 0, minute: 0),
|
||||
TimeOfDay(hour: 0, minute: 5),
|
||||
TimeOfDay(hour: 0, minute: 10),
|
||||
@ -1243,15 +1234,14 @@ class _DialState extends State<_Dial> with SingleTickerProviderStateMixin {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final ThemeData theme = Theme.of(context);
|
||||
final TimePickerThemeData pickerTheme = TimePickerTheme.of(context);
|
||||
final Color backgroundColor = pickerTheme.dialBackgroundColor ??
|
||||
final theme = Theme.of(context);
|
||||
final pickerTheme = TimePickerTheme.of(context);
|
||||
final backgroundColor = pickerTheme.dialBackgroundColor ??
|
||||
themeData.colorScheme.onBackground.withOpacity(0.12);
|
||||
final Color accentColor =
|
||||
pickerTheme.dialHandColor ?? themeData.accentColor;
|
||||
final Color primaryLabelColor = MaterialStateProperty.resolveAs(
|
||||
final accentColor = pickerTheme.dialHandColor ?? themeData.accentColor;
|
||||
final primaryLabelColor = MaterialStateProperty.resolveAs(
|
||||
pickerTheme.dialTextColor, <MaterialState>{});
|
||||
final Color secondaryLabelColor = MaterialStateProperty.resolveAs(
|
||||
final secondaryLabelColor = MaterialStateProperty.resolveAs(
|
||||
pickerTheme.dialTextColor, <MaterialState>{MaterialState.selected});
|
||||
List<_TappableLabel> primaryLabels;
|
||||
List<_TappableLabel> secondaryLabels;
|
||||
@ -1339,7 +1329,7 @@ class _TimePickerInputState extends State<_TimePickerInput> {
|
||||
return null;
|
||||
}
|
||||
|
||||
int newHour = int.tryParse(value);
|
||||
var newHour = int.tryParse(value);
|
||||
if (newHour == null) {
|
||||
return null;
|
||||
}
|
||||
@ -1366,7 +1356,7 @@ class _TimePickerInputState extends State<_TimePickerInput> {
|
||||
return null;
|
||||
}
|
||||
|
||||
final int newMinute = int.tryParse(value);
|
||||
final newMinute = int.tryParse(value);
|
||||
if (newMinute == null) {
|
||||
return null;
|
||||
}
|
||||
@ -1378,7 +1368,7 @@ class _TimePickerInputState extends State<_TimePickerInput> {
|
||||
}
|
||||
|
||||
void _handleHourSavedSubmitted(String value) {
|
||||
final int newHour = _parseHour(value);
|
||||
final newHour = _parseHour(value);
|
||||
if (newHour != null) {
|
||||
_selectedTime = TimeOfDay(hour: newHour, minute: _selectedTime.minute);
|
||||
widget.onChanged(_selectedTime);
|
||||
@ -1386,7 +1376,7 @@ class _TimePickerInputState extends State<_TimePickerInput> {
|
||||
}
|
||||
|
||||
void _handleHourChanged(String value) {
|
||||
final int newHour = _parseHour(value);
|
||||
final newHour = _parseHour(value);
|
||||
if (newHour != null && value.length == 2) {
|
||||
// If a valid hour is typed, move focus to the minute TextField.
|
||||
FocusScope.of(context).nextFocus();
|
||||
@ -1394,7 +1384,7 @@ class _TimePickerInputState extends State<_TimePickerInput> {
|
||||
}
|
||||
|
||||
void _handleMinuteSavedSubmitted(String value) {
|
||||
final int newMinute = _parseMinute(value);
|
||||
final newMinute = _parseMinute(value);
|
||||
if (newMinute != null) {
|
||||
_selectedTime =
|
||||
TimeOfDay(hour: _selectedTime.hour, minute: int.parse(value));
|
||||
@ -1408,7 +1398,7 @@ class _TimePickerInputState extends State<_TimePickerInput> {
|
||||
}
|
||||
|
||||
String _validateHour(String value) {
|
||||
final int newHour = _parseHour(value);
|
||||
final newHour = _parseHour(value);
|
||||
setState(() {
|
||||
hourHasError = newHour == null;
|
||||
});
|
||||
@ -1419,7 +1409,7 @@ class _TimePickerInputState extends State<_TimePickerInput> {
|
||||
}
|
||||
|
||||
String _validateMinute(String value) {
|
||||
final int newMinute = _parseMinute(value);
|
||||
final newMinute = _parseMinute(value);
|
||||
setState(() {
|
||||
minuteHasError = newMinute == null;
|
||||
});
|
||||
@ -1432,14 +1422,13 @@ class _TimePickerInputState extends State<_TimePickerInput> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
assert(debugCheckHasMediaQuery(context));
|
||||
final MediaQueryData media = MediaQuery.of(context);
|
||||
final TimeOfDayFormat timeOfDayFormat = MaterialLocalizations.of(context)
|
||||
final media = MediaQuery.of(context);
|
||||
final timeOfDayFormat = MaterialLocalizations.of(context)
|
||||
.timeOfDayFormat(alwaysUse24HourFormat: media.alwaysUse24HourFormat);
|
||||
final bool use24HourDials = hourFormat(of: timeOfDayFormat) != HourFormat.h;
|
||||
final ThemeData theme = Theme.of(context);
|
||||
final TextStyle hourMinuteStyle =
|
||||
TimePickerTheme.of(context).hourMinuteTextStyle ??
|
||||
theme.textTheme.headline2;
|
||||
final use24HourDials = hourFormat(of: timeOfDayFormat) != HourFormat.h;
|
||||
final theme = Theme.of(context);
|
||||
final hourMinuteStyle = TimePickerTheme.of(context).hourMinuteTextStyle ??
|
||||
theme.textTheme.headline2;
|
||||
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 24.0, vertical: 16.0),
|
||||
@ -1588,10 +1577,8 @@ class _HourMinuteTextFieldState extends State<_HourMinuteTextField> {
|
||||
}
|
||||
|
||||
String get _formattedValue {
|
||||
final bool alwaysUse24HourFormat =
|
||||
MediaQuery.of(context).alwaysUse24HourFormat;
|
||||
final MaterialLocalizations localizations =
|
||||
MaterialLocalizations.of(context);
|
||||
final alwaysUse24HourFormat = MediaQuery.of(context).alwaysUse24HourFormat;
|
||||
final localizations = MaterialLocalizations.of(context);
|
||||
return !widget.isHour
|
||||
? localizations.formatMinute(widget.selectedTime)
|
||||
: localizations.formatHour(
|
||||
@ -1602,18 +1589,17 @@ class _HourMinuteTextFieldState extends State<_HourMinuteTextField> {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final ThemeData theme = Theme.of(context);
|
||||
final TimePickerThemeData timePickerTheme = TimePickerTheme.of(context);
|
||||
final ColorScheme colorScheme = theme.colorScheme;
|
||||
final theme = Theme.of(context);
|
||||
final timePickerTheme = TimePickerTheme.of(context);
|
||||
final colorScheme = theme.colorScheme;
|
||||
|
||||
final InputDecorationTheme inputDecorationTheme =
|
||||
timePickerTheme.inputDecorationTheme;
|
||||
final inputDecorationTheme = timePickerTheme.inputDecorationTheme;
|
||||
InputDecoration inputDecoration;
|
||||
if (inputDecorationTheme != null) {
|
||||
inputDecoration =
|
||||
const InputDecoration().applyDefaults(inputDecorationTheme);
|
||||
} else {
|
||||
final Color unfocusedFillColor = timePickerTheme.hourMinuteColor ??
|
||||
final unfocusedFillColor = timePickerTheme.hourMinuteColor ??
|
||||
colorScheme.onSurface.withOpacity(0.12);
|
||||
inputDecoration = InputDecoration(
|
||||
contentPadding: EdgeInsets.zero,
|
||||
@ -1807,9 +1793,8 @@ class _TimePickerDialogState extends State<_TimePickerDialog> {
|
||||
void _announceInitialTimeOnce() {
|
||||
if (_announcedInitialTime) return;
|
||||
|
||||
final MediaQueryData media = MediaQuery.of(context);
|
||||
final MaterialLocalizations localizations =
|
||||
MaterialLocalizations.of(context);
|
||||
final media = MediaQuery.of(context);
|
||||
final localizations = MaterialLocalizations.of(context);
|
||||
_announceToAccessibility(
|
||||
context,
|
||||
localizations.formatTimeOfDay(widget.initialTime,
|
||||
@ -1837,7 +1822,7 @@ class _TimePickerDialogState extends State<_TimePickerDialog> {
|
||||
|
||||
void _handleOk() {
|
||||
if (_entryMode == TimePickerEntryMode.input) {
|
||||
final FormState form = _formKey.currentState;
|
||||
final form = _formKey.currentState;
|
||||
if (!form.validate()) {
|
||||
setState(() {
|
||||
_autoValidate = true;
|
||||
@ -1850,12 +1835,12 @@ class _TimePickerDialogState extends State<_TimePickerDialog> {
|
||||
}
|
||||
|
||||
Size _dialogSize(BuildContext context) {
|
||||
final Orientation orientation = MediaQuery.of(context).orientation;
|
||||
final ThemeData theme = Theme.of(context);
|
||||
final orientation = MediaQuery.of(context).orientation;
|
||||
final theme = Theme.of(context);
|
||||
// Constrain the textScaleFactor to prevent layout issues. Since only some
|
||||
// parts of the time picker scale up with textScaleFactor, we cap the factor
|
||||
// to 1.1 as that provides enough space to reasonably fit all the content.
|
||||
final double textScaleFactor =
|
||||
final textScaleFactor =
|
||||
math.min(MediaQuery.of(context).textScaleFactor, 1.1);
|
||||
|
||||
double timePickerWidth;
|
||||
@ -1890,14 +1875,13 @@ class _TimePickerDialogState extends State<_TimePickerDialog> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
assert(debugCheckHasMediaQuery(context));
|
||||
final MediaQueryData media = MediaQuery.of(context);
|
||||
final TimeOfDayFormat timeOfDayFormat = localizations.timeOfDayFormat(
|
||||
final media = MediaQuery.of(context);
|
||||
final timeOfDayFormat = localizations.timeOfDayFormat(
|
||||
alwaysUse24HourFormat: media.alwaysUse24HourFormat);
|
||||
final bool use24HourDials = hourFormat(of: timeOfDayFormat) != HourFormat.h;
|
||||
final ThemeData theme = Theme.of(context);
|
||||
final ShapeBorder shape =
|
||||
TimePickerTheme.of(context).shape ?? _kDefaultShape;
|
||||
final Orientation orientation = media.orientation;
|
||||
final use24HourDials = hourFormat(of: timeOfDayFormat) != HourFormat.h;
|
||||
final theme = Theme.of(context);
|
||||
final shape = TimePickerTheme.of(context).shape ?? _kDefaultShape;
|
||||
final orientation = media.orientation;
|
||||
|
||||
final Widget actions = Row(
|
||||
children: <Widget>[
|
||||
@ -1924,7 +1908,7 @@ class _TimePickerDialogState extends State<_TimePickerDialog> {
|
||||
onPressed: _handleCancel,
|
||||
child: Text(
|
||||
widget.cancelText ?? localizations.cancelButtonLabel,
|
||||
style: TextStyle(color: Theme.of(context).accentColor),
|
||||
style: TextStyle(color: Colors.grey[600]),
|
||||
),
|
||||
),
|
||||
FlatButton(
|
||||
@ -2029,7 +2013,7 @@ class _TimePickerDialogState extends State<_TimePickerDialog> {
|
||||
break;
|
||||
}
|
||||
|
||||
final Size dialogSize = _dialogSize(context);
|
||||
final dialogSize = _dialogSize(context);
|
||||
return Dialog(
|
||||
shape: shape,
|
||||
elevation: 2,
|
||||
@ -2166,7 +2150,7 @@ Future<TimeOfDay> showCustomTimePicker({
|
||||
? Color.fromRGBO(113, 113, 113, 1)
|
||||
: Color.fromRGBO(15, 15, 15, 1),
|
||||
),
|
||||
child: Builder(builder: (BuildContext context) {
|
||||
child: Builder(builder: (context) {
|
||||
return builder == null ? dialog : builder(context, dialog);
|
||||
}),
|
||||
//routeSettings: routeSettings,
|
||||
|
@ -2,6 +2,7 @@ import 'dart:io';
|
||||
import 'dart:math' as math;
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:tsacdop/type/episodebrief.dart';
|
||||
|
||||
import 'episodegrid.dart';
|
||||
import 'extension_helper.dart';
|
||||
@ -587,9 +588,8 @@ class _LineLoaderState extends State<LineLoader>
|
||||
}
|
||||
|
||||
class ImageRotate extends StatefulWidget {
|
||||
final String title;
|
||||
final String path;
|
||||
ImageRotate({this.title, this.path, Key key}) : super(key: key);
|
||||
final EpisodeBrief episodeItem;
|
||||
ImageRotate({this.episodeItem, Key key}) : super(key: key);
|
||||
@override
|
||||
_ImageRotateState createState() => _ImageRotateState();
|
||||
}
|
||||
@ -599,6 +599,7 @@ class _ImageRotateState extends State<ImageRotate>
|
||||
Animation _animation;
|
||||
AnimationController _controller;
|
||||
double _value;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
@ -635,16 +636,14 @@ class _ImageRotateState extends State<ImageRotate>
|
||||
Widget build(BuildContext context) {
|
||||
return Transform.rotate(
|
||||
angle: 2 * math.pi * _value,
|
||||
child: Container(
|
||||
padding: EdgeInsets.all(10.0),
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.all(Radius.circular(15.0)),
|
||||
child: Container(
|
||||
height: 30.0,
|
||||
width: 30.0,
|
||||
color: Colors.white,
|
||||
child: Image.file(File("${widget.path}")),
|
||||
),
|
||||
child: Padding(
|
||||
padding: EdgeInsets.symmetric(vertical: 10.0),
|
||||
child: SizedBox(
|
||||
width: 30,
|
||||
height: 30,
|
||||
child: CircleAvatar(
|
||||
backgroundColor: widget.episodeItem.backgroudColor(context),
|
||||
backgroundImage: widget.episodeItem.avatarImage),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
@ -1,4 +1,3 @@
|
||||
import 'dart:io';
|
||||
import 'dart:ui';
|
||||
|
||||
import 'package:auto_animated/auto_animated.dart';
|
||||
@ -134,8 +133,7 @@ class EpisodeGrid extends StatelessWidget {
|
||||
? Center()
|
||||
: CircleAvatar(
|
||||
backgroundColor: color.withOpacity(0.5),
|
||||
backgroundImage: FileImage(File("${episode.imagePath}")),
|
||||
),
|
||||
backgroundImage: episode.avatarImage),
|
||||
);
|
||||
|
||||
Widget _downloadIndicater(BuildContext context,
|
||||
@ -227,9 +225,7 @@ class EpisodeGrid extends StatelessWidget {
|
||||
crossAxisSpacing: 6.0,
|
||||
),
|
||||
itemBuilder: (context, index, animation) {
|
||||
var _c = (Theme.of(context).brightness == Brightness.light)
|
||||
? episodes[index].primaryColor.colorizedark()
|
||||
: episodes[index].primaryColor.colorizeLight();
|
||||
final c = episodes[index].backgroudColor(context);
|
||||
scrollController.addListener(() {});
|
||||
|
||||
return FadeTransition(
|
||||
@ -463,11 +459,11 @@ class EpisodeGrid extends StatelessWidget {
|
||||
layout != Layout.one
|
||||
? _circleImage(context,
|
||||
episode: episodes[index],
|
||||
color: _c,
|
||||
color: c,
|
||||
boo: boo)
|
||||
: _pubDate(context,
|
||||
episode: episodes[index],
|
||||
color: _c),
|
||||
color: c),
|
||||
Spacer(),
|
||||
// _listenIndicater(context,
|
||||
// episode: episodes[index],
|
||||
@ -477,7 +473,7 @@ class EpisodeGrid extends StatelessWidget {
|
||||
episode: episodes[index],
|
||||
isDownloaded: isDownloaded),
|
||||
_numberIndicater(context,
|
||||
index: index, color: _c)
|
||||
index: index, color: c)
|
||||
],
|
||||
),
|
||||
),
|
||||
@ -491,7 +487,7 @@ class EpisodeGrid extends StatelessWidget {
|
||||
children: [
|
||||
_circleImage(context,
|
||||
episode: episodes[index],
|
||||
color: _c,
|
||||
color: c,
|
||||
boo: boo),
|
||||
SizedBox(
|
||||
width: 5,
|
||||
@ -513,7 +509,7 @@ class EpisodeGrid extends StatelessWidget {
|
||||
if (layout != Layout.one)
|
||||
_pubDate(context,
|
||||
episode: episodes[index],
|
||||
color: _c),
|
||||
color: c),
|
||||
Spacer(),
|
||||
if (layout != Layout.three &&
|
||||
episodes[index].duration != 0)
|
||||
@ -600,9 +596,7 @@ class OpenContainerWrapper extends StatelessWidget {
|
||||
builder: (_, data, __) => OpenContainer(
|
||||
playerRunning: data.item1,
|
||||
playerHeight: kMinPlayerHeight[data.item2.index],
|
||||
flightWidget: CircleAvatar(
|
||||
backgroundImage: FileImage(File("${episode.imagePath}")),
|
||||
),
|
||||
flightWidget: CircleAvatar(backgroundImage: episode.avatarImage),
|
||||
transitionDuration: Duration(milliseconds: 400),
|
||||
beginColor: Theme.of(context).primaryColor,
|
||||
endColor: Theme.of(context).primaryColor,
|
||||
|
@ -73,28 +73,26 @@ extension StringExtension on String {
|
||||
}
|
||||
|
||||
Color colorizedark() {
|
||||
Color _c;
|
||||
Color c;
|
||||
var color = json.decode(this);
|
||||
if (color[0] > 200 && color[1] > 200 && color[2] > 200) {
|
||||
_c =
|
||||
Color.fromRGBO((255 - color[0]), 255 - color[1], 255 - color[2], 1.0);
|
||||
c = Color.fromRGBO((255 - color[0]), 255 - color[1], 255 - color[2], 1.0);
|
||||
} else {
|
||||
_c = Color.fromRGBO(color[0], color[1] > 200 ? 190 : color[1],
|
||||
c = Color.fromRGBO(color[0], color[1] > 200 ? 190 : color[1],
|
||||
color[2] > 200 ? 190 : color[2], 1);
|
||||
}
|
||||
return _c;
|
||||
return c;
|
||||
}
|
||||
|
||||
Color colorizeLight() {
|
||||
Color _c;
|
||||
Color c;
|
||||
var color = json.decode(this);
|
||||
if (color[0] < 50 && color[1] < 50 && color[2] < 50) {
|
||||
_c =
|
||||
Color.fromRGBO((255 - color[0]), 255 - color[1], 255 - color[2], 1.0);
|
||||
c = Color.fromRGBO((255 - color[0]), 255 - color[1], 255 - color[2], 1.0);
|
||||
} else {
|
||||
_c = Color.fromRGBO(color[0] < 50 ? 100 : color[0],
|
||||
c = Color.fromRGBO(color[0] < 50 ? 100 : color[0],
|
||||
color[1] < 50 ? 100 : color[1], color[2] < 50 ? 100 : color[2], 1.0);
|
||||
}
|
||||
return _c;
|
||||
return c;
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user