Support audio cache
This commit is contained in:
parent
e8cedbce75
commit
ce698dd548
|
@ -137,8 +137,8 @@ class AudioPlayerNotifier extends ChangeNotifier {
|
||||||
SleepTimerMode _sleepTimerMode = SleepTimerMode.undefined;
|
SleepTimerMode _sleepTimerMode = SleepTimerMode.undefined;
|
||||||
//set autoplay episode in playlist
|
//set autoplay episode in playlist
|
||||||
bool _autoPlay = true;
|
bool _autoPlay = true;
|
||||||
//Set auto add episodes to playlist
|
//TODO Set auto add episodes to playlist
|
||||||
bool _autoAdd = false;
|
//bool _autoAdd = false;
|
||||||
DateTime _current;
|
DateTime _current;
|
||||||
int _currentPosition;
|
int _currentPosition;
|
||||||
double _currentSpeed = 1;
|
double _currentSpeed = 1;
|
||||||
|
@ -159,7 +159,6 @@ class AudioPlayerNotifier extends ChangeNotifier {
|
||||||
bool get startSleepTimer => _startSleepTimer;
|
bool get startSleepTimer => _startSleepTimer;
|
||||||
SleepTimerMode get sleepTimerMode => _sleepTimerMode;
|
SleepTimerMode get sleepTimerMode => _sleepTimerMode;
|
||||||
bool get autoPlay => _autoPlay;
|
bool get autoPlay => _autoPlay;
|
||||||
bool get autoAdd => _autoAdd;
|
|
||||||
int get timeLeft => _timeLeft;
|
int get timeLeft => _timeLeft;
|
||||||
double get switchValue => _switchValue;
|
double get switchValue => _switchValue;
|
||||||
double get currentSpeed => _currentSpeed;
|
double get currentSpeed => _currentSpeed;
|
||||||
|
@ -177,28 +176,13 @@ class AudioPlayerNotifier extends ChangeNotifier {
|
||||||
|
|
||||||
Future _getAutoPlay() async {
|
Future _getAutoPlay() async {
|
||||||
int i = await autoPlayStorage.getInt();
|
int i = await autoPlayStorage.getInt();
|
||||||
_autoAdd = i == 0 ? true : false;
|
_autoPlay = i == 0 ? true : false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future _setAutoPlay() async {
|
Future _setAutoPlay() async {
|
||||||
await autoPlayStorage.saveInt(_autoPlay ? 1 : 0);
|
await autoPlayStorage.saveInt(_autoPlay ? 1 : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
set autoAddSwitch(bool boo) {
|
|
||||||
_autoAdd = boo;
|
|
||||||
notifyListeners();
|
|
||||||
_setAutoAdd();
|
|
||||||
}
|
|
||||||
|
|
||||||
//Future _getAutoAdd() async {
|
|
||||||
// int i = await autoAddStorage.getInt();
|
|
||||||
// _autoAdd = i == 0 ? false : true;
|
|
||||||
//}
|
|
||||||
|
|
||||||
Future _setAutoAdd() async {
|
|
||||||
await autoAddStorage.saveInt(_autoAdd ? 1 : 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
set setSleepTimerMode(SleepTimerMode timer) {
|
set setSleepTimerMode(SleepTimerMode timer) {
|
||||||
_sleepTimerMode = timer;
|
_sleepTimerMode = timer;
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
|
@ -270,6 +254,7 @@ class AudioPlayerNotifier extends ChangeNotifier {
|
||||||
if (!AudioService.connected) {
|
if (!AudioService.connected) {
|
||||||
await AudioService.connect();
|
await AudioService.connect();
|
||||||
}
|
}
|
||||||
|
|
||||||
await AudioService.start(
|
await AudioService.start(
|
||||||
backgroundTaskEntrypoint: _audioPlayerTaskEntrypoint,
|
backgroundTaskEntrypoint: _audioPlayerTaskEntrypoint,
|
||||||
androidNotificationChannelName: 'Tsacdop',
|
androidNotificationChannelName: 'Tsacdop',
|
||||||
|
@ -278,7 +263,6 @@ class AudioPlayerNotifier extends ChangeNotifier {
|
||||||
enableQueue: true,
|
enableQueue: true,
|
||||||
androidStopOnRemoveTask: true,
|
androidStopOnRemoveTask: true,
|
||||||
androidStopForegroundOnPause: true);
|
androidStopForegroundOnPause: true);
|
||||||
|
|
||||||
if (_autoPlay) {
|
if (_autoPlay) {
|
||||||
await Future.forEach(_queue.playlist, (episode) async {
|
await Future.forEach(_queue.playlist, (episode) async {
|
||||||
await AudioService.addQueueItem(episode.toMediaItem());
|
await AudioService.addQueueItem(episode.toMediaItem());
|
||||||
|
@ -572,13 +556,15 @@ class AudioPlayerNotifier extends ChangeNotifier {
|
||||||
}
|
}
|
||||||
|
|
||||||
class AudioPlayerTask extends BackgroundAudioTask {
|
class AudioPlayerTask extends BackgroundAudioTask {
|
||||||
|
KeyValueStorage cacheStorage = KeyValueStorage(cacheMaxKey);
|
||||||
|
|
||||||
List<MediaItem> _queue = [];
|
List<MediaItem> _queue = [];
|
||||||
AudioPlayer _audioPlayer = AudioPlayer();
|
AudioPlayer _audioPlayer = AudioPlayer();
|
||||||
Completer _completer = Completer();
|
Completer _completer = Completer();
|
||||||
BasicPlaybackState _skipState;
|
BasicPlaybackState _skipState;
|
||||||
bool _playing;
|
bool _playing;
|
||||||
bool _stopAtEnd;
|
bool _stopAtEnd;
|
||||||
|
int cacheMax;
|
||||||
bool get hasNext => _queue.length > 0;
|
bool get hasNext => _queue.length > 0;
|
||||||
|
|
||||||
MediaItem get mediaItem => _queue.length > 0 ? _queue.first : null;
|
MediaItem get mediaItem => _queue.length > 0 ? _queue.first : null;
|
||||||
|
@ -605,6 +591,8 @@ class AudioPlayerTask extends BackgroundAudioTask {
|
||||||
@override
|
@override
|
||||||
Future<void> onStart() async {
|
Future<void> onStart() async {
|
||||||
_stopAtEnd = false;
|
_stopAtEnd = false;
|
||||||
|
int cache = await cacheStorage.getInt();
|
||||||
|
cacheMax = cache == 0 ? 500 * 1024 * 1024 : cache;
|
||||||
var playerStateSubscription = _audioPlayer.playbackStateStream
|
var playerStateSubscription = _audioPlayer.playbackStateStream
|
||||||
.where((state) => state == AudioPlaybackState.completed)
|
.where((state) => state == AudioPlaybackState.completed)
|
||||||
.listen((state) {
|
.listen((state) {
|
||||||
|
@ -664,7 +652,7 @@ class AudioPlayerTask extends BackgroundAudioTask {
|
||||||
} else {
|
} else {
|
||||||
await AudioServiceBackground.setQueue(_queue);
|
await AudioServiceBackground.setQueue(_queue);
|
||||||
await AudioServiceBackground.setMediaItem(mediaItem);
|
await AudioServiceBackground.setMediaItem(mediaItem);
|
||||||
await _audioPlayer.setUrl(mediaItem.id);
|
await _audioPlayer.setUrl(mediaItem.id, cacheMax);
|
||||||
print(mediaItem.title);
|
print(mediaItem.title);
|
||||||
Duration duration = await _audioPlayer.durationFuture;
|
Duration duration = await _audioPlayer.durationFuture;
|
||||||
if (duration != null)
|
if (duration != null)
|
||||||
|
@ -687,7 +675,7 @@ class AudioPlayerTask extends BackgroundAudioTask {
|
||||||
if (_playing == null) {
|
if (_playing == null) {
|
||||||
_playing = true;
|
_playing = true;
|
||||||
// await AudioServiceBackground.setQueue(_queue);
|
// await AudioServiceBackground.setQueue(_queue);
|
||||||
await _audioPlayer.setUrl(mediaItem.id);
|
await _audioPlayer.setUrl(mediaItem.id, cacheMax);
|
||||||
var duration = await _audioPlayer.durationFuture;
|
var duration = await _audioPlayer.durationFuture;
|
||||||
if (duration != null)
|
if (duration != null)
|
||||||
await AudioServiceBackground.setMediaItem(
|
await AudioServiceBackground.setMediaItem(
|
||||||
|
@ -777,7 +765,7 @@ class AudioPlayerTask extends BackgroundAudioTask {
|
||||||
_queue.insert(0, mediaItem);
|
_queue.insert(0, mediaItem);
|
||||||
await AudioServiceBackground.setQueue(_queue);
|
await AudioServiceBackground.setQueue(_queue);
|
||||||
await AudioServiceBackground.setMediaItem(mediaItem);
|
await AudioServiceBackground.setMediaItem(mediaItem);
|
||||||
await _audioPlayer.setUrl(mediaItem.id);
|
await _audioPlayer.setUrl(mediaItem.id, cacheMax);
|
||||||
Duration duration = await _audioPlayer.durationFuture ?? Duration.zero;
|
Duration duration = await _audioPlayer.durationFuture ?? Duration.zero;
|
||||||
AudioServiceBackground.setMediaItem(
|
AudioServiceBackground.setMediaItem(
|
||||||
mediaItem.copyWith(duration: duration.inMilliseconds));
|
mediaItem.copyWith(duration: duration.inMilliseconds));
|
||||||
|
|
|
@ -4,7 +4,7 @@ import 'package:tsacdop/util/custompaint.dart';
|
||||||
import 'package:url_launcher/url_launcher.dart';
|
import 'package:url_launcher/url_launcher.dart';
|
||||||
import 'package:line_icons/line_icons.dart';
|
import 'package:line_icons/line_icons.dart';
|
||||||
|
|
||||||
const String version = '0.2.0';
|
const String version = '0.2.0+1';
|
||||||
|
|
||||||
class AboutApp extends StatelessWidget {
|
class AboutApp extends StatelessWidget {
|
||||||
_launchUrl(String url) async {
|
_launchUrl(String url) async {
|
||||||
|
|
|
@ -18,92 +18,8 @@ import 'package:tsacdop/util/pageroute.dart';
|
||||||
import 'package:tsacdop/util/colorize.dart';
|
import 'package:tsacdop/util/colorize.dart';
|
||||||
import 'package:tsacdop/util/context_extension.dart';
|
import 'package:tsacdop/util/context_extension.dart';
|
||||||
import 'package:tsacdop/util/custompaint.dart';
|
import 'package:tsacdop/util/custompaint.dart';
|
||||||
|
import '../util/customslider.dart';
|
||||||
|
|
||||||
class MyRectangularTrackShape extends RectangularSliderTrackShape {
|
|
||||||
Rect getPreferredRect({
|
|
||||||
@required RenderBox parentBox,
|
|
||||||
Offset offset = Offset.zero,
|
|
||||||
@required SliderThemeData sliderTheme,
|
|
||||||
bool isEnabled = false,
|
|
||||||
bool isDiscrete = false,
|
|
||||||
}) {
|
|
||||||
final double trackHeight = sliderTheme.trackHeight;
|
|
||||||
final double trackLeft = offset.dx;
|
|
||||||
final double trackTop =
|
|
||||||
offset.dy + (parentBox.size.height - trackHeight) / 2;
|
|
||||||
final double trackWidth = parentBox.size.width;
|
|
||||||
return Rect.fromLTWH(trackLeft - 5, trackTop, trackWidth, trackHeight);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class MyRoundSliderThumpShape extends SliderComponentShape {
|
|
||||||
const MyRoundSliderThumpShape({
|
|
||||||
this.enabledThumbRadius = 10.0,
|
|
||||||
this.disabledThumbRadius,
|
|
||||||
this.thumbCenterColor,
|
|
||||||
});
|
|
||||||
final Color thumbCenterColor;
|
|
||||||
final double enabledThumbRadius;
|
|
||||||
final double disabledThumbRadius;
|
|
||||||
double get _disabledThumbRadius => disabledThumbRadius ?? enabledThumbRadius;
|
|
||||||
|
|
||||||
@override
|
|
||||||
Size getPreferredSize(bool isEnabled, bool isDiscrete) {
|
|
||||||
return Size.fromRadius(
|
|
||||||
isEnabled == true ? enabledThumbRadius : _disabledThumbRadius);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void paint(
|
|
||||||
PaintingContext context,
|
|
||||||
Offset center, {
|
|
||||||
Animation<double> activationAnimation,
|
|
||||||
@required Animation<double> enableAnimation,
|
|
||||||
bool isDiscrete,
|
|
||||||
TextPainter labelPainter,
|
|
||||||
RenderBox parentBox,
|
|
||||||
@required SliderThemeData sliderTheme,
|
|
||||||
TextDirection textDirection,
|
|
||||||
double value,
|
|
||||||
}) {
|
|
||||||
final Canvas canvas = context.canvas;
|
|
||||||
final Tween<double> radiusTween = Tween<double>(
|
|
||||||
begin: _disabledThumbRadius,
|
|
||||||
end: enabledThumbRadius,
|
|
||||||
);
|
|
||||||
// final ColorTween colorTween = ColorTween(
|
|
||||||
// begin: sliderTheme.disabledThumbColor,
|
|
||||||
// end: sliderTheme.thumbColor,
|
|
||||||
// );
|
|
||||||
|
|
||||||
canvas.drawCircle(
|
|
||||||
center,
|
|
||||||
radiusTween.evaluate(enableAnimation),
|
|
||||||
Paint()
|
|
||||||
..color = thumbCenterColor
|
|
||||||
..style = PaintingStyle.fill
|
|
||||||
..strokeWidth = 2,
|
|
||||||
);
|
|
||||||
|
|
||||||
canvas.drawRect(
|
|
||||||
Rect.fromLTRB(
|
|
||||||
center.dx - 10, center.dy + 10, center.dx + 10, center.dy - 10),
|
|
||||||
Paint()
|
|
||||||
..color = Colors.white
|
|
||||||
..style = PaintingStyle.fill
|
|
||||||
..strokeWidth = 10,
|
|
||||||
);
|
|
||||||
|
|
||||||
canvas.drawLine(
|
|
||||||
Offset(center.dx - 5, center.dy - 2),
|
|
||||||
Offset(center.dx + 5, center.dy + 2),
|
|
||||||
Paint()
|
|
||||||
..color = Colors.transparent
|
|
||||||
..style = PaintingStyle.fill
|
|
||||||
..strokeWidth = 2,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
final List<BoxShadow> _customShadow = [
|
final List<BoxShadow> _customShadow = [
|
||||||
BoxShadow(blurRadius: 26, offset: Offset(-6, -6), color: Colors.white),
|
BoxShadow(blurRadius: 26, offset: Offset(-6, -6), color: Colors.white),
|
||||||
|
|
|
@ -15,6 +15,7 @@ const String updateIntervalKey = 'updateInterval';
|
||||||
const String downloadUsingDataKey = 'downloadUsingData';
|
const String downloadUsingDataKey = 'downloadUsingData';
|
||||||
const String introKey = 'intro';
|
const String introKey = 'intro';
|
||||||
const String realDarkKey = 'realDark';
|
const String realDarkKey = 'realDark';
|
||||||
|
const String cacheMaxKey = 'cacheMax';
|
||||||
|
|
||||||
class KeyValueStorage {
|
class KeyValueStorage {
|
||||||
final String key;
|
final String key;
|
||||||
|
|
|
@ -264,12 +264,14 @@ class _SettingsState extends State<Settings>
|
||||||
),
|
),
|
||||||
Divider(height: 2),
|
Divider(height: 2),
|
||||||
ListTile(
|
ListTile(
|
||||||
onTap: () {
|
onTap: () async {
|
||||||
if (_value == 0)
|
if (_value == 0) {
|
||||||
|
_showFeedback = !_showFeedback;
|
||||||
_controller.forward();
|
_controller.forward();
|
||||||
else
|
} else {
|
||||||
_controller.reverse();
|
await _controller.reverse();
|
||||||
_showFeedback = !_showFeedback;
|
_showFeedback = !_showFeedback;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
contentPadding:
|
contentPadding:
|
||||||
EdgeInsets.symmetric(horizontal: 25.0),
|
EdgeInsets.symmetric(horizontal: 25.0),
|
||||||
|
|
|
@ -1,11 +1,57 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
import 'package:app_settings/app_settings.dart';
|
import 'package:google_fonts/google_fonts.dart';
|
||||||
import 'package:tsacdop/settings/downloads_manage.dart';
|
import 'package:tsacdop/settings/downloads_manage.dart';
|
||||||
import 'package:tsacdop/class/settingstate.dart';
|
import 'package:tsacdop/class/settingstate.dart';
|
||||||
|
import '../local_storage/key_value_storage.dart';
|
||||||
|
import '../util/context_extension.dart';
|
||||||
|
|
||||||
|
class StorageSetting extends StatefulWidget {
|
||||||
|
@override
|
||||||
|
_StorageSettingState createState() => _StorageSettingState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _StorageSettingState extends State<StorageSetting>
|
||||||
|
with SingleTickerProviderStateMixin {
|
||||||
|
final KeyValueStorage cacheStorage = KeyValueStorage(cacheMaxKey);
|
||||||
|
AnimationController _controller;
|
||||||
|
Animation<double> _animation;
|
||||||
|
_getCacheMax() async {
|
||||||
|
int cache = await cacheStorage.getInt();
|
||||||
|
int value = cache == 0 ? 500 : cache ~/ (1024 * 1024);
|
||||||
|
if (value > 100) {
|
||||||
|
_controller = AnimationController(
|
||||||
|
vsync: this, duration: Duration(milliseconds: value * 2));
|
||||||
|
_animation = Tween<double>(begin: 100, end: value.toDouble()).animate(
|
||||||
|
CurvedAnimation(curve: Curves.easeOutQuart, parent: _controller))
|
||||||
|
..addListener(() {
|
||||||
|
setState(() => _value = _animation.value);
|
||||||
|
});
|
||||||
|
_controller.forward();
|
||||||
|
// _controller.addStatusListener((status) {
|
||||||
|
// if (status == AnimationStatus.completed) {
|
||||||
|
// _controller.reset();
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
double _value;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
_value = 100;
|
||||||
|
_getCacheMax();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_controller?.dispose();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
class StorageSetting extends StatelessWidget {
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
var settings = Provider.of<SettingState>(context, listen: false);
|
var settings = Provider.of<SettingState>(context, listen: false);
|
||||||
|
@ -54,8 +100,8 @@ class StorageSetting extends StatelessWidget {
|
||||||
context,
|
context,
|
||||||
MaterialPageRoute(
|
MaterialPageRoute(
|
||||||
builder: (context) => DownloadsManage())),
|
builder: (context) => DownloadsManage())),
|
||||||
contentPadding:
|
contentPadding: EdgeInsets.only(
|
||||||
EdgeInsets.only(left: 80.0, right: 25, bottom: 10, top: 10),
|
left: 80.0, right: 25, bottom: 10, top: 10),
|
||||||
title: Text('Ask before using cellular data'),
|
title: Text('Ask before using cellular data'),
|
||||||
subtitle: Text(
|
subtitle: Text(
|
||||||
'Ask to confirm when using cellular data to download episodes.'),
|
'Ask to confirm when using cellular data to download episodes.'),
|
||||||
|
@ -108,11 +154,44 @@ class StorageSetting extends StatelessWidget {
|
||||||
),
|
),
|
||||||
Divider(height: 2),
|
Divider(height: 2),
|
||||||
ListTile(
|
ListTile(
|
||||||
onTap: () => AppSettings.openAppSettings(),
|
contentPadding: EdgeInsets.only(left: 80.0, right: 25),
|
||||||
contentPadding: EdgeInsets.symmetric(horizontal: 80.0),
|
|
||||||
// leading: Icon(Icons.colorize),
|
// leading: Icon(Icons.colorize),
|
||||||
title: Text('Cache'),
|
title: Text('Cache'),
|
||||||
subtitle: Text('App cache'),
|
subtitle: Text('Audio cache max size'),
|
||||||
|
trailing: Text.rich(TextSpan(
|
||||||
|
text: '${(_value ~/ 100) * 100}',
|
||||||
|
style: GoogleFonts.teko(
|
||||||
|
textStyle: context.textTheme.headline6
|
||||||
|
.copyWith(color: context.accentColor)),
|
||||||
|
children: [
|
||||||
|
TextSpan(
|
||||||
|
text: ' Mb',
|
||||||
|
style: context.textTheme.subtitle2),
|
||||||
|
])),
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsets.only(
|
||||||
|
left: 60.0, right: 20.0, bottom: 10.0),
|
||||||
|
child: SliderTheme(
|
||||||
|
data: Theme.of(context).sliderTheme.copyWith(
|
||||||
|
showValueIndicator: ShowValueIndicator.always,
|
||||||
|
),
|
||||||
|
child: Slider(
|
||||||
|
label: '${_value ~/ 100 * 100} Mb',
|
||||||
|
activeColor: context.accentColor,
|
||||||
|
inactiveColor: context.primaryColorDark,
|
||||||
|
value: _value,
|
||||||
|
min: 100,
|
||||||
|
max: 1000,
|
||||||
|
divisions: 9,
|
||||||
|
onChanged: (double val) {
|
||||||
|
setState(() {
|
||||||
|
_value = val;
|
||||||
|
});
|
||||||
|
cacheStorage
|
||||||
|
.saveInt((val * 1024 * 1024).toInt());
|
||||||
|
}),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
Divider(height: 2),
|
Divider(height: 2),
|
||||||
],
|
],
|
||||||
|
|
|
@ -123,7 +123,9 @@ class ThemeSetting extends StatelessWidget {
|
||||||
contentPadding:
|
contentPadding:
|
||||||
EdgeInsets.only(left: 80.0, right: 20, bottom: 10),
|
EdgeInsets.only(left: 80.0, right: 20, bottom: 10),
|
||||||
// leading: Icon(Icons.colorize),
|
// leading: Icon(Icons.colorize),
|
||||||
title: Text('Real Dark',),
|
title: Text(
|
||||||
|
'Real Dark',
|
||||||
|
),
|
||||||
subtitle: Text(
|
subtitle: Text(
|
||||||
'Turn on if you think the night is not dark enough'),
|
'Turn on if you think the night is not dark enough'),
|
||||||
trailing: Selector<SettingState, bool>(
|
trailing: Selector<SettingState, bool>(
|
||||||
|
@ -167,18 +169,22 @@ class ThemeSetting extends StatelessWidget {
|
||||||
borderRadius: BorderRadius.all(
|
borderRadius: BorderRadius.all(
|
||||||
Radius.circular(10.0))),
|
Radius.circular(10.0))),
|
||||||
title: Text('Choose a color'),
|
title: Text('Choose a color'),
|
||||||
content: SingleChildScrollView(
|
content: MaterialPicker(
|
||||||
child: MaterialPicker(
|
onColorChanged: (value) {
|
||||||
onColorChanged: (value) {
|
settings.setAccentColor = value;
|
||||||
settings.setAccentColor = value;
|
},
|
||||||
},
|
pickerColor: context.accentColor,
|
||||||
pickerColor: context.accentColor,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
))),
|
))),
|
||||||
contentPadding: EdgeInsets.symmetric(horizontal: 80.0),
|
contentPadding: EdgeInsets.only(left: 80.0, right: 25),
|
||||||
title: Text('Accent color'),
|
title: Text('Accent color'),
|
||||||
subtitle: Text('Include the overlay color'),
|
subtitle: Text('Include the overlay color'),
|
||||||
|
trailing: Container(
|
||||||
|
height: 25,
|
||||||
|
width: 25,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
shape: BoxShape.circle, color: context.accentColor),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
Divider(height: 2),
|
Divider(height: 2),
|
||||||
],
|
],
|
||||||
|
@ -191,3 +197,13 @@ class ThemeSetting extends StatelessWidget {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const List<Color> colorList = [
|
||||||
|
Colors.pink,
|
||||||
|
Colors.pinkAccent,
|
||||||
|
Colors.red,
|
||||||
|
Colors.blue,
|
||||||
|
Colors.green
|
||||||
|
];
|
||||||
|
|
||||||
|
List<int> intList = List<int>.generate(9, (index) => (index + 1) * 100);
|
||||||
|
|
|
@ -0,0 +1,87 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class MyRectangularTrackShape extends RectangularSliderTrackShape {
|
||||||
|
Rect getPreferredRect({
|
||||||
|
@required RenderBox parentBox,
|
||||||
|
Offset offset = Offset.zero,
|
||||||
|
@required SliderThemeData sliderTheme,
|
||||||
|
bool isEnabled = false,
|
||||||
|
bool isDiscrete = false,
|
||||||
|
}) {
|
||||||
|
final double trackHeight = sliderTheme.trackHeight;
|
||||||
|
final double trackLeft = offset.dx;
|
||||||
|
final double trackTop =
|
||||||
|
offset.dy + (parentBox.size.height - trackHeight) / 2;
|
||||||
|
final double trackWidth = parentBox.size.width;
|
||||||
|
return Rect.fromLTWH(trackLeft - 5, trackTop, trackWidth, trackHeight);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class MyRoundSliderThumpShape extends SliderComponentShape {
|
||||||
|
const MyRoundSliderThumpShape({
|
||||||
|
this.enabledThumbRadius = 10.0,
|
||||||
|
this.disabledThumbRadius,
|
||||||
|
this.thumbCenterColor,
|
||||||
|
});
|
||||||
|
final Color thumbCenterColor;
|
||||||
|
final double enabledThumbRadius;
|
||||||
|
final double disabledThumbRadius;
|
||||||
|
double get _disabledThumbRadius => disabledThumbRadius ?? enabledThumbRadius;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Size getPreferredSize(bool isEnabled, bool isDiscrete) {
|
||||||
|
return Size.fromRadius(
|
||||||
|
isEnabled == true ? enabledThumbRadius : _disabledThumbRadius);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void paint(
|
||||||
|
PaintingContext context,
|
||||||
|
Offset center, {
|
||||||
|
Animation<double> activationAnimation,
|
||||||
|
@required Animation<double> enableAnimation,
|
||||||
|
bool isDiscrete,
|
||||||
|
TextPainter labelPainter,
|
||||||
|
RenderBox parentBox,
|
||||||
|
@required SliderThemeData sliderTheme,
|
||||||
|
TextDirection textDirection,
|
||||||
|
double value,
|
||||||
|
}) {
|
||||||
|
final Canvas canvas = context.canvas;
|
||||||
|
final Tween<double> radiusTween = Tween<double>(
|
||||||
|
begin: _disabledThumbRadius,
|
||||||
|
end: enabledThumbRadius,
|
||||||
|
);
|
||||||
|
// final ColorTween colorTween = ColorTween(
|
||||||
|
// begin: sliderTheme.disabledThumbColor,
|
||||||
|
// end: sliderTheme.thumbColor,
|
||||||
|
// );
|
||||||
|
|
||||||
|
canvas.drawCircle(
|
||||||
|
center,
|
||||||
|
radiusTween.evaluate(enableAnimation),
|
||||||
|
Paint()
|
||||||
|
..color = thumbCenterColor
|
||||||
|
..style = PaintingStyle.fill
|
||||||
|
..strokeWidth = 2,
|
||||||
|
);
|
||||||
|
|
||||||
|
canvas.drawRect(
|
||||||
|
Rect.fromLTRB(
|
||||||
|
center.dx - 10, center.dy + 10, center.dx + 10, center.dy - 10),
|
||||||
|
Paint()
|
||||||
|
..color = Colors.white
|
||||||
|
..style = PaintingStyle.fill
|
||||||
|
..strokeWidth = 10,
|
||||||
|
);
|
||||||
|
|
||||||
|
canvas.drawLine(
|
||||||
|
Offset(center.dx - 5, center.dy - 2),
|
||||||
|
Offset(center.dx + 5, center.dy + 2),
|
||||||
|
Paint()
|
||||||
|
..color = Colors.transparent
|
||||||
|
..style = PaintingStyle.fill
|
||||||
|
..strokeWidth = 2,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
27
pubspec.yaml
27
pubspec.yaml
|
@ -1,16 +1,6 @@
|
||||||
name: tsacdop
|
name: tsacdop
|
||||||
description: An easy-use podacasts player.
|
description: An easy-use podacasts player.
|
||||||
|
|
||||||
# The following defines the version and build number for your application.
|
|
||||||
# A version number is three numbers separated by dots, like 1.2.43
|
|
||||||
# followed by an optional build number separated by a +.
|
|
||||||
# Both the version and the builder number may be overridden in flutter
|
|
||||||
# build by specifying --build-name and --build-number, respectively.
|
|
||||||
# In Android, build-name is used as versionName while build-number used as versionCode.
|
|
||||||
# Read more about Android versioning at https://developer.android.com/studio/publish/versioning
|
|
||||||
# In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion.
|
|
||||||
# Read more about iOS versioning at
|
|
||||||
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
|
|
||||||
version: 0.2.0+1
|
version: 0.2.0+1
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
|
@ -20,8 +10,6 @@ dependencies:
|
||||||
flutter:
|
flutter:
|
||||||
sdk: flutter
|
sdk: flutter
|
||||||
|
|
||||||
# The following adds the Cupertino Icons font to your application.
|
|
||||||
# Use with the CupertinoIcons class for iOS style icons.
|
|
||||||
cupertino_icons: ^0.1.3
|
cupertino_icons: ^0.1.3
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
|
@ -30,19 +18,19 @@ dev_dependencies:
|
||||||
json_annotation: ^3.0.1
|
json_annotation: ^3.0.1
|
||||||
sqflite: ^1.3.0
|
sqflite: ^1.3.0
|
||||||
flutter_html: ^0.11.1
|
flutter_html: ^0.11.1
|
||||||
path_provider: ^1.6.5
|
path_provider: ^1.6.7
|
||||||
color_thief_flutter: ^1.0.2
|
color_thief_flutter: ^1.0.2
|
||||||
provider: ^4.0.5
|
provider: ^4.0.5
|
||||||
google_fonts: ^1.0.0
|
google_fonts: ^1.0.0
|
||||||
dio: ^3.0.9
|
dio: ^3.0.9
|
||||||
file_picker: ^1.6.3+1
|
file_picker: ^1.6.3+1
|
||||||
xml: ^3.5.0
|
xml: ^3.6.1
|
||||||
marquee: ^1.3.1
|
marquee: ^1.3.1
|
||||||
flutter_downloader: ^1.4.3
|
flutter_downloader: ^1.4.4
|
||||||
permission_handler: ^5.0.0+hotfix.3
|
permission_handler: ^5.0.0+hotfix.3
|
||||||
fluttertoast: ^4.0.1
|
fluttertoast: ^4.0.1
|
||||||
intl: ^0.16.1
|
intl: ^0.16.1
|
||||||
url_launcher: ^5.4.2
|
url_launcher: ^5.4.5
|
||||||
image: ^2.1.12
|
image: ^2.1.12
|
||||||
shared_preferences: ^0.5.7
|
shared_preferences: ^0.5.7
|
||||||
uuid: ^2.0.4
|
uuid: ^2.0.4
|
||||||
|
@ -50,7 +38,6 @@ dev_dependencies:
|
||||||
cached_network_image: ^2.1.0+1
|
cached_network_image: ^2.1.0+1
|
||||||
workmanager: ^0.2.2
|
workmanager: ^0.2.2
|
||||||
flutter_colorpicker: ^0.3.4
|
flutter_colorpicker: ^0.3.4
|
||||||
app_settings: ^3.0.1
|
|
||||||
fl_chart: ^0.9.3
|
fl_chart: ^0.9.3
|
||||||
audio_service: ^0.7.2
|
audio_service: ^0.7.2
|
||||||
just_audio:
|
just_audio:
|
||||||
|
@ -60,7 +47,7 @@ dev_dependencies:
|
||||||
git:
|
git:
|
||||||
url: https://github.com/galonsos/line_icons.git
|
url: https://github.com/galonsos/line_icons.git
|
||||||
flutter_file_dialog: ^0.0.5
|
flutter_file_dialog: ^0.0.5
|
||||||
flutter_linkify: ^3.1.0
|
flutter_linkify: ^3.1.2
|
||||||
extended_nested_scroll_view: ^0.4.0
|
extended_nested_scroll_view: ^0.4.0
|
||||||
connectivity: ^0.4.8+2
|
connectivity: ^0.4.8+2
|
||||||
flare_flutter: ^2.0.3
|
flare_flutter: ^2.0.3
|
||||||
|
@ -68,10 +55,6 @@ dev_dependencies:
|
||||||
flutter_isolate: ^1.0.0+11
|
flutter_isolate: ^1.0.0+11
|
||||||
|
|
||||||
|
|
||||||
# For information on the generic Dart part of this file, see the
|
|
||||||
# following page: https://www.dartlang.org/tools/pub/pubspec
|
|
||||||
|
|
||||||
# The following section is specific to Flutter.
|
|
||||||
flutter:
|
flutter:
|
||||||
assets:
|
assets:
|
||||||
- assets/
|
- assets/
|
||||||
|
|
Loading…
Reference in New Issue