adding packages
This commit is contained in:
@@ -0,0 +1,4 @@
|
||||
export 'master_detail_controller/controller.dart';
|
||||
export 'table_view_controller/cell.dart';
|
||||
export 'table_view_controller/controller.dart';
|
||||
export 'widgets/search.dart';
|
||||
@@ -0,0 +1,138 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
typedef ItemWidgetBuilder = Widget Function(
|
||||
BuildContext context, dynamic item, bool tablet);
|
||||
typedef IndexedWidgetBuilder = Widget Function(BuildContext context, int index);
|
||||
|
||||
class CupertinoMasterDetailController extends StatelessWidget {
|
||||
final ItemWidgetBuilder detailBuilder;
|
||||
final IndexedWidgetBuilder itemBuilder;
|
||||
final Widget? onNull, onEmpty;
|
||||
final PreferredSizeWidget? appBar;
|
||||
final dynamic selectedItem;
|
||||
final ValueChanged<dynamic> itemSelected;
|
||||
final List<dynamic> items;
|
||||
|
||||
CupertinoMasterDetailController({
|
||||
required this.detailBuilder,
|
||||
required this.selectedItem,
|
||||
required this.itemSelected,
|
||||
required this.itemBuilder,
|
||||
required this.items,
|
||||
this.appBar,
|
||||
this.onNull,
|
||||
this.onEmpty,
|
||||
});
|
||||
|
||||
Widget _buildMobileLayout(BuildContext context) {
|
||||
return Scaffold(
|
||||
body: CupertinoPageScaffold(
|
||||
child: CustomScrollView(
|
||||
semanticChildCount: items.length,
|
||||
slivers: <Widget>[
|
||||
CupertinoSliverNavigationBar(
|
||||
largeTitle: Text("Presidents"),
|
||||
),
|
||||
_ItemListing(
|
||||
onEmpty: onEmpty,
|
||||
onNull: onNull,
|
||||
itemBuilder: itemBuilder,
|
||||
items: items,
|
||||
selectedItem: selectedItem,
|
||||
itemSelectedCallback: (item) {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) => detailBuilder(context, item, false)),
|
||||
);
|
||||
},
|
||||
),
|
||||
])));
|
||||
}
|
||||
|
||||
Widget _buildTabletLayout(BuildContext context) {
|
||||
return OrientationBuilder(builder: (context, orientation) {
|
||||
return Row(
|
||||
children: <Widget>[
|
||||
Flexible(
|
||||
flex: orientation == Orientation.landscape ? 1 : 2,
|
||||
child: Scaffold(
|
||||
appBar: appBar,
|
||||
body: CustomScrollView(slivers: [
|
||||
_ItemListing(
|
||||
onEmpty: onEmpty,
|
||||
onNull: onNull,
|
||||
itemBuilder: itemBuilder,
|
||||
items: items,
|
||||
selectedItem: selectedItem,
|
||||
itemSelectedCallback: itemSelected,
|
||||
),
|
||||
])),
|
||||
),
|
||||
Container(
|
||||
width: 1.0,
|
||||
color: Colors.grey[300],
|
||||
),
|
||||
Flexible(
|
||||
flex: 3,
|
||||
child: detailBuilder(context, selectedItem, true),
|
||||
),
|
||||
],
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
var shortestSide = MediaQuery.of(context).size.shortestSide;
|
||||
final bool useMobileLayout = shortestSide < 600;
|
||||
|
||||
if (useMobileLayout) {
|
||||
return _buildMobileLayout(context);
|
||||
}
|
||||
|
||||
return _buildTabletLayout(context);
|
||||
}
|
||||
}
|
||||
|
||||
class _ItemListing extends StatelessWidget {
|
||||
_ItemListing({
|
||||
required this.itemSelectedCallback,
|
||||
this.selectedItem,
|
||||
this.itemBuilder,
|
||||
this.items,
|
||||
this.onNull,
|
||||
this.onEmpty,
|
||||
});
|
||||
|
||||
final ValueChanged<dynamic> itemSelectedCallback;
|
||||
final dynamic selectedItem;
|
||||
final IndexedWidgetBuilder? itemBuilder;
|
||||
final List<dynamic>? items;
|
||||
final Widget? onNull, onEmpty;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
if (items == null) {
|
||||
return onNull ?? Center(child: CircularProgressIndicator());
|
||||
}
|
||||
|
||||
if (items!.isEmpty) {
|
||||
return onEmpty ?? Center(child: Text("No Items Found"));
|
||||
}
|
||||
|
||||
return SliverList(
|
||||
delegate: SliverChildBuilderDelegate(
|
||||
(BuildContext context, int index) {
|
||||
final _child = itemBuilder!(context, index);
|
||||
return GestureDetector(
|
||||
onTap: () => itemSelectedCallback(items![index]),
|
||||
child: _child,
|
||||
);
|
||||
},
|
||||
childCount: items!.length,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,337 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_slidable/flutter_slidable.dart' as slidable;
|
||||
|
||||
import 'templates/avatar_tile.dart';
|
||||
import 'templates/base_tile.dart';
|
||||
import 'templates/basic_tile.dart';
|
||||
import 'templates/phone_tile.dart';
|
||||
|
||||
class CupertinoTableCell extends StatelessWidget {
|
||||
final bool selected;
|
||||
final bool editing;
|
||||
final bool canEdit;
|
||||
final bool canDelete;
|
||||
final bool lastItem;
|
||||
final Widget? child;
|
||||
final String id;
|
||||
final VoidCallback? onDelete, onTap;
|
||||
final List<slidable.IconSlideAction>? leadingActions, trailingActions;
|
||||
final ValueChanged<bool>? onSelected;
|
||||
|
||||
// -- Styling --
|
||||
final CupertinoAccessory accessory;
|
||||
final VoidCallback? accessoryTap;
|
||||
final CupertinoEditingAction editingAction;
|
||||
final CupertinoEditingAccessory editingAccessory;
|
||||
final VoidCallback? editingAccessoryTap;
|
||||
|
||||
const CupertinoTableCell({
|
||||
Key? key,
|
||||
this.selected = false,
|
||||
this.canEdit = true,
|
||||
this.canDelete = true,
|
||||
this.editing = false,
|
||||
this.lastItem = false,
|
||||
this.trailingActions,
|
||||
this.leadingActions,
|
||||
this.onTap,
|
||||
this.child,
|
||||
required this.id,
|
||||
this.onDelete,
|
||||
this.onSelected,
|
||||
this.accessory = CupertinoAccessory.disclosureIndicator,
|
||||
this.accessoryTap,
|
||||
this.editingAccessoryTap,
|
||||
this.editingAccessory = CupertinoEditingAccessory.none,
|
||||
this.editingAction = CupertinoEditingAction.select,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
Widget _child;
|
||||
// CupertinoListTile _item = cell?.data as CupertinoListTile;
|
||||
|
||||
final CupertinoListTileData _ios = CupertinoListTileData(
|
||||
hideLeadingIcon: true,
|
||||
style: CupertinoCellStyle.custom,
|
||||
accessory: accessory,
|
||||
editingAction: editingAction,
|
||||
editingAccessory: editingAccessory,
|
||||
padding: null,
|
||||
editingAccessoryTap: editingAccessoryTap,
|
||||
accessoryTap: accessoryTap,
|
||||
editingActionTap: () {
|
||||
switch (editingAction) {
|
||||
case CupertinoEditingAction.remove:
|
||||
onDelete!();
|
||||
break;
|
||||
case CupertinoEditingAction.select:
|
||||
onSelected!(!selected);
|
||||
break;
|
||||
default:
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
switch (editingAction) {
|
||||
case CupertinoEditingAction.select:
|
||||
_child = GestureDetector(
|
||||
onTapDown: (TapDownDetails details) {
|
||||
if (!editing) {
|
||||
print("On Tap Down..");
|
||||
onSelected!(true);
|
||||
}
|
||||
},
|
||||
onTapCancel: () {
|
||||
if (!editing) {
|
||||
print("On Tap Cancel..");
|
||||
onSelected!(false);
|
||||
}
|
||||
},
|
||||
child: CupertinoListTile(
|
||||
editing: editing,
|
||||
selected: selected,
|
||||
child: child,
|
||||
ios: _ios,
|
||||
lastItem: lastItem,
|
||||
onTap: () {
|
||||
if (!editing) {
|
||||
onSelected!(false);
|
||||
onTap!();
|
||||
} else {
|
||||
print("On Tap Down..");
|
||||
onSelected!(!selected);
|
||||
}
|
||||
},
|
||||
),
|
||||
);
|
||||
break;
|
||||
case CupertinoEditingAction.remove:
|
||||
_child = GestureDetector(
|
||||
onTapDown: (TapDownDetails details) {
|
||||
if (!editing) {
|
||||
onSelected!(true);
|
||||
}
|
||||
},
|
||||
onTapCancel: () {
|
||||
if (!editing) {
|
||||
onSelected!(false);
|
||||
}
|
||||
},
|
||||
child: CupertinoListTile(
|
||||
editing: editing,
|
||||
selected: selected,
|
||||
child: child,
|
||||
ios: _ios,
|
||||
lastItem: lastItem,
|
||||
onTap: () {
|
||||
if (!editing) {
|
||||
print("Item Tapped...");
|
||||
onSelected!(false);
|
||||
onTap!();
|
||||
}
|
||||
},
|
||||
),
|
||||
);
|
||||
break;
|
||||
default:
|
||||
_child = CupertinoListTile(
|
||||
editing: editing,
|
||||
selected: selected,
|
||||
child: child,
|
||||
ios: _ios,
|
||||
lastItem: lastItem,
|
||||
onTap: () {
|
||||
if (!editing) {
|
||||
print("Item Tapped...");
|
||||
onSelected!(false);
|
||||
onTap!();
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
final List<Widget> _trailingActions = <Widget>[];
|
||||
|
||||
if (trailingActions != null) {
|
||||
_trailingActions..addAll(trailingActions!);
|
||||
}
|
||||
|
||||
_trailingActions.add(
|
||||
slidable.IconSlideAction(
|
||||
caption: 'Delete',
|
||||
color: Colors.red,
|
||||
icon: Icons.delete,
|
||||
onTap: onDelete!,
|
||||
),
|
||||
);
|
||||
|
||||
return slidable.Slidable(
|
||||
key: key,
|
||||
actionPane: slidable.SlidableDrawerActionPane(),
|
||||
actionExtentRatio: 0.25,
|
||||
child: _child,
|
||||
actions: leadingActions,
|
||||
secondaryActions: _trailingActions,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class CupertinoListTile extends StatelessWidget {
|
||||
final Text? subtitle, title, id;
|
||||
final Widget? avatar, child;
|
||||
final List<Widget>? trailing;
|
||||
final IconData? leading;
|
||||
final CupertinoListTileData? ios;
|
||||
final VoidCallback? onTap, onLongPressed;
|
||||
final bool selected, editing;
|
||||
final bool lastItem;
|
||||
|
||||
CupertinoListTile({
|
||||
this.title,
|
||||
this.id,
|
||||
this.subtitle,
|
||||
this.leading,
|
||||
this.trailing,
|
||||
this.avatar,
|
||||
this.onTap,
|
||||
this.onLongPressed,
|
||||
this.ios,
|
||||
this.child,
|
||||
this.lastItem = true,
|
||||
this.selected = false,
|
||||
this.editing = false,
|
||||
});
|
||||
// : assert(ios?.style == CupertinoCellStyle.custom && child != null);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
Widget _child = Container();
|
||||
|
||||
switch (ios?.style ?? CupertinoCellStyle.custom) {
|
||||
case CupertinoCellStyle.avatarDetail:
|
||||
_child = CupertinoAvatarListTile(
|
||||
avatar: avatar,
|
||||
title: title?.data,
|
||||
subtitle: subtitle?.data,
|
||||
actions: trailing,
|
||||
);
|
||||
break;
|
||||
case CupertinoCellStyle.subtitle:
|
||||
_child = CupertinoPhoneListTile(
|
||||
title: title?.data,
|
||||
subtitle: subtitle?.data,
|
||||
actions: trailing,
|
||||
icon: leading,
|
||||
hideLeadingIcon: ios?.hideLeadingIcon,
|
||||
);
|
||||
break;
|
||||
case CupertinoCellStyle.basic:
|
||||
_child = CupertinoTextMenu(
|
||||
children: <Widget?>[title]..addAll(trailing ?? []),
|
||||
);
|
||||
break;
|
||||
|
||||
case CupertinoCellStyle.leftDetail:
|
||||
_child = Row(
|
||||
children: <Widget>[
|
||||
...[subtitle ?? Container()],
|
||||
...[title ?? Container()],
|
||||
],
|
||||
);
|
||||
break;
|
||||
case CupertinoCellStyle.rightDetail:
|
||||
_child = CupertinoTextMenu(
|
||||
children: <Widget?>[title, subtitle],
|
||||
);
|
||||
break;
|
||||
case CupertinoCellStyle.custom:
|
||||
_child = child ?? Container();
|
||||
break;
|
||||
}
|
||||
|
||||
final Widget _row = CupertinoBaseTile(
|
||||
selected: selected,
|
||||
onTap: onTap,
|
||||
onLongPressed: onLongPressed,
|
||||
accessory: ios?.accessory,
|
||||
editing: editing,
|
||||
editingAccessory: ios?.editingAccessory,
|
||||
editingAction: ios?.editingAction,
|
||||
accessoryTap: ios?.accessoryTap,
|
||||
editingAccessoryTap: ios?.editingAccessoryTap,
|
||||
editingActionTap: ios?.editingActionTap,
|
||||
child: _child,
|
||||
padding: ios?.padding,
|
||||
);
|
||||
|
||||
if (lastItem) {
|
||||
return _row;
|
||||
}
|
||||
|
||||
return Column(
|
||||
children: <Widget>[
|
||||
_row,
|
||||
Container(
|
||||
height: 1.0,
|
||||
color: const Color(0xFFD9D9D9),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class CupertinoListTileData {
|
||||
final CupertinoCellStyle style;
|
||||
final CupertinoEditingAction editingAction;
|
||||
final CupertinoEditingAccessory editingAccessory;
|
||||
final CupertinoAccessory accessory;
|
||||
final VoidCallback? accessoryTap, editingAccessoryTap, editingActionTap;
|
||||
final bool hideLeadingIcon, enableReorder;
|
||||
final EdgeInsets? padding;
|
||||
|
||||
CupertinoListTileData({
|
||||
this.style = CupertinoCellStyle.custom,
|
||||
this.accessory = CupertinoAccessory.none,
|
||||
this.editingAccessory = CupertinoEditingAccessory.none,
|
||||
this.editingAction = CupertinoEditingAction.remove,
|
||||
this.accessoryTap,
|
||||
this.hideLeadingIcon = false,
|
||||
this.enableReorder = true,
|
||||
this.editingAccessoryTap,
|
||||
this.editingActionTap,
|
||||
this.padding = const EdgeInsets.only(left: 8.0, bottom: 8.0, top: 8.0),
|
||||
});
|
||||
}
|
||||
|
||||
enum CupertinoCellStyle {
|
||||
basic,
|
||||
rightDetail,
|
||||
leftDetail,
|
||||
subtitle,
|
||||
avatarDetail,
|
||||
custom,
|
||||
}
|
||||
|
||||
enum CupertinoEditingAction {
|
||||
none,
|
||||
remove,
|
||||
select,
|
||||
}
|
||||
|
||||
enum CupertinoAccessory {
|
||||
none,
|
||||
disclosureIndicator,
|
||||
detailDisclosure,
|
||||
checkmark,
|
||||
detail
|
||||
}
|
||||
|
||||
enum CupertinoEditingAccessory {
|
||||
none,
|
||||
disclosureIndicator,
|
||||
detailDisclosure,
|
||||
checkmark,
|
||||
detail,
|
||||
dragHandle
|
||||
}
|
||||
@@ -0,0 +1,220 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_sticky_header/flutter_sticky_header.dart';
|
||||
|
||||
typedef RefreshCallback = Future<void> Function();
|
||||
|
||||
class CupertinoTableViewController extends StatelessWidget {
|
||||
final String? title, previousTitle;
|
||||
final Widget? leading, trailing;
|
||||
final ValueChanged<bool>? onEditing;
|
||||
final RefreshCallback? onRefresh;
|
||||
final bool showEditingButtonLeft, showEditingButtonRight, hideAppBarOnSearch;
|
||||
final bool isEditing, isSearching;
|
||||
final List<CupertinoTableViewSection> sections;
|
||||
final List<Widget>? widgets, toolbarButtons;
|
||||
|
||||
CupertinoTableViewController({
|
||||
this.previousTitle,
|
||||
this.title,
|
||||
this.trailing,
|
||||
this.leading,
|
||||
this.onRefresh,
|
||||
this.hideAppBarOnSearch = false,
|
||||
this.isSearching = false,
|
||||
this.isEditing = false,
|
||||
this.onEditing,
|
||||
List<Widget> children = const <Widget>[],
|
||||
this.widgets,
|
||||
this.showEditingButtonLeft = true,
|
||||
this.showEditingButtonRight = false,
|
||||
this.toolbarButtons,
|
||||
}) : sections = [CupertinoTableViewSection(children: children)],
|
||||
assert(showEditingButtonLeft != showEditingButtonRight);
|
||||
|
||||
CupertinoTableViewController.builder({
|
||||
// this.item,
|
||||
|
||||
this.previousTitle,
|
||||
this.title,
|
||||
this.trailing,
|
||||
this.leading,
|
||||
this.onRefresh,
|
||||
this.hideAppBarOnSearch = false,
|
||||
this.isSearching = false,
|
||||
this.isEditing = false,
|
||||
this.onEditing,
|
||||
required IndexedWidgetBuilder itemBuilder,
|
||||
int? itemCount,
|
||||
this.widgets,
|
||||
this.showEditingButtonLeft = true,
|
||||
this.showEditingButtonRight = false,
|
||||
this.toolbarButtons,
|
||||
}) : sections = [
|
||||
CupertinoTableViewSection.builder(
|
||||
itemBuilder: itemBuilder,
|
||||
itemCount: itemCount,
|
||||
)
|
||||
],
|
||||
assert(showEditingButtonLeft != showEditingButtonRight);
|
||||
|
||||
const CupertinoTableViewController.sectioned({
|
||||
this.previousTitle,
|
||||
this.title,
|
||||
this.trailing,
|
||||
this.hideAppBarOnSearch = false,
|
||||
this.leading,
|
||||
this.onRefresh,
|
||||
this.isSearching = false,
|
||||
this.isEditing = false,
|
||||
this.onEditing,
|
||||
this.showEditingButtonLeft = true,
|
||||
this.showEditingButtonRight = false,
|
||||
this.toolbarButtons,
|
||||
required this.sections,
|
||||
this.widgets,
|
||||
}) : assert(showEditingButtonLeft != showEditingButtonRight);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final _editingButton = Container(
|
||||
padding: EdgeInsets.only(top: 10.0),
|
||||
child: CupertinoTableViewEditingButton(
|
||||
isEditing: isEditing,
|
||||
onPressed: () => onEditing!(!isEditing),
|
||||
),
|
||||
);
|
||||
|
||||
final _searchNavBar = <Widget>[];
|
||||
|
||||
if (!isSearching && hideAppBarOnSearch) {
|
||||
_searchNavBar.addAll([
|
||||
CupertinoSliverNavigationBar(
|
||||
// heroTag: title ?? "Title",
|
||||
// transitionBetweenRoutes: false,
|
||||
largeTitle: Text(title ?? "Title"),
|
||||
// We're specifying a back label here because the previous page
|
||||
// is a Material page. CupertinoPageRoutes could auto-populate
|
||||
// these back labels.
|
||||
previousPageTitle: previousTitle ?? "",
|
||||
leading: showEditingButtonLeft ? _editingButton : leading,
|
||||
trailing: showEditingButtonRight ? _editingButton : trailing,
|
||||
),
|
||||
CupertinoSliverRefreshControl(onRefresh: onRefresh),
|
||||
]);
|
||||
}
|
||||
|
||||
final _widgets = <Widget>[];
|
||||
|
||||
if (widgets != null) {
|
||||
for (Widget _widget in widgets!) {
|
||||
_widgets.add(SliverToBoxAdapter(child: _widget));
|
||||
}
|
||||
}
|
||||
|
||||
final _sections = <Widget>[];
|
||||
|
||||
int _index = 0;
|
||||
for (CupertinoTableViewSection _section in sections) {
|
||||
_sections.add(new SliverStickyHeader(
|
||||
header: _section.header == null
|
||||
? null
|
||||
: new Container(
|
||||
color: CupertinoColors.lightBackgroundGray,
|
||||
padding:
|
||||
const EdgeInsets.symmetric(horizontal: 16.0, vertical: 5.0),
|
||||
alignment: Alignment.centerLeft,
|
||||
child: _section.header,
|
||||
),
|
||||
sliver: SliverSafeArea(
|
||||
top: false,
|
||||
bottom: sections.length == _index + 1,
|
||||
sliver: SliverList(
|
||||
delegate: _section.childrenDelegate,
|
||||
),
|
||||
),
|
||||
));
|
||||
_index++;
|
||||
}
|
||||
|
||||
return DefaultTextStyle(
|
||||
style: Theme.of(context).textTheme.title!,
|
||||
child: Scaffold(
|
||||
body: CustomScrollView(
|
||||
primary: true,
|
||||
slivers: [
|
||||
..._searchNavBar,
|
||||
..._widgets,
|
||||
..._sections,
|
||||
],
|
||||
),
|
||||
persistentFooterButtons: toolbarButtons,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class CupertinoTableViewEditingButton extends StatelessWidget {
|
||||
final bool? isEditing;
|
||||
final VoidCallback? onPressed;
|
||||
|
||||
const CupertinoTableViewEditingButton({
|
||||
this.isEditing,
|
||||
this.onPressed,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
if (isEditing!) {
|
||||
return GestureDetector(
|
||||
onTap: onPressed,
|
||||
child: const Text("Cancel",
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
color: CupertinoColors.activeBlue,
|
||||
)),
|
||||
);
|
||||
}
|
||||
return GestureDetector(
|
||||
onTap: onPressed,
|
||||
child: const Text("Edit",
|
||||
style: TextStyle(
|
||||
color: CupertinoColors.activeBlue,
|
||||
)),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Todo; Seconts for Tableview
|
||||
class CupertinoTableViewSection {
|
||||
final Widget? header;
|
||||
final SliverChildDelegate childrenDelegate;
|
||||
|
||||
CupertinoTableViewSection({
|
||||
this.header,
|
||||
List<Widget> children = const <Widget>[],
|
||||
bool addAutomaticKeepAlives = true,
|
||||
bool addRepaintBoundaries = true,
|
||||
bool addSemanticIndexes = true,
|
||||
}) : childrenDelegate = SliverChildListDelegate(
|
||||
children,
|
||||
addAutomaticKeepAlives: addAutomaticKeepAlives,
|
||||
addRepaintBoundaries: addRepaintBoundaries,
|
||||
addSemanticIndexes: addSemanticIndexes,
|
||||
);
|
||||
|
||||
CupertinoTableViewSection.builder({
|
||||
this.header,
|
||||
required IndexedWidgetBuilder itemBuilder,
|
||||
int? itemCount,
|
||||
bool addAutomaticKeepAlives = true,
|
||||
bool addRepaintBoundaries = true,
|
||||
bool addSemanticIndexes = true,
|
||||
}) : childrenDelegate = SliverChildBuilderDelegate(
|
||||
itemBuilder,
|
||||
childCount: itemCount,
|
||||
addAutomaticKeepAlives: addAutomaticKeepAlives,
|
||||
addRepaintBoundaries: addRepaintBoundaries,
|
||||
addSemanticIndexes: addSemanticIndexes,
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../../widgets/text.dart';
|
||||
|
||||
class CupertinoAvatarListTile extends StatelessWidget {
|
||||
const CupertinoAvatarListTile({
|
||||
required this.title,
|
||||
this.subtitle,
|
||||
this.actions,
|
||||
this.avatar,
|
||||
});
|
||||
|
||||
final Widget? avatar;
|
||||
final String? title, subtitle;
|
||||
final List<Widget>? actions;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final List<Widget> _widgets = <Widget>[
|
||||
Container(
|
||||
height: 60.0,
|
||||
width: 60.0,
|
||||
child: avatar,
|
||||
),
|
||||
Expanded(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 12.0),
|
||||
child: subtitle == null
|
||||
? CupertinoText(title, type: CupertinoTextTheme.title)
|
||||
: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
CupertinoText(title, type: CupertinoTextTheme.title),
|
||||
CupertinoText(subtitle, type: CupertinoTextTheme.subtitle),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
];
|
||||
|
||||
final Widget row = Container(
|
||||
padding: const EdgeInsets.only(left: 8.0),
|
||||
child: Row(
|
||||
children: _widgets..addAll(actions ?? <Widget>[]),
|
||||
),
|
||||
);
|
||||
|
||||
return row;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,206 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../cell.dart';
|
||||
|
||||
class CupertinoBaseTile extends StatelessWidget {
|
||||
const CupertinoBaseTile({
|
||||
this.selected = false,
|
||||
this.editing = false,
|
||||
required this.child,
|
||||
this.accessory = CupertinoAccessory.none,
|
||||
this.editingAccessory = CupertinoEditingAccessory.none,
|
||||
this.editingAction = CupertinoEditingAction.remove,
|
||||
this.accessoryTap,
|
||||
this.onLongPressed,
|
||||
this.onTap,
|
||||
this.editingAccessoryTap,
|
||||
this.editingActionTap,
|
||||
this.padding,
|
||||
});
|
||||
|
||||
final bool editing, selected;
|
||||
final Widget child;
|
||||
final EdgeInsets? padding;
|
||||
final CupertinoEditingAction? editingAction;
|
||||
final CupertinoEditingAccessory? editingAccessory;
|
||||
final CupertinoAccessory? accessory;
|
||||
final VoidCallback? accessoryTap,
|
||||
onTap,
|
||||
onLongPressed,
|
||||
editingAccessoryTap,
|
||||
editingActionTap;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final List<Widget> _widgets = <Widget>[];
|
||||
|
||||
if (editing) {
|
||||
if (editingAccessory != null) {
|
||||
switch (editingAccessory) {
|
||||
case CupertinoEditingAccessory.disclosureIndicator:
|
||||
_widgets
|
||||
..add(
|
||||
const Icon(CupertinoIcons.right_chevron),
|
||||
);
|
||||
break;
|
||||
case CupertinoEditingAccessory.detailDisclosure:
|
||||
_widgets
|
||||
..addAll([
|
||||
IconButton(
|
||||
icon: const Icon(CupertinoIcons.info,
|
||||
color: CupertinoColors.activeBlue),
|
||||
onPressed: editingAccessoryTap,
|
||||
),
|
||||
const Icon(CupertinoIcons.right_chevron),
|
||||
]);
|
||||
break;
|
||||
case CupertinoEditingAccessory.detail:
|
||||
_widgets
|
||||
..add(
|
||||
IconButton(
|
||||
icon: const Icon(CupertinoIcons.info,
|
||||
color: CupertinoColors.activeBlue),
|
||||
onPressed: editingAccessoryTap,
|
||||
),
|
||||
);
|
||||
break;
|
||||
case CupertinoEditingAccessory.checkmark:
|
||||
_widgets
|
||||
..add(
|
||||
const Icon(CupertinoIcons.check_mark),
|
||||
);
|
||||
break;
|
||||
case CupertinoEditingAccessory.dragHandle:
|
||||
_widgets
|
||||
..add(IconButton(
|
||||
icon: const Icon(Icons.dehaze),
|
||||
onPressed: () {},
|
||||
));
|
||||
break;
|
||||
case null:
|
||||
case CupertinoEditingAccessory.none:
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (accessory != null)
|
||||
switch (accessory) {
|
||||
case CupertinoAccessory.disclosureIndicator:
|
||||
_widgets..add(const Icon(CupertinoIcons.right_chevron));
|
||||
break;
|
||||
case CupertinoAccessory.detailDisclosure:
|
||||
_widgets
|
||||
..addAll([
|
||||
IconButton(
|
||||
icon: const Icon(CupertinoIcons.info),
|
||||
onPressed: accessoryTap,
|
||||
),
|
||||
const Icon(CupertinoIcons.right_chevron),
|
||||
]);
|
||||
break;
|
||||
case CupertinoAccessory.detail:
|
||||
_widgets
|
||||
..add(IconButton(
|
||||
icon: const Icon(CupertinoIcons.info),
|
||||
onPressed: accessoryTap,
|
||||
));
|
||||
break;
|
||||
case CupertinoAccessory.checkmark:
|
||||
_widgets..add(const Icon(CupertinoIcons.check_mark));
|
||||
break;
|
||||
case null:
|
||||
case CupertinoAccessory.none:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Widget? _editingAction;
|
||||
|
||||
if (editingAction != null) {
|
||||
switch (editingAction) {
|
||||
case CupertinoEditingAction.remove:
|
||||
_editingAction = Container(
|
||||
height: 25.0,
|
||||
width: 25.0,
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.red,
|
||||
borderRadius: BorderRadius.circular(25.0),
|
||||
),
|
||||
child: GestureDetector(
|
||||
child: Icon(
|
||||
Icons.remove,
|
||||
color: CupertinoColors.white,
|
||||
// size: 18.0,
|
||||
),
|
||||
onTap: editingActionTap,
|
||||
),
|
||||
);
|
||||
break;
|
||||
case CupertinoEditingAction.select:
|
||||
_editingAction = Container(
|
||||
height: 25.0,
|
||||
width: 25.0,
|
||||
decoration: selected
|
||||
? BoxDecoration(
|
||||
color: CupertinoColors.activeBlue,
|
||||
borderRadius: BorderRadius.circular(25.0),
|
||||
)
|
||||
: new BoxDecoration(
|
||||
border: new Border.all(
|
||||
color: CupertinoColors.lightBackgroundGray),
|
||||
shape: BoxShape.circle),
|
||||
child: GestureDetector(
|
||||
child: Icon(
|
||||
CupertinoIcons.check_mark,
|
||||
color: selected ? CupertinoColors.white : Colors.transparent,
|
||||
),
|
||||
onTap: editingActionTap,
|
||||
),
|
||||
);
|
||||
break;
|
||||
case null:
|
||||
case CupertinoEditingAction.none:
|
||||
_editingAction = null;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Color? _rowColor = Colors.transparent;
|
||||
|
||||
if (selected && editing) {
|
||||
_rowColor = Colors.lightBlue[50];
|
||||
}
|
||||
|
||||
if (!editing && selected) {
|
||||
_rowColor = Colors.lightBlue[50];
|
||||
}
|
||||
|
||||
final Widget row = GestureDetector(
|
||||
behavior: HitTestBehavior.opaque,
|
||||
onTap: onTap,
|
||||
onLongPress: onLongPressed,
|
||||
child: SafeArea(
|
||||
top: false,
|
||||
bottom: false,
|
||||
child: Container(
|
||||
color: _rowColor,
|
||||
padding: padding,
|
||||
child: Row(
|
||||
children: <Widget>[
|
||||
Container(
|
||||
padding: editing && _editingAction != null
|
||||
? const EdgeInsets.only(left: 12.0)
|
||||
: null,
|
||||
child: editing ? _editingAction : null,
|
||||
),
|
||||
Expanded(child: child),
|
||||
]..addAll(_widgets),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
return row;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class CupertinoTextMenu extends StatelessWidget {
|
||||
final bool lastItem;
|
||||
final List<Widget?> children;
|
||||
|
||||
CupertinoTextMenu({
|
||||
required this.children,
|
||||
this.lastItem = false,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
decoration: const BoxDecoration(
|
||||
color: Colors.transparent,
|
||||
border: Border(
|
||||
top: BorderSide(color: Color(0xFFBCBBC1), width: 0.0),
|
||||
bottom: BorderSide(color: Color(0xFFBCBBC1), width: 0.0),
|
||||
),
|
||||
),
|
||||
height: 44.0,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16.0),
|
||||
child: SafeArea(
|
||||
top: false,
|
||||
bottom: false,
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: children as List<Widget>,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../../widgets/text.dart';
|
||||
|
||||
class CupertinoPhoneListTile extends StatelessWidget {
|
||||
final String? subtitle, title;
|
||||
final List<Widget>? actions;
|
||||
final IconData? icon;
|
||||
final bool? hideLeadingIcon;
|
||||
|
||||
const CupertinoPhoneListTile({
|
||||
this.actions,
|
||||
this.subtitle,
|
||||
required this.title,
|
||||
this.icon,
|
||||
this.hideLeadingIcon = true,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
Widget row;
|
||||
if (subtitle == null) {
|
||||
row = Container(
|
||||
// color: selected ? Colors.grey[400] : Colors.transparent,
|
||||
height: 40.0,
|
||||
padding: EdgeInsets.only(top: subtitle == null ? 0.0 : 9.0),
|
||||
child: Row(
|
||||
children: <Widget>[
|
||||
Container(
|
||||
width: hideLeadingIcon! ? 12.0 : 38.0,
|
||||
child: icon != null && !hideLeadingIcon!
|
||||
? Align(
|
||||
alignment: Alignment.center,
|
||||
child: Icon(
|
||||
icon,
|
||||
color: CupertinoColors.inactiveGray,
|
||||
size: 18.0,
|
||||
),
|
||||
)
|
||||
: null,
|
||||
),
|
||||
Expanded(
|
||||
child: Container(
|
||||
padding:
|
||||
const EdgeInsets.only(left: 1.0, bottom: 0.0, right: 10.0),
|
||||
child: Row(
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
CupertinoText(title, type: CupertinoTextTheme.title)
|
||||
],
|
||||
),
|
||||
),
|
||||
]..addAll(actions ?? <Widget>[])),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
} else {
|
||||
row = Container(
|
||||
// color: selected ? Colors.grey[400] : Colors.transparent,
|
||||
height: 60.0,
|
||||
padding: const EdgeInsets.only(top: 9.0),
|
||||
child: Row(
|
||||
children: <Widget>[
|
||||
Container(
|
||||
width: hideLeadingIcon! ? 12.0 : 38.0,
|
||||
child: icon != null && !hideLeadingIcon!
|
||||
? Align(
|
||||
alignment: Alignment.topCenter,
|
||||
child: Icon(
|
||||
icon,
|
||||
color: CupertinoColors.inactiveGray,
|
||||
size: 18.0,
|
||||
),
|
||||
)
|
||||
: null,
|
||||
),
|
||||
Expanded(
|
||||
child: Container(
|
||||
padding:
|
||||
const EdgeInsets.only(left: 1.0, bottom: 9.0, right: 10.0),
|
||||
child: Row(
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: <Widget>[
|
||||
CupertinoText(title, type: CupertinoTextTheme.title),
|
||||
CupertinoText(subtitle,
|
||||
type: CupertinoTextTheme.subtitle),
|
||||
],
|
||||
),
|
||||
),
|
||||
]..addAll(actions ?? <Widget>[])),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
return row;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,149 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
|
||||
class CupertinoSearchBar extends AnimatedWidget {
|
||||
const CupertinoSearchBar({
|
||||
Key? key,
|
||||
required this.controller,
|
||||
required this.focusNode,
|
||||
this.onCancel,
|
||||
this.onChanged,
|
||||
this.onSubmitted,
|
||||
this.autoFocus = false,
|
||||
required this.animation,
|
||||
this.onClear,
|
||||
this.enabled = true,
|
||||
this.autoCorrect = true,
|
||||
}) : assert(controller != null),
|
||||
assert(focusNode != null),
|
||||
super(key: key, listenable: animation);
|
||||
|
||||
final TextEditingController controller;
|
||||
final FocusNode focusNode;
|
||||
final ValueChanged<String>? onChanged, onSubmitted;
|
||||
final VoidCallback? onCancel, onClear;
|
||||
final bool autoFocus, enabled, autoCorrect;
|
||||
final Animation<double> animation;
|
||||
|
||||
static final _opacityTween = new Tween(begin: 1.0, end: 0.0);
|
||||
static final _paddingTween = new Tween(begin: 0.0, end: 60.0);
|
||||
static final _kFontSize = 13.0;
|
||||
// static final Key _inputKey = new Key(debugLabel: 'searchBox');
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
// if (!widget.alwaysShowAppBar)
|
||||
// FocusScope.of(context).requestFocus(_searchFocusNode);
|
||||
|
||||
return new Padding(
|
||||
padding: const EdgeInsets.fromLTRB(10.0, 0.0, 20.0, 0.0),
|
||||
child: new Row(
|
||||
children: <Widget>[
|
||||
new Expanded(
|
||||
child: new Container(
|
||||
padding:
|
||||
const EdgeInsets.symmetric(horizontal: 8.0, vertical: 6.0),
|
||||
decoration: new BoxDecoration(
|
||||
color: CupertinoColors.lightBackgroundGray,
|
||||
border:
|
||||
new Border.all(width: 0.0, color: CupertinoColors.white),
|
||||
borderRadius: new BorderRadius.circular(10.0),
|
||||
),
|
||||
child: new Stack(
|
||||
alignment: Alignment.centerLeft,
|
||||
children: <Widget>[
|
||||
new Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
new Padding(
|
||||
padding: const EdgeInsets.fromLTRB(0.0, 0.0, 4.0, 1.0),
|
||||
child: new Icon(
|
||||
CupertinoIcons.search,
|
||||
color: CupertinoColors.inactiveGray,
|
||||
size: _kFontSize + 2.0,
|
||||
),
|
||||
),
|
||||
new Text(
|
||||
'Search',
|
||||
style: new TextStyle(
|
||||
inherit: false,
|
||||
color: CupertinoColors.inactiveGray
|
||||
.withOpacity(_opacityTween.evaluate(animation)),
|
||||
fontSize: _kFontSize,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
new Row(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: <Widget>[
|
||||
new Expanded(
|
||||
child: new Padding(
|
||||
padding: const EdgeInsets.only(left: 20.0),
|
||||
child: enabled
|
||||
? new EditableText(
|
||||
key: Key("Search_Input_Box"),
|
||||
controller: controller,
|
||||
focusNode: focusNode,
|
||||
onChanged: onChanged,
|
||||
autofocus: autoFocus,
|
||||
onSubmitted: onSubmitted,
|
||||
style: new TextStyle(
|
||||
color: CupertinoColors.black,
|
||||
inherit: false,
|
||||
fontSize: _kFontSize,
|
||||
),
|
||||
autocorrect: autoCorrect,
|
||||
cursorColor: CupertinoColors.black,
|
||||
backgroundCursorColor: Colors.grey,
|
||||
)
|
||||
: null,
|
||||
),
|
||||
),
|
||||
new CupertinoButton(
|
||||
minSize: 10.0,
|
||||
padding: const EdgeInsets.all(1.0),
|
||||
borderRadius: new BorderRadius.circular(30.0),
|
||||
color: CupertinoColors.inactiveGray.withOpacity(
|
||||
1.0 - _opacityTween.evaluate(animation),
|
||||
),
|
||||
child: new Icon(
|
||||
Icons.close,
|
||||
size: 8.0,
|
||||
color: CupertinoColors.white,
|
||||
),
|
||||
onPressed: () {
|
||||
if (animation.isDismissed)
|
||||
return;
|
||||
else
|
||||
onClear!();
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
new SizedBox(
|
||||
width: _paddingTween.evaluate(animation),
|
||||
child: new CupertinoButton(
|
||||
padding: const EdgeInsets.only(left: 8.0),
|
||||
onPressed: onCancel,
|
||||
child: new Text(
|
||||
'Cancel',
|
||||
softWrap: false,
|
||||
style: new TextStyle(
|
||||
inherit: false,
|
||||
color: CupertinoColors.activeBlue,
|
||||
fontSize: _kFontSize,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
|
||||
enum CupertinoTextTheme { title, subtitle, detail, custom }
|
||||
|
||||
class CupertinoText extends StatelessWidget {
|
||||
final String? data;
|
||||
final TextStyle? style;
|
||||
final int maxLines;
|
||||
final CupertinoTextTheme type;
|
||||
|
||||
const CupertinoText(
|
||||
this.data, {
|
||||
Key? key,
|
||||
this.style,
|
||||
this.maxLines = 1,
|
||||
this.type = CupertinoTextTheme.detail,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
switch (type) {
|
||||
case CupertinoTextTheme.title:
|
||||
return Text(
|
||||
data!,
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: const TextStyle(
|
||||
fontWeight: FontWeight.w600,
|
||||
letterSpacing: -0.18,
|
||||
),
|
||||
);
|
||||
case CupertinoTextTheme.subtitle:
|
||||
return Text(
|
||||
data!,
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: const TextStyle(
|
||||
fontSize: 15.0,
|
||||
letterSpacing: -0.24,
|
||||
color: CupertinoColors.inactiveGray,
|
||||
),
|
||||
);
|
||||
case CupertinoTextTheme.detail:
|
||||
return Text(
|
||||
data!,
|
||||
style: const TextStyle(
|
||||
color: CupertinoColors.inactiveGray,
|
||||
fontSize: 15.0,
|
||||
letterSpacing: -0.41,
|
||||
),
|
||||
);
|
||||
case CupertinoTextTheme.custom:
|
||||
return Text(
|
||||
data!,
|
||||
style: style ??
|
||||
const TextStyle(
|
||||
color: CupertinoColors.inactiveGray,
|
||||
fontSize: 15.0,
|
||||
letterSpacing: -0.41,
|
||||
),
|
||||
);
|
||||
}
|
||||
return Container();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user