Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Import CheckButton & RadioButton from ubuntu-flutter-plugins/ubuntu_widgets #291

Merged
merged 4 commits into from
Oct 12, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions example/lib/example_page_items.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@ import 'package:flutter/material.dart';
import 'package:yaru_icons/yaru_icons.dart';
import 'pages/banner_page.dart';
import 'pages/carousel_page.dart';
import 'pages/check_button_page.dart';
import 'pages/color_disk_page.dart';
import 'pages/draggable_page.dart';
import 'pages/expandable_page.dart';
import 'pages/icon_button_page.dart';
import 'pages/option_button_page.dart';
import 'pages/progress_indicator_page.dart';
import 'pages/radio_button_page.dart';
import 'pages/section_page.dart';
import 'pages/selectable_container_page.dart';
import 'pages/tabbed_page_page.dart';
Expand Down Expand Up @@ -38,6 +40,12 @@ final examplePageItems = <PageItem>[
pageBuilder: (_) => const CarouselPage(),
iconBuilder: (context, selected) => const Icon(YaruIcons.refresh),
),
PageItem(
titleBuilder: (context) => const Text('YaruCheckButton'),
pageBuilder: (context) => const CheckButtonPage(),
iconBuilder: (context, selected) =>
const Icon(YaruIcons.checkbox_button_checked),
),
PageItem(
titleBuilder: (context) => const Text('YaruColorDisk'),
pageBuilder: (context) => const ColorDiskPage(),
Expand Down Expand Up @@ -68,6 +76,12 @@ final examplePageItems = <PageItem>[
iconBuilder: (context, selected) => const Icon(YaruIcons.download),
pageBuilder: (_) => const ProgressIndicatorPage(),
),
PageItem(
titleBuilder: (context) => const Text('YaruRadioButton'),
pageBuilder: (context) => const RadioButtonPage(),
iconBuilder: (context, selected) =>
const Icon(YaruIcons.radio_button_checked),
),
PageItem(
titleBuilder: (context) => const Text('YaruSection'),
iconBuilder: (context, selected) => const Icon(YaruIcons.window),
Expand Down
30 changes: 30 additions & 0 deletions example/lib/pages/check_button_page.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import 'package:flutter/material.dart';
import 'package:yaru_widgets/yaru_widgets.dart';

class CheckButtonPage extends StatefulWidget {
const CheckButtonPage({super.key});

@override
_CheckButtonPageState createState() => _CheckButtonPageState();
}

class _CheckButtonPageState extends State<CheckButtonPage> {
final _values = List.generate(3, (i) => i % 2 == 0);

@override
Widget build(BuildContext context) {
return ListView(
padding: const EdgeInsets.all(kYaruPagePadding),
children: [
for (var i = 0; i < _values.length; ++i) ...[
YaruCheckButton(
value: _values[i],
onChanged: (v) => setState(() => _values[i] = v!),
title: const Text('YaruCheckButton'),
),
const SizedBox(height: 10),
],
],
);
}
}
31 changes: 31 additions & 0 deletions example/lib/pages/radio_button_page.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import 'package:flutter/material.dart';
import 'package:yaru_widgets/yaru_widgets.dart';

class RadioButtonPage extends StatefulWidget {
const RadioButtonPage({super.key});

@override
_RadioButtonPageState createState() => _RadioButtonPageState();
}

class _RadioButtonPageState extends State<RadioButtonPage> {
int _value = 0;

@override
Widget build(BuildContext context) {
return ListView(
padding: const EdgeInsets.all(kYaruPagePadding),
children: [
for (var i = 0; i < 3; ++i) ...[
YaruRadioButton<int>(
value: i,
groupValue: _value,
onChanged: (v) => setState(() => _value = v!),
title: const Text('YaruRadioButton'),
),
const SizedBox(height: 10),
],
],
);
}
}
50 changes: 50 additions & 0 deletions lib/src/controls/yaru_check_button.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import 'package:flutter/material.dart';

import 'yaru_toggle_button.dart';

/// A desktop style check button with an interactive label.
class YaruCheckButton extends StatelessWidget {
/// Creates a new check button.
const YaruCheckButton({
super.key,
required this.value,
required this.onChanged,
required this.title,
this.subtitle,
this.contentPadding,
});

/// See [Checkbox.value]
final bool value;

/// See [Checkbox.onChanged]
final ValueChanged<bool?>? onChanged;

/// See [YaruToggleButton.title]
final Widget title;

/// See [YaruToggleButton.subtitle]
final Widget? subtitle;

/// See [YaruToggleButton.contentPadding]
final EdgeInsetsGeometry? contentPadding;

@override
Widget build(BuildContext context) {
return YaruToggleButton(
title: title,
subtitle: subtitle,
contentPadding: contentPadding,
leading: SizedBox.square(
dimension: kMinInteractiveDimension - 8,
child: Center(
child: Checkbox(
value: value,
onChanged: onChanged,
),
),
),
onToggled: onChanged != null ? () => onChanged!(!value) : null,
);
}
}
55 changes: 55 additions & 0 deletions lib/src/controls/yaru_radio_button.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import 'package:flutter/material.dart';

import 'yaru_toggle_button.dart';

/// A desktop style radio button with an interactive label.
class YaruRadioButton<T> extends StatelessWidget {
/// Creates a new radio button.
const YaruRadioButton({
super.key,
required this.value,
required this.groupValue,
required this.onChanged,
required this.title,
this.subtitle,
this.contentPadding,
});

/// See [Radio.value]
final T value;

/// See [Radio.groupValue]
final T? groupValue;

/// See [Radio.onChanged]
final ValueChanged<T?>? onChanged;

/// See [YaruToggleButton.title]
final Widget title;

/// See [YaruToggleButton.subtitle]
final Widget? subtitle;

/// See [YaruToggleButton.contentPadding]
final EdgeInsetsGeometry? contentPadding;

@override
Widget build(BuildContext context) {
return YaruToggleButton(
title: title,
subtitle: subtitle,
contentPadding: contentPadding,
leading: SizedBox.square(
dimension: kMinInteractiveDimension - 8,
child: Center(
child: Radio<T>(
value: value,
groupValue: groupValue,
onChanged: onChanged,
),
),
),
onToggled: onChanged != null ? () => onChanged!(value) : null,
);
}
}
94 changes: 94 additions & 0 deletions lib/src/controls/yaru_toggle_button.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import 'dart:math' as math;

import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';

import 'yaru_toggle_button_theme.dart';

part 'yaru_toggle_button_layout.dart';

/// A desktop style toggle button with an indicator and an interactive label.
///
/// See [YaruCheckButton] and [YaruRadioButton] for concrete implementations.
class YaruToggleButton extends StatelessWidget {
/// Creates a toggle button.
const YaruToggleButton({
super.key,
required this.leading,
required this.title,
this.subtitle,
this.contentPadding,
this.onToggled,
});

/// The toggle indicator.
final Widget leading;

/// The button label.
final Widget title;

/// An optional secondary label.
final Widget? subtitle;

/// Padding around the content.
final EdgeInsetsGeometry? contentPadding;

/// Called when the button is toggled.
final VoidCallback? onToggled;

@override
Widget build(BuildContext context) {
final theme = YaruToggleButtonTheme.of(context);
return MergeSemantics(
child: Semantics(
child: GestureDetector(
onTap: onToggled,
child: MouseRegion(
cursor: onToggled != null
? SystemMouseCursors.click
: SystemMouseCursors.basic,
child: Padding(
padding: contentPadding ?? EdgeInsets.zero,
child: _YaryToggleButtonLayout(
horizontalSpacing: theme?.horizontalSpacing ?? 8,
verticalSpacing: theme?.verticalSpacing ?? 4,
textDirection: Directionality.of(context),
leading: leading,
title: _wrapTextStyle(
context,
overflow: TextOverflow.ellipsis,
style: Theme.of(context).textTheme.subtitle1!,
child: title,
),
subtitle: subtitle != null
? _wrapTextStyle(
context,
softWrap: true,
style: Theme.of(context).textTheme.caption!,
child: subtitle!,
)
: null,
),
),
),
),
),
);
}

Widget _wrapTextStyle(
BuildContext context, {
required Widget child,
required TextStyle style,
TextOverflow overflow = TextOverflow.clip,
bool softWrap = false,
}) {
final color = onToggled == null ? Theme.of(context).disabledColor : null;
return DefaultTextStyle(
style: style.copyWith(color: color),
overflow: overflow,
softWrap: softWrap,
child: child,
);
}
}
Loading