diff --git a/.vscode/settings.json b/.vscode/settings.json index efc84d44b..120f24097 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,4 +1,4 @@ { "dart.lineLength": 80, "files.eol": "\n", -} \ No newline at end of file +} diff --git a/demo/lib/main.dart b/demo/lib/main.dart index 82070b82c..0fc6d7fff 100644 --- a/demo/lib/main.dart +++ b/demo/lib/main.dart @@ -1,3 +1,4 @@ +import 'package:demo/screen/feature/custom_loading_indicator_screen.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; @@ -110,6 +111,8 @@ class MyApp extends StatelessWidget { const TimeTypeColumnScreen(), ValueFormatterScreen.routeName: (context) => const ValueFormatterScreen(), + CustomLoadingIndicatorScreen.routeName: (context) => + const CustomLoadingIndicatorScreen(), // only development EmptyScreen.routeName: (context) => const EmptyScreen(), DevelopmentScreen.routeName: (context) => const DevelopmentScreen(), diff --git a/demo/lib/screen/feature/custom_loading_indicator_screen.dart b/demo/lib/screen/feature/custom_loading_indicator_screen.dart new file mode 100644 index 000000000..e1c8f94c7 --- /dev/null +++ b/demo/lib/screen/feature/custom_loading_indicator_screen.dart @@ -0,0 +1,139 @@ +import 'package:flutter/material.dart'; +import 'package:pluto_grid_plus/pluto_grid_plus.dart'; + +import '../../dummy_data/development.dart'; + +class CustomLoadingIndicatorScreen extends StatefulWidget { + static const routeName = 'feature/custom-loading-indicator'; + + const CustomLoadingIndicatorScreen({super.key}); + + @override + _CustomLoadingIndicatorScreenState createState() => _CustomLoadingIndicatorScreenState(); +} + +class _CustomLoadingIndicatorScreenState extends State { + late List columns; + + late List rows; + + PlutoGridStateManager? stateManager; + + @override + void initState() { + super.initState(); + + columns = [ + PlutoColumn( + title: 'column1', + field: 'column1', + type: PlutoColumnType.text(), + ), + PlutoColumn( + title: 'column2', + field: 'column2', + type: PlutoColumnType.text(), + ), + PlutoColumn( + title: 'column3', + field: 'column3', + type: PlutoColumnType.text(), + ), + ]; + + rows = DummyData.rowsByColumns(length: 10, columns: columns); + } + + @override + Widget build(BuildContext context) { + return ListenableBuilder( + listenable: Listenable.merge([stateManager]), + builder: (context, child) { + return Scaffold( + appBar: AppBar( + title: const Text('Custom Loading Indicator'), + actions: PlutoGridLoadingLevel.values.map((level) { + if (stateManager == null) return SizedBox.shrink(); + + return Padding( + padding: const EdgeInsets.all(8), + child: GestureDetector( + onTap: () => stateManager?.setLoadingLevel(level), + child: MouseRegion( + cursor: SystemMouseCursors.click, + child: Container( + decoration: BoxDecoration( + border: Border.all( + color: stateManager?.loadingLevel == level + ? Theme.of(context).colorScheme.primary + : Colors.transparent), + borderRadius: BorderRadius.circular(8), + ), + padding: const EdgeInsets.all(8), + child: Text(level.name), + ), + ), + ), + ); + }).toList(), + ), + persistentFooterButtons: [ + TextButton( + onPressed: () { + stateManager?.setShowLoading(stateManager?.showLoading == false, + level: stateManager!.loadingLevel); + }, + child: const Text('Toggle Loading'), + ) + ], + body: SafeArea( + child: Container( + padding: const EdgeInsets.all(8), + child: PlutoGrid( + columns: columns, + rows: rows, + mode: PlutoGridMode.readOnly, + onChanged: (PlutoGridOnChangedEvent event) { + print(event); + }, + onLoaded: (PlutoGridOnLoadedEvent event) { + setState(() => stateManager = event.stateManager); + + stateManager?.setCustomLoadingIndicator( + (context) => CustomLoadingIndicator()); + }, + configuration: const PlutoGridConfiguration( + columnSize: PlutoGridColumnSizeConfig( + autoSizeMode: PlutoAutoSizeMode.scale)), + ), + ), + ), + ); + }, + ); + } +} + +class CustomLoadingIndicator extends StatefulWidget { + const CustomLoadingIndicator({super.key}); + + @override + State createState() => _CustomLoadingIndicatorState(); +} + +class _CustomLoadingIndicatorState extends State { + @override + Widget build(BuildContext context) { + return Stack( + children: [ + Positioned.fill( + child: ColoredBox( + color: + Theme.of(context).colorScheme.onPrimary.withValues(alpha: .6), + ), + ), + Center(child: CircularProgressIndicator.adaptive()), + ], + ); + } +} diff --git a/demo/lib/screen/home_screen.dart b/demo/lib/screen/home_screen.dart index 8daa879fc..fc41fbbd7 100644 --- a/demo/lib/screen/home_screen.dart +++ b/demo/lib/screen/home_screen.dart @@ -1,6 +1,6 @@ import 'dart:math'; - import 'package:demo/screen/empty_screen.dart'; +import 'package:demo/screen/feature/custom_loading_indicator_screen.dart'; import 'package:flutter/material.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart'; @@ -492,6 +492,14 @@ class PlutoFeatures extends StatelessWidget { Navigator.pushNamed(context, DarkModeScreen.routeName); }, ), + PlutoListTile( + title: 'Custom Loading Indicator', + description: 'Define a custom loading indicator.', + onTapLiveDemo: () { + Navigator.pushNamed( + context, CustomLoadingIndicatorScreen.routeName); + }, + ), PlutoListTile.amber( title: 'Empty', description: @@ -713,6 +721,13 @@ class PlutoContributors extends StatelessWidget { launchUrl('https://github.com/coruscant187'); }, ), + PlutoContributorTile( + name: 'sten435', + linkTitle: 'Github', + onTapLink: () { + launchUrl('https://github.com/sten435'); + }, + ), PlutoContributorTile.invisible( name: 'And you.', linkTitle: 'Github', diff --git a/demo/linux/flutter/ephemeral/.plugin_symlinks/file_saver b/demo/linux/flutter/ephemeral/.plugin_symlinks/file_saver index 265ba5f45..c933a2ee0 120000 --- a/demo/linux/flutter/ephemeral/.plugin_symlinks/file_saver +++ b/demo/linux/flutter/ephemeral/.plugin_symlinks/file_saver @@ -1 +1 @@ -C:/Users/DOONF/AppData/Local/Pub/Cache/hosted/pub.dev/file_saver-0.2.10/ \ No newline at end of file +C:/Users/stanp/AppData/Local/Pub/Cache/hosted/pub.dev/file_saver-0.2.14/ \ No newline at end of file diff --git a/demo/linux/flutter/ephemeral/.plugin_symlinks/path_provider_linux b/demo/linux/flutter/ephemeral/.plugin_symlinks/path_provider_linux index f9f3220b6..c3766d494 120000 --- a/demo/linux/flutter/ephemeral/.plugin_symlinks/path_provider_linux +++ b/demo/linux/flutter/ephemeral/.plugin_symlinks/path_provider_linux @@ -1 +1 @@ -C:/Users/DOONF/AppData/Local/Pub/Cache/hosted/pub.dev/path_provider_linux-2.2.1/ \ No newline at end of file +C:/Users/stanp/AppData/Local/Pub/Cache/hosted/pub.dev/path_provider_linux-2.2.1/ \ No newline at end of file diff --git a/demo/linux/flutter/ephemeral/.plugin_symlinks/printing b/demo/linux/flutter/ephemeral/.plugin_symlinks/printing index 08c478a37..79b0dd171 120000 --- a/demo/linux/flutter/ephemeral/.plugin_symlinks/printing +++ b/demo/linux/flutter/ephemeral/.plugin_symlinks/printing @@ -1 +1 @@ -C:/Users/DOONF/AppData/Local/Pub/Cache/hosted/pub.dev/printing-5.11.1/ \ No newline at end of file +C:/Users/stanp/AppData/Local/Pub/Cache/hosted/pub.dev/printing-5.13.4/ \ 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 debad87a2..a5652a592 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/DOONF/AppData/Local/Pub/Cache/hosted/pub.dev/url_launcher_linux-3.1.1/ \ No newline at end of file +C:/Users/stanp/AppData/Local/Pub/Cache/hosted/pub.dev/url_launcher_linux-3.2.1/ \ No newline at end of file diff --git a/example/lib/main.dart b/example/lib/main.dart index dad9d280d..78c17d30a 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -170,29 +170,28 @@ class _PlutoGridExamplePageState extends State { body: Container( padding: const EdgeInsets.all(15), child: PlutoGrid( - columns: columns, - rows: rows, - columnGroups: columnGroups, - onLoaded: (PlutoGridOnLoadedEvent event) { - stateManager = event.stateManager; - stateManager.setShowColumnFilter(true); - }, - onChanged: (PlutoGridOnChangedEvent event) { - print(event); - }, - configuration: const PlutoGridConfiguration(), - selectDateCallback: (PlutoCell cell, PlutoColumn column) async { - return showDatePicker( - context: context, - initialDate: PlutoDateTimeHelper.parseOrNullWithFormat( - cell.value, - column.type.date.format, - ) ?? DateTime.now(), - firstDate: column.type.date.startDate ?? DateTime(0), - lastDate: column.type.date.endDate ?? DateTime(9999) - ); - } - ), + columns: columns, + rows: rows, + columnGroups: columnGroups, + onLoaded: (PlutoGridOnLoadedEvent event) { + stateManager = event.stateManager; + stateManager.setShowColumnFilter(true); + }, + onChanged: (PlutoGridOnChangedEvent event) { + print(event); + }, + configuration: const PlutoGridConfiguration(), + selectDateCallback: (PlutoCell cell, PlutoColumn column) async { + return showDatePicker( + context: context, + initialDate: PlutoDateTimeHelper.parseOrNullWithFormat( + cell.value, + column.type.date.format, + ) ?? + DateTime.now(), + firstDate: column.type.date.startDate ?? DateTime(0), + lastDate: column.type.date.endDate ?? DateTime(9999)); + }), ), ); } diff --git a/lib/src/helper/show_column_menu.dart b/lib/src/helper/show_column_menu.dart index 4f5138def..8e66c2e9e 100644 --- a/lib/src/helper/show_column_menu.dart +++ b/lib/src/helper/show_column_menu.dart @@ -104,7 +104,8 @@ List> _getDefaultColumnMenuItems({ }) { final Color textColor = stateManager.style.cellTextStyle.color!; - final Color disableTextColor = textColor.withAlpha((0.5 * 255).toInt()); + final Color disableTextColor = textColor.withValues(alpha: 0.5); + final bool enoughFrozenColumnsWidth = stateManager.enoughFrozenColumnsWidth( stateManager.maxWidth! - column.width, @@ -182,7 +183,7 @@ PopupMenuItem _buildMenuItem({ child: Text( text, style: TextStyle( - color: enabled ? textColor : textColor!.withAlpha((0.5 * 255).toInt()), + color: enabled ? textColor : textColor!.withValues(alpha: 0.5), fontSize: 13, ), ), diff --git a/lib/src/manager/event/pluto_grid_row_hover_event.dart b/lib/src/manager/event/pluto_grid_row_hover_event.dart index 4987d459f..6f9abbd75 100644 --- a/lib/src/manager/event/pluto_grid_row_hover_event.dart +++ b/lib/src/manager/event/pluto_grid_row_hover_event.dart @@ -12,7 +12,8 @@ class PlutoGridRowHoverEvent extends PlutoGridEvent { @override void handler(PlutoGridStateManager stateManager) { - bool enableRowHoverColor = stateManager.configuration.style.enableRowHoverColor; + bool enableRowHoverColor = + stateManager.configuration.style.enableRowHoverColor; // only change current hovered row index // if row hover color effect is enabled diff --git a/lib/src/manager/shortcut/pluto_grid_shortcut_action.dart b/lib/src/manager/shortcut/pluto_grid_shortcut_action.dart index 88599e773..1bfaee5e7 100644 --- a/lib/src/manager/shortcut/pluto_grid_shortcut_action.dart +++ b/lib/src/manager/shortcut/pluto_grid_shortcut_action.dart @@ -657,12 +657,14 @@ class PlutoGridActionPasteValues extends PlutoGridShortcutAction { return; } - Clipboard.getData('text/plain').then((value) { - if (value == null) { - return; - } + Clipboard.getData('text/plain').then((ClipboardData? data) { + final text = data?.text; + + if (text == null) return; + List> textList = - PlutoClipboardTransformation.stringToList(value.text!); + PlutoClipboardTransformation.stringToList(text); + stateManager.pasteCellValue(textList); }); diff --git a/lib/src/manager/state/hovering_state.dart b/lib/src/manager/state/hovering_state.dart index 59b30b646..21abfe000 100644 --- a/lib/src/manager/state/hovering_state.dart +++ b/lib/src/manager/state/hovering_state.dart @@ -1,13 +1,9 @@ import 'package:pluto_grid_plus/pluto_grid_plus.dart'; abstract class IHoveringState { - int? get hoveredRowIdx; - void setHoveredRowIdx( - int? rowIdx, - {bool notify = true} - ); + void setHoveredRowIdx(int? rowIdx, {bool notify = true}); bool isRowIdxHovered(int rowIdx); } @@ -24,9 +20,9 @@ mixin HoveringState implements IPlutoGridState { @override void setHoveredRowIdx( - int? rowIdx, - {bool notify = true,} - ) { + int? rowIdx, { + bool notify = true, + }) { if (hoveredRowIdx == rowIdx) { return; } diff --git a/lib/src/manager/state/layout_state.dart b/lib/src/manager/state/layout_state.dart index 339dd710a..2331d5729 100644 --- a/lib/src/manager/state/layout_state.dart +++ b/lib/src/manager/state/layout_state.dart @@ -43,6 +43,8 @@ abstract class ILayoutState { PlutoGridLoadingLevel get loadingLevel; + WidgetBuilder? get customLoadingIndicator; + bool get hasLeftFrozenColumns; bool get hasRightFrozenColumns; diff --git a/lib/src/plugin/pluto_infinity_scroll_rows.dart b/lib/src/plugin/pluto_infinity_scroll_rows.dart index 756d0232f..13f340582 100644 --- a/lib/src/plugin/pluto_infinity_scroll_rows.dart +++ b/lib/src/plugin/pluto_infinity_scroll_rows.dart @@ -203,7 +203,8 @@ class _PlutoInfinityScrollRowsState extends State { if (!_isLast) { WidgetsBinding.instance.addPostFrameCallback((_) { if (scroll.hasClients && scroll.position.maxScrollExtent == 0) { - var lastRow = stateManager.rows.isNotEmpty ? stateManager.rows.last : null; + var lastRow = + stateManager.rows.isNotEmpty ? stateManager.rows.last : null; _update(lastRow); } }); diff --git a/lib/src/plugin/pluto_lazy_pagination.dart b/lib/src/plugin/pluto_lazy_pagination.dart index 6126c8cc4..4dd915d0d 100644 --- a/lib/src/plugin/pluto_lazy_pagination.dart +++ b/lib/src/plugin/pluto_lazy_pagination.dart @@ -180,7 +180,7 @@ class _PlutoLazyPaginationState extends State { ), ) .then((data) { - if(!mounted)return; + if (!mounted) return; stateManager.scroll.bodyRowsVertical!.jumpTo(0); stateManager.refRows.clearFromOriginal(); diff --git a/lib/src/pluto_grid_configuration.dart b/lib/src/pluto_grid_configuration.dart index c3bed1f8b..0c932002c 100644 --- a/lib/src/pluto_grid_configuration.dart +++ b/lib/src/pluto_grid_configuration.dart @@ -642,7 +642,8 @@ class PlutoGridStyleConfig { defaultColumnFilterPadding ?? this.defaultColumnFilterPadding, defaultCellPadding: defaultCellPadding ?? this.defaultCellPadding, columnTextStyle: columnTextStyle ?? this.columnTextStyle, - columnUnselectedColor: columnUnselectedColor ?? this.columnUnselectedColor, + columnUnselectedColor: + columnUnselectedColor ?? this.columnUnselectedColor, columnActiveColor: columnActiveColor ?? this.columnActiveColor, cellUnselectedColor: cellUnselectedColor ?? this.cellUnselectedColor, cellActiveColor: cellActiveColor ?? this.cellActiveColor, @@ -1784,12 +1785,16 @@ class PlutoGridLocaleText { enum PlutoGridRowSelectionCheckBoxBehavior { /// Selecting a row does nothing to its checkbox none, + /// Automatically enables the checkbox of the selected rows checkRow, + /// Automatically toggles the checkbox of the selected rows toggleCheckRow, + /// Automatically enabels the checkbox of a selected row (if another row is checked via select, the previous one is unchecked) singleRowCheck, + /// Automatically toggles the checkbox of a selected row (if another row is checked via select, the previous one is unchecked) toggleSingleRowCheck, } diff --git a/lib/src/ui/cells/pluto_date_cell.dart b/lib/src/ui/cells/pluto_date_cell.dart index cf8d3d628..1d197096b 100644 --- a/lib/src/ui/cells/pluto_date_cell.dart +++ b/lib/src/ui/cells/pluto_date_cell.dart @@ -52,7 +52,8 @@ class PlutoDateCellState extends State final date = await sm.selectDateCallback!(widget.cell, widget.column); isOpenedPopup = false; if (date != null) { - handleSelected(widget.column.type.date.dateFormat.format(date)); // Consider call onSelected + handleSelected(widget.column.type.date.dateFormat + .format(date)); // Consider call onSelected } } else { PlutoGridDatePicker( diff --git a/lib/src/widgets/pluto_loading.dart b/lib/src/widgets/pluto_loading.dart index 6a662a8af..4684e3fd8 100644 --- a/lib/src/widgets/pluto_loading.dart +++ b/lib/src/widgets/pluto_loading.dart @@ -94,3 +94,39 @@ class _GridLoading extends StatelessWidget { ); } } + +class _CustomLoading extends StatelessWidget { + const _CustomLoading({required this.stateManager}); + + final PlutoGridStateManager stateManager; + + @override + Widget build(BuildContext context) { + return stateManager.customLoadingIndicator?.call(context) ?? + CustomLoadingIndicator(); + } +} + +class CustomLoadingIndicator extends StatefulWidget { + const CustomLoadingIndicator({super.key}); + + @override + State createState() => _CustomLoadingIndicatorState(); +} + +class _CustomLoadingIndicatorState extends State { + @override + Widget build(BuildContext context) { + return Stack( + children: [ + Positioned.fill( + child: ColoredBox( + color: + Theme.of(context).colorScheme.onPrimary.withValues(alpha: .6), + ), + ), + Center(child: CircularProgressIndicator.adaptive()), + ], + ); + } +} diff --git a/lib/src/widgets/pluto_scrollbar.dart b/lib/src/widgets/pluto_scrollbar.dart index c430a9693..d8a180c9a 100644 --- a/lib/src/widgets/pluto_scrollbar.dart +++ b/lib/src/widgets/pluto_scrollbar.dart @@ -982,20 +982,20 @@ class _ScrollbarPainter extends ChangeNotifier implements CustomPainter { Paint get _paintThumb { return Paint() ..color = - color.withAlpha((color.a * fadeoutOpacityAnimation.value).toInt()); + color.withValues(alpha: color.a * fadeoutOpacityAnimation.value); } Paint _paintTrack({bool isBorder = false}) { if (isBorder) { return Paint() - ..color = trackBorderColor.withAlpha( - (trackBorderColor.a * fadeoutOpacityAnimation.value).toInt()) + ..color = trackBorderColor.withValues( + alpha: trackBorderColor.a * fadeoutOpacityAnimation.value) ..style = PaintingStyle.stroke ..strokeWidth = 1.0; } return Paint() - ..color = trackColor - .withAlpha((trackColor.a * fadeoutOpacityAnimation.value).toInt()); + ..color = trackColor.withValues( + alpha: trackColor.a * fadeoutOpacityAnimation.value); } void _paintScrollbar( diff --git a/lib/src/widgets/pluto_shadow_container.dart b/lib/src/widgets/pluto_shadow_container.dart index de0bcc0af..fae54a6cb 100644 --- a/lib/src/widgets/pluto_shadow_container.dart +++ b/lib/src/widgets/pluto_shadow_container.dart @@ -41,7 +41,7 @@ class PlutoShadowContainer extends StatelessWidget { ), boxShadow: [ BoxShadow( - color: Colors.grey.withAlpha((0.5 * 255).toInt()), + color: Colors.grey.withValues(alpha: 0.5), spreadRadius: 5, blurRadius: 7, offset: const Offset(0, 3), // changes position of shadow diff --git a/lib/src/widgets/pluto_shadow_line.dart b/lib/src/widgets/pluto_shadow_line.dart index 9f8dc5e5d..2a0c34183 100644 --- a/lib/src/widgets/pluto_shadow_line.dart +++ b/lib/src/widgets/pluto_shadow_line.dart @@ -25,7 +25,7 @@ class PlutoShadowLine extends StatelessWidget { boxShadow: shadow == true ? [ BoxShadow( - color: Colors.grey.withAlpha((0.15 * 255).toInt()), + color: Colors.grey.withValues(alpha: 0.15), spreadRadius: 1, blurRadius: 3, offset: reverse == true diff --git a/pubspec.yaml b/pubspec.yaml index cbb5c419c..852b8286d 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -12,7 +12,7 @@ dependencies: sdk: flutter # Follows the intl version included in Flutter. # https://github.com/flutter/flutter/blob/84a1e904f44f9b0e9c4510138010edcc653163f8/packages/flutter_localizations/pubspec.yaml#L11 - intl: any + intl: ^0.19.0 rxdart: ^0.28.0 collection: ^1.18.0 diff --git a/test/src/manager/state/hovering_row_state_test.dart b/test/src/manager/state/hovering_row_state_test.dart index da52c2540..e5a7ee6ab 100644 --- a/test/src/manager/state/hovering_row_state_test.dart +++ b/test/src/manager/state/hovering_row_state_test.dart @@ -38,7 +38,7 @@ void main() { group('setHoveredRowIdx', () { test( 'If the rowIdx passed as an argument is the same as' - 'hoveredRowIdx, then notifyListeners should not be called.', + 'hoveredRowIdx, then notifyListeners should not be called.', () { // given stateManager.setHoveredRowIdx(1); @@ -55,7 +55,7 @@ void main() { test( 'If the rowIdx passed as an argument is different from ' - 'hoveredRowIdx, notifyListeners should be called.', + 'hoveredRowIdx, notifyListeners should be called.', () { // given stateManager.setHoveredRowIdx(1); @@ -73,8 +73,8 @@ void main() { test( 'If the rowIdx passed as an argument is different from ' - 'hoveredRowIdx, but notify is false,' - 'notifyListeners should not be called.', + 'hoveredRowIdx, but notify is false,' + 'notifyListeners should not be called.', () { // given stateManager.setHoveredRowIdx(1); diff --git a/test/src/pluto_grid_test.dart b/test/src/pluto_grid_test.dart index f7d1a62dc..161fdf24a 100644 --- a/test/src/pluto_grid_test.dart +++ b/test/src/pluto_grid_test.dart @@ -314,7 +314,6 @@ void main() { // 수정 상태 확인 expect(stateManager!.isEditing, true); - // TODO : 셀 값 변경 (1) 안되서 (2) 강제로 // (1) // await tester.pump(Duration(milliseconds:800)); //