diff --git a/.fvm/fvm_config.json b/.fvm/fvm_config.json index 41959e974..3e7195748 100644 --- a/.fvm/fvm_config.json +++ b/.fvm/fvm_config.json @@ -1,4 +1,4 @@ { - "flutterSdkVersion": "stable", + "flutterSdkVersion": "3.16.9", "flavors": {} -} +} \ No newline at end of file diff --git a/.vscode/git-commit.js b/.vscode/git-commit.js new file mode 100644 index 000000000..54e8861e2 --- /dev/null +++ b/.vscode/git-commit.js @@ -0,0 +1,2 @@ +const { exec } = require('child_process'); +exec('git commit -m "latest_deployment"'); \ No newline at end of file diff --git a/.vscode/git-push.js b/.vscode/git-push.js new file mode 100644 index 000000000..02b693a1a --- /dev/null +++ b/.vscode/git-push.js @@ -0,0 +1,2 @@ +const { exec } = require('child_process'); +exec('git push origin'); \ No newline at end of file diff --git a/.vscode/git-stage.js b/.vscode/git-stage.js new file mode 100644 index 000000000..77bb6e082 --- /dev/null +++ b/.vscode/git-stage.js @@ -0,0 +1,2 @@ +const { exec } = require('child_process'); +exec('git add .'); diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 000000000..1cb16cec3 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,11 @@ +{ + "dart.flutterSdkPath": ".fvm/flutter_sdk", + // Remove .fvm files from search + "search.exclude": { + "**/.fvm": true + }, + // Remove from file watching + "files.watcherExclude": { + "**/.fvm": true + } + } \ No newline at end of file diff --git a/demo/linux/flutter/ephemeral/.plugin_symlinks/url_launcher_linux b/demo/linux/flutter/ephemeral/.plugin_symlinks/url_launcher_linux index e433ea04f..f2fd81190 120000 --- a/demo/linux/flutter/ephemeral/.plugin_symlinks/url_launcher_linux +++ b/demo/linux/flutter/ephemeral/.plugin_symlinks/url_launcher_linux @@ -1 +1 @@ -C:/Users/manek/AppData/Local/Pub/Cache/hosted/pub.dev/url_launcher_linux-3.0.2/ \ No newline at end of file +C:/Users/Administrator/AppData/Local/Pub/Cache/hosted/pub.dev/url_launcher_linux-3.1.1/ \ No newline at end of file diff --git a/example/lib/main.dart b/example/lib/main.dart index 260b5266f..3d974f347 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -13,6 +13,7 @@ class MyApp extends StatelessWidget { return MaterialApp( title: 'PlutoGrid Example', theme: ThemeData( + useMaterial3: false, primarySwatch: Colors.blue, ), home: const PlutoGridExamplePage(), @@ -35,12 +36,12 @@ class _PlutoGridExamplePageState extends State { PlutoColumn( title: 'Id', field: 'id', - type: PlutoColumnType.text(), + type: PlutoColumnType.duration(), ), PlutoColumn( title: 'Name', field: 'name', - type: PlutoColumnType.text(), + type: PlutoColumnType.duration(), ), PlutoColumn( title: 'Age', @@ -95,8 +96,8 @@ class _PlutoGridExamplePageState extends State { final List rows = [ PlutoRow( cells: { - 'id': PlutoCell(value: 'user1'), - 'name': PlutoCell(value: 'Mike'), + 'id': PlutoCell(value: 'user 113'), + 'name': PlutoCell(value: '1111 days'), 'age': PlutoCell(value: 20), 'role': PlutoCell(value: 'Programmer'), 'joined': PlutoCell(value: '2021-01-01'), @@ -106,8 +107,8 @@ class _PlutoGridExamplePageState extends State { ), PlutoRow( cells: { - 'id': PlutoCell(value: 'user2'), - 'name': PlutoCell(value: 'Jack'), + 'id': PlutoCell(value: 'user 212'), + 'name': PlutoCell(value: '210 days'), 'age': PlutoCell(value: 25), 'role': PlutoCell(value: 'Designer'), 'joined': PlutoCell(value: '2021-02-01'), @@ -117,8 +118,8 @@ class _PlutoGridExamplePageState extends State { ), PlutoRow( cells: { - 'id': PlutoCell(value: 'user3'), - 'name': PlutoCell(value: 'Suzi'), + 'id': PlutoCell(value: 'user 312'), + 'name': PlutoCell(value: '2111210 days'), 'age': PlutoCell(value: 40), 'role': PlutoCell(value: 'Owner'), 'joined': PlutoCell(value: '2021-03-01'), diff --git a/example/windows/runner/Runner.rc b/example/windows/runner/Runner.rc index 51812dcd4..e5666e022 100644 --- a/example/windows/runner/Runner.rc +++ b/example/windows/runner/Runner.rc @@ -60,14 +60,14 @@ IDI_APP_ICON ICON "resources\\app_icon.ico" // Version // -#ifdef FLUTTER_BUILD_NUMBER -#define VERSION_AS_NUMBER FLUTTER_BUILD_NUMBER +#if defined(FLUTTER_VERSION_MAJOR) && defined(FLUTTER_VERSION_MINOR) && defined(FLUTTER_VERSION_PATCH) && defined(FLUTTER_VERSION_BUILD) +#define VERSION_AS_NUMBER FLUTTER_VERSION_MAJOR,FLUTTER_VERSION_MINOR,FLUTTER_VERSION_PATCH,FLUTTER_VERSION_BUILD #else -#define VERSION_AS_NUMBER 1,0,0 +#define VERSION_AS_NUMBER 1,0,0,0 #endif -#ifdef FLUTTER_BUILD_NAME -#define VERSION_AS_STRING #FLUTTER_BUILD_NAME +#if defined(FLUTTER_VERSION) +#define VERSION_AS_STRING FLUTTER_VERSION #else #define VERSION_AS_STRING "1.0.0" #endif diff --git a/lib/src/helper/filter_helper.dart b/lib/src/helper/filter_helper.dart index 9a47632ba..2acd4cc1c 100644 --- a/lib/src/helper/filter_helper.dart +++ b/lib/src/helper/filter_helper.dart @@ -3,8 +3,9 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:pluto_grid/pluto_grid.dart'; -typedef SetFilterPopupHandler = void Function( - PlutoGridStateManager? stateManager); +import '../ui/columns/pluto_column_title.dart'; + +typedef SetFilterPopupHandler = void Function(PlutoGridStateManager? stateManager); class FilterHelper { /// A value to identify all column searches when searching filters. @@ -41,10 +42,8 @@ class FilterHelper { }) { return PlutoRow( cells: { - filterFieldColumn: - PlutoCell(value: columnField ?? filterFieldAllColumns), - filterFieldType: - PlutoCell(value: filterType ?? const PlutoFilterTypeContains()), + filterFieldColumn: PlutoCell(value: columnField ?? filterFieldAllColumns), + filterFieldType: PlutoCell(value: filterType ?? const PlutoFilterTypeContains()), filterFieldValue: PlutoCell(value: filterValue ?? ''), }, ); @@ -97,8 +96,7 @@ class FilterHelper { flag, compareByFilterType( filterType: filterType!, - base: row!.cells[e.cells[filterFieldColumn]!.value]!.value - .toString(), + base: row!.cells[e.cells[filterFieldColumn]!.value]!.value.toString(), search: e.cells[filterFieldValue]!.value.toString(), column: foundColumn, ), @@ -139,9 +137,7 @@ class FilterHelper { columnField = allField; } - final String filterType = - (row.cells[FilterHelper.filterFieldType]!.value as PlutoFilterType) - .title; + final String filterType = (row.cells[FilterHelper.filterFieldType]!.value as PlutoFilterType).title; final filterValue = row.cells[FilterHelper.filterFieldValue]!.value; @@ -171,8 +167,7 @@ class FilterHelper { } for (var row in filteredRows) { - if (row!.cells[filterFieldColumn]!.value == filterFieldAllColumns || - row.cells[filterFieldColumn]!.value == column.field) { + if (row!.cells[filterFieldColumn]!.value == filterFieldAllColumns || row.cells[filterFieldColumn]!.value == column.field) { return true; } } @@ -447,8 +442,7 @@ class FilterPopupState { required List columns, }) { Map columnMap = { - FilterHelper.filterFieldAllColumns: - configuration.localeText.filterAllColumns, + FilterHelper.filterFieldAllColumns: configuration.localeText.filterAllColumns, }; columns.where((element) => element.enableFilterMenuItem).forEach((element) { @@ -523,36 +517,54 @@ class PlutoGridFilterPopupHeader extends StatelessWidget { } void handleClearButton() { - if (stateManager!.rows.isEmpty) { - Navigator.of(stateManager!.gridFocusNode.context!).pop(); - } else { - stateManager!.removeRows(stateManager!.rows); - } + stateManager!.removeRows(stateManager!.rows); } @override Widget build(BuildContext context) { - return SingleChildScrollView( - scrollDirection: Axis.horizontal, + Size size = MediaQuery.sizeOf(context); + return SizedBox( + width: size.width, child: Row( children: [ - IconButton( - icon: const Icon(Icons.add), - color: configuration!.style.iconColor, - iconSize: configuration!.style.iconSize, - onPressed: handleAddButton, + Row( + children: [ + IconButton( + icon: const Icon(Icons.add), + color: configuration!.style.iconColor, + iconSize: configuration!.style.iconSize, + onPressed: handleAddButton, + ), + IconButton( + icon: const Icon(Icons.remove), + color: configuration!.style.iconColor, + iconSize: configuration!.style.iconSize, + onPressed: handleRemoveButton, + ), + InkWell( + onTap: handleClearButton, + child: const Text( + 'Clear Filter', + style: TextStyle(color: Colors.blue), + ), + ), + ], ), - IconButton( - icon: const Icon(Icons.remove), - color: configuration!.style.iconColor, - iconSize: configuration!.style.iconSize, - onPressed: handleRemoveButton, + const SizedBox( + width: 370, ), - IconButton( - icon: const Icon(Icons.clear_sharp), - color: Colors.red, - iconSize: configuration!.style.iconSize, - onPressed: handleClearButton, + ElevatedButton( + style: ButtonStyle( + backgroundColor: MaterialStateProperty.all(Colors.redAccent), + ), + onPressed: () { + Navigator.of(stateManager!.gridFocusNode.context!).pop(); + isFiltered = false; + }, + child: const Text( + 'Close', + style: TextStyle(color: Colors.white), + ), ), ], ), diff --git a/lib/src/helper/show_column_menu.dart b/lib/src/helper/show_column_menu.dart index 878eab54c..d978024c3 100644 --- a/lib/src/helper/show_column_menu.dart +++ b/lib/src/helper/show_column_menu.dart @@ -1,6 +1,8 @@ import 'package:flutter/material.dart'; import 'package:pluto_grid/pluto_grid.dart'; +import '../ui/columns/pluto_column_title.dart'; + abstract class PlutoColumnMenuDelegate { List> buildMenuItems({ required PlutoGridStateManager stateManager, @@ -16,8 +18,7 @@ abstract class PlutoColumnMenuDelegate { }); } -class PlutoColumnMenuDelegateDefault - implements PlutoColumnMenuDelegate { +class PlutoColumnMenuDelegateDefault implements PlutoColumnMenuDelegate { const PlutoColumnMenuDelegateDefault(); @override @@ -39,37 +40,16 @@ class PlutoColumnMenuDelegateDefault required bool mounted, required PlutoGridColumnMenuItem? selected, }) { - switch (selected) { - case PlutoGridColumnMenuItem.unfreeze: - stateManager.toggleFrozenColumn(column, PlutoColumnFrozen.none); - break; - case PlutoGridColumnMenuItem.freezeToStart: - stateManager.toggleFrozenColumn(column, PlutoColumnFrozen.start); - break; - case PlutoGridColumnMenuItem.freezeToEnd: - stateManager.toggleFrozenColumn(column, PlutoColumnFrozen.end); - break; - case PlutoGridColumnMenuItem.autoFit: - if (!mounted) return; - stateManager.autoFitColumn(context, column); - stateManager.notifyResizingListeners(); - break; - case PlutoGridColumnMenuItem.hideColumn: - stateManager.hideColumn(column, true); - break; - case PlutoGridColumnMenuItem.setColumns: - if (!mounted) return; - stateManager.showSetColumnsPopup(context); - break; - case PlutoGridColumnMenuItem.setFilter: - if (!mounted) return; - stateManager.showFilterPopup(context, calledColumn: column); - break; - case PlutoGridColumnMenuItem.resetFilter: - stateManager.setFilter(null); - break; - default: - break; + if (isFiltered == false) { + switch (selected) { + case PlutoGridColumnMenuItem.setFilter: + stateManager.showFilterPopup(context, calledColumn: column); + break; + default: + break; + } + } else { + null; } } } @@ -81,8 +61,7 @@ Future? showColumnMenu({ required List> items, Color backgroundColor = Colors.white, }) { - final RenderBox overlay = - Overlay.of(context).context.findRenderObject() as RenderBox; + final RenderBox overlay = Overlay.of(context).context.findRenderObject() as RenderBox; return showMenu( context: context, @@ -103,69 +82,14 @@ List> _getDefaultColumnMenuItems({ required PlutoColumn column, }) { final Color textColor = stateManager.style.cellTextStyle.color!; - - final Color disableTextColor = textColor.withOpacity(0.5); - - final bool enoughFrozenColumnsWidth = stateManager.enoughFrozenColumnsWidth( - stateManager.maxWidth! - column.width, - ); - final localeText = stateManager.localeText; return [ - if (column.frozen.isFrozen == true) - _buildMenuItem( - value: PlutoGridColumnMenuItem.unfreeze, - text: localeText.unfreezeColumn, - textColor: textColor, - ), - if (column.frozen.isFrozen != true) ...[ - _buildMenuItem( - value: PlutoGridColumnMenuItem.freezeToStart, - enabled: enoughFrozenColumnsWidth, - text: localeText.freezeColumnToStart, - textColor: enoughFrozenColumnsWidth ? textColor : disableTextColor, - ), - _buildMenuItem( - value: PlutoGridColumnMenuItem.freezeToEnd, - enabled: enoughFrozenColumnsWidth, - text: localeText.freezeColumnToEnd, - textColor: enoughFrozenColumnsWidth ? textColor : disableTextColor, - ), - ], - const PopupMenuDivider(), _buildMenuItem( - value: PlutoGridColumnMenuItem.autoFit, - text: localeText.autoFitColumn, + value: PlutoGridColumnMenuItem.setFilter, + text: localeText.setFilter, textColor: textColor, ), - if (column.enableHideColumnMenuItem == true) - _buildMenuItem( - value: PlutoGridColumnMenuItem.hideColumn, - text: localeText.hideColumn, - textColor: textColor, - enabled: stateManager.refColumns.length > 1, - ), - if (column.enableSetColumnsMenuItem == true) - _buildMenuItem( - value: PlutoGridColumnMenuItem.setColumns, - text: localeText.setColumns, - textColor: textColor, - ), - if (column.enableFilterMenuItem == true) ...[ - const PopupMenuDivider(), - _buildMenuItem( - value: PlutoGridColumnMenuItem.setFilter, - text: localeText.setFilter, - textColor: textColor, - ), - _buildMenuItem( - value: PlutoGridColumnMenuItem.resetFilter, - text: localeText.resetFilter, - textColor: textColor, - enabled: stateManager.hasFilter, - ), - ], ]; } @@ -191,12 +115,5 @@ PopupMenuItem _buildMenuItem({ /// Items in the context menu on the right side of the column enum PlutoGridColumnMenuItem { - unfreeze, - freezeToStart, - freezeToEnd, - hideColumn, - setColumns, - autoFit, setFilter, - resetFilter, } diff --git a/lib/src/manager/pluto_grid_state_manager.dart b/lib/src/manager/pluto_grid_state_manager.dart index 5e0a6f031..fc0dcfa2a 100644 --- a/lib/src/manager/pluto_grid_state_manager.dart +++ b/lib/src/manager/pluto_grid_state_manager.dart @@ -186,7 +186,6 @@ class PlutoGridStateChangeNotifier extends PlutoChangeNotifier /// onLoaded: (PlutoGridOnLoadedEvent event) => stateManager = event.stateManager, /// ) /// ``` -/// {@template initialize_rows_sync_or_async} /// It is created when [PlutoGrid] is first created, /// and the state required for the grid is set for `List rows`. /// [PlutoGridStateManager.initializeRows], which operates at this time, works synchronously, diff --git a/lib/src/manager/state/column_state.dart b/lib/src/manager/state/column_state.dart index 77109320d..04f22ea03 100644 --- a/lib/src/manager/state/column_state.dart +++ b/lib/src/manager/state/column_state.dart @@ -1,3 +1,5 @@ +// ignore_for_file: prefer_null_aware_operators + import 'dart:collection'; import 'package:flutter/material.dart'; diff --git a/lib/src/manager/state/filtering_row_state.dart b/lib/src/manager/state/filtering_row_state.dart index 1db515b4d..b7b5b63e1 100644 --- a/lib/src/manager/state/filtering_row_state.dart +++ b/lib/src/manager/state/filtering_row_state.dart @@ -73,7 +73,7 @@ mixin FilteringRowState implements IPlutoGridState { refRows.setFilter(savedFilter); } - resetCurrentState(notify: false); + resetCurrentState(notify: true); notifyListeners(notify, setFilter.hashCode); } diff --git a/lib/src/model/pluto_column_type.dart b/lib/src/model/pluto_column_type.dart index 12203c48b..3b41f15d6 100644 --- a/lib/src/model/pluto_column_type.dart +++ b/lib/src/model/pluto_column_type.dart @@ -13,6 +13,15 @@ abstract class PlutoColumnType { ); } + /// Set as a boolean column. + factory PlutoColumnType.boolean({ + dynamic defaultValue = false, + }) { + return PlutoColumnTypeBoolean( + defaultValue: defaultValue, + ); + } + /// Set to numeric column. /// /// [format] @@ -31,7 +40,7 @@ abstract class PlutoColumnType { factory PlutoColumnType.number({ dynamic defaultValue = 0, bool negative = true, - String format = '#,###', + String format = '#,###.#######', bool applyFormatOnInit = true, bool allowFirstDot = false, String? locale, @@ -45,6 +54,32 @@ abstract class PlutoColumnType { locale: locale, ); } + factory PlutoColumnType.duration({ + dynamic defaultValue = 0.0, + }) { + return PlutoColumnTypeDuration( + defaultValue: defaultValue, + ); + } + +//this sorting is custom build for sorting double + factory PlutoColumnType.double({ + dynamic defaultValue = 0.0, + bool negative = true, + String format = '#,###.#######', + bool applyFormatOnInit = true, + bool allowFirstDot = false, + String? locale, + }) { + return PlutoColumnTypeDouble( + defaultValue: defaultValue, + format: format, + negative: negative, + applyFormatOnInit: applyFormatOnInit, + allowFirstDot: allowFirstDot, + locale: locale, + ); + } /// Set to currency column. /// @@ -224,11 +259,83 @@ extension PlutoColumnTypeExtension on PlutoColumnType { bool get hasFormat => this is PlutoColumnTypeHasFormat; - bool get applyFormatOnInit => - hasFormat ? (this as PlutoColumnTypeHasFormat).applyFormatOnInit : false; + bool get applyFormatOnInit => hasFormat ? (this as PlutoColumnTypeHasFormat).applyFormatOnInit : false; - dynamic applyFormat(dynamic value) => - hasFormat ? (this as PlutoColumnTypeHasFormat).applyFormat(value) : value; + dynamic applyFormat(dynamic value) => hasFormat ? (this as PlutoColumnTypeHasFormat).applyFormat(value) : value; +} + +class PlutoColumnTypeDuration implements PlutoColumnType { + @override + final dynamic defaultValue; + + const PlutoColumnTypeDuration({ + this.defaultValue, + }); + + @override + bool isValid(dynamic value) { + return value is String || value is num; + } + + @override + int compare(dynamic a, dynamic b) { + if (a is num && b is num) { + return a.compareTo(b); + } else if (a is num) { + return 1; // a is considered greater + } else if (b is num) { + return -1; // b is considered greater + } else { + // If both are strings containing both numbers and alphabets, + // extract the numeric part for comparison + final num aNum = _extractNumber(a); + final num bNum = _extractNumber(b); + return aNum.compareTo(bNum); + } + } + + num _extractNumber(dynamic value) { + final RegExp regex = RegExp(r'\d+'); + final Iterable matches = regex.allMatches(value.toString()); + if (matches.isNotEmpty) { + return num.parse(matches.first.group(0)!); + } else { + return defaultValue; + } + } + + @override + dynamic makeCompareValue(dynamic v) { + return v; + } +} + +class PlutoColumnTypeBoolean implements PlutoColumnType { + @override + final dynamic defaultValue; + + const PlutoColumnTypeBoolean({ + this.defaultValue, + }); + + @override + bool isValid(dynamic value) { + return value is bool; + } + + @override + int compare(dynamic a, dynamic b) { + bool boolA = a == null ? false : a as bool; + bool boolB = b == null ? false : b as bool; + + // Custom sorting for booleans: false first, then true + return boolA == boolB ? 0 : (boolA ? 1 : -1); + } + + @override + dynamic makeCompareValue(dynamic v) { + return v == null ? false : v as bool; + } } class PlutoColumnTypeText implements PlutoColumnType { @@ -246,18 +353,58 @@ class PlutoColumnTypeText implements PlutoColumnType { @override int compare(dynamic a, dynamic b) { - return _compareWithNull(a, b, () => a.toString().compareTo(b.toString())); + return _compareWithNull(a, b, () => a.toString().toLowerCase().compareTo(b.toString().toLowerCase())); } @override dynamic makeCompareValue(dynamic v) { - return v.toString(); + return v.toString().toLowerCase(); + } +} + +class PlutoColumnTypeDouble with PlutoColumnTypeWithDoubleFormat implements PlutoColumnType, PlutoColumnTypeHasFormat { + @override + final dynamic defaultValue; + + @override + final bool negative; + + @override + final String format; + + @override + final bool applyFormatOnInit; + + @override + final bool allowFirstDot; + + @override + final String? locale; + + PlutoColumnTypeDouble({ + this.defaultValue, + required this.negative, + required this.format, + required this.applyFormatOnInit, + required this.allowFirstDot, + required this.locale, + }) : numberFormat = intl.NumberFormat(format, locale), + decimalPoint = _getDecimalPoint(format); + + @override + final intl.NumberFormat numberFormat; + + @override + final int decimalPoint; + + static int _getDecimalPoint(String format) { + final int dotIndex = format.indexOf('.'); + + return dotIndex < 0 ? 0 : format.substring(dotIndex).length - 1; } } -class PlutoColumnTypeNumber - with PlutoColumnTypeWithNumberFormat - implements PlutoColumnType, PlutoColumnTypeHasFormat { +class PlutoColumnTypeNumber with PlutoColumnTypeWithNumberFormat implements PlutoColumnType, PlutoColumnTypeHasFormat { @override final dynamic defaultValue; @@ -299,9 +446,7 @@ class PlutoColumnTypeNumber } } -class PlutoColumnTypeCurrency - with PlutoColumnTypeWithNumberFormat - implements PlutoColumnType, PlutoColumnTypeHasFormat { +class PlutoColumnTypeCurrency with PlutoColumnTypeWithNumberFormat implements PlutoColumnType, PlutoColumnTypeHasFormat { @override final dynamic defaultValue; @@ -351,8 +496,7 @@ class PlutoColumnTypeCurrency late final int decimalPoint; } -class PlutoColumnTypeSelect - implements PlutoColumnType, PlutoColumnTypeHasPopupIcon { +class PlutoColumnTypeSelect implements PlutoColumnType, PlutoColumnTypeHasPopupIcon { @override final dynamic defaultValue; @@ -386,12 +530,7 @@ class PlutoColumnTypeSelect } } -class PlutoColumnTypeDate - implements - PlutoColumnType, - PlutoColumnTypeHasFormat, - PlutoColumnTypeHasDateFormat, - PlutoColumnTypeHasPopupIcon { +class PlutoColumnTypeDate implements PlutoColumnType, PlutoColumnTypeHasFormat, PlutoColumnTypeHasDateFormat, PlutoColumnTypeHasPopupIcon { @override final dynamic defaultValue; @@ -477,8 +616,7 @@ class PlutoColumnTypeDate } } -class PlutoColumnTypeTime - implements PlutoColumnType, PlutoColumnTypeHasPopupIcon { +class PlutoColumnTypeTime implements PlutoColumnType, PlutoColumnTypeHasPopupIcon { @override final dynamic defaultValue; @@ -539,6 +677,74 @@ abstract class PlutoColumnTypeHasPopupIcon { IconData? get popupIcon; } +mixin PlutoColumnTypeWithDoubleFormat { + intl.NumberFormat get numberFormat; + + bool get negative; + + int get decimalPoint; + + bool get allowFirstDot; + + String? get locale; + + bool isValid(dynamic value) { + if (!isNumeric(value)) { + return false; + } + + if (negative == false && num.parse(value.toString()) < 0) { + return false; + } + + return true; + } + + int compare(dynamic a, dynamic b) { + return _compareWithNull( + a, + b, + () => toDouble(a.toString()).compareTo(toDouble(b.toString())), + ); + } + + dynamic makeCompareValue(dynamic v) { + return v.runtimeType != num ? toDouble(v.toString()) : v; + } + + String applyFormat(dynamic value) { + double number = toDouble(value.toString()); + + if (negative == false && number < 0) { + number = 0.0; + } + + return numberFormat.format(number); + } + + /// Convert [String] converted to [applyFormat] to [double]. + double toDouble(String formatted) { + String match = '0-9\\-${numberFormat.symbols.DECIMAL_SEP}'; + + if (negative) { + match += numberFormat.symbols.MINUS_SIGN; + } + + formatted = formatted.replaceAll(RegExp('[^$match]'), '').replaceFirst(numberFormat.symbols.DECIMAL_SEP, '.'); + + final double formattedDouble = double.tryParse(formatted) ?? 0.0; + + return formattedDouble.isFinite ? formattedDouble : 0.0; + } + + bool isNumeric(dynamic s) { + if (s == null) { + return false; + } + return double.tryParse(s.toString()) != null; + } +} + mixin PlutoColumnTypeWithNumberFormat { intl.NumberFormat get numberFormat; @@ -595,9 +801,7 @@ mixin PlutoColumnTypeWithNumberFormat { match += numberFormat.symbols.MINUS_SIGN; } - formatted = formatted - .replaceAll(RegExp('[^$match]'), '') - .replaceFirst(numberFormat.symbols.DECIMAL_SEP, '.'); + formatted = formatted.replaceAll(RegExp('[^$match]'), '').replaceFirst(numberFormat.symbols.DECIMAL_SEP, '.'); final num formattedNumber = num.tryParse(formatted) ?? 0; diff --git a/lib/src/pluto_dual_grid.dart b/lib/src/pluto_dual_grid.dart index 167686ba1..9035ed39b 100644 --- a/lib/src/pluto_dual_grid.dart +++ b/lib/src/pluto_dual_grid.dart @@ -3,8 +3,7 @@ import 'dart:async'; import 'package:flutter/material.dart'; import 'package:pluto_grid/pluto_grid.dart'; -typedef PlutoDualOnSelectedEventCallback = void Function( - PlutoDualOnSelectedEvent event); +typedef PlutoDualOnSelectedEventCallback = void Function(PlutoDualOnSelectedEvent event); /// In [PlutoDualGrid], set the separation widget between the two grids. class PlutoDualGridDivider { @@ -84,8 +83,7 @@ class PlutoDualGridResizeNotifier extends ChangeNotifier { } class PlutoDualGridState extends State { - final PlutoDualGridResizeNotifier resizeNotifier = - PlutoDualGridResizeNotifier(); + final PlutoDualGridResizeNotifier resizeNotifier = PlutoDualGridResizeNotifier(); late final PlutoDualGridDisplay display; @@ -144,11 +142,9 @@ class PlutoDualGridState extends State { } if (isGridA) { - _streamA = - onLoadedEvent.stateManager.eventManager!.listener(handleEvent); + _streamA = onLoadedEvent.stateManager.eventManager!.listener(handleEvent); } else { - _streamB = - onLoadedEvent.stateManager.eventManager!.listener(handleEvent); + _streamB = onLoadedEvent.stateManager.eventManager!.listener(handleEvent); } if (props.onLoaded != null) { @@ -224,8 +220,7 @@ class PlutoDualGridState extends State { indicatorColor: widget.divider.indicatorColor, draggingColor: widget.divider.draggingColor, dragCallback: (details) { - final RenderBox object = - context.findRenderObject() as RenderBox; + final RenderBox object = context.findRenderObject() as RenderBox; display.offset = object .globalToLocal(Offset( @@ -266,12 +261,10 @@ class PlutoDualGridDividerWidget extends StatefulWidget { }) : super(key: key); @override - State createState() => - PlutoDualGridDividerWidgetState(); + State createState() => PlutoDualGridDividerWidgetState(); } -class PlutoDualGridDividerWidgetState - extends State { +class PlutoDualGridDividerWidgetState extends State { bool isDragging = false; void onHorizontalDragStart(DragStartDetails details) { @@ -355,8 +348,7 @@ class PlutoDualGridLayoutDelegate extends MultiChildLayoutDelegate { maxHeight: size.height, ); - final dividerHalf = - showDraggableDivider ? PlutoDualGrid.dividerWidth / 2 : 0; + final dividerHalf = showDraggableDivider ? PlutoDualGrid.dividerWidth / 2 : 0; final dividerWidth = dividerHalf * 2; @@ -613,33 +605,20 @@ class PlutoDualGridProps { return PlutoDualGridProps( columns: columns ?? this.columns, rows: rows ?? this.rows, - columnGroups: - columnGroups == null ? this.columnGroups : columnGroups.value, + columnGroups: columnGroups == null ? this.columnGroups : columnGroups.value, onLoaded: onLoaded == null ? this.onLoaded : onLoaded.value, onChanged: onChanged == null ? this.onChanged : onChanged.value, onSorted: onSorted == null ? this.onSorted : onSorted.value, - onRowChecked: - onRowChecked == null ? this.onRowChecked : onRowChecked.value, - onRowDoubleTap: - onRowDoubleTap == null ? this.onRowDoubleTap : onRowDoubleTap.value, - onRowSecondaryTap: onRowSecondaryTap == null - ? this.onRowSecondaryTap - : onRowSecondaryTap.value, + onRowChecked: onRowChecked == null ? this.onRowChecked : onRowChecked.value, + onRowDoubleTap: onRowDoubleTap == null ? this.onRowDoubleTap : onRowDoubleTap.value, + onRowSecondaryTap: onRowSecondaryTap == null ? this.onRowSecondaryTap : onRowSecondaryTap.value, onRowsMoved: onRowsMoved == null ? this.onRowsMoved : onRowsMoved.value, - onColumnsMoved: - onColumnsMoved == null ? this.onColumnsMoved : onColumnsMoved.value, - createHeader: - createHeader == null ? this.createHeader : createHeader.value, - createFooter: - createFooter == null ? this.createFooter : createFooter.value, - noRowsWidget: - noRowsWidget == null ? this.noRowsWidget : noRowsWidget.value, - rowColorCallback: rowColorCallback == null - ? this.rowColorCallback - : rowColorCallback.value, - columnMenuDelegate: columnMenuDelegate == null - ? this.columnMenuDelegate - : columnMenuDelegate.value, + onColumnsMoved: onColumnsMoved == null ? this.onColumnsMoved : onColumnsMoved.value, + createHeader: createHeader == null ? this.createHeader : createHeader.value, + createFooter: createFooter == null ? this.createFooter : createFooter.value, + noRowsWidget: noRowsWidget == null ? this.noRowsWidget : noRowsWidget.value, + rowColorCallback: rowColorCallback == null ? this.rowColorCallback : rowColorCallback.value, + columnMenuDelegate: columnMenuDelegate == null ? this.columnMenuDelegate : columnMenuDelegate.value, configuration: configuration ?? this.configuration, mode: mode == null ? this.mode : mode.value, key: key ?? this.key, diff --git a/lib/src/pluto_grid_configuration.dart b/lib/src/pluto_grid_configuration.dart index 9b946b169..4b24e413c 100644 --- a/lib/src/pluto_grid_configuration.dart +++ b/lib/src/pluto_grid_configuration.dart @@ -105,8 +105,7 @@ class PlutoGridConfiguration { PlutoFilterTypeStartsWith.name = localeText.filterStartsWith; PlutoFilterTypeEndsWith.name = localeText.filterEndsWith; PlutoFilterTypeGreaterThan.name = localeText.filterGreaterThan; - PlutoFilterTypeGreaterThanOrEqualTo.name = - localeText.filterGreaterThanOrEqualTo; + PlutoFilterTypeGreaterThanOrEqualTo.name = localeText.filterGreaterThanOrEqualTo; PlutoFilterTypeLessThan.name = localeText.filterLessThan; PlutoFilterTypeLessThanOrEqualTo.name = localeText.filterLessThanOrEqualTo; } @@ -141,10 +140,8 @@ class PlutoGridConfiguration { PlutoGridLocaleText? localeText, }) { return PlutoGridConfiguration( - enableMoveDownAfterSelecting: - enableMoveDownAfterSelecting ?? this.enableMoveDownAfterSelecting, - enableMoveHorizontalInEditing: - enableMoveHorizontalInEditing ?? this.enableMoveHorizontalInEditing, + enableMoveDownAfterSelecting: enableMoveDownAfterSelecting ?? this.enableMoveDownAfterSelecting, + enableMoveHorizontalInEditing: enableMoveHorizontalInEditing ?? this.enableMoveHorizontalInEditing, enterKeyAction: enterKeyAction ?? this.enterKeyAction, tabKeyAction: tabKeyAction ?? this.tabKeyAction, shortcut: shortcut ?? this.shortcut, @@ -161,10 +158,8 @@ class PlutoGridConfiguration { return identical(this, other) || other is PlutoGridConfiguration && runtimeType == other.runtimeType && - enableMoveDownAfterSelecting == - other.enableMoveDownAfterSelecting && - enableMoveHorizontalInEditing == - other.enableMoveHorizontalInEditing && + enableMoveDownAfterSelecting == other.enableMoveDownAfterSelecting && + enableMoveHorizontalInEditing == other.enableMoveHorizontalInEditing && enterKeyAction == other.enterKeyAction && tabKeyAction == other.tabKeyAction && shortcut == other.shortcut && @@ -492,67 +487,47 @@ class PlutoGridStyleConfig { BorderRadiusGeometry? gridPopupBorderRadius, }) { return PlutoGridStyleConfig( - enableGridBorderShadow: - enableGridBorderShadow ?? this.enableGridBorderShadow, - enableColumnBorderVertical: - enableColumnBorderVertical ?? this.enableColumnBorderVertical, - enableColumnBorderHorizontal: - enableColumnBorderHorizontal ?? this.enableColumnBorderHorizontal, - enableCellBorderVertical: - enableCellBorderVertical ?? this.enableCellBorderVertical, - enableCellBorderHorizontal: - enableCellBorderHorizontal ?? this.enableCellBorderHorizontal, - enableRowColorAnimation: - enableRowColorAnimation ?? this.enableRowColorAnimation, + enableGridBorderShadow: enableGridBorderShadow ?? this.enableGridBorderShadow, + enableColumnBorderVertical: enableColumnBorderVertical ?? this.enableColumnBorderVertical, + enableColumnBorderHorizontal: enableColumnBorderHorizontal ?? this.enableColumnBorderHorizontal, + enableCellBorderVertical: enableCellBorderVertical ?? this.enableCellBorderVertical, + enableCellBorderHorizontal: enableCellBorderHorizontal ?? this.enableCellBorderHorizontal, + enableRowColorAnimation: enableRowColorAnimation ?? this.enableRowColorAnimation, gridBackgroundColor: gridBackgroundColor ?? this.gridBackgroundColor, rowColor: rowColor ?? this.rowColor, oddRowColor: oddRowColor == null ? this.oddRowColor : oddRowColor.value, - evenRowColor: - evenRowColor == null ? this.evenRowColor : evenRowColor.value, + evenRowColor: evenRowColor == null ? this.evenRowColor : evenRowColor.value, activatedColor: activatedColor ?? this.activatedColor, checkedColor: checkedColor ?? this.checkedColor, cellColorInEditState: cellColorInEditState ?? this.cellColorInEditState, - cellColorInReadOnlyState: - cellColorInReadOnlyState ?? this.cellColorInReadOnlyState, - cellColorGroupedRow: cellColorGroupedRow == null - ? this.cellColorGroupedRow - : cellColorGroupedRow.value, - dragTargetColumnColor: - dragTargetColumnColor ?? this.dragTargetColumnColor, + cellColorInReadOnlyState: cellColorInReadOnlyState ?? this.cellColorInReadOnlyState, + cellColorGroupedRow: cellColorGroupedRow == null ? this.cellColorGroupedRow : cellColorGroupedRow.value, + dragTargetColumnColor: dragTargetColumnColor ?? this.dragTargetColumnColor, iconColor: iconColor ?? this.iconColor, disabledIconColor: disabledIconColor ?? this.disabledIconColor, menuBackgroundColor: menuBackgroundColor ?? this.menuBackgroundColor, gridBorderColor: gridBorderColor ?? this.gridBorderColor, borderColor: borderColor ?? this.borderColor, activatedBorderColor: activatedBorderColor ?? this.activatedBorderColor, - inactivatedBorderColor: - inactivatedBorderColor ?? this.inactivatedBorderColor, + inactivatedBorderColor: inactivatedBorderColor ?? this.inactivatedBorderColor, iconSize: iconSize ?? this.iconSize, rowHeight: rowHeight ?? this.rowHeight, columnHeight: columnHeight ?? this.columnHeight, columnFilterHeight: columnFilterHeight ?? this.columnFilterHeight, - defaultColumnTitlePadding: - defaultColumnTitlePadding ?? this.defaultColumnTitlePadding, - defaultColumnFilterPadding: - defaultColumnFilterPadding ?? this.defaultColumnFilterPadding, + defaultColumnTitlePadding: defaultColumnTitlePadding ?? this.defaultColumnTitlePadding, + defaultColumnFilterPadding: defaultColumnFilterPadding ?? this.defaultColumnFilterPadding, defaultCellPadding: defaultCellPadding ?? this.defaultCellPadding, columnTextStyle: columnTextStyle ?? this.columnTextStyle, cellTextStyle: cellTextStyle ?? this.cellTextStyle, columnContextIcon: columnContextIcon ?? this.columnContextIcon, columnResizeIcon: columnResizeIcon ?? this.columnResizeIcon, - columnAscendingIcon: columnAscendingIcon == null - ? this.columnAscendingIcon - : columnAscendingIcon.value, - columnDescendingIcon: columnDescendingIcon == null - ? this.columnDescendingIcon - : columnDescendingIcon.value, + columnAscendingIcon: columnAscendingIcon == null ? this.columnAscendingIcon : columnAscendingIcon.value, + columnDescendingIcon: columnDescendingIcon == null ? this.columnDescendingIcon : columnDescendingIcon.value, rowGroupExpandedIcon: rowGroupExpandedIcon ?? this.rowGroupExpandedIcon, - rowGroupCollapsedIcon: - rowGroupCollapsedIcon ?? this.rowGroupCollapsedIcon, + rowGroupCollapsedIcon: rowGroupCollapsedIcon ?? this.rowGroupCollapsedIcon, rowGroupEmptyIcon: rowGroupEmptyIcon ?? this.rowGroupEmptyIcon, gridBorderRadius: gridBorderRadius ?? this.gridBorderRadius, - gridPopupBorderRadius: - gridPopupBorderRadius ?? this.gridPopupBorderRadius, + gridPopupBorderRadius: gridPopupBorderRadius ?? this.gridPopupBorderRadius, ); } @@ -563,8 +538,7 @@ class PlutoGridStyleConfig { runtimeType == other.runtimeType && enableGridBorderShadow == other.enableGridBorderShadow && enableColumnBorderVertical == other.enableColumnBorderVertical && - enableColumnBorderHorizontal == - other.enableColumnBorderHorizontal && + enableColumnBorderHorizontal == other.enableColumnBorderHorizontal && enableCellBorderVertical == other.enableCellBorderVertical && enableCellBorderHorizontal == other.enableCellBorderHorizontal && enableRowColorAnimation == other.enableRowColorAnimation && @@ -662,16 +636,14 @@ class PlutoGridScrollbarConfig { this.onlyDraggingThumb = true, this.enableScrollAfterDragEnd = true, this.scrollbarThickness = PlutoScrollbar.defaultThickness, - this.scrollbarThicknessWhileDragging = - PlutoScrollbar.defaultThicknessWhileDragging, + this.scrollbarThicknessWhileDragging = PlutoScrollbar.defaultThicknessWhileDragging, this.hoverWidth = PlutoScrollbar.defaultScrollbarHoverWidth, this.mainAxisMargin, this.crossAxisMargin, this.scrollBarColor, this.scrollBarTrackColor, this.scrollbarRadius = PlutoScrollbar.defaultRadius, - this.scrollbarRadiusWhileDragging = - PlutoScrollbar.defaultRadiusWhileDragging, + this.scrollbarRadiusWhileDragging = PlutoScrollbar.defaultRadiusWhileDragging, this.longPressDuration, this.dragDevices, }); @@ -725,16 +697,14 @@ class PlutoGridScrollbarConfig { onlyDraggingThumb == other.onlyDraggingThumb && enableScrollAfterDragEnd == other.enableScrollAfterDragEnd && scrollbarThickness == other.scrollbarThickness && - scrollbarThicknessWhileDragging == - other.scrollbarThicknessWhileDragging && + scrollbarThicknessWhileDragging == other.scrollbarThicknessWhileDragging && hoverWidth == other.hoverWidth && mainAxisMargin == other.mainAxisMargin && crossAxisMargin == other.crossAxisMargin && scrollBarColor == other.scrollBarColor && scrollBarTrackColor == other.scrollBarTrackColor && scrollbarRadius == other.scrollbarRadius && - scrollbarRadiusWhileDragging == - other.scrollbarRadiusWhileDragging && + scrollbarRadiusWhileDragging == other.scrollbarRadiusWhileDragging && longPressDuration == other.longPressDuration && dragDevices == other.dragDevices; } @@ -835,8 +805,7 @@ class PlutoGridColumnFilterConfig { bool get hasUserFilter => _userFilters != null && _userFilters!.isNotEmpty; - List get filters => - hasUserFilter ? _userFilters! : FilterHelper.defaultFilters; + List get filters => hasUserFilter ? _userFilters! : FilterHelper.defaultFilters; int get debounceMilliseconds => _debounceMilliseconds; @@ -865,8 +834,7 @@ class PlutoGridColumnFilterConfig { other is PlutoGridColumnFilterConfig && runtimeType == other.runtimeType && listEquals(_userFilters, other._userFilters) && - _userResolveDefaultColumnFilter == - other._userResolveDefaultColumnFilter && + _userResolveDefaultColumnFilter == other._userResolveDefaultColumnFilter && _debounceMilliseconds == other._debounceMilliseconds; } @@ -933,16 +901,11 @@ class PlutoGridColumnSizeConfig { return PlutoGridColumnSizeConfig( autoSizeMode: autoSizeMode ?? this.autoSizeMode, resizeMode: resizeMode ?? this.resizeMode, - restoreAutoSizeAfterHideColumn: - restoreAutoSizeAfterHideColumn ?? this.restoreAutoSizeAfterHideColumn, - restoreAutoSizeAfterFrozenColumn: restoreAutoSizeAfterFrozenColumn ?? - this.restoreAutoSizeAfterFrozenColumn, - restoreAutoSizeAfterMoveColumn: - restoreAutoSizeAfterMoveColumn ?? this.restoreAutoSizeAfterMoveColumn, - restoreAutoSizeAfterInsertColumn: restoreAutoSizeAfterInsertColumn ?? - this.restoreAutoSizeAfterInsertColumn, - restoreAutoSizeAfterRemoveColumn: restoreAutoSizeAfterRemoveColumn ?? - this.restoreAutoSizeAfterRemoveColumn, + restoreAutoSizeAfterHideColumn: restoreAutoSizeAfterHideColumn ?? this.restoreAutoSizeAfterHideColumn, + restoreAutoSizeAfterFrozenColumn: restoreAutoSizeAfterFrozenColumn ?? this.restoreAutoSizeAfterFrozenColumn, + restoreAutoSizeAfterMoveColumn: restoreAutoSizeAfterMoveColumn ?? this.restoreAutoSizeAfterMoveColumn, + restoreAutoSizeAfterInsertColumn: restoreAutoSizeAfterInsertColumn ?? this.restoreAutoSizeAfterInsertColumn, + restoreAutoSizeAfterRemoveColumn: restoreAutoSizeAfterRemoveColumn ?? this.restoreAutoSizeAfterRemoveColumn, ); } @@ -953,16 +916,11 @@ class PlutoGridColumnSizeConfig { runtimeType == other.runtimeType && autoSizeMode == other.autoSizeMode && resizeMode == other.resizeMode && - restoreAutoSizeAfterHideColumn == - other.restoreAutoSizeAfterHideColumn && - restoreAutoSizeAfterFrozenColumn == - other.restoreAutoSizeAfterFrozenColumn && - restoreAutoSizeAfterMoveColumn == - other.restoreAutoSizeAfterMoveColumn && - restoreAutoSizeAfterInsertColumn == - other.restoreAutoSizeAfterInsertColumn && - restoreAutoSizeAfterRemoveColumn == - other.restoreAutoSizeAfterRemoveColumn; + restoreAutoSizeAfterHideColumn == other.restoreAutoSizeAfterHideColumn && + restoreAutoSizeAfterFrozenColumn == other.restoreAutoSizeAfterFrozenColumn && + restoreAutoSizeAfterMoveColumn == other.restoreAutoSizeAfterMoveColumn && + restoreAutoSizeAfterInsertColumn == other.restoreAutoSizeAfterInsertColumn && + restoreAutoSizeAfterRemoveColumn == other.restoreAutoSizeAfterRemoveColumn; } @override @@ -1671,11 +1629,9 @@ enum PlutoGridEnterKeyAction { /// Pressing the Enter key does nothing. none; - bool get isEditingAndMoveDown => - this == PlutoGridEnterKeyAction.editingAndMoveDown; + bool get isEditingAndMoveDown => this == PlutoGridEnterKeyAction.editingAndMoveDown; - bool get isEditingAndMoveRight => - this == PlutoGridEnterKeyAction.editingAndMoveRight; + bool get isEditingAndMoveRight => this == PlutoGridEnterKeyAction.editingAndMoveRight; bool get isToggleEditing => this == PlutoGridEnterKeyAction.toggleEditing; diff --git a/lib/src/pluto_grid_popup.dart b/lib/src/pluto_grid_popup.dart index 710e2c350..33c16ed50 100644 --- a/lib/src/pluto_grid_popup.dart +++ b/lib/src/pluto_grid_popup.dart @@ -109,51 +109,48 @@ class PlutoGridPopup { textDirection, ); - PlutoGridOnSelectedEvent? selected = - await showDialog( - context: context, - builder: (BuildContext ctx) { - return Dialog( - shape: borderRadius == BorderRadius.zero - ? null - : RoundedRectangleBorder(borderRadius: borderRadius), - child: LayoutBuilder( - builder: (ctx, size) { - return SizedBox( - width: (width ?? size.maxWidth) + - PlutoGridSettings.gridInnerSpacing, - height: height ?? size.maxHeight, - child: Directionality( - textDirection: textDirection, - child: PlutoGrid( - columns: columns, - rows: rows, - columnGroups: columnGroups, - onLoaded: onLoaded, - onChanged: onChanged, - onSelected: (PlutoGridOnSelectedEvent event) { - Navigator.pop(ctx, event); - }, - onSorted: onSorted, - onRowChecked: onRowChecked, - onRowDoubleTap: onRowDoubleTap, - onRowSecondaryTap: onRowSecondaryTap, - onRowsMoved: onRowsMoved, - onColumnsMoved: onColumnsMoved, - createHeader: createHeader, - createFooter: createFooter, - noRowsWidget: noRowsWidget, - rowColorCallback: rowColorCallback, - columnMenuDelegate: columnMenuDelegate, - configuration: configuration, - mode: mode, - ), - ), - ); - }, - ), - ); - }); + PlutoGridOnSelectedEvent? selected = await showDialog( + barrierDismissible: false, + context: context, + builder: (BuildContext ctx) { + return Dialog( + shape: borderRadius == BorderRadius.zero ? null : RoundedRectangleBorder(borderRadius: borderRadius), + child: LayoutBuilder( + builder: (ctx, size) { + return SizedBox( + width: (width ?? size.maxWidth) + PlutoGridSettings.gridInnerSpacing, + height: height ?? size.maxHeight, + child: Directionality( + textDirection: textDirection, + child: PlutoGrid( + columns: columns, + rows: rows, + columnGroups: columnGroups, + onLoaded: onLoaded, + onChanged: onChanged, + onSelected: (PlutoGridOnSelectedEvent event) { + Navigator.pop(ctx, event); + }, + onSorted: onSorted, + onRowChecked: onRowChecked, + onRowDoubleTap: onRowDoubleTap, + onRowSecondaryTap: onRowSecondaryTap, + onRowsMoved: onRowsMoved, + onColumnsMoved: onColumnsMoved, + createHeader: createHeader, + createFooter: createFooter, + noRowsWidget: noRowsWidget, + rowColorCallback: rowColorCallback, + columnMenuDelegate: columnMenuDelegate, + configuration: configuration, + mode: mode, + ), + ), + ); + }, + ), + ); + }); if (onSelected != null && selected != null) { onSelected!(selected); } diff --git a/lib/src/ui/columns/pluto_column_title.dart b/lib/src/ui/columns/pluto_column_title.dart index a9d46cd0f..f0995e327 100644 --- a/lib/src/ui/columns/pluto_column_title.dart +++ b/lib/src/ui/columns/pluto_column_title.dart @@ -4,6 +4,7 @@ import 'package:flutter/material.dart'; import 'package:pluto_grid/pluto_grid.dart'; import '../ui.dart'; +bool isFiltered = false; class PlutoColumnTitle extends PlutoStatefulWidget { final PlutoGridStateManager stateManager; @@ -31,9 +32,7 @@ class PlutoColumnTitleState extends PlutoStateWithChange { PlutoColumnSort _sort = PlutoColumnSort.none; bool get showContextIcon { - return widget.column.enableContextMenu || - widget.column.enableDropToResize || - !_sort.isNone; + return widget.column.enableContextMenu || widget.column.enableDropToResize || !_sort.isNone; } bool get enableGesture { @@ -42,9 +41,7 @@ class PlutoColumnTitleState extends PlutoStateWithChange { MouseCursor get contextMenuCursor { if (enableGesture) { - return widget.column.enableDropToResize - ? SystemMouseCursors.resizeLeftRight - : SystemMouseCursors.click; + return widget.column.enableDropToResize ? SystemMouseCursors.resizeLeftRight : SystemMouseCursors.click; } return SystemMouseCursors.basic; @@ -69,24 +66,15 @@ class PlutoColumnTitleState extends PlutoStateWithChange { } void _showContextMenu(BuildContext context, Offset position) async { - final selected = await showColumnMenu( - context: context, - position: position, - backgroundColor: stateManager.style.menuBackgroundColor, - items: stateManager.columnMenuDelegate.buildMenuItems( - stateManager: stateManager, - column: widget.column, - ), - ); - if (context.mounted) { stateManager.columnMenuDelegate.onSelected( context: context, stateManager: stateManager, column: widget.column, mounted: mounted, - selected: selected, + selected: PlutoGridColumnMenuItem.setFilter, ); + isFiltered = true; } } @@ -98,8 +86,7 @@ class PlutoColumnTitleState extends PlutoStateWithChange { void _handleOnPointMove(PointerMoveEvent event) { // if at least one movement event has distanceSquared > 0.5 _isPointMoving will be true - _isPointMoving |= - (_columnRightPosition - event.position).distanceSquared > 0.5; + _isPointMoving |= (_columnRightPosition - event.position).distanceSquared > 0.5; if (!_isPointMoving) return; @@ -144,9 +131,7 @@ class PlutoColumnTitleState extends PlutoStateWithChange { icon: PlutoGridColumnIcon( sort: _sort, color: style.iconColor, - icon: widget.column.enableContextMenu - ? style.columnContextIcon - : style.columnResizeIcon, + icon: widget.column.enableContextMenu ? style.columnContextIcon : style.columnResizeIcon, ascendingIcon: style.columnAscendingIcon, descendingIcon: style.columnDescendingIcon, ), @@ -279,8 +264,7 @@ class _DraggableWidget extends StatelessWidget { alignment: column.titleTextAlign.alignmentValue, width: PlutoGridSettings.minColumnWidth, height: stateManager.columnHeight, - backgroundColor: - stateManager.configuration.style.gridBackgroundColor, + backgroundColor: stateManager.configuration.style.gridBackgroundColor, borderColor: stateManager.configuration.style.gridBorderColor, child: Text( column.title, @@ -346,13 +330,9 @@ class _ColumnWidget extends StatelessWidget { Key? key, }) : super(key: key); - EdgeInsets get padding => - column.titlePadding ?? - stateManager.configuration.style.defaultColumnTitlePadding; + EdgeInsets get padding => column.titlePadding ?? stateManager.configuration.style.defaultColumnTitlePadding; - bool get showSizedBoxForIcon => - column.isShowRightIcon && - (column.titleTextAlign.isRight || stateManager.isRTL); + bool get showSizedBoxForIcon => column.isShowRightIcon && (column.titleTextAlign.isRight || stateManager.isRTL); @override Widget build(BuildContext context) { @@ -380,13 +360,9 @@ class _ColumnWidget extends StatelessWidget { height: height, child: DecoratedBox( decoration: BoxDecoration( - color: noDragTarget - ? column.backgroundColor - : style.dragTargetColumnColor, + color: noDragTarget ? column.backgroundColor : style.dragTargetColumnColor, border: BorderDirectional( - end: style.enableColumnBorderVertical - ? BorderSide(color: style.borderColor, width: 1.0) - : BorderSide.none, + end: style.enableColumnBorderVertical ? BorderSide(color: style.borderColor, width: 1.0) : BorderSide.none, ), ), child: Padding( @@ -395,8 +371,7 @@ class _ColumnWidget extends StatelessWidget { alignment: Alignment.centerLeft, child: Row( children: [ - if (column.enableRowChecked) - CheckboxAllSelectionWidget(stateManager: stateManager), + if (column.enableRowChecked) CheckboxAllSelectionWidget(stateManager: stateManager), Expanded( child: _ColumnTextWidget( column: column, @@ -419,16 +394,13 @@ class _ColumnWidget extends StatelessWidget { class CheckboxAllSelectionWidget extends PlutoStatefulWidget { final PlutoGridStateManager stateManager; - const CheckboxAllSelectionWidget({required this.stateManager, Key? key}) - : super(key: key); + const CheckboxAllSelectionWidget({required this.stateManager, Key? key}) : super(key: key); @override - CheckboxAllSelectionWidgetState createState() => - CheckboxAllSelectionWidgetState(); + CheckboxAllSelectionWidgetState createState() => CheckboxAllSelectionWidgetState(); } -class CheckboxAllSelectionWidgetState - extends PlutoStateWithChange { +class CheckboxAllSelectionWidgetState extends PlutoStateWithChange { bool? _checked; @override @@ -487,7 +459,6 @@ class CheckboxAllSelectionWidgetState class _ColumnTextWidget extends PlutoStatefulWidget { final PlutoGridStateManager stateManager; - final PlutoColumn column; final double height; @@ -503,16 +474,41 @@ class _ColumnTextWidget extends PlutoStatefulWidget { _ColumnTextWidgetState createState() => _ColumnTextWidgetState(); } +abstract class IFilteringRowState { + List get filterRows; + + bool get hasFilter; + + void setFilter(FilteredListFilter? filter, {bool notify = true}); + + void setFilterWithFilterRows(List rows, {bool notify = true}); + + void setFilterRows(List rows); + + List filterRowsByField(String columnField); + + /// Check if the column is in a state with filtering applied. + bool isFilteredColumn(PlutoColumn column); + + void removeColumnsInFilterRows( + List columns, { + bool notify = true, + }); + + void showFilterPopup( + BuildContext context, { + PlutoColumn? calledColumn, + }); +} + class _ColumnTextWidgetState extends PlutoStateWithChange<_ColumnTextWidget> { bool _isFilteredList = false; @override PlutoGridStateManager get stateManager => widget.stateManager; - @override void initState() { super.initState(); - updateState(PlutoNotifierEventForceUpdate.instance); } @@ -531,8 +527,14 @@ class _ColumnTextWidgetState extends PlutoStateWithChange<_ColumnTextWidget> { ); } - String? get _title => - widget.column.titleSpan == null ? widget.column.title : null; + void clearFilter() { + stateManager.setFilter( + null, + ); + stateManager.setPage(1); + } + + String? get _title => widget.column.titleSpan == null ? widget.column.title : null; List get _children => [ if (widget.column.titleSpan != null) widget.column.titleSpan!, @@ -547,8 +549,22 @@ class _ColumnTextWidgetState extends PlutoStateWithChange<_ColumnTextWidget> { ), onPressed: _handleOnPressedFilter, constraints: BoxConstraints( - maxHeight: - widget.height + (PlutoGridSettings.rowBorderWidth * 2), + maxHeight: widget.height + (PlutoGridSettings.rowBorderWidth * 2), + ), + ), + ), + if (_isFilteredList) + WidgetSpan( + alignment: PlaceholderAlignment.middle, + child: IconButton( + icon: Icon( + Icons.filter_alt_off, + color: stateManager.configuration.style.iconColor, + size: stateManager.configuration.style.iconSize, + ), + onPressed: clearFilter, + constraints: BoxConstraints( + maxHeight: widget.height + (PlutoGridSettings.rowBorderWidth * 2), ), ), ), diff --git a/packages/pluto_grid_export/example/macos/Flutter/GeneratedPluginRegistrant.swift b/packages/pluto_grid_export/example/macos/Flutter/GeneratedPluginRegistrant.swift index 416ef8457..9c4efdd9c 100644 --- a/packages/pluto_grid_export/example/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/packages/pluto_grid_export/example/macos/Flutter/GeneratedPluginRegistrant.swift @@ -6,7 +6,7 @@ import FlutterMacOS import Foundation import file_saver -import path_provider_macos +import path_provider_foundation import printing func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { diff --git a/packages/pluto_grid_export/lib/src/pdf/generic_pdf_controller.dart b/packages/pluto_grid_export/lib/src/pdf/generic_pdf_controller.dart index 82ea42a9c..150f82bab 100644 --- a/packages/pluto_grid_export/lib/src/pdf/generic_pdf_controller.dart +++ b/packages/pluto_grid_export/lib/src/pdf/generic_pdf_controller.dart @@ -79,10 +79,9 @@ class GenericPdfController extends PdfController { } Widget _table(List columns, List> rows) { - return Table.fromTextArray( + return TableHelper.fromTextArray( border: null, cellAlignment: Alignment.center, - // [Resolved 3.8.1] https://github.com/DavBfr/dart_pdf/pull/1033 to replace "headerDecoration" with "headerCellDecoration" headerCellDecoration: BoxDecoration( color: headerBackground, border: Border.all( diff --git a/pubspec.yaml b/pubspec.yaml index 9ff0f667c..734e76ec8 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,11 +1,12 @@ name: pluto_grid description: PlutoGrid is a dataGrid that can be controlled by the keyboard on desktop and web. Of course, it works well on Android and IOS. (DataGrid, DataTable, Data Grid, Data Table, Sticky) -version: 7.0.2 +version: 7.1.4 + homepage: https://pluto.weblaze.dev -repository: https://github.com/bosskmk/pluto_grid +repository: https://github.com/videalphatech/pluto_grid_modified environment: - sdk: ">=2.17.0 <3.0.0" + sdk: '>=3.0.3 <4.0.0' flutter: ">=2.5.0" dependencies: @@ -13,9 +14,9 @@ dependencies: sdk: flutter # Follows the intl version included in Flutter. # https://github.com/flutter/flutter/blob/84a1e904f44f9b0e9c4510138010edcc653163f8/packages/flutter_localizations/pubspec.yaml#L11 - intl: ^0.18.0 - rxdart: ^0.27.7 - collection: ^1.17.1 + intl: + rxdart: + collection: dev_dependencies: flutter_test: