├── linux ├── .gitignore ├── main.cc ├── flutter │ ├── generated_plugin_registrant.cc │ ├── generated_plugin_registrant.h │ ├── generated_plugins.cmake │ └── CMakeLists.txt ├── my_application.h ├── my_application.cc └── CMakeLists.txt ├── .DS_Store ├── lib ├── hive_ui.dart ├── widgets │ ├── idgenerator.dart │ ├── list_details_dialog.dart │ ├── list_pagination_view.dart │ ├── update_dialog_type_picker.dart │ ├── columns_filter_dialog.dart │ ├── number_pagination_hive_ui.dart │ ├── update_dialog.dart │ └── add_dialog.dart ├── services │ ├── flutter_clipboard_hive_ui.dart │ ├── idgenerator.dart │ └── format-time │ │ ├── english_date_locale.dart │ │ └── format_date.dart ├── core │ ├── hive_view_state.dart │ └── box_update_handler.dart ├── boxes_list.dart ├── search │ └── search_widget.dart └── extensions.dart ├── AddNewRow.png ├── EditRow.png ├── TableList.png ├── ios ├── Runner │ ├── Runner-Bridging-Header.h │ ├── Assets.xcassets │ │ ├── LaunchImage.imageset │ │ │ ├── LaunchImage.png │ │ │ ├── LaunchImage@2x.png │ │ │ ├── LaunchImage@3x.png │ │ │ ├── README.md │ │ │ └── Contents.json │ │ └── AppIcon.appiconset │ │ │ ├── Icon-App-20x20@1x.png │ │ │ ├── Icon-App-20x20@2x.png │ │ │ ├── Icon-App-20x20@3x.png │ │ │ ├── Icon-App-29x29@1x.png │ │ │ ├── Icon-App-29x29@2x.png │ │ │ ├── Icon-App-29x29@3x.png │ │ │ ├── Icon-App-40x40@1x.png │ │ │ ├── Icon-App-40x40@2x.png │ │ │ ├── Icon-App-40x40@3x.png │ │ │ ├── Icon-App-60x60@2x.png │ │ │ ├── Icon-App-60x60@3x.png │ │ │ ├── Icon-App-76x76@1x.png │ │ │ ├── Icon-App-76x76@2x.png │ │ │ ├── Icon-App-1024x1024@1x.png │ │ │ ├── Icon-App-83.5x83.5@2x.png │ │ │ └── Contents.json │ ├── AppDelegate.swift │ ├── Base.lproj │ │ ├── Main.storyboard │ │ └── LaunchScreen.storyboard │ └── Info.plist ├── Flutter │ ├── Debug.xcconfig │ ├── Release.xcconfig │ └── AppFrameworkInfo.plist ├── Runner.xcodeproj │ ├── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ ├── WorkspaceSettings.xcsettings │ │ │ └── IDEWorkspaceChecks.plist │ └── xcshareddata │ │ └── xcschemes │ │ └── Runner.xcscheme ├── Runner.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ ├── WorkspaceSettings.xcsettings │ │ └── IDEWorkspaceChecks.plist ├── .gitignore └── Podfile ├── web ├── favicon.png ├── icons │ ├── Icon-192.png │ ├── Icon-512.png │ ├── Icon-maskable-192.png │ └── Icon-maskable-512.png ├── manifest.json └── index.html ├── TableDetails.png ├── android ├── gradle.properties ├── app │ ├── src │ │ ├── main │ │ │ ├── res │ │ │ │ ├── mipmap-hdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-mdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-xhdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-xxhdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-xxxhdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ ├── drawable │ │ │ │ │ └── launch_background.xml │ │ │ │ ├── drawable-v21 │ │ │ │ │ └── launch_background.xml │ │ │ │ ├── values │ │ │ │ │ └── styles.xml │ │ │ │ └── values-night │ │ │ │ │ └── styles.xml │ │ │ ├── kotlin │ │ │ │ └── com │ │ │ │ │ └── hive_ui_example │ │ │ │ │ └── hive_ui_example │ │ │ │ │ └── MainActivity.kt │ │ │ └── AndroidManifest.xml │ │ ├── debug │ │ │ └── AndroidManifest.xml │ │ └── profile │ │ │ └── AndroidManifest.xml │ └── build.gradle ├── gradle │ └── wrapper │ │ └── gradle-wrapper.properties ├── .gitignore ├── settings.gradle ├── build.gradle └── hive_ui_example_android.iml ├── macos ├── Runner │ ├── Configs │ │ ├── Debug.xcconfig │ │ ├── Release.xcconfig │ │ ├── Warnings.xcconfig │ │ └── AppInfo.xcconfig │ ├── Assets.xcassets │ │ └── AppIcon.appiconset │ │ │ ├── app_icon_16.png │ │ │ ├── app_icon_32.png │ │ │ ├── app_icon_64.png │ │ │ ├── app_icon_1024.png │ │ │ ├── app_icon_128.png │ │ │ ├── app_icon_256.png │ │ │ ├── app_icon_512.png │ │ │ └── Contents.json │ ├── AppDelegate.swift │ ├── Release.entitlements │ ├── DebugProfile.entitlements │ ├── MainFlutterWindow.swift │ └── Info.plist ├── .gitignore ├── Flutter │ ├── Flutter-Debug.xcconfig │ ├── Flutter-Release.xcconfig │ └── GeneratedPluginRegistrant.swift ├── Runner.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist ├── Runner.xcodeproj │ ├── project.xcworkspace │ │ └── xcshareddata │ │ │ └── IDEWorkspaceChecks.plist │ └── xcshareddata │ │ └── xcschemes │ │ └── Runner.xcscheme └── Podfile ├── windows ├── runner │ ├── resources │ │ └── app_icon.ico │ ├── resource.h │ ├── utils.h │ ├── runner.exe.manifest │ ├── flutter_window.h │ ├── main.cpp │ ├── CMakeLists.txt │ ├── utils.cpp │ ├── flutter_window.cpp │ ├── Runner.rc │ ├── win32_window.h │ └── win32_window.cpp ├── flutter │ ├── generated_plugin_registrant.cc │ ├── generated_plugin_registrant.h │ ├── generated_plugins.cmake │ └── CMakeLists.txt ├── .gitignore └── CMakeLists.txt ├── CHANGELOG.md ├── hive_ui_example.iml ├── example └── lib │ ├── models │ ├── organization │ │ ├── organization.dart │ │ └── organization.g.dart │ └── customer │ │ ├── customer.dart │ │ └── customer.g.dart │ ├── boxes.dart │ └── main.dart ├── Contributing.md ├── LICENSE ├── test ├── widget_test.dart └── core │ └── box_update_handler_test.dart ├── .gitignore ├── analysis_options.yaml ├── pubspec.yaml └── README.md /linux/.gitignore: -------------------------------------------------------------------------------- 1 | flutter/ephemeral 2 | -------------------------------------------------------------------------------- /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmrSaied/hive_ui/HEAD/.DS_Store -------------------------------------------------------------------------------- /lib/hive_ui.dart: -------------------------------------------------------------------------------- 1 | library hive_ui; 2 | 3 | export 'boxes_view.dart'; 4 | -------------------------------------------------------------------------------- /AddNewRow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmrSaied/hive_ui/HEAD/AddNewRow.png -------------------------------------------------------------------------------- /EditRow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmrSaied/hive_ui/HEAD/EditRow.png -------------------------------------------------------------------------------- /TableList.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmrSaied/hive_ui/HEAD/TableList.png -------------------------------------------------------------------------------- /ios/Runner/Runner-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | #import "GeneratedPluginRegistrant.h" 2 | -------------------------------------------------------------------------------- /web/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmrSaied/hive_ui/HEAD/web/favicon.png -------------------------------------------------------------------------------- /TableDetails.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmrSaied/hive_ui/HEAD/TableDetails.png -------------------------------------------------------------------------------- /web/icons/Icon-192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmrSaied/hive_ui/HEAD/web/icons/Icon-192.png -------------------------------------------------------------------------------- /web/icons/Icon-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmrSaied/hive_ui/HEAD/web/icons/Icon-512.png -------------------------------------------------------------------------------- /web/icons/Icon-maskable-192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmrSaied/hive_ui/HEAD/web/icons/Icon-maskable-192.png -------------------------------------------------------------------------------- /web/icons/Icon-maskable-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmrSaied/hive_ui/HEAD/web/icons/Icon-maskable-512.png -------------------------------------------------------------------------------- /android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx1536M 2 | android.useAndroidX=true 3 | android.enableJetifier=true 4 | -------------------------------------------------------------------------------- /macos/Runner/Configs/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include "../../Flutter/Flutter-Debug.xcconfig" 2 | #include "Warnings.xcconfig" 3 | -------------------------------------------------------------------------------- /macos/Runner/Configs/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include "../../Flutter/Flutter-Release.xcconfig" 2 | #include "Warnings.xcconfig" 3 | -------------------------------------------------------------------------------- /windows/runner/resources/app_icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmrSaied/hive_ui/HEAD/windows/runner/resources/app_icon.ico -------------------------------------------------------------------------------- /macos/.gitignore: -------------------------------------------------------------------------------- 1 | # Flutter-related 2 | **/Flutter/ephemeral/ 3 | **/Pods/ 4 | 5 | # Xcode-related 6 | **/dgph 7 | **/xcuserdata/ 8 | -------------------------------------------------------------------------------- /ios/Flutter/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /ios/Flutter/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmrSaied/hive_ui/HEAD/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmrSaied/hive_ui/HEAD/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmrSaied/hive_ui/HEAD/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmrSaied/hive_ui/HEAD/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmrSaied/hive_ui/HEAD/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /lib/widgets/idgenerator.dart: -------------------------------------------------------------------------------- 1 | import 'package:uuid/uuid.dart'; 2 | class IdGenerator { 3 | static String generate() { 4 | return const Uuid().v4(); 5 | } 6 | } -------------------------------------------------------------------------------- /macos/Flutter/Flutter-Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" 2 | #include "ephemeral/Flutter-Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /macos/Flutter/Flutter-Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" 2 | #include "ephemeral/Flutter-Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmrSaied/hive_ui/HEAD/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmrSaied/hive_ui/HEAD/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmrSaied/hive_ui/HEAD/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmrSaied/hive_ui/HEAD/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmrSaied/hive_ui/HEAD/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmrSaied/hive_ui/HEAD/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmrSaied/hive_ui/HEAD/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmrSaied/hive_ui/HEAD/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmrSaied/hive_ui/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmrSaied/hive_ui/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmrSaied/hive_ui/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmrSaied/hive_ui/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmrSaied/hive_ui/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmrSaied/hive_ui/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmrSaied/hive_ui/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmrSaied/hive_ui/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmrSaied/hive_ui/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmrSaied/hive_ui/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmrSaied/hive_ui/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmrSaied/hive_ui/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmrSaied/hive_ui/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmrSaied/hive_ui/HEAD/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmrSaied/hive_ui/HEAD/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmrSaied/hive_ui/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmrSaied/hive_ui/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png -------------------------------------------------------------------------------- /linux/main.cc: -------------------------------------------------------------------------------- 1 | #include "my_application.h" 2 | 3 | int main(int argc, char** argv) { 4 | g_autoptr(MyApplication) app = my_application_new(); 5 | return g_application_run(G_APPLICATION(app), argc, argv); 6 | } 7 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /android/app/src/main/kotlin/com/hive_ui_example/hive_ui_example/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.hive_ui_example.hive_ui_example 2 | 3 | import io.flutter.embedding.android.FlutterActivity 4 | 5 | class MainActivity: FlutterActivity() { 6 | } 7 | -------------------------------------------------------------------------------- /linux/flutter/generated_plugin_registrant.cc: -------------------------------------------------------------------------------- 1 | // 2 | // Generated file. Do not edit. 3 | // 4 | 5 | // clang-format off 6 | 7 | #include "generated_plugin_registrant.h" 8 | 9 | 10 | void fl_register_plugins(FlPluginRegistry* registry) { 11 | } 12 | -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | zipStoreBase=GRADLE_USER_HOME 4 | zipStorePath=wrapper/dists 5 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-all.zip 6 | -------------------------------------------------------------------------------- /windows/flutter/generated_plugin_registrant.cc: -------------------------------------------------------------------------------- 1 | // 2 | // Generated file. Do not edit. 3 | // 4 | 5 | // clang-format off 6 | 7 | #include "generated_plugin_registrant.h" 8 | 9 | 10 | void RegisterPlugins(flutter::PluginRegistry* registry) { 11 | } 12 | -------------------------------------------------------------------------------- /macos/Runner/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import Cocoa 2 | import FlutterMacOS 3 | 4 | @NSApplicationMain 5 | class AppDelegate: FlutterAppDelegate { 6 | override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { 7 | return true 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /macos/Runner/Release.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.app-sandbox 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 0.0.1 2 | 3 | * TODO: Describe initial release. 4 | ## 1.0.1 5 | * Add size for table 6 | ## 1.0.2 7 | * Update links Related to Issue Tracker and Contributing Rules 8 | ## 1.0.3 9 | * Update dialog ui update 10 | * add row dialog ui update 11 | ## 1.0.4 12 | * Update description 13 | -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /macos/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /android/.gitignore: -------------------------------------------------------------------------------- 1 | gradle-wrapper.jar 2 | /.gradle 3 | /captures/ 4 | /gradlew 5 | /gradlew.bat 6 | /local.properties 7 | GeneratedPluginRegistrant.java 8 | 9 | # Remember to never publicly share your keystore. 10 | # See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app 11 | key.properties 12 | **/*.keystore 13 | **/*.jks 14 | -------------------------------------------------------------------------------- /macos/Flutter/GeneratedPluginRegistrant.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Generated file. Do not edit. 3 | // 4 | 5 | import FlutterMacOS 6 | import Foundation 7 | 8 | import path_provider_foundation 9 | 10 | func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { 11 | PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) 12 | } 13 | -------------------------------------------------------------------------------- /windows/.gitignore: -------------------------------------------------------------------------------- 1 | flutter/ephemeral/ 2 | 3 | # Visual Studio user-specific files. 4 | *.suo 5 | *.user 6 | *.userosscache 7 | *.sln.docstates 8 | 9 | # Visual Studio build-related files. 10 | x64/ 11 | x86/ 12 | 13 | # Visual Studio cache files 14 | # files ending in .cache can be ignored 15 | *.[Cc]ache 16 | # but keep track of directories ending in .cache 17 | !*.[Cc]ache/ 18 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md: -------------------------------------------------------------------------------- 1 | # Launch Screen Assets 2 | 3 | You can customize the launch screen with your own desired assets by replacing the image files in this directory. 4 | 5 | You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. -------------------------------------------------------------------------------- /linux/flutter/generated_plugin_registrant.h: -------------------------------------------------------------------------------- 1 | // 2 | // Generated file. Do not edit. 3 | // 4 | 5 | // clang-format off 6 | 7 | #ifndef GENERATED_PLUGIN_REGISTRANT_ 8 | #define GENERATED_PLUGIN_REGISTRANT_ 9 | 10 | #include 11 | 12 | // Registers Flutter plugins. 13 | void fl_register_plugins(FlPluginRegistry* registry); 14 | 15 | #endif // GENERATED_PLUGIN_REGISTRANT_ 16 | -------------------------------------------------------------------------------- /windows/flutter/generated_plugin_registrant.h: -------------------------------------------------------------------------------- 1 | // 2 | // Generated file. Do not edit. 3 | // 4 | 5 | // clang-format off 6 | 7 | #ifndef GENERATED_PLUGIN_REGISTRANT_ 8 | #define GENERATED_PLUGIN_REGISTRANT_ 9 | 10 | #include 11 | 12 | // Registers Flutter plugins. 13 | void RegisterPlugins(flutter::PluginRegistry* registry); 14 | 15 | #endif // GENERATED_PLUGIN_REGISTRANT_ 16 | -------------------------------------------------------------------------------- /macos/Runner/DebugProfile.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.app-sandbox 6 | 7 | com.apple.security.cs.allow-jit 8 | 9 | com.apple.security.network.server 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /ios/Runner/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | import Flutter 3 | 4 | @UIApplicationMain 5 | @objc class AppDelegate: FlutterAppDelegate { 6 | override func application( 7 | _ application: UIApplication, 8 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? 9 | ) -> Bool { 10 | GeneratedPluginRegistrant.register(with: self) 11 | return super.application(application, didFinishLaunchingWithOptions: launchOptions) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /android/app/src/profile/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /lib/services/flutter_clipboard_hive_ui.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/services.dart'; 2 | 3 | class FlutterClipboardHiveUi { 4 | static Future copy(String text) { 5 | return Clipboard.setData(ClipboardData(text: text)); 6 | } 7 | 8 | static Future getData() async { 9 | var result = await Clipboard.getData(Clipboard.kTextPlain); 10 | if (result != null) { 11 | return result.text; 12 | } else { 13 | return null; 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /linux/my_application.h: -------------------------------------------------------------------------------- 1 | #ifndef FLUTTER_MY_APPLICATION_H_ 2 | #define FLUTTER_MY_APPLICATION_H_ 3 | 4 | #include 5 | 6 | G_DECLARE_FINAL_TYPE(MyApplication, my_application, MY, APPLICATION, 7 | GtkApplication) 8 | 9 | /** 10 | * my_application_new: 11 | * 12 | * Creates a new Flutter-based application. 13 | * 14 | * Returns: a new #MyApplication. 15 | */ 16 | MyApplication* my_application_new(); 17 | 18 | #endif // FLUTTER_MY_APPLICATION_H_ 19 | -------------------------------------------------------------------------------- /macos/Runner/MainFlutterWindow.swift: -------------------------------------------------------------------------------- 1 | import Cocoa 2 | import FlutterMacOS 3 | 4 | class MainFlutterWindow: NSWindow { 5 | override func awakeFromNib() { 6 | let flutterViewController = FlutterViewController.init() 7 | let windowFrame = self.frame 8 | self.contentViewController = flutterViewController 9 | self.setFrame(windowFrame, display: true) 10 | 11 | RegisterGeneratedPlugins(registry: flutterViewController) 12 | 13 | super.awakeFromNib() 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /windows/runner/resource.h: -------------------------------------------------------------------------------- 1 | //{{NO_DEPENDENCIES}} 2 | // Microsoft Visual C++ generated include file. 3 | // Used by Runner.rc 4 | // 5 | #define IDI_APP_ICON 101 6 | 7 | // Next default values for new objects 8 | // 9 | #ifdef APSTUDIO_INVOKED 10 | #ifndef APSTUDIO_READONLY_SYMBOLS 11 | #define _APS_NEXT_RESOURCE_VALUE 102 12 | #define _APS_NEXT_COMMAND_VALUE 40001 13 | #define _APS_NEXT_CONTROL_VALUE 1001 14 | #define _APS_NEXT_SYMED_VALUE 101 15 | #endif 16 | #endif 17 | -------------------------------------------------------------------------------- /android/settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | 3 | def localPropertiesFile = new File(rootProject.projectDir, "local.properties") 4 | def properties = new Properties() 5 | 6 | assert localPropertiesFile.exists() 7 | localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) } 8 | 9 | def flutterSdkPath = properties.getProperty("flutter.sdk") 10 | assert flutterSdkPath != null, "flutter.sdk not set in local.properties" 11 | apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle" 12 | -------------------------------------------------------------------------------- /android/app/src/main/res/drawable/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-v21/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "LaunchImage.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "LaunchImage@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "LaunchImage@3x.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /macos/Runner/Configs/Warnings.xcconfig: -------------------------------------------------------------------------------- 1 | WARNING_CFLAGS = -Wall -Wconditional-uninitialized -Wnullable-to-nonnull-conversion -Wmissing-method-return-type -Woverlength-strings 2 | GCC_WARN_UNDECLARED_SELECTOR = YES 3 | CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES 4 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE 5 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES 6 | CLANG_WARN_PRAGMA_PACK = YES 7 | CLANG_WARN_STRICT_PROTOTYPES = YES 8 | CLANG_WARN_COMMA = YES 9 | GCC_WARN_STRICT_SELECTOR_MATCH = YES 10 | CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES 11 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES 12 | GCC_WARN_SHADOW = YES 13 | CLANG_WARN_UNREACHABLE_CODE = YES 14 | -------------------------------------------------------------------------------- /hive_ui_example.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /macos/Runner/Configs/AppInfo.xcconfig: -------------------------------------------------------------------------------- 1 | // Application-level settings for the Runner target. 2 | // 3 | // This may be replaced with something auto-generated from metadata (e.g., pubspec.yaml) in the 4 | // future. If not, the values below would default to using the project name when this becomes a 5 | // 'flutter create' template. 6 | 7 | // The application's name. By default this is also the title of the Flutter window. 8 | PRODUCT_NAME = hive_ui_example 9 | 10 | // The application's bundle identifier 11 | PRODUCT_BUNDLE_IDENTIFIER = com.hiveuiexample.hiveUiExample 12 | 13 | // The copyright displayed in application information 14 | PRODUCT_COPYRIGHT = Copyright © 2023 com.hive_ui_example. All rights reserved. 15 | -------------------------------------------------------------------------------- /ios/.gitignore: -------------------------------------------------------------------------------- 1 | **/dgph 2 | *.mode1v3 3 | *.mode2v3 4 | *.moved-aside 5 | *.pbxuser 6 | *.perspectivev3 7 | **/*sync/ 8 | .sconsign.dblite 9 | .tags* 10 | **/.vagrant/ 11 | **/DerivedData/ 12 | Icon? 13 | **/Pods/ 14 | **/.symlinks/ 15 | profile 16 | xcuserdata 17 | **/.generated/ 18 | Flutter/App.framework 19 | Flutter/Flutter.framework 20 | Flutter/Flutter.podspec 21 | Flutter/Generated.xcconfig 22 | Flutter/ephemeral/ 23 | Flutter/app.flx 24 | Flutter/app.zip 25 | Flutter/flutter_assets/ 26 | Flutter/flutter_export_environment.sh 27 | ServiceDefinitions.json 28 | Runner/GeneratedPluginRegistrant.* 29 | 30 | # Exceptions to above rules. 31 | !default.mode1v3 32 | !default.mode2v3 33 | !default.pbxuser 34 | !default.perspectivev3 35 | -------------------------------------------------------------------------------- /lib/widgets/list_details_dialog.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class ListDetailsDialog extends StatelessWidget { 4 | final String title; 5 | final List values; 6 | const ListDetailsDialog({Key? key, required this.values, required this.title}) 7 | : super(key: key); 8 | 9 | @override 10 | Widget build(BuildContext context) { 11 | return AlertDialog( 12 | title: Text(title), 13 | content: SingleChildScrollView( 14 | child: Column( 15 | children: values 16 | .map((value) => ListTile( 17 | title: Text('$value'), 18 | )) 19 | .toList(), 20 | ), 21 | ), 22 | ); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | ext.kotlin_version = '1.6.10' 3 | repositories { 4 | google() 5 | mavenCentral() 6 | } 7 | 8 | dependencies { 9 | classpath 'com.android.tools.build:gradle:7.1.2' 10 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 11 | } 12 | } 13 | 14 | allprojects { 15 | repositories { 16 | google() 17 | mavenCentral() 18 | } 19 | } 20 | 21 | rootProject.buildDir = '../build' 22 | subprojects { 23 | project.buildDir = "${rootProject.buildDir}/${project.name}" 24 | } 25 | subprojects { 26 | project.evaluationDependsOn(':app') 27 | } 28 | 29 | task clean(type: Delete) { 30 | delete rootProject.buildDir 31 | } 32 | -------------------------------------------------------------------------------- /windows/runner/utils.h: -------------------------------------------------------------------------------- 1 | #ifndef RUNNER_UTILS_H_ 2 | #define RUNNER_UTILS_H_ 3 | 4 | #include 5 | #include 6 | 7 | // Creates a console for the process, and redirects stdout and stderr to 8 | // it for both the runner and the Flutter library. 9 | void CreateAndAttachConsole(); 10 | 11 | // Takes a null-terminated wchar_t* encoded in UTF-16 and returns a std::string 12 | // encoded in UTF-8. Returns an empty std::string on failure. 13 | std::string Utf8FromUtf16(const wchar_t* utf16_string); 14 | 15 | // Gets the command line arguments passed in as a std::vector, 16 | // encoded in UTF-8. Returns an empty std::vector on failure. 17 | std::vector GetCommandLineArguments(); 18 | 19 | #endif // RUNNER_UTILS_H_ 20 | -------------------------------------------------------------------------------- /example/lib/models/organization/organization.dart: -------------------------------------------------------------------------------- 1 | import 'package:hive_flutter/adapters.dart'; 2 | 3 | part 'organization.g.dart'; 4 | 5 | @HiveType(typeId: 2) 6 | class Organization { 7 | @HiveField(0) 8 | final String id; 9 | @HiveField(1) 10 | final String name; 11 | @HiveField(2) 12 | final String jobTitle; 13 | 14 | Organization({ 15 | required this.id, 16 | required this.name, 17 | required this.jobTitle, 18 | }); 19 | 20 | Map toJson() => { 21 | "id": id, 22 | "name": name, 23 | "jobTitle": jobTitle, 24 | }; 25 | factory Organization.fromJson(dynamic json) => Organization( 26 | id: json['id'], 27 | name: json['name'], 28 | jobTitle: json['jobTitle'], 29 | ); 30 | } 31 | -------------------------------------------------------------------------------- /lib/services/idgenerator.dart: -------------------------------------------------------------------------------- 1 | import 'dart:math' as math; 2 | 3 | class IdGenerator { 4 | static String generate() { 5 | math.Random random = math.Random(DateTime.now().millisecond); 6 | const String hexDigits = "0123456789abcdef"; 7 | int length = 36; 8 | final List uuid = List.generate(length, (_) => ""); 9 | 10 | for (int i = 0; i < length; i++) { 11 | final int hexPos = random.nextInt(16); 12 | uuid[i] = (hexDigits.substring(hexPos, hexPos + 1)); 13 | } 14 | 15 | int pos = (int.parse(uuid[19], radix: 16) & 0x3) | 0x8; 16 | 17 | uuid[14] = "4"; 18 | uuid[19] = hexDigits.substring(pos, pos + 1); 19 | 20 | uuid[8] = uuid[13] = uuid[18] = uuid[23] = "-"; 21 | 22 | final StringBuffer buffer = StringBuffer(); 23 | buffer.writeAll(uuid); 24 | return buffer.toString(); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /linux/flutter/generated_plugins.cmake: -------------------------------------------------------------------------------- 1 | # 2 | # Generated file, do not edit. 3 | # 4 | 5 | list(APPEND FLUTTER_PLUGIN_LIST 6 | ) 7 | 8 | list(APPEND FLUTTER_FFI_PLUGIN_LIST 9 | ) 10 | 11 | set(PLUGIN_BUNDLED_LIBRARIES) 12 | 13 | foreach(plugin ${FLUTTER_PLUGIN_LIST}) 14 | add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/linux plugins/${plugin}) 15 | target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) 16 | list(APPEND PLUGIN_BUNDLED_LIBRARIES $) 17 | list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) 18 | endforeach(plugin) 19 | 20 | foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) 21 | add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/linux plugins/${ffi_plugin}) 22 | list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) 23 | endforeach(ffi_plugin) 24 | -------------------------------------------------------------------------------- /windows/flutter/generated_plugins.cmake: -------------------------------------------------------------------------------- 1 | # 2 | # Generated file, do not edit. 3 | # 4 | 5 | list(APPEND FLUTTER_PLUGIN_LIST 6 | ) 7 | 8 | list(APPEND FLUTTER_FFI_PLUGIN_LIST 9 | ) 10 | 11 | set(PLUGIN_BUNDLED_LIBRARIES) 12 | 13 | foreach(plugin ${FLUTTER_PLUGIN_LIST}) 14 | add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/windows plugins/${plugin}) 15 | target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) 16 | list(APPEND PLUGIN_BUNDLED_LIBRARIES $) 17 | list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) 18 | endforeach(plugin) 19 | 20 | foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) 21 | add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/windows plugins/${ffi_plugin}) 22 | list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) 23 | endforeach(ffi_plugin) 24 | -------------------------------------------------------------------------------- /lib/widgets/list_pagination_view.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | import 'number_pagination_hive_ui.dart'; 4 | 5 | class ListPaginationView extends StatelessWidget { 6 | final Function(int) onPageChanged; 7 | final int pageTotal; 8 | final int pageInit; 9 | 10 | const ListPaginationView({ 11 | Key? key, 12 | required this.onPageChanged, 13 | required this.pageTotal, 14 | required this.pageInit, 15 | }) : super(key: key); 16 | 17 | @override 18 | Widget build(BuildContext context) { 19 | return NumberPaginationPageHiveUi( 20 | pageTotal: pageTotal, 21 | onPageChanged: (page) => onPageChanged(page - 1), 22 | // initially selected index 23 | pageInit: pageInit + 1, 24 | iconPrevious: const Icon(Icons.arrow_back), 25 | iconNext: const Icon(Icons.arrow_forward), 26 | ); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /ios/Flutter/AppFrameworkInfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | App 9 | CFBundleIdentifier 10 | io.flutter.flutter.app 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | App 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1.0 23 | MinimumOSVersion 24 | 11.0 25 | 26 | 27 | -------------------------------------------------------------------------------- /Contributing.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | We welcome contributions to the hive_ui package! If you have an idea for a new feature or a bug to report, please open an issue on GitHub. 3 | 4 | 1-**Fork** the repository on GitHub. 5 | 6 | 2-**Clone** the repository to your local machine. 7 | 8 | 3-**Create a new branch** 9 | 10 | 4-**Make your changes** and **commit** them 11 | 12 | 5-**Push** your changes to your fork on GitHub. 13 | 14 | 6-**Create a pull request** to the 'master' branch of the original repository. 15 | 16 | 7-**Make sure all tests pass** before submitting your pull request. 17 | 18 | 8-**Include a clear and detailed description** of your changes in the pull request. 19 | 20 | 9-**Be responsive** to feedback on your pull request. 21 | 22 | If you're planning to work on a larger feature, it's a good idea to open an issue first to discuss it with the maintainers. 23 | 24 | 25 | Thanks for contributing to hive_ui! 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /lib/widgets/update_dialog_type_picker.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:hive_ui/widgets/update_dialog.dart'; 3 | 4 | class UpdateDialogTypePicker extends StatelessWidget { 5 | final UpdateDialogType selectedType; 6 | final void Function(UpdateDialogType? type) onTypeChanged; 7 | const UpdateDialogTypePicker({ 8 | Key? key, 9 | required this.selectedType, 10 | required this.onTypeChanged, 11 | }) : super(key: key); 12 | 13 | @override 14 | Widget build(BuildContext context) { 15 | return Row( 16 | children: UpdateDialogType.values 17 | .map( 18 | (e) => Flexible( 19 | child: RadioListTile( 20 | value: e, 21 | groupValue: selectedType, 22 | onChanged: onTypeChanged, 23 | title: Text(e.name), 24 | ), 25 | ), 26 | ) 27 | .toList(), 28 | ); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /windows/runner/runner.exe.manifest: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PerMonitorV2 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /windows/runner/flutter_window.h: -------------------------------------------------------------------------------- 1 | #ifndef RUNNER_FLUTTER_WINDOW_H_ 2 | #define RUNNER_FLUTTER_WINDOW_H_ 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | #include "win32_window.h" 10 | 11 | // A window that does nothing but host a Flutter view. 12 | class FlutterWindow : public Win32Window { 13 | public: 14 | // Creates a new FlutterWindow hosting a Flutter view running |project|. 15 | explicit FlutterWindow(const flutter::DartProject& project); 16 | virtual ~FlutterWindow(); 17 | 18 | protected: 19 | // Win32Window: 20 | bool OnCreate() override; 21 | void OnDestroy() override; 22 | LRESULT MessageHandler(HWND window, UINT const message, WPARAM const wparam, 23 | LPARAM const lparam) noexcept override; 24 | 25 | private: 26 | // The project to run. 27 | flutter::DartProject project_; 28 | 29 | // The Flutter instance hosted by this window. 30 | std::unique_ptr flutter_controller_; 31 | }; 32 | 33 | #endif // RUNNER_FLUTTER_WINDOW_H_ 34 | -------------------------------------------------------------------------------- /android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /android/app/src/main/res/values-night/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Amr Saied 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /test/widget_test.dart: -------------------------------------------------------------------------------- 1 | // This is a basic Flutter widget test. 2 | // 3 | // To perform an interaction with a widget in your test, use the WidgetTester 4 | // utility in the flutter_test package. For example, you can send tap and scroll 5 | // gestures. You can also use WidgetTester to find child widgets in the widget 6 | // tree, read text, and verify that the values of widget properties are correct. 7 | 8 | import 'package:flutter/material.dart'; 9 | import 'package:flutter_test/flutter_test.dart'; 10 | 11 | 12 | import '../example/lib/main.dart'; 13 | 14 | void main() { 15 | testWidgets('Counter increments smoke test', (WidgetTester tester) async { 16 | // Build our app and trigger a frame. 17 | await tester.pumpWidget(const App()); 18 | 19 | // Verify that our counter starts at 0. 20 | expect(find.text('0'), findsOneWidget); 21 | expect(find.text('1'), findsNothing); 22 | 23 | // Tap the '+' icon and trigger a frame. 24 | await tester.tap(find.byIcon(Icons.add)); 25 | await tester.pump(); 26 | 27 | // Verify that our counter has incremented. 28 | expect(find.text('0'), findsNothing); 29 | expect(find.text('1'), findsOneWidget); 30 | }); 31 | } 32 | -------------------------------------------------------------------------------- /macos/Runner/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIconFile 10 | 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | $(FLUTTER_BUILD_NAME) 21 | CFBundleVersion 22 | $(FLUTTER_BUILD_NUMBER) 23 | LSMinimumSystemVersion 24 | $(MACOSX_DEPLOYMENT_TARGET) 25 | NSHumanReadableCopyright 26 | $(PRODUCT_COPYRIGHT) 27 | NSMainNibFile 28 | MainMenu 29 | NSPrincipalClass 30 | NSApplication 31 | 32 | 33 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .buildlog/ 9 | .history 10 | .svn/ 11 | 12 | # IntelliJ related 13 | *.iml 14 | *.ipr 15 | *.iws 16 | .idea/ 17 | 18 | # The .vscode folder contains launch configuration and tasks you configure in 19 | # VS Code which you may wish to be included in version control, so this line 20 | # is commented out by default. 21 | #.vscode/ 22 | 23 | # Flutter/Dart/Pub related 24 | **/doc/api/ 25 | **/ios/Flutter/.last_build_id 26 | .dart_tool/ 27 | .flutter-plugins 28 | .flutter-plugins-dependencies 29 | .packages 30 | .pub-cache/ 31 | .pub/ 32 | /build/ 33 | 34 | # Web related 35 | lib/generated_plugin_registrant.dart 36 | 37 | # Symbolication related 38 | app.*.symbols 39 | 40 | # Obfuscation related 41 | app.*.map.json 42 | 43 | # Android Studio will place build artifacts here 44 | /android/app/debug 45 | /android/app/profile 46 | /android/app/release 47 | lib/generated_plugin_registrant.dart 48 | linux/flutter/generated_plugin_registrant.cc 49 | linux/flutter/generated_plugin_registrant.h 50 | linux/flutter/generated_plugins.cmake 51 | macos/Flutter/GeneratedPluginRegistrant.swift 52 | windows/flutter/generated_plugin_registrant.cc 53 | windows/flutter/generated_plugins.cmake 54 | macos/Podfile.lock 55 | -------------------------------------------------------------------------------- /example/lib/models/customer/customer.dart: -------------------------------------------------------------------------------- 1 | import 'package:hive_flutter/adapters.dart'; 2 | 3 | import '../organization/organization.dart'; 4 | 5 | part 'customer.g.dart'; 6 | 7 | @HiveType(typeId: 1) 8 | class Customer { 9 | @HiveField(0) 10 | final String id; 11 | @HiveField(1) 12 | final String name; 13 | @HiveField(2) 14 | final String phoneNumber; 15 | @HiveField(3) 16 | final String numberValueExample; 17 | @HiveField(4) 18 | final Organization organization; 19 | 20 | const Customer({ 21 | required this.id, 22 | required this.name, 23 | required this.phoneNumber, 24 | required this.numberValueExample, 25 | required this.organization, 26 | }); 27 | 28 | Map toJson() { 29 | return { 30 | 'id': id, 31 | 'name': name, 32 | 'phoneNumber': phoneNumber, 33 | 'numberValueExample': numberValueExample, 34 | 'organization': organization.toJson(), 35 | }; 36 | } 37 | 38 | factory Customer.fromJson(dynamic map) { 39 | return Customer( 40 | id: map['id'] as String, 41 | name: map['name'] as String, 42 | phoneNumber: map['phoneNumber'] as String, 43 | numberValueExample: map['numberValueExample'] as String, 44 | organization: Organization.fromJson(map['organization'])); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /web/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hive_ui_example", 3 | "short_name": "hive_ui_example", 4 | "start_url": ".", 5 | "display": "standalone", 6 | "background_color": "#0175C2", 7 | "theme_color": "#0175C2", 8 | "description": "A Flutter package that allows you to easily work with Hive databases. With this package, you can explore all database boxes, edit table rows, add new rows to tables, search boxes by column name and value, delete rows or all data from a box, copy selected values and select specific color for the Hive UI view.", 9 | "orientation": "portrait-primary", 10 | "prefer_related_applications": false, 11 | "icons": [ 12 | { 13 | "src": "icons/Icon-192.png", 14 | "sizes": "192x192", 15 | "type": "image/png" 16 | }, 17 | { 18 | "src": "icons/Icon-512.png", 19 | "sizes": "512x512", 20 | "type": "image/png" 21 | }, 22 | { 23 | "src": "icons/Icon-maskable-192.png", 24 | "sizes": "192x192", 25 | "type": "image/png", 26 | "purpose": "maskable" 27 | }, 28 | { 29 | "src": "icons/Icon-maskable-512.png", 30 | "sizes": "512x512", 31 | "type": "image/png", 32 | "purpose": "maskable" 33 | } 34 | ] 35 | } 36 | -------------------------------------------------------------------------------- /lib/services/format-time/english_date_locale.dart: -------------------------------------------------------------------------------- 1 | class EnglishDateLocale implements DateLocale { 2 | const EnglishDateLocale(); 3 | 4 | @override 5 | final List monthsShort = const [ 6 | 'Jan', 7 | 'Feb', 8 | 'Mar', 9 | 'Apr', 10 | 'May', 11 | 'Jun', 12 | 'Jul', 13 | 'Aug', 14 | 'Sep', 15 | 'Oct', 16 | 'Nov', 17 | 'Dec' 18 | ]; 19 | @override 20 | final List monthsLong = const [ 21 | 'January', 22 | 'February', 23 | 'March', 24 | 'April', 25 | 'May', 26 | 'June', 27 | 'July', 28 | 'August', 29 | 'September', 30 | 'October', 31 | 'November', 32 | 'December' 33 | ]; 34 | @override 35 | final List daysShort = const [ 36 | 'Mon', 37 | 'Tue', 38 | 'Wed', 39 | 'Thur', 40 | 'Fri', 41 | 'Sat', 42 | 'Sun' 43 | ]; 44 | @override 45 | final List daysLong = const [ 46 | 'Monday', 47 | 'Tuesday', 48 | 'Wednesday', 49 | 'Thursday', 50 | 'Friday', 51 | 'Saturday', 52 | 'Sunday' 53 | ]; 54 | 55 | @override 56 | String get am => "AM"; 57 | 58 | @override 59 | String get pm => "PM"; 60 | } 61 | 62 | abstract class DateLocale { 63 | List get monthsShort; 64 | 65 | List get monthsLong; 66 | 67 | List get daysShort; 68 | 69 | List get daysLong; 70 | 71 | String get am; 72 | 73 | String get pm; 74 | } 75 | -------------------------------------------------------------------------------- /example/lib/models/organization/organization.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'organization.dart'; 4 | 5 | // ************************************************************************** 6 | // TypeAdapterGenerator 7 | // ************************************************************************** 8 | 9 | class OrganizationAdapter extends TypeAdapter { 10 | @override 11 | final int typeId = 2; 12 | 13 | @override 14 | Organization read(BinaryReader reader) { 15 | final numOfFields = reader.readByte(); 16 | final fields = { 17 | for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(), 18 | }; 19 | return Organization( 20 | id: fields[0] as String, 21 | name: fields[1] as String, 22 | jobTitle: fields[2] as String, 23 | ); 24 | } 25 | 26 | @override 27 | void write(BinaryWriter writer, Organization obj) { 28 | writer 29 | ..writeByte(3) 30 | ..writeByte(0) 31 | ..write(obj.id) 32 | ..writeByte(1) 33 | ..write(obj.name) 34 | ..writeByte(2) 35 | ..write(obj.jobTitle); 36 | } 37 | 38 | @override 39 | int get hashCode => typeId.hashCode; 40 | 41 | @override 42 | bool operator ==(Object other) => 43 | identical(this, other) || 44 | other is OrganizationAdapter && 45 | runtimeType == other.runtimeType && 46 | typeId == other.typeId; 47 | } 48 | -------------------------------------------------------------------------------- /windows/runner/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "flutter_window.h" 6 | #include "utils.h" 7 | 8 | int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev, 9 | _In_ wchar_t *command_line, _In_ int show_command) { 10 | // Attach to console when present (e.g., 'flutter run') or create a 11 | // new console when running with a debugger. 12 | if (!::AttachConsole(ATTACH_PARENT_PROCESS) && ::IsDebuggerPresent()) { 13 | CreateAndAttachConsole(); 14 | } 15 | 16 | // Initialize COM, so that it is available for use in the library and/or 17 | // plugins. 18 | ::CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED); 19 | 20 | flutter::DartProject project(L"data"); 21 | 22 | std::vector command_line_arguments = 23 | GetCommandLineArguments(); 24 | 25 | project.set_dart_entrypoint_arguments(std::move(command_line_arguments)); 26 | 27 | FlutterWindow window(project); 28 | Win32Window::Point origin(10, 10); 29 | Win32Window::Size size(1280, 720); 30 | if (!window.CreateAndShow(L"hive_ui_example", origin, size)) { 31 | return EXIT_FAILURE; 32 | } 33 | window.SetQuitOnClose(true); 34 | 35 | ::MSG msg; 36 | while (::GetMessage(&msg, nullptr, 0, 0)) { 37 | ::TranslateMessage(&msg); 38 | ::DispatchMessage(&msg); 39 | } 40 | 41 | ::CoUninitialize(); 42 | return EXIT_SUCCESS; 43 | } 44 | -------------------------------------------------------------------------------- /macos/Podfile: -------------------------------------------------------------------------------- 1 | platform :osx, '10.11' 2 | 3 | # CocoaPods analytics sends network stats synchronously affecting flutter build latency. 4 | ENV['COCOAPODS_DISABLE_STATS'] = 'true' 5 | 6 | project 'Runner', { 7 | 'Debug' => :debug, 8 | 'Profile' => :release, 9 | 'Release' => :release, 10 | } 11 | 12 | def flutter_root 13 | generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'ephemeral', 'Flutter-Generated.xcconfig'), __FILE__) 14 | unless File.exist?(generated_xcode_build_settings_path) 15 | raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure \"flutter pub get\" is executed first" 16 | end 17 | 18 | File.foreach(generated_xcode_build_settings_path) do |line| 19 | matches = line.match(/FLUTTER_ROOT\=(.*)/) 20 | return matches[1].strip if matches 21 | end 22 | raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Flutter-Generated.xcconfig, then run \"flutter pub get\"" 23 | end 24 | 25 | require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) 26 | 27 | flutter_macos_podfile_setup 28 | 29 | target 'Runner' do 30 | use_frameworks! 31 | use_modular_headers! 32 | 33 | flutter_install_all_macos_pods File.dirname(File.realpath(__FILE__)) 34 | end 35 | 36 | post_install do |installer| 37 | installer.pods_project.targets.each do |target| 38 | flutter_additional_macos_build_settings(target) 39 | end 40 | end 41 | -------------------------------------------------------------------------------- /ios/Podfile: -------------------------------------------------------------------------------- 1 | # Uncomment this line to define a global platform for your project 2 | # platform :ios, '11.0' 3 | 4 | # CocoaPods analytics sends network stats synchronously affecting flutter build latency. 5 | ENV['COCOAPODS_DISABLE_STATS'] = 'true' 6 | 7 | project 'Runner', { 8 | 'Debug' => :debug, 9 | 'Profile' => :release, 10 | 'Release' => :release, 11 | } 12 | 13 | def flutter_root 14 | generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) 15 | unless File.exist?(generated_xcode_build_settings_path) 16 | raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" 17 | end 18 | 19 | File.foreach(generated_xcode_build_settings_path) do |line| 20 | matches = line.match(/FLUTTER_ROOT\=(.*)/) 21 | return matches[1].strip if matches 22 | end 23 | raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" 24 | end 25 | 26 | require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) 27 | 28 | flutter_ios_podfile_setup 29 | 30 | target 'Runner' do 31 | use_frameworks! 32 | use_modular_headers! 33 | 34 | flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) 35 | end 36 | 37 | post_install do |installer| 38 | installer.pods_project.targets.each do |target| 39 | flutter_additional_ios_build_settings(target) 40 | end 41 | end 42 | -------------------------------------------------------------------------------- /example/lib/boxes.dart: -------------------------------------------------------------------------------- 1 | import 'dart:math' as math; 2 | 3 | import 'package:hive_flutter/hive_flutter.dart'; 4 | 5 | import 'models/customer/customer.dart'; 6 | import 'models/organization/organization.dart'; 7 | 8 | class Boxes { 9 | static Box get customersBox => Hive.box("customer"); 10 | 11 | static Future initHive() async { 12 | await Hive.initFlutter(); 13 | await openBoxes(); 14 | } 15 | 16 | static Future openBoxes() async { 17 | Hive.registerAdapter(CustomerAdapter()); 18 | Hive.registerAdapter(OrganizationAdapter()); 19 | await Hive.openBox("customer"); 20 | await _generateCustomer(customersBox); 21 | } 22 | 23 | static Map, dynamic Function(dynamic json)> get allBoxes => { 24 | customersBox: (json) => Customer.fromJson(json), 25 | }; 26 | 27 | static Future _generateCustomer(Box box) async { 28 | final numberValueExample = math.Random().nextInt(25545454).toString(); 29 | final id = math.Random().nextDouble().toString(); 30 | final name = 'Customer$numberValueExample'; 31 | final organization = Organization( 32 | id: id, 33 | name: "org$name", 34 | jobTitle: "org job for $name", 35 | ); 36 | final customer = Customer( 37 | id: id, 38 | name: name, 39 | numberValueExample: numberValueExample, 40 | phoneNumber: numberValueExample.toString(), 41 | organization: organization, 42 | ); 43 | await box.put(customer.id, customer); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /analysis_options.yaml: -------------------------------------------------------------------------------- 1 | # This file configures the analyzer, which statically analyzes Dart code to 2 | # check for errors, warnings, and lints. 3 | # 4 | # The issues identified by the analyzer are surfaced in the UI of Dart-enabled 5 | # IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be 6 | # invoked from the command line by running `flutter analyze`. 7 | 8 | # The following line activates a set of recommended lints for Flutter apps, 9 | # packages, and plugins designed to encourage good coding practices. 10 | include: package:flutter_lints/flutter.yaml 11 | 12 | linter: 13 | # The lint rules applied to this project can be customized in the 14 | # section below to disable rules from the `package:flutter_lints/flutter.yaml` 15 | # included above or to enable additional rules. A list of all available lints 16 | # and their documentation is published at 17 | # https://dart-lang.github.io/linter/lints/index.html. 18 | # 19 | # Instead of disabling a lint rule for the entire project in the 20 | # section below, it can also be suppressed for a single line of code 21 | # or a specific dart file by using the `// ignore: name_of_lint` and 22 | # `// ignore_for_file: name_of_lint` syntax on the line or in the file 23 | # producing the lint. 24 | rules: 25 | # avoid_print: false # Uncomment to disable the `avoid_print` rule 26 | # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule 27 | 28 | # Additional information about this file can be found at 29 | # https://dart.dev/guides/language/analysis-options 30 | -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "16x16", 5 | "idiom" : "mac", 6 | "filename" : "app_icon_16.png", 7 | "scale" : "1x" 8 | }, 9 | { 10 | "size" : "16x16", 11 | "idiom" : "mac", 12 | "filename" : "app_icon_32.png", 13 | "scale" : "2x" 14 | }, 15 | { 16 | "size" : "32x32", 17 | "idiom" : "mac", 18 | "filename" : "app_icon_32.png", 19 | "scale" : "1x" 20 | }, 21 | { 22 | "size" : "32x32", 23 | "idiom" : "mac", 24 | "filename" : "app_icon_64.png", 25 | "scale" : "2x" 26 | }, 27 | { 28 | "size" : "128x128", 29 | "idiom" : "mac", 30 | "filename" : "app_icon_128.png", 31 | "scale" : "1x" 32 | }, 33 | { 34 | "size" : "128x128", 35 | "idiom" : "mac", 36 | "filename" : "app_icon_256.png", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "size" : "256x256", 41 | "idiom" : "mac", 42 | "filename" : "app_icon_256.png", 43 | "scale" : "1x" 44 | }, 45 | { 46 | "size" : "256x256", 47 | "idiom" : "mac", 48 | "filename" : "app_icon_512.png", 49 | "scale" : "2x" 50 | }, 51 | { 52 | "size" : "512x512", 53 | "idiom" : "mac", 54 | "filename" : "app_icon_512.png", 55 | "scale" : "1x" 56 | }, 57 | { 58 | "size" : "512x512", 59 | "idiom" : "mac", 60 | "filename" : "app_icon_1024.png", 61 | "scale" : "2x" 62 | } 63 | ], 64 | "info" : { 65 | "version" : 1, 66 | "author" : "xcode" 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /example/lib/models/customer/customer.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'customer.dart'; 4 | 5 | // ************************************************************************** 6 | // TypeAdapterGenerator 7 | // ************************************************************************** 8 | 9 | class CustomerAdapter extends TypeAdapter { 10 | @override 11 | final int typeId = 1; 12 | 13 | @override 14 | Customer read(BinaryReader reader) { 15 | final numOfFields = reader.readByte(); 16 | final fields = { 17 | for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(), 18 | }; 19 | return Customer( 20 | id: fields[0] as String, 21 | name: fields[1] as String, 22 | phoneNumber: fields[2] as String, 23 | numberValueExample: fields[3] as String, 24 | organization: fields[4] as Organization, 25 | ); 26 | } 27 | 28 | @override 29 | void write(BinaryWriter writer, Customer obj) { 30 | writer 31 | ..writeByte(5) 32 | ..writeByte(0) 33 | ..write(obj.id) 34 | ..writeByte(1) 35 | ..write(obj.name) 36 | ..writeByte(2) 37 | ..write(obj.phoneNumber) 38 | ..writeByte(3) 39 | ..write(obj.numberValueExample) 40 | ..writeByte(4) 41 | ..write(obj.organization); 42 | } 43 | 44 | @override 45 | int get hashCode => typeId.hashCode; 46 | 47 | @override 48 | bool operator ==(Object other) => 49 | identical(this, other) || 50 | other is CustomerAdapter && 51 | runtimeType == other.runtimeType && 52 | typeId == other.typeId; 53 | } 54 | -------------------------------------------------------------------------------- /ios/Runner/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /android/hive_ui_example_android.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /example/lib/main.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:hive_ui/boxes_view.dart'; 3 | 4 | import 'boxes.dart'; 5 | 6 | void main() async { 7 | WidgetsFlutterBinding.ensureInitialized(); 8 | runApp(const App()); 9 | Boxes.initHive(); 10 | } 11 | 12 | class App extends StatelessWidget { 13 | const App({super.key}); 14 | 15 | @override 16 | Widget build(BuildContext context) { 17 | return const MaterialApp( 18 | title: "Hive UI", 19 | debugShowCheckedModeBanner: false, 20 | home: HomePage(), 21 | ); 22 | } 23 | } 24 | 25 | class HomePage extends StatelessWidget { 26 | const HomePage({super.key}); 27 | 28 | @override 29 | Widget build(BuildContext context) { 30 | return Scaffold( 31 | body: Center( 32 | child: Column( 33 | crossAxisAlignment: CrossAxisAlignment.center, 34 | mainAxisAlignment: MainAxisAlignment.center, 35 | children: [ 36 | MaterialButton( 37 | child: const Text("OPEN HIVE UI"), 38 | onPressed: () { 39 | Navigator.push( 40 | context, 41 | MaterialPageRoute( 42 | builder: (context) => HiveBoxesView( 43 | hiveBoxes: Boxes.allBoxes, 44 | onError: (String errorMessage) => { 45 | print(errorMessage), 46 | }, 47 | ), 48 | ), 49 | ); 50 | }, 51 | ), 52 | MaterialButton( 53 | child: const Text("Clear HIVE UI"), 54 | onPressed: () { 55 | Boxes.customersBox.clear(); 56 | }, 57 | ), 58 | 59 | ], 60 | ), 61 | ), 62 | ); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 7 | 15 | 19 | 23 | 24 | 25 | 26 | 27 | 28 | 30 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /windows/runner/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.14) 2 | project(runner LANGUAGES CXX) 3 | 4 | # Define the application target. To change its name, change BINARY_NAME in the 5 | # top-level CMakeLists.txt, not the value here, or `flutter run` will no longer 6 | # work. 7 | # 8 | # Any new source files that you add to the application should be added here. 9 | add_executable(${BINARY_NAME} WIN32 10 | "flutter_window.cpp" 11 | "main.cpp" 12 | "utils.cpp" 13 | "win32_window.cpp" 14 | "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" 15 | "Runner.rc" 16 | "runner.exe.manifest" 17 | ) 18 | 19 | # Apply the standard set of build settings. This can be removed for applications 20 | # that need different build settings. 21 | apply_standard_settings(${BINARY_NAME}) 22 | 23 | # Add preprocessor definitions for the build version. 24 | target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION=\"${FLUTTER_VERSION}\"") 25 | target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MAJOR=${FLUTTER_VERSION_MAJOR}") 26 | target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MINOR=${FLUTTER_VERSION_MINOR}") 27 | target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_PATCH=${FLUTTER_VERSION_PATCH}") 28 | target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_BUILD=${FLUTTER_VERSION_BUILD}") 29 | 30 | # Disable Windows macros that collide with C++ standard library functions. 31 | target_compile_definitions(${BINARY_NAME} PRIVATE "NOMINMAX") 32 | 33 | # Add dependency libraries and include directories. Add any application-specific 34 | # dependencies here. 35 | target_link_libraries(${BINARY_NAME} PRIVATE flutter flutter_wrapper_app) 36 | target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}") 37 | 38 | # Run the Flutter tool portions of the build. This must not be removed. 39 | add_dependencies(${BINARY_NAME} flutter_assemble) 40 | -------------------------------------------------------------------------------- /ios/Runner/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleDisplayName 8 | Hive Ui Example 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | hive_ui_example 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | $(FLUTTER_BUILD_NAME) 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | $(FLUTTER_BUILD_NUMBER) 25 | LSRequiresIPhoneOS 26 | 27 | UILaunchStoryboardName 28 | LaunchScreen 29 | UIMainStoryboardFile 30 | Main 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | UISupportedInterfaceOrientations~ipad 38 | 39 | UIInterfaceOrientationPortrait 40 | UIInterfaceOrientationPortraitUpsideDown 41 | UIInterfaceOrientationLandscapeLeft 42 | UIInterfaceOrientationLandscapeRight 43 | 44 | UIViewControllerBasedStatusBarAppearance 45 | 46 | CADisableMinimumFrameDurationOnPhone 47 | 48 | UIApplicationSupportsIndirectInputEvents 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /windows/runner/utils.cpp: -------------------------------------------------------------------------------- 1 | #include "utils.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | 10 | void CreateAndAttachConsole() { 11 | if (::AllocConsole()) { 12 | FILE *unused; 13 | if (freopen_s(&unused, "CONOUT$", "w", stdout)) { 14 | _dup2(_fileno(stdout), 1); 15 | } 16 | if (freopen_s(&unused, "CONOUT$", "w", stderr)) { 17 | _dup2(_fileno(stdout), 2); 18 | } 19 | std::ios::sync_with_stdio(); 20 | FlutterDesktopResyncOutputStreams(); 21 | } 22 | } 23 | 24 | std::vector GetCommandLineArguments() { 25 | // Convert the UTF-16 command line arguments to UTF-8 for the Engine to use. 26 | int argc; 27 | wchar_t** argv = ::CommandLineToArgvW(::GetCommandLineW(), &argc); 28 | if (argv == nullptr) { 29 | return std::vector(); 30 | } 31 | 32 | std::vector command_line_arguments; 33 | 34 | // Skip the first argument as it's the binary name. 35 | for (int i = 1; i < argc; i++) { 36 | command_line_arguments.push_back(Utf8FromUtf16(argv[i])); 37 | } 38 | 39 | ::LocalFree(argv); 40 | 41 | return command_line_arguments; 42 | } 43 | 44 | std::string Utf8FromUtf16(const wchar_t* utf16_string) { 45 | if (utf16_string == nullptr) { 46 | return std::string(); 47 | } 48 | int target_length = ::WideCharToMultiByte( 49 | CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, 50 | -1, nullptr, 0, nullptr, nullptr); 51 | std::string utf8_string; 52 | if (target_length == 0 || target_length > utf8_string.max_size()) { 53 | return utf8_string; 54 | } 55 | utf8_string.resize(target_length); 56 | int converted_length = ::WideCharToMultiByte( 57 | CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, 58 | -1, utf8_string.data(), 59 | target_length, nullptr, nullptr); 60 | if (converted_length == 0) { 61 | return std::string(); 62 | } 63 | return utf8_string; 64 | } 65 | -------------------------------------------------------------------------------- /windows/runner/flutter_window.cpp: -------------------------------------------------------------------------------- 1 | #include "flutter_window.h" 2 | 3 | #include 4 | 5 | #include "flutter/generated_plugin_registrant.h" 6 | 7 | FlutterWindow::FlutterWindow(const flutter::DartProject& project) 8 | : project_(project) {} 9 | 10 | FlutterWindow::~FlutterWindow() {} 11 | 12 | bool FlutterWindow::OnCreate() { 13 | if (!Win32Window::OnCreate()) { 14 | return false; 15 | } 16 | 17 | RECT frame = GetClientArea(); 18 | 19 | // The size here must match the window dimensions to avoid unnecessary surface 20 | // creation / destruction in the startup path. 21 | flutter_controller_ = std::make_unique( 22 | frame.right - frame.left, frame.bottom - frame.top, project_); 23 | // Ensure that basic setup of the controller was successful. 24 | if (!flutter_controller_->engine() || !flutter_controller_->view()) { 25 | return false; 26 | } 27 | RegisterPlugins(flutter_controller_->engine()); 28 | SetChildContent(flutter_controller_->view()->GetNativeWindow()); 29 | return true; 30 | } 31 | 32 | void FlutterWindow::OnDestroy() { 33 | if (flutter_controller_) { 34 | flutter_controller_ = nullptr; 35 | } 36 | 37 | Win32Window::OnDestroy(); 38 | } 39 | 40 | LRESULT 41 | FlutterWindow::MessageHandler(HWND hwnd, UINT const message, 42 | WPARAM const wparam, 43 | LPARAM const lparam) noexcept { 44 | // Give Flutter, including plugins, an opportunity to handle window messages. 45 | if (flutter_controller_) { 46 | std::optional result = 47 | flutter_controller_->HandleTopLevelWindowProc(hwnd, message, wparam, 48 | lparam); 49 | if (result) { 50 | return *result; 51 | } 52 | } 53 | 54 | switch (message) { 55 | case WM_FONTCHANGE: 56 | flutter_controller_->engine()->ReloadSystemFonts(); 57 | break; 58 | } 59 | 60 | return Win32Window::MessageHandler(hwnd, message, wparam, lparam); 61 | } 62 | -------------------------------------------------------------------------------- /pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: hive_ui 2 | description: 3 | DBMS Hive Ui is a package that presents a smart methodology to work with the Hive database, It is easy to view, edit and create new rows. 4 | version: 1.0.4 5 | homepage: "https://github.com/AmrSaied/hive_ui" 6 | 7 | environment: 8 | sdk: ">=2.17.3 <3.0.0" 9 | flutter: ">=1.17.0" 10 | 11 | dependencies: 12 | clipboard: ^0.1.3 13 | flutter: 14 | sdk: flutter 15 | hive_flutter: ^1.1.0 16 | intl: ^0.18.0 17 | number_pagination: ^0.0.3+2 18 | uuid: ^3.0.7 19 | 20 | dev_dependencies: 21 | flutter_test: 22 | sdk: flutter 23 | flutter_lints: ^2.0.1 24 | build_runner: ^2.3.3 25 | hive_generator: ^2.0.0 26 | 27 | # For information on the generic Dart part of this file, see the 28 | # following page: https://dart.dev/tools/pub/pubspec 29 | 30 | # The following section is specific to Flutter packages. 31 | flutter: 32 | uses-material-design: true 33 | # To add assets to your package, add an assets section, like this: 34 | # assets: 35 | # - images/a_dot_burr.jpeg 36 | # - images/a_dot_ham.jpeg 37 | # 38 | # For details regarding assets in packages, see 39 | # https://flutter.dev/assets-and-images/#from-packages 40 | # 41 | # An image asset can refer to one or more resolution-specific "variants", see 42 | # https://flutter.dev/assets-and-images/#resolution-aware 43 | 44 | # To add custom fonts to your package, add a fonts section here, 45 | # in this "flutter" section. Each entry in this list should have a 46 | # "family" key with the font family name, and a "fonts" key with a 47 | # list giving the asset and other descriptors for the font. For 48 | # example: 49 | # fonts: 50 | # - family: Schyler 51 | # fonts: 52 | # - asset: fonts/Schyler-Regular.ttf 53 | # - asset: fonts/Schyler-Italic.ttf 54 | # style: italic 55 | # - family: Trajan Pro 56 | # fonts: 57 | # - asset: fonts/TrajanPro.ttf 58 | # - asset: fonts/TrajanPro_Bold.ttf 59 | # weight: 700 60 | # 61 | # For details regarding fonts in packages, see 62 | # https://flutter.dev/custom-fonts/#from-packages 63 | -------------------------------------------------------------------------------- /lib/core/hive_view_state.dart: -------------------------------------------------------------------------------- 1 | import 'package:hive_flutter/hive_flutter.dart'; 2 | 3 | import '../boxes_view.dart'; 4 | 5 | typedef HiveViewObject = List>; 6 | 7 | class HiveViewState { 8 | /// A map of Box objects and their associated FromJsonConverter functions 9 | final Map boxesMap; 10 | 11 | /// The currently opened box 12 | final Box? currentOpenedBox; 13 | 14 | /// The selected value of the current opened box 15 | final HiveViewObject? selectedBoxValue; 16 | 17 | /// List of nested objects in the current opened box 18 | final List? nestedObjectList; 19 | 20 | /// Indices of the nested objects in the current opened box 21 | final List>? objectNestedIndices; 22 | 23 | /// Initializes a HiveViewState object with the given parameters 24 | /// 25 | /// [boxesMap] : A map of Box objects and their associated FromJsonConverter functions 26 | /// [currentOpenedBox] : The currently opened box 27 | /// [selectedBoxValue] : The selected value of the current opened box 28 | /// [nestedObjectList] : List of nested objects in the current opened box 29 | /// [objectNestedIndices] : Indices of the nested objects in the current opened box 30 | HiveViewState({ 31 | required this.boxesMap, 32 | this.currentOpenedBox, 33 | this.selectedBoxValue, 34 | this.nestedObjectList, 35 | this.objectNestedIndices, 36 | }); 37 | 38 | /// Creates a new HiveViewState object with the given parameters 39 | HiveViewState copyWith({ 40 | Box? currentOpenedBox, 41 | HiveViewObject? selectedBoxValue, 42 | List? nestedObjectList, 43 | Map? boxesMap, 44 | List>? objectNestedIndices, 45 | }) { 46 | return HiveViewState( 47 | boxesMap: boxesMap ?? this.boxesMap, 48 | currentOpenedBox: currentOpenedBox ?? this.currentOpenedBox, 49 | selectedBoxValue: selectedBoxValue ?? this.selectedBoxValue, 50 | nestedObjectList: nestedObjectList ?? this.nestedObjectList, 51 | objectNestedIndices: objectNestedIndices ?? this.objectNestedIndices, 52 | ); 53 | } 54 | 55 | /// Clears the state of the HiveViewState object 56 | HiveViewState clearState() => HiveViewState(boxesMap: boxesMap); 57 | } 58 | -------------------------------------------------------------------------------- /web/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | hive_ui_example 33 | 34 | 35 | 39 | 40 | 41 | 42 | 43 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /android/app/build.gradle: -------------------------------------------------------------------------------- 1 | def localProperties = new Properties() 2 | def localPropertiesFile = rootProject.file('local.properties') 3 | if (localPropertiesFile.exists()) { 4 | localPropertiesFile.withReader('UTF-8') { reader -> 5 | localProperties.load(reader) 6 | } 7 | } 8 | 9 | def flutterRoot = localProperties.getProperty('flutter.sdk') 10 | if (flutterRoot == null) { 11 | throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") 12 | } 13 | 14 | def flutterVersionCode = localProperties.getProperty('flutter.versionCode') 15 | if (flutterVersionCode == null) { 16 | flutterVersionCode = '1' 17 | } 18 | 19 | def flutterVersionName = localProperties.getProperty('flutter.versionName') 20 | if (flutterVersionName == null) { 21 | flutterVersionName = '1.0' 22 | } 23 | 24 | apply plugin: 'com.android.application' 25 | apply plugin: 'kotlin-android' 26 | apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" 27 | 28 | android { 29 | compileSdkVersion flutter.compileSdkVersion 30 | ndkVersion flutter.ndkVersion 31 | 32 | compileOptions { 33 | sourceCompatibility JavaVersion.VERSION_1_8 34 | targetCompatibility JavaVersion.VERSION_1_8 35 | } 36 | 37 | kotlinOptions { 38 | jvmTarget = '1.8' 39 | } 40 | 41 | sourceSets { 42 | main.java.srcDirs += 'src/main/kotlin' 43 | } 44 | 45 | defaultConfig { 46 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). 47 | applicationId "com.hive_ui_example.hive_ui_example" 48 | // You can update the following values to match your application needs. 49 | // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-build-configuration. 50 | minSdkVersion flutter.minSdkVersion 51 | targetSdkVersion flutter.targetSdkVersion 52 | versionCode flutterVersionCode.toInteger() 53 | versionName flutterVersionName 54 | } 55 | 56 | buildTypes { 57 | release { 58 | // TODO: Add your own signing config for the release build. 59 | // Signing with the debug keys for now, so `flutter run --release` works. 60 | signingConfig signingConfigs.debug 61 | } 62 | } 63 | } 64 | 65 | flutter { 66 | source '../..' 67 | } 68 | 69 | dependencies { 70 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" 71 | } 72 | -------------------------------------------------------------------------------- /ios/Runner/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /lib/boxes_list.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:flutter/material.dart'; 4 | import 'package:hive_flutter/adapters.dart'; 5 | import 'package:hive_ui/search/search_widget.dart'; 6 | 7 | class HiveBoxesList extends StatefulWidget { 8 | final List boxes; 9 | final void Function(String boxName) onBoxNameSelected; 10 | 11 | const HiveBoxesList({ 12 | Key? key, 13 | required this.boxes, 14 | required this.onBoxNameSelected, 15 | }) : super(key: key); 16 | 17 | @override 18 | State createState() => _HiveBoxesListState(); 19 | } 20 | 21 | class _HiveBoxesListState extends State { 22 | Timer? _timer; 23 | String searchValue = ''; 24 | late List boxNamesList; 25 | 26 | @override 27 | void initState() { 28 | boxNamesList = widget.boxes.map((e) => e.name).toList(); 29 | super.initState(); 30 | } 31 | 32 | void onSearchValue(String value) { 33 | searchValue = value; 34 | if (_timer?.isActive ?? false) _timer?.cancel(); 35 | _timer = Timer(const Duration(milliseconds: 500), () { 36 | if (searchValue.isNotEmpty) { 37 | boxNamesList = widget.boxes 38 | .map((e) => e.name) 39 | .toList() 40 | .where((element) => element.contains(searchValue)) 41 | .toList(); 42 | } else { 43 | boxNamesList = widget.boxes.map((e) => e.name).toList(); 44 | } 45 | setState(() {}); 46 | }); 47 | } 48 | 49 | @override 50 | void dispose() { 51 | _timer?.cancel(); 52 | super.dispose(); 53 | } 54 | 55 | int getLength(String name) { 56 | final selectedBox = widget.boxes.singleWhere( 57 | (element) => element.name == name, 58 | ); 59 | return selectedBox.values.length; 60 | } 61 | 62 | @override 63 | Widget build(BuildContext context) { 64 | return Column( 65 | children: [ 66 | SearchWidget( 67 | scope: SearchScope.box, 68 | onSearch: onSearchValue, 69 | ), 70 | Expanded( 71 | child: SingleChildScrollView( 72 | child: Column( 73 | children: boxNamesList.map( 74 | (boxName) { 75 | return ListTile( 76 | title: Text(boxName), 77 | trailing: Text("Length : ${getLength(boxName)}"), 78 | onTap: () => widget.onBoxNameSelected(boxName), 79 | ); 80 | }, 81 | ).toList(), 82 | ), 83 | ), 84 | ), 85 | ], 86 | ); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /linux/flutter/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # This file controls Flutter-level build steps. It should not be edited. 2 | cmake_minimum_required(VERSION 3.10) 3 | 4 | set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral") 5 | 6 | # Configuration provided via flutter tool. 7 | include(${EPHEMERAL_DIR}/generated_config.cmake) 8 | 9 | # TODO: Move the rest of this into files in ephemeral. See 10 | # https://github.com/flutter/flutter/issues/57146. 11 | 12 | # Serves the same purpose as list(TRANSFORM ... PREPEND ...), 13 | # which isn't available in 3.10. 14 | function(list_prepend LIST_NAME PREFIX) 15 | set(NEW_LIST "") 16 | foreach(element ${${LIST_NAME}}) 17 | list(APPEND NEW_LIST "${PREFIX}${element}") 18 | endforeach(element) 19 | set(${LIST_NAME} "${NEW_LIST}" PARENT_SCOPE) 20 | endfunction() 21 | 22 | # === Flutter Library === 23 | # System-level dependencies. 24 | find_package(PkgConfig REQUIRED) 25 | pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) 26 | pkg_check_modules(GLIB REQUIRED IMPORTED_TARGET glib-2.0) 27 | pkg_check_modules(GIO REQUIRED IMPORTED_TARGET gio-2.0) 28 | 29 | set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/libflutter_linux_gtk.so") 30 | 31 | # Published to parent scope for install step. 32 | set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE) 33 | set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE) 34 | set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE) 35 | set(AOT_LIBRARY "${PROJECT_DIR}/build/lib/libapp.so" PARENT_SCOPE) 36 | 37 | list(APPEND FLUTTER_LIBRARY_HEADERS 38 | "fl_basic_message_channel.h" 39 | "fl_binary_codec.h" 40 | "fl_binary_messenger.h" 41 | "fl_dart_project.h" 42 | "fl_engine.h" 43 | "fl_json_message_codec.h" 44 | "fl_json_method_codec.h" 45 | "fl_message_codec.h" 46 | "fl_method_call.h" 47 | "fl_method_channel.h" 48 | "fl_method_codec.h" 49 | "fl_method_response.h" 50 | "fl_plugin_registrar.h" 51 | "fl_plugin_registry.h" 52 | "fl_standard_message_codec.h" 53 | "fl_standard_method_codec.h" 54 | "fl_string_codec.h" 55 | "fl_value.h" 56 | "fl_view.h" 57 | "flutter_linux.h" 58 | ) 59 | list_prepend(FLUTTER_LIBRARY_HEADERS "${EPHEMERAL_DIR}/flutter_linux/") 60 | add_library(flutter INTERFACE) 61 | target_include_directories(flutter INTERFACE 62 | "${EPHEMERAL_DIR}" 63 | ) 64 | target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}") 65 | target_link_libraries(flutter INTERFACE 66 | PkgConfig::GTK 67 | PkgConfig::GLIB 68 | PkgConfig::GIO 69 | ) 70 | add_dependencies(flutter flutter_assemble) 71 | 72 | # === Flutter tool backend === 73 | # _phony_ is a non-existent file to force this command to run every time, 74 | # since currently there's no way to get a full input/output list from the 75 | # flutter tool. 76 | add_custom_command( 77 | OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} 78 | ${CMAKE_CURRENT_BINARY_DIR}/_phony_ 79 | COMMAND ${CMAKE_COMMAND} -E env 80 | ${FLUTTER_TOOL_ENVIRONMENT} 81 | "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.sh" 82 | ${FLUTTER_TARGET_PLATFORM} ${CMAKE_BUILD_TYPE} 83 | VERBATIM 84 | ) 85 | add_custom_target(flutter_assemble DEPENDS 86 | "${FLUTTER_LIBRARY}" 87 | ${FLUTTER_LIBRARY_HEADERS} 88 | ) 89 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "20x20", 5 | "idiom" : "iphone", 6 | "filename" : "Icon-App-20x20@2x.png", 7 | "scale" : "2x" 8 | }, 9 | { 10 | "size" : "20x20", 11 | "idiom" : "iphone", 12 | "filename" : "Icon-App-20x20@3x.png", 13 | "scale" : "3x" 14 | }, 15 | { 16 | "size" : "29x29", 17 | "idiom" : "iphone", 18 | "filename" : "Icon-App-29x29@1x.png", 19 | "scale" : "1x" 20 | }, 21 | { 22 | "size" : "29x29", 23 | "idiom" : "iphone", 24 | "filename" : "Icon-App-29x29@2x.png", 25 | "scale" : "2x" 26 | }, 27 | { 28 | "size" : "29x29", 29 | "idiom" : "iphone", 30 | "filename" : "Icon-App-29x29@3x.png", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "size" : "40x40", 35 | "idiom" : "iphone", 36 | "filename" : "Icon-App-40x40@2x.png", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "size" : "40x40", 41 | "idiom" : "iphone", 42 | "filename" : "Icon-App-40x40@3x.png", 43 | "scale" : "3x" 44 | }, 45 | { 46 | "size" : "60x60", 47 | "idiom" : "iphone", 48 | "filename" : "Icon-App-60x60@2x.png", 49 | "scale" : "2x" 50 | }, 51 | { 52 | "size" : "60x60", 53 | "idiom" : "iphone", 54 | "filename" : "Icon-App-60x60@3x.png", 55 | "scale" : "3x" 56 | }, 57 | { 58 | "size" : "20x20", 59 | "idiom" : "ipad", 60 | "filename" : "Icon-App-20x20@1x.png", 61 | "scale" : "1x" 62 | }, 63 | { 64 | "size" : "20x20", 65 | "idiom" : "ipad", 66 | "filename" : "Icon-App-20x20@2x.png", 67 | "scale" : "2x" 68 | }, 69 | { 70 | "size" : "29x29", 71 | "idiom" : "ipad", 72 | "filename" : "Icon-App-29x29@1x.png", 73 | "scale" : "1x" 74 | }, 75 | { 76 | "size" : "29x29", 77 | "idiom" : "ipad", 78 | "filename" : "Icon-App-29x29@2x.png", 79 | "scale" : "2x" 80 | }, 81 | { 82 | "size" : "40x40", 83 | "idiom" : "ipad", 84 | "filename" : "Icon-App-40x40@1x.png", 85 | "scale" : "1x" 86 | }, 87 | { 88 | "size" : "40x40", 89 | "idiom" : "ipad", 90 | "filename" : "Icon-App-40x40@2x.png", 91 | "scale" : "2x" 92 | }, 93 | { 94 | "size" : "76x76", 95 | "idiom" : "ipad", 96 | "filename" : "Icon-App-76x76@1x.png", 97 | "scale" : "1x" 98 | }, 99 | { 100 | "size" : "76x76", 101 | "idiom" : "ipad", 102 | "filename" : "Icon-App-76x76@2x.png", 103 | "scale" : "2x" 104 | }, 105 | { 106 | "size" : "83.5x83.5", 107 | "idiom" : "ipad", 108 | "filename" : "Icon-App-83.5x83.5@2x.png", 109 | "scale" : "2x" 110 | }, 111 | { 112 | "size" : "1024x1024", 113 | "idiom" : "ios-marketing", 114 | "filename" : "Icon-App-1024x1024@1x.png", 115 | "scale" : "1x" 116 | } 117 | ], 118 | "info" : { 119 | "version" : 1, 120 | "author" : "xcode" 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 37 | 38 | 39 | 40 | 41 | 42 | 52 | 54 | 60 | 61 | 62 | 63 | 69 | 71 | 77 | 78 | 79 | 80 | 82 | 83 | 86 | 87 | 88 | -------------------------------------------------------------------------------- /macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 37 | 38 | 39 | 40 | 41 | 42 | 52 | 54 | 60 | 61 | 62 | 63 | 69 | 71 | 77 | 78 | 79 | 80 | 82 | 83 | 86 | 87 | 88 | -------------------------------------------------------------------------------- /windows/runner/Runner.rc: -------------------------------------------------------------------------------- 1 | // Microsoft Visual C++ generated resource script. 2 | // 3 | #pragma code_page(65001) 4 | #include "resource.h" 5 | 6 | #define APSTUDIO_READONLY_SYMBOLS 7 | ///////////////////////////////////////////////////////////////////////////// 8 | // 9 | // Generated from the TEXTINCLUDE 2 resource. 10 | // 11 | #include "winres.h" 12 | 13 | ///////////////////////////////////////////////////////////////////////////// 14 | #undef APSTUDIO_READONLY_SYMBOLS 15 | 16 | ///////////////////////////////////////////////////////////////////////////// 17 | // English (United States) resources 18 | 19 | #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) 20 | LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US 21 | 22 | #ifdef APSTUDIO_INVOKED 23 | ///////////////////////////////////////////////////////////////////////////// 24 | // 25 | // TEXTINCLUDE 26 | // 27 | 28 | 1 TEXTINCLUDE 29 | BEGIN 30 | "resource.h\0" 31 | END 32 | 33 | 2 TEXTINCLUDE 34 | BEGIN 35 | "#include ""winres.h""\r\n" 36 | "\0" 37 | END 38 | 39 | 3 TEXTINCLUDE 40 | BEGIN 41 | "\r\n" 42 | "\0" 43 | END 44 | 45 | #endif // APSTUDIO_INVOKED 46 | 47 | 48 | ///////////////////////////////////////////////////////////////////////////// 49 | // 50 | // Icon 51 | // 52 | 53 | // Icon with lowest ID value placed first to ensure application icon 54 | // remains consistent on all systems. 55 | IDI_APP_ICON ICON "resources\\app_icon.ico" 56 | 57 | 58 | ///////////////////////////////////////////////////////////////////////////// 59 | // 60 | // Version 61 | // 62 | 63 | #if defined(FLUTTER_VERSION_MAJOR) && defined(FLUTTER_VERSION_MINOR) && defined(FLUTTER_VERSION_PATCH) && defined(FLUTTER_VERSION_BUILD) 64 | #define VERSION_AS_NUMBER FLUTTER_VERSION_MAJOR,FLUTTER_VERSION_MINOR,FLUTTER_VERSION_PATCH,FLUTTER_VERSION_BUILD 65 | #else 66 | #define VERSION_AS_NUMBER 1,0,0,0 67 | #endif 68 | 69 | #if defined(FLUTTER_VERSION) 70 | #define VERSION_AS_STRING FLUTTER_VERSION 71 | #else 72 | #define VERSION_AS_STRING "1.0.0" 73 | #endif 74 | 75 | VS_VERSION_INFO VERSIONINFO 76 | FILEVERSION VERSION_AS_NUMBER 77 | PRODUCTVERSION VERSION_AS_NUMBER 78 | FILEFLAGSMASK VS_FFI_FILEFLAGSMASK 79 | #ifdef _DEBUG 80 | FILEFLAGS VS_FF_DEBUG 81 | #else 82 | FILEFLAGS 0x0L 83 | #endif 84 | FILEOS VOS__WINDOWS32 85 | FILETYPE VFT_APP 86 | FILESUBTYPE 0x0L 87 | BEGIN 88 | BLOCK "StringFileInfo" 89 | BEGIN 90 | BLOCK "040904e4" 91 | BEGIN 92 | VALUE "CompanyName", "com.hive_ui_example" "\0" 93 | VALUE "FileDescription", "hive_ui_example" "\0" 94 | VALUE "FileVersion", VERSION_AS_STRING "\0" 95 | VALUE "InternalName", "hive_ui_example" "\0" 96 | VALUE "LegalCopyright", "Copyright (C) 2023 com.hive_ui_example. All rights reserved." "\0" 97 | VALUE "OriginalFilename", "hive_ui_example.exe" "\0" 98 | VALUE "ProductName", "hive_ui_example" "\0" 99 | VALUE "ProductVersion", VERSION_AS_STRING "\0" 100 | END 101 | END 102 | BLOCK "VarFileInfo" 103 | BEGIN 104 | VALUE "Translation", 0x409, 1252 105 | END 106 | END 107 | 108 | #endif // English (United States) resources 109 | ///////////////////////////////////////////////////////////////////////////// 110 | 111 | 112 | 113 | #ifndef APSTUDIO_INVOKED 114 | ///////////////////////////////////////////////////////////////////////////// 115 | // 116 | // Generated from the TEXTINCLUDE 3 resource. 117 | // 118 | 119 | 120 | ///////////////////////////////////////////////////////////////////////////// 121 | #endif // not APSTUDIO_INVOKED 122 | -------------------------------------------------------------------------------- /lib/widgets/columns_filter_dialog.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class ColumnsFilterDialog extends StatefulWidget { 4 | final List allColumns; 5 | final List selectedColumns; 6 | const ColumnsFilterDialog({ 7 | Key? key, 8 | required this.allColumns, 9 | required this.selectedColumns, 10 | }) : super(key: key); 11 | 12 | @override 13 | State createState() => _ColumnsFilterDialogState(); 14 | } 15 | 16 | class _ColumnsFilterDialogState extends State { 17 | late List _selectedColumns; 18 | 19 | @override 20 | void initState() { 21 | _selectedColumns = List.of(widget.selectedColumns); 22 | super.initState(); 23 | } 24 | 25 | @override 26 | Widget build(BuildContext context) { 27 | final mediaQuerySize = MediaQuery.of(context).size; 28 | return Dialog( 29 | child: SizedBox( 30 | height: mediaQuerySize.height * 0.5, 31 | width: mediaQuerySize.width * 0.35, 32 | child: Column( 33 | crossAxisAlignment: CrossAxisAlignment.center, 34 | children: [ 35 | const SizedBox(height: 16), 36 | const Align( 37 | alignment: Alignment.center, 38 | child: Text('Select Columns To Show'), 39 | ), 40 | const SizedBox(height: 16), 41 | Expanded( 42 | child: SingleChildScrollView( 43 | child: Column( 44 | children: widget.allColumns.map( 45 | (column) { 46 | final isSelected = _selectedColumns.contains(column); 47 | return ListTile( 48 | title: Text(column), 49 | selected: isSelected, 50 | onTap: () { 51 | if (isSelected) { 52 | _selectedColumns.remove(column); 53 | } else { 54 | _selectedColumns.add(column); 55 | } 56 | setState(() {}); 57 | }, 58 | ); 59 | }, 60 | ).toList(), 61 | ), 62 | ), 63 | ), 64 | const SizedBox(height: 32), 65 | Row( 66 | mainAxisAlignment: MainAxisAlignment.spaceAround, 67 | children: [ 68 | TextButton( 69 | onPressed: () { 70 | _selectedColumns = widget.allColumns; 71 | setState(() {}); 72 | }, 73 | style: TextButton.styleFrom( 74 | foregroundColor: Colors.red, 75 | fixedSize: const Size( 76 | 100, 77 | 50, 78 | ), 79 | ), 80 | child: const Text('Reset'), 81 | ), 82 | TextButton( 83 | onPressed: () { 84 | Navigator.pop(context, _selectedColumns); 85 | }, 86 | style: TextButton.styleFrom( 87 | foregroundColor: Colors.green, 88 | fixedSize: const Size( 89 | 100, 90 | 50, 91 | ), 92 | ), 93 | child: const Text('Confirm'), 94 | ), 95 | ], 96 | ), 97 | const SizedBox(height: 32), 98 | ], 99 | ), 100 | ), 101 | ); 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /windows/runner/win32_window.h: -------------------------------------------------------------------------------- 1 | #ifndef RUNNER_WIN32_WINDOW_H_ 2 | #define RUNNER_WIN32_WINDOW_H_ 3 | 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | // A class abstraction for a high DPI-aware Win32 Window. Intended to be 11 | // inherited from by classes that wish to specialize with custom 12 | // rendering and input handling 13 | class Win32Window { 14 | public: 15 | struct Point { 16 | unsigned int x; 17 | unsigned int y; 18 | Point(unsigned int x, unsigned int y) : x(x), y(y) {} 19 | }; 20 | 21 | struct Size { 22 | unsigned int width; 23 | unsigned int height; 24 | Size(unsigned int width, unsigned int height) 25 | : width(width), height(height) {} 26 | }; 27 | 28 | Win32Window(); 29 | virtual ~Win32Window(); 30 | 31 | // Creates and shows a win32 window with |title| and position and size using 32 | // |origin| and |size|. New windows are created on the default monitor. Window 33 | // sizes are specified to the OS in physical pixels, hence to ensure a 34 | // consistent size to will treat the width height passed in to this function 35 | // as logical pixels and scale to appropriate for the default monitor. Returns 36 | // true if the window was created successfully. 37 | bool CreateAndShow(const std::wstring& title, 38 | const Point& origin, 39 | const Size& size); 40 | 41 | // Release OS resources associated with window. 42 | void Destroy(); 43 | 44 | // Inserts |content| into the window tree. 45 | void SetChildContent(HWND content); 46 | 47 | // Returns the backing Window handle to enable clients to set icon and other 48 | // window properties. Returns nullptr if the window has been destroyed. 49 | HWND GetHandle(); 50 | 51 | // If true, closing this window will quit the application. 52 | void SetQuitOnClose(bool quit_on_close); 53 | 54 | // Return a RECT representing the bounds of the current client area. 55 | RECT GetClientArea(); 56 | 57 | protected: 58 | // Processes and route salient window messages for mouse handling, 59 | // size change and DPI. Delegates handling of these to member overloads that 60 | // inheriting classes can handle. 61 | virtual LRESULT MessageHandler(HWND window, 62 | UINT const message, 63 | WPARAM const wparam, 64 | LPARAM const lparam) noexcept; 65 | 66 | // Called when CreateAndShow is called, allowing subclass window-related 67 | // setup. Subclasses should return false if setup fails. 68 | virtual bool OnCreate(); 69 | 70 | // Called when Destroy is called. 71 | virtual void OnDestroy(); 72 | 73 | private: 74 | friend class WindowClassRegistrar; 75 | 76 | // OS callback called by message pump. Handles the WM_NCCREATE message which 77 | // is passed when the non-client area is being created and enables automatic 78 | // non-client DPI scaling so that the non-client area automatically 79 | // responsponds to changes in DPI. All other messages are handled by 80 | // MessageHandler. 81 | static LRESULT CALLBACK WndProc(HWND const window, 82 | UINT const message, 83 | WPARAM const wparam, 84 | LPARAM const lparam) noexcept; 85 | 86 | // Retrieves a class instance pointer for |window| 87 | static Win32Window* GetThisFromHandle(HWND const window) noexcept; 88 | 89 | bool quit_on_close_ = false; 90 | 91 | // window handle for top level window. 92 | HWND window_handle_ = nullptr; 93 | 94 | // window handle for hosted content. 95 | HWND child_content_ = nullptr; 96 | }; 97 | 98 | #endif // RUNNER_WIN32_WINDOW_H_ 99 | -------------------------------------------------------------------------------- /windows/flutter/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # This file controls Flutter-level build steps. It should not be edited. 2 | cmake_minimum_required(VERSION 3.14) 3 | 4 | set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral") 5 | 6 | # Configuration provided via flutter tool. 7 | include(${EPHEMERAL_DIR}/generated_config.cmake) 8 | 9 | # TODO: Move the rest of this into files in ephemeral. See 10 | # https://github.com/flutter/flutter/issues/57146. 11 | set(WRAPPER_ROOT "${EPHEMERAL_DIR}/cpp_client_wrapper") 12 | 13 | # === Flutter Library === 14 | set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/flutter_windows.dll") 15 | 16 | # Published to parent scope for install step. 17 | set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE) 18 | set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE) 19 | set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE) 20 | set(AOT_LIBRARY "${PROJECT_DIR}/build/windows/app.so" PARENT_SCOPE) 21 | 22 | list(APPEND FLUTTER_LIBRARY_HEADERS 23 | "flutter_export.h" 24 | "flutter_windows.h" 25 | "flutter_messenger.h" 26 | "flutter_plugin_registrar.h" 27 | "flutter_texture_registrar.h" 28 | ) 29 | list(TRANSFORM FLUTTER_LIBRARY_HEADERS PREPEND "${EPHEMERAL_DIR}/") 30 | add_library(flutter INTERFACE) 31 | target_include_directories(flutter INTERFACE 32 | "${EPHEMERAL_DIR}" 33 | ) 34 | target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}.lib") 35 | add_dependencies(flutter flutter_assemble) 36 | 37 | # === Wrapper === 38 | list(APPEND CPP_WRAPPER_SOURCES_CORE 39 | "core_implementations.cc" 40 | "standard_codec.cc" 41 | ) 42 | list(TRANSFORM CPP_WRAPPER_SOURCES_CORE PREPEND "${WRAPPER_ROOT}/") 43 | list(APPEND CPP_WRAPPER_SOURCES_PLUGIN 44 | "plugin_registrar.cc" 45 | ) 46 | list(TRANSFORM CPP_WRAPPER_SOURCES_PLUGIN PREPEND "${WRAPPER_ROOT}/") 47 | list(APPEND CPP_WRAPPER_SOURCES_APP 48 | "flutter_engine.cc" 49 | "flutter_view_controller.cc" 50 | ) 51 | list(TRANSFORM CPP_WRAPPER_SOURCES_APP PREPEND "${WRAPPER_ROOT}/") 52 | 53 | # Wrapper sources needed for a plugin. 54 | add_library(flutter_wrapper_plugin STATIC 55 | ${CPP_WRAPPER_SOURCES_CORE} 56 | ${CPP_WRAPPER_SOURCES_PLUGIN} 57 | ) 58 | apply_standard_settings(flutter_wrapper_plugin) 59 | set_target_properties(flutter_wrapper_plugin PROPERTIES 60 | POSITION_INDEPENDENT_CODE ON) 61 | set_target_properties(flutter_wrapper_plugin PROPERTIES 62 | CXX_VISIBILITY_PRESET hidden) 63 | target_link_libraries(flutter_wrapper_plugin PUBLIC flutter) 64 | target_include_directories(flutter_wrapper_plugin PUBLIC 65 | "${WRAPPER_ROOT}/include" 66 | ) 67 | add_dependencies(flutter_wrapper_plugin flutter_assemble) 68 | 69 | # Wrapper sources needed for the runner. 70 | add_library(flutter_wrapper_app STATIC 71 | ${CPP_WRAPPER_SOURCES_CORE} 72 | ${CPP_WRAPPER_SOURCES_APP} 73 | ) 74 | apply_standard_settings(flutter_wrapper_app) 75 | target_link_libraries(flutter_wrapper_app PUBLIC flutter) 76 | target_include_directories(flutter_wrapper_app PUBLIC 77 | "${WRAPPER_ROOT}/include" 78 | ) 79 | add_dependencies(flutter_wrapper_app flutter_assemble) 80 | 81 | # === Flutter tool backend === 82 | # _phony_ is a non-existent file to force this command to run every time, 83 | # since currently there's no way to get a full input/output list from the 84 | # flutter tool. 85 | set(PHONY_OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/_phony_") 86 | set_source_files_properties("${PHONY_OUTPUT}" PROPERTIES SYMBOLIC TRUE) 87 | add_custom_command( 88 | OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} 89 | ${CPP_WRAPPER_SOURCES_CORE} ${CPP_WRAPPER_SOURCES_PLUGIN} 90 | ${CPP_WRAPPER_SOURCES_APP} 91 | ${PHONY_OUTPUT} 92 | COMMAND ${CMAKE_COMMAND} -E env 93 | ${FLUTTER_TOOL_ENVIRONMENT} 94 | "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.bat" 95 | windows-x64 $ 96 | VERBATIM 97 | ) 98 | add_custom_target(flutter_assemble DEPENDS 99 | "${FLUTTER_LIBRARY}" 100 | ${FLUTTER_LIBRARY_HEADERS} 101 | ${CPP_WRAPPER_SOURCES_CORE} 102 | ${CPP_WRAPPER_SOURCES_PLUGIN} 103 | ${CPP_WRAPPER_SOURCES_APP} 104 | ) 105 | -------------------------------------------------------------------------------- /linux/my_application.cc: -------------------------------------------------------------------------------- 1 | #include "my_application.h" 2 | 3 | #include 4 | #ifdef GDK_WINDOWING_X11 5 | #include 6 | #endif 7 | 8 | #include "flutter/generated_plugin_registrant.h" 9 | 10 | struct _MyApplication { 11 | GtkApplication parent_instance; 12 | char** dart_entrypoint_arguments; 13 | }; 14 | 15 | G_DEFINE_TYPE(MyApplication, my_application, GTK_TYPE_APPLICATION) 16 | 17 | // Implements GApplication::activate. 18 | static void my_application_activate(GApplication* application) { 19 | MyApplication* self = MY_APPLICATION(application); 20 | GtkWindow* window = 21 | GTK_WINDOW(gtk_application_window_new(GTK_APPLICATION(application))); 22 | 23 | // Use a header bar when running in GNOME as this is the common style used 24 | // by applications and is the setup most users will be using (e.g. Ubuntu 25 | // desktop). 26 | // If running on X and not using GNOME then just use a traditional title bar 27 | // in case the window manager does more exotic layout, e.g. tiling. 28 | // If running on Wayland assume the header bar will work (may need changing 29 | // if future cases occur). 30 | gboolean use_header_bar = TRUE; 31 | #ifdef GDK_WINDOWING_X11 32 | GdkScreen* screen = gtk_window_get_screen(window); 33 | if (GDK_IS_X11_SCREEN(screen)) { 34 | const gchar* wm_name = gdk_x11_screen_get_window_manager_name(screen); 35 | if (g_strcmp0(wm_name, "GNOME Shell") != 0) { 36 | use_header_bar = FALSE; 37 | } 38 | } 39 | #endif 40 | if (use_header_bar) { 41 | GtkHeaderBar* header_bar = GTK_HEADER_BAR(gtk_header_bar_new()); 42 | gtk_widget_show(GTK_WIDGET(header_bar)); 43 | gtk_header_bar_set_title(header_bar, "hive_ui_example"); 44 | gtk_header_bar_set_show_close_button(header_bar, TRUE); 45 | gtk_window_set_titlebar(window, GTK_WIDGET(header_bar)); 46 | } else { 47 | gtk_window_set_title(window, "hive_ui_example"); 48 | } 49 | 50 | gtk_window_set_default_size(window, 1280, 720); 51 | gtk_widget_show(GTK_WIDGET(window)); 52 | 53 | g_autoptr(FlDartProject) project = fl_dart_project_new(); 54 | fl_dart_project_set_dart_entrypoint_arguments(project, self->dart_entrypoint_arguments); 55 | 56 | FlView* view = fl_view_new(project); 57 | gtk_widget_show(GTK_WIDGET(view)); 58 | gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(view)); 59 | 60 | fl_register_plugins(FL_PLUGIN_REGISTRY(view)); 61 | 62 | gtk_widget_grab_focus(GTK_WIDGET(view)); 63 | } 64 | 65 | // Implements GApplication::local_command_line. 66 | static gboolean my_application_local_command_line(GApplication* application, gchar*** arguments, int* exit_status) { 67 | MyApplication* self = MY_APPLICATION(application); 68 | // Strip out the first argument as it is the binary name. 69 | self->dart_entrypoint_arguments = g_strdupv(*arguments + 1); 70 | 71 | g_autoptr(GError) error = nullptr; 72 | if (!g_application_register(application, nullptr, &error)) { 73 | g_warning("Failed to register: %s", error->message); 74 | *exit_status = 1; 75 | return TRUE; 76 | } 77 | 78 | g_application_activate(application); 79 | *exit_status = 0; 80 | 81 | return TRUE; 82 | } 83 | 84 | // Implements GObject::dispose. 85 | static void my_application_dispose(GObject* object) { 86 | MyApplication* self = MY_APPLICATION(object); 87 | g_clear_pointer(&self->dart_entrypoint_arguments, g_strfreev); 88 | G_OBJECT_CLASS(my_application_parent_class)->dispose(object); 89 | } 90 | 91 | static void my_application_class_init(MyApplicationClass* klass) { 92 | G_APPLICATION_CLASS(klass)->activate = my_application_activate; 93 | G_APPLICATION_CLASS(klass)->local_command_line = my_application_local_command_line; 94 | G_OBJECT_CLASS(klass)->dispose = my_application_dispose; 95 | } 96 | 97 | static void my_application_init(MyApplication* self) {} 98 | 99 | MyApplication* my_application_new() { 100 | return MY_APPLICATION(g_object_new(my_application_get_type(), 101 | "application-id", APPLICATION_ID, 102 | "flags", G_APPLICATION_NON_UNIQUE, 103 | nullptr)); 104 | } 105 | -------------------------------------------------------------------------------- /lib/search/search_widget.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | import 'drop_down_search/dropdown.dart'; 4 | 5 | class SearchWidget extends StatefulWidget { 6 | final SearchScope scope; 7 | final void Function(String searchValue) onSearch; 8 | final void Function(String searchValue)? onSearchValue; 9 | final List fields; 10 | const SearchWidget({ 11 | Key? key, 12 | required this.scope, 13 | required this.onSearch, 14 | this.onSearchValue, 15 | this.fields = const [], 16 | }) : super(key: key); 17 | 18 | @override 19 | State createState() => _SearchWidgetState(); 20 | } 21 | 22 | class _SearchWidgetState extends State { 23 | late TextEditingController textEditingController; 24 | late TextEditingController textEditingController2; 25 | @override 26 | void initState() { 27 | textEditingController = TextEditingController(); 28 | textEditingController2 = TextEditingController(); 29 | super.initState(); 30 | } 31 | 32 | @override 33 | void dispose() { 34 | try { 35 | textEditingController.dispose(); 36 | textEditingController2.dispose(); 37 | } catch (e) {} 38 | 39 | super.dispose(); 40 | } 41 | 42 | @override 43 | Widget build(BuildContext context) { 44 | final hintText = 45 | widget.scope == SearchScope.box ? "Search Boxes" : "Search Field"; 46 | return Row( 47 | children: [ 48 | if (widget.scope == SearchScope.box) 49 | Container( 50 | padding: const EdgeInsets.symmetric( 51 | horizontal: 24, 52 | vertical: 8, 53 | ), 54 | height: 65, 55 | width: MediaQuery.of(context).size.width * 0.25, 56 | child: TextFormField( 57 | controller: textEditingController, 58 | onChanged: widget.onSearch, 59 | decoration: InputDecoration( 60 | border: const OutlineInputBorder(), 61 | contentPadding: const EdgeInsets.symmetric( 62 | horizontal: 16, 63 | ), 64 | hintText: hintText, 65 | ), 66 | ), 67 | ) 68 | else 69 | Container( 70 | padding: const EdgeInsets.symmetric( 71 | horizontal: 24, 72 | vertical: 8, 73 | ), 74 | constraints: BoxConstraints.loose( 75 | Size( 76 | MediaQuery.of(context).size.width * 0.3, 77 | 65, 78 | ), 79 | ), 80 | child: DropdownFormField( 81 | decoration: const InputDecoration( 82 | border: OutlineInputBorder(), 83 | contentPadding: EdgeInsets.symmetric(horizontal: 16), 84 | ), 85 | onChanged: widget.onSearch, 86 | displayItemFn: (str) => Text(str ?? ""), 87 | findFn: (str) async => widget.fields 88 | .where((element) => element.startsWith(str)) 89 | .toList(), 90 | dropdownItemFn: (item, position, focused, selected, onTap) { 91 | return ListTile( 92 | title: Text(item), 93 | tileColor: focused ? Colors.grey : Colors.transparent, 94 | onTap: onTap, 95 | ); 96 | }, 97 | ), 98 | ), 99 | if (widget.scope == SearchScope.field) 100 | Container( 101 | padding: const EdgeInsets.symmetric( 102 | horizontal: 24, 103 | vertical: 8, 104 | ), 105 | height: 65, 106 | width: MediaQuery.of(context).size.width * 0.25, 107 | child: TextFormField( 108 | controller: textEditingController2, 109 | onChanged: widget.onSearchValue, 110 | decoration: const InputDecoration( 111 | border: OutlineInputBorder(), 112 | contentPadding: EdgeInsets.symmetric( 113 | horizontal: 16, 114 | ), 115 | hintText: "Search Value", 116 | ), 117 | ), 118 | ), 119 | ], 120 | ); 121 | } 122 | } 123 | 124 | enum SearchScope { 125 | box, 126 | field, 127 | } 128 | -------------------------------------------------------------------------------- /windows/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Project-level configuration. 2 | cmake_minimum_required(VERSION 3.14) 3 | project(hive_ui_example LANGUAGES CXX) 4 | 5 | # The name of the executable created for the application. Change this to change 6 | # the on-disk name of your application. 7 | set(BINARY_NAME "hive_ui_example") 8 | 9 | # Explicitly opt in to modern CMake behaviors to avoid warnings with recent 10 | # versions of CMake. 11 | cmake_policy(SET CMP0063 NEW) 12 | 13 | # Define build configuration option. 14 | get_property(IS_MULTICONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) 15 | if(IS_MULTICONFIG) 16 | set(CMAKE_CONFIGURATION_TYPES "Debug;Profile;Release" 17 | CACHE STRING "" FORCE) 18 | else() 19 | if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) 20 | set(CMAKE_BUILD_TYPE "Debug" CACHE 21 | STRING "Flutter build mode" FORCE) 22 | set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS 23 | "Debug" "Profile" "Release") 24 | endif() 25 | endif() 26 | # Define settings for the Profile build mode. 27 | set(CMAKE_EXE_LINKER_FLAGS_PROFILE "${CMAKE_EXE_LINKER_FLAGS_RELEASE}") 28 | set(CMAKE_SHARED_LINKER_FLAGS_PROFILE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE}") 29 | set(CMAKE_C_FLAGS_PROFILE "${CMAKE_C_FLAGS_RELEASE}") 30 | set(CMAKE_CXX_FLAGS_PROFILE "${CMAKE_CXX_FLAGS_RELEASE}") 31 | 32 | # Use Unicode for all projects. 33 | add_definitions(-DUNICODE -D_UNICODE) 34 | 35 | # Compilation settings that should be applied to most targets. 36 | # 37 | # Be cautious about adding new options here, as plugins use this function by 38 | # default. In most cases, you should add new options to specific targets instead 39 | # of modifying this function. 40 | function(APPLY_STANDARD_SETTINGS TARGET) 41 | target_compile_features(${TARGET} PUBLIC cxx_std_17) 42 | target_compile_options(${TARGET} PRIVATE /W4 /WX /wd"4100") 43 | target_compile_options(${TARGET} PRIVATE /EHsc) 44 | target_compile_definitions(${TARGET} PRIVATE "_HAS_EXCEPTIONS=0") 45 | target_compile_definitions(${TARGET} PRIVATE "$<$:_DEBUG>") 46 | endfunction() 47 | 48 | # Flutter library and tool build rules. 49 | set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") 50 | add_subdirectory(${FLUTTER_MANAGED_DIR}) 51 | 52 | # Application build; see runner/CMakeLists.txt. 53 | add_subdirectory("runner") 54 | 55 | # Generated plugin build rules, which manage building the plugins and adding 56 | # them to the application. 57 | include(flutter/generated_plugins.cmake) 58 | 59 | 60 | # === Installation === 61 | # Support files are copied into place next to the executable, so that it can 62 | # run in place. This is done instead of making a separate bundle (as on Linux) 63 | # so that building and running from within Visual Studio will work. 64 | set(BUILD_BUNDLE_DIR "$") 65 | # Make the "install" step default, as it's required to run. 66 | set(CMAKE_VS_INCLUDE_INSTALL_TO_DEFAULT_BUILD 1) 67 | if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) 68 | set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE) 69 | endif() 70 | 71 | set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data") 72 | set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}") 73 | 74 | install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}" 75 | COMPONENT Runtime) 76 | 77 | install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" 78 | COMPONENT Runtime) 79 | 80 | install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" 81 | COMPONENT Runtime) 82 | 83 | if(PLUGIN_BUNDLED_LIBRARIES) 84 | install(FILES "${PLUGIN_BUNDLED_LIBRARIES}" 85 | DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" 86 | COMPONENT Runtime) 87 | endif() 88 | 89 | # Fully re-copy the assets directory on each build to avoid having stale files 90 | # from a previous install. 91 | set(FLUTTER_ASSET_DIR_NAME "flutter_assets") 92 | install(CODE " 93 | file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\") 94 | " COMPONENT Runtime) 95 | install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}" 96 | DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) 97 | 98 | # Install the AOT library on non-Debug builds only. 99 | install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" 100 | CONFIGURATIONS Profile;Release 101 | COMPONENT Runtime) 102 | -------------------------------------------------------------------------------- /lib/extensions.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | 3 | import 'package:flutter/material.dart'; 4 | 5 | import 'boxes_view.dart'; 6 | import 'services/flutter_clipboard_hive_ui.dart'; 7 | import 'widgets/hive_boxes_details.dart'; 8 | import 'widgets/list_details_dialog.dart'; 9 | 10 | bool isMap(dynamic fieldValue) { 11 | bool containKeys = false; 12 | try { 13 | containKeys = fieldValue is Map; 14 | } on TypeError { 15 | containKeys = false; 16 | } 17 | return containKeys; 18 | } 19 | 20 | bool isList(dynamic fieldValue) { 21 | try { 22 | fieldValue.toList(); 23 | return true; 24 | } catch (e) { 25 | return false; 26 | } 27 | } 28 | 29 | mixin BoxViewMixin on State { 30 | void showListDetailsDialog(String title, List values) => showDialog( 31 | context: context, 32 | builder: (_) => ListDetailsDialog(values: values, title: title), 33 | ); 34 | 35 | DataColumn buildColumn(String columnTitle) => DataColumn( 36 | label: Center( 37 | child: Text( 38 | columnTitle, 39 | textAlign: TextAlign.center, 40 | ), 41 | ), 42 | ); 43 | DataRow buildRow({ 44 | required Map objectAsJson, 45 | required FieldPressedCallback onFieldPressed, 46 | required int cellsNumber, 47 | required int objectIndex, 48 | required void Function({ 49 | required bool selected, 50 | required int index, 51 | }) 52 | onSelectRow, 53 | required bool isSelected, 54 | required bool enableSelection, 55 | required List keys, 56 | }) { 57 | String dataCellValue( 58 | dynamic field, 59 | ) { 60 | if (field.runtimeType == List>) { 61 | return 'List OF Objects'; 62 | } else if (isMap(field)) { 63 | return "Object"; 64 | } else if (isList(field)) { 65 | return 'List'; 66 | } else { 67 | return field.toString(); 68 | } 69 | } 70 | 71 | List rowKeys = []; 72 | rowKeys = keys; 73 | 74 | return DataRow( 75 | onSelectChanged: !enableSelection 76 | ? null 77 | : (isSelected) => 78 | onSelectRow(selected: isSelected!, index: objectIndex), 79 | selected: isSelected, 80 | cells: rowKeys.map((fieldName) { 81 | final cellValue = dataCellValue(objectAsJson[fieldName]); 82 | final isList = cellValue == 'List'; 83 | return DataCell( 84 | onLongPress: () { 85 | final value = objectAsJson[fieldName]; 86 | final json = const JsonEncoder.withIndent(' ').convert(value); 87 | FlutterClipboardHiveUi.copy(json); 88 | }, 89 | Center( 90 | child: Text( 91 | cellValue, 92 | ), 93 | ), 94 | onTap: () => !isList 95 | ? onFieldPressed( 96 | "boxName", 97 | fieldName, 98 | objectAsJson, 99 | objectIndex: objectIndex, 100 | ) 101 | : showListDetailsDialog( 102 | fieldName, 103 | objectAsJson[fieldName] as List, 104 | ), 105 | ); 106 | }).toList(), 107 | ); 108 | } 109 | 110 | List mapToDataColumns(List columnKeys) { 111 | if (columnKeys.isEmpty) { 112 | return []; 113 | } else { 114 | return columnKeys.map(buildColumn).toList(); 115 | } 116 | } 117 | 118 | List mapToDataRows( 119 | List> nestedObject, 120 | FieldPressedCallback onFieldPressed, 121 | int cellsNumber, 122 | void Function({required bool selected, required int index}) onSelectRow, 123 | List selectedRows, 124 | bool enableSelection, 125 | List keys, 126 | ) { 127 | return nestedObject.map((obj) { 128 | final index = nestedObject.indexOf(obj); 129 | final isSelected = selectedRows.contains(index); 130 | return buildRow( 131 | objectAsJson: obj, 132 | onFieldPressed: onFieldPressed, 133 | cellsNumber: cellsNumber, 134 | objectIndex: index, 135 | isSelected: isSelected, 136 | onSelectRow: onSelectRow, 137 | enableSelection: enableSelection, 138 | keys: keys, 139 | ); 140 | }).toList(); 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Hive UI 2 | [![Build Status](https://travis-ci.org/joemccann/dillinger.svg?branch=master)](https://travis-ci.org/joemccann/dillinger) 3 | 4 | 5 | A Flutter package that allows you to easily work with Hive databases. With this package, you can explore all database boxes, edit table rows, add new rows to tables, search boxes by column name and value, delete rows or all data from a box, copy selected values and select specific color for the Hive UI view. 6 | 7 | ## Features 8 | - Explore all database boxes 9 | - Edit any table rows and set new values 10 | - Add new row to table database 11 | - Search boxes by column name and value 12 | - Delete a single row or all data from a box 13 | - Copy selected values 14 | - Select specific color for the Hive UI view 15 | - Support all platfoem (Android - Web - IOS - Windows - Linux - Mac ) 16 | 17 | 18 | ![alt text](https://github.com/AmrSaied/hive_ui/blob/main/TableList.png?raw=true) 19 | ![alt text](https://github.com/AmrSaied/hive_ui/blob/main/TableDetails.png?raw=true) 20 | ![alt text](https://github.com/AmrSaied/hive_ui/blob/main/AddNewRow.png?raw=true) 21 | ![alt text](https://github.com/AmrSaied/hive_ui/blob/main/EditRow.png?raw=true) 22 | 23 | 24 | 25 | 26 | ## Requirements 27 | - Hive must be installed 28 | - All boxes must be open 29 | - toJson and fromJson methods must be implemented for each box 30 | 31 | ## Usage 32 | - Add the package as a dependency in your 'pubspec.yaml' file: 33 | ```sh 34 | dependencies: 35 | hive_ui: ^1.0.4 36 | ``` 37 | - Import the package in your dart file where you want to use it by adding the following line at the top of the file: 38 | 39 | ```sh 40 | import 'package:hive_ui/hive_ui.dart'; 41 | ``` 42 | - To route to the Hive UI view: 43 | ```sh 44 | Navigator.push( 45 | context, 46 | MaterialPageRoute(builder: (context) => HiveBoxesView( 47 | hiveBoxes: Boxes.allBoxes, 48 | onError: (String errorMessage) => 49 | { 50 | print(errorMessage) 51 | })), 52 | ); 53 | ``` 54 | - Example for Box view: 55 | ```sh 56 | class BoxExample extends HiveObject { 57 | BoxExample({ 58 | this.id, 59 | }); 60 | BoxExample.fromJson(dynamic json) { 61 | id = json['id'] ?? ''; 62 | } 63 | @HiveField(0) 64 | String? id; 65 | Map toJson() { 66 | final Map map = {}; 67 | map['id'] = id; 68 | } 69 | ``` 70 | 71 | ## Example 72 | You can see a full example of how to use the package in the [Example] example directory. 73 | 74 | ## Issues 75 | If you encounter any issues while using the package, please file a bug report in [the GitHub issue tracker]. 76 | 77 | 78 | ## Contributing 79 | 80 | If you would like to contribute to the package, please read the [contributing guidelines] before submitting a pull request. 81 | 82 | 83 | ## HiveBoxesView Parameters 84 | | Parameters | Name | 85 | | ------ | ------ | 86 | | hiveBoxes | The hiveBoxes parameter is a map of boxes to display. In this example, it is set to Boxes.allBoxes, which likely refers to a static property of a Boxes class that contains all the boxes that need to be displayed.| 87 | | onError | The onError parameter is a callback function that is called when an error occurs. In this example, it is set to a function that shows a toast message with the error message passed as a parameter. | 88 | | dateFormat | The dateFormat parameter is the format of the date and time that is used in the view. In this example, it is set to the format "yyyy-MM-dd".| 89 | | appBarColor |The appBarColor parameter is the color of the app bar. In this example, it is set to a variable called primaryColor. | 90 | | columnTitleTextStyle | he columnTitleTextStyle and rowTitleTextStyle parameters are the text styles of the column and row titles respectively. In this example, they are set to specific styles with fontWeight: FontWeight.w600 and fontSize: 14.sp for columns and fontSize: 12.sp for rows.| 91 | 92 | 93 | 94 | 95 | 96 | 97 | **Free Software, Hell Yeah!** 98 | 99 | [//]: # (These are reference links used in the body of this note and get stripped out when the markdown processor does its job. There is no need to format nicely because it shouldn't be seen. Thanks SO - http://stackoverflow.com/questions/4823468/store-comments-in-markdown-syntax) 100 | 101 | [Example]: 102 | [the GitHub issue tracker]: 103 | [contributing guidelines]: 104 | 105 | 106 | 107 | 108 | -------------------------------------------------------------------------------- /linux/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Project-level configuration. 2 | cmake_minimum_required(VERSION 3.10) 3 | project(runner LANGUAGES CXX) 4 | 5 | # The name of the executable created for the application. Change this to change 6 | # the on-disk name of your application. 7 | set(BINARY_NAME "hive_ui_example") 8 | # The unique GTK application identifier for this application. See: 9 | # https://wiki.gnome.org/HowDoI/ChooseApplicationID 10 | set(APPLICATION_ID "com.hive_ui_example.hive_ui_example") 11 | 12 | # Explicitly opt in to modern CMake behaviors to avoid warnings with recent 13 | # versions of CMake. 14 | cmake_policy(SET CMP0063 NEW) 15 | 16 | # Load bundled libraries from the lib/ directory relative to the binary. 17 | set(CMAKE_INSTALL_RPATH "$ORIGIN/lib") 18 | 19 | # Root filesystem for cross-building. 20 | if(FLUTTER_TARGET_PLATFORM_SYSROOT) 21 | set(CMAKE_SYSROOT ${FLUTTER_TARGET_PLATFORM_SYSROOT}) 22 | set(CMAKE_FIND_ROOT_PATH ${CMAKE_SYSROOT}) 23 | set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) 24 | set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) 25 | set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) 26 | set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) 27 | endif() 28 | 29 | # Define build configuration options. 30 | if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) 31 | set(CMAKE_BUILD_TYPE "Debug" CACHE 32 | STRING "Flutter build mode" FORCE) 33 | set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS 34 | "Debug" "Profile" "Release") 35 | endif() 36 | 37 | # Compilation settings that should be applied to most targets. 38 | # 39 | # Be cautious about adding new options here, as plugins use this function by 40 | # default. In most cases, you should add new options to specific targets instead 41 | # of modifying this function. 42 | function(APPLY_STANDARD_SETTINGS TARGET) 43 | target_compile_features(${TARGET} PUBLIC cxx_std_14) 44 | target_compile_options(${TARGET} PRIVATE -Wall -Werror) 45 | target_compile_options(${TARGET} PRIVATE "$<$>:-O3>") 46 | target_compile_definitions(${TARGET} PRIVATE "$<$>:NDEBUG>") 47 | endfunction() 48 | 49 | # Flutter library and tool build rules. 50 | set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") 51 | add_subdirectory(${FLUTTER_MANAGED_DIR}) 52 | 53 | # System-level dependencies. 54 | find_package(PkgConfig REQUIRED) 55 | pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) 56 | 57 | add_definitions(-DAPPLICATION_ID="${APPLICATION_ID}") 58 | 59 | # Define the application target. To change its name, change BINARY_NAME above, 60 | # not the value here, or `flutter run` will no longer work. 61 | # 62 | # Any new source files that you add to the application should be added here. 63 | add_executable(${BINARY_NAME} 64 | "main.cc" 65 | "my_application.cc" 66 | "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" 67 | ) 68 | 69 | # Apply the standard set of build settings. This can be removed for applications 70 | # that need different build settings. 71 | apply_standard_settings(${BINARY_NAME}) 72 | 73 | # Add dependency libraries. Add any application-specific dependencies here. 74 | target_link_libraries(${BINARY_NAME} PRIVATE flutter) 75 | target_link_libraries(${BINARY_NAME} PRIVATE PkgConfig::GTK) 76 | 77 | # Run the Flutter tool portions of the build. This must not be removed. 78 | add_dependencies(${BINARY_NAME} flutter_assemble) 79 | 80 | # Only the install-generated bundle's copy of the executable will launch 81 | # correctly, since the resources must in the right relative locations. To avoid 82 | # people trying to run the unbundled copy, put it in a subdirectory instead of 83 | # the default top-level location. 84 | set_target_properties(${BINARY_NAME} 85 | PROPERTIES 86 | RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/intermediates_do_not_run" 87 | ) 88 | 89 | # Generated plugin build rules, which manage building the plugins and adding 90 | # them to the application. 91 | include(flutter/generated_plugins.cmake) 92 | 93 | 94 | # === Installation === 95 | # By default, "installing" just makes a relocatable bundle in the build 96 | # directory. 97 | set(BUILD_BUNDLE_DIR "${PROJECT_BINARY_DIR}/bundle") 98 | if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) 99 | set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE) 100 | endif() 101 | 102 | # Start with a clean build bundle directory every time. 103 | install(CODE " 104 | file(REMOVE_RECURSE \"${BUILD_BUNDLE_DIR}/\") 105 | " COMPONENT Runtime) 106 | 107 | set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data") 108 | set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib") 109 | 110 | install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}" 111 | COMPONENT Runtime) 112 | 113 | install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" 114 | COMPONENT Runtime) 115 | 116 | install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" 117 | COMPONENT Runtime) 118 | 119 | foreach(bundled_library ${PLUGIN_BUNDLED_LIBRARIES}) 120 | install(FILES "${bundled_library}" 121 | DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" 122 | COMPONENT Runtime) 123 | endforeach(bundled_library) 124 | 125 | # Fully re-copy the assets directory on each build to avoid having stale files 126 | # from a previous install. 127 | set(FLUTTER_ASSET_DIR_NAME "flutter_assets") 128 | install(CODE " 129 | file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\") 130 | " COMPONENT Runtime) 131 | install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}" 132 | DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) 133 | 134 | # Install the AOT library on non-Debug builds only. 135 | if(NOT CMAKE_BUILD_TYPE MATCHES "Debug") 136 | install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" 137 | COMPONENT Runtime) 138 | endif() 139 | -------------------------------------------------------------------------------- /test/core/box_update_handler_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/foundation.dart'; 2 | import 'package:flutter/services.dart'; 3 | import 'package:flutter_test/flutter_test.dart'; 4 | import 'package:hive_flutter/adapters.dart'; 5 | // import 'package:hive/hive.dart'; 6 | import 'package:hive_ui/core/box_update_handler.dart'; 7 | import 'package:hive_ui/core/hive_view_state.dart'; 8 | import 'package:mockito/mockito.dart'; 9 | 10 | import '../../example/lib/boxes.dart'; 11 | 12 | // import '../../example/lib/boxes.dart'; 13 | 14 | class BoxUpdateHandlerMock extends Mock implements BoxUpdateHandler {} 15 | 16 | void main() async { 17 | const String macOs = 'plugins.flutter.io/path_provider_macos'; 18 | const String windows = 'plugins.flutter.io/path_provider'; 19 | 20 | TestWidgetsFlutterBinding.ensureInitialized(); 21 | const MethodChannel channel = MethodChannel(windows); 22 | const MethodChannel channelMac = MethodChannel(macOs); 23 | channelMac.setMockMethodCallHandler((MethodCall call) async { 24 | return "."; 25 | }); 26 | channel.setMockMethodCallHandler((MethodCall methodCall) async { 27 | return "."; 28 | }); 29 | Boxes.initHive(); 30 | 31 | late Box currentBox; 32 | late HiveViewState hiveViewState; 33 | late BoxUpdateHandler boxUpdateHandlerMock; 34 | 35 | setUpAll(() async { 36 | currentBox = await Hive.openBox('testBox'); 37 | hiveViewState = HiveViewState( 38 | boxesMap: {currentBox: (json) => json}, 39 | currentOpenedBox: currentBox, 40 | ); 41 | boxUpdateHandlerMock = BoxUpdateHandler( 42 | hiveViewState, 43 | (errorMessage) {}, 44 | ); 45 | }); 46 | tearDownAll(() { 47 | currentBox.clear(); 48 | currentBox.close(); 49 | hiveViewState.clearState(); 50 | boxUpdateHandlerMock.clearBox(); 51 | }); 52 | 53 | group('BoxUpdateHandler', () { 54 | test('addObject() should return true when object is added successfully', 55 | () async { 56 | final addedObject = {"id": 1, "name": "test"}; 57 | 58 | final result = await boxUpdateHandlerMock.addObject(addedObject); 59 | 60 | expect(result, true); 61 | currentBox.close(); 62 | }); 63 | 64 | test( 65 | 'addObject() should return false when object is not added successfully', 66 | () async { 67 | // final addedObject = {"id": 1, "name": "test"}; 68 | final addedObject = {"name": "test"}; 69 | final result = await boxUpdateHandlerMock.addObject(addedObject); 70 | 71 | expect(result, false); 72 | currentBox.close(); 73 | }); 74 | 75 | test( 76 | 'addObject() should call errorCallback when exception is thrown while adding object', 77 | () async { 78 | final hiveViewState = HiveViewState( 79 | boxesMap: {currentBox: (json) => json}, 80 | // currentOpenedBox: currentBox, 81 | ); 82 | final boxUpdateHandlerMock = BoxUpdateHandler( 83 | hiveViewState, 84 | (errorMessage) { 85 | // the error is 86 | debugPrint(" errorMessage $errorMessage "); 87 | }, 88 | ); 89 | // final addedObject = {"id": 1, "name": "test"}; 90 | final addedObject = {"name": "test"}; 91 | final result = await boxUpdateHandlerMock.addObject(addedObject); 92 | 93 | expect(result, false); 94 | currentBox.close(); 95 | }); 96 | }); 97 | 98 | group('addObject', () { 99 | setUpAll(() async { 100 | currentBox = await Hive.openBox('testBox'); 101 | hiveViewState = HiveViewState( 102 | boxesMap: {currentBox: (json) => json}, 103 | currentOpenedBox: currentBox, 104 | ); 105 | boxUpdateHandlerMock = BoxUpdateHandler( 106 | hiveViewState, 107 | (errorMessage) {}, 108 | ); 109 | }); 110 | test('should add object to box', () async { 111 | final boxHandler = BoxUpdateHandler( 112 | HiveViewState( 113 | boxesMap: {currentBox: (json) => json}, 114 | currentOpenedBox: currentBox, 115 | ), 116 | (error) => print(error)); 117 | final addedObject = {"id": 1, "name": "John Doe"}; 118 | final isAdded = await boxHandler.addObject(addedObject); 119 | expect(isAdded, true); 120 | expect(currentBox.get(1), addedObject); 121 | }); 122 | test('should not add object to box and show error', () async { 123 | await currentBox.clear(); 124 | final boxHandler = BoxUpdateHandler( 125 | HiveViewState(boxesMap: {currentBox: (json) => json}), 126 | (error) => print(error)); 127 | final addedObject = {"name": "John Do"}; 128 | final isAdded = await boxHandler.addObject(addedObject); 129 | expect(isAdded, false); 130 | expect(currentBox.get(1), null); 131 | }); 132 | 133 | // focus on this please 134 | // Can not fromJsonConverter provided 135 | test( 136 | 'should not add object to box and show error if fromJsonConverter is not provided', 137 | () async { 138 | currentBox.clear(); 139 | final boxHandler = BoxUpdateHandler( 140 | HiveViewState( 141 | boxesMap: { 142 | // currentBox: (json) => null, 143 | }, 144 | currentOpenedBox: currentBox, 145 | ), 146 | (error) => print(error)); 147 | final addedObject = {"id": 1, "name": "John Doe"}; 148 | final isAdded = await boxHandler.addObject(addedObject); 149 | expect(isAdded, false); 150 | expect(currentBox.get(1), null); 151 | }); 152 | test('should not add object to box if box is not opened', () async { 153 | final boxHandler = BoxUpdateHandler( 154 | HiveViewState(boxesMap: {}), (error) => print(error)); 155 | final addedObject = {"id": 1, "name": "John Doe"}; 156 | final isAdded = await boxHandler.addObject(addedObject); 157 | expect(isAdded, false); 158 | }); 159 | }); 160 | } 161 | -------------------------------------------------------------------------------- /lib/core/box_update_handler.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:hive_flutter/adapters.dart'; 3 | 4 | import '../boxes_view.dart'; 5 | import 'hive_view_state.dart'; 6 | 7 | class BoxUpdateHandler { 8 | final HiveViewState _hiveViewState; 9 | final ErrorCallback _errorCallback; 10 | final int? objectIndex; 11 | 12 | /// BoxUpdateHandler constructor 13 | /// 14 | /// [_hiveViewState] : The HiveViewState instance. 15 | /// [_errorCallback] : The callback function to handle errors. 16 | /// [objectIndex] : Optional, the index of the object to update. 17 | BoxUpdateHandler( 18 | this._hiveViewState, 19 | this._errorCallback, { 20 | this.objectIndex, 21 | }); 22 | 23 | /// Adds an object to the current opened box 24 | /// 25 | /// [addedObject] : A Map representing the new object to be added. 26 | /// Returns a Future indicating success or failure of the operation. 27 | Future addObject(Map addedObject) async { 28 | // final currentBox = _hiveViewState.currentOpenedBox!; 29 | // try { 30 | // final fromJson = _hiveViewState.boxesMap[currentBox]!; 31 | // final newAddedObject = fromJson(addedObject); 32 | // await currentBox.put(addedObject["id"], newAddedObject); 33 | // return true; 34 | // } catch (e) { 35 | // _errorCallback(e.toString()); 36 | // return false; 37 | // } 38 | 39 | try { 40 | bool isThereBoxes = _hiveViewState.boxesMap.entries.isNotEmpty; 41 | bool isFoundOpenBox = _hiveViewState.currentOpenedBox != null; 42 | bool isHaveIdProperty = 43 | addedObject.keys.any((element) => element == "id"); 44 | if (!isThereBoxes) { 45 | _errorCallback("there is Not Boxes"); 46 | return false; 47 | } else if (!isFoundOpenBox) { 48 | _errorCallback("there is Not Open Box"); 49 | return false; 50 | } else if (!isHaveIdProperty) { 51 | _errorCallback("there is Not ID Property \n add {\"id\":(888 as id)}"); 52 | return false; 53 | } else { 54 | final currentBox = _hiveViewState.currentOpenedBox!; 55 | 56 | final fromJson = _hiveViewState.boxesMap[currentBox]!; 57 | final newAddedObject = fromJson(addedObject); 58 | await currentBox.put(addedObject["id"], newAddedObject); 59 | return true; 60 | } 61 | } catch (e) { 62 | _errorCallback(e.toString()); 63 | return false; 64 | } 65 | } 66 | 67 | /// Updates an object in the current opened box 68 | /// 69 | /// Returns a Future indicating success or failure of the operation. 70 | Future updateObject() async { 71 | final boxValue = _hiveViewState.selectedBoxValue!; 72 | final currentBox = _hiveViewState.currentOpenedBox!; 73 | Map updatedObjectJson = {}; 74 | int index = 0; 75 | if (_hiveViewState.objectNestedIndices!.isNotEmpty) { 76 | index = _hiveViewState.objectNestedIndices!.first.keys.single; 77 | updatedObjectJson = boxValue[index]; 78 | } else { 79 | index = objectIndex!; 80 | updatedObjectJson = boxValue[index]; 81 | } 82 | debugPrint(_hiveViewState.objectNestedIndices.toString()); 83 | return await _updateBoxWithObject( 84 | currentBox, 85 | index, 86 | updatedObjectJson, 87 | ); 88 | } 89 | 90 | /// Helper method to update an object in a box 91 | /// 92 | /// [box] : The Hive box. 93 | /// [indexOfObject] : The index of the object to update. 94 | /// [replacementObject] : The new object to replace the existing one. 95 | /// Returns a Future indicating success or failure of the operation. 96 | Future _updateBoxWithObject( 97 | Box box, 98 | int indexOfObject, 99 | dynamic replacementObject, 100 | ) async { 101 | try { 102 | final fromJson = _hiveViewState.boxesMap[box]!; 103 | final updatedObject = fromJson(replacementObject); 104 | await box.putAt(indexOfObject, updatedObject); 105 | return true; 106 | } catch (e) { 107 | _errorCallback(e.toString()); 108 | return false; 109 | } 110 | } 111 | 112 | /// Deletes a field of an object in the current opened box 113 | /// 114 | /// Returns a Future indicating success or failure of the operation. 115 | Future deleteFieldOfObject() async { 116 | final viewState = _hiveViewState; 117 | final currentBox = viewState.currentOpenedBox!; 118 | var boxValue = viewState.selectedBoxValue!; 119 | final indices = viewState.objectNestedIndices!; 120 | final firstIndexMap = indices.first; 121 | final lastIndexMap = indices.last; 122 | var refObj = 123 | boxValue[firstIndexMap.keys.single][firstIndexMap.values.single]; 124 | if (indices.length == 1) { 125 | refObj.clear(); 126 | } else { 127 | for (var indexMap in indices..removeAt(0)) { 128 | if (indexMap == lastIndexMap) { 129 | refObj[indexMap.values.single].clear(); 130 | } else if (indexMap.keys.single == -1) { 131 | refObj = refObj[indexMap.values.single]; 132 | } else { 133 | refObj = refObj[indexMap.keys.single][indexMap.values.single]; 134 | } 135 | } 136 | } 137 | final replacementObject = boxValue[firstIndexMap.keys.single]; 138 | 139 | return await _updateBoxWithObject( 140 | currentBox, 141 | firstIndexMap.keys.single, 142 | replacementObject, 143 | ); 144 | } 145 | 146 | /// Deletes multiple rows of an object in the current opened box 147 | /// 148 | /// [rowIndices] : A list of indices of the rows to delete. 149 | /// Returns a Future indicating success or failure of the operation. 150 | Future deleteRowObject(List rowIndices) async { 151 | final viewState = _hiveViewState; 152 | final currentBox = viewState.currentOpenedBox!; 153 | var boxValue = viewState.selectedBoxValue!; 154 | final nestedObjectIndices = viewState.objectNestedIndices!; 155 | if (nestedObjectIndices.isEmpty) { 156 | try { 157 | for (var index in rowIndices) { 158 | await currentBox.deleteAt(index); 159 | } 160 | return true; 161 | } catch (e) { 162 | _errorCallback(e.toString()); 163 | return false; 164 | } 165 | } else { 166 | final firstIndexMap = nestedObjectIndices.first; 167 | final lastIndexMap = nestedObjectIndices.last; 168 | var refObj = 169 | boxValue[firstIndexMap.keys.single][firstIndexMap.values.single]; 170 | if (nestedObjectIndices.length == 1) { 171 | for (int index in rowIndices) { 172 | refObj.removeAt(index); 173 | } 174 | } else { 175 | for (var indexMap in nestedObjectIndices..removeAt(0)) { 176 | if (indexMap == lastIndexMap) { 177 | for (int index in rowIndices) { 178 | refObj[indexMap.values.single].removeAt(index); 179 | } 180 | } else if (indexMap.keys.single == -1) { 181 | refObj = refObj[indexMap.values.single]; 182 | } else { 183 | refObj = refObj[indexMap.keys.single][indexMap.values.single]; 184 | } 185 | } 186 | } 187 | final replacementObject = boxValue[firstIndexMap.keys.single]; 188 | 189 | return await _updateBoxWithObject( 190 | currentBox, 191 | firstIndexMap.keys.single, 192 | replacementObject, 193 | ); 194 | } 195 | } 196 | 197 | Future clearBox() async { 198 | try { 199 | await _hiveViewState.currentOpenedBox?.clear(); 200 | return true; 201 | } catch (e) { 202 | _errorCallback(e.toString()); 203 | return false; 204 | } 205 | } 206 | } 207 | -------------------------------------------------------------------------------- /lib/widgets/number_pagination_hive_ui.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class NumberPaginationPageHiveUi extends StatefulWidget { 4 | /// Creates a NumberPagination widget. 5 | 6 | ///Trigger when page changed 7 | final Function(int) onPageChanged; 8 | 9 | ///End of numbers. 10 | final int pageTotal; 11 | 12 | ///Page number to be displayed first 13 | final int pageInit; 14 | 15 | ///Numbers to show at once. 16 | final int threshold; 17 | 18 | ///Color of numbers. 19 | final Color colorPrimary; 20 | 21 | ///Color of background. 22 | final Color colorSub; 23 | 24 | ///to First, to Previous, to next, to Last Button UI. 25 | final Widget? controlButton; 26 | 27 | ///The icon of button to first. 28 | final Widget? iconToFirst; 29 | 30 | ///The icon of button to previous. 31 | final Widget? iconPrevious; 32 | 33 | ///The icon of button to next. 34 | final Widget? iconNext; 35 | 36 | ///The icon of button to last. 37 | final Widget? iconToLast; 38 | 39 | ///The size of numbers. 40 | final double fontSize; 41 | 42 | ///The fontFamily of numbers. 43 | final String? fontFamily; 44 | 45 | const NumberPaginationPageHiveUi({ 46 | super.key, 47 | required this.onPageChanged, 48 | required this.pageTotal, 49 | this.threshold = 10, 50 | this.pageInit = 1, 51 | this.colorPrimary = Colors.black, 52 | this.colorSub = Colors.white, 53 | this.controlButton, 54 | this.iconToFirst, 55 | this.iconPrevious, 56 | this.iconNext, 57 | this.iconToLast, 58 | this.fontSize = 15, 59 | this.fontFamily, 60 | }); 61 | 62 | @override 63 | _NumberPaginationPageHiveUiState createState() => 64 | _NumberPaginationPageHiveUiState(); 65 | } 66 | 67 | class _NumberPaginationPageHiveUiState 68 | extends State { 69 | late int rangeStart; 70 | late int rangeEnd; 71 | late int currentPage; 72 | late final Widget iconToFirst; 73 | late final Widget iconPrevious; 74 | late final Widget iconNext; 75 | late final Widget iconToLast; 76 | 77 | @override 78 | void initState() { 79 | currentPage = widget.pageInit; 80 | iconToFirst = widget.iconToFirst ?? const Icon(Icons.first_page); 81 | iconPrevious = widget.iconPrevious ?? const Icon(Icons.keyboard_arrow_left); 82 | iconNext = widget.iconNext ?? const Icon(Icons.keyboard_arrow_right); 83 | iconToLast = widget.iconToLast ?? const Icon(Icons.last_page); 84 | 85 | _rangeSet(); 86 | 87 | super.initState(); 88 | } 89 | 90 | Widget _defaultControlButton(Widget icon) { 91 | return AbsorbPointer( 92 | child: TextButton( 93 | style: ButtonStyle( 94 | elevation: MaterialStateProperty.all(5.0), 95 | padding: MaterialStateProperty.all(EdgeInsets.zero), 96 | minimumSize: MaterialStateProperty.all(const Size(48, 48)), 97 | foregroundColor: MaterialStateProperty.all(widget.colorPrimary), 98 | backgroundColor: MaterialStateProperty.all(widget.colorSub), 99 | ), 100 | onPressed: () {}, 101 | child: icon, 102 | ), 103 | ); 104 | } 105 | 106 | void _changePage(int page) { 107 | if (page <= 0) page = 1; 108 | 109 | if (page > widget.pageTotal) page = widget.pageTotal; 110 | 111 | setState(() { 112 | currentPage = page; 113 | _rangeSet(); 114 | widget.onPageChanged(currentPage); 115 | }); 116 | } 117 | 118 | void _rangeSet() { 119 | rangeStart = currentPage % widget.threshold == 0 120 | ? currentPage - widget.threshold 121 | : (currentPage ~/ widget.threshold) * widget.threshold; 122 | 123 | rangeEnd = rangeStart + widget.threshold; 124 | } 125 | 126 | @override 127 | Widget build(BuildContext context) { 128 | return Padding( 129 | padding: const EdgeInsets.all(10.0), 130 | child: Row( 131 | mainAxisAlignment: MainAxisAlignment.center, 132 | children: [ 133 | InkWell( 134 | onTap: () => _changePage(0), 135 | child: Stack( 136 | children: [ 137 | if (widget.controlButton != null) ...[ 138 | widget.controlButton!, 139 | iconToFirst 140 | ] else 141 | _defaultControlButton(iconToFirst), 142 | ], 143 | ), 144 | ), 145 | const SizedBox( 146 | width: 4, 147 | ), 148 | InkWell( 149 | onTap: () => _changePage(--currentPage), 150 | child: Stack( 151 | children: [ 152 | if (widget.controlButton != null) ...[ 153 | widget.controlButton!, 154 | iconPrevious 155 | ] else 156 | _defaultControlButton(iconPrevious), 157 | ], 158 | ), 159 | ), 160 | const SizedBox( 161 | width: 10, 162 | ), 163 | ...List.generate( 164 | rangeEnd <= widget.pageTotal 165 | ? widget.threshold 166 | : widget.pageTotal % widget.threshold, 167 | (index) => Flexible( 168 | child: InkWell( 169 | splashColor: Colors.transparent, 170 | highlightColor: Colors.transparent, 171 | onTap: () => _changePage(index + 1 + rangeStart), 172 | child: Container( 173 | margin: const EdgeInsets.all(4), 174 | padding: 175 | const EdgeInsets.symmetric(vertical: 4, horizontal: 8), 176 | decoration: BoxDecoration( 177 | color: (currentPage - 1) % widget.threshold == index 178 | ? widget.colorPrimary 179 | : widget.colorSub, 180 | borderRadius: const BorderRadius.all(Radius.circular(4)), 181 | boxShadow: const [ 182 | BoxShadow( 183 | color: Colors.grey, 184 | offset: Offset(0.0, 1.0), //(x,y) 185 | blurRadius: 6.0, 186 | ), 187 | ], 188 | ), 189 | child: Text( 190 | '${index + 1 + rangeStart}', 191 | style: TextStyle( 192 | fontSize: widget.fontSize, 193 | fontFamily: widget.fontFamily, 194 | color: (currentPage - 1) % widget.threshold == index 195 | ? widget.colorSub 196 | : widget.colorPrimary, 197 | ), 198 | ), 199 | ), 200 | ), 201 | ), 202 | ), 203 | const SizedBox( 204 | width: 10, 205 | ), 206 | InkWell( 207 | onTap: () => _changePage(++currentPage), 208 | child: Stack( 209 | children: [ 210 | if (widget.controlButton != null) ...[ 211 | widget.controlButton!, 212 | iconNext 213 | ] else 214 | _defaultControlButton(iconNext), 215 | ], 216 | ), 217 | ), 218 | const SizedBox( 219 | width: 4, 220 | ), 221 | InkWell( 222 | onTap: () => _changePage(widget.pageTotal), 223 | child: Stack( 224 | children: [ 225 | if (widget.controlButton != null) ...[ 226 | widget.controlButton!, 227 | iconToLast 228 | ] else 229 | _defaultControlButton(iconToLast), 230 | ], 231 | ), 232 | ), 233 | ], 234 | ), 235 | ); 236 | } 237 | } 238 | -------------------------------------------------------------------------------- /windows/runner/win32_window.cpp: -------------------------------------------------------------------------------- 1 | #include "win32_window.h" 2 | 3 | #include 4 | 5 | #include "resource.h" 6 | 7 | namespace { 8 | 9 | constexpr const wchar_t kWindowClassName[] = L"FLUTTER_RUNNER_WIN32_WINDOW"; 10 | 11 | // The number of Win32Window objects that currently exist. 12 | static int g_active_window_count = 0; 13 | 14 | using EnableNonClientDpiScaling = BOOL __stdcall(HWND hwnd); 15 | 16 | // Scale helper to convert logical scaler values to physical using passed in 17 | // scale factor 18 | int Scale(int source, double scale_factor) { 19 | return static_cast(source * scale_factor); 20 | } 21 | 22 | // Dynamically loads the |EnableNonClientDpiScaling| from the User32 module. 23 | // This API is only needed for PerMonitor V1 awareness mode. 24 | void EnableFullDpiSupportIfAvailable(HWND hwnd) { 25 | HMODULE user32_module = LoadLibraryA("User32.dll"); 26 | if (!user32_module) { 27 | return; 28 | } 29 | auto enable_non_client_dpi_scaling = 30 | reinterpret_cast( 31 | GetProcAddress(user32_module, "EnableNonClientDpiScaling")); 32 | if (enable_non_client_dpi_scaling != nullptr) { 33 | enable_non_client_dpi_scaling(hwnd); 34 | FreeLibrary(user32_module); 35 | } 36 | } 37 | 38 | } // namespace 39 | 40 | // Manages the Win32Window's window class registration. 41 | class WindowClassRegistrar { 42 | public: 43 | ~WindowClassRegistrar() = default; 44 | 45 | // Returns the singleton registar instance. 46 | static WindowClassRegistrar* GetInstance() { 47 | if (!instance_) { 48 | instance_ = new WindowClassRegistrar(); 49 | } 50 | return instance_; 51 | } 52 | 53 | // Returns the name of the window class, registering the class if it hasn't 54 | // previously been registered. 55 | const wchar_t* GetWindowClass(); 56 | 57 | // Unregisters the window class. Should only be called if there are no 58 | // instances of the window. 59 | void UnregisterWindowClass(); 60 | 61 | private: 62 | WindowClassRegistrar() = default; 63 | 64 | static WindowClassRegistrar* instance_; 65 | 66 | bool class_registered_ = false; 67 | }; 68 | 69 | WindowClassRegistrar* WindowClassRegistrar::instance_ = nullptr; 70 | 71 | const wchar_t* WindowClassRegistrar::GetWindowClass() { 72 | if (!class_registered_) { 73 | WNDCLASS window_class{}; 74 | window_class.hCursor = LoadCursor(nullptr, IDC_ARROW); 75 | window_class.lpszClassName = kWindowClassName; 76 | window_class.style = CS_HREDRAW | CS_VREDRAW; 77 | window_class.cbClsExtra = 0; 78 | window_class.cbWndExtra = 0; 79 | window_class.hInstance = GetModuleHandle(nullptr); 80 | window_class.hIcon = 81 | LoadIcon(window_class.hInstance, MAKEINTRESOURCE(IDI_APP_ICON)); 82 | window_class.hbrBackground = 0; 83 | window_class.lpszMenuName = nullptr; 84 | window_class.lpfnWndProc = Win32Window::WndProc; 85 | RegisterClass(&window_class); 86 | class_registered_ = true; 87 | } 88 | return kWindowClassName; 89 | } 90 | 91 | void WindowClassRegistrar::UnregisterWindowClass() { 92 | UnregisterClass(kWindowClassName, nullptr); 93 | class_registered_ = false; 94 | } 95 | 96 | Win32Window::Win32Window() { 97 | ++g_active_window_count; 98 | } 99 | 100 | Win32Window::~Win32Window() { 101 | --g_active_window_count; 102 | Destroy(); 103 | } 104 | 105 | bool Win32Window::CreateAndShow(const std::wstring& title, 106 | const Point& origin, 107 | const Size& size) { 108 | Destroy(); 109 | 110 | const wchar_t* window_class = 111 | WindowClassRegistrar::GetInstance()->GetWindowClass(); 112 | 113 | const POINT target_point = {static_cast(origin.x), 114 | static_cast(origin.y)}; 115 | HMONITOR monitor = MonitorFromPoint(target_point, MONITOR_DEFAULTTONEAREST); 116 | UINT dpi = FlutterDesktopGetDpiForMonitor(monitor); 117 | double scale_factor = dpi / 96.0; 118 | 119 | HWND window = CreateWindow( 120 | window_class, title.c_str(), WS_OVERLAPPEDWINDOW | WS_VISIBLE, 121 | Scale(origin.x, scale_factor), Scale(origin.y, scale_factor), 122 | Scale(size.width, scale_factor), Scale(size.height, scale_factor), 123 | nullptr, nullptr, GetModuleHandle(nullptr), this); 124 | 125 | if (!window) { 126 | return false; 127 | } 128 | 129 | return OnCreate(); 130 | } 131 | 132 | // static 133 | LRESULT CALLBACK Win32Window::WndProc(HWND const window, 134 | UINT const message, 135 | WPARAM const wparam, 136 | LPARAM const lparam) noexcept { 137 | if (message == WM_NCCREATE) { 138 | auto window_struct = reinterpret_cast(lparam); 139 | SetWindowLongPtr(window, GWLP_USERDATA, 140 | reinterpret_cast(window_struct->lpCreateParams)); 141 | 142 | auto that = static_cast(window_struct->lpCreateParams); 143 | EnableFullDpiSupportIfAvailable(window); 144 | that->window_handle_ = window; 145 | } else if (Win32Window* that = GetThisFromHandle(window)) { 146 | return that->MessageHandler(window, message, wparam, lparam); 147 | } 148 | 149 | return DefWindowProc(window, message, wparam, lparam); 150 | } 151 | 152 | LRESULT 153 | Win32Window::MessageHandler(HWND hwnd, 154 | UINT const message, 155 | WPARAM const wparam, 156 | LPARAM const lparam) noexcept { 157 | switch (message) { 158 | case WM_DESTROY: 159 | window_handle_ = nullptr; 160 | Destroy(); 161 | if (quit_on_close_) { 162 | PostQuitMessage(0); 163 | } 164 | return 0; 165 | 166 | case WM_DPICHANGED: { 167 | auto newRectSize = reinterpret_cast(lparam); 168 | LONG newWidth = newRectSize->right - newRectSize->left; 169 | LONG newHeight = newRectSize->bottom - newRectSize->top; 170 | 171 | SetWindowPos(hwnd, nullptr, newRectSize->left, newRectSize->top, newWidth, 172 | newHeight, SWP_NOZORDER | SWP_NOACTIVATE); 173 | 174 | return 0; 175 | } 176 | case WM_SIZE: { 177 | RECT rect = GetClientArea(); 178 | if (child_content_ != nullptr) { 179 | // Size and position the child window. 180 | MoveWindow(child_content_, rect.left, rect.top, rect.right - rect.left, 181 | rect.bottom - rect.top, TRUE); 182 | } 183 | return 0; 184 | } 185 | 186 | case WM_ACTIVATE: 187 | if (child_content_ != nullptr) { 188 | SetFocus(child_content_); 189 | } 190 | return 0; 191 | } 192 | 193 | return DefWindowProc(window_handle_, message, wparam, lparam); 194 | } 195 | 196 | void Win32Window::Destroy() { 197 | OnDestroy(); 198 | 199 | if (window_handle_) { 200 | DestroyWindow(window_handle_); 201 | window_handle_ = nullptr; 202 | } 203 | if (g_active_window_count == 0) { 204 | WindowClassRegistrar::GetInstance()->UnregisterWindowClass(); 205 | } 206 | } 207 | 208 | Win32Window* Win32Window::GetThisFromHandle(HWND const window) noexcept { 209 | return reinterpret_cast( 210 | GetWindowLongPtr(window, GWLP_USERDATA)); 211 | } 212 | 213 | void Win32Window::SetChildContent(HWND content) { 214 | child_content_ = content; 215 | SetParent(content, window_handle_); 216 | RECT frame = GetClientArea(); 217 | 218 | MoveWindow(content, frame.left, frame.top, frame.right - frame.left, 219 | frame.bottom - frame.top, true); 220 | 221 | SetFocus(child_content_); 222 | } 223 | 224 | RECT Win32Window::GetClientArea() { 225 | RECT frame; 226 | GetClientRect(window_handle_, &frame); 227 | return frame; 228 | } 229 | 230 | HWND Win32Window::GetHandle() { 231 | return window_handle_; 232 | } 233 | 234 | void Win32Window::SetQuitOnClose(bool quit_on_close) { 235 | quit_on_close_ = quit_on_close; 236 | } 237 | 238 | bool Win32Window::OnCreate() { 239 | // No-op; provided for subclasses. 240 | return true; 241 | } 242 | 243 | void Win32Window::OnDestroy() { 244 | // No-op; provided for subclasses. 245 | } 246 | -------------------------------------------------------------------------------- /lib/services/format-time/format_date.dart: -------------------------------------------------------------------------------- 1 | import 'english_date_locale.dart'; 2 | 3 | /// Outputs year as four digits 4 | /// 5 | /// Example: 6 | /// formatDate(DateTime(1989), [yyyy]); 7 | /// // => 1989 8 | const String yyyy = 'yyyy'; 9 | 10 | /// Outputs year as two digits 11 | /// 12 | /// Example: 13 | /// formatDate(DateTime(1989), [yy]); 14 | /// // => 89 15 | const String yy = 'yy'; 16 | 17 | /// Outputs month as two digits 18 | /// 19 | /// Example: 20 | /// formatDate(DateTime(1989, 11), [mm]); 21 | /// // => 11 22 | /// formatDate(DateTime(1989, 5), [mm]); 23 | /// // => 05 24 | const String mm = 'mm'; 25 | 26 | /// Outputs month compactly 27 | /// 28 | /// Example: 29 | /// formatDate(DateTime(1989, 11), [mm]); 30 | /// // => 11 31 | /// formatDate(DateTime(1989, 5), [m]); 32 | /// // => 5 33 | const String m = 'm'; 34 | 35 | /// Outputs month as long name 36 | /// 37 | /// Example: 38 | /// formatDate(DateTime(1989, 2), [MM]); 39 | /// // => february 40 | const String MM = 'MM'; 41 | 42 | /// Outputs month as short name 43 | /// 44 | /// Example: 45 | /// formatDate(DateTime(1989, 2), [M]); 46 | /// // => feb 47 | const String M = 'M'; 48 | 49 | /// Outputs day as two digits 50 | /// 51 | /// Example: 52 | /// formatDate(DateTime(1989, 2, 21), [dd]); 53 | /// // => 21 54 | /// formatDate(DateTime(1989, 2, 5), [dd]); 55 | /// // => 05 56 | const String dd = 'dd'; 57 | 58 | /// Outputs day compactly 59 | /// 60 | /// Example: 61 | /// formatDate(DateTime(1989, 2, 21), [d]); 62 | /// // => 21 63 | /// formatDate(DateTime(1989, 2, 5), [d]); 64 | /// // => 5 65 | const String d = 'd'; 66 | 67 | /// Outputs week in month 68 | /// 69 | /// Example: 70 | /// formatDate(DateTime(1989, 2, 21), [w]); 71 | /// // => 4 72 | const String w = 'w'; 73 | 74 | /// Outputs week in year as two digits 75 | /// 76 | /// Example: 77 | /// formatDate(DateTime(1989, 12, 31), [W]); 78 | /// // => 53 79 | /// formatDate(DateTime(1989, 2, 21), [W]); 80 | /// // => 08 81 | const String WW = 'WW'; 82 | 83 | /// Outputs week in year compactly 84 | /// 85 | /// Example: 86 | /// formatDate(DateTime(1989, 2, 21), [W]); 87 | /// // => 8 88 | const String W = 'W'; 89 | 90 | /// Outputs week day as long name 91 | /// 92 | /// Example: 93 | /// formatDate(DateTime(2018, 1, 14), [DD]); 94 | /// // => sunday 95 | const String DD = 'DD'; 96 | 97 | /// Outputs week day as long name 98 | /// 99 | /// Example: 100 | /// formatDate(DateTime(2018, 1, 14), [D]); 101 | /// // => sun 102 | const String D = 'D'; 103 | 104 | /// Outputs hour (0 - 11) as two digits 105 | /// 106 | /// Example: 107 | /// formatDate(DateTime(1989, 02, 1, 15), [hh]); 108 | /// // => 03 109 | const String hh = 'hh'; 110 | 111 | /// Outputs hour (0 - 11) compactly 112 | /// 113 | /// Example: 114 | /// formatDate(DateTime(1989, 02, 1, 15), [h]); 115 | /// // => 3 116 | const String h = 'h'; 117 | 118 | /// Outputs hour (0 to 23) as two digits 119 | /// 120 | /// Example: 121 | /// formatDate(DateTime(1989, 02, 1, 15), [HH]); 122 | /// // => 15 123 | const String HH = 'HH'; 124 | 125 | /// Outputs hour (0 to 23) compactly 126 | /// 127 | /// Example: 128 | /// formatDate(DateTime(1989, 02, 1, 5), [H]); 129 | /// // => 5 130 | const String H = 'H'; 131 | 132 | /// Outputs minute as two digits 133 | /// 134 | /// Example: 135 | /// formatDate(DateTime(1989, 02, 1, 15, 40), [nn]); 136 | /// // => 40 137 | /// formatDate(DateTime(1989, 02, 1, 15, 4), [nn]); 138 | /// // => 04 139 | const String nn = 'nn'; 140 | 141 | /// Outputs minute compactly 142 | /// 143 | /// Example: 144 | /// formatDate(DateTime(1989, 02, 1, 15, 4), [n]); 145 | /// // => 4 146 | const String n = 'n'; 147 | 148 | /// Outputs second as two digits 149 | /// 150 | /// Example: 151 | /// formatDate(DateTime(1989, 02, 1, 15, 40, 10), [ss]); 152 | /// // => 10 153 | /// formatDate(DateTime(1989, 02, 1, 15, 40, 5), [ss]); 154 | /// // => 05 155 | const String ss = 'ss'; 156 | 157 | /// Outputs second compactly 158 | /// 159 | /// Example: 160 | /// formatDate(DateTime(1989, 02, 1, 15, 40, 5), [s]); 161 | /// // => 5 162 | const String s = 's'; 163 | 164 | /// Outputs millisecond as three digits 165 | /// 166 | /// Example: 167 | /// formatDate(DateTime(1989, 02, 1, 15, 40, 10, 999), [SSS]); 168 | /// // => 999 169 | /// formatDate(DateTime(1989, 02, 1, 15, 40, 10, 99), [SS]); 170 | /// // => 099 171 | /// formatDate(DateTime(1989, 02, 1, 15, 40, 10, 0), [SS]); 172 | /// // => 009 173 | const String SSS = 'SSS'; 174 | 175 | /// Outputs millisecond compactly 176 | /// 177 | /// Example: 178 | /// formatDate(DateTime(1989, 02, 1, 15, 40, 10, 999), [SSS]); 179 | /// // => 999 180 | /// formatDate(DateTime(1989, 02, 1, 15, 40, 10, 99), [SS]); 181 | /// // => 99 182 | /// formatDate(DateTime(1989, 02, 1, 15, 40, 10, 9), [SS]); 183 | /// // => 9 184 | const String S = 'S'; 185 | 186 | /// Outputs microsecond as three digits 187 | /// 188 | /// Example: 189 | /// formatDate(DateTime(1989, 02, 1, 15, 40, 10, 0, 999), [uuu]); 190 | /// // => 999 191 | /// formatDate(DateTime(1989, 02, 1, 15, 40, 10, 0, 99), [uuu]); 192 | /// // => 099 193 | /// formatDate(DateTime(1989, 02, 1, 15, 40, 10, 0, 9), [uuu]); 194 | /// // => 009 195 | const String uuu = 'uuu'; 196 | 197 | /// Outputs millisecond compactly 198 | /// 199 | /// Example: 200 | /// formatDate(DateTime(1989, 02, 1, 15, 40, 10, 0, 999), [u]); 201 | /// // => 999 202 | /// formatDate(DateTime(1989, 02, 1, 15, 40, 10, 0, 99), [u]); 203 | /// // => 99 204 | /// formatDate(DateTime(1989, 02, 1, 15, 40, 10, 0, 9), [u]); 205 | /// // => 9 206 | const String u = 'u'; 207 | 208 | /// Outputs if hour is AM or PM 209 | /// 210 | /// Example: 211 | /// print(formatDate(DateTime(1989, 02, 1, 5), [am])); 212 | /// // => AM 213 | /// print(formatDate(DateTime(1989, 02, 1, 15), [am])); 214 | /// // => PM 215 | const String am = 'am'; 216 | 217 | /// Outputs timezone as time offset 218 | /// 219 | /// Example: 220 | /// 221 | const String z = 'z'; 222 | const String Z = 'Z'; 223 | 224 | /// Escape delimiters to be used as normal string. 225 | /// 226 | /// Example: 227 | /// formatDate(DateTime(1989, 02, 1, 15, 40), [HH,'\\h',nn]); 228 | /// // => 15h40 229 | /// 230 | 231 | const String escape = '\\'; 232 | 233 | String formatDate( 234 | DateTime date, 235 | List formats, { 236 | DateLocale locale = const EnglishDateLocale(), 237 | }) { 238 | final sb = StringBuffer(); 239 | // english_date_locale 240 | for (String format in formats) { 241 | if (format.startsWith(escape)) { 242 | format = format.substring(1); 243 | sb.write(format); 244 | } else if (format == yyyy) { 245 | sb.write(_digits(date.year, 4)); 246 | } else if (format == yy) { 247 | sb.write(_digits(date.year % 100, 2)); 248 | } else if (format == mm) { 249 | sb.write(_digits(date.month, 2)); 250 | } else if (format == m) { 251 | sb.write(date.month); 252 | } else if (format == MM) { 253 | sb.write(locale.monthsLong[date.month - 1]); 254 | } else if (format == M) { 255 | sb.write(locale.monthsShort[date.month - 1]); 256 | } else if (format == dd) { 257 | sb.write(_digits(date.day, 2)); 258 | } else if (format == d) { 259 | sb.write(date.day); 260 | } else if (format == w) { 261 | sb.write((date.day + 7) ~/ 7); 262 | } else if (format == W) { 263 | sb.write((dayInYear(date) + 7) ~/ 7); 264 | } else if (format == WW) { 265 | sb.write(_digits((dayInYear(date) + 7) ~/ 7, 2)); 266 | } else if (format == DD) { 267 | sb.write(locale.daysLong[date.weekday - 1]); 268 | } else if (format == D) { 269 | sb.write(locale.daysShort[date.weekday - 1]); 270 | } else if (format == HH) { 271 | sb.write(_digits(date.hour, 2)); 272 | } else if (format == H) { 273 | sb.write(date.hour); 274 | } else if (format == hh) { 275 | int hour = date.hour % 12; 276 | if (hour == 0) hour = 12; 277 | sb.write(_digits(hour, 2)); 278 | } else if (format == h) { 279 | int hour = date.hour % 12; 280 | if (hour == 0) hour = 12; 281 | sb.write(hour); 282 | } else if (format == am) { 283 | sb.write(date.hour < 12 ? locale.am : locale.pm); 284 | } else if (format == nn) { 285 | sb.write(_digits(date.minute, 2)); 286 | } else if (format == n) { 287 | sb.write(date.minute); 288 | } else if (format == ss) { 289 | sb.write(_digits(date.second, 2)); 290 | } else if (format == s) { 291 | sb.write(date.second); 292 | } else if (format == SSS) { 293 | sb.write(_digits(date.millisecond, 3)); 294 | } else if (format == S) { 295 | sb.write(date.millisecond); 296 | } else if (format == uuu) { 297 | sb.write(_digits(date.microsecond, 3)); 298 | } else if (format == u) { 299 | sb.write(date.microsecond); 300 | } else if (format == z) { 301 | if (date.timeZoneOffset.inMinutes == 0) { 302 | sb.write('Z'); 303 | } else { 304 | if (date.timeZoneOffset.isNegative) { 305 | sb.write('-'); 306 | sb.write(_digits((-date.timeZoneOffset.inHours) % 24, 2)); 307 | sb.write(_digits((-date.timeZoneOffset.inMinutes) % 60, 2)); 308 | } else { 309 | sb.write('+'); 310 | sb.write(_digits(date.timeZoneOffset.inHours % 24, 2)); 311 | sb.write(_digits(date.timeZoneOffset.inMinutes % 60, 2)); 312 | } 313 | } 314 | } else if (format == Z) { 315 | sb.write(date.timeZoneName); 316 | } else { 317 | sb.write(format); 318 | } 319 | } 320 | 321 | return sb.toString(); 322 | } 323 | 324 | String _digits(int value, int length) { 325 | String ret = '$value'; 326 | if (ret.length < length) { 327 | ret = '0' * (length - ret.length) + ret; 328 | } 329 | return ret; 330 | } 331 | 332 | int dayInYear(DateTime date) => 333 | date.difference(DateTime(date.year, 1, 1)).inDays; 334 | -------------------------------------------------------------------------------- /lib/widgets/update_dialog.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | import '../services/flutter_clipboard_hive_ui.dart'; 4 | import 'update_dialog_type_picker.dart'; 5 | 6 | class UpdateDialog extends StatefulWidget { 7 | final Map objectAsJson; 8 | final String fieldName; 9 | final String? dateFormat; 10 | 11 | const UpdateDialog({ 12 | Key? key, 13 | required this.objectAsJson, 14 | required this.fieldName, 15 | this.dateFormat, 16 | }) : super(key: key); 17 | 18 | @override 19 | State createState() => _UpdateDialogState(); 20 | } 21 | 22 | class _UpdateDialogState extends State { 23 | Map get jsonObject => widget.objectAsJson; 24 | UpdateDialogType fieldType = UpdateDialogType.string; 25 | late TextEditingController _controller; 26 | late bool booleanFieldValue; 27 | 28 | @override 29 | void initState() { 30 | _controller = TextEditingController(); 31 | super.initState(); 32 | } 33 | 34 | @override 35 | void dispose() { 36 | _controller.dispose(); 37 | super.dispose(); 38 | } 39 | 40 | void onTypeChanged(UpdateDialogType? type) { 41 | if (type == UpdateDialogType.bool) { 42 | booleanFieldValue = false; 43 | } 44 | setState(() => fieldType = type!); 45 | } 46 | 47 | Future onFormFieldTapped() async { 48 | if (fieldType == UpdateDialogType.datePicker) { 49 | final currentDate = jsonObject[widget.fieldName]; 50 | late DateTime initialDate; 51 | 52 | if (currentDate != null && currentDate.isNotEmpty) { 53 | initialDate = DateTime.parse(currentDate.replaceAll("/", "-")); 54 | } else { 55 | initialDate = DateTime.now(); 56 | } 57 | final datePicked = await showDatePicker( 58 | context: context, 59 | initialDate: initialDate, 60 | firstDate: DateTime.now(), 61 | lastDate: DateTime.now().add( 62 | const Duration(days: 30 * 4), 63 | ), 64 | ); 65 | if (datePicked != null) { 66 | // _controller.text = 67 | // widget.dateFormat?.format(datePicked) ?? datePicked.toString(); 68 | _controller.text = datePicked.toString(); 69 | } 70 | } 71 | } 72 | 73 | @override 74 | Widget build(BuildContext context) { 75 | final mediaQuerySize = MediaQuery.of(context).size; 76 | return Dialog( 77 | shape: const RoundedRectangleBorder( 78 | borderRadius: BorderRadius.all( 79 | Radius.circular(20), 80 | ), 81 | ), 82 | child: Container( 83 | constraints: BoxConstraints.loose( 84 | Size( 85 | mediaQuerySize.width * 0.5, 86 | mediaQuerySize.height * 0.6, 87 | ), 88 | ), 89 | child: Column( 90 | mainAxisSize: MainAxisSize.min, 91 | children: [ 92 | Column( 93 | children: [ 94 | ListTile( 95 | title: Text( 96 | widget.fieldName, 97 | style: const TextStyle( 98 | fontWeight: FontWeight.bold, 99 | fontSize: 18, 100 | ), 101 | ), 102 | trailing: IconButton( 103 | icon: const Icon(Icons.close), 104 | onPressed: () => Navigator.pop(context), 105 | ), 106 | ), 107 | const Divider(), 108 | ], 109 | ), 110 | const SizedBox(height: 24), 111 | UpdateDialogTypePicker( 112 | selectedType: fieldType, 113 | onTypeChanged: onTypeChanged, 114 | ), 115 | const SizedBox(height: 24), 116 | Flexible( 117 | child: Padding( 118 | padding: const EdgeInsets.symmetric(horizontal: 32.0), 119 | child: Row( 120 | children: [ 121 | Flexible( 122 | child: TextFormField( 123 | readOnly: true, 124 | enabled: false, 125 | textAlign: TextAlign.center, 126 | initialValue: jsonObject[widget.fieldName].toString(), 127 | decoration: InputDecoration( 128 | label: const Text('Old Value'), 129 | border: OutlineInputBorder( 130 | borderRadius: BorderRadius.circular(5), 131 | ), 132 | ), 133 | ), 134 | ), 135 | const SizedBox(width: 32), 136 | if (fieldType != UpdateDialogType.bool) 137 | Flexible( 138 | child: TextField( 139 | readOnly: fieldType == UpdateDialogType.datePicker, 140 | onTap: () async => await onFormFieldTapped(), 141 | controller: _controller, 142 | textAlign: TextAlign.center, 143 | decoration: InputDecoration( 144 | label: const Text('New Value'), 145 | hintText: 'New Value', 146 | border: OutlineInputBorder( 147 | borderRadius: BorderRadius.circular(5), 148 | ), 149 | ), 150 | ), 151 | ) 152 | else 153 | Flexible( 154 | child: DropdownButtonFormField( 155 | items: [true, false] 156 | .map((e) => DropdownMenuItem( 157 | value: e, 158 | child: Text(e.toString()), 159 | )) 160 | .toList(), 161 | onChanged: (value) => setState( 162 | () => booleanFieldValue = value!, 163 | ), 164 | decoration: const InputDecoration( 165 | contentPadding: EdgeInsets.symmetric( 166 | horizontal: 16, 167 | )), 168 | ), 169 | ) 170 | ], 171 | ), 172 | ), 173 | ), 174 | Flexible( 175 | child: Padding( 176 | padding: const EdgeInsets.symmetric(horizontal: 32.0), 177 | child: Align( 178 | alignment: Alignment.bottomRight, 179 | child: Row( 180 | mainAxisAlignment: MainAxisAlignment.end, 181 | mainAxisSize: MainAxisSize.min, 182 | children: [ 183 | ElevatedButton( 184 | style: ElevatedButton.styleFrom( 185 | fixedSize: const Size(125, 42), 186 | elevation: 0, 187 | backgroundColor: Colors.white, 188 | shape: RoundedRectangleBorder( 189 | borderRadius: const BorderRadius.all( 190 | Radius.circular(12), 191 | ), 192 | side: BorderSide( 193 | color: Theme.of(context).primaryColor, 194 | ), 195 | ), 196 | ), 197 | onPressed: () { 198 | FlutterClipboardHiveUi.copy( 199 | jsonObject[widget.fieldName].toString()); 200 | }, 201 | child: Text( 202 | 'Copy Value', 203 | style: TextStyle( 204 | color: Theme.of(context).primaryColor, 205 | ), 206 | ), 207 | ), 208 | const SizedBox(width: 24), 209 | ElevatedButton( 210 | style: ElevatedButton.styleFrom( 211 | fixedSize: const Size(125, 42), 212 | elevation: 0, 213 | shape: const RoundedRectangleBorder( 214 | borderRadius: BorderRadius.all( 215 | Radius.circular(12), 216 | ), 217 | ), 218 | ), 219 | onPressed: () { 220 | Object updatedValue; 221 | switch (fieldType) { 222 | case UpdateDialogType.datePicker: 223 | updatedValue = _controller.text; 224 | break; 225 | case UpdateDialogType.string: 226 | updatedValue = _controller.text; 227 | break; 228 | case UpdateDialogType.num: 229 | updatedValue = num.parse(_controller.text); 230 | break; 231 | case UpdateDialogType.bool: 232 | updatedValue = booleanFieldValue; 233 | break; 234 | } 235 | jsonObject[widget.fieldName] = updatedValue; 236 | Navigator.pop(context, jsonObject); 237 | }, 238 | child: const Text('Confirm'), 239 | ), 240 | ], 241 | ), 242 | ), 243 | ), 244 | ), 245 | const SizedBox(height: 24), 246 | ], 247 | ), 248 | ), 249 | ); 250 | } 251 | } 252 | 253 | enum UpdateDialogType { 254 | datePicker, 255 | string, 256 | num, 257 | bool, 258 | } 259 | -------------------------------------------------------------------------------- /lib/widgets/add_dialog.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | import '../services/idgenerator.dart'; 4 | import 'update_dialog.dart'; 5 | import 'update_dialog_type_picker.dart'; 6 | 7 | class AddNewDialog extends StatefulWidget { 8 | final Map objectAsJson; 9 | 10 | final List allColumns; 11 | 12 | const AddNewDialog({ 13 | Key? key, 14 | required this.objectAsJson, 15 | required this.allColumns, 16 | }) : super(key: key); 17 | 18 | @override 19 | State createState() => _AddNewDialogState(); 20 | } 21 | 22 | class _AddNewDialogState extends State { 23 | UpdateDialogType fieldType = UpdateDialogType.string; 24 | final textControllers = {}; 25 | late bool booleanFieldValue; 26 | 27 | @override 28 | void initState() { 29 | super.initState(); 30 | } 31 | 32 | void initTextControllers() { 33 | var id = IdGenerator.generate(); 34 | for (int index = 0; index < widget.allColumns.length; index++) { 35 | if (widget.allColumns[index] == 'id') { 36 | textControllers[widget.allColumns[index]] = 37 | TextEditingController(text: id); 38 | widget.objectAsJson[widget.allColumns[index]] = id; 39 | } else { 40 | textControllers[widget.allColumns[index]] = TextEditingController(); 41 | } 42 | } 43 | } 44 | 45 | @override 46 | void dispose() { 47 | //try{_controller.dispose();}catch(e){} 48 | super.dispose(); 49 | } 50 | 51 | void onTypeChanged(UpdateDialogType? type) { 52 | if (type == UpdateDialogType.bool) { 53 | booleanFieldValue = false; 54 | } 55 | setState(() => fieldType = type!); 56 | } 57 | 58 | @override 59 | Widget build(BuildContext context) { 60 | initTextControllers(); 61 | final mediaQuerySize = MediaQuery.of(context).size; 62 | return Dialog( 63 | shape: const RoundedRectangleBorder( 64 | borderRadius: BorderRadius.all( 65 | Radius.circular(20), 66 | ), 67 | ), 68 | child: Container( 69 | constraints: BoxConstraints.loose(Size( 70 | mediaQuerySize.width * 0.5, 71 | mediaQuerySize.height * 0.6, 72 | )), 73 | child: Column( 74 | crossAxisAlignment: CrossAxisAlignment.center, 75 | children: [ 76 | const SizedBox(height: 16), 77 | const Align( 78 | alignment: Alignment.center, 79 | child: Text( 80 | 'Add New Row', 81 | style: TextStyle( 82 | fontSize: 18, 83 | fontWeight: FontWeight.bold, 84 | ), 85 | ), 86 | ), 87 | const Divider(), 88 | const SizedBox(height: 16), 89 | Expanded( 90 | child: SingleChildScrollView( 91 | child: Column( 92 | children: widget.allColumns.map( 93 | (column) { 94 | return Column( 95 | crossAxisAlignment: CrossAxisAlignment.start, 96 | children: [ 97 | SizedBox( 98 | height: 50, 99 | child: UpdateDialogTypePicker( 100 | selectedType: fieldType, 101 | onTypeChanged: onTypeChanged, 102 | ), 103 | ), 104 | const SizedBox(height: 8), 105 | Container( 106 | constraints: BoxConstraints.loose( 107 | Size(mediaQuerySize.width * 0.2, 50), 108 | ), 109 | padding: const EdgeInsets.symmetric( 110 | horizontal: 24, 111 | ), 112 | child: (fieldType != UpdateDialogType.bool) 113 | ? TextField( 114 | readOnly: fieldType == 115 | UpdateDialogType.datePicker, 116 | // onTap: () async => await onFormFieldTapped(), 117 | onChanged: (value) => 118 | widget.objectAsJson[column] = 119 | textControllers[column]?.text, 120 | 121 | onEditingComplete: () { 122 | switch (fieldType) { 123 | case UpdateDialogType.datePicker: 124 | widget.objectAsJson[column] = 125 | textControllers[column]?.text; 126 | break; 127 | case UpdateDialogType.string: 128 | widget.objectAsJson[column] = 129 | textControllers[column]?.text; 130 | break; 131 | case UpdateDialogType.num: 132 | widget.objectAsJson[column] = 133 | num.parse( 134 | textControllers[column]! 135 | .text); 136 | break; 137 | case UpdateDialogType.bool: 138 | widget.objectAsJson[column] = 139 | booleanFieldValue; 140 | break; 141 | } 142 | }, 143 | controller: textControllers[column], 144 | textAlign: TextAlign.center, 145 | decoration: InputDecoration( 146 | label: Text( 147 | column, 148 | style: const TextStyle( 149 | fontSize: 16, 150 | fontWeight: FontWeight.bold, 151 | ), 152 | ), 153 | hintText: 'New Value', 154 | border: OutlineInputBorder( 155 | borderRadius: 156 | BorderRadius.circular(5), 157 | ), 158 | ), 159 | ) 160 | : DropdownButtonFormField( 161 | items: [true, false] 162 | .map((e) => DropdownMenuItem( 163 | value: e, 164 | child: Text(e.toString()), 165 | )) 166 | .toList(), 167 | onChanged: (value) => setState( 168 | () => booleanFieldValue = value!, 169 | ), 170 | decoration: const InputDecoration( 171 | contentPadding: EdgeInsets.symmetric( 172 | horizontal: 16, 173 | )), 174 | )), 175 | const SizedBox(height: 42), 176 | ], 177 | ); 178 | }, 179 | ).toList(), 180 | ), 181 | ), 182 | ), 183 | const SizedBox(height: 24), 184 | Padding( 185 | padding: const EdgeInsets.symmetric(horizontal: 12.0), 186 | child: Row( 187 | mainAxisAlignment: MainAxisAlignment.end, 188 | children: [ 189 | ElevatedButton( 190 | onPressed: () {}, 191 | style: ElevatedButton.styleFrom( 192 | backgroundColor: Colors.red, 193 | elevation: 0, 194 | shape: const RoundedRectangleBorder( 195 | borderRadius: BorderRadius.all( 196 | Radius.circular(12), 197 | ), 198 | ), 199 | fixedSize: const Size( 200 | 100, 201 | 42, 202 | ), 203 | ), 204 | child: const Text( 205 | 'Reset', 206 | style: TextStyle(color: Colors.white), 207 | ), 208 | ), 209 | const SizedBox( 210 | width: 24, 211 | ), 212 | ElevatedButton( 213 | onPressed: () { 214 | Navigator.pop(context, widget.objectAsJson); 215 | }, 216 | style: ElevatedButton.styleFrom( 217 | elevation: 0, 218 | backgroundColor: Colors.green, 219 | shape: const RoundedRectangleBorder( 220 | borderRadius: BorderRadius.all( 221 | Radius.circular(12), 222 | ), 223 | ), 224 | fixedSize: const Size( 225 | 100, 226 | 42, 227 | ), 228 | ), 229 | child: const Text( 230 | 'Confirm', 231 | style: TextStyle( 232 | color: Colors.white, 233 | ), 234 | ), 235 | ), 236 | ], 237 | ), 238 | ), 239 | const SizedBox(height: 32), 240 | ], 241 | ), 242 | ), 243 | ); 244 | } 245 | } 246 | --------------------------------------------------------------------------------