mirror of
https://github.com/Iconica-Development/flutter_nested_categories.git
synced 2025-05-18 23:33:44 +02:00
Feat/intial nested categories (#1)
* feat: add nested category functionality * feat(example): add nested category example app * chore(changelog): add v0.0.1 changelog * chore(readme): add readme * feat(custom-header): add custom category header functionality * feat(header_style): add default header style requirement * feat(capitalization): add header capitalization * fix: feedback * fix: feedback
This commit is contained in:
parent
fd6e7170bf
commit
8fce7a499e
13 changed files with 649 additions and 29 deletions
|
@ -1,3 +1,5 @@
|
|||
## 0.0.1
|
||||
|
||||
* TODO: Describe initial release.
|
||||
* Initial Nested Category functionality.
|
||||
* Title of categories
|
||||
* Collapsible categories
|
||||
|
|
83
README.md
83
README.md
|
@ -1,39 +1,68 @@
|
|||
<!--
|
||||
This README describes the package. If you publish this package to pub.dev,
|
||||
this README's contents appear on the landing page for your package.
|
||||
# flutter_nested_categories
|
||||
|
||||
For information about how to write a good package README, see the guide for
|
||||
[writing package pages](https://dart.dev/guides/libraries/writing-package-pages).
|
||||
|
||||
For general information about developing packages, see the Dart guide for
|
||||
[creating packages](https://dart.dev/guides/libraries/create-library-packages)
|
||||
and the Flutter guide for
|
||||
[developing packages and plugins](https://flutter.dev/developing-packages).
|
||||
-->
|
||||
|
||||
TODO: Put a short description of the package here that helps potential users
|
||||
know whether this package might be useful for them.
|
||||
This Flutter component allows you to easily create nested categories that are very
|
||||
customizable.
|
||||
|
||||
## Features
|
||||
|
||||
TODO: List what your package can do. Maybe include images, gifs, or videos.
|
||||
|
||||
## Getting started
|
||||
|
||||
TODO: List prerequisites and provide or point to information on how to
|
||||
start using the package.
|
||||
* Nested Categories
|
||||
* Collapsible Categories
|
||||
|
||||
## Usage
|
||||
|
||||
TODO: Include short and useful examples for package users. Add longer examples
|
||||
to `/example` folder.
|
||||
You can build a nested category using the `CategoryList` class, like this:
|
||||
|
||||
```dart
|
||||
const like = 'sample';
|
||||
CategoryList(
|
||||
content: [
|
||||
Category(
|
||||
name: "Category 1",
|
||||
content: [
|
||||
const Text("Content 1"),
|
||||
const Text("Content 2"),
|
||||
],
|
||||
nestedCategories: [
|
||||
Category(
|
||||
name: "Category 1.1",
|
||||
content: [
|
||||
const Text("Content 1.1"),
|
||||
const Text("Content 1.2"),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
```
|
||||
|
||||
## Additional information
|
||||
You have a bunch of customization options available as well, such as:
|
||||
|
||||
TODO: Tell users more about the package: where to find more information, how to
|
||||
contribute to the package, how to file issues, what response they can expect
|
||||
from the package authors, and more.
|
||||
* Setting a (text)title (and title styling/center),
|
||||
* Setting a custom title,
|
||||
* Collapsible categories,
|
||||
* Header styling.
|
||||
|
||||
For a more detailed example you can see the [example](https://github.com/Iconica-Development/flutter_nested_categories/tree/main/example).
|
||||
|
||||
Or, you could run the example yourself:
|
||||
```
|
||||
git clone https://github.com/Iconica-Development/flutter_nested_categories.git
|
||||
|
||||
cd flutter_nested_categories
|
||||
|
||||
cd example
|
||||
|
||||
flutter run
|
||||
```
|
||||
|
||||
## Issues
|
||||
|
||||
Please file any issues, bugs or feature request as an issue on our [GitHub](https://github.com/Iconica-Development/flutter_nested_categories) page. Commercial support is available if you need help with integration with your app or services. You can contact us at [support@iconica.nl](mailto:support@iconica.nl).
|
||||
|
||||
## Want to contribute
|
||||
|
||||
If you would like to contribute to the component (e.g. by improving the documentation, solving a bug or adding a cool new feature), please carefully review our [contribution guide](./CONTRIBUTING.md) and send us your [pull request](https://github.com/Iconica-Development/flutter_nested_categories/pulls).
|
||||
|
||||
## Author
|
||||
|
||||
This flutter_thermal_printer for Flutter is developed by [Iconica](https://iconica.nl). You can contact us at <support@iconica.nl>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
include: package:flutter_iconica_analysis/analysis_options.yaml
|
||||
include: package:flutter_iconica_analysis/components_options.yaml
|
||||
|
||||
# Possible to overwrite the rules from the package
|
||||
|
||||
|
|
53
example/.gitignore
vendored
Normal file
53
example/.gitignore
vendored
Normal file
|
@ -0,0 +1,53 @@
|
|||
# Miscellaneous
|
||||
*.class
|
||||
*.log
|
||||
*.pyc
|
||||
*.swp
|
||||
.DS_Store
|
||||
.atom/
|
||||
.buildlog/
|
||||
.history
|
||||
.svn/
|
||||
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
|
||||
.flutter-plugins-dependencies
|
||||
.pub-cache/
|
||||
.pub/
|
||||
/build/
|
||||
.metadata
|
||||
pubspec.lock
|
||||
|
||||
# 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
|
||||
|
||||
# Platforms
|
||||
/android/
|
||||
/ios/
|
||||
/linux/
|
||||
/macos/
|
||||
/web/
|
||||
/windows/
|
16
example/README.md
Normal file
16
example/README.md
Normal file
|
@ -0,0 +1,16 @@
|
|||
# flutter_nested_categories_example
|
||||
|
||||
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.
|
9
example/analysis_options.yaml
Normal file
9
example/analysis_options.yaml
Normal file
|
@ -0,0 +1,9 @@
|
|||
include: package:flutter_iconica_analysis/analysis_options.yaml
|
||||
|
||||
# Possible to overwrite the rules from the package
|
||||
|
||||
analyzer:
|
||||
exclude:
|
||||
|
||||
linter:
|
||||
rules:
|
106
example/lib/main.dart
Normal file
106
example/lib/main.dart
Normal file
|
@ -0,0 +1,106 @@
|
|||
import "package:flutter/material.dart";
|
||||
import "package:flutter_nested_categories/flutter_nested_categories.dart";
|
||||
|
||||
void main() {
|
||||
runApp(const MyApp());
|
||||
}
|
||||
|
||||
class MyApp extends StatelessWidget {
|
||||
const MyApp({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
var theme = Theme.of(context);
|
||||
|
||||
return MaterialApp(
|
||||
home: Scaffold(
|
||||
appBar: AppBar(
|
||||
title: const Text("Nested Categories Example"),
|
||||
),
|
||||
body: CategoryList(
|
||||
title: "This is the title of the list",
|
||||
titleCentered: true,
|
||||
headerCentered: false,
|
||||
isCategoryCollapsible: true,
|
||||
headerStyling: CategoryHeaderStyling(
|
||||
headerStyles: {
|
||||
0: theme.textTheme.titleLarge?.copyWith(color: Colors.red),
|
||||
2: theme.textTheme.titleLarge?.copyWith(color: Colors.blue),
|
||||
},
|
||||
defaultStyle:
|
||||
theme.textTheme.titleLarge!.copyWith(color: Colors.green),
|
||||
capitalization: CategoryHeaderCapitalization.uppercase,
|
||||
),
|
||||
content: [
|
||||
Category(
|
||||
name: "category 1",
|
||||
content: [
|
||||
const Text("Content 1"),
|
||||
Image.network(
|
||||
"https://via.placeholder.com/150?text=Content+2+Image",
|
||||
),
|
||||
],
|
||||
nestedCategories: [
|
||||
const Category(
|
||||
name: "Category 1.1",
|
||||
content: [
|
||||
Text("Content 1.1"),
|
||||
Text("Content 1.2"),
|
||||
],
|
||||
nestedCategories: [
|
||||
Category(
|
||||
name: "Category 1.1.1",
|
||||
content: [
|
||||
Text("Content 1.1.1"),
|
||||
Text("Content 1.1.2"),
|
||||
],
|
||||
),
|
||||
Category(
|
||||
name: "Category 1.1.2",
|
||||
content: [
|
||||
Text("Content 1.1.2"),
|
||||
Text("Content 1.1.2"),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
const Category(
|
||||
name: "Category 1.2",
|
||||
content: [
|
||||
Text("Content 1.2"),
|
||||
Text("Content 1.2"),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
const Category(
|
||||
name: "Category 2",
|
||||
content: [
|
||||
Text("Content 2"),
|
||||
Text("Content 2"),
|
||||
],
|
||||
nestedCategories: [
|
||||
Category(
|
||||
name: "Category 2.1",
|
||||
content: [
|
||||
Text("Content 2.1"),
|
||||
Text("Content 2.2"),
|
||||
],
|
||||
nestedCategories: [
|
||||
Category(
|
||||
name: "Category 2.1.1",
|
||||
content: [
|
||||
Text("Content 2.1.1"),
|
||||
Text("Content 2.1.2"),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
33
example/pubspec.yaml
Normal file
33
example/pubspec.yaml
Normal file
|
@ -0,0 +1,33 @@
|
|||
name: flutter_nested_categories_example
|
||||
description: "Demonstrates how to use the flutter_nested_categories package."
|
||||
publish_to: 'none'
|
||||
|
||||
environment:
|
||||
sdk: '>=3.3.0 <4.0.0'
|
||||
|
||||
dependencies:
|
||||
flutter:
|
||||
sdk: flutter
|
||||
flutter_hooks: ^0.20.0
|
||||
flutter_nested_categories:
|
||||
path: ../
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
sdk: flutter
|
||||
flutter_iconica_analysis:
|
||||
git:
|
||||
url: https://github.com/Iconica-Development/flutter_iconica_analysis
|
||||
ref: 7.0.0
|
||||
|
||||
flutter:
|
||||
uses-material-design: true
|
||||
# assets:
|
||||
# - images/a_dot_burr.jpeg
|
||||
# - images/a_dot_ham.jpeg
|
||||
# fonts:
|
||||
# - family: Schyler
|
||||
# fonts:
|
||||
# - asset: fonts/Schyler-Regular.ttf
|
||||
# - asset: fonts/Schyler-Italic.ttf
|
||||
# style: italic
|
10
lib/flutter_nested_categories.dart
Normal file
10
lib/flutter_nested_categories.dart
Normal file
|
@ -0,0 +1,10 @@
|
|||
/// Flutter Nested Categories
|
||||
///
|
||||
/// A Flutter package that allows you to create nested categories that
|
||||
/// are very easy to use and customize.
|
||||
library flutter_nested_categories;
|
||||
|
||||
export "src/category.dart";
|
||||
export "src/category_header_capitalization.dart";
|
||||
export "src/category_header_styling.dart";
|
||||
export "src/category_list.dart";
|
49
lib/src/category.dart
Normal file
49
lib/src/category.dart
Normal file
|
@ -0,0 +1,49 @@
|
|||
import "package:flutter/widgets.dart";
|
||||
|
||||
/// One of the categories in the list. Each category can contain content,
|
||||
/// which can be an empty list, but also nested categories. The nested
|
||||
/// categories are the same type as the parent category which allows for
|
||||
/// infinite nesting.
|
||||
class Category {
|
||||
/// Creates a category.
|
||||
///
|
||||
/// The [name] is the name of the category. This will be displayed at the
|
||||
/// top of the category. If the [customTitle] is set, this will be ignored.
|
||||
/// Inside of the [content] you can put any widget you want. This will be
|
||||
/// displayed after the title of the category. If the category has nested
|
||||
/// categories, the content will be displayed before the nested categories.
|
||||
/// The [nestedCategories] are the nested categories of this category. This
|
||||
/// can be an empty list if there are no nested categories.
|
||||
const Category({
|
||||
this.name,
|
||||
this.customTitle,
|
||||
this.content = const <Widget>[],
|
||||
this.nestedCategories = const <Category>[],
|
||||
}) : assert(
|
||||
name != null || customTitle != null,
|
||||
"A name or a custom title must be set",
|
||||
);
|
||||
|
||||
/// The name of the category.
|
||||
final String? name;
|
||||
|
||||
/// Optional custom title widget for the category. This will be displayed
|
||||
/// at the top of the category. If set, the text title will be ignored.
|
||||
/// This will be displayed before the content of the category.
|
||||
final Widget? customTitle;
|
||||
|
||||
/// The content of the category. This can be anything, but is usually
|
||||
/// a list of widgets.
|
||||
///
|
||||
/// Default is an empty list.
|
||||
///
|
||||
/// If the category has nested categories, it will show this content
|
||||
/// before the nested categories.
|
||||
final List<Category> nestedCategories;
|
||||
|
||||
/// The nested categories of this category. This can be an empty list
|
||||
/// if there are no nested categories.
|
||||
///
|
||||
/// Default is an empty list.
|
||||
final List<Widget> content;
|
||||
}
|
16
lib/src/category_header_capitalization.dart
Normal file
16
lib/src/category_header_capitalization.dart
Normal file
|
@ -0,0 +1,16 @@
|
|||
/// An enum that represents the capitalization of the category header.
|
||||
/// This is used to determine how the header should be displayed.
|
||||
/// The header is the name of the category.
|
||||
enum CategoryHeaderCapitalization {
|
||||
/// The first letter of the header will be capitalized.
|
||||
capitalizeFirstLetter,
|
||||
|
||||
/// The header will be displayed in all lowercase.
|
||||
lowercase,
|
||||
|
||||
/// The header will be displayed in all uppercase.
|
||||
uppercase,
|
||||
|
||||
/// The header will be displayed as is.
|
||||
none,
|
||||
}
|
32
lib/src/category_header_styling.dart
Normal file
32
lib/src/category_header_styling.dart
Normal file
|
@ -0,0 +1,32 @@
|
|||
import "package:flutter/widgets.dart";
|
||||
import "package:flutter_nested_categories/src/category_header_capitalization.dart";
|
||||
|
||||
/// This class is used to style the headers of the categories in the list.
|
||||
/// The headers are the names of the categories.
|
||||
class CategoryHeaderStyling {
|
||||
/// Creates a category header styling.
|
||||
///
|
||||
/// The [defaultStyle] is the default style for the headers. This will be
|
||||
/// used if the depth is not found in the [headerStyles].
|
||||
///
|
||||
/// The [capitalization] is used to determine how the headers should be
|
||||
/// displayed. This is useful if your data comes out of a database for
|
||||
/// example and you want to display it in a certain way.
|
||||
const CategoryHeaderStyling({
|
||||
required this.defaultStyle,
|
||||
this.capitalization = CategoryHeaderCapitalization.none,
|
||||
this.headerStyles = const {},
|
||||
});
|
||||
|
||||
/// The styles for the headers. The key is the depth of the category.
|
||||
/// The value is the text style for the header.
|
||||
final Map<int, TextStyle?> headerStyles;
|
||||
|
||||
/// The capitalization of the headers. This is used to determine how the
|
||||
/// headers should be displayed.
|
||||
final CategoryHeaderCapitalization capitalization;
|
||||
|
||||
/// The default style for the headers. This will be used if the depth
|
||||
/// is not found in the [headerStyles].
|
||||
final TextStyle defaultStyle;
|
||||
}
|
265
lib/src/category_list.dart
Normal file
265
lib/src/category_list.dart
Normal file
|
@ -0,0 +1,265 @@
|
|||
import "package:flutter/material.dart";
|
||||
import "package:flutter_nested_categories/flutter_nested_categories.dart";
|
||||
|
||||
/// This widget displays a list of categories. Each category can contain
|
||||
/// content, which can be an empty list, but also nested categories. The
|
||||
/// nested categories are the same type as the parent category which allows
|
||||
/// for infinite nesting.
|
||||
///
|
||||
/// The content of the categories is displayed in the order it is given in
|
||||
/// the list. If a category has nested categories, the content of the nested
|
||||
/// categories is displayed after the content of the parent category.
|
||||
class CategoryList extends StatelessWidget {
|
||||
/// Creates a category list.
|
||||
///
|
||||
/// This Widget allows you to create nested categories. Each category can
|
||||
/// contain content, which can be an empty list, but also nested categories.
|
||||
/// The nested categories are the same type as the parent category which
|
||||
/// allows for infinite nesting.
|
||||
const CategoryList({
|
||||
required this.content,
|
||||
this.headerStyling,
|
||||
this.headerCentered = false,
|
||||
this.customTitle,
|
||||
this.title,
|
||||
this.titleStyle,
|
||||
this.titleCentered = false,
|
||||
this.isCategoryCollapsible = true,
|
||||
this.categoryDepth = 0,
|
||||
super.key,
|
||||
});
|
||||
|
||||
/// Optional title for the category list. This will be displayed at the
|
||||
/// top of the list.
|
||||
final String? title;
|
||||
|
||||
/// Optional custom title widget for the category list. This will be
|
||||
/// displayed at the top of the list. If set, the text title will be
|
||||
/// ignored.
|
||||
final Widget? customTitle;
|
||||
|
||||
/// Optional title style for the title of the category list. This will
|
||||
/// be applied to the title of the category list. If not set, the default
|
||||
/// text style will be used.
|
||||
final TextStyle? titleStyle;
|
||||
|
||||
/// Configure if the title should be centered.
|
||||
///
|
||||
/// Default is false.
|
||||
final bool titleCentered;
|
||||
|
||||
/// Optional header styling for the categories. This will be applied to
|
||||
/// the name of the categories. If not set, the default text style will
|
||||
/// be used.
|
||||
final CategoryHeaderStyling? headerStyling;
|
||||
|
||||
/// Configure if the category header should be centered.
|
||||
///
|
||||
/// Default is false.
|
||||
final bool headerCentered;
|
||||
|
||||
/// Configure if the category should be collapsible.
|
||||
///
|
||||
/// Default is true.
|
||||
final bool isCategoryCollapsible;
|
||||
|
||||
/// The depth of the category list. This is used to keep track of
|
||||
/// the depth of the categories. This is used internally and should
|
||||
/// not be set manually.
|
||||
final int categoryDepth;
|
||||
|
||||
/// The content of the category list. This is a list of categories.
|
||||
final List<Category> content;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => SingleChildScrollView(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
if (title != null || customTitle != null)
|
||||
titleCentered
|
||||
? Center(
|
||||
child: _CategoryTitle(
|
||||
title: title,
|
||||
titleStyle: titleStyle,
|
||||
customTitle: customTitle,
|
||||
),
|
||||
)
|
||||
: _CategoryTitle(
|
||||
title: title,
|
||||
titleStyle: titleStyle,
|
||||
customTitle: customTitle,
|
||||
),
|
||||
...content.map(
|
||||
(category) => _CategoryColumn(
|
||||
category: category,
|
||||
headerCentered: headerCentered,
|
||||
headerStyling: headerStyling,
|
||||
collapsible: isCategoryCollapsible,
|
||||
categoryDepth: categoryDepth,
|
||||
),
|
||||
),
|
||||
].toList(),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
class _CategoryTitle extends StatelessWidget {
|
||||
const _CategoryTitle({
|
||||
this.customTitle,
|
||||
this.title,
|
||||
this.titleStyle,
|
||||
}) : assert(
|
||||
customTitle != null || title != null,
|
||||
"Either customTitle or title must be set.",
|
||||
);
|
||||
|
||||
final String? title;
|
||||
final Widget? customTitle;
|
||||
final TextStyle? titleStyle;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
var theme = Theme.of(context);
|
||||
var styleOfTitle = titleStyle ?? theme.textTheme.titleLarge;
|
||||
|
||||
return customTitle ??
|
||||
Text(
|
||||
title!,
|
||||
style: styleOfTitle,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _CategoryColumn extends StatefulWidget {
|
||||
const _CategoryColumn({
|
||||
required this.category,
|
||||
required this.categoryDepth,
|
||||
required this.headerCentered,
|
||||
this.headerStyling,
|
||||
this.collapsible = true,
|
||||
});
|
||||
|
||||
final Category category;
|
||||
final CategoryHeaderStyling? headerStyling;
|
||||
final bool headerCentered;
|
||||
final int categoryDepth;
|
||||
final bool collapsible;
|
||||
|
||||
@override
|
||||
State<_CategoryColumn> createState() => _CategoryColumnState();
|
||||
}
|
||||
|
||||
class _CategoryColumnState extends State<_CategoryColumn> {
|
||||
bool _isExpanded = true;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
var theme = Theme.of(context);
|
||||
|
||||
var styleOfCategory =
|
||||
widget.headerStyling?.headerStyles[widget.categoryDepth] ??
|
||||
widget.headerStyling?.defaultStyle ??
|
||||
theme.textTheme.titleMedium ??
|
||||
const TextStyle();
|
||||
|
||||
String? formatCategoryName() {
|
||||
var name = widget.category.name;
|
||||
if (name == null) return null;
|
||||
|
||||
return switch (widget.headerStyling?.capitalization) {
|
||||
CategoryHeaderCapitalization.capitalizeFirstLetter =>
|
||||
name[0].toUpperCase() + name.substring(1),
|
||||
CategoryHeaderCapitalization.lowercase => name.toLowerCase(),
|
||||
CategoryHeaderCapitalization.uppercase => name.toUpperCase(),
|
||||
CategoryHeaderCapitalization.none => name,
|
||||
_ => name,
|
||||
};
|
||||
}
|
||||
|
||||
Widget buildCollapsibleHeader(TextStyle styleOfCategory) => InkWell(
|
||||
onTap: () {
|
||||
setState(() {
|
||||
_isExpanded = !_isExpanded;
|
||||
});
|
||||
},
|
||||
child: Row(
|
||||
mainAxisAlignment: widget.headerCentered
|
||||
? MainAxisAlignment.center
|
||||
: MainAxisAlignment.start,
|
||||
children: [
|
||||
ExpandIcon(
|
||||
onPressed: (value) => setState(() {
|
||||
_isExpanded = !_isExpanded;
|
||||
}),
|
||||
isExpanded: _isExpanded,
|
||||
padding: EdgeInsets.zero,
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
if (widget.category.customTitle != null)
|
||||
widget.category.customTitle!
|
||||
else
|
||||
Text(
|
||||
formatCategoryName()!,
|
||||
style: styleOfCategory,
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
Widget buildNonCollapsibleHeader(TextStyle styleOfCategory) =>
|
||||
widget.headerCentered
|
||||
? Center(
|
||||
child: widget.category.customTitle != null
|
||||
? widget.category.customTitle!
|
||||
: Text(
|
||||
formatCategoryName()!,
|
||||
style: styleOfCategory,
|
||||
),
|
||||
)
|
||||
: widget.category.customTitle != null
|
||||
? widget.category.customTitle!
|
||||
: Text(
|
||||
formatCategoryName()!,
|
||||
style: styleOfCategory,
|
||||
);
|
||||
|
||||
Widget buildNestedCategoryList() => CategoryList(
|
||||
content: widget.category.nestedCategories,
|
||||
headerCentered: widget.headerCentered,
|
||||
headerStyling: widget.headerStyling,
|
||||
isCategoryCollapsible: widget.collapsible,
|
||||
categoryDepth: widget.categoryDepth + 1,
|
||||
);
|
||||
|
||||
return SizedBox(
|
||||
width: double.infinity,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
if (widget.collapsible) ...[
|
||||
buildCollapsibleHeader(styleOfCategory),
|
||||
] else ...[
|
||||
buildNonCollapsibleHeader(styleOfCategory),
|
||||
],
|
||||
AnimatedCrossFade(
|
||||
duration: const Duration(milliseconds: 300),
|
||||
firstChild: const SizedBox(width: double.infinity),
|
||||
secondChild: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
if (widget.category.content.isNotEmpty)
|
||||
...widget.category.content,
|
||||
if (widget.category.nestedCategories.isNotEmpty)
|
||||
buildNestedCategoryList(),
|
||||
],
|
||||
),
|
||||
crossFadeState: _isExpanded
|
||||
? CrossFadeState.showSecond
|
||||
: CrossFadeState.showFirst,
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue