Skip to content

Instantly share code, notes, and snippets.

@Metal-666
Created January 20, 2022 17:53
Show Gist options
  • Select an option

  • Save Metal-666/9be7f0f888e9f4f82e17bd9fedea80ef to your computer and use it in GitHub Desktop.

Select an option

Save Metal-666/9be7f0f888e9f4f82e17bd9fedea80ef to your computer and use it in GitHub Desktop.
Challenge 3 (BLoC)
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'dart:ui' as ui;
import 'dart:math';
void main() => runApp(App());
//------------------------------Widgets-----------------------------
class App extends StatelessWidget {
final Color _primaryColor = Colors.deepPurple[700]!;
final ThemeData _theme = ThemeData.dark();
@override
Widget build(BuildContext context) => BlocProvider<RootBloc>(
create: (BuildContext context) => RootBloc(),
child: MaterialApp(
theme: _theme.copyWith(
colorScheme: _theme.colorScheme
.copyWith(primary: _primaryColor, secondary: Colors.white),
appBarTheme: AppBarTheme(color: _primaryColor)),
home: Scaffold(
appBar: _appBar(),
body: SizedBox.expand(
child: _root(),
),
),
));
PreferredSizeWidget _appBar() => AppBar(
title: const Text('Clock'),
);
Widget _root() => Stack(children: <Widget>[_fab(), _clock()]);
Widget _fab() => Positioned(
bottom: 10,
right: 10,
child: BlocBuilder<RootBloc, RootState>(
builder: (BuildContext context, RootState state) =>
FloatingActionButton(
onPressed: () => context.read<RootBloc>().add(ToggleNumberStyle()),
child: const Icon(Icons.refresh),
),
));
Widget _clock() =>
Center(child: SizedBox(height: 300, width: 300, child: Clock()));
}
class Clock extends StatelessWidget {
@override
Widget build(BuildContext context) => BlocBuilder<RootBloc, RootState>(
builder: (BuildContext context, RootState state) =>
CustomPaint(painter: ClockPainter(state.numberStyle)));
}
class ClockPainter extends CustomPainter {
final NumberStyle style;
ClockPainter(this.style);
@override
void paint(Canvas canvas, Size size) {
//Create our paints and colors
final Paint background = Paint()..color = Colors.deepPurple[500]!,
face = Paint()
..shader = ui.Gradient.linear(
Offset.zero,
Offset(size.width, size.height),
[
Colors.deepPurple[600]!,
Colors.deepPurple[900]!,
],
),
bigMark = (Paint()..color = Colors.white)..strokeWidth = 2,
smallMark = (Paint()..color = Colors.grey[400]!)..strokeWidth = 1;
Color numbers = Colors.white;
//Calculate some useful values
final double radius = size.height / 2,
centerX = size.width / 2,
centerY = size.height / 2;
//We might need this in the future?
//canvas.clipRect(Rect.fromLTWH(0, 0, size.width, size.height));
//Draw clock background (outer circle)
canvas.drawCircle(Offset(centerX, centerY), radius, background);
//Draw clock face (inner circle)
canvas.drawCircle(Offset(centerX, centerY), radius - 5, face);
//Draw the dot in the middle (idk what it's called)
canvas.drawCircle(Offset(centerX, centerY), 5, background);
//Draw hour marks and minute marks
_drawRadialMarks(
12, 13, 10, centerX, centerY, radius - 20, canvas, bigMark);
_drawRadialMarks(
12 * 5, 5, 7, centerX, centerY, radius - 17, canvas, smallMark);
//Draw numbers
_drawRadialText(
12, centerX, centerY, radius - 35, _getClockNumbers(), canvas, numbers);
}
void _drawRadialMarks(
int howMany,
int skipEach,
double length,
double centerX,
double centerY,
double radius,
Canvas canvas,
Paint paint) {
for (int i = 1; i <= howMany; i++) {
if (i % skipEach != 0) {
final double angle = i * (360 / howMany) * pi / 180;
final double x1 = centerX + radius * cos(angle),
y1 = centerY - radius * sin(angle);
final double x2 = centerX + (radius + length) * cos(angle),
y2 = centerY - (radius + length) * sin(angle);
canvas.drawLine(Offset(x1, y1), Offset(x2, y2), paint);
}
}
}
void _drawRadialText(int howMany, double centerX, double centerY,
double radius, List<String> strings, Canvas canvas, Color textColor) {
final TextStyle style = TextStyle(
color: textColor,
fontSize: 20,
);
for (int i = 0; i < howMany; i++) {
final TextSpan text = TextSpan(
text: strings.length > i ? strings[i] : 'uh',
style: style,
);
final TextPainter painter = TextPainter(
text: text,
textDirection: TextDirection.ltr,
)..layout(maxWidth: 100, minWidth: 0);
final double angle = (i * (360 / howMany) + 120) * pi / 180;
final double x = centerX - radius * cos(angle),
y = centerY - radius * sin(angle);
painter.paint(
canvas, Offset(x - painter.width / 2, y - painter.height / 2));
}
}
//Returns a set of numbers depending on current number style (roman|arabic)
List<String> _getClockNumbers() {
switch (style) {
case NumberStyle.arabic:
{
return <String>[
'1',
'2',
'3',
'4',
'5',
'6',
'7',
'8',
'9',
'10',
'11',
'12'
];
}
case NumberStyle.roman:
{
return <String>[
'I',
'II',
'III',
'IV',
'V',
'VI',
'VII',
'VIII',
'IX',
'X',
'XI',
'XII'
];
}
default:
{
return <String>['Huh?'];
}
}
}
@override
bool shouldRepaint(covariant CustomPainter oldDelegate) => true;
}
//------------------------------Widgets-----------------------------
//------------------------------Events------------------------------
abstract class RootEvents {}
class ToggleNumberStyle extends RootEvents {}
//------------------------------Events------------------------------
//------------------------------States------------------------------
class RootState {
final NumberStyle numberStyle;
RootState(this.numberStyle);
}
enum NumberStyle { roman, arabic }
//------------------------------States------------------------------
//-------------------------------Bloc-------------------------------
class RootBloc extends Bloc<RootEvents, RootState> {
RootBloc() : super(RootState(NumberStyle.roman)) {
//Toggle numberStyle
on<ToggleNumberStyle>((event, emit) => emit(RootState(
state.numberStyle == NumberStyle.roman
? NumberStyle.arabic
: NumberStyle.roman)));
}
}
//-------------------------------Bloc-------------------------------
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment