JavaScript preprocessors can help make authoring JavaScript easier and more convenient.
Babel includes JSX processing.
Search for and use JavaScript packages from npm here. By selecting a package, an import
statement will be added to the top of the JavaScript editor for this package.
Using packages here is powered by esm.sh, which makes packages from npm not only available on a CDN, but prepares them for native JavaScript ESM usage.
All packages are different, so refer to their docs for how they work.
If you're using React / ReactDOM, make sure to turn on Babel for the JSX processing.
If active, Pens will autosave every 30 seconds after being saved once.
If enabled, the preview panel updates automatically as you code. If disabled, use the "Run" button to update.
If enabled, your code will be formatted when you actively save your Pen. Note: your code becomes un-folded during formatting.
Visit your global Editor Settings.
/*
COPYRIGHT 2020. @ishandeveloper
YOU CAN FIND THE REFACTORED CODE AT https://github.com/ishandeveloper/WinAMP_Flutter
LISTEN TO ACTUAL MUSIC IN THE DEMO AT :
https://winamp.ishandeveloper.com
*/
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
import 'dart:ui';
bool mono = false;
double seekTime = 0;
String currentTrack = "No Track Selected";
String trackMin = "00";
String trackSec = "00";
int trackMinint = 0;
int trackSecint = 0;
void main() {
runApp(
MaterialApp(
title: 'Ishan Sharma',
debugShowCheckedModeBanner: false,
theme: ThemeData(
scaffoldBackgroundColor: Colors.black,
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: Player(),
),
);
}
class Player extends StatefulWidget {
@override
_PlayerState createState() => _PlayerState();
}
class _PlayerState extends State<Player> {
@override
Widget build(BuildContext context) {
return LayoutBuilder(
builder: (context, constraints) {
if (constraints.maxWidth > 768) {
return DesktopUI();
}
return MobileUI();
},
);
}
}
class DesktopUI extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Color(0xff020088),
body: Container(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
decoration: BoxDecoration(
image: DecorationImage(
image: NetworkImage(
'https://github.com/ishandeveloper/WinAMP_Flutter/blob/master/assets/xp.jpg?raw=false'),
fit: BoxFit.cover,
),
),
child: Center(
child: Container(
width: 780,
height: 350,
decoration: BoxDecoration(color: Colors.black, boxShadow: [
BoxShadow(blurRadius: 5, color: Colors.black, spreadRadius: 1)
]),
child: Column(
children: [
DesktopNavbar(),
DesktopMain(),
],
),
),
),
),
);
}
}
// DESKTOP NAVBAR
class DesktopNavbar extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Padding(
padding: EdgeInsets.symmetric(vertical: 5, horizontal: 10),
child: Row(
children: [
WinLogo(),
SizedBox(width: 10),
Row(
children: [
NavLine(),
SizedBox(width: 10),
Text(
"WINAMP",
style: TextStyle(
color: Colors.white,
fontFamily: 'Pixer',
fontSize: 18,
),
),
SizedBox(width: 10),
NavLine(),
SizedBox(width: 10),
Padding(
padding: const EdgeInsets.all(0.0),
child: Container(
width: 18,
height: 18,
decoration: BoxDecoration(
image: DecorationImage(
image: NetworkImage(
'https://github.com/ishandeveloper/WinAMP_Flutter/blob/master/assets/btn1.png?raw=false',
),
fit: BoxFit.cover,
)),
),
),
Padding(
padding: const EdgeInsets.all(0.0),
child: Container(
width: 18,
height: 18,
decoration: BoxDecoration(
// color: Colors.white,
image: DecorationImage(
image: NetworkImage(
'https://github.com/ishandeveloper/WinAMP_Flutter/blob/master/assets/btn1.png?raw=false',
),
fit: BoxFit.cover,
)),
),
)
],
)
],
),
);
}
}
class DesktopMain extends StatefulWidget {
@override
_DesktopMainState createState() => _DesktopMainState();
}
class _DesktopMainState extends State<DesktopMain> {
bool paused = true;
bool initial = true;
@override
Widget build(BuildContext context) {
void stopMusic() {
setState(() {
paused = true;
currentTrack = "No Track Selected";
});
}
void trackTime() {
setState(() {
// ignore: division_optimization
trackMinint = (seekTime / 60).toInt();
trackSecint = (seekTime - (trackMinint * 60)).toInt();
});
if (trackSecint < 10) {
setState(() {
trackSec = "0" + trackSecint.toString();
});
} else {
setState(() {
trackSec = trackSecint.toString();
});
}
setState(() {
trackMin = "0" + trackMinint.toString();
});
if (trackMin == "04" && trackSec == "59") {
setState(() {
seekTime = 0;
trackMinint = 0;
trackSecint = 0;
trackMin = "00";
trackSec = "00";
});
stopMusic();
}
}
void seeker() async {
Timer.periodic(Duration(milliseconds: 1000), (timer) {
if (!paused) {
setState(() {
seekTime += 1;
});
trackTime();
} else {
// dispose();
}
});
}
void playMusic() async {
if (paused) {
// playAudio('assets/music.mp3');
setState(() {
paused = false;
// initial=false;
currentTrack = "Silent - DEMO Track (*JavaScript Required)";
});
if (initial) {
setState(() {
initial = false;
seekTime = 0;
});
seeker();
}
}
}
void seekMusic(double position) {
int time = position.toInt();
setState(() {
trackSecint = time;
seekTime = position;
});
trackTime();
}
void pauseMusic() {
setState(() {
paused = true;
currentTrack = "PAUSED - Silent - DEMO Track (*JavaScript Required)";
});
}
return Container(
width: 770,
height: 300,
decoration: BoxDecoration(
border: Border.all(color: Color(0xFF555569), width: 2.0),
gradient: LinearGradient(
begin: Alignment.centerLeft,
end: Alignment(0.8, 0.0),
colors: [
Color(0xFF212132),
Color(0XFF353454),
Color(0xFF474766),
],
tileMode: TileMode.repeated,
),
),
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
/* TOP CONTROLS */
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Transform.scale(
scale: 1,
child: MainInfoWidget(
minutes: trackMin,
seconds: trackSec,
playing: !paused)),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.center,
children: [
TrackNameBar(currentTrack),
SizedBox(height: 15),
Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
MiniControls(
units: "kbps",
initialValue: 160,
min: 98,
max: 320),
MiniControls(
units: "dB",
initialValue: 50,
min: 0,
max: 100,
control: (double level) {
// setAudioVolume(level);
},
),
MiniControls(
units: "kHz", initialValue: 44, min: 32, max: 98),
Row(
children: [
Column(
children: [
ControlLabel(
text: "mono",
enabled: mono,
onPress: () {
setState(() {
mono = true;
});
}),
SizedBox(height: 15),
MiniButton(light: Colors.yellow, text: "EQ"),
],
),
SizedBox(width: 10),
Column(
children: [
ControlLabel(
text: "stereo",
enabled: !mono,
onPress: () => setState(() {
mono = false;
})),
SizedBox(height: 15),
MiniButton(light: Colors.red, text: "PL"),
],
)
],
)
],
),
],
)
],
),
SizedBox(height: 15),
SeekBar(
min: 0,
max: 300, // Time in seconds,
value: seekTime,
seek: (val) {
print("SEEKED" + val.toString());
seekMusic(val);
},
),
SizedBox(height: 20),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
RetroButton(
onPress: () {
seekMusic(0);
},
icon: Icons.fast_rewind),
SizedBox(width: 5),
RetroButton(
onPress: () => playMusic(), icon: Icons.play_arrow),
SizedBox(width: 5),
RetroButton(onPress: () => pauseMusic(), icon: Icons.pause),
SizedBox(width: 5),
RetroButton(
onPress: () {
stopMusic();
this.initState();
},
icon: Icons.stop),
SizedBox(width: 5),
RetroButton(onPress: () {}, icon: Icons.fast_forward),
SizedBox(width: 10),
RetroButton(onPress: () {}, icon: Icons.eject),
],
),
Row(
children: [
TextControlButton(text: "Shuffle", light: Colors.red),
SizedBox(width: 10),
TextControlButton(
icon: true,
ico: Icons.repeat,
light: Colors.yellow,
width: 40)
],
)
],
)
],
),
),
);
}
}
class TextControlButton extends StatefulWidget {
final Color light;
final String text;
final bool selected;
final bool icon;
final double width;
final IconData ico;
TextControlButton(
{this.light,
this.text,
this.selected = false,
this.icon = false,
this.width = 60,
this.ico});
@override
_TextControlButtonState createState() => _TextControlButtonState();
}
class _TextControlButtonState extends State<TextControlButton> {
bool enabled;
@override
void initState() {
enabled = widget.selected;
super.initState();
}
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () {
setState(() {
enabled = !enabled;
});
},
child: Container(
width: widget.width,
height: 30,
decoration: BoxDecoration(
color: enabled ? Color(0xFFBDCED6) : Color(0xFFBDCED6),
border: Border(
top: BorderSide(
width: 1,
color: enabled ? Color(0xFF000000) : Color(0xFFFFFFFF)),
left: BorderSide(
width: 1,
color: enabled ? Color(0xFF000000) : Color(0xFFFFFFFF)),
right: BorderSide(
width: 2,
color: enabled ? Color(0xFFFFFFFF) : Color(0xFF000000)),
bottom: BorderSide(
width: 2,
color: enabled ? Color(0xFFFFFFFF) : Color(0xFF000000)),
)),
child: Row(mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [
Container(
height: 10,
width: 10,
decoration: BoxDecoration(
color: widget.light,
border: Border.all(color: Color(0xFF000000), width: 1)),
),
widget.icon
? Icon(
widget.ico,
size: 18,
color: Colors.black,
)
: Text(
widget.text,
style: TextStyle(
fontFamily: 'Pixer', color: Colors.black, fontSize: 14),
),
]),
),
);
}
}
class SeekBar extends StatelessWidget {
final Function seek;
final double min;
final double max;
final double value;
SeekBar({this.seek, this.min, this.max, this.value});
@override
Widget build(BuildContext context) {
return Row(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.max,
children: [
Container(
// decoration: BoxDecoration(color: Color(0xff1B1932)),
child: CustomSlider(
value: value,
min: min,
max: max,
thumbSize: 34.0,
sliderWidth: 720.0,
thumbColor: Colors.yellow,
roundedRectangleThumbRadius: 0.0,
topLeftShadow: false,
bottomRightShadow: true,
bottomRightShadowBlur: MaskFilter.blur(BlurStyle.outer, 3),
bottomRightShadowColor: Colors.black,
activeLineStroke: 2.0,
activeLineColor: Color(0xff1B1932),
inactiveLineColor: Color(0xff1B1932),
child: Padding(
padding: EdgeInsets.all(2.0),
child: Center(
child: Text(
'──',
style: TextStyle(
color: Colors.black,
fontSize: 18.0,
fontFamily: 'Pixer',
fontWeight: FontWeight.bold,
),
)),
),
onChanged: (double val) {
seek(val);
},
),
),
],
);
}
}
class RetroButton extends StatefulWidget {
final IconData icon;
final Function onPress;
final double width;
final double height;
RetroButton({this.icon, this.onPress, this.width = 50, this.height = 30});
@override
_RetroButtonState createState() => _RetroButtonState();
}
class _RetroButtonState extends State<RetroButton> {
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: widget.onPress,
child: Container(
width: widget.width,
height: widget.height,
decoration: BoxDecoration(
color: Color(0xFFBDCED6),
border: Border(
top: BorderSide(width: 1, color: Color(0xFFFFFFFF)),
left: BorderSide(width: 1, color: Color(0xFFFFFFFF)),
right: BorderSide(width: 2, color: Color(0xFF000000)),
bottom: BorderSide(width: 2, color: Color(0xFF000000)),
)),
child: Row(mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [
Icon(
widget.icon,
size: 24,
color: Color(0xff687582),
),
]),
),
);
}
}
class MiniButton extends StatefulWidget {
final Color light;
final String text;
final bool selected;
MiniButton({this.light, this.text, this.selected = false});
@override
_MiniButtonState createState() => _MiniButtonState();
}
class _MiniButtonState extends State<MiniButton> {
bool enabled;
@override
void initState() {
enabled = widget.selected;
super.initState();
}
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () {
setState(() {
enabled = !enabled;
});
},
child: Container(
width: 40,
height: 25,
decoration: BoxDecoration(
color: enabled ? Color(0xFFBDCED6) : Colors.grey[500],
border: Border(
top: BorderSide(
width: 1,
color: enabled ? Color(0xFF000000) : Color(0xFFFFFFFF)),
left: BorderSide(
width: 1,
color: enabled ? Color(0xFF000000) : Color(0xFFFFFFFF)),
right: BorderSide(
width: 2,
color: enabled ? Color(0xFFFFFFFF) : Color(0xFF000000)),
bottom: BorderSide(
width: 2,
color: enabled ? Color(0xFFFFFFFF) : Color(0xFF000000)),
)),
child: Row(mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [
Container(
height: 10,
width: 10,
decoration: BoxDecoration(
color: widget.light,
border: Border.all(color: Color(0xFF000000), width: 1)),
),
Text(
widget.text,
style: TextStyle(
fontFamily: 'Pixer', color: Colors.black, fontSize: 16),
),
]),
),
);
}
}
class ControlLabel extends StatelessWidget {
final String text;
final bool enabled;
final Function onPress;
ControlLabel({this.text, this.enabled, this.onPress});
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: onPress,
child: Text(
text,
style: TextStyle(
fontFamily: 'Pixer',
fontSize: 18,
color: enabled ? Color(0XFF04E406) : Colors.white),
),
);
}
}
class MiniControls extends StatefulWidget {
final String units;
final double initialValue;
final double min;
final double max;
final Function control;
MiniControls(
{this.units, this.initialValue, this.min, this.max, this.control});
@override
_MiniControlsState createState() => _MiniControlsState();
}
class _MiniControlsState extends State<MiniControls> {
double _value = 0;
@override
void initState() {
_value = widget.initialValue;
super.initState();
}
@override
Widget build(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Container(
width: 45,
height: 32,
padding: EdgeInsets.symmetric(horizontal: 3, vertical: 2),
decoration: BoxDecoration(
color: Color(0xFF040405),
border: Border(
right: BorderSide(width: 2, color: Color(0xFF555569)),
bottom: BorderSide(width: 2, color: Color(0xFF555569)),
),
image: DecorationImage(
image: NetworkImage(
'https://github.com/ishandeveloper/WinAMP_Flutter/blob/master/assets/gridtexture.png?raw=false'),
fit: BoxFit.fill,
repeat: ImageRepeat.repeat),
),
child: Text(
_value.toString(),
textAlign: TextAlign.center,
style: TextStyle(
fontFamily: 'Pixer',
fontSize: 19,
color: Color(0XFF04E406)),
),
),
SizedBox(
width: 5,
),
Text(
widget.units,
style: TextStyle(
fontFamily: 'Pixer', fontSize: 18, color: Colors.white),
),
],
),
SizedBox(height: 10),
Container(
padding: EdgeInsets.all(0),
width: 110,
child: AwesomeSlider(
value: _value,
min: widget.min,
max: widget.max,
thumbSize: 22.0,
sliderWidth: 80.0,
thumbColor: Colors.grey[500],
roundedRectangleThumbRadius: 0.0,
topLeftShadow: false,
bottomRightShadow: true,
bottomRightShadowBlur: MaskFilter.blur(BlurStyle.outer, 3),
bottomRightShadowColor: Colors.black,
activeLineStroke: 2.0,
activeLineColor: Color(0xFF248A19),
inactiveLineColor: Color(0xFF248A19),
child: Padding(
padding: EdgeInsets.all(2.0),
child: Center(
child: Text(
'〣 ',
style: TextStyle(
color: Colors.black,
fontSize: 18.0,
fontFamily: 'Pixer',
fontWeight: FontWeight.bold,
),
)),
),
onChanged: (double value) {
widget.control(value);
setState(() {
_value = value;
});
},
),
),
],
);
}
}
class TrackNameBar extends StatelessWidget {
final String trackName;
TrackNameBar(this.trackName);
@override
Widget build(BuildContext context) {
return Container(
width: 460,
height: 32,
padding: EdgeInsets.symmetric(horizontal: 6, vertical: 2),
decoration: BoxDecoration(
color: Color(0xFF040405),
border: Border(
right: BorderSide(width: 2, color: Color(0xFF555569)),
bottom: BorderSide(width: 2, color: Color(0xFF555569)),
),
image: DecorationImage(
image: NetworkImage(
'https://github.com/ishandeveloper/WinAMP_Flutter/blob/master/assets/gridtexture.png?raw=false'),
fit: BoxFit.fill,
repeat: ImageRepeat.repeat),
),
child: Text(
this.trackName,
textAlign: TextAlign.right,
style: TextStyle(
fontFamily: 'Pixer', fontSize: 18, color: Color(0XFF04E406)),
),
);
}
}
class MainInfoWidget extends StatelessWidget {
final String minutes;
final String seconds;
final bool playing;
MainInfoWidget({this.minutes, this.seconds, this.playing});
@override
Widget build(BuildContext context) {
return Container(
width: 250,
height: 150,
decoration: BoxDecoration(
color: Color(0xFF040405),
border: Border(
right: BorderSide(width: 2, color: Color(0xFF555569)),
bottom: BorderSide(width: 2, color: Color(0xFF555569)),
),
image: DecorationImage(
image: NetworkImage(
'https://github.com/ishandeveloper/WinAMP_Flutter/blob/master/assets/gridtexture.png?raw=false'),
fit: BoxFit.fill,
repeat: ImageRepeat.repeat),
),
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
SidebarText(),
Column(
children: [
MusicTimer(minutes: this.minutes, seconds: this.seconds),
Container(
width: 190,
height: 50,
decoration: BoxDecoration(
image: DecorationImage(
image: playing
? NetworkImage(
'https://github.com/ishandeveloper/WinAMP_Flutter/blob/master/assets/music_bars.gif?raw=false')
: NetworkImage(
'https://github.com/ishandeveloper/WinAMP_Flutter/blob/master/assets/musicbars.png?raw=false')),
),
)
],
),
],
),
),
);
}
}
class SidebarText extends StatelessWidget {
const SidebarText({
Key key,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Text(
"O",
style: TextStyle(
fontFamily: 'Pixer',
color: Color(0xFF404C61),
fontSize: 20,
),
),
Text(
"A",
style: TextStyle(
fontFamily: 'Pixer',
color: Color(0xFF404C61),
fontSize: 20,
),
),
Text(
"I",
style: TextStyle(
fontFamily: 'Pixer',
color: Color(0xFF404C61),
fontSize: 20,
),
),
Text(
"D",
style: TextStyle(
fontFamily: 'Pixer',
color: Color(0xFF404C61),
fontSize: 20,
),
),
Text(
"V",
style: TextStyle(
fontFamily: 'Pixer',
color: Color(0xFF404C61),
fontSize: 20,
),
),
],
);
}
}
class MusicTimer extends StatelessWidget {
final String minutes;
final String seconds;
MusicTimer({this.minutes, this.seconds});
@override
Widget build(BuildContext context) {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Text(
"▶- ",
style: TextStyle(
fontFamily: 'Pixer', fontSize: 36, color: Color(0XFF04E406)),
),
Text(
"${this.minutes}:${this.seconds}",
style: TextStyle(
fontFamily: 'Pixer', fontSize: 64, color: Color(0XFF04E406)),
),
],
);
}
}
class WinLogo extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
width: 36,
height: 36,
decoration: BoxDecoration(
// color: Colors.white,
image: DecorationImage(
image: NetworkImage(
'https://github.com/ishandeveloper/WinAMP_Flutter/blob/master/assets/logo.png?raw=false',
),
fit: BoxFit.cover,
)),
);
}
}
class NavLine extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
width: 285,
color: Colors.yellow,
height: 5,
);
}
}
/* MOBILE */
class MobileUI extends StatefulWidget {
@override
_MobileUIState createState() => _MobileUIState();
}
class _MobileUIState extends State<MobileUI> {
bool mono = false;
double seekTime = 0;
String currentTrack = "No Track Selected";
String trackMin = "00";
String trackSec = "00";
int trackMinint = 0;
int trackSecint = 0;
bool paused = true;
bool initial = true;
@override
void initState() {
setState(() {
mono = false;
seekTime = 0;
currentTrack = "No Track Selected";
trackMin = "00";
trackSec = "00";
trackMinint = 0;
trackSecint = 0;
});
super.initState();
}
@override
Widget build(BuildContext context) {
// ignore: unused_element
void stopMusic() {
setState(() {
paused = true;
currentTrack = "No Track Selected";
});
}
void trackTime() {
setState(() {
// ignore: division_optimization
trackMinint = (seekTime / 60).toInt();
trackSecint = (seekTime - (trackMinint * 60)).toInt();
});
if (trackSecint < 10) {
setState(() {
trackSec = "0" + trackSecint.toString();
});
} else {
setState(() {
trackSec = trackSecint.toString();
});
}
setState(() {
trackMin = "0" + trackMinint.toString();
});
if (trackMin == "03" && trackSec == "04") {
setState(() {
seekTime = 0;
trackMinint = 0;
trackSecint = 0;
trackMin = "00";
trackSec = "00";
});
stopMusic();
// seekAudio(0);
}
}
void seeker() async {
Timer.periodic(Duration(milliseconds: 1000), (timer) {
if (!paused) {
trackTime();
if (seekTime == 185) {
stopMusic();
}
setState(() {
seekTime += 1;
});
} else {
// dispose();
}
});
}
// ignore: unused_element
void playMusic() {
if (paused) {
// playAudio();
setState(() {
paused = false;
// initial=false;
currentTrack = "Silent - DEMO Track (*JavaScript Required)";
});
if (initial) {
setState(() {
initial = false;
seekTime = 0;
});
seeker();
}
}
}
// ignore: unused_element
void seekMusic(double position) {
int time = position.toInt();
// seekAudio(time);
setState(() {
trackSecint = time;
seekTime = position;
});
trackTime();
}
// ignore: unused_element
void pauseMusic() {
// pauseAudio();
setState(() {
paused = true;
currentTrack = "PAUSED - Silent - DEMO Track";
});
}
return Scaffold(
body: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
MobileNav(),
Container(
width: MediaQuery.of(context).size.width * 0.97,
height: MediaQuery.of(context).size.height - 40,
decoration: BoxDecoration(
border: Border.all(color: Color(0xFF555569), width: 2.0),
gradient: LinearGradient(
begin: Alignment.centerLeft,
end: Alignment(0.8, 0.0),
colors: [
Color(0xFF212132),
Color(0XFF353454),
Color(0xFF474766),
],
tileMode: TileMode.repeated,
),
),
child: Padding(
padding: const EdgeInsets.only(left: 4.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
SizedBox(width: MediaQuery.of(context).size.width * 0.98),
SizedBox(height: 5),
MobileTrackBar(currentTrack),
SizedBox(height: 10),
MobileInfoWidget(
minutes: trackMin,
seconds: trackSec,
playing: !paused,
),
SizedBox(height: 15),
Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
MiniControls(
units: "kbps", initialValue: 160, min: 98, max: 320),
MiniControls(
units: "dB",
initialValue: 50,
min: 0,
max: 100,
control: (double level) {
// setAudioVolume(level);
},
),
MiniControls(
units: "kHz", initialValue: 44, min: 32, max: 98),
SizedBox(width: 10),
Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ControlLabel(
text: "mono",
enabled: mono,
onPress: () {
setState(() {
mono = true;
});
}),
SizedBox(height: 15),
MiniButton(light: Colors.yellow, text: "EQ"),
],
),
Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ControlLabel(
text: "stereo",
enabled: !mono,
onPress: () => setState(() {
mono = false;
})),
SizedBox(height: 15),
MiniButton(light: Colors.red, text: "PL"),
],
)
],
),
SizedBox(height: 40),
MobileSeekBar(
min: 0,
max: 185, // Time in seconds,
value: seekTime,
seek: (val) {
print("SEEKED" + val.toString());
seekMusic(val);
},
),
SizedBox(height: 40),
Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
RetroButton(
width: 60,
height: 40,
onPress: () {
seekMusic(0);
},
icon: Icons.fast_rewind),
// SizedBox(width: 10),
RetroButton(
onPress: () => playMusic(),
icon: Icons.play_arrow,
width: 60,
height: 40,
),
// SizedBox(width: 10),
RetroButton(
width: 60,
height: 40,
onPress: () => pauseMusic(),
icon: Icons.pause),
// SizedBox(width: 10),
RetroButton(
width: 60,
height: 40,
onPress: () {
stopMusic();
this.initState();
},
icon: Icons.stop),
// SizedBox(width: 10),
RetroButton(
width: 60,
height: 40,
icon: Icons.fast_forward,
onPress: () {},
),
],
),
SizedBox(height: 25),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
mainAxisSize: MainAxisSize.max,
children: [
Transform.scale(
scale: 1.25,
child: TextControlButton(
text: "Shuffle", light: Colors.red, width: 65),
),
Transform.scale(
scale: 1.25,
child: TextControlButton(
icon: true,
ico: Icons.repeat,
light: Colors.yellow,
width: 65),
)
],
),
SizedBox(
height: 20,
),
Container(
width: 54,
height: 54,
decoration: BoxDecoration(
// color: Colors.white,
image: DecorationImage(
image: NetworkImage(
'https://github.com/ishandeveloper/WinAMP_Flutter/blob/master/assets/logo2.png?raw=true',
),
fit: BoxFit.cover,
)),
)
],
),
),
),
],
),
);
}
}
// MOBILE SEEKBAR
class MobileSeekBar extends StatelessWidget {
final Function seek;
final double min;
final double max;
final double value;
MobileSeekBar({this.seek, this.min, this.max, this.value});
@override
Widget build(BuildContext context) {
return Row(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.max,
children: [
Container(
// decoration: BoxDecoration(color: Color(0xff1B1932)),
child: MobileSlider(
value: value,
min: min,
max: max,
thumbSize: 28.0,
sliderWidth: MediaQuery.of(context).size.width * 0.9,
thumbColor: Colors.yellow,
roundedRectangleThumbRadius: 0.0,
topLeftShadow: false,
bottomRightShadow: true,
bottomRightShadowBlur: MaskFilter.blur(BlurStyle.outer, 3),
bottomRightShadowColor: Colors.black,
activeLineStroke: 2.0,
activeLineColor: Color(0xff1B1932),
inactiveLineColor: Color(0xff1B1932),
child: Padding(
padding: EdgeInsets.all(2.0),
child: Center(
child: Text(
'──',
style: TextStyle(
color: Colors.black,
fontSize: 18.0,
fontFamily: 'Pixer',
fontWeight: FontWeight.bold,
),
)),
),
onChanged: (double val) {
seek(val);
},
),
),
],
);
}
}
// MOBILE SLIDER
class MobileSlider extends StatefulWidget {
MobileSlider({
this.value,
this.min,
this.max,
this.onChanged,
this.child,
this.sliderWidth,
this.thumbSize,
this.thumbColor = Colors.grey,
this.roundedRectangleThumbRadius = 0.0,
this.inactiveLineColor = Colors.blue,
this.inactiveLineStroke,
this.activeLineColor = Colors.blue,
this.activeLineStroke,
this.topLeftShadow = false,
this.topLeftShadowColor = Colors.blueGrey,
this.topLeftShadowBlur,
this.bottomRightShadow = false,
this.bottomRightShadowColor = Colors.blueGrey,
this.bottomRightShadowBlur,
}) : assert(value != null),
assert(min != null),
assert(max != null),
assert(min <= max),
assert(value >= min && value <= max);
/// Value of the Slider Position
/// (Value!=null)
/// (value >= min && value <= max)
final double value;
/// minimum value for the Slider
/// (min != null)
/// (min <= max)
final double min;
/// maximum value for the Slider
/// (max != null)
final double max;
/// Called when the user starts selecting a new value for the slider.
final ValueChanged<double> onChanged;
/// Provide a child Widget to the Slider Thumb
final Widget child;
/// Total Width of the Slider.
/// Default width will be the Canvas Width with a difference of 40px
final double sliderWidth;
/// Size of the thumb
/// Default value will be a 90px ratio of the original Canvas
final double thumbSize;
///Colour of the thumb
///Default colour is grey Colour
final Color thumbColor;
/// Give this radius to convert the Rectangle into a Rounded Rectangle
/// Increase in radius will make the rectangle into a circle
final double roundedRectangleThumbRadius;
///The color for the inactive portion of the slider track.
///Default colour is Blue Colour
final Color inactiveLineColor;
///The stroke value for the inactive portion of the slider track.
///Default stroke value is 4.0
///Value for inactiveLineStroke = activeLineStroke unless given different values for both
final double inactiveLineStroke;
///The color for the active portion of the slider track.
///Default colour is Blue Colour
final Color activeLineColor;
///The stroke value for the active portion of the slider track.
///Default stroke value is 4.0
///Value for activeLineStroke = inactiveLineStroke unless given different values for both
final double activeLineStroke;
///Give true value if a Shadow required on Top - Left of the thumb
final bool topLeftShadow;
///Colour of shadow of Top - Left of the thumb
///Default is Blue - Grey
final Color topLeftShadowColor;
///MaskFilter blur value for shadow of Top - Left of the thumb
///MaskFilter.blur(BlurStyle.normal, 3.0)
final MaskFilter topLeftShadowBlur;
///Give true value if a Shadow required on Bottom - Right of the thumb
final bool bottomRightShadow;
///Colour of shadow of Bottom - Right of the thumb
///Default is Blue - Grey
final Color bottomRightShadowColor;
///MaskFilter blur value for shadow of Top - Left of the thumb
///MaskFilter.blur(BlurStyle.normal, 3.0)
final MaskFilter bottomRightShadowBlur;
@override
_MobileSliderState createState() => _MobileSliderState();
}
class _MobileSliderState extends State<MobileSlider> {
double sliderXCoordinatePositionNow = 0.0;
double _strokeOfInactiveLine() => (widget.inactiveLineStroke == null)
? (widget.activeLineStroke == null) ? 4.0 : widget.activeLineStroke
: widget.inactiveLineStroke;
double _strokeOfActiveLine() => (widget.activeLineStroke == null)
? (widget.inactiveLineStroke == null) ? 4.0 : widget.inactiveLineStroke
: widget.activeLineStroke;
MaskFilter _topLeftShadowBlur() => (widget.topLeftShadowBlur == null)
? MaskFilter.blur(BlurStyle.normal, 3.0)
: widget.topLeftShadowBlur;
MaskFilter _bottomRightShadowBlur() => (widget.bottomRightShadowBlur == null)
? MaskFilter.blur(BlurStyle.normal, 3.0)
: widget.bottomRightShadowBlur;
double _incrementValueForThumb() =>
(widget.value == 0.0) ? widget.min : widget.value - widget.min;
double _lineLengthForPixel() => _sliderWidth() - _sliderHeight();
double _userValueForPixel() => widget.max - widget.min;
double _pixelDivision() => _lineLengthForPixel() / _userValueForPixel();
double _sliderChildPosition() => _incrementValueForThumb() * _pixelDivision();
double _sliderWidth() {
double userInputWidth = widget.sliderWidth;
double screenWidth = window.physicalSize.width;
double pixelRatio = window.devicePixelRatio;
double sliderWidth = (userInputWidth == null)
? ((screenWidth / pixelRatio) - 40.0)
: userInputWidth;
return sliderWidth;
}
double _sliderHeight() {
double userInputHeight = widget.thumbSize;
double screenHeight = window.physicalSize.height;
double pixelRatio = window.devicePixelRatio;
double multiplicationFactor = (90 / 805.3333334);
double sliderHeight = (userInputHeight == null)
? ((screenHeight / pixelRatio) * multiplicationFactor)
: userInputHeight;
return sliderHeight.roundToDouble();
// return 25;
}
void _onDragUpdate(DragUpdateDetails dragUpdateDetails) {
Offset localDragUpdate = dragUpdateDetails.localPosition;
double xCoordinate;
(localDragUpdate.dx < 0)
? xCoordinate = 0
: (localDragUpdate.dx > _sliderWidth())
? xCoordinate = _sliderWidth()
: xCoordinate = localDragUpdate.dx;
setState(() {
sliderXCoordinatePositionNow = xCoordinate;
});
}
void _onDragStart(DragStartDetails dragStartDetails) {
Offset localDragStart = dragStartDetails.localPosition;
double xCoordinate;
(localDragStart.dx < 0)
? xCoordinate = 0
: (localDragStart.dx > _sliderWidth())
? xCoordinate = _sliderWidth()
: xCoordinate = localDragStart.dx;
setState(() {
sliderXCoordinatePositionNow = xCoordinate;
});
}
void _value() {
double incrementValue = sliderXCoordinatePositionNow / _pixelDivision();
double value = (incrementValue > _userValueForPixel())
? _userValueForPixel()
: incrementValue;
double userValue = value + widget.min;
if (widget.onChanged != null) {
widget.onChanged(userValue);
}
}
@override
Widget build(BuildContext context) {
return GestureDetector(
behavior: HitTestBehavior.translucent,
onHorizontalDragUpdate: (DragUpdateDetails updateDetails) {
_onDragUpdate(updateDetails);
_value();
},
onHorizontalDragStart: (DragStartDetails startDetails) {
_onDragStart(startDetails);
_value();
},
child: Container(
padding: EdgeInsets.all(0.0),
child: Stack(
children: <Widget>[
Container(
height: _sliderHeight(),
width: _sliderWidth(),
child: CustomPaint(
painter: MobileSliderPaint(
sliderLength: _sliderWidth(),
thumbSize: _sliderHeight(),
thumbColor: widget.thumbColor,
value: _incrementValueForThumb(),
min: widget.min,
max: widget.max,
inactiveLineColor: widget.inactiveLineColor,
inactiveLineStroke: _strokeOfInactiveLine(),
activeLineColor: widget.activeLineColor,
activeLineStroke: _strokeOfActiveLine(),
currentTouchPosition: sliderXCoordinatePositionNow,
roundedThumbRadius: widget.roundedRectangleThumbRadius,
topLeftShadowColor: widget.topLeftShadowColor,
bottomRightShadowColor: widget.bottomRightShadowColor,
topLeftShadowBlurFactor: _topLeftShadowBlur(),
bottomRightShadowBlurFactor: _bottomRightShadowBlur(),
bottomRightShadow: widget.bottomRightShadow,
topLeftShadow: widget.topLeftShadow,
),
),
),
Positioned(
height: _sliderHeight(),
width: _sliderHeight(),
left: _sliderChildPosition(),
child: Container(
height: double.infinity,
width: double.infinity,
child: widget.child,
),
),
],
),
),
);
}
}
class MobileSliderPaint extends CustomPainter {
MobileSliderPaint({
@required this.sliderLength,
@required this.thumbSize,
@required this.thumbColor,
@required this.value,
@required this.min,
@required this.max,
@required this.roundedThumbRadius,
@required this.inactiveLineColor,
@required this.inactiveLineStroke,
@required this.currentTouchPosition,
@required this.activeLineColor,
@required this.activeLineStroke,
@required this.topLeftShadowColor,
@required this.bottomRightShadowColor,
@required this.topLeftShadowBlurFactor,
@required this.bottomRightShadowBlurFactor,
@required this.topLeftShadow,
@required this.bottomRightShadow,
});
final double sliderLength;
final double thumbSize;
final Color thumbColor;
final double value;
final double min;
final double max;
final double roundedThumbRadius;
final Color inactiveLineColor;
final double inactiveLineStroke;
final double currentTouchPosition;
final Color activeLineColor;
final double activeLineStroke;
final Color topLeftShadowColor;
final Color bottomRightShadowColor;
final MaskFilter bottomRightShadowBlurFactor;
final MaskFilter topLeftShadowBlurFactor;
final bool topLeftShadow;
final bool bottomRightShadow;
@override
void paint(Canvas canvas, Size size) {
double roundedRectangleTopLeftShadowShift = 13.0;
double roundedRectangleBottomRightShadowShift = 1.5;
double _increment() {
double lineLengthForPixel = sliderLength - thumbSize;
double userValueForPixel = max - min;
double pixelDivision = lineLengthForPixel / userValueForPixel;
return value * pixelDivision;
}
/// Inactive Line Paint
Path inactiveLinePath = Path();
Paint inactiveLinePaint = Paint()
..color = inactiveLineColor
..style = PaintingStyle.stroke
..strokeWidth = 20;
inactiveLinePath.moveTo(0.0, thumbSize / 2);
inactiveLinePath.lineTo(sliderLength, thumbSize / 2);
canvas.drawPath(inactiveLinePath, inactiveLinePaint);
/// Active Line Paint
Path activeLinePath = Path();
Paint activeLinePaint = Paint()
..color = activeLineColor
..style = PaintingStyle.stroke
..strokeWidth = 20;
activeLinePath.moveTo(0.0, thumbSize / 2);
activeLinePath.lineTo(currentTouchPosition, thumbSize / 2);
canvas.drawPath(activeLinePath, activeLinePaint);
/// Rounded Rectangle Top Left Shadow Paint
Path roundedRectangleTopLeftShadow = Path();
Paint roundedRectangleTopLeftShadowPaint = Paint()
..color = topLeftShadowColor
..maskFilter = topLeftShadowBlurFactor;
roundedRectangleTopLeftShadow.addRRect(RRect.fromLTRBR(
0.0 - roundedRectangleTopLeftShadowShift + _increment(),
0.0 - roundedRectangleTopLeftShadowShift,
thumbSize - roundedRectangleTopLeftShadowShift + _increment(),
thumbSize - roundedRectangleTopLeftShadowShift,
Radius.circular(roundedThumbRadius)));
if (topLeftShadow == true)
canvas.drawPath(
roundedRectangleTopLeftShadow, roundedRectangleTopLeftShadowPaint);
/// Rounded Rectangle Bottom Right Shadow Paint
Path roundedRectangleBottomRightShadow = Path();
Paint roundedRectangleBottomRightShadowPaint = Paint()
..color = bottomRightShadowColor
..maskFilter = bottomRightShadowBlurFactor;
roundedRectangleBottomRightShadow.addRRect(RRect.fromLTRBR(
0.0 + roundedRectangleBottomRightShadowShift + _increment(),
0.0 + roundedRectangleBottomRightShadowShift,
thumbSize + roundedRectangleBottomRightShadowShift + _increment(),
thumbSize + roundedRectangleBottomRightShadowShift,
Radius.circular(roundedThumbRadius)));
if (bottomRightShadow == true)
canvas.drawPath(roundedRectangleBottomRightShadow,
roundedRectangleBottomRightShadowPaint);
/// Rounded Rectangle Thumb Paint
Path roundedRectangle = Path();
Paint roundedRectanglePaint = Paint()..color = thumbColor;
roundedRectangle.addRRect(RRect.fromLTRBR(
-5.0 + _increment(),
0.0,
thumbSize + 5 + _increment(),
thumbSize,
Radius.circular(roundedThumbRadius)));
canvas.drawPath(roundedRectangle, roundedRectanglePaint);
}
@override
bool shouldRepaint(CustomPainter oldDelegate) {
return true;
}
}
// MOBILE TRACK BAR
class MobileTrackBar extends StatelessWidget {
final String trackName;
MobileTrackBar(this.trackName);
@override
Widget build(BuildContext context) {
return Container(
width: MediaQuery.of(context).size.width * 0.98,
height: 32,
padding: EdgeInsets.symmetric(horizontal: 6, vertical: 2),
decoration: BoxDecoration(
color: Color(0xFF040405),
border: Border(
right: BorderSide(width: 2, color: Color(0xFF555569)),
bottom: BorderSide(width: 2, color: Color(0xFF555569)),
),
image: DecorationImage(
image: NetworkImage(
'https://github.com/ishandeveloper/WinAMP_Flutter/blob/master/assets/gridtexture.png?raw=false'),
fit: BoxFit.fill,
repeat: ImageRepeat.repeat),
),
child: Text(
this.trackName,
textAlign: TextAlign.right,
style: TextStyle(
fontFamily: 'Pixer', fontSize: 18, color: Color(0XFF04E406)),
),
);
}
}
class MobileInfoWidget extends StatelessWidget {
final String minutes;
final String seconds;
final bool playing;
MobileInfoWidget({this.minutes, this.seconds, this.playing});
@override
Widget build(BuildContext context) {
return Container(
width: MediaQuery.of(context).size.width * 0.98,
height: 250,
decoration: BoxDecoration(
color: Color(0xFF040405),
border: Border(
right: BorderSide(width: 2, color: Color(0xFF555569)),
bottom: BorderSide(width: 2, color: Color(0xFF555569)),
),
image: DecorationImage(
image: NetworkImage(
'https://github.com/ishandeveloper/WinAMP_Flutter/blob/master/assets/gridtexture.png?raw=false'),
fit: BoxFit.fill,
repeat: ImageRepeat.repeat),
),
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
SizedBox(
width: MediaQuery.of(context).size.width * 0.9,
),
MusicTimer(
minutes: this.minutes,
seconds: this.seconds,
),
Container(
width: MediaQuery.of(context).size.width * 0.90,
height: 140,
decoration: BoxDecoration(
image: DecorationImage(
image: playing
? NetworkImage(
'https://github.com/ishandeveloper/WinAMP_Flutter/blob/master/assets/music_bars.gif?raw=false')
: NetworkImage(
'https://github.com/ishandeveloper/WinAMP_Flutter/blob/master/assets/musicbars.png?raw=false'),
),
),
)
],
),
],
),
),
);
}
}
// MOBILE NAV
class MobileNav extends StatelessWidget {
const MobileNav({
Key key,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 5, horizontal: 8),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Container(
width: MediaQuery.of(context).size.width * 0.33,
color: Colors.yellow,
height: 5,
),
SizedBox(width: 10),
Text(
"WINAMP",
style: TextStyle(
color: Colors.white,
fontFamily: 'Pixer',
fontSize: 18,
),
),
Container(
width: MediaQuery.of(context).size.width * 0.33,
color: Colors.yellow,
height: 5,
),
],
),
);
}
}
// AWESOME SLIDER
class AwesomeSlider extends StatefulWidget {
AwesomeSlider({
this.value,
this.min,
this.max,
this.onChanged,
this.child,
this.sliderWidth,
this.thumbSize,
this.thumbColor = Colors.grey,
this.roundedRectangleThumbRadius = 0.0,
this.inactiveLineColor = Colors.blue,
this.inactiveLineStroke,
this.activeLineColor = Colors.blue,
this.activeLineStroke,
this.topLeftShadow = false,
this.topLeftShadowColor = Colors.blueGrey,
this.topLeftShadowBlur,
this.bottomRightShadow = false,
this.bottomRightShadowColor = Colors.blueGrey,
this.bottomRightShadowBlur,
}) : assert(value != null),
assert(min != null),
assert(max != null),
assert(min <= max),
assert(value >= min && value <= max);
/// Value of the Slider Position
/// (Value!=null)
/// (value >= min && value <= max)
final double value;
/// minimum value for the Slider
/// (min != null)
/// (min <= max)
final double min;
/// maximum value for the Slider
/// (max != null)
final double max;
/// Called when the user starts selecting a new value for the slider.
final ValueChanged<double> onChanged;
/// Provide a child Widget to the Slider Thumb
final Widget child;
/// Total Width of the Slider.
/// Default width will be the Canvas Width with a difference of 40px
final double sliderWidth;
/// Size of the thumb
/// Default value will be a 90px ratio of the original Canvas
final double thumbSize;
///Colour of the thumb
///Default colour is grey Colour
final Color thumbColor;
/// Give this radius to convert the Rectangle into a Rounded Rectangle
/// Increase in radius will make the rectangle into a circle
final double roundedRectangleThumbRadius;
///The color for the inactive portion of the slider track.
///Default colour is Blue Colour
final Color inactiveLineColor;
///The stroke value for the inactive portion of the slider track.
///Default stroke value is 4.0
///Value for inactiveLineStroke = activeLineStroke unless given different values for both
final double inactiveLineStroke;
///The color for the active portion of the slider track.
///Default colour is Blue Colour
final Color activeLineColor;
///The stroke value for the active portion of the slider track.
///Default stroke value is 4.0
///Value for activeLineStroke = inactiveLineStroke unless given different values for both
final double activeLineStroke;
///Give true value if a Shadow required on Top - Left of the thumb
final bool topLeftShadow;
///Colour of shadow of Top - Left of the thumb
///Default is Blue - Grey
final Color topLeftShadowColor;
///MaskFilter blur value for shadow of Top - Left of the thumb
///MaskFilter.blur(BlurStyle.normal, 3.0)
final MaskFilter topLeftShadowBlur;
///Give true value if a Shadow required on Bottom - Right of the thumb
final bool bottomRightShadow;
///Colour of shadow of Bottom - Right of the thumb
///Default is Blue - Grey
final Color bottomRightShadowColor;
///MaskFilter blur value for shadow of Top - Left of the thumb
///MaskFilter.blur(BlurStyle.normal, 3.0)
final MaskFilter bottomRightShadowBlur;
@override
_AwesomeSliderState createState() => _AwesomeSliderState();
}
class _AwesomeSliderState extends State<AwesomeSlider> {
double sliderXCoordinatePositionNow = 0.0;
double _strokeOfInactiveLine() => (widget.inactiveLineStroke == null)
? (widget.activeLineStroke == null) ? 4.0 : widget.activeLineStroke
: widget.inactiveLineStroke;
double _strokeOfActiveLine() => (widget.activeLineStroke == null)
? (widget.inactiveLineStroke == null) ? 4.0 : widget.inactiveLineStroke
: widget.activeLineStroke;
MaskFilter _topLeftShadowBlur() => (widget.topLeftShadowBlur == null)
? MaskFilter.blur(BlurStyle.normal, 3.0)
: widget.topLeftShadowBlur;
MaskFilter _bottomRightShadowBlur() => (widget.bottomRightShadowBlur == null)
? MaskFilter.blur(BlurStyle.normal, 3.0)
: widget.bottomRightShadowBlur;
double _incrementValueForThumb() =>
(widget.value == 0.0) ? widget.min : widget.value - widget.min;
double _lineLengthForPixel() => _sliderWidth() - _sliderHeight();
double _userValueForPixel() => widget.max - widget.min;
double _pixelDivision() => _lineLengthForPixel() / _userValueForPixel();
double _sliderChildPosition() => _incrementValueForThumb() * _pixelDivision();
double _sliderWidth() {
double userInputWidth = widget.sliderWidth;
double screenWidth = window.physicalSize.width;
double pixelRatio = window.devicePixelRatio;
double sliderWidth = (userInputWidth == null)
? ((screenWidth / pixelRatio) - 40.0)
: userInputWidth;
return sliderWidth;
}
double _sliderHeight() {
double userInputHeight = widget.thumbSize;
double screenHeight = window.physicalSize.height;
double pixelRatio = window.devicePixelRatio;
double multiplicationFactor = (90 / 805.3333334);
double sliderHeight = (userInputHeight == null)
? ((screenHeight / pixelRatio) * multiplicationFactor)
: userInputHeight;
return sliderHeight.roundToDouble();
}
void _onDragUpdate(DragUpdateDetails dragUpdateDetails) {
Offset localDragUpdate = dragUpdateDetails.localPosition;
double xCoordinate;
(localDragUpdate.dx < 0)
? xCoordinate = 0
: (localDragUpdate.dx > _sliderWidth())
? xCoordinate = _sliderWidth()
: xCoordinate = localDragUpdate.dx;
setState(() {
sliderXCoordinatePositionNow = xCoordinate;
});
}
void _onDragStart(DragStartDetails dragStartDetails) {
Offset localDragStart = dragStartDetails.localPosition;
double xCoordinate;
(localDragStart.dx < 0)
? xCoordinate = 0
: (localDragStart.dx > _sliderWidth())
? xCoordinate = _sliderWidth()
: xCoordinate = localDragStart.dx;
setState(() {
sliderXCoordinatePositionNow = xCoordinate;
});
}
void _value() {
double incrementValue = sliderXCoordinatePositionNow / _pixelDivision();
double value = (incrementValue > _userValueForPixel())
? _userValueForPixel()
: incrementValue;
double userValue = value + widget.min;
if (widget.onChanged != null) {
widget.onChanged(userValue);
}
}
@override
Widget build(BuildContext context) {
return GestureDetector(
behavior: HitTestBehavior.translucent,
onHorizontalDragUpdate: (DragUpdateDetails updateDetails) {
_onDragUpdate(updateDetails);
_value();
},
onHorizontalDragStart: (DragStartDetails startDetails) {
_onDragStart(startDetails);
_value();
},
child: Container(
padding: EdgeInsets.all(0.0),
child: Stack(
children: <Widget>[
Container(
height: _sliderHeight(),
width: _sliderWidth(),
child: CustomPaint(
painter: AwesomeSliderPaint(
sliderLength: _sliderWidth(),
thumbSize: _sliderHeight(),
thumbColor: widget.thumbColor,
value: _incrementValueForThumb(),
min: widget.min,
max: widget.max,
inactiveLineColor: widget.inactiveLineColor,
inactiveLineStroke: _strokeOfInactiveLine(),
activeLineColor: widget.activeLineColor,
activeLineStroke: _strokeOfActiveLine(),
currentTouchPosition: sliderXCoordinatePositionNow,
roundedThumbRadius: widget.roundedRectangleThumbRadius,
topLeftShadowColor: widget.topLeftShadowColor,
bottomRightShadowColor: widget.bottomRightShadowColor,
topLeftShadowBlurFactor: _topLeftShadowBlur(),
bottomRightShadowBlurFactor: _bottomRightShadowBlur(),
bottomRightShadow: widget.bottomRightShadow,
topLeftShadow: widget.topLeftShadow,
),
),
),
Positioned(
height: _sliderHeight(),
width: _sliderHeight(),
left: _sliderChildPosition(),
child: Container(
height: double.infinity,
width: double.infinity,
child: widget.child,
),
),
],
),
),
);
}
}
class AwesomeSliderPaint extends CustomPainter {
AwesomeSliderPaint({
@required this.sliderLength,
@required this.thumbSize,
@required this.thumbColor,
@required this.value,
@required this.min,
@required this.max,
@required this.roundedThumbRadius,
@required this.inactiveLineColor,
@required this.inactiveLineStroke,
@required this.currentTouchPosition,
@required this.activeLineColor,
@required this.activeLineStroke,
@required this.topLeftShadowColor,
@required this.bottomRightShadowColor,
@required this.topLeftShadowBlurFactor,
@required this.bottomRightShadowBlurFactor,
@required this.topLeftShadow,
@required this.bottomRightShadow,
});
final double sliderLength;
final double thumbSize;
final Color thumbColor;
final double value;
final double min;
final double max;
final double roundedThumbRadius;
final Color inactiveLineColor;
final double inactiveLineStroke;
final double currentTouchPosition;
final Color activeLineColor;
final double activeLineStroke;
final Color topLeftShadowColor;
final Color bottomRightShadowColor;
final MaskFilter bottomRightShadowBlurFactor;
final MaskFilter topLeftShadowBlurFactor;
final bool topLeftShadow;
final bool bottomRightShadow;
@override
void paint(Canvas canvas, Size size) {
double roundedRectangleTopLeftShadowShift = 13.0;
double roundedRectangleBottomRightShadowShift = 1.5;
double _increment() {
double lineLengthForPixel = sliderLength - thumbSize;
double userValueForPixel = max - min;
double pixelDivision = lineLengthForPixel / userValueForPixel;
return value * pixelDivision;
}
/// Inactive Line Paint
Path inactiveLinePath = Path();
Paint inactiveLinePaint = Paint()
..color = inactiveLineColor
..style = PaintingStyle.stroke
..strokeWidth = inactiveLineStroke;
inactiveLinePath.moveTo(0.0, thumbSize / 2);
inactiveLinePath.lineTo(sliderLength, thumbSize / 2);
canvas.drawPath(inactiveLinePath, inactiveLinePaint);
/// Active Line Paint
Path activeLinePath = Path();
Paint activeLinePaint = Paint()
..color = activeLineColor
..style = PaintingStyle.stroke
..strokeWidth = activeLineStroke;
activeLinePath.moveTo(0.0, thumbSize / 2);
activeLinePath.lineTo(currentTouchPosition, thumbSize / 2);
canvas.drawPath(activeLinePath, activeLinePaint);
/// Rounded Rectangle Top Left Shadow Paint
Path roundedRectangleTopLeftShadow = Path();
Paint roundedRectangleTopLeftShadowPaint = Paint()
..color = topLeftShadowColor
..maskFilter = topLeftShadowBlurFactor;
roundedRectangleTopLeftShadow.addRRect(RRect.fromLTRBR(
0.0 - roundedRectangleTopLeftShadowShift + _increment(),
0.0 - roundedRectangleTopLeftShadowShift,
thumbSize - roundedRectangleTopLeftShadowShift + _increment(),
thumbSize - roundedRectangleTopLeftShadowShift,
Radius.circular(roundedThumbRadius)));
if (topLeftShadow == true)
canvas.drawPath(
roundedRectangleTopLeftShadow, roundedRectangleTopLeftShadowPaint);
/// Rounded Rectangle Bottom Right Shadow Paint
Path roundedRectangleBottomRightShadow = Path();
Paint roundedRectangleBottomRightShadowPaint = Paint()
..color = bottomRightShadowColor
..maskFilter = bottomRightShadowBlurFactor;
roundedRectangleBottomRightShadow.addRRect(RRect.fromLTRBR(
0.0 + roundedRectangleBottomRightShadowShift + _increment(),
0.0 + roundedRectangleBottomRightShadowShift,
thumbSize + roundedRectangleBottomRightShadowShift + _increment(),
thumbSize + roundedRectangleBottomRightShadowShift,
Radius.circular(roundedThumbRadius)));
if (bottomRightShadow == true)
canvas.drawPath(roundedRectangleBottomRightShadow,
roundedRectangleBottomRightShadowPaint);
/// Rounded Rectangle Thumb Paint
Path roundedRectangle = Path();
Paint roundedRectanglePaint = Paint()..color = thumbColor;
roundedRectangle.addRRect(RRect.fromLTRBR(
0.0 + _increment(),
0.0,
thumbSize + _increment(),
thumbSize,
Radius.circular(roundedThumbRadius)));
canvas.drawPath(roundedRectangle, roundedRectanglePaint);
}
@override
bool shouldRepaint(CustomPainter oldDelegate) {
return true;
}
}
// CUSTOM SLIDER
class CustomSlider extends StatefulWidget {
CustomSlider({
this.value,
this.min,
this.max,
this.onChanged,
this.child,
this.sliderWidth,
this.thumbSize,
this.thumbColor = Colors.grey,
this.roundedRectangleThumbRadius = 0.0,
this.inactiveLineColor = Colors.blue,
this.inactiveLineStroke,
this.activeLineColor = Colors.blue,
this.activeLineStroke,
this.topLeftShadow = false,
this.topLeftShadowColor = Colors.blueGrey,
this.topLeftShadowBlur,
this.bottomRightShadow = false,
this.bottomRightShadowColor = Colors.blueGrey,
this.bottomRightShadowBlur,
}) : assert(value != null),
assert(min != null),
assert(max != null),
assert(min <= max),
assert(value >= min && value <= max);
/// Value of the Slider Position
/// (Value!=null)
/// (value >= min && value <= max)
final double value;
/// minimum value for the Slider
/// (min != null)
/// (min <= max)
final double min;
/// maximum value for the Slider
/// (max != null)
final double max;
/// Called when the user starts selecting a new value for the slider.
final ValueChanged<double> onChanged;
/// Provide a child Widget to the Slider Thumb
final Widget child;
/// Total Width of the Slider.
/// Default width will be the Canvas Width with a difference of 40px
final double sliderWidth;
/// Size of the thumb
/// Default value will be a 90px ratio of the original Canvas
final double thumbSize;
///Colour of the thumb
///Default colour is grey Colour
final Color thumbColor;
/// Give this radius to convert the Rectangle into a Rounded Rectangle
/// Increase in radius will make the rectangle into a circle
final double roundedRectangleThumbRadius;
///The color for the inactive portion of the slider track.
///Default colour is Blue Colour
final Color inactiveLineColor;
///The stroke value for the inactive portion of the slider track.
///Default stroke value is 4.0
///Value for inactiveLineStroke = activeLineStroke unless given different values for both
final double inactiveLineStroke;
///The color for the active portion of the slider track.
///Default colour is Blue Colour
final Color activeLineColor;
///The stroke value for the active portion of the slider track.
///Default stroke value is 4.0
///Value for activeLineStroke = inactiveLineStroke unless given different values for both
final double activeLineStroke;
///Give true value if a Shadow required on Top - Left of the thumb
final bool topLeftShadow;
///Colour of shadow of Top - Left of the thumb
///Default is Blue - Grey
final Color topLeftShadowColor;
///MaskFilter blur value for shadow of Top - Left of the thumb
///MaskFilter.blur(BlurStyle.normal, 3.0)
final MaskFilter topLeftShadowBlur;
///Give true value if a Shadow required on Bottom - Right of the thumb
final bool bottomRightShadow;
///Colour of shadow of Bottom - Right of the thumb
///Default is Blue - Grey
final Color bottomRightShadowColor;
///MaskFilter blur value for shadow of Top - Left of the thumb
///MaskFilter.blur(BlurStyle.normal, 3.0)
final MaskFilter bottomRightShadowBlur;
@override
_CustomSliderState createState() => _CustomSliderState();
}
class _CustomSliderState extends State<CustomSlider> {
double sliderXCoordinatePositionNow = 0.0;
double _strokeOfInactiveLine() => (widget.inactiveLineStroke == null)
? (widget.activeLineStroke == null) ? 4.0 : widget.activeLineStroke
: widget.inactiveLineStroke;
double _strokeOfActiveLine() => (widget.activeLineStroke == null)
? (widget.inactiveLineStroke == null) ? 4.0 : widget.inactiveLineStroke
: widget.activeLineStroke;
MaskFilter _topLeftShadowBlur() => (widget.topLeftShadowBlur == null)
? MaskFilter.blur(BlurStyle.normal, 3.0)
: widget.topLeftShadowBlur;
MaskFilter _bottomRightShadowBlur() => (widget.bottomRightShadowBlur == null)
? MaskFilter.blur(BlurStyle.normal, 3.0)
: widget.bottomRightShadowBlur;
double _incrementValueForThumb() =>
(widget.value == 0.0) ? widget.min : widget.value - widget.min;
double _lineLengthForPixel() => _sliderWidth() - _sliderHeight();
double _userValueForPixel() => widget.max - widget.min;
double _pixelDivision() => _lineLengthForPixel() / _userValueForPixel();
double _sliderChildPosition() => _incrementValueForThumb() * _pixelDivision();
double _sliderWidth() {
double userInputWidth = widget.sliderWidth;
double screenWidth = window.physicalSize.width;
double pixelRatio = window.devicePixelRatio;
double sliderWidth = (userInputWidth == null)
? ((screenWidth / pixelRatio) - 40.0)
: userInputWidth;
return sliderWidth;
}
double _sliderHeight() {
double userInputHeight = widget.thumbSize;
double screenHeight = window.physicalSize.height;
double pixelRatio = window.devicePixelRatio;
double multiplicationFactor = (90 / 805.3333334);
double sliderHeight = (userInputHeight == null)
? ((screenHeight / pixelRatio) * multiplicationFactor)
: userInputHeight;
return sliderHeight.roundToDouble();
// return 25;
}
void _onDragUpdate(DragUpdateDetails dragUpdateDetails) {
Offset localDragUpdate = dragUpdateDetails.localPosition;
double xCoordinate;
(localDragUpdate.dx < 0)
? xCoordinate = 0
: (localDragUpdate.dx > _sliderWidth())
? xCoordinate = _sliderWidth()
: xCoordinate = localDragUpdate.dx;
setState(() {
sliderXCoordinatePositionNow = xCoordinate;
});
}
void _onDragStart(DragStartDetails dragStartDetails) {
Offset localDragStart = dragStartDetails.localPosition;
double xCoordinate;
(localDragStart.dx < 0)
? xCoordinate = 0
: (localDragStart.dx > _sliderWidth())
? xCoordinate = _sliderWidth()
: xCoordinate = localDragStart.dx;
setState(() {
sliderXCoordinatePositionNow = xCoordinate;
});
}
void _value() {
double incrementValue = sliderXCoordinatePositionNow / _pixelDivision();
double value = (incrementValue > _userValueForPixel())
? _userValueForPixel()
: incrementValue;
double userValue = value + widget.min;
if (widget.onChanged != null) {
widget.onChanged(userValue);
}
}
@override
Widget build(BuildContext context) {
return GestureDetector(
behavior: HitTestBehavior.translucent,
onHorizontalDragUpdate: (DragUpdateDetails updateDetails) {
_onDragUpdate(updateDetails);
_value();
},
onHorizontalDragStart: (DragStartDetails startDetails) {
_onDragStart(startDetails);
_value();
},
child: Container(
padding: EdgeInsets.all(0.0),
child: Stack(
children: <Widget>[
Container(
height: _sliderHeight(),
width: _sliderWidth(),
child: CustomPaint(
painter: CustomSliderPaint(
sliderLength: _sliderWidth(),
thumbSize: _sliderHeight(),
thumbColor: widget.thumbColor,
value: _incrementValueForThumb(),
min: widget.min,
max: widget.max,
inactiveLineColor: widget.inactiveLineColor,
inactiveLineStroke: _strokeOfInactiveLine(),
activeLineColor: widget.activeLineColor,
activeLineStroke: _strokeOfActiveLine(),
currentTouchPosition: sliderXCoordinatePositionNow,
roundedThumbRadius: widget.roundedRectangleThumbRadius,
topLeftShadowColor: widget.topLeftShadowColor,
bottomRightShadowColor: widget.bottomRightShadowColor,
topLeftShadowBlurFactor: _topLeftShadowBlur(),
bottomRightShadowBlurFactor: _bottomRightShadowBlur(),
bottomRightShadow: widget.bottomRightShadow,
topLeftShadow: widget.topLeftShadow,
),
),
),
Positioned(
height: _sliderHeight(),
width: _sliderHeight(),
left: _sliderChildPosition(),
child: Container(
height: double.infinity,
width: double.infinity,
child: widget.child,
),
),
],
),
),
);
}
}
class CustomSliderPaint extends CustomPainter {
CustomSliderPaint({
@required this.sliderLength,
@required this.thumbSize,
@required this.thumbColor,
@required this.value,
@required this.min,
@required this.max,
@required this.roundedThumbRadius,
@required this.inactiveLineColor,
@required this.inactiveLineStroke,
@required this.currentTouchPosition,
@required this.activeLineColor,
@required this.activeLineStroke,
@required this.topLeftShadowColor,
@required this.bottomRightShadowColor,
@required this.topLeftShadowBlurFactor,
@required this.bottomRightShadowBlurFactor,
@required this.topLeftShadow,
@required this.bottomRightShadow,
});
final double sliderLength;
final double thumbSize;
final Color thumbColor;
final double value;
final double min;
final double max;
final double roundedThumbRadius;
final Color inactiveLineColor;
final double inactiveLineStroke;
final double currentTouchPosition;
final Color activeLineColor;
final double activeLineStroke;
final Color topLeftShadowColor;
final Color bottomRightShadowColor;
final MaskFilter bottomRightShadowBlurFactor;
final MaskFilter topLeftShadowBlurFactor;
final bool topLeftShadow;
final bool bottomRightShadow;
@override
void paint(Canvas canvas, Size size) {
double roundedRectangleTopLeftShadowShift = 13.0;
double roundedRectangleBottomRightShadowShift = 1.5;
double _increment() {
double lineLengthForPixel = sliderLength - thumbSize;
double userValueForPixel = max - min;
double pixelDivision = lineLengthForPixel / userValueForPixel;
return value * pixelDivision;
}
/// Inactive Line Paint
Path inactiveLinePath = Path();
Paint inactiveLinePaint = Paint()
..color = inactiveLineColor
..style = PaintingStyle.stroke
..strokeWidth = 30;
inactiveLinePath.moveTo(0.0, thumbSize / 2);
inactiveLinePath.lineTo(sliderLength, thumbSize / 2);
canvas.drawPath(inactiveLinePath, inactiveLinePaint);
/// Active Line Paint
Path activeLinePath = Path();
Paint activeLinePaint = Paint()
..color = activeLineColor
..style = PaintingStyle.stroke
..strokeWidth = 32;
activeLinePath.moveTo(0.0, thumbSize / 2);
activeLinePath.lineTo(currentTouchPosition, thumbSize / 2);
canvas.drawPath(activeLinePath, activeLinePaint);
/// Rounded Rectangle Top Left Shadow Paint
Path roundedRectangleTopLeftShadow = Path();
Paint roundedRectangleTopLeftShadowPaint = Paint()
..color = topLeftShadowColor
..maskFilter = topLeftShadowBlurFactor;
roundedRectangleTopLeftShadow.addRRect(RRect.fromLTRBR(
0.0 - roundedRectangleTopLeftShadowShift + _increment(),
0.0 - roundedRectangleTopLeftShadowShift,
thumbSize - roundedRectangleTopLeftShadowShift + _increment(),
thumbSize - roundedRectangleTopLeftShadowShift,
Radius.circular(roundedThumbRadius)));
if (topLeftShadow == true)
canvas.drawPath(
roundedRectangleTopLeftShadow, roundedRectangleTopLeftShadowPaint);
/// Rounded Rectangle Bottom Right Shadow Paint
Path roundedRectangleBottomRightShadow = Path();
Paint roundedRectangleBottomRightShadowPaint = Paint()
..color = bottomRightShadowColor
..maskFilter = bottomRightShadowBlurFactor;
roundedRectangleBottomRightShadow.addRRect(RRect.fromLTRBR(
0.0 + roundedRectangleBottomRightShadowShift + _increment(),
0.0 + roundedRectangleBottomRightShadowShift,
thumbSize + roundedRectangleBottomRightShadowShift + _increment(),
thumbSize + roundedRectangleBottomRightShadowShift,
Radius.circular(roundedThumbRadius)));
if (bottomRightShadow == true)
canvas.drawPath(roundedRectangleBottomRightShadow,
roundedRectangleBottomRightShadowPaint);
/// Rounded Rectangle Thumb Paint
Path roundedRectangle = Path();
Paint roundedRectanglePaint = Paint()..color = thumbColor;
roundedRectangle.addRRect(RRect.fromLTRBR(
-5.0 + _increment(),
0.0,
thumbSize + 5 + _increment(),
thumbSize,
Radius.circular(roundedThumbRadius)));
canvas.drawPath(roundedRectangle, roundedRectanglePaint);
}
@override
bool shouldRepaint(CustomPainter oldDelegate) {
return true;
}
}
Also see: Tab Triggers