Skip to content

Commit

Permalink
feat: create slider component (#53)
Browse files Browse the repository at this point in the history
  • Loading branch information
ahmed-osman3 authored and thelukewalton committed Jun 17, 2024
1 parent 40044c0 commit 6394ef6
Show file tree
Hide file tree
Showing 6 changed files with 226 additions and 0 deletions.
3 changes: 3 additions & 0 deletions example/lib/home.dart
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,10 @@ import 'package:zeta_example/pages/components/phone_input_example.dart';
import 'package:zeta_example/pages/components/radio_example.dart';
import 'package:zeta_example/pages/components/screen_header_bar_example.dart';
import 'package:zeta_example/pages/components/select_input_example.dart';

import 'package:zeta_example/pages/components/search_bar_example.dart';
import 'package:zeta_example/pages/components/segmented_control_example.dart';
import 'package:zeta_example/pages/components/slider_example.dart';
import 'package:zeta_example/pages/components/stepper_example.dart';
import 'package:zeta_example/pages/components/stepper_input_example.dart';
import 'package:zeta_example/pages/components/switch_example.dart';
Expand Down Expand Up @@ -84,6 +86,7 @@ final List<Component> components = [
Component(DialPadExample.name, (context) => const DialPadExample()),
Component(RadioButtonExample.name, (context) => const RadioButtonExample()),
Component(SwitchExample.name, (context) => const SwitchExample()),
Component(SliderExample.name, (context) => const SliderExample()),
Component(DateInputExample.name, (context) => const DateInputExample()),
Component(PhoneInputExample.name, (context) => const PhoneInputExample()),
Component(DialogExample.name, (context) => const DialogExample()),
Expand Down
33 changes: 33 additions & 0 deletions example/lib/pages/components/slider_example.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import 'package:flutter/material.dart';
import 'package:zeta_example/widgets.dart';
import 'package:zeta_flutter/zeta_flutter.dart';

class SliderExample extends StatefulWidget {
static const String name = 'Slider';

const SliderExample({super.key});

@override
State<SliderExample> createState() => _SliderExampleState();
}

class _SliderExampleState extends State<SliderExample> {
double value = 0.5;

@override
Widget build(BuildContext context) {
return ExampleScaffold(
name: SliderExample.name,
child: Center(
child: ZetaSlider(
value: value,
onChange: (newValue) {
setState(() {
value = newValue;
});
},
),
),
);
}
}
2 changes: 2 additions & 0 deletions example/widgetbook/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import 'pages/assets/icon_widgetbook.dart';
import 'pages/components/accordion_widgetbook.dart';
import 'pages/components/dropdown_list_item_widgetbook.dart';
import 'pages/components/notification_list_item_widgetbook.dart';
import 'pages/components/slider_widgetbook.dart';
import 'pages/components/text_input_widgetbook.dart';
import 'pages/components/top_app_bar_widgetbook.dart';
import 'pages/components/avatar_widgetbook.dart';
Expand Down Expand Up @@ -201,6 +202,7 @@ class _HotReloadState extends State<HotReload> {
WidgetbookUseCase(name: 'Search Bar', builder: (context) => searchBarUseCase(context)),
WidgetbookUseCase(name: 'Segmented Control', builder: (context) => segmentedControlUseCase(context)),
WidgetbookUseCase(name: 'Select Input', builder: (context) => selectInputUseCase(context)),
WidgetbookUseCase(name: 'Slider', builder: (context) => sliderUseCase(context)),
WidgetbookUseCase(name: 'Snack Bar', builder: (context) => snackBarUseCase(context)),
WidgetbookUseCase(name: 'Stepper Input', builder: (context) => stepperInputUseCase(context)),
WidgetbookUseCase(name: 'Stepper', builder: (context) => stepperUseCase(context)),
Expand Down
39 changes: 39 additions & 0 deletions example/widgetbook/pages/components/slider_widgetbook.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import 'package:flutter/material.dart';
import 'package:widgetbook/widgetbook.dart';
import 'package:zeta_flutter/zeta_flutter.dart';

import '../../test/test_components.dart';

Widget sliderUseCase(BuildContext context) {
return WidgetbookTestWidget(widget: Builder(builder: (context) {
return ZetaSliderExample(context);
}));
}

class ZetaSliderExample extends StatefulWidget {
const ZetaSliderExample(this.c);
final BuildContext c;

@override
State<ZetaSliderExample> createState() => _ZetaSliderExampleState();
}

class _ZetaSliderExampleState extends State<ZetaSliderExample> {
double value = 0.5;

@override
Widget build(BuildContext context) {
return ZetaSlider(
value: value,
rounded: widget.c.knobs.boolean(label: "Rounded"),
divisions: widget.c.knobs.intOrNull.slider(label: "Divisions", min: 1, initialValue: 10),
onChange: widget.c.knobs.boolean(label: "Disabled")
? null
: (newValue) {
setState(() {
value = newValue;
});
},
);
}
}
148 changes: 148 additions & 0 deletions lib/src/components/slider/slider.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';

import '../../theme/tokens.dart';
import '../../zeta.dart';

/// Slider component with customized styling
class ZetaSlider extends StatefulWidget {
/// Default constructor for [ZetaSlider]
const ZetaSlider({
super.key,
required this.value,
this.onChange,
this.rounded = false,
this.divisions,
});

/// Double value to represent slider percentage
final double value;

/// Callback to handle changing of slider
final ValueChanged<double>? onChange;

/// {@macro zeta-component-rounded}
final bool rounded;

/// Number of divisions.
final int? divisions;

@override
State<ZetaSlider> createState() => _ZetaSliderState();
@override
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
super.debugFillProperties(properties);
properties
..add(DiagnosticsProperty<bool>('rounded', rounded))
..add(DoubleProperty('value', value))
..add(ObjectFlagProperty<ValueChanged<double>?>.has('onChange', onChange))
..add(IntProperty('divisions', divisions));
}
}

class _ZetaSliderState extends State<ZetaSlider> {
bool _selected = false;

@override
Widget build(BuildContext context) {
final colors = Zeta.of(context).colors;

return SliderTheme(
data: SliderThemeData(
/** TODO: Match with new colors */

/// Active Track
activeTrackColor: _activeColor,
disabledActiveTrackColor: colors.surfaceDisabled,

/// Inactive Track
inactiveTrackColor: colors.surfaceInfoSubtle,

/// Ticks
activeTickMarkColor: colors.surfaceDefault,
inactiveTickMarkColor: colors.surfaceDefault,

/// Thumb
thumbColor: colors.surfaceDefaultInverse,
disabledThumbColor: colors.surfaceDisabled,
overlayShape: SliderThumb(size: ZetaSpacing.xl_1, rounded: widget.rounded, color: _activeColor),
thumbShape: SliderThumb(
size: ZetaSpacing.large,
rounded: widget.rounded,
color: _activeColor,
),
),
child: Slider(
value: widget.value,
onChanged: widget.onChange,
divisions: widget.divisions,
onChangeStart: (_) {
setState(() {
_selected = true;
});
},
onChangeEnd: (_) {
setState(() {
_selected = false;
});
},
),
);
}

Color get _activeColor {
final colors = Zeta.of(context).colors;
if (widget.onChange == null) {
return colors.surfaceDisabled;
}
return _selected ? colors.primary : colors.surfaceDefaultInverse;
}
}

/// Custom slider thumb component
class SliderThumb extends SliderComponentShape {
/// Constructor for [SliderThumb]
const SliderThumb({required this.size, required this.rounded, required this.color});

/// Radius or width/height for [SliderThumb] depending on shape
final double size;

/// If [SliderThumb] is circular or a square
final bool rounded;

/// Color of [SliderThumb]
final Color color;

@override
Size getPreferredSize(bool isEnabled, bool isDiscrete) {
return Size.fromRadius(size);
}

/// Paints thumb
@override
void paint(
PaintingContext context,
Offset center, {
required Animation<double> activationAnimation,
required Animation<double> enableAnimation,
required bool isDiscrete,
required TextPainter labelPainter,
required RenderBox parentBox,
required SliderThemeData sliderTheme,
required TextDirection textDirection,
required double value,
required double textScaleFactor,
required Size sizeWithOverflow,
}) {
final Canvas canvas = context.canvas;

final paint = Paint()
..style = PaintingStyle.fill
..color = color;

// draw icon with text painter
rounded
? canvas.drawCircle(center, size, paint)
: canvas.drawRect(Rect.fromCenter(center: center, width: size, height: size), paint);
}
}
1 change: 1 addition & 0 deletions lib/zeta_flutter.dart
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ export 'src/components/screen_header_bar/screen_header_bar.dart';
export 'src/components/search_bar/search_bar.dart';
export 'src/components/segmented_control/segmented_control.dart';
export 'src/components/select_input/select_input.dart';
export 'src/components/slider/slider.dart';
export 'src/components/snack_bar/snack_bar.dart';
export 'src/components/stepper/stepper.dart';
export 'src/components/stepper_input/stepper_input.dart';
Expand Down

0 comments on commit 6394ef6

Please sign in to comment.