Skip to content

Commit

Permalink
feat: add YaruInfoBadge, YaruInfoBox, YaruTranslucentBorderContainer (#…
Browse files Browse the repository at this point in the history
…880)

* feat(YaruInfo): add YaruInfoBadge, YaruInfoBox, YaruTranslucentBorderContainer
  • Loading branch information
Feichtmeier committed Mar 9, 2024
1 parent 54e666e commit 198495b
Show file tree
Hide file tree
Showing 6 changed files with 514 additions and 0 deletions.
28 changes: 28 additions & 0 deletions example/lib/example_page_items.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import 'package:yaru/yaru.dart';
import 'code_snippet_button.dart';
import 'pages/autocomplete_page.dart';
import 'pages/banner_page.dart';
import 'pages/border_container_page.dart';
import 'pages/carousel_page.dart';
import 'pages/checkbox_page.dart';
import 'pages/choice_chip_bar_page.dart';
Expand All @@ -17,6 +18,7 @@ import 'pages/expansion_panel_page.dart';
import 'pages/full_color_icons_page.dart';
import 'pages/icon_button_page.dart';
import 'pages/icons_page/icons_page.dart';
import 'pages/info_page.dart';
import 'pages/navigation_page.dart';
import 'pages/option_button_page.dart';
import 'pages/page_indicator.dart';
Expand Down Expand Up @@ -332,4 +334,30 @@ final examplePageItems = <PageItem>[
? const Icon(YaruIcons.colors_filled)
: const Icon(YaruIcons.colors),
),
PageItem(
title: 'YaruInfo',
pageBuilder: (context) {
return const InfoPage();
},
iconBuilder: (context, selected) => selected
? const Icon(YaruIcons.information_filled)
: const Icon(YaruIcons.information),
floatingActionButtonBuilder: (_) => const CodeSnippedButton(
snippetUrl:
'https://raw.githubusercontent.com/ubuntu/yaru.dart/main/example/lib/pages/info_page.dart',
),
),
PageItem(
title: 'YaruBorderContainer',
pageBuilder: (context) {
return const BorderContainerPage();
},
iconBuilder: (context, selected) => selected
? const Icon(YaruIcons.cloud_filled)
: const Icon(YaruIcons.cloud),
floatingActionButtonBuilder: (_) => const CodeSnippedButton(
snippetUrl:
'https://raw.githubusercontent.com/ubuntu/yaru.dart/main/example/lib/pages/border_container_page.dart',
),
),
].sortedBy((page) => page.title);
57 changes: 57 additions & 0 deletions example/lib/pages/border_container_page.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import 'package:flutter/material.dart';
import 'package:yaru/yaru.dart';

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

@override
State<BorderContainerPage> createState() => _BorderContainerPageState();
}

class _BorderContainerPageState extends State<BorderContainerPage> {
int _take = 80;

@override
Widget build(BuildContext context) {
return Column(
children: [
Padding(
padding: const EdgeInsets.all(kYaruPagePadding),
child: Slider(
value: _take.toDouble(),
min: 1,
max: _lorem.characters.length.toDouble(),
onChanged: (v) => setState(() => _take = v.toInt()),
),
),
Expanded(
child: ListView.separated(
padding: const EdgeInsets.all(kYaruPagePadding),
itemCount: YaruInfoType.values.length,
itemBuilder: (context, index) {
return YaruBorderContainer(
padding: const EdgeInsets.all(8),
child: Text(_lorem.characters.take(_take).toString()),
);
},
separatorBuilder: (context, index) {
final info = YaruInfoType.values[index];

return Padding(
padding: const EdgeInsets.symmetric(vertical: kYaruPagePadding),
child: YaruTranslucentContainer(
padding: const EdgeInsets.all(8),
color: info.getColor(context),
child: Text(_lorem.characters.take(_take).toString()),
),
);
},
),
),
],
);
}
}

const _lorem =
'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.';
137 changes: 137 additions & 0 deletions example/lib/pages/info_page.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:yaru/yaru.dart';

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

@override
State<InfoPage> createState() => _InfoPageState();
}

class _InfoPageState extends State<InfoPage> {
int _take = 80;
bool _idea = false;

@override
Widget build(BuildContext context) {
return Column(
children: [
Padding(
padding: const EdgeInsets.all(kYaruPagePadding),
child: Row(
children: [
IconButton(
tooltip: 'Custom icons and colors are possible',
isSelected: _idea,
onPressed: () => setState(() => _idea = !_idea),
icon: const Icon(
YaruIcons.light_bulb_off,
size: 30,
),
selectedIcon: const Icon(
YaruIcons.light_bulb_on,
size: 30,
),
),
const SizedBox(
width: 5,
),
Expanded(
child: Slider(
value: _take.toDouble(),
min: 1,
max: _lorem.characters.length.toDouble(),
onChanged: (v) => setState(() => _take = v.toInt()),
),
),
],
),
),
Expanded(
child: ListView.builder(
padding: const EdgeInsets.all(kYaruPagePadding),
itemCount: YaruInfoType.values.length,
itemBuilder: (context, index) {
final info = YaruInfoType.values[index];
return Column(
mainAxisSize: MainAxisSize.min,
children: [
YaruInfoBox(
icon: info == YaruInfoType.information && _idea
? const Icon(YaruIcons.light_bulb_on)
: null,
color: info == YaruInfoType.information && _idea
? YaruColors.magenta
: null,
yaruInfoType: info,
title: Text(info.name.capitalize()),
subtitle: Text(_lorem.characters.take(_take).toString()),
trailing: info == YaruInfoType.information && _idea
? const _CopyButton(
text: _lorem,
)
: null,
),
Padding(
padding:
const EdgeInsets.symmetric(vertical: kYaruPagePadding),
child: Row(
children: [
YaruInfoBadge(
yaruInfoType: info,
title: Text(info.name.capitalize()),
),
],
),
),
],
);
},
),
),
],
);
}
}

class _CopyButton extends StatelessWidget {
const _CopyButton({required this.text});

final String text;

@override
Widget build(BuildContext context) {
return OutlinedButton(
style: OutlinedButton.styleFrom(
minimumSize: const Size.square(kYaruTitleBarItemHeight),
maximumSize: const Size.square(kYaruTitleBarItemHeight),
fixedSize: const Size.square(kYaruTitleBarItemHeight),
side: BorderSide(
width: 1,
color: YaruColors.magenta.withOpacity(0.5),
),
padding: EdgeInsets.zero,
),
onPressed: () {
Clipboard.setData(ClipboardData(text: text));
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Copied')),
);
},
child: const Icon(
YaruIcons.copy,
color: YaruColors.magenta,
),
);
}
}

extension _StringExtension on String {
String capitalize() {
return '${this[0].toUpperCase()}${substring(1).toLowerCase()}';
}
}

const _lorem =
'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.';
89 changes: 89 additions & 0 deletions lib/src/widgets/yaru_border_container.dart
Original file line number Diff line number Diff line change
Expand Up @@ -97,3 +97,92 @@ class YaruBorderContainer extends StatelessWidget {
);
}
}

/// A container with a rounded Yaru-style border and translucent background color
/// derived from the border color.
class YaruTranslucentContainer extends StatelessWidget {
/// Creates a [YaruTranslucentContainer].
const YaruTranslucentContainer({
super.key,
required this.color,
this.opacity = 0.1,
this.child,
this.alignment,
this.padding,
this.width,
this.height,
this.constraints,
this.margin,
this.transform,
this.transformAlignment,
this.clipBehavior = Clip.none,
this.border,
this.borderRadius,
});

/// See [Container.child].
final Widget? child;

/// See [Container.alignment].
final AlignmentGeometry? alignment;

/// See [Container.padding].
final EdgeInsetsGeometry? padding;

/// See [Container.color].
final Color color;

/// See [Container.width].
final double? width;

/// See [Container.height].
final double? height;

/// See [Container.constraints].
final BoxConstraints? constraints;

/// See [Container.margin].
final EdgeInsetsGeometry? margin;

/// See [Container.transform].
final Matrix4? transform;

/// See [Container.transformAlignment].
final AlignmentGeometry? transformAlignment;

/// See [Container.clipBehavior].
final Clip clipBehavior;

/// The border.
///
/// The default border is 1px wide and the color is [ThemeData.dividerColor].
final BoxBorder? border;

/// The border radius.
///
/// The default border is circular with the radius of `kYaruContainerRadius`.
final BorderRadiusGeometry? borderRadius;

/// The opacity value used to derive the background color from the border
final double opacity;

@override
Widget build(BuildContext context) {
return YaruBorderContainer(
alignment: alignment,
padding: padding,
color: color.withOpacity(opacity),
border: Border.all(color: color),
width: width,
height: height,
constraints: constraints,
margin: margin,
transform: transform,
transformAlignment: transformAlignment,
clipBehavior: clipBehavior,
borderRadius: borderRadius,
child: child,
);
}
}

0 comments on commit 198495b

Please sign in to comment.