[
  {
    "path": ".gitattributes",
    "content": "# Auto detect text files and perform LF normalization\n* text=auto\n"
  },
  {
    "path": ".github/workflows/main.yml",
    "content": "name: github pages\n\non:\n  push:\n    branches:\n      - master\n\njobs:\n  deploy:\n    runs-on: ubuntu-18.04\n    steps:\n      - uses: actions/checkout@v2\n\n      - name: Setup Flutter\n        uses: subosito/flutter-action@v1\n        with:\n          channel: 'stable'\n\n      - name: Install\n        run: flutter pub get\n      - name: Build\n        run: cd example && flutter build web\n\n      - name: Deploy\n        uses: peaceiris/actions-gh-pages@v3\n        with:\n          github_token: ${{ secrets.GITHUB_TOKEN }}\n          publish_dir: ./example/build/web\n"
  },
  {
    "path": ".gitignore",
    "content": ".DS_Store\n.dart_tool/\n\n.packages\n.pub/\n\nbuild/\n"
  },
  {
    "path": ".idea/codeStyles/Project.xml",
    "content": "<component name=\"ProjectCodeStyleConfiguration\">\n  <code_scheme name=\"Project\" version=\"173\">\n    <Objective-C-extensions>\n      <file>\n        <option name=\"com.jetbrains.cidr.lang.util.OCDeclarationKind\" value=\"Import\" />\n        <option name=\"com.jetbrains.cidr.lang.util.OCDeclarationKind\" value=\"Macro\" />\n        <option name=\"com.jetbrains.cidr.lang.util.OCDeclarationKind\" value=\"Typedef\" />\n        <option name=\"com.jetbrains.cidr.lang.util.OCDeclarationKind\" value=\"Enum\" />\n        <option name=\"com.jetbrains.cidr.lang.util.OCDeclarationKind\" value=\"Constant\" />\n        <option name=\"com.jetbrains.cidr.lang.util.OCDeclarationKind\" value=\"Global\" />\n        <option name=\"com.jetbrains.cidr.lang.util.OCDeclarationKind\" value=\"Struct\" />\n        <option name=\"com.jetbrains.cidr.lang.util.OCDeclarationKind\" value=\"FunctionPredecl\" />\n        <option name=\"com.jetbrains.cidr.lang.util.OCDeclarationKind\" value=\"Function\" />\n      </file>\n      <class>\n        <option name=\"com.jetbrains.cidr.lang.util.OCDeclarationKind\" value=\"Property\" />\n        <option name=\"com.jetbrains.cidr.lang.util.OCDeclarationKind\" value=\"Synthesize\" />\n        <option name=\"com.jetbrains.cidr.lang.util.OCDeclarationKind\" value=\"InitMethod\" />\n        <option name=\"com.jetbrains.cidr.lang.util.OCDeclarationKind\" value=\"StaticMethod\" />\n        <option name=\"com.jetbrains.cidr.lang.util.OCDeclarationKind\" value=\"InstanceMethod\" />\n        <option name=\"com.jetbrains.cidr.lang.util.OCDeclarationKind\" value=\"DeallocMethod\" />\n      </class>\n      <extensions>\n        <pair source=\"cpp\" header=\"h\" fileNamingConvention=\"NONE\" />\n        <pair source=\"c\" header=\"h\" fileNamingConvention=\"NONE\" />\n      </extensions>\n    </Objective-C-extensions>\n  </code_scheme>\n</component>"
  },
  {
    "path": ".idea/libraries/Dart_SDK.xml",
    "content": "<component name=\"libraryTable\">\n  <library name=\"Dart SDK\">\n    <CLASSES>\n      <root url=\"file:///Users/developer/flutter/bin/cache/dart-sdk/lib/async\" />\n      <root url=\"file:///Users/developer/flutter/bin/cache/dart-sdk/lib/collection\" />\n      <root url=\"file:///Users/developer/flutter/bin/cache/dart-sdk/lib/convert\" />\n      <root url=\"file:///Users/developer/flutter/bin/cache/dart-sdk/lib/core\" />\n      <root url=\"file:///Users/developer/flutter/bin/cache/dart-sdk/lib/developer\" />\n      <root url=\"file:///Users/developer/flutter/bin/cache/dart-sdk/lib/html\" />\n      <root url=\"file:///Users/developer/flutter/bin/cache/dart-sdk/lib/io\" />\n      <root url=\"file:///Users/developer/flutter/bin/cache/dart-sdk/lib/isolate\" />\n      <root url=\"file:///Users/developer/flutter/bin/cache/dart-sdk/lib/math\" />\n      <root url=\"file:///Users/developer/flutter/bin/cache/dart-sdk/lib/mirrors\" />\n      <root url=\"file:///Users/developer/flutter/bin/cache/dart-sdk/lib/typed_data\" />\n    </CLASSES>\n    <JAVADOC />\n    <SOURCES />\n  </library>\n</component>"
  },
  {
    "path": ".idea/libraries/Flutter_Plugins.xml",
    "content": "<component name=\"libraryTable\">\n  <library name=\"Flutter Plugins\" type=\"FlutterPluginsLibraryType\">\n    <CLASSES>\n      <root url=\"file://$PROJECT_DIR$\" />\n    </CLASSES>\n    <JAVADOC />\n    <SOURCES />\n  </library>\n</component>"
  },
  {
    "path": ".idea/libraries/Flutter_for_Android.xml",
    "content": "<component name=\"libraryTable\">\n  <library name=\"Flutter for Android\">\n    <CLASSES>\n      <root url=\"jar:///Users/developer/flutter/bin/cache/artifacts/engine/android-arm/flutter.jar!/\" />\n    </CLASSES>\n    <JAVADOC />\n    <SOURCES />\n  </library>\n</component>\n"
  },
  {
    "path": ".idea/modules.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project version=\"4\">\n  <component name=\"ProjectModuleManager\">\n    <modules>\n      <module fileurl=\"file://$PROJECT_DIR$/data_tables.iml\" filepath=\"$PROJECT_DIR$/data_tables.iml\" />\n      <module fileurl=\"file://$PROJECT_DIR$/android/data_tables_android.iml\" filepath=\"$PROJECT_DIR$/android/data_tables_android.iml\" />\n      <module fileurl=\"file://$PROJECT_DIR$/example/android/data_tables_example_android.iml\" filepath=\"$PROJECT_DIR$/example/android/data_tables_example_android.iml\" />\n    </modules>\n  </component>\n</project>\n"
  },
  {
    "path": ".idea/runConfigurations/example_lib_main_dart.xml",
    "content": "<component name=\"ProjectRunConfigurationManager\">\n  <configuration default=\"false\" name=\"example/lib/main.dart\" type=\"FlutterRunConfigurationType\" factoryName=\"Flutter\">\n    <option name=\"filePath\" value=\"$PROJECT_DIR$/example/lib/main.dart\" />\n    <method />\n  </configuration>\n</component>"
  },
  {
    "path": ".idea/vcs.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project version=\"4\">\n  <component name=\"VcsDirectoryMappings\">\n    <mapping directory=\"$PROJECT_DIR$/../..\" vcs=\"Git\" />\n  </component>\n</project>"
  },
  {
    "path": ".idea/workspace.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project version=\"4\">\n  <component name=\"ChangeListManager\">\n    <list default=\"true\" id=\"ca160bec-0575-4943-95ce-117072a81cb2\" name=\"Default Changelist\" comment=\"\">\n      <change beforePath=\"$PROJECT_DIR$/../data_table/.gitignore\" beforeDir=\"false\" />\n      <change beforePath=\"$PROJECT_DIR$/../data_table/.idea/codeStyles/Project.xml\" beforeDir=\"false\" />\n      <change beforePath=\"$PROJECT_DIR$/../data_table/.idea/libraries/Dart_Packages.xml\" beforeDir=\"false\" />\n      <change beforePath=\"$PROJECT_DIR$/../data_table/.idea/libraries/Dart_SDK.xml\" beforeDir=\"false\" />\n      <change beforePath=\"$PROJECT_DIR$/../data_table/.idea/libraries/Flutter_Plugins.xml\" beforeDir=\"false\" />\n      <change beforePath=\"$PROJECT_DIR$/../data_table/.idea/modules.xml\" beforeDir=\"false\" />\n      <change beforePath=\"$PROJECT_DIR$/../data_table/.idea/vcs.xml\" beforeDir=\"false\" />\n      <change beforePath=\"$PROJECT_DIR$/../data_table/.idea/workspace.xml\" beforeDir=\"false\" />\n      <change beforePath=\"$PROJECT_DIR$/../data_table/.metadata\" beforeDir=\"false\" />\n      <change beforePath=\"$PROJECT_DIR$/../data_table/CHANGELOG.md\" beforeDir=\"false\" />\n      <change beforePath=\"$PROJECT_DIR$/../data_table/LICENSE\" beforeDir=\"false\" />\n      <change beforePath=\"$PROJECT_DIR$/../data_table/README.md\" beforeDir=\"false\" />\n      <change beforePath=\"$PROJECT_DIR$/../data_table/data_table.iml\" beforeDir=\"false\" />\n      <change beforePath=\"$PROJECT_DIR$/../data_table/lib/data_table.dart\" beforeDir=\"false\" />\n      <change beforePath=\"$PROJECT_DIR$/../data_table/pubspec.yaml\" beforeDir=\"false\" />\n      <change beforePath=\"$PROJECT_DIR$/../data_table/test/data_table_test.dart\" beforeDir=\"false\" />\n    </list>\n    <ignored path=\"$PROJECT_DIR$/.dart_tool/\" />\n    <ignored path=\"$PROJECT_DIR$/.idea/\" />\n    <ignored path=\"$PROJECT_DIR$/.pub/\" />\n    <ignored path=\"$PROJECT_DIR$/build/\" />\n    <ignored path=\"$PROJECT_DIR$/example/.pub/\" />\n    <ignored path=\"$PROJECT_DIR$/example/build/\" />\n    <option name=\"EXCLUDED_CONVERTED_TO_IGNORED\" value=\"true\" />\n    <option name=\"SHOW_DIALOG\" value=\"false\" />\n    <option name=\"HIGHLIGHT_CONFLICTS\" value=\"true\" />\n    <option name=\"HIGHLIGHT_NON_ACTIVE_CHANGELIST\" value=\"false\" />\n    <option name=\"LAST_RESOLUTION\" value=\"IGNORE\" />\n  </component>\n  <component name=\"FUSProjectUsageTrigger\">\n    <session id=\"-268260249\">\n      <usages-collector id=\"statistics.lifecycle.project\">\n        <counts>\n          <entry key=\"project.closed\" value=\"1\" />\n          <entry key=\"project.open.time.1\" value=\"1\" />\n          <entry key=\"project.opened\" value=\"1\" />\n        </counts>\n      </usages-collector>\n    </session>\n  </component>\n  <component name=\"FileEditorManager\">\n    <leaf SIDE_TABS_SIZE_LIMIT_KEY=\"300\">\n      <file pinned=\"false\" current-in-tab=\"true\">\n        <entry file=\"file://$PROJECT_DIR$/lib/data_tables.dart\">\n          <provider selected=\"true\" editor-type-id=\"text-editor\" />\n        </entry>\n      </file>\n      <file pinned=\"false\" current-in-tab=\"false\">\n        <entry file=\"file://$PROJECT_DIR$/example/lib/main.dart\">\n          <provider selected=\"true\" editor-type-id=\"text-editor\" />\n        </entry>\n      </file>\n    </leaf>\n  </component>\n  <component name=\"Git.Settings\">\n    <option name=\"RECENT_GIT_ROOT_PATH\" value=\"$PROJECT_DIR$/../..\" />\n  </component>\n  <component name=\"ProjectFrameBounds\">\n    <option name=\"x\" value=\"683\" />\n    <option name=\"y\" value=\"343\" />\n    <option name=\"width\" value=\"2569\" />\n    <option name=\"height\" value=\"1529\" />\n  </component>\n  <component name=\"ProjectLevelVcsManager\" settingsEditedManually=\"true\" />\n  <component name=\"ProjectView\">\n    <navigator currentView=\"ProjectPane\" proportions=\"\" version=\"1\">\n      <foldersAlwaysOnTop value=\"true\" />\n    </navigator>\n    <panes>\n      <pane id=\"ProjectPane\">\n        <subPane>\n          <expand>\n            <path>\n              <item name=\"data_tables\" type=\"b2602c69:ProjectViewProjectNode\" />\n              <item name=\"data_tables\" type=\"462c0819:PsiDirectoryNode\" />\n            </path>\n          </expand>\n          <select />\n        </subPane>\n        <option name=\"show-excluded-files\" value=\"false\" />\n      </pane>\n      <pane id=\"Scope\" />\n      <pane id=\"PackagesPane\" />\n      <pane id=\"AndroidView\" />\n    </panes>\n  </component>\n  <component name=\"PropertiesComponent\">\n    <property name=\"dart.analysis.tool.window.force.activate\" value=\"false\" />\n    <property name=\"last_opened_file_path\" value=\"$PROJECT_DIR$\" />\n    <property name=\"show.migrate.to.gradle.popup\" value=\"false\" />\n  </component>\n  <component name=\"RunDashboard\">\n    <option name=\"ruleStates\">\n      <list>\n        <RuleState>\n          <option name=\"name\" value=\"ConfigurationTypeDashboardGroupingRule\" />\n        </RuleState>\n        <RuleState>\n          <option name=\"name\" value=\"StatusDashboardGroupingRule\" />\n        </RuleState>\n      </list>\n    </option>\n  </component>\n  <component name=\"SvnConfiguration\">\n    <configuration />\n  </component>\n  <component name=\"TaskManager\">\n    <task active=\"true\" id=\"Default\" summary=\"Default task\">\n      <changelist id=\"ca160bec-0575-4943-95ce-117072a81cb2\" name=\"Default Changelist\" comment=\"\" />\n      <created>1551211010640</created>\n      <option name=\"number\" value=\"Default\" />\n      <option name=\"presentableId\" value=\"Default\" />\n      <updated>1551211010640</updated>\n    </task>\n    <servers />\n  </component>\n  <component name=\"ToolWindowManager\">\n    <frame x=\"683\" y=\"343\" width=\"2569\" height=\"1529\" extended-state=\"0\" />\n    <layout>\n      <window_info id=\"Capture Tool\" />\n      <window_info id=\"Structure\" side_tool=\"true\" />\n      <window_info id=\"Favorites\" side_tool=\"true\" />\n      <window_info id=\"Build Variants\" side_tool=\"true\" />\n      <window_info id=\"Image Layers\" />\n      <window_info id=\"Designer\" />\n      <window_info id=\"Captures\" side_tool=\"true\" />\n      <window_info active=\"true\" content_ui=\"combo\" id=\"Project\" order=\"0\" visible=\"true\" weight=\"0.20617333\" />\n      <window_info anchor=\"bottom\" id=\"Run\" />\n      <window_info anchor=\"bottom\" id=\"Dart Analysis\" visible=\"true\" weight=\"0.24913013\" />\n      <window_info anchor=\"bottom\" id=\"Logcat\" />\n      <window_info anchor=\"bottom\" id=\"TODO\" />\n      <window_info anchor=\"bottom\" id=\"Debug\" />\n      <window_info anchor=\"bottom\" id=\"Terminal\" />\n      <window_info anchor=\"bottom\" id=\"Event Log\" side_tool=\"true\" />\n      <window_info anchor=\"bottom\" id=\"Flutter Performance\" side_tool=\"true\" />\n      <window_info anchor=\"bottom\" id=\"Version Control\" show_stripe_button=\"false\" />\n      <window_info anchor=\"bottom\" id=\"Android Profiler\" show_stripe_button=\"false\" />\n      <window_info anchor=\"right\" id=\"Device File Explorer\" side_tool=\"true\" />\n      <window_info anchor=\"right\" id=\"Capture Analysis\" />\n      <window_info anchor=\"right\" id=\"Theme Preview\" />\n      <window_info anchor=\"right\" id=\"Flutter Inspector\" />\n      <window_info anchor=\"right\" id=\"Flutter Outline\" />\n      <window_info anchor=\"right\" id=\"Palette&#9;\" />\n    </layout>\n  </component>\n  <component name=\"VcsContentAnnotationSettings\">\n    <option name=\"myLimit\" value=\"2678400000\" />\n  </component>\n  <component name=\"editorHistoryManager\">\n    <entry file=\"file://$PROJECT_DIR$/lib/data_tables.dart\">\n      <provider selected=\"true\" editor-type-id=\"text-editor\" />\n    </entry>\n    <entry file=\"file://$PROJECT_DIR$/example/lib/main.dart\">\n      <provider selected=\"true\" editor-type-id=\"text-editor\" />\n    </entry>\n  </component>\n</project>"
  },
  {
    "path": ".metadata",
    "content": "# This file tracks properties of this Flutter project.\n# Used by Flutter tool to assess capabilities and perform upgrades etc.\n#\n# This file should be version controlled and should not be manually edited.\n\nversion:\n  revision: 746d5f7676e116041dd125d98ffbeeaf9251b90d\n  channel: master\n\nproject_type: plugin\n"
  },
  {
    "path": ".vscode/launch.json",
    "content": "{\n    // Use IntelliSense to learn about possible attributes.\n    // Hover to view descriptions of existing attributes.\n    // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387\n    \"version\": \"0.2.0\",\n    \"configurations\": [\n        {\n            \"name\": \"Flutter\",\n            \"request\": \"launch\",\n            \"type\": \"dart\",\n            \"program\": \"example/lib/main.dart\"\n        }\n    ]\n}"
  },
  {
    "path": ".vscode/settings.json",
    "content": "{\n    \"cSpell.words\": [\n        \"datatable\",\n        \"listview\"\n    ]\n}"
  },
  {
    "path": "CHANGELOG.md",
    "content": "## 1.4.0\n\n* fixed deprecated theme properties\n\n## 1.3.2\n\n* fixing hide select box\n* recreating example target folders\n\n## 1.3.1\n\n* support for no items\n* adding totalItems\n\n## 1.3.0\n\n* adding `showSelect'\n* adding `showSort'\n\n## 1.2.0\n\n* Stable Version\n* Added '.fromJson'\n* Updated Examples\n\n## 1.1.1-nullsafety\n\n* Updating to null safety\n\n## 1.1.0-nullsafety\n\n* Updating to null safety\n\n## 1.0.1 - 04.06.2019\n\n* Fixing Bugs on Mobile\n* Added `alwaysShowDataTable`\n\n## 1.0.0 - 04.26.2019\n\n* Adding Desktop to Example\n* Requiring `Dart 2.2.2`\n* Fixing Sort Fields\n* Fixing Bottom Bar\n* Fixed Mobile Item Builder\n\n## 0.3.0 - 04.06.2019\n\n* Making Example Desktop Aware\n\n## 0.2.4\n\n* Fixed Padding on Refresh\n* Added CupertinoRefreshController\n\n## 0.2.3\n\n* Removing SafeArea\n\n## 0.2.2\n\n* Adding Mobile Slivers\n* Updated Example\n\n## 0.2.1\n\n* Updating Toolbar on Mobile\n\n## 0.2.0\n\n* Updating Size Attribute to Detect if Tablet\n\n## 0.1.3\n\n* Adding Size Attribute to Detect if Tablet\n\n## 0.1.2\n\n* Fixing Mobile onSort Behavior\n* Fixing Bottom Bar Sizing\n\n## 0.1.1\n\n* Adding Support for Widgets when No Items Loded and Empty Items\n\n## 0.1.0\n\n* Updated Example\n* Made Tableview Stateless\n* Removed Need for Data Source\n\n## 0.0.2\n\n* Updated Example\n* Made Tableview Stateless\n* Removed Need for Data Source\n\n\n## 0.0.1\n\n* Created Data Table\n* Created Mobile ListView\n"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2020 Rody Davis\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "[![Buy Me A Coffee](https://img.shields.io/badge/Donate-Buy%20Me%20A%20Coffee-yellow.svg)](https://www.buymeacoffee.com/rodydavis)\n[![Donate](https://img.shields.io/badge/Donate-PayPal-green.svg)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=WSH3GVC49GNNJ)\n![github pages](https://github.com/rodydavis/data_tables/workflows/github%20pages/badge.svg)\n[![GitHub stars](https://img.shields.io/github/stars/rodydavis/data_tables?color=blue)](https://github.com/rodydavis/data_tables)\n[![data_tables](https://img.shields.io/pub/v/data_tables.svg)](https://pub.dev/packages/data_tables)\n\n# data_tables\n\n- Full Screen Paginated Data Tables for Tablets/Desktops\n- Mobile ListView with Action Buttons for Sorting and Selecting All\n- Supports Dark Mode\n- From Json\n\nOnline Demo: https://rodydavis.github.io/data_tables/\n\n## Getting Started\n\n- You can optionally build the listview for mobile with a builder, by default it creates a ExpansionTile with the remaining columns as children\n- The tablet breakpoint can also be set.\n\n  `bool showMobileListView;` - When set to false it will always show a data table\n\n  `int sortColumnIndex;` - Current Sorted Column\n\n  `bool sortAscending;` - Sort Order\n\n  `ValueChanged<bool> onSelectAll;` - Called for Selecting and Deselecting All\n\n  `ValueChanged<int> onRowsPerPageChanged;` - Called when rows change on data table or last row reached on mobile.\n\n  `int rowsPerPage;` - Default Rows per page\n\n  `Widget header;` - Widget header for Desktop and Tablet Data Table\n\n  `List<DataColumn> columns;` - List of Columns (Must match length of DataCells in DataSource)\n\n  `IndexedWidgetBuilder mobileItemBuilder;` - Optional Item builder for the list view for Mobile\n\n  `Size tabletBreakpoint;` - Tablet breakpoint for the screen width and height\n\n  `List<Widget> actions, selectedActions;` - Actions that show when items are selected or not\n\n  `RefreshCallback onRefresh;` - If not null the list view will be wrapped in a RefreshIndicator\n\n## Screenshots\n\n![](https://github.com/rodydavis/data_tables/blob/master/screenshots/1.PNG)\n\n![](https://github.com/rodydavis/data_tables/blob/master/screenshots/2.PNG)\n\n![](https://github.com/rodydavis/data_tables/blob/master/screenshots/3.PNG)\n\n![](https://github.com/rodydavis/data_tables/blob/master/screenshots/4.PNG)\n\n![](https://github.com/rodydavis/data_tables/blob/master/screenshots/5.PNG)\n"
  },
  {
    "path": "analysis_options.yaml",
    "content": "include: package:pedantic/analysis_options.yaml\n\nanalyzer:\n  exclude:\n    - lib/**\n    - pubspec.lock"
  },
  {
    "path": "data_tables.iml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<module type=\"JAVA_MODULE\" version=\"4\">\n  <component name=\"NewModuleRootManager\" inherit-compiler-output=\"true\">\n    <exclude-output />\n    <content url=\"file://$MODULE_DIR$\">\n      <sourceFolder url=\"file://$MODULE_DIR$/lib\" isTestSource=\"false\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/.dart_tool\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/.idea\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/.pub\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/build\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/example/.dart_tool\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/example/.pub\" />\n      <excludeFolder url=\"file://$MODULE_DIR$/example/build\" />\n    </content>\n    <orderEntry type=\"sourceFolder\" forTests=\"false\" />\n    <orderEntry type=\"library\" name=\"Dart SDK\" level=\"project\" />\n    <orderEntry type=\"library\" name=\"Flutter Plugins\" level=\"project\" />\n  </component>\n</module>"
  },
  {
    "path": "example/ios/Flutter/flutter_export_environment.sh",
    "content": "#!/bin/sh\n# This is a generated file; do not edit or check into version control.\nexport \"FLUTTER_ROOT=/usr/local/Caskroom/flutter/1.2.1/flutter\"\nexport \"FLUTTER_APPLICATION_PATH=/Users/rodydavis/Developer/GitHub/plugins/packages/data_tables/example\"\nexport \"COCOAPODS_PARALLEL_CODE_SIGN=true\"\nexport \"FLUTTER_TARGET=lib/main.dart\"\nexport \"FLUTTER_BUILD_DIR=build\"\nexport \"FLUTTER_BUILD_NAME=1.0.0\"\nexport \"FLUTTER_BUILD_NUMBER=1\"\nexport \"DART_OBFUSCATION=false\"\nexport \"TRACK_WIDGET_CREATION=false\"\nexport \"TREE_SHAKE_ICONS=false\"\nexport \"PACKAGE_CONFIG=.packages\"\n"
  },
  {
    "path": "example/linux/flutter/generated_plugin_registrant.cc",
    "content": "//\n//  Generated file. Do not edit.\n//\n\n// clang-format off\n\n#include \"generated_plugin_registrant.h\"\n\n\nvoid fl_register_plugins(FlPluginRegistry* registry) {\n}\n"
  },
  {
    "path": "example/linux/flutter/generated_plugin_registrant.h",
    "content": "//\n//  Generated file. Do not edit.\n//\n\n// clang-format off\n\n#ifndef GENERATED_PLUGIN_REGISTRANT_\n#define GENERATED_PLUGIN_REGISTRANT_\n\n#include <flutter_linux/flutter_linux.h>\n\n// Registers Flutter plugins.\nvoid fl_register_plugins(FlPluginRegistry* registry);\n\n#endif  // GENERATED_PLUGIN_REGISTRANT_\n"
  },
  {
    "path": "example/macos/Flutter/ephemeral/Flutter-Generated.xcconfig",
    "content": "// This is a generated file; do not edit or check into version control.\nFLUTTER_ROOT=/usr/local/Caskroom/flutter/1.2.1/flutter\nFLUTTER_APPLICATION_PATH=/Users/rodydavis/Developer/GitHub/plugins/packages/data_tables/example\nCOCOAPODS_PARALLEL_CODE_SIGN=true\nFLUTTER_BUILD_DIR=build\nFLUTTER_BUILD_NAME=1.0.0\nFLUTTER_BUILD_NUMBER=1\nEXCLUDED_ARCHS=arm64\nDART_OBFUSCATION=false\nTRACK_WIDGET_CREATION=false\nTREE_SHAKE_ICONS=false\nPACKAGE_CONFIG=.packages\n"
  },
  {
    "path": "example/macos/Flutter/ephemeral/flutter_export_environment.sh",
    "content": "#!/bin/sh\n# This is a generated file; do not edit or check into version control.\nexport \"FLUTTER_ROOT=/usr/local/Caskroom/flutter/1.2.1/flutter\"\nexport \"FLUTTER_APPLICATION_PATH=/Users/rodydavis/Developer/GitHub/plugins/packages/data_tables/example\"\nexport \"COCOAPODS_PARALLEL_CODE_SIGN=true\"\nexport \"FLUTTER_BUILD_DIR=build\"\nexport \"FLUTTER_BUILD_NAME=1.0.0\"\nexport \"FLUTTER_BUILD_NUMBER=1\"\nexport \"EXCLUDED_ARCHS=arm64\"\nexport \"DART_OBFUSCATION=false\"\nexport \"TRACK_WIDGET_CREATION=false\"\nexport \"TREE_SHAKE_ICONS=false\"\nexport \"PACKAGE_CONFIG=.packages\"\n"
  },
  {
    "path": "example/windows/flutter/generated_plugin_registrant.cc",
    "content": "//\n//  Generated file. Do not edit.\n//\n\n// clang-format off\n\n#include \"generated_plugin_registrant.h\"\n\n\nvoid RegisterPlugins(flutter::PluginRegistry* registry) {\n}\n"
  },
  {
    "path": "example/windows/flutter/generated_plugin_registrant.h",
    "content": "//\n//  Generated file. Do not edit.\n//\n\n// clang-format off\n\n#ifndef GENERATED_PLUGIN_REGISTRANT_\n#define GENERATED_PLUGIN_REGISTRANT_\n\n#include <flutter/plugin_registry.h>\n\n// Registers Flutter plugins.\nvoid RegisterPlugins(flutter::PluginRegistry* registry);\n\n#endif  // GENERATED_PLUGIN_REGISTRANT_\n"
  },
  {
    "path": "lib/data_tables.dart",
    "content": "import 'package:flutter/material.dart';\n\nimport 'ui/mobile_paged_listview.dart';\nimport 'ui/stateless_datatable.dart';\n\nconst _kTabletBreakpoint = Size(480, 480);\n\nclass NativeDataTable extends StatelessWidget {\n  const NativeDataTable({\n    required this.columns,\n    required this.rows,\n    this.rowsPerPage = PaginatedDataTable.defaultRowsPerPage,\n    this.header,\n    this.showSelect = true,\n    this.showSort = true,\n    this.onRowsPerPageChanged,\n    this.totalItems,\n    this.onSelectAll,\n    this.sortAscending,\n    this.sortColumnIndex,\n    this.mobileItemBuilder,\n    this.tabletBreakpoint = _kTabletBreakpoint,\n    this.actions,\n    this.firstRowIndex = 0,\n    this.selectedActions,\n    this.onRefresh,\n    this.mobileFetchNextRows = 100,\n    this.handlePrevious,\n    this.handleNext,\n    this.rowCountApproximate = false,\n    this.noItems,\n    this.mobileIsLoading,\n    this.mobileSlivers,\n    this.alwaysShowDataTable = false,\n  });\n\n  NativeDataTable.fromJson({\n    required List<Map<String, dynamic>> items,\n    List<String>? columnKeys,\n    DataColumn Function(String key)? columnBuilder,\n    DataRow Function(Map<String, dynamic> item)? rowBuilder,\n    DataCell Function(String key, dynamic value)? cellBuilder,\n    this.rowsPerPage = PaginatedDataTable.defaultRowsPerPage,\n    this.header,\n    this.showSelect = true,\n    this.showSort = true,\n    this.onRowsPerPageChanged,\n    this.onSelectAll,\n    this.sortAscending,\n    this.sortColumnIndex,\n    this.mobileItemBuilder,\n    this.totalItems,\n    this.tabletBreakpoint = _kTabletBreakpoint,\n    this.actions,\n    this.firstRowIndex = 0,\n    this.selectedActions,\n    this.onRefresh,\n    this.mobileFetchNextRows = 100,\n    this.handlePrevious,\n    this.handleNext,\n    this.rowCountApproximate = false,\n    this.noItems,\n    this.mobileIsLoading,\n    this.mobileSlivers,\n    this.alwaysShowDataTable = false,\n  })  : assert(items.isNotEmpty || columnKeys != null),\n        columns = (columnKeys ?? items[0].keys.toList()).map((e) {\n          if (columnBuilder != null) return columnBuilder(e);\n          return DataColumn(label: Text(e));\n        }).toList(),\n        rows = items.isEmpty\n            ? []\n            : items.map((e) {\n                if (rowBuilder != null) return rowBuilder(e);\n                return DataRow(\n                    cells: e.entries.map((e) {\n                  if (cellBuilder != null) return cellBuilder(e.key, e.value);\n                  return DataCell(Text(e.value.toString()));\n                }).toList());\n              }).toList();\n\n  NativeDataTable.builder({\n    required this.columns,\n    this.rowsPerPage = PaginatedDataTable.defaultRowsPerPage,\n    required int itemCount,\n    required DataRowBuilder itemBuilder,\n    this.totalItems,\n    this.header,\n    this.onRowsPerPageChanged,\n    this.onSelectAll,\n    this.sortAscending,\n    this.showSelect = true,\n    this.showSort = true,\n    this.sortColumnIndex,\n    this.mobileItemBuilder,\n    this.tabletBreakpoint = _kTabletBreakpoint,\n    this.actions,\n    this.selectedActions,\n    this.firstRowIndex = 0,\n    this.onRefresh,\n    this.mobileFetchNextRows = 100,\n    this.handlePrevious,\n    this.handleNext,\n    this.rowCountApproximate = false,\n    this.noItems,\n    this.mobileIsLoading,\n    this.mobileSlivers,\n    this.alwaysShowDataTable = false,\n  }) : rows = _buildRows(itemCount, itemBuilder);\n\n  final int? sortColumnIndex;\n  final bool? sortAscending;\n  final ValueChanged<bool?>? onSelectAll;\n  final ValueChanged<int?>? onRowsPerPageChanged;\n  final int? totalItems;\n  final int rowsPerPage;\n  final int firstRowIndex;\n\n  /// Visible on Tablet/Desktop\n  final Widget? header;\n  final List<DataColumn> columns;\n  final List<DataRow> rows;\n  final IndexedWidgetBuilder? mobileItemBuilder;\n  final Size tabletBreakpoint;\n  final List<Widget>? actions, selectedActions;\n  final int mobileFetchNextRows;\n  final RefreshCallback? onRefresh;\n  final VoidCallback? handlePrevious, handleNext;\n\n  /// Set this to [true] for using this with a api\n  final bool rowCountApproximate;\n  final bool showSelect, showSort;\n  final Widget? noItems;\n  final Widget? mobileIsLoading;\n  final List<Widget>? mobileSlivers;\n  final bool alwaysShowDataTable;\n\n  @override\n  Widget build(BuildContext context) {\n    final size = MediaQuery.of(context).size;\n    final isTablet = size.width >= tabletBreakpoint.width &&\n        size.height >= tabletBreakpoint.height;\n    if (alwaysShowDataTable || isTablet) {\n      return StatelessDataTable(\n        rows: rows,\n        firstRowIndex: firstRowIndex,\n        totalItems: totalItems,\n        header: header,\n        showCheckboxColumn: showSelect,\n        handleNext: handleNext,\n        handlePrevious: handlePrevious,\n        rowsPerPage: rowsPerPage,\n        onRowsPerPageChanged: onRowsPerPageChanged,\n        sortColumnIndex: sortColumnIndex,\n        sortAscending: sortAscending ?? false,\n        onSelectAll: showSelect ? onSelectAll : null,\n        columns: columns,\n        // ignore: avoid_redundant_argument_values\n        shrinkWrap: false,\n        rowCountApproximate: rowCountApproximate,\n        actions: [\n          ...actions ?? [],\n          Container(\n            child: onRefresh == null\n                ? null\n                : IconButton(\n                    icon: const Icon(Icons.refresh),\n                    onPressed: onRefresh,\n                  ),\n          ),\n        ],\n        selectedActions: selectedActions,\n      );\n    }\n\n    return PagedListView(\n      rows: rows,\n      slivers: mobileSlivers,\n      columns: columns,\n      showSelect: showSelect,\n      showSort: showSort,\n      loadNext: handleNext,\n      mobileItemBuilder: mobileItemBuilder,\n      actions: actions,\n      selectedActions: selectedActions,\n      onSelectAll: onSelectAll,\n      rowsPerPage: rowsPerPage,\n      sortAscending: sortAscending,\n      sortColumnIndex: sortColumnIndex,\n      onRefresh: onRefresh,\n      isRowCountApproximate: rowCountApproximate,\n      isLoading: mobileIsLoading,\n      noItems: noItems,\n    );\n  }\n\n  static List<DataRow> _buildRows(int count, DataRowBuilder builder) {\n    List<DataRow> _rows = [];\n\n    for (int i = 0; i < count; i++) {\n      _rows.add(builder(i));\n    }\n\n    return _rows;\n  }\n}\n\ntypedef DataRowBuilder = DataRow Function(int index);\n"
  },
  {
    "path": "lib/ui/mobile_paged_listview.dart",
    "content": "import 'package:flutter/material.dart';\nimport 'package:flutter/cupertino.dart' as cupertino;\n\nclass PagedListView extends StatefulWidget {\n  const PagedListView({\n    required this.rows,\n    required this.columns,\n    this.showSelect = true,\n    this.showSort = true,\n    this.mobileItemBuilder,\n    this.selectedActions,\n    this.actions,\n    this.onSelectAll,\n    this.rowsPerPage,\n    this.loadNext,\n    this.sortColumnIndex,\n    this.sortAscending,\n    this.onRefresh,\n    this.isRowCountApproximate = false,\n    this.initialScrollOffset = 0,\n    this.noItems,\n    this.isLoading,\n    this.slivers,\n  });\n\n  final double initialScrollOffset;\n  final List<DataColumn> columns;\n  final List<DataRow> rows;\n  final IndexedWidgetBuilder? mobileItemBuilder;\n  final bool showSelect, showSort;\n  final List<Widget>? actions;\n  final List<Widget>? selectedActions;\n  final ValueChanged<bool?>? onSelectAll;\n  final int? rowsPerPage;\n  final VoidCallback? loadNext;\n  final int? sortColumnIndex;\n  final bool? sortAscending;\n  final Widget? noItems, isLoading;\n  final RefreshCallback? onRefresh;\n  final bool isRowCountApproximate;\n  final List<Widget>? slivers;\n\n  @override\n  _NativePagedListViewState createState() => _NativePagedListViewState();\n}\n\nclass _NativePagedListViewState extends State<PagedListView> {\n  ScrollController? _controller;\n  PersistentBottomSheetController? _sortController;\n\n  @override\n  void initState() {\n    _controller = ScrollController(\n      initialScrollOffset: widget.initialScrollOffset * 40.0,\n    );\n    _controller!.addListener(_scrollListener);\n\n    super.initState();\n  }\n\n  @override\n  void didUpdateWidget(covariant PagedListView oldWidget) {\n    if (oldWidget.showSelect != widget.showSelect) if (mounted) setState(() {});\n    if (oldWidget.showSort != widget.showSort) if (mounted) setState(() {});\n    if (oldWidget.rows != widget.rows) if (mounted) setState(() {});\n    if (oldWidget.columns != widget.columns) if (mounted) setState(() {});\n    super.didUpdateWidget(oldWidget);\n  }\n\n  void _scrollListener() {\n    if (_controller!.offset >= _controller!.position.maxScrollExtent && !_controller!.position.outOfRange) {\n      // Bottom of List\n      widget.loadNext!();\n    }\n    if (_controller!.offset <= _controller!.position.minScrollExtent && !_controller!.position.outOfRange) {\n      // Top of List\n    }\n  }\n\n  @override\n  Widget build(BuildContext context) {\n    return Column(\n      children: <Widget>[\n        Expanded(\n          child: CustomScrollView(\n            controller: _controller,\n            slivers: <Widget>[\n              ...?widget.slivers,\n              if (widget.onRefresh == null) SliverToBoxAdapter(child: Container()) else cupertino.CupertinoSliverRefreshControl(onRefresh: widget.onRefresh),\n              if (widget.isLoading != null && widget.rows.isEmpty)\n                Center(child: widget.isLoading)\n              else\n                widget.noItems != null && widget.rows.isEmpty\n                    ? Center(child: widget.noItems)\n                    : SliverList(\n                        delegate: SliverChildBuilderDelegate(\n                          widget.mobileItemBuilder ??\n                              (context, index) {\n                                return ExpansionTile(\n                                  leading: widget.showSelect\n                                      ? Checkbox(\n                                          value: widget.rows[index].selected,\n                                          onChanged: (bool? value) {\n                                            setState(() {\n                                              widget.rows[index].onSelectChanged!(value);\n                                            });\n                                          },\n                                        )\n                                      : null,\n                                  title: widget.rows[index].cells.first.child,\n                                  children: _buildMobileChildren(index),\n                                );\n                              },\n                          childCount: widget.rows.length,\n                        ),\n                      )\n            ],\n          ),\n        ),\n        if (widget.showSelect || widget.showSort)\n          SafeArea(\n            top: false,\n            child: Container(\n              decoration: BoxDecoration(\n                  border: Border(\n                top: cupertino.BorderSide(color: Colors.grey[200]!),\n              )),\n              child: Row(\n                mainAxisAlignment: MainAxisAlignment.spaceBetween,\n                children: rowsSelected ? selectedActions : actions,\n              ),\n            ),\n          ),\n      ],\n    );\n  }\n\n  List<Widget> get actions => [\n        if (widget.showSelect)\n          IconButton(\n            icon: const Icon(Icons.select_all),\n            onPressed: () {\n              setState(() {\n                widget.onSelectAll!(true);\n              });\n            },\n          ),\n        if (widget.showSort)\n          IconButton(\n            tooltip: \"Sort Items\",\n            icon: const Icon(Icons.sort_by_alpha),\n            onPressed: () {\n              if (_sortController != null) {\n                _sortController!.close();\n                debugPrint(\"Close...\");\n                return;\n              }\n\n              _sortController = Scaffold.of(context).showBottomSheet((context) {\n                final List<DataColumn> _cols = widget.columns.where((c) => c.onSort != null).toList();\n                final bool? _sortAsc = widget.sortAscending;\n                final int? selectedIndex = widget.sortColumnIndex;\n                return Container(\n                  decoration: BoxDecoration(\n                      color: Theme.of(context).brightness == Brightness.dark ? Colors.black38 : Colors.grey[200],\n                      borderRadius: const BorderRadius.only(topLeft: Radius.circular(20), topRight: Radius.circular(20))),\n                  child: SingleChildScrollView(\n                    child: Column(\n                      mainAxisSize: MainAxisSize.min,\n                      children: <Widget>[\n                        for (var i = 0; i < _cols.length; i++) ...[\n                          ListTile(\n                            dense: true,\n                            selected: selectedIndex == i,\n                            title: _cols[i].label,\n                            subtitle: Text(widget.sortAscending! ? 'Ascending' : 'Descending'),\n                            leading: Radio<int>(\n                              groupValue: selectedIndex,\n                              onChanged: (value) {\n                                _sortController!.setState!(() {\n                                  _cols[i].onSort!(i, _sortAsc!);\n                                });\n                              },\n                              value: i,\n                            ),\n                            trailing: IconButton(\n                              icon: Icon(_sortAsc! ? Icons.arrow_upward : Icons.arrow_downward),\n                              onPressed: () {\n                                _sortController!.setState!(() {\n                                  _cols[i].onSort!(i, !_sortAsc);\n                                });\n                              },\n                            ),\n                            onTap: () {\n                              if (selectedIndex == i) {\n                                _sortController!.setState!(() {\n                                  _cols[i].onSort!(i, !_sortAsc);\n                                });\n                              } else {\n                                _sortController!.setState!(() {\n                                  _cols[i].onSort!(i, _sortAsc);\n                                });\n                              }\n                            },\n                          ),\n                        ],\n                        Container(\n                          padding: EdgeInsets.only(top: 10.0, bottom: 10.0),\n                          child: Container(\n                            child: TextButton(\n                              child: Text(\n                                \"Close\",\n                                style: Theme.of(context).textTheme.headline5,\n                              ),\n                              onPressed: () {\n                                _sortController!.close();\n                              },\n                            ),\n                          ),\n                        ),\n                      ],\n                    ),\n                  ),\n                );\n              });\n\n              _sortController!.closed.whenComplete(() {\n                debugPrint(\"Done\");\n                _sortController = null;\n              });\n            },\n          ),\n        Container(\n          child: widget.onRefresh == null\n              ? null\n              : IconButton(\n                  icon: Icon(Icons.refresh),\n                  onPressed: widget.onRefresh,\n                ),\n        ),\n        ...widget.actions ?? [],\n      ];\n  List<Widget> get selectedActions => [\n        IconButton(\n          icon: Icon(Icons.clear_all),\n          onPressed: () {\n            setState(() {\n              widget.onSelectAll!(false);\n            });\n          },\n        ),\n        ...widget.selectedActions ?? []\n      ];\n\n  bool get rowsSelected => _selectedRowCount != 0;\n\n  int get _selectedRowCount => widget.rows.where((d) => d.selected).toSet().toList().length;\n\n  List<Widget> _buildMobileChildren(int index) {\n    List<Widget> _children = [];\n    int i = 0;\n    for (var _cell in widget.rows[index].cells) {\n      _children.add(ListTile(\n        title: widget.columns[i].label,\n        subtitle: _cell.child,\n      ));\n      i++;\n    }\n    return _children;\n  }\n}\n"
  },
  {
    "path": "lib/ui/stateless_datatable.dart",
    "content": "import 'dart:ui';\n\nimport 'package:flutter/gestures.dart' show DragStartBehavior;\nimport 'package:flutter/material.dart';\nimport 'package:flutter/rendering.dart';\nimport 'package:flutter/widgets.dart';\n\nclass StatelessDataTable extends StatelessWidget {\n  StatelessDataTable({\n    Key? key,\n    this.header,\n    this.actions,\n    required this.columns,\n    required this.rows,\n    this.sortColumnIndex,\n    this.showCheckboxColumn = true,\n    this.sortAscending = true,\n    this.totalItems,\n    this.onSelectAll,\n    this.firstRowIndex = 0,\n    this.onPageChanged,\n    this.shrinkWrap = false,\n    this.selectedActions,\n    this.rowCountApproximate = false,\n    this.rowsPerPage = defaultRowsPerPage,\n    this.handlePrevious,\n    this.handleNext,\n    this.availableRowsPerPage = const <int>[defaultRowsPerPage, defaultRowsPerPage * 2, defaultRowsPerPage * 5, defaultRowsPerPage * 10],\n    this.onRowsPerPageChanged,\n    this.dragStartBehavior = DragStartBehavior.down,\n  })  : assert(columns.isNotEmpty),\n        assert(sortColumnIndex == null || (sortColumnIndex >= 0 && sortColumnIndex < columns.length)),\n        assert(rowsPerPage > 0),\n        assert(() {\n          if (onRowsPerPageChanged != null) {\n            assert(availableRowsPerPage.contains(rowsPerPage));\n          }\n          return true;\n        }()),\n        super(key: key);\n\n  final VoidCallback? handleNext, handlePrevious;\n  final Widget? header;\n  final bool showCheckboxColumn;\n  final List<Widget>? actions, selectedActions;\n  final List<DataColumn> columns;\n  final List<DataRow> rows;\n  final bool shrinkWrap;\n  final int? sortColumnIndex;\n  final int? totalItems;\n  final bool sortAscending;\n  final ValueSetter<bool?>? onSelectAll;\n  final ValueChanged<int?>? onPageChanged;\n  final int rowsPerPage;\n  static const int defaultRowsPerPage = 10;\n  final List<int> availableRowsPerPage;\n  final ValueChanged<int?>? onRowsPerPageChanged;\n  final DragStartBehavior dragStartBehavior;\n  final int firstRowIndex;\n  final bool rowCountApproximate;\n  final Map<int, DataRow> _rows = <int, DataRow>{};\n\n  DataRow _getBlankRowFor(int index) => DataRow.byIndex(index: index, cells: columns.map<DataCell>((DataColumn column) => DataCell.empty).toList());\n\n  DataRow _getProgressIndicatorRowFor(int index) {\n    bool haveProgressIndicator = false;\n    final List<DataCell> cells = columns.map<DataCell>((DataColumn column) {\n      if (!column.numeric) {\n        haveProgressIndicator = true;\n        return const DataCell(CircularProgressIndicator());\n      }\n      return DataCell.empty;\n    }).toList();\n    if (!haveProgressIndicator) {\n      haveProgressIndicator = true;\n      cells[0] = const DataCell(CircularProgressIndicator());\n    }\n    return DataRow.byIndex(index: index, cells: cells);\n  }\n\n  List<DataRow> _getRows(int firstRowIndex, int rowsPerPage) {\n    final List<DataRow> result = <DataRow>[];\n    final int nextPageFirstRowIndex = firstRowIndex + rowsPerPage;\n    bool haveProgressIndicator = false;\n    for (int index = firstRowIndex; index < nextPageFirstRowIndex; index += 1) {\n      DataRow? row;\n      if (index < rows.length || rowCountApproximate) {\n        try {\n          row = _rows.putIfAbsent(index, () => rows[index]);\n        } catch (e) {\n          print(\"Row not found => $e\");\n        }\n        if (row == null && !haveProgressIndicator) {\n          row ??= _getProgressIndicatorRowFor(index);\n          haveProgressIndicator = true;\n        }\n        row ??= _getBlankRowFor(index);\n        result.add(row);\n      }\n    }\n    //show no data\n    if (result.isEmpty) {\n      var cells = columns.map<DataCell>((DataColumn column) => DataCell.empty).toList();\n      cells[cells.length ~/ 2] = const DataCell(Text('no data'));\n      result.add(DataRow.byIndex(index: 0, cells: cells));\n    }\n\n    return result;\n  }\n\n  final GlobalKey _tableKey = GlobalKey();\n\n  int get _selectedRowCount => rows.where((d) => d.selected).toSet().toList().length;\n\n  @override\n  Widget build(BuildContext context) {\n    assert(debugCheckHasMaterialLocalizations(context));\n    final ThemeData themeData = Theme.of(context);\n    final MaterialLocalizations localizations = MaterialLocalizations.of(context);\n\n    final List<Widget> headerWidgets = <Widget>[];\n    double startPadding = 24;\n\n    if (_selectedRowCount == 0) {\n      if (header != null) {\n        headerWidgets.add(Expanded(child: header!));\n        if (header is ButtonBar) {\n          startPadding = 12.0;\n        }\n      }\n    } else {\n      headerWidgets.add(Expanded(\n        child: Text(localizations.selectedRowCountTitle(_selectedRowCount)),\n      ));\n    }\n    if (selectedActions != null && _selectedRowCount != 0) {\n      headerWidgets.addAll(selectedActions!.map<Widget>((Widget action) {\n        return Padding(\n          padding: const EdgeInsetsDirectional.only(start: 24.0 - 8.0 * 2.0),\n          child: action,\n        );\n      }).toList());\n    } else if (actions != null) {\n      headerWidgets.addAll(actions!.map<Widget>((Widget action) {\n        return Padding(\n          padding: const EdgeInsetsDirectional.only(start: 24.0 - 8.0 * 2.0),\n          child: action,\n        );\n      }).toList());\n    }\n\n    final TextStyle? footerTextStyle = themeData.textTheme.caption;\n    final List<Widget> footerWidgets = <Widget>[];\n    if (onRowsPerPageChanged != null) {\n      final List<Widget> _footerChildren =\n          availableRowsPerPage.where((int value) => value <= rows.length || value == rowsPerPage).map<DropdownMenuItem<int>>((int value) {\n        return DropdownMenuItem<int>(value: value, child: Text('$value'));\n      }).toList();\n      footerWidgets.addAll(<Widget>[\n        Container(width: 14),\n        Text(localizations.rowsPerPageTitle),\n        ConstrainedBox(\n          constraints: const BoxConstraints(minWidth: 64),\n          child: Align(\n            alignment: AlignmentDirectional.centerEnd,\n            child: DropdownButtonHideUnderline(\n              child: DropdownButton<int>(\n                items: _footerChildren as List<DropdownMenuItem<int>>?,\n                value: rowsPerPage,\n                onChanged: onRowsPerPageChanged,\n                style: footerTextStyle,\n              ),\n            ),\n          ),\n        ),\n      ]);\n    }\n    footerWidgets.addAll(<Widget>[\n      Container(width: 32),\n      Text(localizations.pageRowsInfoTitle(firstRowIndex + 1, firstRowIndex + rowsPerPage, totalItems ?? rows.length, rowCountApproximate)),\n      Container(width: 32),\n      IconButton(\n          icon: const Icon(Icons.chevron_left),\n          padding: EdgeInsets.zero,\n          tooltip: localizations.previousPageTooltip,\n          onPressed: firstRowIndex <= 0 ? null : handlePrevious),\n      Container(width: 24),\n      IconButton(\n          icon: const Icon(Icons.chevron_right),\n          padding: EdgeInsets.zero,\n          tooltip: localizations.nextPageTooltip,\n          onPressed: (!rowCountApproximate && (firstRowIndex + rowsPerPage >= (totalItems ?? rows.length))) ? null : handleNext),\n      Container(width: 14),\n    ]);\n\n    if (shrinkWrap) {\n      return SafeArea(\n        child: Column(\n          crossAxisAlignment: CrossAxisAlignment.stretch,\n          children: <Widget>[\n            if (showCheckboxColumn)\n              Semantics(\n                container: true,\n                child: DefaultTextStyle(\n                  style: _selectedRowCount > 0\n                      ? themeData.textTheme.subtitle1!.copyWith(color: themeData.colorScheme.secondary)\n                      : themeData.textTheme.headline6!.copyWith(fontWeight: FontWeight.w400),\n                  child: IconTheme.merge(\n                    data: const IconThemeData(opacity: 0.54),\n                    child: ButtonTheme(\n                      child: Ink(\n                        height: 64,\n                        color: _selectedRowCount > 0 ? themeData.secondaryHeaderColor : null,\n                        child: Padding(\n                          padding: EdgeInsetsDirectional.only(start: startPadding, end: 14),\n                          child: Row(mainAxisAlignment: MainAxisAlignment.end, children: headerWidgets),\n                        ),\n                      ),\n                    ),\n                  ),\n                ),\n              ),\n            SingleChildScrollView(\n              scrollDirection: Axis.horizontal,\n              dragStartBehavior: dragStartBehavior,\n              child: Builder(\n                builder: (BuildContext context) {\n                  final rows = _getRows(firstRowIndex, rowsPerPage);\n                  return DataTable(\n                    showCheckboxColumn: showCheckboxColumn,\n                    key: _tableKey,\n                    columns: columns,\n                    sortColumnIndex: sortColumnIndex,\n                    sortAscending: sortAscending,\n                    onSelectAll: onSelectAll,\n                    rows: rows,\n                  );\n                },\n              ),\n            ),\n            DefaultTextStyle(\n              style: footerTextStyle!,\n              child: IconTheme.merge(\n                data: const IconThemeData(opacity: 0.54),\n                child: Container(\n                  height: 56,\n                  child: SingleChildScrollView(\n                    dragStartBehavior: dragStartBehavior,\n                    scrollDirection: Axis.horizontal,\n                    reverse: true,\n                    child: Row(\n                      children: footerWidgets,\n                    ),\n                  ),\n                ),\n              ),\n            ),\n          ],\n        ),\n      );\n    }\n\n    return SafeArea(\n      child: Column(\n        crossAxisAlignment: CrossAxisAlignment.stretch,\n        children: <Widget>[\n          if (showCheckboxColumn)\n            Semantics(\n              container: true,\n              child: DefaultTextStyle(\n                style: _selectedRowCount > 0\n                    ? themeData.textTheme.subtitle1!.copyWith(color: themeData.colorScheme.secondary)\n                    : themeData.textTheme.headline6!.copyWith(fontWeight: FontWeight.w400),\n                child: IconTheme.merge(\n                  data: const IconThemeData(opacity: 0.54),\n                  child: ButtonTheme(\n                    child: Ink(\n                      height: 64,\n                      color: _selectedRowCount > 0 ? themeData.secondaryHeaderColor : null,\n                      child: Padding(\n                        padding: EdgeInsetsDirectional.only(start: startPadding, end: 14),\n                        child: Row(mainAxisAlignment: MainAxisAlignment.end, children: headerWidgets),\n                      ),\n                    ),\n                  ),\n                ),\n              ),\n            ),\n          Expanded(\n              flex: 8,\n              child: ScrollConfiguration(\n                behavior: CustomScrollBehavior(),\n                child: SingleChildScrollView(\n                    scrollDirection: Axis.vertical,\n                    child: SingleChildScrollView(\n                    scrollDirection: Axis.horizontal,\n                    child: DataTable(\n                        key: _tableKey,\n                        columns: columns,\n                        sortColumnIndex: sortColumnIndex,\n                        sortAscending: sortAscending,\n                        onSelectAll: onSelectAll,\n                        rows: _getRows(firstRowIndex, rowsPerPage)),\n                  ),\n                ),\n              ),\n          ),\n          DefaultTextStyle(\n            style: footerTextStyle!,\n            child: IconTheme.merge(\n              data: const IconThemeData(opacity: 0.54),\n              child: SizedBox(\n                height: 56,\n                child: SingleChildScrollView(\n                  dragStartBehavior: dragStartBehavior,\n                  scrollDirection: Axis.horizontal,\n                  reverse: true,\n                  child: Row(\n                    children: footerWidgets,\n                  ),\n                ),\n              ),\n            ),\n          ),\n        ],\n      ),\n    );\n  }\n}\n\nclass CustomScrollBehavior extends MaterialScrollBehavior {\n  @override\n  Set<PointerDeviceKind> get dragDevices => {\n        PointerDeviceKind.touch,\n        PointerDeviceKind.mouse,\n      };\n}\n"
  },
  {
    "path": "pubspec.yaml",
    "content": "name: data_tables\ndescription: ListView on Mobile and Stateless Data Tables on Tablets and Desktops.\nversion: 1.4.0\nhomepage: https://github.com/rodydavis/plugins\nrepository: https://github.com/rodydavis/data_tables\nenvironment:\n  sdk: '>=2.12.0-259.8.beta <3.0.0'\n\ndependencies:\n  flutter:\n    sdk: flutter\n\ndev_dependencies:\n  flutter_test:\n    sdk: flutter\n  pedantic: 1.11.1\n\nflutter:\n"
  }
]