JavaScript preprocessors can help make authoring JavaScript easier and more convenient. For instance, CoffeeScript can help prevent easy-to-make mistakes and offer a cleaner syntax and Babel can bring ECMAScript 6 features to browsers that only support ECMAScript 5.
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.
import 'dart:html';
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
void main() {
runApp(MaterialApp(
home: Home(),
debugShowCheckedModeBanner: false,
));
}
class Home extends StatefulWidget {
@override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> with TickerProviderStateMixin {
AnimationController _animationController;
Animation<double> _animation;
AnimationController _confettiController;
Animation<int> _confettiAnimation;
final _followersCount = ValueNotifier<int>(0);
final _pageController = PageController(initialPage: 0);
int maxLength = 6;
final shapeColor = <Color>[
Color(0xFF2F4E92),
Color(0xFF6BE222),
Color(0xFFCECCB2),
Color(0xFFD4BBA5),
Color(0xFFBBBBBB),
Colors.white,
];
final shapeSize = <Size>[
Size(330, 630),
Size(300, 500),
Size(400, 500),
Size(300, 600),
Size(600, 440),
Size(854, 480),
];
final shapeRadius = <BorderRadius>[
BorderRadius.only(
topLeft: Radius.circular(30),
topRight: Radius.circular(30),
bottomLeft: Radius.circular(30),
bottomRight: Radius.circular(30)),
BorderRadius.only(
topLeft: Radius.circular(15),
topRight: Radius.circular(15),
bottomLeft: Radius.circular(15),
bottomRight: Radius.circular(15)),
BorderRadius.only(
topLeft: Radius.circular(10),
topRight: Radius.circular(10),
bottomLeft: Radius.circular(10),
bottomRight: Radius.circular(10)),
BorderRadius.only(
topLeft: Radius.circular(30),
topRight: Radius.circular(30),
bottomLeft: Radius.circular(30),
bottomRight: Radius.circular(30)),
BorderRadius.only(
topLeft: Radius.circular(30),
topRight: Radius.circular(30),
bottomLeft: Radius.circular(0),
bottomRight: Radius.circular(0)),
BorderRadius.circular(0),
];
final screenSize = <Size>[
Size(280, 500),
Size(180, 170),
Size(300, 300),
Size(270, 480),
Size(540, 310),
Size(854, 480),
];
final screenMargin = <double>[
60,
50,
40,
60,
60,
0,
];
final screenColor = <Color>[
Colors.transparent,
Colors.transparent,
Colors.transparent,
Colors.transparent,
Colors.transparent,
Colors.transparent,
];
final bodyWidgets = <Widget>[
Pixel(),
Gameboy(),
Macintosh(),
SmartPhone(),
Chromebook(),
SizedBox(),
];
final fontFamily = <String>[
'Roboto',
'Gameboy',
'Macintosh',
'Iphone',
'Roboto',
'Roboto',
];
final fontSize = <double>[
40,
30,
30,
20,
18,
25,
];
final fontAlign = <Alignment>[
Alignment(0.04, 0.3),
Alignment(0.9, -0.9),
Alignment(0.8, 0.5),
Alignment(0.95, 0.74),
Alignment(-0.48, 0.74),
Alignment(-0.47, 0.73),
];
final fontColor = <Color>[
Colors.black,
Colors.white,
Colors.grey[600],
Colors.white,
Colors.black,
Colors.black,
];
ScrollPhysics _physics = NeverScrollableScrollPhysics();
final listAngle = List<double>.generate(
Utils.listLength, (index) => (Random().nextDouble() * (Random().nextBool() ? -1 : 1) * Random().nextInt(360)));
final listOffset = List<int>.generate(Utils.listLength, (index) => Random().nextInt(100) * -1);
final listPositivity = List<bool>.generate(Utils.listLength, (index) => Random().nextBool());
final listColor =
List<Color>.generate(Utils.listLength, (index) => Colors.primaries[Random().nextInt(Colors.primaries.length)]);
final listPow = List<double>.generate(Utils.listLength, (index) => Utils.doubleInRange(Random(), 0.1, 0.4));
bool loading = true;
bool finished = false;
void start() {
_animationController.forward();
_animationController.addStatusListener((status) async {
if (status == AnimationStatus.completed) {
_confettiController.forward();
}
});
}
@override
void initState() {
super.initState();
_loadFonts();
_animationController = AnimationController(duration: Duration(seconds: 15), vsync: this);
_animation = CurvedAnimation(parent: _animationController, curve: Curves.easeIn);
_animation.addListener(_onAnimationChanged);
// CONFETTI CONTROLLER
_confettiController = AnimationController(duration: Duration(milliseconds: 2500), vsync: this);
_confettiAnimation =
IntTween(begin: 0, end: 200).animate(CurvedAnimation(parent: _confettiController, curve: Curves.easeOutQuad))
..addListener(() {
setState(() {
_confettiAnimation.value;
});
});
_confettiController.addStatusListener((status) {
if (status == AnimationStatus.completed) {
setState(() => finished = true);
}
});
// setState(() => _physics = ClampingScrollPhysics());
}
void _onAnimationChanged() {
final newPage = (_animation.value * (maxLength - 1)).round();
if (_pageController.page.round() != newPage) {
_pageController.jumpToPage(newPage);
}
final fraction = Duration(milliseconds: 650).inMilliseconds / _animationController.duration.inMilliseconds;
final maxFollowers = 100000 + (100000 * fraction).toInt();
final newFollowersCount = min((_animation.value * maxFollowers).toInt(), 100000);
_followersCount.value = newFollowersCount;
}
void _loadFonts() async {
// LOAD FONTS
final gameboy = await FontFace('Gameboy', 'url(https://assets.codepen.io/2399829/gameboy.ttf)').load();
final macintosh = await FontFace('Macintosh', 'url(https://assets.codepen.io/2399829/macintosh.ttf)').load();
final iphone = await FontFace('Iphone', 'url(https://assets.codepen.io/2399829/iphone.otf)').load();
document.fonts.add(gameboy);
document.fonts.add(macintosh);
document.fonts.add(iphone);
// LOAD IMAGES
final gbc = Image.network('https://assets.codepen.io/2399829/gbcbg.png', fit: BoxFit.cover);
await precacheImage(gbc.image, context);
final mac = Image.network('https://assets.codepen.io/2399829/macintosh.png', fit: BoxFit.cover);
await precacheImage(mac.image, context);
final ios = Image.network('https://assets.codepen.io/2399829/iphone_bg.jpg', fit: BoxFit.cover);
await precacheImage(ios.image, context);
final iconOne = Image.network('https://assets.codepen.io/2399829/icon_one.png', fit: BoxFit.fill);
await precacheImage(iconOne.image, context);
final iconTwo = Image.network('https://assets.codepen.io/2399829/icon_two.png', fit: BoxFit.fill);
await precacheImage(iconTwo.image, context);
final iconThree = Image.network('https://assets.codepen.io/2399829/icon_three.png', fit: BoxFit.fill);
await precacheImage(iconThree.image, context);
final iconFour = Image.network('https://assets.codepen.io/2399829/icon_four.png', fit: BoxFit.fill);
await precacheImage(iconFour.image, context);
final iconFive = Image.network('https://assets.codepen.io/2399829/icon_five.png', fit: BoxFit.fill);
await precacheImage(iconFive.image, context);
final iconEmail = Image.network('https://assets.codepen.io/2399829/email.png', fit: BoxFit.fill);
await precacheImage(iconEmail.image, context);
final chrome = Image.network('https://assets.codepen.io/2399829/chrome_home.png');
await precacheImage(chrome.image, context);
setState(() => loading = false);
}
@override
void dispose() {
_pageController.dispose();
_animationController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
final isMobile = MediaQuery.of(context).size.width < 600;
return Material(
color: Colors.white,
child: loading
? Center(child: CircularProgressIndicator())
: PageMorpher(
controller: _pageController,
pageCount: shapeSize.length,
physics: _physics,
builder: (context, page, child) {
return Container(
color: shapeColor[(_pageController.page is num) ? _pageController.page.floor() : 0].withOpacity(0.6),
child: isMobile
? Column(
children: [
SizedBox(height: 50),
Expanded(
child: Transform(
transform: Matrix4.identity()..scale(0.8, 0.8),
alignment: Alignment.center,
child: FittedBox(
child: AnimatedContainer(
duration: const Duration(milliseconds: 650),
curve: Curves.decelerate,
width: shapeSize[page].width,
height: shapeSize[page].height,
decoration: BoxDecoration(
borderRadius: shapeRadius[page],
color: shapeColor[page],
boxShadow: [
BoxShadow(
color: Colors.black.withAlpha(0xAA),
spreadRadius: 10,
blurRadius: 40,
)
],
),
child: Stack(
alignment: Alignment.topCenter,
children: [
bodyWidgets[page],
FittedBox(
child: Stack(
children: [
if (page > 3)
Positioned.fill(
child: Container(
width: screenSize[page].width,
height: screenSize[page].height,
margin: EdgeInsets.only(top: screenMargin[page]),
child: SocialMediaFeed(),
),
),
if (page > 4 && !finished)
Container(
width: screenSize[page].width,
height: screenSize[page].height,
child: Visibility(
visible: _confettiAnimation.value > 0,
child: CustomPaint(
painter: Confetti(
animation: _confettiAnimation,
angle: listAngle,
pows: listPow,
offset: listOffset,
positivity: listPositivity,
color: listColor,
isMobile: true,
),
),
),
),
IgnorePointer(
ignoring: true,
child: AnimatedContainer(
duration: const Duration(milliseconds: 650),
width: screenSize[page].width,
height: screenSize[page].height,
margin: EdgeInsets.only(top: screenMargin[page]),
decoration: page == 2
? ShapeDecoration(
color: screenColor[page],
shape: SquircleBorder(superRadius: 10),
)
: BoxDecoration(color: screenColor[page]),
alignment: fontAlign[page],
padding: const EdgeInsets.only(right: 10),
child: ValueListenableBuilder<int>(
valueListenable: _followersCount,
builder: (context, value, child) {
return Container(
padding: EdgeInsets.symmetric(
horizontal: page == 3 ? 10 : 0,
vertical: page == 3 ? 4 : 0,
),
decoration: page == 3
? BoxDecoration(
borderRadius: BorderRadius.circular(20),
color: Colors.red)
: null,
child: Text(
'${value.toString().replaceAllMapped(Utils.reg, Utils.mathFunc)}',
style: TextStyle(
fontFamily: fontFamily[page],
color: fontColor[page],
fontSize: fontSize[page],
),
),
);
},
),
),
),
],
),
),
],
),
),
),
),
),
Container(
height: 50,
child: Visibility(
visible: finished,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
IconButton(
icon: Icon(Icons.keyboard_arrow_left),
onPressed: () {
_pageController.jumpToPage(
_pageController.page > 0 ? _pageController.page.floor() - 1 : 0,
);
},
),
IconButton(
icon: Icon(Icons.keyboard_arrow_right),
onPressed: () {
_pageController.jumpToPage(
_pageController.page < maxLength
? _pageController.page.floor() + 1
: maxLength - 1,
);
},
),
],
),
),
)
],
)
: Row(
children: [
Container(
width: 50,
child: Visibility(
visible: finished,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
IconButton(
icon: Icon(Icons.keyboard_arrow_up),
onPressed: () {
_pageController.jumpToPage(
_pageController.page > 0 ? _pageController.page.floor() - 1 : 0,
);
},
),
IconButton(
icon: Icon(Icons.keyboard_arrow_down),
onPressed: () {
_pageController.jumpToPage(
_pageController.page < maxLength
? _pageController.page.floor() + 1
: maxLength - 1,
);
},
),
],
),
),
),
Expanded(
child: Transform(
transform: Matrix4.identity()..scale(0.8, 0.8),
alignment: Alignment.center,
child: FittedBox(
child: AnimatedContainer(
duration: const Duration(milliseconds: 650),
curve: Curves.decelerate,
width: shapeSize[page].width,
height: shapeSize[page].height,
decoration: BoxDecoration(
borderRadius: shapeRadius[page],
color: shapeColor[page],
boxShadow: [
BoxShadow(
color: Colors.black.withAlpha(0xAA),
spreadRadius: 10,
blurRadius: 40,
)
],
),
child: Stack(
alignment: Alignment.topCenter,
children: [
bodyWidgets[page],
FittedBox(
child: Stack(
children: [
if (page > 3)
Positioned.fill(
child: Container(
width: screenSize[page].width,
height: screenSize[page].height,
margin: EdgeInsets.only(top: screenMargin[page]),
child: SocialMediaFeed(),
),
),
if (page > 4 && !finished)
Container(
width: screenSize[page].width,
height: screenSize[page].height,
child: Visibility(
visible: _confettiAnimation.value > 0,
child: CustomPaint(
painter: Confetti(
animation: _confettiAnimation,
angle: listAngle,
pows: listPow,
offset: listOffset,
positivity: listPositivity,
color: listColor,
isMobile: false,
),
),
),
),
IgnorePointer(
ignoring: true,
child: AnimatedContainer(
duration: const Duration(milliseconds: 650),
width: screenSize[page].width,
height: screenSize[page].height,
margin: EdgeInsets.only(top: screenMargin[page]),
decoration: page == 2
? ShapeDecoration(
color: screenColor[page],
shape: SquircleBorder(superRadius: 10),
)
: BoxDecoration(color: screenColor[page]),
alignment: fontAlign[page],
padding: const EdgeInsets.only(right: 10),
child: ValueListenableBuilder(
valueListenable: _followersCount,
builder: (context, value, child) {
return Container(
padding: EdgeInsets.symmetric(
horizontal: page == 3 ? 10 : 0,
vertical: page == 3 ? 4 : 0,
),
decoration: page == 3
? BoxDecoration(
borderRadius: BorderRadius.circular(20),
color: Colors.red)
: null,
child: Text(
'${value.toString().replaceAllMapped(Utils.reg, Utils.mathFunc)}',
textAlign: TextAlign.end,
style: TextStyle(
fontFamily: fontFamily[page],
color: fontColor[page],
fontSize: fontSize[page],
),
),
);
},
),
),
),
],
),
),
],
),
),
),
),
),
SizedBox(width: 50)
],
),
);
},
),
);
}
}
class SocialMediaFeed extends StatelessWidget {
@override
Widget build(BuildContext context) {
return FittedBox(
child: Container(
height: 310,
width: 540,
child: Stack(
children: [
Column(children: [
Container(
height: 100,
width: 540,
child: Image.network('https://pbs.twimg.com/profile_banners/420730316/1592930310/1500x500',
fit: BoxFit.cover),
),
Container(
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 10),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.end,
children: [
RaisedButton(
elevation: 0,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(30), side: BorderSide(color: Colors.blue, width: 2)),
onPressed: () {
window.open('https://www.twitter.com/flutterdev', 'flutterdev');
},
child: Text('Follow',
style: TextStyle(fontWeight: FontWeight.w600, color: Colors.blue, fontSize: 14)),
color: Colors.transparent,
),
],
),
Text('Flutter', style: TextStyle(fontSize: 18, fontWeight: FontWeight.w600)),
SizedBox(height: 4),
Opacity(
opacity: 0.6,
child: Text('@FlutterDev', style: TextStyle(fontSize: 15)),
),
SizedBox(height: 8),
Text('Google’s UI toolkit to build apps for mobile, web, & desktop from a single codebase',
style: TextStyle(fontSize: 15)),
SizedBox(height: 8),
Row(
mainAxisSize: MainAxisSize.min,
children: [
Text('35', style: TextStyle(fontWeight: FontWeight.w600)),
SizedBox(width: 2),
Opacity(opacity: 0.6, child: Text('Following')),
SizedBox(width: 80),
Text('', style: TextStyle(fontWeight: FontWeight.w600)),
SizedBox(width: 2),
Opacity(opacity: 0.6, child: Text('Followers')),
],
),
],
),
),
SizedBox(height: 10),
Container(height: 1, color: Theme.of(context).selectedRowColor),
SizedBox(height: 10),
]),
Padding(
padding: EdgeInsets.only(left: 15, top: 60),
child: Container(
width: 80,
height: 80,
alignment: Alignment.center,
padding: const EdgeInsets.all(4),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(50),
border: Border.all(color: Colors.grey[200], width: 2),
),
child: ClipRRect(
borderRadius: BorderRadius.circular(50),
child: Image.network(
'https://pbs.twimg.com/profile_images/1187814172307800064/MhnwJbxw_400x400.jpg',
fit: BoxFit.cover,
),
),
),
),
],
),
),
);
}
}
class Pixel extends StatefulWidget {
const Pixel({Key key}) : super(key: key);
@override
_PixelState createState() => _PixelState();
}
class _PixelState extends State<Pixel> {
bool started = false;
void start() {
context.findAncestorStateOfType<_HomeState>().start();
setState(() => started = true);
}
@override
Widget build(BuildContext context) {
return Container(
margin: const EdgeInsets.all(5),
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 70),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(30),
color: Colors.white,
),
child: Container(
padding: const EdgeInsets.all(1),
color: Colors.grey[800],
child: Scaffold(
appBar: AppBar(title: Text('FlutterDev')),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'We count on you!',
style: TextStyle(fontSize: 20),
),
SizedBox(height: 40),
],
),
),
floatingActionButton: FloatingActionButton(
child: Icon(Icons.add),
onPressed: !started ? start : null,
),
),
),
);
}
}
class Gameboy extends StatefulWidget {
@override
_GameboyState createState() => _GameboyState();
}
class _GameboyState extends State<Gameboy> {
@override
Widget build(BuildContext context) {
return Container(
child: Column(
children: [
SizedBox(height: 20),
Container(
width: 240,
height: 230,
decoration: BoxDecoration(
color: Colors.black,
borderRadius: BorderRadius.circular(5),
),
child: Center(
child: Container(
width: 180,
height: 170,
child: Image.network('https://assets.codepen.io/2399829/gbcbg.png', fit: BoxFit.cover),
),
),
),
SizedBox(height: 40),
Expanded(
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(width: 30),
Container(
child: Stack(
alignment: Alignment.center,
children: [
Container(
height: 30,
width: 80,
decoration: BoxDecoration(
color: Colors.black,
borderRadius: BorderRadius.circular(5),
),
child: Row(
children: [
Icon(Icons.keyboard_arrow_left, color: Colors.grey[800]),
Expanded(child: SizedBox()),
Icon(Icons.keyboard_arrow_right, color: Colors.grey[800]),
],
),
),
Container(
height: 80,
width: 30,
decoration: BoxDecoration(
color: Colors.black,
borderRadius: BorderRadius.circular(5),
),
child: Column(
children: [
Icon(Icons.keyboard_arrow_up, color: Colors.grey[800]),
Expanded(child: SizedBox()),
Icon(Icons.keyboard_arrow_down, color: Colors.grey[800]),
],
),
),
],
),
),
Expanded(child: SizedBox()),
Container(
width: 36,
height: 36,
margin: const EdgeInsets.only(top: 30),
decoration: BoxDecoration(color: Colors.black, borderRadius: BorderRadius.circular(18)),
child:
Center(child: Text('A', style: TextStyle(color: Colors.grey[800], fontWeight: FontWeight.bold))),
),
SizedBox(width: 10),
Container(
width: 36,
height: 36,
margin: const EdgeInsets.only(top: 5),
decoration: BoxDecoration(color: Colors.black, borderRadius: BorderRadius.circular(18)),
child:
Center(child: Text('B', style: TextStyle(color: Colors.grey[800], fontWeight: FontWeight.bold))),
),
SizedBox(width: 30),
],
),
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
height: 8,
width: 25,
decoration: BoxDecoration(color: Colors.black, borderRadius: BorderRadius.circular(4)),
),
SizedBox(width: 10),
Container(
height: 8,
width: 25,
decoration: BoxDecoration(color: Colors.black, borderRadius: BorderRadius.circular(4)),
)
],
),
SizedBox(height: 10),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('SELECT', style: TextStyle(color: Color(0xFF418719), fontSize: 8)),
SizedBox(width: 10),
Text('START', style: TextStyle(color: Color(0xFF418719), fontSize: 8)),
],
),
SizedBox(height: 60),
],
),
);
}
}
class Macintosh extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(
color: Color(0xFFB9AC89),
borderRadius: BorderRadius.circular(10),
),
child: Column(
mainAxisSize: MainAxisSize.max,
children: [
Expanded(
child: FittedBox(
child: Container(
width: 400,
height: 450,
margin: const EdgeInsets.only(bottom: 50),
decoration: BoxDecoration(
color: Color(0xFFCECCB2),
borderRadius: BorderRadius.circular(10),
),
child: Column(
children: [
Container(
width: 340,
height: 340,
margin: const EdgeInsets.only(top: 20),
decoration: BoxDecoration(
color: Color(0xFFB9AC89),
borderRadius: BorderRadius.circular(10),
),
child: Center(
child: Container(
width: 300,
height: 300,
child: Image.network('https://assets.codepen.io/2399829/macintosh.png', fit: BoxFit.cover),
),
),
),
Expanded(
child: Container(
alignment: Alignment.centerRight,
margin: const EdgeInsets.only(top: 10, right: 30),
child: Stack(
alignment: Alignment.centerRight,
children: [
Container(
height: 40,
width: 80,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5),
color: Color(0xFFB9AC89),
),
),
Container(
height: 10,
width: 140,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5),
color: Colors.black,
),
),
],
),
),
)
],
),
),
),
),
],
),
);
}
}
class SmartPhone extends StatefulWidget {
@override
_SmartPhoneState createState() => _SmartPhoneState();
}
class _SmartPhoneState extends State<SmartPhone> {
@override
Widget build(BuildContext context) {
final size = MediaQuery.of(context).size;
return Column(
mainAxisSize: MainAxisSize.max,
children: [
Expanded(
child: FittedBox(
child: Container(
width: 300,
height: 600,
margin: const EdgeInsets.all(4),
padding: const EdgeInsets.all(4),
decoration: BoxDecoration(borderRadius: BorderRadius.circular(30), color: Colors.white),
child: Center(
child: Container(
width: 270,
height: 480,
child: Stack(
fit: StackFit.expand,
children: [
SizedBox(
width: size.width,
height: size.height,
child: Image.network('https://assets.codepen.io/2399829/iphone_bg.jpg', fit: BoxFit.cover),
),
Padding(
padding: const EdgeInsets.only(left: 10, right: 10, top: 20),
child: Wrap(
spacing: 15,
runSpacing: 15,
children: [
appIcon('https://assets.codepen.io/2399829/icon_one.png'),
appIcon('https://assets.codepen.io/2399829/icon_two.png'),
appIcon('https://assets.codepen.io/2399829/icon_three.png'),
appIcon('https://assets.codepen.io/2399829/icon_four.png'),
appIcon('https://assets.codepen.io/2399829/icon_five.png'),
],
),
),
Align(
alignment: Alignment(0.8, 0.9),
child: appIcon('https://assets.codepen.io/2399829/email.png'),
),
],
),
),
),
),
),
),
],
);
}
Widget appIcon(String url) {
return Container(
decoration: BoxDecoration(boxShadow: [
BoxShadow(
blurRadius: 8,
spreadRadius: 4,
color: Colors.black54,
)
]),
child: Image.network(url, width: 50, height: 50, fit: BoxFit.fill),
);
}
}
class Chromebook extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
child: Column(
children: [
Expanded(
child: FittedBox(
child: Container(
width: 600,
height: 420,
margin: const EdgeInsets.only(left: 4, right: 4, top: 4),
decoration: BoxDecoration(
borderRadius: BorderRadius.only(topLeft: Radius.circular(30), topRight: Radius.circular(30)),
color: Color(0xFF0F0F0F),
),
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 22),
child: Image.network('https://assets.codepen.io/2399829/chrome_home.png'),
),
),
),
),
Container(
height: 20,
child: Row(
children: [
Container(
width: 30,
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [
Color(0xFF787878),
Color(0xFFBBBBBB),
],
begin: Alignment.centerLeft,
end: Alignment.centerRight,
),
),
),
Expanded(
child: Column(
children: [
Container(
height: 10,
width: 100,
decoration: BoxDecoration(
borderRadius: BorderRadius.only(
bottomLeft: Radius.circular(5),
bottomRight: Radius.circular(5),
),
gradient: LinearGradient(
colors: [
Color(0xFF787878),
Color(0xFFBBBBBB),
Color(0xFFBBBBBB),
],
begin: Alignment.bottomCenter,
end: Alignment.topCenter,
),
border: Border.all(color: Color(0xFFCCCCCC), width: 1),
),
),
],
),
),
Container(
width: 30,
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [
Color(0xFF787878),
Color(0xFFBBBBBB),
],
begin: Alignment.centerRight,
end: Alignment.centerLeft,
),
),
),
],
),
)
],
),
);
}
}
class PageMorpher extends StatefulWidget {
const PageMorpher({
Key key,
@required this.controller,
@required this.pageCount,
@required this.builder,
this.physics = const PageScrollPhysics(),
this.child,
}) : super(key: key);
final ScrollController controller;
final int pageCount;
final ValueWidgetBuilder<int> builder;
final ScrollPhysics physics;
final Widget child;
@override
_PageMorpherState createState() => _PageMorpherState();
}
class _PageMorpherState extends State<PageMorpher> {
final _page = ValueNotifier<int>(0);
@override
Widget build(BuildContext context) {
return Scrollable(
axisDirection: AxisDirection.right,
controller: widget.controller,
physics: widget?.physics?.applyTo(const PageScrollPhysics()),
viewportBuilder: (BuildContext context, ViewportOffset position) {
return PageMorpherViewport(
position: position,
page: _page,
pageCount: widget.pageCount,
child: ValueListenableBuilder(
valueListenable: _page,
builder: widget.builder,
child: widget.child,
),
);
},
);
}
}
class PageMorpherViewport extends SingleChildRenderObjectWidget {
const PageMorpherViewport({
Key key,
@required this.position,
@required this.page,
@required this.pageCount,
@required Widget child,
}) : super(key: key, child: child);
final ViewportOffset position;
final ValueNotifier page;
final int pageCount;
@override
RenderObject createRenderObject(BuildContext context) {
return RenderPageMorpherViewport(position, page, pageCount);
}
@override
void updateRenderObject(BuildContext context, RenderPageMorpherViewport renderObject) {
renderObject
..position = position
..page = page
..pageCount = pageCount;
}
}
class RenderPageMorpherViewport extends RenderProxyBox {
RenderPageMorpherViewport(
this._position,
this._page,
this._pageCount,
);
ViewportOffset _position;
ValueNotifier _page;
int _pageCount;
set position(ViewportOffset value) {
if (_position != value) {
_position.removeListener(_onPositionChanged);
_position = value;
if (attached) {
_position.addListener(_onPositionChanged);
}
}
}
set page(ValueNotifier value) {
if (_page != value) {
_page = value;
_onPositionChanged();
}
}
set pageCount(int value) {
if (_pageCount != value) {
_pageCount = value;
markNeedsLayout();
}
}
@override
void attach(PipelineOwner owner) {
super.attach(owner);
_position.addListener(_onPositionChanged);
}
void _onPositionChanged() {
_page.value = (_position.pixels / size.width).floor();
markNeedsLayout();
}
@override
void detach() {
_position.removeListener(_onPositionChanged);
super.detach();
}
@override
void performLayout() {
super.performLayout();
final width = size.width;
_position.applyViewportDimension(width);
_position.applyContentDimensions(0.0, width * (_pageCount - 1));
}
}
class SquircleBorder extends ShapeBorder {
final BorderSide side;
final double superRadius;
const SquircleBorder({
this.side: BorderSide.none,
this.superRadius: 5.0,
}) : assert(side != null),
assert(superRadius != null);
@override
EdgeInsetsGeometry get dimensions => EdgeInsets.all(side.width);
@override
ShapeBorder scale(double t) {
return new SquircleBorder(
side: side.scale(t),
superRadius: superRadius * t,
);
}
@override
Path getInnerPath(Rect rect, {TextDirection textDirection}) {
return _squirclePath(rect.deflate(side.width), superRadius);
}
@override
Path getOuterPath(Rect rect, {TextDirection textDirection}) {
return _squirclePath(rect, superRadius);
}
static Path _squirclePath(Rect rect, double superRadius) {
final c = Offset(rect.width / 2, rect.height / 2);
final dx = c.dx * (1.0 / superRadius);
final dy = c.dy * (1.0 / superRadius);
return Path()
..moveTo(rect.center.dx, rect.top)
..relativeCubicTo(c.dx - dx, 0.0, c.dx, dy, c.dx, c.dy)
..relativeCubicTo(0.0, c.dy - dy, -dx, c.dy, -c.dx, c.dy)
..relativeCubicTo(-(c.dx - dx), 0.0, -c.dx, -dy, -c.dx, -c.dy)
..relativeCubicTo(0.0, -(c.dy - dy), dx, -c.dy, c.dx, -c.dy)
..close();
}
@override
void paint(Canvas canvas, Rect rect, {TextDirection textDirection}) {
switch (side.style) {
case BorderStyle.none:
break;
case BorderStyle.solid:
var path = getOuterPath(rect.deflate(side.width / 2.0), textDirection: textDirection);
canvas.drawPath(path, side.toPaint());
}
}
}
class Tuple<F, S> {
final F first;
final S second;
const Tuple(this.first, this.second);
}
class Confetti extends CustomPainter {
final Animation animation;
final List<double> angle;
final List<double> pows;
final List<int> offset;
final List<bool> positivity;
final List<Color> color;
final bool isMobile;
Confetti({this.animation, this.angle, this.pows, this.offset, this.positivity, this.color, this.isMobile});
@override
void paint(Canvas canvas, Size size) {
final posX = (size.width / 2) * 0.57;
final posY = (size.height / 2) * 1.70;
for (int i = 0; i < (isMobile ? Utils.listLength / 4 : Utils.listLength); i++) {
canvas.drawCircle(
Offset(
posX + ((pow(animation.value, (1.3 - pows[i])) * cos(angle[i])) * (positivity[i] ? -1 : 1)),
posY + ((pow(animation.value, (1.3 - pows[i])) * sin(angle[i])) * (positivity[i] ? -1 : 1)),
),
4,
Paint()..color = color[i].withOpacity(pow(1 - (animation.value / 200.0), 0.9)));
}
}
@override
bool shouldRepaint(CustomPainter oldDelegate) => false;
}
class Utils {
static final int listLength = 500;
static double doubleInRange(Random source, num start, num end) => source.nextDouble() * (end - start) + start;
static RegExp reg = RegExp(r'(\d{1,3})(?=(\d{3})+(?!\d))');
static Function mathFunc = (Match match) => '${match[1]},';
}
Also see: Tab Triggers