forked from mirrors/material_3_expressive
Add initial configuration, tokens, and widgets for M3E components
- Introduced `.gitignore` and `.metadata` for apps and examples. - Added Flutter/Dart analysis configurations (`analysis_options.yaml`). - Implemented foundational tokens and themes for M3E (colors, shapes). - Created base implementations for `IconButtonM3E` and `SplitButtonM3E`. - Set up CI workflow (`ci.yaml`) to automate testing and analysis.
This commit is contained in:
parent
2c0f2df0b8
commit
62ecb86b76
184 changed files with 9872 additions and 0 deletions
45
apps/gallery/.gitignore
vendored
Normal file
45
apps/gallery/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
# Miscellaneous
|
||||
*.class
|
||||
*.log
|
||||
*.pyc
|
||||
*.swp
|
||||
.DS_Store
|
||||
.atom/
|
||||
.build/
|
||||
.buildlog/
|
||||
.history
|
||||
.svn/
|
||||
.swiftpm/
|
||||
migrate_working_dir/
|
||||
|
||||
# IntelliJ related
|
||||
*.iml
|
||||
*.ipr
|
||||
*.iws
|
||||
.idea/
|
||||
|
||||
# The .vscode folder contains launch configuration and tasks you configure in
|
||||
# VS Code which you may wish to be included in version control, so this line
|
||||
# is commented out by default.
|
||||
#.vscode/
|
||||
|
||||
# Flutter/Dart/Pub related
|
||||
**/doc/api/
|
||||
**/ios/Flutter/.last_build_id
|
||||
.dart_tool/
|
||||
.flutter-plugins-dependencies
|
||||
.pub-cache/
|
||||
.pub/
|
||||
/build/
|
||||
/coverage/
|
||||
|
||||
# Symbolication related
|
||||
app.*.symbols
|
||||
|
||||
# Obfuscation related
|
||||
app.*.map.json
|
||||
|
||||
# Android Studio will place build artifacts here
|
||||
/android/app/debug
|
||||
/android/app/profile
|
||||
/android/app/release
|
||||
45
apps/gallery/.metadata
Normal file
45
apps/gallery/.metadata
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
# This file tracks properties of this Flutter project.
|
||||
# Used by Flutter tool to assess capabilities and perform upgrades etc.
|
||||
#
|
||||
# This file should be version controlled and should not be manually edited.
|
||||
|
||||
version:
|
||||
revision: "d693b4b9dbac2acd4477aea4555ca6dcbea44ba2"
|
||||
channel: "stable"
|
||||
|
||||
project_type: app
|
||||
|
||||
# Tracks metadata for the flutter migrate command
|
||||
migration:
|
||||
platforms:
|
||||
- platform: root
|
||||
create_revision: d693b4b9dbac2acd4477aea4555ca6dcbea44ba2
|
||||
base_revision: d693b4b9dbac2acd4477aea4555ca6dcbea44ba2
|
||||
- platform: android
|
||||
create_revision: d693b4b9dbac2acd4477aea4555ca6dcbea44ba2
|
||||
base_revision: d693b4b9dbac2acd4477aea4555ca6dcbea44ba2
|
||||
- platform: ios
|
||||
create_revision: d693b4b9dbac2acd4477aea4555ca6dcbea44ba2
|
||||
base_revision: d693b4b9dbac2acd4477aea4555ca6dcbea44ba2
|
||||
- platform: linux
|
||||
create_revision: d693b4b9dbac2acd4477aea4555ca6dcbea44ba2
|
||||
base_revision: d693b4b9dbac2acd4477aea4555ca6dcbea44ba2
|
||||
- platform: macos
|
||||
create_revision: d693b4b9dbac2acd4477aea4555ca6dcbea44ba2
|
||||
base_revision: d693b4b9dbac2acd4477aea4555ca6dcbea44ba2
|
||||
- platform: web
|
||||
create_revision: d693b4b9dbac2acd4477aea4555ca6dcbea44ba2
|
||||
base_revision: d693b4b9dbac2acd4477aea4555ca6dcbea44ba2
|
||||
- platform: windows
|
||||
create_revision: d693b4b9dbac2acd4477aea4555ca6dcbea44ba2
|
||||
base_revision: d693b4b9dbac2acd4477aea4555ca6dcbea44ba2
|
||||
|
||||
# User provided section
|
||||
|
||||
# List of Local paths (relative to this file) that should be
|
||||
# ignored by the migrate tool.
|
||||
#
|
||||
# Files that are not part of the templates will be ignored by default.
|
||||
unmanaged_files:
|
||||
- 'lib/main.dart'
|
||||
- 'ios/Runner.xcodeproj/project.pbxproj'
|
||||
16
apps/gallery/README.md
Normal file
16
apps/gallery/README.md
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
# m3e_gallery
|
||||
|
||||
A new Flutter project.
|
||||
|
||||
## Getting Started
|
||||
|
||||
This project is a starting point for a Flutter application.
|
||||
|
||||
A few resources to get you started if this is your first Flutter project:
|
||||
|
||||
- [Lab: Write your first Flutter app](https://docs.flutter.dev/get-started/codelab)
|
||||
- [Cookbook: Useful Flutter samples](https://docs.flutter.dev/cookbook)
|
||||
|
||||
For help getting started with Flutter development, view the
|
||||
[online documentation](https://docs.flutter.dev/), which offers tutorials,
|
||||
samples, guidance on mobile development, and a full API reference.
|
||||
28
apps/gallery/analysis_options.yaml
Normal file
28
apps/gallery/analysis_options.yaml
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
# This file configures the analyzer, which statically analyzes Dart code to
|
||||
# check for errors, warnings, and lints.
|
||||
#
|
||||
# The issues identified by the analyzer are surfaced in the UI of Dart-enabled
|
||||
# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be
|
||||
# invoked from the command line by running `flutter analyze`.
|
||||
|
||||
# The following line activates a set of recommended lints for Flutter apps,
|
||||
# packages, and plugins designed to encourage good coding practices.
|
||||
# include: package:flutter_lints/flutter.yaml
|
||||
|
||||
linter:
|
||||
# The lint rules applied to this project can be customized in the
|
||||
# section below to disable rules from the `package:flutter_lints/flutter.yaml`
|
||||
# included above or to enable additional rules. A list of all available lints
|
||||
# and their documentation is published at https://dart.dev/lints.
|
||||
#
|
||||
# Instead of disabling a lint rule for the entire project in the
|
||||
# section below, it can also be suppressed for a single line of code
|
||||
# or a specific dart file by using the `// ignore: name_of_lint` and
|
||||
# `// ignore_for_file: name_of_lint` syntax on the line or in the file
|
||||
# producing the lint.
|
||||
rules:
|
||||
# avoid_print: false # Uncomment to disable the `avoid_print` rule
|
||||
prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule
|
||||
|
||||
# Additional information about this file can be found at
|
||||
# https://dart.dev/guides/language/analysis-options
|
||||
560
apps/gallery/lib/main.dart
Normal file
560
apps/gallery/lib/main.dart
Normal file
|
|
@ -0,0 +1,560 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:m3e_collection/m3e_collection.dart';
|
||||
|
||||
void main() => runApp(const GalleryApp());
|
||||
|
||||
class GalleryApp extends StatelessWidget {
|
||||
const GalleryApp({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final base = ThemeData(useMaterial3: true, colorSchemeSeed: Colors.purple);
|
||||
return MaterialApp(
|
||||
title: 'M3E Gallery',
|
||||
theme: withM3ETheme(base),
|
||||
home: const GalleryHome(),
|
||||
debugShowCheckedModeBanner: false,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class GalleryHome extends StatefulWidget {
|
||||
const GalleryHome({super.key});
|
||||
|
||||
@override
|
||||
State<GalleryHome> createState() => _GalleryHomeState();
|
||||
}
|
||||
|
||||
class _GalleryHomeState extends State<GalleryHome> {
|
||||
// Navigation examples
|
||||
int _navBarIndex = 0;
|
||||
int _railIndex = 0;
|
||||
|
||||
// Slider examples
|
||||
double _sliderValue = 0.4;
|
||||
RangeValues _rangeValues = const RangeValues(0.25, 0.75);
|
||||
|
||||
// Progress examples
|
||||
double _progressValue = 0.6;
|
||||
|
||||
void onPressed() {
|
||||
// Placeholder function for button onPressed
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final cs = Theme.of(context).colorScheme;
|
||||
final m3e =
|
||||
Theme.of(context).extension<M3ETheme>() ?? M3ETheme.defaults(cs);
|
||||
return Scaffold(
|
||||
appBar: AppBarM3E(
|
||||
titleText: 'M3E Gallery',
|
||||
actions: const [
|
||||
Icon(Icons.search),
|
||||
SizedBox(width: 8),
|
||||
Icon(Icons.more_vert),
|
||||
],
|
||||
),
|
||||
body: ListView(
|
||||
padding: const EdgeInsets.all(16),
|
||||
children: [
|
||||
// Icon buttons
|
||||
Text('IconButtonM3E', style: Theme.of(context).textTheme.titleLarge),
|
||||
const SizedBox(height: 12),
|
||||
Wrap(
|
||||
spacing: 12,
|
||||
runSpacing: 12,
|
||||
children: [
|
||||
IconButtonM3E(
|
||||
icon: Icon(Icons.favorite),
|
||||
variant: IconButtonM3EVariant.filled,
|
||||
onPressed: onPressed),
|
||||
IconButtonM3E(
|
||||
icon: Icon(Icons.favorite),
|
||||
variant: IconButtonM3EVariant.tonal,
|
||||
onPressed: onPressed),
|
||||
IconButtonM3E(
|
||||
icon: Icon(Icons.favorite),
|
||||
variant: IconButtonM3EVariant.outlined,
|
||||
onPressed: onPressed),
|
||||
IconButtonM3E(
|
||||
icon: Icon(Icons.favorite),
|
||||
variant: IconButtonM3EVariant.standard,
|
||||
onPressed: onPressed),
|
||||
],
|
||||
),
|
||||
|
||||
const SizedBox(height: 24),
|
||||
// Split Button
|
||||
Text('SplitButtonM3E', style: Theme.of(context).textTheme.titleLarge),
|
||||
const SizedBox(height: 12),
|
||||
Wrap(
|
||||
spacing: 12,
|
||||
runSpacing: 12,
|
||||
children: [
|
||||
SplitButtonM3E<String>(
|
||||
label: 'Primary',
|
||||
onPressed: () {},
|
||||
items: const [
|
||||
SplitButtonM3EItem<String>(value: 'one', child: 'One'),
|
||||
SplitButtonM3EItem<String>(value: 'two', child: 'Two'),
|
||||
],
|
||||
),
|
||||
SplitButtonM3E<String>(
|
||||
label: 'Tonal',
|
||||
emphasis: SplitButtonM3EEmphasis.tonal,
|
||||
onPressed: () {},
|
||||
items: const [
|
||||
SplitButtonM3EItem<String>(value: 'one', child: 'One'),
|
||||
SplitButtonM3EItem<String>(value: 'two', child: 'Two'),
|
||||
],
|
||||
),
|
||||
SplitButtonM3E<String>(
|
||||
label: 'Outlined',
|
||||
emphasis: SplitButtonM3EEmphasis.outlined,
|
||||
onPressed: () {},
|
||||
items: const [
|
||||
SplitButtonM3EItem<String>(value: 'one', child: 'One'),
|
||||
SplitButtonM3EItem<String>(value: 'two', child: 'Two'),
|
||||
],
|
||||
),
|
||||
SplitButtonM3E<String>(
|
||||
label: 'Text',
|
||||
emphasis: SplitButtonM3EEmphasis.text,
|
||||
onPressed: () {},
|
||||
items: const [
|
||||
SplitButtonM3EItem<String>(value: 'one', child: 'One'),
|
||||
SplitButtonM3EItem<String>(value: 'two', child: 'Two'),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
const SizedBox(height: 24),
|
||||
// Buttons
|
||||
Text('ButtonM3E', style: Theme.of(context).textTheme.titleLarge),
|
||||
const SizedBox(height: 12),
|
||||
Wrap(spacing: 12, runSpacing: 12, children: [
|
||||
Wrap(
|
||||
spacing: 12,
|
||||
runSpacing: 12,
|
||||
children: [
|
||||
ButtonM3E(
|
||||
labelText: 'Filled',
|
||||
variant: ButtonM3EVariant.filled,
|
||||
onPressed: onPressed),
|
||||
ButtonM3E(
|
||||
labelText: 'Tonal',
|
||||
variant: ButtonM3EVariant.tonal,
|
||||
onPressed: onPressed),
|
||||
ButtonM3E(
|
||||
labelText: 'Outlined',
|
||||
variant: ButtonM3EVariant.outlined,
|
||||
onPressed: onPressed),
|
||||
ButtonM3E(
|
||||
labelText: 'Text',
|
||||
variant: ButtonM3EVariant.text,
|
||||
onPressed: onPressed),
|
||||
ButtonM3E(
|
||||
labelText: 'Elevated',
|
||||
variant: ButtonM3EVariant.elevated,
|
||||
onPressed: onPressed),
|
||||
],
|
||||
),
|
||||
Wrap(
|
||||
spacing: 12,
|
||||
runSpacing: 12,
|
||||
children: [
|
||||
ButtonM3E(
|
||||
labelText: 'Filled',
|
||||
variant: ButtonM3EVariant.filled,
|
||||
shapeFamily: ButtonM3EShapeFamily.square,
|
||||
onPressed: onPressed),
|
||||
ButtonM3E(
|
||||
labelText: 'Tonal',
|
||||
variant: ButtonM3EVariant.tonal,
|
||||
shapeFamily: ButtonM3EShapeFamily.square,
|
||||
onPressed: onPressed),
|
||||
ButtonM3E(
|
||||
labelText: 'Outlined',
|
||||
variant: ButtonM3EVariant.outlined,
|
||||
shapeFamily: ButtonM3EShapeFamily.square,
|
||||
onPressed: onPressed),
|
||||
ButtonM3E(
|
||||
labelText: 'Text',
|
||||
variant: ButtonM3EVariant.text,
|
||||
shapeFamily: ButtonM3EShapeFamily.square,
|
||||
onPressed: onPressed),
|
||||
ButtonM3E(
|
||||
labelText: 'Elevated',
|
||||
variant: ButtonM3EVariant.elevated,
|
||||
shapeFamily: ButtonM3EShapeFamily.square,
|
||||
onPressed: onPressed),
|
||||
],
|
||||
),
|
||||
]),
|
||||
|
||||
const SizedBox(height: 24),
|
||||
// Button groups
|
||||
Text('ButtonGroupM3E', style: Theme.of(context).textTheme.titleLarge),
|
||||
const SizedBox(height: 12),
|
||||
// Standard group, round, md
|
||||
ButtonGroupM3E(
|
||||
type: ButtonGroupM3EType.standard,
|
||||
shape: ButtonGroupM3EShape.round,
|
||||
size: ButtonGroupM3ESize.md,
|
||||
children: const [
|
||||
IconButtonM3E(icon: Icon(Icons.skip_previous)),
|
||||
IconButtonM3E(icon: Icon(Icons.play_arrow)),
|
||||
IconButtonM3E(icon: Icon(Icons.skip_next)),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
// Connected group with divider and clipping for outer corners
|
||||
ButtonGroupM3E(
|
||||
type: ButtonGroupM3EType.connected,
|
||||
shape: ButtonGroupM3EShape.round,
|
||||
size: ButtonGroupM3ESize.lg,
|
||||
showDividers: true,
|
||||
clipBehavior: Clip.hardEdge,
|
||||
equalizeWidths: true,
|
||||
semanticLabel: 'Actions',
|
||||
children: [
|
||||
SplitButtonM3E<String>(
|
||||
label: 'Primary',
|
||||
onPressed: () {},
|
||||
items: const [
|
||||
SplitButtonM3EItem<String>(value: 'one', child: 'One'),
|
||||
SplitButtonM3EItem<String>(value: 'two', child: 'Two'),
|
||||
],
|
||||
),
|
||||
SplitButtonM3E<String>(
|
||||
label: 'Tonal',
|
||||
emphasis: SplitButtonM3EEmphasis.tonal,
|
||||
onPressed: () {},
|
||||
items: const [
|
||||
SplitButtonM3EItem<String>(value: 'one', child: 'One'),
|
||||
SplitButtonM3EItem<String>(value: 'two', child: 'Two'),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
// Square, compact, vertical wrap
|
||||
ButtonGroupM3E(
|
||||
type: ButtonGroupM3EType.standard,
|
||||
shape: ButtonGroupM3EShape.square,
|
||||
size: ButtonGroupM3ESize.sm,
|
||||
density: ButtonGroupM3EDensity.compact,
|
||||
direction: Axis.vertical,
|
||||
children: const [
|
||||
IconButtonM3E(icon: Icon(Icons.view_agenda_outlined)),
|
||||
IconButtonM3E(icon: Icon(Icons.table_rows_outlined)),
|
||||
IconButtonM3E(icon: Icon(Icons.grid_view_outlined)),
|
||||
],
|
||||
),
|
||||
|
||||
const SizedBox(height: 24),
|
||||
// Toolbar
|
||||
Text('ToolbarM3E', style: Theme.of(context).textTheme.titleLarge),
|
||||
const SizedBox(height: 12),
|
||||
ToolbarM3E(
|
||||
titleText: 'Toolbar Title',
|
||||
subtitleText: 'Subtitle',
|
||||
actions: [
|
||||
ToolbarActionM3E(icon: Icons.search, onPressed: () {}),
|
||||
ToolbarActionM3E(icon: Icons.share, onPressed: () {}),
|
||||
ToolbarActionM3E(
|
||||
icon: Icons.delete,
|
||||
onPressed: () {},
|
||||
isDestructive: true,
|
||||
label: 'Delete'),
|
||||
ToolbarActionM3E(
|
||||
icon: Icons.settings, onPressed: () {}, label: 'Settings'),
|
||||
],
|
||||
maxInlineActions: 2,
|
||||
),
|
||||
|
||||
const SizedBox(height: 24),
|
||||
// FABs
|
||||
Text('FabM3E', style: Theme.of(context).textTheme.titleLarge),
|
||||
const SizedBox(height: 12),
|
||||
Wrap(
|
||||
spacing: 12,
|
||||
runSpacing: 12,
|
||||
children: const [
|
||||
FabM3E(icon: Icon(Icons.add)),
|
||||
FabM3E(icon: Icon(Icons.edit), kind: FabM3EKind.secondary),
|
||||
FabM3E(icon: Icon(Icons.share), kind: FabM3EKind.tertiary),
|
||||
FabM3E(icon: Icon(Icons.more_horiz), kind: FabM3EKind.surface),
|
||||
FabM3E(icon: Icon(Icons.add), size: FabM3ESize.small),
|
||||
FabM3E(icon: Icon(Icons.add), size: FabM3ESize.large),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
Wrap(
|
||||
spacing: 12,
|
||||
runSpacing: 12,
|
||||
children: const [
|
||||
ExtendedFabM3E(label: Text('Create'), icon: Icon(Icons.add)),
|
||||
ExtendedFabM3E(
|
||||
label: Text('Edit'),
|
||||
icon: Icon(Icons.edit),
|
||||
kind: FabM3EKind.secondary),
|
||||
ExtendedFabM3E(
|
||||
label: Text('Share'),
|
||||
icon: Icon(Icons.share),
|
||||
kind: FabM3EKind.tertiary),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
SizedBox(
|
||||
height: 180,
|
||||
child: Stack(
|
||||
children: [
|
||||
Positioned.fill(
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
color:
|
||||
Theme.of(context).colorScheme.surfaceContainerHighest,
|
||||
borderRadius: m3e.shapes.round.lg,
|
||||
),
|
||||
),
|
||||
),
|
||||
Align(
|
||||
alignment: Alignment.bottomRight,
|
||||
child: FabMenuM3E(
|
||||
primaryFab: const FabM3E(icon: Icon(Icons.menu)),
|
||||
items: [
|
||||
FabMenuItem(
|
||||
icon: const Icon(Icons.image),
|
||||
label: const Text('Image'),
|
||||
onPressed: () {}),
|
||||
FabMenuItem(
|
||||
icon: const Icon(Icons.camera_alt),
|
||||
label: const Text('Camera'),
|
||||
onPressed: () {}),
|
||||
FabMenuItem(
|
||||
icon: const Icon(Icons.file_upload),
|
||||
label: const Text('Upload'),
|
||||
onPressed: () {}),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
const SizedBox(height: 24),
|
||||
// Loading indicators
|
||||
Text('LoadingIndicatorM3E',
|
||||
style: Theme.of(context).textTheme.titleLarge),
|
||||
const SizedBox(height: 12),
|
||||
Wrap(
|
||||
spacing: 16,
|
||||
runSpacing: 16,
|
||||
crossAxisAlignment: WrapCrossAlignment.center,
|
||||
children: const [
|
||||
LoadingIndicatorM3E(
|
||||
variant: LoadingIndicatorM3EVariant.defaultStyle),
|
||||
LoadingIndicatorM3E(
|
||||
variant: LoadingIndicatorM3EVariant.contained),
|
||||
],
|
||||
),
|
||||
|
||||
const SizedBox(height: 24),
|
||||
// Progress indicators
|
||||
Text('ProgressIndicatorM3E',
|
||||
style: Theme.of(context).textTheme.titleLarge),
|
||||
const SizedBox(height: 12),
|
||||
Wrap(
|
||||
spacing: 16,
|
||||
runSpacing: 16,
|
||||
crossAxisAlignment: WrapCrossAlignment.center,
|
||||
children: [
|
||||
const CircularProgressM3E(),
|
||||
const CircularProgressM3E(size: ProgressM3ESize.small),
|
||||
CircularProgressM3E(
|
||||
size: ProgressM3ESize.large,
|
||||
value: _progressValue,
|
||||
showCenterLabel: true),
|
||||
const LinearProgressM3E(minWidth: 200),
|
||||
LinearProgressM3E(minWidth: 200, value: _progressValue),
|
||||
const LinearProgressM3E(
|
||||
minWidth: 200,
|
||||
variant: LinearProgressM3EVariant.indeterminate),
|
||||
const LinearProgressM3E(
|
||||
minWidth: 200, variant: LinearProgressM3EVariant.query),
|
||||
const LinearProgressM3E(
|
||||
minWidth: 200,
|
||||
variant: LinearProgressM3EVariant.buffer,
|
||||
bufferValue: 0.8,
|
||||
value: 0.4),
|
||||
],
|
||||
),
|
||||
|
||||
const SizedBox(height: 24),
|
||||
// Sliders
|
||||
Text('SliderM3E', style: Theme.of(context).textTheme.titleLarge),
|
||||
const SizedBox(height: 12),
|
||||
SliderM3E(
|
||||
value: _sliderValue,
|
||||
onChanged: (v) => setState(() => _sliderValue = v),
|
||||
min: 0,
|
||||
max: 100,
|
||||
label: '${_sliderValue.toStringAsFixed(0)}',
|
||||
startIcon: const Icon(Icons.volume_mute),
|
||||
endIcon: const Icon(Icons.volume_up),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
RangeSliderM3E(
|
||||
values: _rangeValues,
|
||||
onChanged: (v) => setState(() => _rangeValues = v),
|
||||
min: 0,
|
||||
max: 100,
|
||||
labels: RangeLabels(
|
||||
_rangeValues.start.toStringAsFixed(0),
|
||||
_rangeValues.end.toStringAsFixed(0),
|
||||
),
|
||||
),
|
||||
|
||||
const SizedBox(height: 24),
|
||||
// Navigation Bar
|
||||
Text('NavigationBarM3E',
|
||||
style: Theme.of(context).textTheme.titleLarge),
|
||||
const SizedBox(height: 12),
|
||||
NavigationBarM3E(
|
||||
selectedIndex: _navBarIndex,
|
||||
onDestinationSelected: (i) => setState(() => _navBarIndex = i),
|
||||
indicatorStyle: NavBarM3EIndicatorStyle.pill,
|
||||
destinations: const [
|
||||
NavigationDestinationM3E(
|
||||
icon: Icon(Icons.home_outlined),
|
||||
selectedIcon: Icon(Icons.home),
|
||||
label: 'Home'),
|
||||
NavigationDestinationM3E(
|
||||
icon: Icon(Icons.search_outlined),
|
||||
selectedIcon: Icon(Icons.search),
|
||||
label: 'Search',
|
||||
badgeDot: true),
|
||||
NavigationDestinationM3E(
|
||||
icon: Icon(Icons.favorite_outline),
|
||||
selectedIcon: Icon(Icons.favorite),
|
||||
label: 'Favorites',
|
||||
badgeCount: 3),
|
||||
NavigationDestinationM3E(
|
||||
icon: Icon(Icons.person_outline),
|
||||
selectedIcon: Icon(Icons.person),
|
||||
label: 'Profile'),
|
||||
],
|
||||
),
|
||||
|
||||
const SizedBox(height: 24),
|
||||
// Navigation Rail
|
||||
Text('NavigationRailM3E',
|
||||
style: Theme.of(context).textTheme.titleLarge),
|
||||
const SizedBox(height: 12),
|
||||
Container(
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).colorScheme.surfaceContainerHighest,
|
||||
borderRadius: m3e.shapes.round.lg,
|
||||
),
|
||||
height: 180,
|
||||
child: Row(
|
||||
children: [
|
||||
NavigationRailM3E(
|
||||
selectedIndex: _railIndex,
|
||||
onDestinationSelected: (i) => setState(() => _railIndex = i),
|
||||
indicatorStyle: RailIndicatorStyle.pill,
|
||||
destinations: const [
|
||||
RailDestinationM3E(
|
||||
icon: Icon(Icons.dashboard_outlined),
|
||||
selectedIcon: Icon(Icons.dashboard),
|
||||
label: 'Dashboard'),
|
||||
RailDestinationM3E(
|
||||
icon: Icon(Icons.analytics_outlined),
|
||||
selectedIcon: Icon(Icons.analytics),
|
||||
label: 'Reports'),
|
||||
RailDestinationM3E(
|
||||
icon: Icon(Icons.settings_outlined),
|
||||
selectedIcon: Icon(Icons.settings),
|
||||
label: 'Settings'),
|
||||
],
|
||||
),
|
||||
const VerticalDivider(width: 1),
|
||||
Expanded(
|
||||
child: Center(
|
||||
child: Text('Selected: $_railIndex'),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
const SizedBox(height: 24),
|
||||
// Sliver App Bar demo route
|
||||
Text('App bars', style: Theme.of(context).textTheme.titleLarge),
|
||||
const SizedBox(height: 12),
|
||||
Wrap(
|
||||
spacing: 12,
|
||||
children: [
|
||||
const ButtonM3E(labelText: 'Open SliverAppBarM3E Demo'),
|
||||
// Use GestureDetector to navigate when tapping the button label area
|
||||
]
|
||||
.map((w) => GestureDetector(
|
||||
onTap: () => Navigator.of(context).push(
|
||||
MaterialPageRoute(
|
||||
builder: (_) => const _SliverAppBarDemoPage()),
|
||||
),
|
||||
child: w,
|
||||
))
|
||||
.toList(),
|
||||
),
|
||||
|
||||
const SizedBox(height: 48),
|
||||
// Theming surface example remains
|
||||
Container(
|
||||
padding: const EdgeInsets.all(16),
|
||||
decoration: BoxDecoration(
|
||||
color: m3e.colors.surfaceStrong,
|
||||
borderRadius: m3e.shapes.square.lg,
|
||||
),
|
||||
child: Text('Surface strong example',
|
||||
style: Theme.of(context)
|
||||
.textTheme
|
||||
.titleMedium
|
||||
?.copyWith(color: cs.onSurface)),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _SliverAppBarDemoPage extends StatelessWidget {
|
||||
const _SliverAppBarDemoPage();
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
body: CustomScrollView(
|
||||
slivers: [
|
||||
const SliverAppBarM3E(
|
||||
titleText: 'SliverAppBarM3E',
|
||||
pinned: true,
|
||||
floating: false,
|
||||
variant: AppBarM3EVariant.large,
|
||||
),
|
||||
SliverList(
|
||||
delegate: SliverChildBuilderDelegate(
|
||||
(context, index) => ListTile(
|
||||
title: Text('Item #$index'),
|
||||
),
|
||||
childCount: 30,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
16
apps/gallery/pubspec.yaml
Normal file
16
apps/gallery/pubspec.yaml
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
name: m3e_gallery
|
||||
description: Gallery app for Material 3 Expressive packages.
|
||||
publish_to: none
|
||||
|
||||
environment:
|
||||
sdk: ">=3.5.0 <4.0.0"
|
||||
|
||||
dependencies:
|
||||
flutter:
|
||||
sdk: flutter
|
||||
m3e_collection:
|
||||
path: ../../packages/m3e_collection
|
||||
material_color_utilities: ^0.11.0
|
||||
|
||||
flutter:
|
||||
uses-material-design: true
|
||||
30
apps/gallery/pubspec_overrides.yaml
Normal file
30
apps/gallery/pubspec_overrides.yaml
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
# melos_managed_dependency_overrides: icon_button_m3e,m3e_collection,m3e_design,split_button_m3e,app_bar_m3e,button_group_m3e,button_m3e,fab_m3e,loading_indicator_m3e,navigation_bar_m3e,navigation_rail_m3e,progress_indicator_m3e,slider_m3e,toolbar_m3e
|
||||
dependency_overrides:
|
||||
app_bar_m3e:
|
||||
path: ..\\..\\packages\\app_bar_m3e
|
||||
button_group_m3e:
|
||||
path: ..\\..\\packages\\button_group_m3e
|
||||
button_m3e:
|
||||
path: ..\\..\\packages\\button_m3e
|
||||
fab_m3e:
|
||||
path: ..\\..\\packages\\fab_m3e
|
||||
icon_button_m3e:
|
||||
path: ..\\..\\packages\\icon_button_m3e
|
||||
loading_indicator_m3e:
|
||||
path: ..\\..\\packages\\loading_indicator_m3e
|
||||
m3e_collection:
|
||||
path: ..\\..\\packages\\m3e_collection
|
||||
m3e_design:
|
||||
path: ..\\..\\packages\\m3e_design
|
||||
navigation_bar_m3e:
|
||||
path: ..\\..\\packages\\navigation_bar_m3e
|
||||
navigation_rail_m3e:
|
||||
path: ..\\..\\packages\\navigation_rail_m3e
|
||||
progress_indicator_m3e:
|
||||
path: ..\\..\\packages\\progress_indicator_m3e
|
||||
slider_m3e:
|
||||
path: ..\\..\\packages\\slider_m3e
|
||||
split_button_m3e:
|
||||
path: ..\\..\\packages\\split_button_m3e
|
||||
toolbar_m3e:
|
||||
path: ..\\..\\packages\\toolbar_m3e
|
||||
Loading…
Add table
Add a link
Reference in a new issue