/*
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;
}
}
View Compiled
This Pen doesn't use any external CSS resources.
This Pen doesn't use any external JavaScript resources.