From 494680bd939ff98fa950bf11554bbf46a919ba56 Mon Sep 17 00:00:00 2001 From: DominicGBauer Date: Tue, 24 Dec 2024 16:46:55 +0200 Subject: [PATCH 01/10] feat: add trello demo --- demos/supabase-trello/.env.template | 4 + demos/supabase-trello/.gitignore | 47 + demos/supabase-trello/.metadata | 45 + demos/supabase-trello/LICENSE | 121 +++ demos/supabase-trello/README.md | 342 ++++++ demos/supabase-trello/analysis_options.yaml | 29 + demos/supabase-trello/android/.gitignore | 13 + .../supabase-trello/android/app/build.gradle | 65 ++ .../android/app/src/debug/AndroidManifest.xml | 7 + .../android/app/src/main/AndroidManifest.xml | 33 + .../trelloappclone_flutter/MainActivity.kt | 6 + .../res/drawable-v21/launch_background.xml | 12 + .../main/res/drawable/launch_background.xml | 12 + .../src/main/res/mipmap-hdpi/ic_launcher.png | Bin 0 -> 544 bytes .../src/main/res/mipmap-mdpi/ic_launcher.png | Bin 0 -> 442 bytes .../src/main/res/mipmap-xhdpi/ic_launcher.png | Bin 0 -> 721 bytes .../main/res/mipmap-xxhdpi/ic_launcher.png | Bin 0 -> 1031 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.png | Bin 0 -> 1443 bytes .../app/src/main/res/values-night/styles.xml | 18 + .../app/src/main/res/values/styles.xml | 18 + .../app/src/profile/AndroidManifest.xml | 7 + demos/supabase-trello/android/build.gradle | 18 + .../supabase-trello/android/gradle.properties | 3 + .../gradle/wrapper/gradle-wrapper.properties | 5 + demos/supabase-trello/android/settings.gradle | 25 + demos/supabase-trello/assets/landing.jpg | Bin 0 -> 182187 bytes demos/supabase-trello/assets/trello-logo.png | Bin 0 -> 3174 bytes demos/supabase-trello/devtools_options.yaml | 3 + demos/supabase-trello/ios/.gitignore | 34 + .../ios/Flutter/AppFrameworkInfo.plist | 26 + .../ios/Flutter/Debug.xcconfig | 2 + .../ios/Flutter/Release.xcconfig | 2 + demos/supabase-trello/ios/Podfile | 47 + demos/supabase-trello/ios/Podfile.lock | 136 +++ .../ios/Runner.xcodeproj/project.pbxproj | 723 +++++++++++++ .../contents.xcworkspacedata | 7 + .../xcshareddata/IDEWorkspaceChecks.plist | 8 + .../xcshareddata/WorkspaceSettings.xcsettings | 8 + .../xcshareddata/xcschemes/Runner.xcscheme | 98 ++ .../contents.xcworkspacedata | 10 + .../xcshareddata/IDEWorkspaceChecks.plist | 8 + .../xcshareddata/WorkspaceSettings.xcsettings | 8 + .../ios/Runner/AppDelegate.swift | 13 + .../AppIcon.appiconset/Contents.json | 122 +++ .../Icon-App-1024x1024@1x.png | Bin 0 -> 10932 bytes .../AppIcon.appiconset/Icon-App-20x20@1x.png | Bin 0 -> 295 bytes .../AppIcon.appiconset/Icon-App-20x20@2x.png | Bin 0 -> 406 bytes .../AppIcon.appiconset/Icon-App-20x20@3x.png | Bin 0 -> 450 bytes .../AppIcon.appiconset/Icon-App-29x29@1x.png | Bin 0 -> 282 bytes .../AppIcon.appiconset/Icon-App-29x29@2x.png | Bin 0 -> 462 bytes .../AppIcon.appiconset/Icon-App-29x29@3x.png | Bin 0 -> 704 bytes .../AppIcon.appiconset/Icon-App-40x40@1x.png | Bin 0 -> 406 bytes .../AppIcon.appiconset/Icon-App-40x40@2x.png | Bin 0 -> 586 bytes .../AppIcon.appiconset/Icon-App-40x40@3x.png | Bin 0 -> 862 bytes .../AppIcon.appiconset/Icon-App-60x60@2x.png | Bin 0 -> 862 bytes .../AppIcon.appiconset/Icon-App-60x60@3x.png | Bin 0 -> 1674 bytes .../AppIcon.appiconset/Icon-App-76x76@1x.png | Bin 0 -> 762 bytes .../AppIcon.appiconset/Icon-App-76x76@2x.png | Bin 0 -> 1226 bytes .../Icon-App-83.5x83.5@2x.png | Bin 0 -> 1418 bytes .../LaunchImage.imageset/Contents.json | 23 + .../LaunchImage.imageset/LaunchImage.png | Bin 0 -> 68 bytes .../LaunchImage.imageset/LaunchImage@2x.png | Bin 0 -> 68 bytes .../LaunchImage.imageset/LaunchImage@3x.png | Bin 0 -> 68 bytes .../LaunchImage.imageset/README.md | 5 + .../Runner/Base.lproj/LaunchScreen.storyboard | 37 + .../ios/Runner/Base.lproj/Main.storyboard | 26 + demos/supabase-trello/ios/Runner/Info.plist | 51 + .../ios/Runner/Runner-Bridging-Header.h | 1 + .../ios/RunnerTests/RunnerTests.swift | 12 + .../aboutboard/presentation/index.dart | 43 + .../features/activity/presentation/index.dart | 67 ++ .../archivedcards/presentation/index.dart | 49 + .../archivedlists/presentation/index.dart | 48 + .../board/domain/board_arguments.dart | 9 + .../board/presentation/boarditemobject.dart | 13 + .../board/presentation/boardlistobject.dart | 13 + .../features/board/presentation/index.dart | 471 +++++++++ .../boardbackground/presentation/index.dart | 59 ++ .../boardmenu/presentation/index.dart | 202 ++++ .../boardsettings/presentation/index.dart | 206 ++++ .../domain/card_detail_arguments.dart | 11 + .../carddetails/presentation/index.dart | 376 +++++++ .../closeboard/presentation/index.dart | 39 + .../copyboard/presentation/index.dart | 115 ++ .../createboard/presentation/index.dart | 145 +++ .../createcard/presentation/index.dart | 137 +++ .../createworkspace/presentation/index.dart | 107 ++ .../features/drawer/presentation/index.dart | 135 +++ .../editlabels/presentation/index.dart | 140 +++ .../emailtoboard/presentation/index.dart | 135 +++ .../lib/features/emptywidget/index.dart | 385 +++++++ .../generateworkspace/presentation/index.dart | 103 ++ .../presentation/custom_floating_action.dart | 42 + .../home/presentation/custom_search.dart | 81 ++ .../lib/features/home/presentation/index.dart | 187 ++++ .../invitemember/presentation/index.dart | 144 +++ .../landing/presentation/bottomsheet.dart | 84 ++ .../features/landing/presentation/index.dart | 91 ++ .../features/members/presentation/index.dart | 131 +++ .../features/mycards/presentation/index.dart | 60 ++ .../notifications/presentation/index.dart | 127 +++ .../offlineboards/presentation/index.dart | 93 ++ .../features/powerups/presentation/index.dart | 38 + .../features/settings/presentation/index.dart | 124 +++ .../signtotrello/domain/sign_arguments.dart | 5 + .../signtotrello/presentation/index.dart | 191 ++++ .../viewmembers/presentation/index.dart | 43 + .../visibility/presentation/index.dart | 59 ++ .../workspace/domain/workspace_arguments.dart | 7 + .../workspace/presentation/index.dart | 161 +++ .../workspacemenu/presentation/index.dart | 140 +++ .../workspacesettings/presentation/index.dart | 65 ++ demos/supabase-trello/lib/main.dart | 117 +++ .../supabase-trello/lib/models/activity.dart | 39 + .../lib/models/attachment.dart | 28 + demos/supabase-trello/lib/models/board.dart | 86 ++ .../lib/models/board_label.dart | 34 + demos/supabase-trello/lib/models/card.dart | 68 ++ .../lib/models/card_label.dart | 34 + .../supabase-trello/lib/models/checklist.dart | 30 + demos/supabase-trello/lib/models/comment.dart | 30 + .../supabase-trello/lib/models/listboard.dart | 44 + demos/supabase-trello/lib/models/member.dart | 30 + demos/supabase-trello/lib/models/models.dart | 12 + demos/supabase-trello/lib/models/schema.dart | 149 +++ demos/supabase-trello/lib/models/user.dart | 26 + .../supabase-trello/lib/models/workspace.dart | 36 + .../lib/protocol/data_client.dart | 854 +++++++++++++++ .../lib/protocol/powersync.dart | 269 +++++ demos/supabase-trello/lib/utils/color.dart | 6 + demos/supabase-trello/lib/utils/config.dart | 44 + demos/supabase-trello/lib/utils/constant.dart | 40 + .../lib/utils/data_generator.dart | 123 +++ demos/supabase-trello/lib/utils/service.dart | 465 ++++++++ .../lib/utils/trello_provider.dart | 74 ++ demos/supabase-trello/lib/utils/widgets.dart | 75 ++ .../lib/widgets/thirdparty/README.md | 5 + .../lib/widgets/thirdparty/board_item.dart | 150 +++ .../lib/widgets/thirdparty/board_list.dart | 188 ++++ .../lib/widgets/thirdparty/boardview.dart | 683 ++++++++++++ .../thirdparty/boardview_controller.dart | 18 + .../lib/widgets/thirdparty/vs_scrollbar.dart | 348 ++++++ demos/supabase-trello/linux/.gitignore | 1 + demos/supabase-trello/linux/CMakeLists.txt | 139 +++ .../linux/flutter/CMakeLists.txt | 88 ++ .../flutter/generated_plugin_registrant.cc | 31 + .../flutter/generated_plugin_registrant.h | 15 + .../linux/flutter/generated_plugins.cmake | 28 + demos/supabase-trello/linux/main.cc | 6 + demos/supabase-trello/linux/my_application.cc | 104 ++ demos/supabase-trello/linux/my_application.h | 18 + demos/supabase-trello/macos/.gitignore | 7 + .../macos/Flutter/Flutter-Debug.xcconfig | 2 + .../macos/Flutter/Flutter-Release.xcconfig | 2 + .../Flutter/GeneratedPluginRegistrant.swift | 24 + demos/supabase-trello/macos/Podfile | 43 + demos/supabase-trello/macos/Podfile.lock | 78 ++ .../macos/Runner.xcodeproj/project.pbxproj | 791 ++++++++++++++ .../xcshareddata/IDEWorkspaceChecks.plist | 8 + .../xcshareddata/xcschemes/Runner.xcscheme | 98 ++ .../contents.xcworkspacedata | 10 + .../xcshareddata/IDEWorkspaceChecks.plist | 8 + .../macos/Runner/AppDelegate.swift | 9 + .../AppIcon.appiconset/Contents.json | 68 ++ .../AppIcon.appiconset/app_icon_1024.png | Bin 0 -> 102994 bytes .../AppIcon.appiconset/app_icon_128.png | Bin 0 -> 5680 bytes .../AppIcon.appiconset/app_icon_16.png | Bin 0 -> 520 bytes .../AppIcon.appiconset/app_icon_256.png | Bin 0 -> 14142 bytes .../AppIcon.appiconset/app_icon_32.png | Bin 0 -> 1066 bytes .../AppIcon.appiconset/app_icon_512.png | Bin 0 -> 36406 bytes .../AppIcon.appiconset/app_icon_64.png | Bin 0 -> 2218 bytes .../macos/Runner/Base.lproj/MainMenu.xib | 343 ++++++ .../macos/Runner/Configs/AppInfo.xcconfig | 14 + .../macos/Runner/Configs/Debug.xcconfig | 2 + .../macos/Runner/Configs/Release.xcconfig | 2 + .../macos/Runner/Configs/Warnings.xcconfig | 13 + .../macos/Runner/DebugProfile.entitlements | 14 + demos/supabase-trello/macos/Runner/Info.plist | 32 + .../macos/Runner/MainFlutterWindow.swift | 15 + .../macos/Runner/Release.entitlements | 10 + .../macos/RunnerTests/RunnerTests.swift | 12 + demos/supabase-trello/pubspec.lock | 991 ++++++++++++++++++ demos/supabase-trello/pubspec.yaml | 67 ++ demos/supabase-trello/sample_workspace.png | Bin 0 -> 133244 bytes demos/supabase-trello/showcase.png | Bin 0 -> 181022 bytes demos/supabase-trello/sync-rules-0.yaml | 19 + demos/supabase-trello/sync-rules-1.yaml | 27 + demos/supabase-trello/tables.sql | 332 ++++++ demos/supabase-trello/test/widget_test.dart | 15 + demos/supabase-trello/web/favicon.png | Bin 0 -> 917 bytes demos/supabase-trello/web/icons/Icon-192.png | Bin 0 -> 5292 bytes demos/supabase-trello/web/icons/Icon-512.png | Bin 0 -> 8252 bytes .../web/icons/Icon-maskable-192.png | Bin 0 -> 5594 bytes .../web/icons/Icon-maskable-512.png | Bin 0 -> 20998 bytes demos/supabase-trello/web/index.html | 59 ++ demos/supabase-trello/web/manifest.json | 35 + demos/supabase-trello/windows/.gitignore | 17 + demos/supabase-trello/windows/CMakeLists.txt | 102 ++ .../windows/flutter/CMakeLists.txt | 104 ++ .../flutter/generated_plugin_registrant.cc | 26 + .../flutter/generated_plugin_registrant.h | 15 + .../windows/flutter/generated_plugins.cmake | 28 + .../windows/runner/CMakeLists.txt | 40 + .../supabase-trello/windows/runner/Runner.rc | 121 +++ .../windows/runner/flutter_window.cpp | 66 ++ .../windows/runner/flutter_window.h | 33 + demos/supabase-trello/windows/runner/main.cpp | 43 + .../supabase-trello/windows/runner/resource.h | 16 + .../windows/runner/resources/app_icon.ico | Bin 0 -> 33772 bytes .../windows/runner/runner.exe.manifest | 20 + .../supabase-trello/windows/runner/utils.cpp | 65 ++ demos/supabase-trello/windows/runner/utils.h | 19 + .../windows/runner/win32_window.cpp | 288 +++++ .../windows/runner/win32_window.h | 102 ++ 214 files changed, 15911 insertions(+) create mode 100644 demos/supabase-trello/.env.template create mode 100644 demos/supabase-trello/.gitignore create mode 100644 demos/supabase-trello/.metadata create mode 100644 demos/supabase-trello/LICENSE create mode 100644 demos/supabase-trello/README.md create mode 100644 demos/supabase-trello/analysis_options.yaml create mode 100644 demos/supabase-trello/android/.gitignore create mode 100644 demos/supabase-trello/android/app/build.gradle create mode 100644 demos/supabase-trello/android/app/src/debug/AndroidManifest.xml create mode 100644 demos/supabase-trello/android/app/src/main/AndroidManifest.xml create mode 100644 demos/supabase-trello/android/app/src/main/kotlin/com/example/trelloappclone_flutter/MainActivity.kt create mode 100644 demos/supabase-trello/android/app/src/main/res/drawable-v21/launch_background.xml create mode 100644 demos/supabase-trello/android/app/src/main/res/drawable/launch_background.xml create mode 100644 demos/supabase-trello/android/app/src/main/res/mipmap-hdpi/ic_launcher.png create mode 100644 demos/supabase-trello/android/app/src/main/res/mipmap-mdpi/ic_launcher.png create mode 100644 demos/supabase-trello/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png create mode 100644 demos/supabase-trello/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png create mode 100644 demos/supabase-trello/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png create mode 100644 demos/supabase-trello/android/app/src/main/res/values-night/styles.xml create mode 100644 demos/supabase-trello/android/app/src/main/res/values/styles.xml create mode 100644 demos/supabase-trello/android/app/src/profile/AndroidManifest.xml create mode 100644 demos/supabase-trello/android/build.gradle create mode 100644 demos/supabase-trello/android/gradle.properties create mode 100644 demos/supabase-trello/android/gradle/wrapper/gradle-wrapper.properties create mode 100644 demos/supabase-trello/android/settings.gradle create mode 100644 demos/supabase-trello/assets/landing.jpg create mode 100644 demos/supabase-trello/assets/trello-logo.png create mode 100644 demos/supabase-trello/devtools_options.yaml create mode 100644 demos/supabase-trello/ios/.gitignore create mode 100644 demos/supabase-trello/ios/Flutter/AppFrameworkInfo.plist create mode 100644 demos/supabase-trello/ios/Flutter/Debug.xcconfig create mode 100644 demos/supabase-trello/ios/Flutter/Release.xcconfig create mode 100644 demos/supabase-trello/ios/Podfile create mode 100644 demos/supabase-trello/ios/Podfile.lock create mode 100644 demos/supabase-trello/ios/Runner.xcodeproj/project.pbxproj create mode 100644 demos/supabase-trello/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata create mode 100644 demos/supabase-trello/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 demos/supabase-trello/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings create mode 100644 demos/supabase-trello/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme create mode 100644 demos/supabase-trello/ios/Runner.xcworkspace/contents.xcworkspacedata create mode 100644 demos/supabase-trello/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 demos/supabase-trello/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings create mode 100644 demos/supabase-trello/ios/Runner/AppDelegate.swift create mode 100644 demos/supabase-trello/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json create mode 100644 demos/supabase-trello/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png create mode 100644 demos/supabase-trello/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png create mode 100644 demos/supabase-trello/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png create mode 100644 demos/supabase-trello/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png create mode 100644 demos/supabase-trello/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png create mode 100644 demos/supabase-trello/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png create mode 100644 demos/supabase-trello/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png create mode 100644 demos/supabase-trello/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png create mode 100644 demos/supabase-trello/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png create mode 100644 demos/supabase-trello/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png create mode 100644 demos/supabase-trello/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png create mode 100644 demos/supabase-trello/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png create mode 100644 demos/supabase-trello/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png create mode 100644 demos/supabase-trello/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png create mode 100644 demos/supabase-trello/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png create mode 100644 demos/supabase-trello/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json create mode 100644 demos/supabase-trello/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png create mode 100644 demos/supabase-trello/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png create mode 100644 demos/supabase-trello/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png create mode 100644 demos/supabase-trello/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md create mode 100644 demos/supabase-trello/ios/Runner/Base.lproj/LaunchScreen.storyboard create mode 100644 demos/supabase-trello/ios/Runner/Base.lproj/Main.storyboard create mode 100644 demos/supabase-trello/ios/Runner/Info.plist create mode 100644 demos/supabase-trello/ios/Runner/Runner-Bridging-Header.h create mode 100644 demos/supabase-trello/ios/RunnerTests/RunnerTests.swift create mode 100644 demos/supabase-trello/lib/features/aboutboard/presentation/index.dart create mode 100644 demos/supabase-trello/lib/features/activity/presentation/index.dart create mode 100644 demos/supabase-trello/lib/features/archivedcards/presentation/index.dart create mode 100644 demos/supabase-trello/lib/features/archivedlists/presentation/index.dart create mode 100644 demos/supabase-trello/lib/features/board/domain/board_arguments.dart create mode 100644 demos/supabase-trello/lib/features/board/presentation/boarditemobject.dart create mode 100644 demos/supabase-trello/lib/features/board/presentation/boardlistobject.dart create mode 100644 demos/supabase-trello/lib/features/board/presentation/index.dart create mode 100644 demos/supabase-trello/lib/features/boardbackground/presentation/index.dart create mode 100644 demos/supabase-trello/lib/features/boardmenu/presentation/index.dart create mode 100644 demos/supabase-trello/lib/features/boardsettings/presentation/index.dart create mode 100644 demos/supabase-trello/lib/features/carddetails/domain/card_detail_arguments.dart create mode 100644 demos/supabase-trello/lib/features/carddetails/presentation/index.dart create mode 100644 demos/supabase-trello/lib/features/closeboard/presentation/index.dart create mode 100644 demos/supabase-trello/lib/features/copyboard/presentation/index.dart create mode 100644 demos/supabase-trello/lib/features/createboard/presentation/index.dart create mode 100644 demos/supabase-trello/lib/features/createcard/presentation/index.dart create mode 100644 demos/supabase-trello/lib/features/createworkspace/presentation/index.dart create mode 100644 demos/supabase-trello/lib/features/drawer/presentation/index.dart create mode 100644 demos/supabase-trello/lib/features/editlabels/presentation/index.dart create mode 100644 demos/supabase-trello/lib/features/emailtoboard/presentation/index.dart create mode 100644 demos/supabase-trello/lib/features/emptywidget/index.dart create mode 100644 demos/supabase-trello/lib/features/generateworkspace/presentation/index.dart create mode 100644 demos/supabase-trello/lib/features/home/presentation/custom_floating_action.dart create mode 100644 demos/supabase-trello/lib/features/home/presentation/custom_search.dart create mode 100644 demos/supabase-trello/lib/features/home/presentation/index.dart create mode 100644 demos/supabase-trello/lib/features/invitemember/presentation/index.dart create mode 100644 demos/supabase-trello/lib/features/landing/presentation/bottomsheet.dart create mode 100644 demos/supabase-trello/lib/features/landing/presentation/index.dart create mode 100644 demos/supabase-trello/lib/features/members/presentation/index.dart create mode 100644 demos/supabase-trello/lib/features/mycards/presentation/index.dart create mode 100644 demos/supabase-trello/lib/features/notifications/presentation/index.dart create mode 100644 demos/supabase-trello/lib/features/offlineboards/presentation/index.dart create mode 100644 demos/supabase-trello/lib/features/powerups/presentation/index.dart create mode 100644 demos/supabase-trello/lib/features/settings/presentation/index.dart create mode 100644 demos/supabase-trello/lib/features/signtotrello/domain/sign_arguments.dart create mode 100644 demos/supabase-trello/lib/features/signtotrello/presentation/index.dart create mode 100644 demos/supabase-trello/lib/features/viewmembers/presentation/index.dart create mode 100644 demos/supabase-trello/lib/features/visibility/presentation/index.dart create mode 100644 demos/supabase-trello/lib/features/workspace/domain/workspace_arguments.dart create mode 100644 demos/supabase-trello/lib/features/workspace/presentation/index.dart create mode 100644 demos/supabase-trello/lib/features/workspacemenu/presentation/index.dart create mode 100644 demos/supabase-trello/lib/features/workspacesettings/presentation/index.dart create mode 100644 demos/supabase-trello/lib/main.dart create mode 100644 demos/supabase-trello/lib/models/activity.dart create mode 100644 demos/supabase-trello/lib/models/attachment.dart create mode 100644 demos/supabase-trello/lib/models/board.dart create mode 100644 demos/supabase-trello/lib/models/board_label.dart create mode 100644 demos/supabase-trello/lib/models/card.dart create mode 100644 demos/supabase-trello/lib/models/card_label.dart create mode 100644 demos/supabase-trello/lib/models/checklist.dart create mode 100644 demos/supabase-trello/lib/models/comment.dart create mode 100644 demos/supabase-trello/lib/models/listboard.dart create mode 100644 demos/supabase-trello/lib/models/member.dart create mode 100644 demos/supabase-trello/lib/models/models.dart create mode 100644 demos/supabase-trello/lib/models/schema.dart create mode 100644 demos/supabase-trello/lib/models/user.dart create mode 100644 demos/supabase-trello/lib/models/workspace.dart create mode 100644 demos/supabase-trello/lib/protocol/data_client.dart create mode 100644 demos/supabase-trello/lib/protocol/powersync.dart create mode 100644 demos/supabase-trello/lib/utils/color.dart create mode 100644 demos/supabase-trello/lib/utils/config.dart create mode 100644 demos/supabase-trello/lib/utils/constant.dart create mode 100644 demos/supabase-trello/lib/utils/data_generator.dart create mode 100644 demos/supabase-trello/lib/utils/service.dart create mode 100644 demos/supabase-trello/lib/utils/trello_provider.dart create mode 100644 demos/supabase-trello/lib/utils/widgets.dart create mode 100644 demos/supabase-trello/lib/widgets/thirdparty/README.md create mode 100644 demos/supabase-trello/lib/widgets/thirdparty/board_item.dart create mode 100644 demos/supabase-trello/lib/widgets/thirdparty/board_list.dart create mode 100644 demos/supabase-trello/lib/widgets/thirdparty/boardview.dart create mode 100644 demos/supabase-trello/lib/widgets/thirdparty/boardview_controller.dart create mode 100644 demos/supabase-trello/lib/widgets/thirdparty/vs_scrollbar.dart create mode 100644 demos/supabase-trello/linux/.gitignore create mode 100644 demos/supabase-trello/linux/CMakeLists.txt create mode 100644 demos/supabase-trello/linux/flutter/CMakeLists.txt create mode 100644 demos/supabase-trello/linux/flutter/generated_plugin_registrant.cc create mode 100644 demos/supabase-trello/linux/flutter/generated_plugin_registrant.h create mode 100644 demos/supabase-trello/linux/flutter/generated_plugins.cmake create mode 100644 demos/supabase-trello/linux/main.cc create mode 100644 demos/supabase-trello/linux/my_application.cc create mode 100644 demos/supabase-trello/linux/my_application.h create mode 100644 demos/supabase-trello/macos/.gitignore create mode 100644 demos/supabase-trello/macos/Flutter/Flutter-Debug.xcconfig create mode 100644 demos/supabase-trello/macos/Flutter/Flutter-Release.xcconfig create mode 100644 demos/supabase-trello/macos/Flutter/GeneratedPluginRegistrant.swift create mode 100644 demos/supabase-trello/macos/Podfile create mode 100644 demos/supabase-trello/macos/Podfile.lock create mode 100644 demos/supabase-trello/macos/Runner.xcodeproj/project.pbxproj create mode 100644 demos/supabase-trello/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 demos/supabase-trello/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme create mode 100644 demos/supabase-trello/macos/Runner.xcworkspace/contents.xcworkspacedata create mode 100644 demos/supabase-trello/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 demos/supabase-trello/macos/Runner/AppDelegate.swift create mode 100644 demos/supabase-trello/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json create mode 100644 demos/supabase-trello/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png create mode 100644 demos/supabase-trello/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png create mode 100644 demos/supabase-trello/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png create mode 100644 demos/supabase-trello/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png create mode 100644 demos/supabase-trello/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png create mode 100644 demos/supabase-trello/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png create mode 100644 demos/supabase-trello/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png create mode 100644 demos/supabase-trello/macos/Runner/Base.lproj/MainMenu.xib create mode 100644 demos/supabase-trello/macos/Runner/Configs/AppInfo.xcconfig create mode 100644 demos/supabase-trello/macos/Runner/Configs/Debug.xcconfig create mode 100644 demos/supabase-trello/macos/Runner/Configs/Release.xcconfig create mode 100644 demos/supabase-trello/macos/Runner/Configs/Warnings.xcconfig create mode 100644 demos/supabase-trello/macos/Runner/DebugProfile.entitlements create mode 100644 demos/supabase-trello/macos/Runner/Info.plist create mode 100644 demos/supabase-trello/macos/Runner/MainFlutterWindow.swift create mode 100644 demos/supabase-trello/macos/Runner/Release.entitlements create mode 100644 demos/supabase-trello/macos/RunnerTests/RunnerTests.swift create mode 100644 demos/supabase-trello/pubspec.lock create mode 100644 demos/supabase-trello/pubspec.yaml create mode 100644 demos/supabase-trello/sample_workspace.png create mode 100644 demos/supabase-trello/showcase.png create mode 100644 demos/supabase-trello/sync-rules-0.yaml create mode 100644 demos/supabase-trello/sync-rules-1.yaml create mode 100644 demos/supabase-trello/tables.sql create mode 100644 demos/supabase-trello/test/widget_test.dart create mode 100644 demos/supabase-trello/web/favicon.png create mode 100644 demos/supabase-trello/web/icons/Icon-192.png create mode 100644 demos/supabase-trello/web/icons/Icon-512.png create mode 100644 demos/supabase-trello/web/icons/Icon-maskable-192.png create mode 100644 demos/supabase-trello/web/icons/Icon-maskable-512.png create mode 100644 demos/supabase-trello/web/index.html create mode 100644 demos/supabase-trello/web/manifest.json create mode 100644 demos/supabase-trello/windows/.gitignore create mode 100644 demos/supabase-trello/windows/CMakeLists.txt create mode 100644 demos/supabase-trello/windows/flutter/CMakeLists.txt create mode 100644 demos/supabase-trello/windows/flutter/generated_plugin_registrant.cc create mode 100644 demos/supabase-trello/windows/flutter/generated_plugin_registrant.h create mode 100644 demos/supabase-trello/windows/flutter/generated_plugins.cmake create mode 100644 demos/supabase-trello/windows/runner/CMakeLists.txt create mode 100644 demos/supabase-trello/windows/runner/Runner.rc create mode 100644 demos/supabase-trello/windows/runner/flutter_window.cpp create mode 100644 demos/supabase-trello/windows/runner/flutter_window.h create mode 100644 demos/supabase-trello/windows/runner/main.cpp create mode 100644 demos/supabase-trello/windows/runner/resource.h create mode 100644 demos/supabase-trello/windows/runner/resources/app_icon.ico create mode 100644 demos/supabase-trello/windows/runner/runner.exe.manifest create mode 100644 demos/supabase-trello/windows/runner/utils.cpp create mode 100644 demos/supabase-trello/windows/runner/utils.h create mode 100644 demos/supabase-trello/windows/runner/win32_window.cpp create mode 100644 demos/supabase-trello/windows/runner/win32_window.h diff --git a/demos/supabase-trello/.env.template b/demos/supabase-trello/.env.template new file mode 100644 index 00000000..073dd3bb --- /dev/null +++ b/demos/supabase-trello/.env.template @@ -0,0 +1,4 @@ +# Update these with your own values +SUPABASE_URL=https://aaaaaaaaaaaa.supabase.co +SUPABASE_ANON_KEY=my_anon_key +POWERSYNC_URL=https://aaaaaaaaaaaa.powersync.journeyapps.com diff --git a/demos/supabase-trello/.gitignore b/demos/supabase-trello/.gitignore new file mode 100644 index 00000000..7f4b32b9 --- /dev/null +++ b/demos/supabase-trello/.gitignore @@ -0,0 +1,47 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ +.env + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# The .vscode folder contains launch configuration and tasks you configure in +# VS Code which you may wish to be included in version control, so this line +# is commented out by default. +#.vscode/ + +# Flutter/Dart/Pub related +**/doc/api/ +**/ios/Flutter/.last_build_id +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Android Studio will place build artifacts here +/android/app/debug +/android/app/profile +/android/app/release diff --git a/demos/supabase-trello/.metadata b/demos/supabase-trello/.metadata new file mode 100644 index 00000000..2e239dba --- /dev/null +++ b/demos/supabase-trello/.metadata @@ -0,0 +1,45 @@ +# This file tracks properties of this Flutter project. +# Used by Flutter tool to assess capabilities and perform upgrades etc. +# +# This file should be version controlled. + +version: + revision: d3d8effc686d73e0114d71abdcccef63fa1f25d2 + channel: stable + +project_type: app + +# Tracks metadata for the flutter migrate command +migration: + platforms: + - platform: root + create_revision: d3d8effc686d73e0114d71abdcccef63fa1f25d2 + base_revision: d3d8effc686d73e0114d71abdcccef63fa1f25d2 + - platform: android + create_revision: d3d8effc686d73e0114d71abdcccef63fa1f25d2 + base_revision: d3d8effc686d73e0114d71abdcccef63fa1f25d2 + - platform: ios + create_revision: d3d8effc686d73e0114d71abdcccef63fa1f25d2 + base_revision: d3d8effc686d73e0114d71abdcccef63fa1f25d2 + - platform: linux + create_revision: d3d8effc686d73e0114d71abdcccef63fa1f25d2 + base_revision: d3d8effc686d73e0114d71abdcccef63fa1f25d2 + - platform: macos + create_revision: d3d8effc686d73e0114d71abdcccef63fa1f25d2 + base_revision: d3d8effc686d73e0114d71abdcccef63fa1f25d2 + - platform: web + create_revision: d3d8effc686d73e0114d71abdcccef63fa1f25d2 + base_revision: d3d8effc686d73e0114d71abdcccef63fa1f25d2 + - platform: windows + create_revision: d3d8effc686d73e0114d71abdcccef63fa1f25d2 + base_revision: d3d8effc686d73e0114d71abdcccef63fa1f25d2 + + # User provided section + + # List of Local paths (relative to this file) that should be + # ignored by the migrate tool. + # + # Files that are not part of the templates will be ignored by default. + unmanaged_files: + - 'lib/main.dart' + - 'ios/Runner.xcodeproj/project.pbxproj' diff --git a/demos/supabase-trello/LICENSE b/demos/supabase-trello/LICENSE new file mode 100644 index 00000000..0e259d42 --- /dev/null +++ b/demos/supabase-trello/LICENSE @@ -0,0 +1,121 @@ +Creative Commons Legal Code + +CC0 1.0 Universal + + CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE + LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN + ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS + INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES + REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS + PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM + THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED + HEREUNDER. + +Statement of Purpose + +The laws of most jurisdictions throughout the world automatically confer +exclusive Copyright and Related Rights (defined below) upon the creator +and subsequent owner(s) (each and all, an "owner") of an original work of +authorship and/or a database (each, a "Work"). + +Certain owners wish to permanently relinquish those rights to a Work for +the purpose of contributing to a commons of creative, cultural and +scientific works ("Commons") that the public can reliably and without fear +of later claims of infringement build upon, modify, incorporate in other +works, reuse and redistribute as freely as possible in any form whatsoever +and for any purposes, including without limitation commercial purposes. +These owners may contribute to the Commons to promote the ideal of a free +culture and the further production of creative, cultural and scientific +works, or to gain reputation or greater distribution for their Work in +part through the use and efforts of others. + +For these and/or other purposes and motivations, and without any +expectation of additional consideration or compensation, the person +associating CC0 with a Work (the "Affirmer"), to the extent that he or she +is an owner of Copyright and Related Rights in the Work, voluntarily +elects to apply CC0 to the Work and publicly distribute the Work under its +terms, with knowledge of his or her Copyright and Related Rights in the +Work and the meaning and intended legal effect of CC0 on those rights. + +1. Copyright and Related Rights. A Work made available under CC0 may be +protected by copyright and related or neighboring rights ("Copyright and +Related Rights"). Copyright and Related Rights include, but are not +limited to, the following: + + i. the right to reproduce, adapt, distribute, perform, display, + communicate, and translate a Work; + ii. moral rights retained by the original author(s) and/or performer(s); +iii. publicity and privacy rights pertaining to a person's image or + likeness depicted in a Work; + iv. rights protecting against unfair competition in regards to a Work, + subject to the limitations in paragraph 4(a), below; + v. rights protecting the extraction, dissemination, use and reuse of data + in a Work; + vi. database rights (such as those arising under Directive 96/9/EC of the + European Parliament and of the Council of 11 March 1996 on the legal + protection of databases, and under any national implementation + thereof, including any amended or successor version of such + directive); and +vii. other similar, equivalent or corresponding rights throughout the + world based on applicable law or treaty, and any national + implementations thereof. + +2. Waiver. To the greatest extent permitted by, but not in contravention +of, applicable law, Affirmer hereby overtly, fully, permanently, +irrevocably and unconditionally waives, abandons, and surrenders all of +Affirmer's Copyright and Related Rights and associated claims and causes +of action, whether now known or unknown (including existing as well as +future claims and causes of action), in the Work (i) in all territories +worldwide, (ii) for the maximum duration provided by applicable law or +treaty (including future time extensions), (iii) in any current or future +medium and for any number of copies, and (iv) for any purpose whatsoever, +including without limitation commercial, advertising or promotional +purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each +member of the public at large and to the detriment of Affirmer's heirs and +successors, fully intending that such Waiver shall not be subject to +revocation, rescission, cancellation, termination, or any other legal or +equitable action to disrupt the quiet enjoyment of the Work by the public +as contemplated by Affirmer's express Statement of Purpose. + +3. Public License Fallback. Should any part of the Waiver for any reason +be judged legally invalid or ineffective under applicable law, then the +Waiver shall be preserved to the maximum extent permitted taking into +account Affirmer's express Statement of Purpose. In addition, to the +extent the Waiver is so judged Affirmer hereby grants to each affected +person a royalty-free, non transferable, non sublicensable, non exclusive, +irrevocable and unconditional license to exercise Affirmer's Copyright and +Related Rights in the Work (i) in all territories worldwide, (ii) for the +maximum duration provided by applicable law or treaty (including future +time extensions), (iii) in any current or future medium and for any number +of copies, and (iv) for any purpose whatsoever, including without +limitation commercial, advertising or promotional purposes (the +"License"). The License shall be deemed effective as of the date CC0 was +applied by Affirmer to the Work. Should any part of the License for any +reason be judged legally invalid or ineffective under applicable law, such +partial invalidity or ineffectiveness shall not invalidate the remainder +of the License, and in such case Affirmer hereby affirms that he or she +will not (i) exercise any of his or her remaining Copyright and Related +Rights in the Work or (ii) assert any associated claims and causes of +action with respect to the Work, in either case contrary to Affirmer's +express Statement of Purpose. + +4. Limitations and Disclaimers. + + a. No trademark or patent rights held by Affirmer are waived, abandoned, + surrendered, licensed or otherwise affected by this document. + b. Affirmer offers the Work as-is and makes no representations or + warranties of any kind concerning the Work, express, implied, + statutory or otherwise, including without limitation warranties of + title, merchantability, fitness for a particular purpose, non + infringement, or the absence of latent or other defects, accuracy, or + the present or absence of errors, whether or not discoverable, all to + the greatest extent permissible under applicable law. + c. Affirmer disclaims responsibility for clearing rights of other persons + that may apply to the Work or any use thereof, including without + limitation any person's Copyright and Related Rights in the Work. + Further, Affirmer disclaims responsibility for obtaining any necessary + consents, permissions or other rights required for any use of the + Work. + d. Affirmer understands and acknowledges that Creative Commons is not a + party to this document and has no duty or obligation with respect to + this CC0 or use of the Work. diff --git a/demos/supabase-trello/README.md b/demos/supabase-trello/README.md new file mode 100644 index 00000000..a267c88e --- /dev/null +++ b/demos/supabase-trello/README.md @@ -0,0 +1,342 @@ +# Trello Clone Using PowerSync + Flutter + +## Introduction + +Trello clone app built with [Flutter](https://flutter.dev/), [PowerSync](https://powersync.co/) and [Supabase](https://supabase.io/) + +drawing + +# Running the app + +Ensure you have [melos](https://melos.invertase.dev/~melos-latest/getting-started) installed. + +1. `cd demos/supabase-trello` +2. `melos prepare` +3. `cp .env.template .env` +4. Insert your Supabase and PowerSync project credentials into `.env` (See instructions below) +5. `flutter run` + +# Getting Started + +First check out [the integration guide](https://docs.powersync.co/integration-guides/supabase-+-powersync) for [PowerSync](https://powersync.co/) and [Supabase](https://supabase.io/). + +Before you proceed, we assume that you have already signed up for free accounts with both Supabase and PowerSync. If you haven't signed up for a **PowerSync account** yet, [click here](https://accounts.journeyapps.com/portal/free-trial?powersync=true) (and if you haven't signed up for **Supabase** yet, [click here](https://supabase.com/dashboard/sign-up)). We also assume that you already have Flutter set up. + +Next up we will follow these steps: + +1. Configure Supabase: + - Create the database schema + - Create the Postgres publication +2. Configure PowerSync: + - Create connection to Supabase + - Configure global Sync Rules +4. Configure the Trello clone app +5. Run the app and test +6. Configure improved Sync Rules +7. Run the app and test + +## Configure Supabase + +- Create a new Supabase project (or use an existing project if you prefer) and follow the below steps. +- For ease of use of this Flutter app, you can **disable email confirmation** in your Supabase Auth settings. In your Supabase project, go to _"Authentication"_ --> _"Providers"_ -> _"Email"_ and then disable _"Confirm email"_. If you keep email confirmation enabled, the Supabase user confirmation email will reference the default Supabase Site URL of http://localhost:3000 — you can ignore this. + +### Create the Database Schema +After creating the Supabase project, we still need to create the tables in the database. For this application we need the following tables: + +* `activity` +* `attachment` +* `board` +* `card` +* `checklist` +* `comment` +* `listboard` +* `member` +* `models` +* `trellouser` +* `workspace` +* `board_label` +* `card_label` + +_(We give a brief overview of the app domain model later in this README.)_ + +Do the following: +- Open the `tables.sql` file, and copy the contents. +- Paste this into the *Supabase SQL Editor* +- Run the SQL statements in the Supabase SQL Editor. (If you get a warning about a "potentially destructive operation", that's a false positive that you can safely ignore.) + +### Create the Postgres Publication + +PowerSync uses the Postgres [Write Ahead Log (WAL)](https://www.postgresql.org/docs/current/wal-intro.html) to replicate data changes in order to keep PowerSync SDK clients up to date. To enable this we need to create a `publication` in Supabase. + +Run the below SQL statement in your Supabase SQL Editor: +```sql +create publication powersync for table activity, attachment, board, card, checklist, comment, listboard, member, trellouser, workspace, board_label, card_label; +``` + +## Configuring PowerSync + +We need to connect PowerSync to the Supabase Postgres database: + +- In the [PowerSync dashboard](https://powersync.journeyapps.com/) project tree, click on _"Create new instance"_. + +- Give your instance a name, such as _"Trello Clone"_. + +- In the _"Edit Instance"_ dialog, navigate to the _"Credentials"_ tab and enable _"Use Supabase Auth"_. + +- Under the _"Connections"_ tab, click on the + icon. + +- On the subsequent screen, we'll configure the connection to Supabase. This is simplest using your Supabase database URI. In your Supabase dashboard, navigate to _"Project Settings"_ -> _"Database"_. Then, under the _"Connection String"_ section, switch to URI and copy the value. + +- Paste the copied value into the _"URI"_ field in PowerSync. + +- Enter the Password for the `postgres` user in your Supabase database. (Supabase also [refers to this password](https://supabase.com/docs/guides/database/managing-passwords) as the database password or project password) + +- Click _"Test Connection"_ and fix any errors. + +- Click "Save" + +PowerSync deploys and configures an isolated cloud environment for you, which will take a few minutes to complete. + + +## Configuring Sync Rules - 1 + +PowerSync [Sync Rules](https://docs.powersync.co/usage/sync-rules) allow developers to control which data gets synced to which user devices using a SQL-like syntax in a YAML file. For this Trello clone demo app, we're first going to use naive global sync rules, and then present improved rules that take the domain permissions into account. + + +### Global Sync Rules to Get Things Working + +We can be naive about it, and start by using a global bucket definition that at least specifies in some way which users can get data. + +- Copy the contents of `sync-rules-0.yaml` to `sync-rules.yaml` under your PowerSync project instance. +- In the top right of the `sync-rules.yaml` editor, click _"Deploy sync rules"_. +- Confirm in the dialog and wait a couple of minutes for the deployment to complete. + +When you now run the app (after completing the next step to configure and run the app), it will actually show and retain data. The app code itself applies some basic filtering to only show data that belongs to the current user, or according to the visibility and membership settings of the various workspaces and boards. + + +## Configuring Flutter App + +We need to configure the app to use the correct PowerSync and Supabase projects. + +- Copy the `trelloappclone_flutter/.env.template` file to `trelloappclone_flutter/.env`. +- Replace the values for `SUPABASE_URL` and `SUPABASE_ANON_KEY` (You can find these under _"Project Settings"_ -> _"API"_ in your Supabase dashboard — under the _"URL"_ section, and anon key under _"Project API keys"_.) +- For the value of `POWERSYNC_URL`, follow these steps: + 1. In the project tree on the PowerSync dashboard, right-click on the instance you created earlier. + 2. Click _"Edit instance"_. + 3. Click on _"Instance URL"_ to copy the value. + + +## Build & Run the Flutter App + +- Run ``` flutter pub get ``` to install the necessary packages (in the root directory of the project.) +- Invoke the ``` flutter run ``` command, and select either an Android device/emulator or iOS device/simulator as destination (_Note: PowerSync does not support Flutter web apps yet._) + + +## Configuring Sync Rules - 2 + +### Using Sync Rules to Enforce Permissions +We have syncing working, but the sync rules are not enforcing the access rules from the domain in any way. + +It is better that we do not sync data to the client that the logged-in user is not allowed to see. We can use PowerSync sync rules to enforce permissions, so that users can only see and edit data that they are allowed to see and edit. + +First, we need to understand the permissions from the app domain model: + +- A **workspace** is created by a user — this user can always see and edit the workspace. +- A **workspace** has a specific *visibility*: private (only the owner can see it), workspace (only owner and members can see it), or public (anyone can see it). +- A **workspace** has a list of *members* (users) that can see and edit the workspace, if the workspace is not private. +- A **board** is created by a user — this user can always see and edit the board as long as the user can still access that workspace +- A **board** has a specific *visibility*: private (only the owner can see it), workspace (only owner and members belonging to the parent workspace can see it) +- A user can see (and edit) any of the **cards** and **lists** belonging to a **board** that they have access to. +- A user can see (and edit) any of the **checklists**, **comments**, and **attachments** belonging to a **card** that they have access to. + +Also have a look at `trelloappclone_flutter/lib/utils/service.dart` for the access patterns used by the app code. + +Let's explore how we can use PowerSync Sync Rules to enforce these permissions and access patterns. + +First we want to sync the relevant `trellouser` records synced to the local database. To enable lookups of users for adding as members to workspaces, we currently sync all user records. For a production app, we would ideally work via an API to invite members, and not worry about direct data lookups on the app side. + +```yaml +bucket_definitions: + user_info: + # this allows syncing of all trellouser records so we can lookup users when adding members + data: + - SELECT * FROM trellouser +``` + +Then we want to look up all the workspaces (a) owned by this user, (b) where this user is a member, or (c) which are public. + +```yaml + by_workspace: + # the entities are filtered by workspaceId, thus linked to the workspaces (a) owned by this user, (b) where this user is a member, or (c) which are public + # Note: the quotes for "workspaceId" and "userId" is important, since otherwise Postgres does not deal well with non-lowercase identifiers + parameters: + - SELECT id as workspace_id FROM workspace WHERE + workspace."userId" = token_parameters.user_id + - SELECT "workspaceId" as workspace_id FROM member WHERE + member."userId" = token_parameters.user_id + - SELECT id as workspace_id FROM workspace WHERE + visibility = "Public" + data: + - SELECT * FROM workspace WHERE workspace.id = bucket.workspace_id + - SELECT * FROM board WHERE board."workspaceId" = bucket.workspace_id + - SELECT * FROM member WHERE member."workspaceId" = bucket.workspace_id + - SELECT * FROM listboard WHERE listboard."workspaceId" = bucket.workspace_id + - SELECT * FROM card WHERE card."workspaceId" = bucket.workspace_id + - SELECT * FROM checklist WHERE checklist."workspaceId" = bucket.workspace_id + - SELECT * FROM activity WHERE activity."workspaceId" = bucket.workspace_id + - SELECT * FROM comment WHERE comment."workspaceId" = bucket.workspace_id + - SELECT * FROM attachment WHERE attachment."workspaceId" = bucket.workspace_id + - SELECT * FROM board_label WHERE board_label."workspaceId" = bucket.workspace_id + - SELECT * FROM card_label WHERE card_label."workspaceId" = bucket.workspace_id +``` + +**To Configure the Improved Sync Rules, Follow These Steps:** + +- Copy the contents of `sync-rules-1.yaml`. +- Paste this to `sync-rules.yaml` under your PowerSync project instance +- Click _"Deploy sync rules"_. +- Confirm in the dialog and wait a couple of minutes for the deployment to complete. + +Now you can run the app again, and it should now only sync the subset of data that a logged in user actually has access to. + +### Importing / Generating Data + +When you run the app, after logging in, you will start without any workspaces or boards. It is possible to generate a workspace with sample boards and cards in order to make it easier to have enough data to experiment with, without having to manually create every item. + +- Sign up and log in to the app. +- In the home view, tap on the "+" floating button in the lower right corner. +- Tap on _"Sample Workspace"_ and give it a name — this will create a new workspace, with multiple boards with lists, and a random number of cards with checklists, comments and activities for each list. + +drawing + +### Structure + +* The data models are in `lib/models`) +* A PowerSync client that makes use of the PowerSync Flutter SDK and adds a few convenience methods for the app use cases (`lib/protocol/powersync.dart`) +* A `DataClient` API that can be used from the app code, and provides the higher level data API. (`lib/protocol/data_client.dart`) + +Two important files to point out as well are: + +* `lib/schema.dart` defines the SQLite schema to use for the local synced datastore, and this maps to the model classes. +* `lib/app_config.dart` contains the tokens and URLs needed to connect to PowerSync and Supabase. + + +### Listening to Updated Data + +The PowerSync SDK makes use of `watch` queries to listen for changes to synced data. When the SDK syncs updated data from the server, and it matches the query, it will send an event out, allowing e.g. an app view (via `StreamBuilder`) or some other state management class to respond. + +As an example look at `trelloappclone_flutter/lib/utils/service.dart`: + +```dart + Stream> getWorkspacesStream() { + return dataClient.workspace.watchWorkspacesByUser(userId: trello.user.id).map((workspaces) { + trello.setWorkspaces(workspaces); + return workspaces; + }); + } +``` + +This in turn makes use of the `_WorkspaceRepository` class: +```dart + Stream> watchWorkspacesByUser({required String userId}) { + //First we get the workspaces + return client.getDBExecutor().watch(''' + SELECT * FROM workspace WHERE userId = ? + ''', parameters: [userId]).asyncMap((event) async { + List workspaces = event.map((row) => Workspace.fromRow(row)).toList(); + + //Then we get the members for each workspace + for (Workspace workspace in workspaces) { + List members = await client.member.getMembersByWorkspace(workspaceId: workspace.id); + workspace.members = members; + } + return workspaces; + }); + } +``` + +Now we can simply make use of a `StreamBuilder` to have a view component that updates whenever a matching workspace is updated: + +```dart + StreamBuilder( + stream: getWorkspacesStream(), + builder: + (BuildContext context, AsyncSnapshot> snapshot) { + if (snapshot.hasData) { + List children = snapshot.data as List; + + if (children.isNotEmpty) { + return SingleChildScrollView( + child: + Column(children: buildWorkspacesAndBoards(children))); + } + } else { + return Container(); + } + }) +``` + +### Doing a Transaction + +It is possible to ensure that a number of related entities are updated in an atomic database transaction. As an example of this, look at `DataClient.archiveCardsInList`: + +```dart + /// Archive cards in and return how many were archived + /// This happens in a transaction + Future archiveCardsInList(Listboard list) async { + if (list.cards == null || list.cards!.isEmpty) { + return 0; + } + + //start a write transaction + return client.getDBExecutor().writeTransaction((sqlContext) async { + List cards = list.cards!; + int numCards = cards.length; + + //we set each of the cards in the list to archived = true + sqlContext.executeBatch(''' + UPDATE card + SET archived = 1 + WHERE id = ? + ''' + , cards.map((card) => [card.id]).toList()); + + //touch listboard to trigger update via stream listeners on Listboard + sqlContext.execute(''' + UPDATE listboard + SET archived = 0 + WHERE id = ? + ''', [list.id]); + + list.cards = []; + return numCards; + //end of transaction + }, debugContext: 'archiveCardsInList'); + } +``` + +The above code is invoked if you choose to archive all the cards in a list from the list popup menu. + +### Changes from Original Trello Clone App + +The app code was forked from the [Serverpod + Flutter Tutorial](https://github.com/Mobterest/serverpod_flutter_tutorial) code. It was changed in the following ways to facilitate the PowerSync integration: + +- Updated data model so that all `id` fields are Strings, and use UUIDs (it was auto-increment integer fields in the original app) +- Updated data model so that all entities refer to the `workspaceId` of workspace in which it was created (this facilitates the Sync Rules) + +## Next + +Below is a list of things that can be implemented to enhance the functionality and experience of this app: + +* Update Workspace + Board edit views to use actual data and update the entity +* Get Comments & Checklists working properly +* Enhance state management - e.g. let `TrelloProvider` listen to streams, and notify changes, to simplify views +* Get the attachments to actually work (using Supabase files upload/download) + +## Feedback + +- Feel free to send feedback. Feature requests are always welcome. If there's anything you'd like to chat about, please [join our Discord](https://discord.gg/powersync). + +## Acknowledgements + +This tutorial is based on the [Serverpod + Flutter Tutorial](https://github.com/Mobterest/serverpod_flutter_tutorial) by [Mobterest](https://www.instagram.com/mobterest/) diff --git a/demos/supabase-trello/analysis_options.yaml b/demos/supabase-trello/analysis_options.yaml new file mode 100644 index 00000000..61b6c4de --- /dev/null +++ b/demos/supabase-trello/analysis_options.yaml @@ -0,0 +1,29 @@ +# This file configures the analyzer, which statically analyzes Dart code to +# check for errors, warnings, and lints. +# +# The issues identified by the analyzer are surfaced in the UI of Dart-enabled +# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be +# invoked from the command line by running `flutter analyze`. + +# The following line activates a set of recommended lints for Flutter apps, +# packages, and plugins designed to encourage good coding practices. +include: package:flutter_lints/flutter.yaml + +linter: + # The lint rules applied to this project can be customized in the + # section below to disable rules from the `package:flutter_lints/flutter.yaml` + # included above or to enable additional rules. A list of all available lints + # and their documentation is published at + # https://dart-lang.github.io/linter/lints/index.html. + # + # Instead of disabling a lint rule for the entire project in the + # section below, it can also be suppressed for a single line of code + # or a specific dart file by using the `// ignore: name_of_lint` and + # `// ignore_for_file: name_of_lint` syntax on the line or in the file + # producing the lint. + rules: + # avoid_print: false # Uncomment to disable the `avoid_print` rule + # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule + +# Additional information about this file can be found at +# https://dart.dev/guides/language/analysis-options diff --git a/demos/supabase-trello/android/.gitignore b/demos/supabase-trello/android/.gitignore new file mode 100644 index 00000000..6f568019 --- /dev/null +++ b/demos/supabase-trello/android/.gitignore @@ -0,0 +1,13 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java + +# Remember to never publicly share your keystore. +# See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app +key.properties +**/*.keystore +**/*.jks diff --git a/demos/supabase-trello/android/app/build.gradle b/demos/supabase-trello/android/app/build.gradle new file mode 100644 index 00000000..21dc0f37 --- /dev/null +++ b/demos/supabase-trello/android/app/build.gradle @@ -0,0 +1,65 @@ +plugins { + id "com.android.application" + id "kotlin-android" + id "dev.flutter.flutter-gradle-plugin" +} + +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +android { + namespace "com.example.trelloappclone_flutter" + compileSdkVersion flutter.compileSdkVersion + ndkVersion flutter.ndkVersion + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + + kotlinOptions { + jvmTarget = '1.8' + } + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.trelloappclone_flutter" + // You can update the following values to match your application needs. + // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration. + minSdkVersion 23 + targetSdkVersion flutter.targetSdkVersion + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + + buildTypes { + release { + // TODO: Add your own signing config for the release build. + // Signing with the debug keys for now, so `flutter run --release` works. + signingConfig signingConfigs.debug + } + } +} + +flutter { + source '../..' +} diff --git a/demos/supabase-trello/android/app/src/debug/AndroidManifest.xml b/demos/supabase-trello/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 00000000..399f6981 --- /dev/null +++ b/demos/supabase-trello/android/app/src/debug/AndroidManifest.xml @@ -0,0 +1,7 @@ + + + + diff --git a/demos/supabase-trello/android/app/src/main/AndroidManifest.xml b/demos/supabase-trello/android/app/src/main/AndroidManifest.xml new file mode 100644 index 00000000..e1dc4071 --- /dev/null +++ b/demos/supabase-trello/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + diff --git a/demos/supabase-trello/android/app/src/main/kotlin/com/example/trelloappclone_flutter/MainActivity.kt b/demos/supabase-trello/android/app/src/main/kotlin/com/example/trelloappclone_flutter/MainActivity.kt new file mode 100644 index 00000000..875d532e --- /dev/null +++ b/demos/supabase-trello/android/app/src/main/kotlin/com/example/trelloappclone_flutter/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.trelloappclone_flutter + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} diff --git a/demos/supabase-trello/android/app/src/main/res/drawable-v21/launch_background.xml b/demos/supabase-trello/android/app/src/main/res/drawable-v21/launch_background.xml new file mode 100644 index 00000000..f74085f3 --- /dev/null +++ b/demos/supabase-trello/android/app/src/main/res/drawable-v21/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/demos/supabase-trello/android/app/src/main/res/drawable/launch_background.xml b/demos/supabase-trello/android/app/src/main/res/drawable/launch_background.xml new file mode 100644 index 00000000..304732f8 --- /dev/null +++ b/demos/supabase-trello/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/demos/supabase-trello/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/demos/supabase-trello/android/app/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..db77bb4b7b0906d62b1847e87f15cdcacf6a4f29 GIT binary patch literal 544 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY3?!3`olAj~WQl7;NpOBzNqJ&XDuZK6ep0G} zXKrG8YEWuoN@d~6R2!h8bpbvhu0Wd6uZuB!w&u2PAxD2eNXD>P5D~Wn-+_Wa#27Xc zC?Zj|6r#X(-D3u$NCt}(Ms06KgJ4FxJVv{GM)!I~&n8Bnc94O7-Hd)cjDZswgC;Qs zO=b+9!WcT8F?0rF7!Uys2bs@gozCP?z~o%U|N3vA*22NaGQG zlg@K`O_XuxvZ&Ks^m&R!`&1=spLvfx7oGDKDwpwW`#iqdw@AL`7MR}m`rwr|mZgU`8P7SBkL78fFf!WnuYWm$5Z0 zNXhDbCv&49sM544K|?c)WrFfiZvCi9h0O)B3Pgg&ebxsLQ05GG~ AQ2+n{ literal 0 HcmV?d00001 diff --git a/demos/supabase-trello/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/demos/supabase-trello/android/app/src/main/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..17987b79bb8a35cc66c3c1fd44f5a5526c1b78be GIT binary patch literal 442 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA3?vioaBc-sk|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*D5Xx&nMcT!A!W`0S9QKQy;}1Cl^CgaH=;G9cpY;r$Q>i*pfB zP2drbID<_#qf;rPZx^FqH)F_D#*k@@q03KywUtLX8Ua?`H+NMzkczFPK3lFz@i_kW%1NOn0|D2I9n9wzH8m|-tHjsw|9>@K=iMBhxvkv6m8Y-l zytQ?X=U+MF$@3 zt`~i=@j|6y)RWMK--}M|=T`o&^Ni>IoWKHEbBXz7?A@mgWoL>!*SXo`SZH-*HSdS+ yn*9;$7;m`l>wYBC5bq;=U}IMqLzqbYCidGC!)_gkIk_C@Uy!y&wkt5C($~2D>~)O*cj@FGjOCM)M>_ixfudOh)?xMu#Fs z#}Y=@YDTwOM)x{K_j*Q;dPdJ?Mz0n|pLRx{4n|)f>SXlmV)XB04CrSJn#dS5nK2lM zrZ9#~WelCp7&e13Y$jvaEXHskn$2V!!DN-nWS__6T*l;H&Fopn?A6HZ-6WRLFP=R` zqG+CE#d4|IbyAI+rJJ`&x9*T`+a=p|0O(+s{UBcyZdkhj=yS1>AirP+0R;mf2uMgM zC}@~JfByORAh4SyRgi&!(cja>F(l*O+nd+@4m$|6K6KDn_&uvCpV23&>G9HJp{xgg zoq1^2_p9@|WEo z*X_Uko@K)qYYv~>43eQGMdbiGbo>E~Q& zrYBH{QP^@Sti!`2)uG{irBBq@y*$B zi#&(U-*=fp74j)RyIw49+0MRPMRU)+a2r*PJ$L5roHt2$UjExCTZSbq%V!HeS7J$N zdG@vOZB4v_lF7Plrx+hxo7(fCV&}fHq)$ literal 0 HcmV?d00001 diff --git a/demos/supabase-trello/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/demos/supabase-trello/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..d5f1c8d34e7a88e3f88bea192c3a370d44689c3c GIT binary patch literal 1031 zcmeAS@N?(olHy`uVBq!ia0vp^6F``Q8Ax83A=Cw=BuiW)N`mv#O3D+9QW+dm@{>{( zJaZG%Q-e|yQz{EjrrIztFa`(sgt!6~Yi|1%a`XoT0ojZ}lNrNjb9xjc(B0U1_% zz5^97Xt*%oq$rQy4?0GKNfJ44uvxI)gC`h-NZ|&0-7(qS@?b!5r36oQ}zyZrNO3 zMO=Or+<~>+A&uN&E!^Sl+>xE!QC-|oJv`ApDhqC^EWD|@=#J`=d#Xzxs4ah}w&Jnc z$|q_opQ^2TrnVZ0o~wh<3t%W&flvYGe#$xqda2bR_R zvPYgMcHgjZ5nSA^lJr%;<&0do;O^tDDh~=pIxA#coaCY>&N%M2^tq^U%3DB@ynvKo}b?yu-bFc-u0JHzced$sg7S3zqI(2 z#Km{dPr7I=pQ5>FuK#)QwK?Y`E`B?nP+}U)I#c1+FM*1kNvWG|a(TpksZQ3B@sD~b zpQ2)*V*TdwjFOtHvV|;OsiDqHi=6%)o4b!)x$)%9pGTsE z-JL={-Ffv+T87W(Xpooq<`r*VzWQcgBN$$`u}f>-ZQI1BB8ykN*=e4rIsJx9>z}*o zo~|9I;xof literal 0 HcmV?d00001 diff --git a/demos/supabase-trello/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/demos/supabase-trello/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..4d6372eebdb28e45604e46eeda8dd24651419bc0 GIT binary patch literal 1443 zcmb`G{WsKk6vsdJTdFg%tJav9_E4vzrOaqkWF|A724Nly!y+?N9`YV6wZ}5(X(D_N(?!*n3`|_r0Hc?=PQw&*vnU?QTFY zB_MsH|!j$PP;I}?dppoE_gA(4uc!jV&0!l7_;&p2^pxNo>PEcNJv za5_RT$o2Mf!<+r?&EbHH6nMoTsDOa;mN(wv8RNsHpG)`^ymG-S5By8=l9iVXzN_eG%Xg2@Xeq76tTZ*dGh~Lo9vl;Zfs+W#BydUw zCkZ$o1LqWQO$FC9aKlLl*7x9^0q%0}$OMlp@Kk_jHXOjofdePND+j!A{q!8~Jn+s3 z?~~w@4?egS02}8NuulUA=L~QQfm;MzCGd)XhiftT;+zFO&JVyp2mBww?;QByS_1w! zrQlx%{^cMj0|Bo1FjwY@Q8?Hx0cIPF*@-ZRFpPc#bBw{5@tD(5%sClzIfl8WU~V#u zm5Q;_F!wa$BSpqhN>W@2De?TKWR*!ujY;Yylk_X5#~V!L*Gw~;$%4Q8~Mad z@`-kG?yb$a9cHIApZDVZ^U6Xkp<*4rU82O7%}0jjHlK{id@?-wpN*fCHXyXh(bLt* zPc}H-x0e4E&nQ>y%B-(EL=9}RyC%MyX=upHuFhAk&MLbsF0LP-q`XnH78@fT+pKPW zu72MW`|?8ht^tz$iC}ZwLp4tB;Q49K!QCF3@!iB1qOI=?w z7In!}F~ij(18UYUjnbmC!qKhPo%24?8U1x{7o(+?^Zu0Hx81|FuS?bJ0jgBhEMzf< zCgUq7r2OCB(`XkKcN-TL>u5y#dD6D!)5W?`O5)V^>jb)P)GBdy%t$uUMpf$SNV31$ zb||OojAbvMP?T@$h_ZiFLFVHDmbyMhJF|-_)HX3%m=CDI+ID$0^C>kzxprBW)hw(v zr!Gmda);ICoQyhV_oP5+C%?jcG8v+D@9f?Dk*!BxY}dazmrT@64UrP3hlslANK)bq z$67n83eh}OeW&SV@HG95P|bjfqJ7gw$e+`Hxo!4cx`jdK1bJ>YDSpGKLPZ^1cv$ek zIB?0S<#tX?SJCLWdMd{-ME?$hc7A$zBOdIJ)4!KcAwb=VMov)nK;9z>x~rfT1>dS+ zZ6#`2v@`jgbqq)P22H)Tx2CpmM^o1$B+xT6`(v%5xJ(?j#>Q$+rx_R|7TzDZe{J6q zG1*EcU%tE?!kO%^M;3aM6JN*LAKUVb^xz8-Pxo#jR5(-KBeLJvA@-gxNHx0M-ZJLl z;#JwQoh~9V?`UVo#}{6ka@II>++D@%KqGpMdlQ}?9E*wFcf5(#XQnP$Dk5~%iX^>f z%$y;?M0BLp{O3a(-4A?ewryHrrD%cx#Q^%KY1H zNre$ve+vceSLZcNY4U(RBX&)oZn*Py()h)XkE?PL$!bNb{N5FVI2Y%LKEm%yvpyTP z(1P?z~7YxD~Rf<(a@_y` literal 0 HcmV?d00001 diff --git a/demos/supabase-trello/android/app/src/main/res/values-night/styles.xml b/demos/supabase-trello/android/app/src/main/res/values-night/styles.xml new file mode 100644 index 00000000..06952be7 --- /dev/null +++ b/demos/supabase-trello/android/app/src/main/res/values-night/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/demos/supabase-trello/android/app/src/main/res/values/styles.xml b/demos/supabase-trello/android/app/src/main/res/values/styles.xml new file mode 100644 index 00000000..cb1ef880 --- /dev/null +++ b/demos/supabase-trello/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/demos/supabase-trello/android/app/src/profile/AndroidManifest.xml b/demos/supabase-trello/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 00000000..399f6981 --- /dev/null +++ b/demos/supabase-trello/android/app/src/profile/AndroidManifest.xml @@ -0,0 +1,7 @@ + + + + diff --git a/demos/supabase-trello/android/build.gradle b/demos/supabase-trello/android/build.gradle new file mode 100644 index 00000000..bc157bd1 --- /dev/null +++ b/demos/supabase-trello/android/build.gradle @@ -0,0 +1,18 @@ +allprojects { + repositories { + google() + mavenCentral() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +tasks.register("clean", Delete) { + delete rootProject.buildDir +} diff --git a/demos/supabase-trello/android/gradle.properties b/demos/supabase-trello/android/gradle.properties new file mode 100644 index 00000000..94adc3a3 --- /dev/null +++ b/demos/supabase-trello/android/gradle.properties @@ -0,0 +1,3 @@ +org.gradle.jvmargs=-Xmx1536M +android.useAndroidX=true +android.enableJetifier=true diff --git a/demos/supabase-trello/android/gradle/wrapper/gradle-wrapper.properties b/demos/supabase-trello/android/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 00000000..348c409e --- /dev/null +++ b/demos/supabase-trello/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-all.zip diff --git a/demos/supabase-trello/android/settings.gradle b/demos/supabase-trello/android/settings.gradle new file mode 100644 index 00000000..e9862544 --- /dev/null +++ b/demos/supabase-trello/android/settings.gradle @@ -0,0 +1,25 @@ +pluginManagement { + def flutterSdkPath = { + def properties = new Properties() + file("local.properties").withInputStream { properties.load(it) } + def flutterSdkPath = properties.getProperty("flutter.sdk") + assert flutterSdkPath != null, "flutter.sdk not set in local.properties" + return flutterSdkPath + }() + + includeBuild("$flutterSdkPath/packages/flutter_tools/gradle") + + repositories { + google() + mavenCentral() + gradlePluginPortal() + } +} + +plugins { + id "dev.flutter.flutter-plugin-loader" version "1.0.0" + id "com.android.application" version "8.7.0" apply false + id "org.jetbrains.kotlin.android" version "1.7.0" apply false +} + +include ":app" diff --git a/demos/supabase-trello/assets/landing.jpg b/demos/supabase-trello/assets/landing.jpg new file mode 100644 index 0000000000000000000000000000000000000000..7614ae9ffeb94376813c2acdc4ebf4599d31028d GIT binary patch literal 182187 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�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 literal 0 HcmV?d00001 diff --git a/demos/supabase-trello/assets/trello-logo.png b/demos/supabase-trello/assets/trello-logo.png new file mode 100644 index 0000000000000000000000000000000000000000..a8068fd646005d5a97688a04ff88e6fa81b1ff6b GIT binary patch literal 3174 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 literal 0 HcmV?d00001 diff --git a/demos/supabase-trello/devtools_options.yaml b/demos/supabase-trello/devtools_options.yaml new file mode 100644 index 00000000..fa0b357c --- /dev/null +++ b/demos/supabase-trello/devtools_options.yaml @@ -0,0 +1,3 @@ +description: This file stores settings for Dart & Flutter DevTools. +documentation: https://docs.flutter.dev/tools/devtools/extensions#configure-extension-enablement-states +extensions: diff --git a/demos/supabase-trello/ios/.gitignore b/demos/supabase-trello/ios/.gitignore new file mode 100644 index 00000000..7a7f9873 --- /dev/null +++ b/demos/supabase-trello/ios/.gitignore @@ -0,0 +1,34 @@ +**/dgph +*.mode1v3 +*.mode2v3 +*.moved-aside +*.pbxuser +*.perspectivev3 +**/*sync/ +.sconsign.dblite +.tags* +**/.vagrant/ +**/DerivedData/ +Icon? +**/Pods/ +**/.symlinks/ +profile +xcuserdata +**/.generated/ +Flutter/App.framework +Flutter/Flutter.framework +Flutter/Flutter.podspec +Flutter/Generated.xcconfig +Flutter/ephemeral/ +Flutter/app.flx +Flutter/app.zip +Flutter/flutter_assets/ +Flutter/flutter_export_environment.sh +ServiceDefinitions.json +Runner/GeneratedPluginRegistrant.* + +# Exceptions to above rules. +!default.mode1v3 +!default.mode2v3 +!default.pbxuser +!default.perspectivev3 diff --git a/demos/supabase-trello/ios/Flutter/AppFrameworkInfo.plist b/demos/supabase-trello/ios/Flutter/AppFrameworkInfo.plist new file mode 100644 index 00000000..7c569640 --- /dev/null +++ b/demos/supabase-trello/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 12.0 + + diff --git a/demos/supabase-trello/ios/Flutter/Debug.xcconfig b/demos/supabase-trello/ios/Flutter/Debug.xcconfig new file mode 100644 index 00000000..ec97fc6f --- /dev/null +++ b/demos/supabase-trello/ios/Flutter/Debug.xcconfig @@ -0,0 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" +#include "Generated.xcconfig" diff --git a/demos/supabase-trello/ios/Flutter/Release.xcconfig b/demos/supabase-trello/ios/Flutter/Release.xcconfig new file mode 100644 index 00000000..c4855bfe --- /dev/null +++ b/demos/supabase-trello/ios/Flutter/Release.xcconfig @@ -0,0 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" +#include "Generated.xcconfig" diff --git a/demos/supabase-trello/ios/Podfile b/demos/supabase-trello/ios/Podfile new file mode 100644 index 00000000..885313b0 --- /dev/null +++ b/demos/supabase-trello/ios/Podfile @@ -0,0 +1,47 @@ +# Uncomment this line to define a global platform for your project +platform :ios, '12.0' + +# CocoaPods analytics sends network stats synchronously affecting flutter build latency. +ENV['COCOAPODS_DISABLE_STATS'] = 'true' + +project 'Runner', { + 'Debug' => :debug, + 'Profile' => :release, + 'Release' => :release, +} + +def flutter_root + generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) + unless File.exist?(generated_xcode_build_settings_path) + raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" + end + + File.foreach(generated_xcode_build_settings_path) do |line| + matches = line.match(/FLUTTER_ROOT\=(.*)/) + return matches[1].strip if matches + end + raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" +end + +require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) + +flutter_ios_podfile_setup + +target 'Runner' do + use_frameworks! + use_modular_headers! + + flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) + target 'RunnerTests' do + inherit! :search_paths + end +end + +post_install do |installer| + installer.pods_project.targets.each do |target| + flutter_additional_ios_build_settings(target) + target.build_configurations.each do |config| + config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '12.0' + end + end +end diff --git a/demos/supabase-trello/ios/Podfile.lock b/demos/supabase-trello/ios/Podfile.lock new file mode 100644 index 00000000..4ca14fbb --- /dev/null +++ b/demos/supabase-trello/ios/Podfile.lock @@ -0,0 +1,136 @@ +PODS: + - app_links (0.0.2): + - Flutter + - DKImagePickerController/Core (4.3.9): + - DKImagePickerController/ImageDataManager + - DKImagePickerController/Resource + - DKImagePickerController/ImageDataManager (4.3.9) + - DKImagePickerController/PhotoGallery (4.3.9): + - DKImagePickerController/Core + - DKPhotoGallery + - DKImagePickerController/Resource (4.3.9) + - DKPhotoGallery (0.0.19): + - DKPhotoGallery/Core (= 0.0.19) + - DKPhotoGallery/Model (= 0.0.19) + - DKPhotoGallery/Preview (= 0.0.19) + - DKPhotoGallery/Resource (= 0.0.19) + - SDWebImage + - SwiftyGif + - DKPhotoGallery/Core (0.0.19): + - DKPhotoGallery/Model + - DKPhotoGallery/Preview + - SDWebImage + - SwiftyGif + - DKPhotoGallery/Model (0.0.19): + - SDWebImage + - SwiftyGif + - DKPhotoGallery/Preview (0.0.19): + - DKPhotoGallery/Model + - DKPhotoGallery/Resource + - SDWebImage + - SwiftyGif + - DKPhotoGallery/Resource (0.0.19): + - SDWebImage + - SwiftyGif + - file_picker (0.0.1): + - DKImagePickerController/PhotoGallery + - Flutter + - Flutter (1.0.0) + - image_picker_ios (0.0.1): + - Flutter + - path_provider_foundation (0.0.1): + - Flutter + - FlutterMacOS + - powersync-sqlite-core (0.3.7) + - powersync_flutter_libs (0.0.1): + - Flutter + - powersync-sqlite-core (~> 0.3.6) + - SDWebImage (5.20.0): + - SDWebImage/Core (= 5.20.0) + - SDWebImage/Core (5.20.0) + - shared_preferences_foundation (0.0.1): + - Flutter + - FlutterMacOS + - sqlite3 (3.47.2): + - sqlite3/common (= 3.47.2) + - sqlite3/common (3.47.2) + - sqlite3/dbstatvtab (3.47.2): + - sqlite3/common + - sqlite3/fts5 (3.47.2): + - sqlite3/common + - sqlite3/perf-threadsafe (3.47.2): + - sqlite3/common + - sqlite3/rtree (3.47.2): + - sqlite3/common + - sqlite3_flutter_libs (0.0.1): + - Flutter + - FlutterMacOS + - sqlite3 (~> 3.47.2) + - sqlite3/dbstatvtab + - sqlite3/fts5 + - sqlite3/perf-threadsafe + - sqlite3/rtree + - SwiftyGif (5.4.5) + - url_launcher_ios (0.0.1): + - Flutter + +DEPENDENCIES: + - app_links (from `.symlinks/plugins/app_links/ios`) + - file_picker (from `.symlinks/plugins/file_picker/ios`) + - Flutter (from `Flutter`) + - image_picker_ios (from `.symlinks/plugins/image_picker_ios/ios`) + - path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`) + - powersync_flutter_libs (from `.symlinks/plugins/powersync_flutter_libs/ios`) + - shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`) + - sqlite3_flutter_libs (from `.symlinks/plugins/sqlite3_flutter_libs/darwin`) + - url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`) + +SPEC REPOS: + trunk: + - DKImagePickerController + - DKPhotoGallery + - powersync-sqlite-core + - SDWebImage + - sqlite3 + - SwiftyGif + +EXTERNAL SOURCES: + app_links: + :path: ".symlinks/plugins/app_links/ios" + file_picker: + :path: ".symlinks/plugins/file_picker/ios" + Flutter: + :path: Flutter + image_picker_ios: + :path: ".symlinks/plugins/image_picker_ios/ios" + path_provider_foundation: + :path: ".symlinks/plugins/path_provider_foundation/darwin" + powersync_flutter_libs: + :path: ".symlinks/plugins/powersync_flutter_libs/ios" + shared_preferences_foundation: + :path: ".symlinks/plugins/shared_preferences_foundation/darwin" + sqlite3_flutter_libs: + :path: ".symlinks/plugins/sqlite3_flutter_libs/darwin" + url_launcher_ios: + :path: ".symlinks/plugins/url_launcher_ios/ios" + +SPEC CHECKSUMS: + app_links: e7a6750a915a9e161c58d91bc610e8cd1d4d0ad0 + DKImagePickerController: 946cec48c7873164274ecc4624d19e3da4c1ef3c + DKPhotoGallery: b3834fecb755ee09a593d7c9e389d8b5d6deed60 + file_picker: 15fd9539e4eb735dc54bae8c0534a7a9511a03de + Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7 + image_picker_ios: c560581cceedb403a6ff17f2f816d7fea1421fc1 + path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46 + powersync-sqlite-core: b9bcd19fa191d3d6f3f85c0573c41799d654cfa7 + powersync_flutter_libs: eb2694b322e1e4ef9a0f1e32dee600847f21ccbc + SDWebImage: 73c6079366fea25fa4bb9640d5fb58f0893facd8 + shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78 + sqlite3: 7559e33dae4c78538df563795af3a86fc887ee71 + sqlite3_flutter_libs: 58ae36c0dd086395d066b4fe4de9cdca83e717b3 + SwiftyGif: 706c60cf65fa2bc5ee0313beece843c8eb8194d4 + url_launcher_ios: 5334b05cef931de560670eeae103fd3e431ac3fe + +PODFILE CHECKSUM: 9d8d1770d47a428fcb57a5d5f228a34e6d072ae7 + +COCOAPODS: 1.16.2 diff --git a/demos/supabase-trello/ios/Runner.xcodeproj/project.pbxproj b/demos/supabase-trello/ios/Runner.xcodeproj/project.pbxproj new file mode 100644 index 00000000..643e5165 --- /dev/null +++ b/demos/supabase-trello/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,723 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 54; + objects = { + +/* Begin PBXBuildFile section */ + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; + 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; }; + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; + 580DE0ECE5B255011C07A13C /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E2B5432F50F552DF6C1D0FA1 /* Pods_Runner.framework */; }; + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; + 9F5E6CDBDFD984AD1CE17EBF /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C37744B39F4E3B36A0BBB0CE /* Pods_RunnerTests.framework */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 331C8085294A63A400263BE5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 97C146E61CF9000F007C117D /* Project object */; + proxyType = 1; + remoteGlobalIDString = 97C146ED1CF9000F007C117D; + remoteInfo = Runner; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 0FF24B675B56F022C3289F08 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; + 331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; + 331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 36C14A9DF8CBED78B8383618 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; + 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; + 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; + 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; + 976B259CF18C36EB3B6F4F0F /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = ""; }; + 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + A2E15785CC927C31AEF6BC6A /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = ""; }; + B0E8CE81B52F70CDF2A4F80B /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = ""; }; + C37744B39F4E3B36A0BBB0CE /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + DB8B11F7834AB262F47996E5 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; + E2B5432F50F552DF6C1D0FA1 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 97C146EB1CF9000F007C117D /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 580DE0ECE5B255011C07A13C /* Pods_Runner.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + A9A2ECF3A7DDE6AA422CD674 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 9F5E6CDBDFD984AD1CE17EBF /* Pods_RunnerTests.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 331C8082294A63A400263BE5 /* RunnerTests */ = { + isa = PBXGroup; + children = ( + 331C807B294A618700263BE5 /* RunnerTests.swift */, + ); + path = RunnerTests; + sourceTree = ""; + }; + 9740EEB11CF90186004384FC /* Flutter */ = { + isa = PBXGroup; + children = ( + 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, + 9740EEB21CF90195004384FC /* Debug.xcconfig */, + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, + 9740EEB31CF90195004384FC /* Generated.xcconfig */, + ); + name = Flutter; + sourceTree = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + 331C8082294A63A400263BE5 /* RunnerTests */, + A7F3D089A45655143E0E6848 /* Pods */, + B312AFB09377AB967113F8FE /* Frameworks */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + 331C8081294A63A400263BE5 /* RunnerTests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; + A7F3D089A45655143E0E6848 /* Pods */ = { + isa = PBXGroup; + children = ( + DB8B11F7834AB262F47996E5 /* Pods-Runner.debug.xcconfig */, + 36C14A9DF8CBED78B8383618 /* Pods-Runner.release.xcconfig */, + 0FF24B675B56F022C3289F08 /* Pods-Runner.profile.xcconfig */, + A2E15785CC927C31AEF6BC6A /* Pods-RunnerTests.debug.xcconfig */, + B0E8CE81B52F70CDF2A4F80B /* Pods-RunnerTests.release.xcconfig */, + 976B259CF18C36EB3B6F4F0F /* Pods-RunnerTests.profile.xcconfig */, + ); + path = Pods; + sourceTree = ""; + }; + B312AFB09377AB967113F8FE /* Frameworks */ = { + isa = PBXGroup; + children = ( + E2B5432F50F552DF6C1D0FA1 /* Pods_Runner.framework */, + C37744B39F4E3B36A0BBB0CE /* Pods_RunnerTests.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 331C8080294A63A400263BE5 /* RunnerTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; + buildPhases = ( + 579312ED36242754EF3992BA /* [CP] Check Pods Manifest.lock */, + 331C807D294A63A400263BE5 /* Sources */, + 331C807F294A63A400263BE5 /* Resources */, + A9A2ECF3A7DDE6AA422CD674 /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + 331C8086294A63A400263BE5 /* PBXTargetDependency */, + ); + name = RunnerTests; + productName = RunnerTests; + productReference = 331C8081294A63A400263BE5 /* RunnerTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; + 97C146ED1CF9000F007C117D /* Runner */ = { + isa = PBXNativeTarget; + buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; + buildPhases = ( + 5582B600ABA2BF2B04110F91 /* [CP] Check Pods Manifest.lock */, + 9740EEB61CF901F6004384FC /* Run Script */, + 97C146EA1CF9000F007C117D /* Sources */, + 97C146EB1CF9000F007C117D /* Frameworks */, + 97C146EC1CF9000F007C117D /* Resources */, + 9705A1C41CF9048500538489 /* Embed Frameworks */, + 3B06AD1E1E4923F5004D2608 /* Thin Binary */, + B27A73ED59948A115A9CD70F /* [CP] Embed Pods Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Runner; + productName = Runner; + productReference = 97C146EE1CF9000F007C117D /* Runner.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 97C146E61CF9000F007C117D /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 1510; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 331C8080294A63A400263BE5 = { + CreatedOnToolsVersion = 14.0; + TestTargetID = 97C146ED1CF9000F007C117D; + }; + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + 331C8080294A63A400263BE5 /* RunnerTests */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 331C807F294A63A400263BE5 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "${TARGET_BUILD_DIR}/${INFOPLIST_PATH}", + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 5582B600ABA2BF2B04110F91 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; + 579312ED36242754EF3992BA /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-RunnerTests-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; + B27A73ED59948A115A9CD70F /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Embed Pods Frameworks"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 331C807D294A63A400263BE5 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 331C8086294A63A400263BE5 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 97C146ED1CF9000F007C117D /* Runner */; + targetProxy = 331C8085294A63A400263BE5 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Profile; + }; + 249021D4217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = K2CV557XCP; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.journeyapps.trelloappcloneFlutter; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 331C8088294A63A400263BE5 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = A2E15785CC927C31AEF6BC6A /* Pods-RunnerTests.debug.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.trelloappcloneFlutter.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; + }; + name = Debug; + }; + 331C8089294A63A400263BE5 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = B0E8CE81B52F70CDF2A4F80B /* Pods-RunnerTests.release.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.trelloappcloneFlutter.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; + }; + name = Release; + }; + 331C808A294A63A400263BE5 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 976B259CF18C36EB3B6F4F0F /* Pods-RunnerTests.profile.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.trelloappcloneFlutter.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 97C147061CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = K2CV557XCP; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.journeyapps.trelloappcloneFlutter; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Debug; + }; + 97C147071CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = K2CV557XCP; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.journeyapps.trelloappcloneFlutter; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 331C8088294A63A400263BE5 /* Debug */, + 331C8089294A63A400263BE5 /* Release */, + 331C808A294A63A400263BE5 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/demos/supabase-trello/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/demos/supabase-trello/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 00000000..919434a6 --- /dev/null +++ b/demos/supabase-trello/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/demos/supabase-trello/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/demos/supabase-trello/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 00000000..18d98100 --- /dev/null +++ b/demos/supabase-trello/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/demos/supabase-trello/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/demos/supabase-trello/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 00000000..f9b0d7c5 --- /dev/null +++ b/demos/supabase-trello/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + diff --git a/demos/supabase-trello/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/demos/supabase-trello/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme new file mode 100644 index 00000000..8e3ca5df --- /dev/null +++ b/demos/supabase-trello/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,98 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/demos/supabase-trello/ios/Runner.xcworkspace/contents.xcworkspacedata b/demos/supabase-trello/ios/Runner.xcworkspace/contents.xcworkspacedata new file mode 100644 index 00000000..21a3cc14 --- /dev/null +++ b/demos/supabase-trello/ios/Runner.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/demos/supabase-trello/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/demos/supabase-trello/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 00000000..18d98100 --- /dev/null +++ b/demos/supabase-trello/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/demos/supabase-trello/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/demos/supabase-trello/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 00000000..f9b0d7c5 --- /dev/null +++ b/demos/supabase-trello/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + diff --git a/demos/supabase-trello/ios/Runner/AppDelegate.swift b/demos/supabase-trello/ios/Runner/AppDelegate.swift new file mode 100644 index 00000000..70693e4a --- /dev/null +++ b/demos/supabase-trello/ios/Runner/AppDelegate.swift @@ -0,0 +1,13 @@ +import UIKit +import Flutter + +@UIApplicationMain +@objc class AppDelegate: FlutterAppDelegate { + override func application( + _ application: UIApplication, + didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? + ) -> Bool { + GeneratedPluginRegistrant.register(with: self) + return super.application(application, didFinishLaunchingWithOptions: launchOptions) + } +} diff --git a/demos/supabase-trello/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/demos/supabase-trello/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 00000000..d36b1fab --- /dev/null +++ b/demos/supabase-trello/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,122 @@ +{ + "images" : [ + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "Icon-App-20x20@2x.png", + "scale" : "2x" + }, + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "Icon-App-20x20@3x.png", + "scale" : "3x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@1x.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@2x.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@3x.png", + "scale" : "3x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "Icon-App-40x40@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "Icon-App-40x40@3x.png", + "scale" : "3x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "Icon-App-60x60@2x.png", + "scale" : "2x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "Icon-App-60x60@3x.png", + "scale" : "3x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "Icon-App-20x20@1x.png", + "scale" : "1x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "Icon-App-20x20@2x.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "Icon-App-29x29@1x.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "Icon-App-29x29@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "Icon-App-40x40@1x.png", + "scale" : "1x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "Icon-App-40x40@2x.png", + "scale" : "2x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "Icon-App-76x76@1x.png", + "scale" : "1x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "Icon-App-76x76@2x.png", + "scale" : "2x" + }, + { + "size" : "83.5x83.5", + "idiom" : "ipad", + "filename" : "Icon-App-83.5x83.5@2x.png", + "scale" : "2x" + }, + { + "size" : "1024x1024", + "idiom" : "ios-marketing", + "filename" : "Icon-App-1024x1024@1x.png", + "scale" : "1x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/demos/supabase-trello/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/demos/supabase-trello/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png new file mode 100644 index 0000000000000000000000000000000000000000..dc9ada4725e9b0ddb1deab583e5b5102493aa332 GIT binary patch literal 10932 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 literal 0 HcmV?d00001 diff --git a/demos/supabase-trello/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/demos/supabase-trello/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..797d452e458972bab9d994556c8305db4c827017 GIT binary patch literal 406 zcmV;H0crk;P))>cdjpWt&rLJgVp-t?DREyuq1A%0Z4)6_WsQ7{nzjN zo!X zGXV)2i3kcZIL~_j>uIKPK_zib+3T+Nt3Mb&Br)s)UIaA}@p{wDda>7=Q|mGRp7pqY zkJ!7E{MNz$9nOwoVqpFb)}$IP24Wn2JJ=Cw(!`OXJBr45rP>>AQr$6c7slJWvbpNW z@KTwna6d?PP>hvXCcp=4F;=GR@R4E7{4VU^0p4F>v^#A|>07*qoM6N<$f*5nx ACIA2c literal 0 HcmV?d00001 diff --git a/demos/supabase-trello/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/demos/supabase-trello/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..6ed2d933e1120817fe9182483a228007b18ab6ae GIT binary patch literal 450 zcmV;z0X_bSP)iGWQ_5NJQ_~rNh*z)}eT%KUb z`7gNk0#AwF^#0T0?hIa^`~Ck;!}#m+_uT050aTR(J!bU#|IzRL%^UsMS#KsYnTF*!YeDOytlP4VhV?b} z%rz_<=#CPc)tU1MZTq~*2=8~iZ!lSa<{9b@2Jl;?IEV8)=fG217*|@)CCYgFze-x? zIFODUIA>nWKpE+bn~n7;-89sa>#DR>TSlqWk*!2hSN6D~Qb#VqbP~4Fk&m`@1$JGr zXPIdeRE&b2Thd#{MtDK$px*d3-Wx``>!oimf%|A-&-q*6KAH)e$3|6JV%HX{Hig)k suLT-RhftRq8b9;(V=235Wa|I=027H2wCDra;{X5v07*qoM6N<$f;9x^2LJ#7 literal 0 HcmV?d00001 diff --git a/demos/supabase-trello/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/demos/supabase-trello/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png new file mode 100644 index 0000000000000000000000000000000000000000..4cd7b0099ca80c806f8fe495613e8d6c69460d76 GIT binary patch literal 282 zcmV+#0p(^bcu7P-R4C8Q z&e;xxFbF_Vrezo%_kH*OKhshZ6BFpG-Y1e10`QXJKbND7AMQ&cMj60B5TNObaZxYybcN07*qoM6N<$g3m;S%K!iX literal 0 HcmV?d00001 diff --git a/demos/supabase-trello/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/demos/supabase-trello/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..fe730945a01f64a61e2235dbe3f45b08f7729182 GIT binary patch literal 462 zcmV;<0WtoGP)-}iV`2<;=$?g5M=KQbZ{F&YRNy7Nn@%_*5{gvDM0aKI4?ESmw z{NnZg)A0R`+4?NF_RZexyVB&^^ZvN!{I28tr{Vje;QNTz`dG&Jz0~Ek&f2;*Z7>B|cg}xYpxEFY+0YrKLF;^Q+-HreN0P{&i zK~zY`?b7ECf-n?@;d<&orQ*Q7KoR%4|C>{W^h6@&01>0SKS`dn{Q}GT%Qj_{PLZ_& zs`MFI#j-(>?bvdZ!8^xTwlY{qA)T4QLbY@j(!YJ7aXJervHy6HaG_2SB`6CC{He}f zHVw(fJWApwPq!6VY7r1w-Fs)@ox~N+q|w~e;JI~C4Vf^@d>Wvj=fl`^u9x9wd9 zR%3*Q+)t%S!MU_`id^@&Y{y7-r98lZX0?YrHlfmwb?#}^1b{8g&KzmkE(L>Z&)179 zp<)v6Y}pRl100G2FL_t(o!|l{-Q-VMg#&MKg7c{O0 z2wJImOS3Gy*Z2Qifdv~JYOp;v+U)a|nLoc7hNH;I$;lzDt$}rkaFw1mYK5_0Q(Sut zvbEloxON7$+HSOgC9Z8ltuC&0OSF!-mXv5caV>#bc3@hBPX@I$58-z}(ZZE!t-aOG zpjNkbau@>yEzH(5Yj4kZiMH32XI!4~gVXNnjAvRx;Sdg^`>2DpUEwoMhTs_st8pKG z(%SHyHdU&v%f36~uERh!bd`!T2dw;z6PrOTQ7Vt*#9F2uHlUVnb#ev_o^fh}Dzmq} zWtlk35}k=?xj28uO|5>>$yXadTUE@@IPpgH`gJ~Ro4>jd1IF|(+IX>8M4Ps{PNvmI zNj4D+XgN83gPt_Gm}`Ybv{;+&yu-C(Grdiahmo~BjG-l&mWM+{e5M1sm&=xduwgM9 z`8OEh`=F3r`^E{n_;%9weN{cf2%7=VzC@cYj+lg>+3|D|_1C@{hcU(DyQG_BvBWe? zvTv``=%b1zrol#=R`JB)>cdjpWt&rLJgVp-t?DREyuq1A%0Z4)6_WsQ7{nzjN zo!X zGXV)2i3kcZIL~_j>uIKPK_zib+3T+Nt3Mb&Br)s)UIaA}@p{wDda>7=Q|mGRp7pqY zkJ!7E{MNz$9nOwoVqpFb)}$IP24Wn2JJ=Cw(!`OXJBr45rP>>AQr$6c7slJWvbpNW z@KTwna6d?PP>hvXCcp=4F;=GR@R4E7{4VU^0p4F>v^#A|>07*qoM6N<$f*5nx ACIA2c literal 0 HcmV?d00001 diff --git a/demos/supabase-trello/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/demos/supabase-trello/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..502f463a9bc882b461c96aadf492d1729e49e725 GIT binary patch literal 586 zcmV-Q0=4~#P)+}#`wDE{8-2Mebf5<{{PqV{TgVcv*r8?UZ3{-|G?_}T*&y;@cqf{ z{Q*~+qr%%p!1pS*_Uicl#q9lc(D`!D`LN62sNwq{oYw(Wmhk)k<@f$!$@ng~_5)Ru z0Z)trIA5^j{DIW^c+vT2%lW+2<(RtE2wR;4O@)Tm`Xr*?A(qYoM}7i5Yxw>D(&6ou zxz!_Xr~yNF+waPe00049Nkl*;a!v6h%{rlvIH#gW3s8p;bFr=l}mRqpW2h zw=OA%hdyL~z+UHOzl0eKhEr$YYOL-c-%Y<)=j?(bzDweB7{b+%_ypvm_cG{SvM=DK zhv{K@m>#Bw>2W$eUI#iU)Wdgs8Y3U+A$Gd&{+j)d)BmGKx+43U_!tik_YlN)>$7G! zhkE!s;%oku3;IwG3U^2kw?z+HM)jB{@zFhK8P#KMSytSthr+4!c(5c%+^UBn`0X*2 zy3(k600_CSZj?O$Qu%&$;|TGUJrptR(HzyIx>5E(2r{eA(<6t3e3I0B)7d6s7?Z5J zZ!rtKvA{MiEBm&KFtoifx>5P^Z=vl)95XJn()aS5%ad(s?4-=Tkis9IGu{`Fy8r+H07*qoM6N<$f20Z)wqMt%V?S?~D#06};F zA3KcL`Wb+>5ObvgQIG&ig8(;V04hz?@cqy3{mSh8o!|U|)cI!1_+!fWH@o*8vh^CU z^ws0;(c$gI+2~q^tO#GDHf@=;DncUw00J^eL_t(&-tE|HQ`%4vfZ;WsBqu-$0nu1R zq^Vj;p$clf^?twn|KHO+IGt^q#a3X?w9dXC@*yxhv&l}F322(8Y1&=P&I}~G@#h6; z1CV9ecD9ZEe87{{NtI*)_aJ<`kJa z?5=RBtFF50s;jQLFil-`)m2wrb=6h(&brpj%nG_U&ut~$?8Rokzxi8zJoWr#2dto5 zOX_URcc<1`Iky+jc;A%Vzx}1QU{2$|cKPom2Vf1{8m`vja4{F>HS?^Nc^rp}xo+Nh zxd}eOm`fm3@MQC1< zIk&aCjb~Yh%5+Yq0`)D;q{#-Uqlv*o+Oor zE!I71Z@ASH3grl8&P^L0WpavHoP|UX4e?!igT`4?AZk$hu*@%6WJ;zDOGlw7kj@ zY5!B-0ft0f?Lgb>C;$Ke07*qoM6N<$f~t1N9smFU literal 0 HcmV?d00001 diff --git a/demos/supabase-trello/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/demos/supabase-trello/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..0ec303439225b78712f49115768196d8d76f6790 GIT binary patch literal 862 zcmV-k1EKthP)20Z)wqMt%V?S?~D#06};F zA3KcL`Wb+>5ObvgQIG&ig8(;V04hz?@cqy3{mSh8o!|U|)cI!1_+!fWH@o*8vh^CU z^ws0;(c$gI+2~q^tO#GDHf@=;DncUw00J^eL_t(&-tE|HQ`%4vfZ;WsBqu-$0nu1R zq^Vj;p$clf^?twn|KHO+IGt^q#a3X?w9dXC@*yxhv&l}F322(8Y1&=P&I}~G@#h6; z1CV9ecD9ZEe87{{NtI*)_aJ<`kJa z?5=RBtFF50s;jQLFil-`)m2wrb=6h(&brpj%nG_U&ut~$?8Rokzxi8zJoWr#2dto5 zOX_URcc<1`Iky+jc;A%Vzx}1QU{2$|cKPom2Vf1{8m`vja4{F>HS?^Nc^rp}xo+Nh zxd}eOm`fm3@MQC1< zIk&aCjb~Yh%5+Yq0`)D;q{#-Uqlv*o+Oor zE!I71Z@ASH3grl8&P^L0WpavHoP|UX4e?!igT`4?AZk$hu*@%6WJ;zDOGlw7kj@ zY5!B-0ft0f?Lgb>C;$Ke07*qoM6N<$f~t1N9smFU literal 0 HcmV?d00001 diff --git a/demos/supabase-trello/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/demos/supabase-trello/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..e9f5fea27c705180eb716271f41b582e76dcbd90 GIT binary patch literal 1674 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 literal 0 HcmV?d00001 diff --git a/demos/supabase-trello/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/demos/supabase-trello/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..0467bf12aa4d28f374bb26596605a46dcbb3e7c8 GIT binary patch literal 1418 zcmV;51$Fv~P)q zKfU)WzW*n(@|xWGCA9ScMt*e9`2kdxPQ&&>|-UCa7_51w+ zLUsW@ZzZSW0y$)Hp~e9%PvP|a03ks1`~K?q{u;6NC8*{AOqIUq{CL&;p56Lf$oQGq z^={4hPQv)y=I|4n+?>7Fim=dxt1 z2H+Dm+1+fh+IF>G0SjJMkQQre1x4|G*Z==(Ot&kCnUrL4I(rf(ucITwmuHf^hXiJT zkdTm&kdTm&kdTm&kdP`esgWG0BcWCVkVZ&2dUwN`cgM8QJb`Z7Z~e<&Yj2(}>Tmf` zm1{eLgw!b{bXkjWbF%dTkTZEJWyWOb##Lfw4EK2}<0d6%>AGS{po>WCOy&f$Tay_> z?NBlkpo@s-O;0V%Y_Xa-G#_O08q5LR*~F%&)}{}r&L%Sbs8AS4t7Y0NEx*{soY=0MZExqA5XHQkqi#4gW3 zqODM^iyZl;dvf)-bOXtOru(s)Uc7~BFx{w-FK;2{`VA?(g&@3z&bfLFyctOH!cVsF z7IL=fo-qBndRUm;kAdXR4e6>k-z|21AaN%ubeVrHl*<|s&Ax@W-t?LR(P-24A5=>a z*R9#QvjzF8n%@1Nw@?CG@6(%>+-0ASK~jEmCV|&a*7-GKT72W<(TbSjf)&Eme6nGE z>Gkj4Sq&2e+-G%|+NM8OOm5zVl9{Z8Dd8A5z3y8mZ=4Bv4%>as_{9cN#bm~;h>62( zdqY93Zy}v&c4n($Vv!UybR8ocs7#zbfX1IY-*w~)p}XyZ-SFC~4w>BvMVr`dFbelV{lLL0bx7@*ZZdebr3`sP;? zVImji)kG)(6Juv0lz@q`F!k1FE;CQ(D0iG$wchPbKZQELlsZ#~rt8#90Y_Xh&3U-< z{s<&cCV_1`^TD^ia9!*mQDq& zn2{r`j};V|uV%_wsP!zB?m%;FeaRe+X47K0e+KE!8C{gAWF8)lCd1u1%~|M!XNRvw zvtqy3iz0WSpWdhn6$hP8PaRBmp)q`#PCA`Vd#Tc$@f1tAcM>f_I@bC)hkI9|o(Iqv zo}Piadq!j76}004RBio<`)70k^`K1NK)q>w?p^C6J2ZC!+UppiK6&y3Kmbv&O!oYF z34$0Z;QO!JOY#!`qyGH<3Pd}Pt@q*A0V=3SVtWKRR8d8Z&@)3qLPA19LPA19LPEUC YUoZo%k(ykuW&i*H07*qoM6N<$f+CH{y8r+H literal 0 HcmV?d00001 diff --git a/demos/supabase-trello/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json b/demos/supabase-trello/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json new file mode 100644 index 00000000..0bedcf2f --- /dev/null +++ b/demos/supabase-trello/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/demos/supabase-trello/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png b/demos/supabase-trello/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png new file mode 100644 index 0000000000000000000000000000000000000000..9da19eacad3b03bb08bbddbbf4ac48dd78b3d838 GIT binary patch literal 68 zcmeAS@N?(olHy`uVBq!ia0vp^j3CUx0wlM}@Gt=>Zci7-kcv6Uzs@r-FtIZ-&5|)J Q1PU{Fy85}Sb4q9e0B4a5jsO4v literal 0 HcmV?d00001 diff --git a/demos/supabase-trello/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png b/demos/supabase-trello/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..9da19eacad3b03bb08bbddbbf4ac48dd78b3d838 GIT binary patch literal 68 zcmeAS@N?(olHy`uVBq!ia0vp^j3CUx0wlM}@Gt=>Zci7-kcv6Uzs@r-FtIZ-&5|)J Q1PU{Fy85}Sb4q9e0B4a5jsO4v literal 0 HcmV?d00001 diff --git a/demos/supabase-trello/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png b/demos/supabase-trello/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..9da19eacad3b03bb08bbddbbf4ac48dd78b3d838 GIT binary patch literal 68 zcmeAS@N?(olHy`uVBq!ia0vp^j3CUx0wlM}@Gt=>Zci7-kcv6Uzs@r-FtIZ-&5|)J Q1PU{Fy85}Sb4q9e0B4a5jsO4v literal 0 HcmV?d00001 diff --git a/demos/supabase-trello/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md b/demos/supabase-trello/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md new file mode 100644 index 00000000..89c2725b --- /dev/null +++ b/demos/supabase-trello/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md @@ -0,0 +1,5 @@ +# Launch Screen Assets + +You can customize the launch screen with your own desired assets by replacing the image files in this directory. + +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. \ No newline at end of file diff --git a/demos/supabase-trello/ios/Runner/Base.lproj/LaunchScreen.storyboard b/demos/supabase-trello/ios/Runner/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 00000000..f2e259c7 --- /dev/null +++ b/demos/supabase-trello/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/demos/supabase-trello/ios/Runner/Base.lproj/Main.storyboard b/demos/supabase-trello/ios/Runner/Base.lproj/Main.storyboard new file mode 100644 index 00000000..f3c28516 --- /dev/null +++ b/demos/supabase-trello/ios/Runner/Base.lproj/Main.storyboard @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/demos/supabase-trello/ios/Runner/Info.plist b/demos/supabase-trello/ios/Runner/Info.plist new file mode 100644 index 00000000..22057481 --- /dev/null +++ b/demos/supabase-trello/ios/Runner/Info.plist @@ -0,0 +1,51 @@ + + + + + CADisableMinimumFrameDurationOnPhone + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleDisplayName + Trelloappclone Flutter + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + trelloappclone_flutter + CFBundlePackageType + APPL + CFBundleShortVersionString + $(FLUTTER_BUILD_NAME) + CFBundleSignature + ???? + CFBundleVersion + $(FLUTTER_BUILD_NUMBER) + LSRequiresIPhoneOS + + UIApplicationSupportsIndirectInputEvents + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UIViewControllerBasedStatusBarAppearance + + + diff --git a/demos/supabase-trello/ios/Runner/Runner-Bridging-Header.h b/demos/supabase-trello/ios/Runner/Runner-Bridging-Header.h new file mode 100644 index 00000000..308a2a56 --- /dev/null +++ b/demos/supabase-trello/ios/Runner/Runner-Bridging-Header.h @@ -0,0 +1 @@ +#import "GeneratedPluginRegistrant.h" diff --git a/demos/supabase-trello/ios/RunnerTests/RunnerTests.swift b/demos/supabase-trello/ios/RunnerTests/RunnerTests.swift new file mode 100644 index 00000000..86a7c3b1 --- /dev/null +++ b/demos/supabase-trello/ios/RunnerTests/RunnerTests.swift @@ -0,0 +1,12 @@ +import Flutter +import UIKit +import XCTest + +class RunnerTests: XCTestCase { + + func testExample() { + // If you add code to the Runner application, consider adding tests here. + // See https://developer.apple.com/documentation/xctest for more information about using XCTest. + } + +} diff --git a/demos/supabase-trello/lib/features/aboutboard/presentation/index.dart b/demos/supabase-trello/lib/features/aboutboard/presentation/index.dart new file mode 100644 index 00000000..4f089aea --- /dev/null +++ b/demos/supabase-trello/lib/features/aboutboard/presentation/index.dart @@ -0,0 +1,43 @@ +import 'package:flutter/material.dart'; +import 'package:trelloappclone_flutter/utils/constant.dart'; + +class AboutBoard extends StatefulWidget { + const AboutBoard({super.key}); + + @override + State createState() => _AboutBoardState(); +} + +class _AboutBoardState extends State { + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: const Text("About this board"), + centerTitle: false, + ), + body: const Padding( + padding: EdgeInsets.all(20.0), + child: Column(children: [ + Text( + "Made by", + style: TextStyle(fontWeight: FontWeight.w600), + ), + ListTile( + leading: CircleAvatar(), + title: Text("Jane Doe"), + subtitle: Text("@janedoe"), + ), + Text( + "Description", + style: TextStyle(fontWeight: FontWeight.w600), + ), + Padding( + padding: EdgeInsets.only(top: 10.0), + child: Text(defaultDescription), + ) + ]), + ), + ); + } +} diff --git a/demos/supabase-trello/lib/features/activity/presentation/index.dart b/demos/supabase-trello/lib/features/activity/presentation/index.dart new file mode 100644 index 00000000..6a15a08c --- /dev/null +++ b/demos/supabase-trello/lib/features/activity/presentation/index.dart @@ -0,0 +1,67 @@ +import 'package:flutter/material.dart'; +import 'package:trelloappclone_flutter/utils/color.dart'; +import 'package:trelloappclone_flutter/models/activity.dart'; +import 'package:trelloappclone_flutter/models/card.dart'; + +import '../../../utils/service.dart'; + +class Activities extends StatefulWidget { + final Cardlist crd; + const Activities(this.crd, {super.key}); + + @override + State createState() => _ActivitiesState(); +} + +class _ActivitiesState extends State with Service { + List activities = []; + + @override + Widget build(BuildContext context) { + return FutureBuilder( + initialData: activities, + future: getActivities(widget.crd), + builder: + (BuildContext context, AsyncSnapshot> snapshot) { + if (snapshot.hasData) { + List children = snapshot.data as List; + + if (children.isNotEmpty) { + return ListView( + shrinkWrap: true, children: buildWidget(children)); + } + } + return const SizedBox.shrink(); + }); + } + + List buildWidget(List activities) { + List tiles = []; + + for (int i = 0; i < activities.length; i++) { + tiles.add(ActivityTile(activity: activities[i].description)); + } + return tiles; + } +} + +class ActivityTile extends StatefulWidget { + final String activity; + const ActivityTile({required this.activity, super.key}); + + @override + State createState() => _ActivityTileState(); +} + +class _ActivityTileState extends State { + @override + Widget build(BuildContext context) { + return ListTile( + leading: const CircleAvatar( + backgroundColor: brandColor, + ), + title: Text(widget.activity), + subtitle: const Text("01 Jan 2023 at 1:11 am"), + ); + } +} diff --git a/demos/supabase-trello/lib/features/archivedcards/presentation/index.dart b/demos/supabase-trello/lib/features/archivedcards/presentation/index.dart new file mode 100644 index 00000000..5702546d --- /dev/null +++ b/demos/supabase-trello/lib/features/archivedcards/presentation/index.dart @@ -0,0 +1,49 @@ +import 'package:flutter/material.dart'; + +import '../../../utils/color.dart'; + +class ArchivedCards extends StatefulWidget { + const ArchivedCards({super.key}); + + @override + State createState() => _ArchivedCardsState(); +} + +class _ArchivedCardsState extends State { + bool select = false; + int selected = 0; + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + leading: (select) + ? IconButton( + onPressed: () {}, + icon: const Icon( + Icons.close, + size: 30, + ), + ) + : null, + title: Text((select) ? "&selected selected" : "Archived cards"), + centerTitle: false, + actions: [ + (select) + ? TextButton( + onPressed: () {}, + child: const Text( + "SEND TO BOARD", + style: TextStyle(color: whiteShade), + )) + : IconButton( + onPressed: () {}, + icon: const Icon(Icons.check_circle_outline)) + ], + ), + body: const Center( + child: Text("No archived cards"), + ), + ); + } +} diff --git a/demos/supabase-trello/lib/features/archivedlists/presentation/index.dart b/demos/supabase-trello/lib/features/archivedlists/presentation/index.dart new file mode 100644 index 00000000..76f5181c --- /dev/null +++ b/demos/supabase-trello/lib/features/archivedlists/presentation/index.dart @@ -0,0 +1,48 @@ +import 'package:flutter/material.dart'; +import 'package:trelloappclone_flutter/utils/color.dart'; + +class ArchivedLists extends StatefulWidget { + const ArchivedLists({super.key}); + + @override + State createState() => _ArchivedListsState(); +} + +class _ArchivedListsState extends State { + bool select = false; + int selected = 0; + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + leading: (select) + ? IconButton( + onPressed: () {}, + icon: const Icon( + Icons.close, + size: 30, + ), + ) + : null, + title: Text((select) ? "&selected selected" : "Archived lists"), + centerTitle: false, + actions: [ + (select) + ? TextButton( + onPressed: () {}, + child: const Text( + "SEND TO BOARD", + style: TextStyle(color: whiteShade), + )) + : IconButton( + onPressed: () {}, + icon: const Icon(Icons.check_circle_outline)) + ], + ), + body: const Center( + child: Text("No archived lists"), + ), + ); + } +} diff --git a/demos/supabase-trello/lib/features/board/domain/board_arguments.dart b/demos/supabase-trello/lib/features/board/domain/board_arguments.dart new file mode 100644 index 00000000..7b7720d5 --- /dev/null +++ b/demos/supabase-trello/lib/features/board/domain/board_arguments.dart @@ -0,0 +1,9 @@ +import 'package:trelloappclone_flutter/models/board.dart'; +import 'package:trelloappclone_flutter/models/workspace.dart'; + +class BoardArguments { + final Board board; + final Workspace workspace; + + BoardArguments(this.board, this.workspace); +} diff --git a/demos/supabase-trello/lib/features/board/presentation/boarditemobject.dart b/demos/supabase-trello/lib/features/board/presentation/boarditemobject.dart new file mode 100644 index 00000000..62f5b5b4 --- /dev/null +++ b/demos/supabase-trello/lib/features/board/presentation/boarditemobject.dart @@ -0,0 +1,13 @@ +import 'package:trelloappclone_flutter/models/card_label.dart'; + +class BoardItemObject { + String? title; + bool? hasDescription; + List? cardLabels; + + BoardItemObject({this.title, this.hasDescription, this.cardLabels}) { + title ??= ""; + hasDescription ??= false; + cardLabels ??= []; + } +} diff --git a/demos/supabase-trello/lib/features/board/presentation/boardlistobject.dart b/demos/supabase-trello/lib/features/board/presentation/boardlistobject.dart new file mode 100644 index 00000000..0b19b482 --- /dev/null +++ b/demos/supabase-trello/lib/features/board/presentation/boardlistobject.dart @@ -0,0 +1,13 @@ +import 'boarditemobject.dart'; + +class BoardListObject { + String? title; + String? listId; + List? items; + + BoardListObject({this.title, this.listId, this.items}) { + listId ??="0"; + title ??= ""; + items ??= []; + } +} diff --git a/demos/supabase-trello/lib/features/board/presentation/index.dart b/demos/supabase-trello/lib/features/board/presentation/index.dart new file mode 100644 index 00000000..b71b38a8 --- /dev/null +++ b/demos/supabase-trello/lib/features/board/presentation/index.dart @@ -0,0 +1,471 @@ +import 'dart:ffi'; + +import 'package:flutter/material.dart'; +import 'package:status_alert/status_alert.dart'; +import 'package:trelloappclone_flutter/features/carddetails/domain/card_detail_arguments.dart'; +import 'package:trelloappclone_flutter/features/carddetails/presentation/index.dart'; +import 'package:trelloappclone_flutter/utils/color.dart'; +import 'package:trelloappclone_flutter/widgets/thirdparty/board_item.dart'; +import 'package:trelloappclone_flutter/widgets/thirdparty/board_list.dart'; +import 'package:trelloappclone_flutter/widgets/thirdparty/boardview.dart'; +import 'package:trelloappclone_flutter/widgets/thirdparty/boardview_controller.dart'; +import 'package:trelloappclone_flutter/models/listboard.dart'; +import 'package:trelloappclone_flutter/models/card.dart'; + +import '../../../main.dart'; +import '../../../utils/config.dart'; +import '../../../utils/service.dart'; +import '../../../utils/widgets.dart'; +import '../domain/board_arguments.dart'; +import 'boarditemobject.dart'; +import 'boardlistobject.dart'; + +class BoardScreen extends StatefulWidget { + const BoardScreen({super.key}); + + @override + State createState() => _BoardScreenState(); + + static const routeName = '/board'; +} + +class _BoardScreenState extends State with Service { + BoardViewController boardViewController = BoardViewController(); + bool showCard = false; + bool show = false; + List lists = []; + final TextEditingController nameController = TextEditingController(); + Map textEditingControllers = {}; + Map showtheCard = {}; + int selectedList = 0; + int selectedCard = 0; + late double width; + + @override + Widget build(BuildContext context) { + width = MediaQuery.of(context).size.width * 0.7; + final args = ModalRoute.of(context)!.settings.arguments as BoardArguments; + trello.setSelectedBoard(args.board); + trello.setSelectedWorkspace(args.workspace); + + return WillPopScope( + onWillPop: () async { + Navigator.pushNamed(context, "/home"); + return false; + }, + child: Scaffold( + appBar: (!show && !showCard) + ? AppBar( + backgroundColor: brandColor, + centerTitle: false, + title: Text(args.board.name), + actions: [ + IconButton( + onPressed: () { + Navigator.pushNamed(context, '/boardmenu'); + }, + icon: const Icon(Icons.more_horiz)) + ], + ) + : AppBar( + leading: IconButton( + onPressed: () { + setState(() { + nameController.clear(); + textEditingControllers[selectedList]!.clear(); + show = false; + showCard = false; + showtheCard[selectedCard] = false; + }); + }, + icon: const Icon(Icons.close)), + title: Text((show) ? "Add list" : "Add card"), + centerTitle: false, + actions: [ + IconButton( + onPressed: () { + if (show) { + addList(Listboard( + id: randomUuid(), + workspaceId: args.workspace.id, + boardId: args.board.id, + userId: trello.user.id, + name: nameController.text, + order: trello.lstbrd.length)); + nameController.clear(); + setState(() { + show = false; + }); + } else { + addCard(Cardlist( + id: randomUuid(), + workspaceId: args.workspace.id, + listId: trello.lstbrd[selectedList].id, + userId: trello.user.id, + name: + textEditingControllers[selectedList]!.text, + rank: + trello.lstbrd[selectedList].cards!.length)); + textEditingControllers[selectedList]!.clear(); + setState(() { + showCard = false; + showtheCard[selectedCard] = false; + }); + } + }, + icon: const Icon(Icons.check)) + ], + ), + body: Padding( + padding: const EdgeInsets.all(10.0), + child: StreamBuilder( + stream: getListsByBoardStream(args.board), + builder: (BuildContext context, + AsyncSnapshot> snapshot) { + if (snapshot.hasData) { + List listBoards = + snapshot.data as List; + return BoardView( + lists: loadBoardView(listBoards), + boardViewController: boardViewController, + ); + } + return const SizedBox.shrink(); + })), + )); + } + + Widget buildBoardItem( + BoardItemObject itemObject, List data) { + return BoardItem( + onStartDragItem: (listIndex, itemIndex, state) {}, + onDropItem: (listIndex, itemIndex, oldListIndex, oldItemIndex, state) { + // if listIndex is null, then item was dropped outside of list reset the state + if (listIndex == null) { + return; + } + + if (itemIndex == null || itemIndex > data[listIndex].items!.length) { + return; + } + + // Move item to new list + var item = data[oldListIndex!].items?[oldItemIndex!]; + data[oldListIndex].items!.removeAt(oldItemIndex!); + data[listIndex].items!.insert(itemIndex, item!); + + var card = trello.lstbrd[oldListIndex].cards![oldItemIndex]; + + // update card listId + card.listId = trello.lstbrd[listIndex].id; + updateCard(card); + + trello.lstbrd[oldListIndex].cards!.removeAt(oldItemIndex); + trello.lstbrd[listIndex].cards!.insert(itemIndex, card); + + // reset rank based on index + trello.lstbrd[listIndex].cards!.asMap().forEach((index, card) { + card.rank = index; + updateCard(card); + }); + }, + onTapItem: (listIndex, itemIndex, state) { + Navigator.pushNamed(context, CardDetails.routeName, + arguments: CardDetailArguments( + trello.lstbrd[listIndex].cards![itemIndex], + trello.selectedBoard, + trello.lstbrd[listIndex])) + .then((value) => setState(() {})); + }, + item: Card( + color: Colors.white, + elevation: 0, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(10.0), + ), + child: Column(children: [ + Padding( + padding: const EdgeInsets.fromLTRB(10, 8, 8, 8), + child: Align( + alignment: Alignment.centerLeft, + child: Text( + itemObject.title!, + ), + ), + ), + Wrap( + children: [ + // Add a horizontal space + const SizedBox(width: 0), + // Example labels with colored Chips + ...itemObject.cardLabels!.map((cardLabel) => Padding( + padding: const EdgeInsets.symmetric( + horizontal: 4, vertical: 2), // Horizontal margin + child: LabelDiplay( + color: trello.selectedBoard.boardLabels! + .firstWhere((boardLabel) => + boardLabel.id == cardLabel.boardLabelId) + .color, + label: trello.selectedBoard.boardLabels! + .firstWhere((boardLabel) => + boardLabel.id == cardLabel.boardLabelId) + .title))), + ], + ), + //Add icon to the column if card has description + if (itemObject.hasDescription!) + const Padding( + padding: EdgeInsets.fromLTRB(8, 2, 8, 8), + child: Align( + alignment: Alignment.centerLeft, + child: Icon(Icons.description, size: 16), + ), + ), + ]))); + } + + Widget _createBoardList( + BoardListObject list, List data, int index) { + List items = []; + for (int i = 0; i < list.items!.length; i++) { + items.insert(i, buildBoardItem(list.items![i], data) as BoardItem); + } + + textEditingControllers.putIfAbsent(index, () => TextEditingController()); + showtheCard.putIfAbsent(index, () => false); + + items.insert( + list.items!.length, + BoardItem( + onTapItem: (listIndex, itemIndex, state) { + setState(() { + selectedList = listIndex!; + selectedCard = index; + showCard = true; + showtheCard[index] = true; + }); + }, + item: (!showtheCard[index]!) + ? ListTile( + leading: const Text.rich(TextSpan( + children: [ + WidgetSpan( + child: Icon( + Icons.add, + size: 19, + color: whiteShade, + )), + WidgetSpan( + child: SizedBox( + width: 5, + ), + ), + TextSpan( + text: "Add card", + style: TextStyle(color: whiteShade)), + ], + )), + trailing: IconButton( + icon: const Icon( + Icons.image, + color: whiteShade, + ), + onPressed: () {}, + ), + ) + : Padding( + padding: const EdgeInsets.all(10.0), + child: TextField( + controller: textEditingControllers[index], + decoration: const InputDecoration(hintText: "Card name"), + ), + ), + )); + + return BoardList( + onStartDragList: (listIndex) {}, + onTapList: (listIndex) async {}, + onDropList: (listIndex, oldListIndex) { + var tmpList = data[oldListIndex!]; + + data.removeAt(oldListIndex); + data.insert(listIndex!, tmpList); + + updateListOrder(tmpList.listId!, listIndex); + + var movedList = trello.lstbrd[oldListIndex]; + + trello.lstbrd.removeAt(oldListIndex); + trello.lstbrd.insert(listIndex, movedList); + + // reset rank based on index + trello.lstbrd.asMap().forEach((index, list) { + updateListOrder(list.id, index); + }); + }, + headerBackgroundColor: brandColor, + backgroundColor: brandColor, + header: [ + Expanded( + child: Padding( + padding: const EdgeInsets.all(5), + child: ListTile( + leading: SizedBox( + width: 180, + child: Text( + overflow: TextOverflow.ellipsis, + softWrap: false, + maxLines: 2, + list.title!, + style: const TextStyle( + fontSize: 16, fontWeight: FontWeight.w500), + ), + ), + trailing: PopupMenuButton( + child: const Icon(Icons.more_vert), + itemBuilder: (BuildContext context) => + >[ + PopupMenuItem( + child: ListTile( + enabled: false, + title: Text(listMenu[1]), + ), + ), + PopupMenuItem( + child: ListTile( + enabled: false, + title: Text(listMenu[2]), + ), + ), + PopupMenuItem( + child: ListTile( + enabled: false, + title: Text(listMenu[3]), + ), + ), + const PopupMenuItem( + child: Divider( + height: 1, + thickness: 1, + )), + PopupMenuItem( + child: ListTile( + enabled: false, + title: Text(listMenu[4]), + trailing: + const Icon(Icons.keyboard_arrow_right), + ), + ), + const PopupMenuItem( + child: Divider( + height: 1, + thickness: 1, + )), + PopupMenuItem( + child: ListTile( + enabled: false, + title: Text(listMenu[5]), + ), + ), + PopupMenuItem( + child: ListTile( + title: Text(listMenu[6]), + onTap: () { + archiveCardsInList(trello.lstbrd[index]) + .then((numCardsArchived) { + StatusAlert.show(context, + duration: const Duration(seconds: 2), + title: + '$numCardsArchived Cards Archived', + configuration: const IconConfiguration( + icon: Icons.archive_outlined, + color: brandColor), + maxWidth: 260); + Navigator.of(context).pop(); + }); + }, + ), + ), + PopupMenuItem( + child: ListTile( + enabled: false, + title: Text(listMenu[7]), + ), + ), + ]), + ))), + ], + items: items, + ); + } + + List generateBoardListObject(List lists) { + final List listData = []; + + for (int i = 0; i < lists.length; i++) { + listData.add(BoardListObject( + title: lists[i].name, + listId: lists[i].id, + items: generateBoardItemObject(lists[i].cards!))); + } + + return listData; + } + + List generateBoardItemObject(List crds) { + final List items = []; + for (int i = 0; i < crds.length; i++) { + items.add(BoardItemObject( + title: crds[i].name, + cardLabels: crds[i].cardLabels, + hasDescription: (crds[i].description != null) ? true : false)); + } + return items; + } + + List loadBoardView(List Listboards) { + List data = generateBoardListObject(Listboards); + lists = []; + + for (int i = 0; i < data.length; i++) { + lists.add(_createBoardList(data[i], data, i) as BoardList); + } + + lists.insert( + data.length, + BoardList( + items: [ + BoardItem( + item: GestureDetector( + onTap: () { + setState(() { + show = true; + }); + }, + child: Container( + alignment: Alignment.center, + width: width, + height: 50, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(10.0), + color: brandColor, + ), + child: (!show) + ? const Text( + "Add list", + style: TextStyle(color: whiteShade), + ) + : Padding( + padding: const EdgeInsets.all(10.0), + child: TextField( + controller: nameController, + decoration: + const InputDecoration(hintText: "List name"), + ), + )), + )) + ], + )); + return lists; + } +} diff --git a/demos/supabase-trello/lib/features/boardbackground/presentation/index.dart b/demos/supabase-trello/lib/features/boardbackground/presentation/index.dart new file mode 100644 index 00000000..6b08897a --- /dev/null +++ b/demos/supabase-trello/lib/features/boardbackground/presentation/index.dart @@ -0,0 +1,59 @@ +import 'package:flutter/material.dart'; +import 'package:trelloappclone_flutter/utils/config.dart'; +import '../../../main.dart'; + +class BoardBackground extends StatefulWidget { + const BoardBackground({super.key}); + + @override + State createState() => _BoardBackgroundState(); +} + +class _BoardBackgroundState extends State { + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: const Text("Board background"), + centerTitle: false, + ), + body: GridView.builder( + gridDelegate: const SliverGridDelegateWithMaxCrossAxisExtent( + maxCrossAxisExtent: 200, + childAspectRatio: 1, + crossAxisSpacing: 3, + mainAxisSpacing: 20), + itemCount: backgrounds.length, + itemBuilder: (BuildContext cxt, index) { + return GestureDetector( + onTap: () { + setState(() { + trello.setSelectedBg(backgrounds[index]); + }); + }, + child: Stack( + children: [ + Container( + alignment: Alignment.center, + decoration: BoxDecoration( + color: Color(int.parse( + backgrounds[index].substring(1, 7), + radix: 16) + + 0xff000000), + borderRadius: BorderRadius.circular(5)), + ), + (backgrounds[index] == trello.selectedBackground) + ? const Center( + child: Icon( + Icons.check, + color: Colors.white, + size: 50, + ), + ) + : const SizedBox.shrink() + ], + )); + }), + ); + } +} diff --git a/demos/supabase-trello/lib/features/boardmenu/presentation/index.dart b/demos/supabase-trello/lib/features/boardmenu/presentation/index.dart new file mode 100644 index 00000000..82badf5b --- /dev/null +++ b/demos/supabase-trello/lib/features/boardmenu/presentation/index.dart @@ -0,0 +1,202 @@ +import 'package:flutter/material.dart'; +import 'package:trelloappclone_flutter/features/visibility/presentation/index.dart'; +import 'package:trelloappclone_flutter/main.dart'; +import 'package:trelloappclone_flutter/utils/color.dart'; + +class BoardMenu extends StatefulWidget { + const BoardMenu({super.key}); + + @override + State createState() => _BoardMenuState(); +} + +class _BoardMenuState extends State { + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + leading: IconButton( + onPressed: () { + Navigator.pop(context); + }, + icon: const Icon(Icons.close), + ), + title: const Text("Board menu"), + centerTitle: false, + ), + body: SingleChildScrollView( + child: Column( + children: [ + Padding( + padding: const EdgeInsets.all(20.0), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Container( + decoration: const BoxDecoration( + color: brandColor, + borderRadius: BorderRadius.all(Radius.circular(10.0))), + child: IconButton( + onPressed: () {}, + icon: const Icon( + Icons.star_border, + size: 30, + ), + ), + ), + Container( + decoration: const BoxDecoration( + color: brandColor, + borderRadius: BorderRadius.all(Radius.circular(10.0))), + child: IconButton( + onPressed: () { + showDialog( + context: context, + builder: (BuildContext context) { + return const BoardVisibility(); + }); + }, + icon: const Icon( + Icons.people, + size: 30, + ), + ), + ), + Container( + decoration: const BoxDecoration( + color: brandColor, + borderRadius: BorderRadius.all(Radius.circular(10.0))), + child: IconButton( + onPressed: () { + Navigator.pushNamed(context, "/copyboard"); + }, + icon: const Icon( + Icons.copy, + size: 30, + ), + ), + ), + Container( + decoration: const BoxDecoration( + color: brandColor, + borderRadius: BorderRadius.all(Radius.circular(10.0))), + child: IconButton( + onPressed: () { + Navigator.pushNamed(context, "/boardsettings"); + }, + icon: const Icon( + Icons.more_horiz, + size: 30, + ), + ), + ), + ], + ), + ), + Container( + padding: const EdgeInsets.only(top: 10.0), + child: ListTile( + tileColor: whiteShade, + leading: const Icon(Icons.person_outline), + title: const Padding( + padding: EdgeInsets.only(top: 15.0, bottom: 15.0), + child: Text("Members"), + ), + subtitle: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: const EdgeInsets.only(bottom: 18.0), + child: InkWell( + onTap: () { + Navigator.pushNamed(context, '/members'); + }, + child: Row( + children: buildMemberAvatars(), + ), + ), + ), + Padding( + padding: const EdgeInsets.only(bottom: 15.0), + child: SizedBox( + height: 37, + width: MediaQuery.of(context).size.width * 0.7, + child: ElevatedButton( + style: ElevatedButton.styleFrom( + backgroundColor: brandColor), + onPressed: () { + Navigator.pushNamed(context, "/invitemember"); + }, + child: const Text("Invite to workspace"), + ), + ), + ) + ], + ), + ), + ), + Padding( + padding: const EdgeInsets.only(top: 15.0), + child: Container( + color: whiteShade, + child: ListTile( + leading: const Icon(Icons.info_outline), + title: const Text("About this board"), + onTap: () { + Navigator.pushNamed(context, '/aboutboard'); + }, + ), + ), + ), + // Padding( + // padding: const EdgeInsets.only(top: 15.0), + // child: Container( + // color: whiteShade, + // child: ListTile( + // leading: const Icon(Icons.rocket), + // title: const Text("Power-Ups"), + // onTap: () { + // Navigator.pushNamed(context, '/powerups'); + // }, + // ), + // )), + // Padding( + // padding: const EdgeInsets.only(top: 15.0), + // child: Container( + // color: whiteShade, + // child: ListTile( + // leading: const Icon(Icons.push_pin_outlined), + // title: const Text("Pin to home screen"), + // onTap: () {}, + // ), + // )), + // const Padding( + // padding: EdgeInsets.all(15.0), + // child: Text( + // "Activity", + // style: TextStyle(fontWeight: FontWeight.bold), + // ), + // ), + // //TODO: figure out what is going on here + // Activities(Cardlist( + // id: "todo", workspaceId: trello.selectedWorkspace.id, listId: "todo", userId: trello.user.id, name: "")) + ], + )), + ); + } + + List buildMemberAvatars() { + List avatars = []; + + trello.selectedWorkspace.members?.forEach((member) { + avatars.add(CircleAvatar( + backgroundColor: brandColor, + child: Text(member.name[0].toUpperCase()), + )); + avatars.add(const SizedBox( + width: 4, + )); + }); + return avatars; + } +} diff --git a/demos/supabase-trello/lib/features/boardsettings/presentation/index.dart b/demos/supabase-trello/lib/features/boardsettings/presentation/index.dart new file mode 100644 index 00000000..b3826325 --- /dev/null +++ b/demos/supabase-trello/lib/features/boardsettings/presentation/index.dart @@ -0,0 +1,206 @@ +import 'package:flutter/material.dart'; +import 'package:trelloappclone_flutter/utils/color.dart'; +import 'package:trelloappclone_flutter/utils/config.dart'; + +import '../../../utils/widgets.dart'; +import '../../closeboard/presentation/index.dart'; + +class BoardSettings extends StatefulWidget { + const BoardSettings({super.key}); + + @override + State createState() => _BoardSettingsState(); +} + +class _BoardSettingsState extends State { + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar(title: const Text("Board settings")), + body: SingleChildScrollView( + child: Column( + children: [ + const BlueRectangle(), + Padding( + padding: const EdgeInsets.only(top: 15.0), + child: Container( + color: whiteShade, + child: const ListTile( + leading: Text("Name"), + trailing: Text("Board 1"), + ), + ), + ), + Padding( + padding: const EdgeInsets.only(top: 3.0), + child: Container( + color: whiteShade, + child: const ListTile( + leading: Text("Workspace"), + trailing: Text("Workspace 1"), + ), + ), + ), + Padding( + padding: const EdgeInsets.only(top: 3.0), + child: Container( + color: whiteShade, + child: ListTile( + leading: const Text("Background"), + trailing: ColorSquare( + bckgrd: backgrounds[0], + ), + onTap: () { + Navigator.pushNamed(context, "/boardbackground"); + }, + ), + ), + ), + // Padding( + // padding: const EdgeInsets.only(top: 3.0), + // child: Container( + // color: whiteShade, + // child: ListTile( + // leading: const Text("Enable card cover images"), + // trailing: Switch(value: true, onChanged: ((value) {})), + // ), + // ), + // ), + // Padding( + // padding: const EdgeInsets.only(top: 3.0), + // child: Container( + // color: whiteShade, + // child: ListTile( + // leading: const Text("Watch"), + // trailing: Switch(value: false, onChanged: ((value) {}))), + // ), + // ), + // Padding( + // padding: const EdgeInsets.only(top: 3.0), + // child: Container( + // color: whiteShade, + // child: ListTile( + // leading: const Text("Available offline"), + // trailing: Switch(value: false, onChanged: ((value) {}))), + // ), + // ), + // Padding( + // padding: const EdgeInsets.only(top: 3.0), + // child: Container( + // color: whiteShade, + // child: ListTile( + // leading: const Text("Edit labels"), + // onTap: () { + // showDialog( + // context: context, + // builder: (BuildContext context) { + // return const EditLabels(); + // }); + // }, + // ), + // ), + // ), + // Padding( + // padding: const EdgeInsets.only(top: 3.0), + // child: Container( + // color: whiteShade, + // child: ListTile( + // leading: const Text("Email-to-board settings"), + // onTap: () { + // Navigator.pushNamed(context, "/emailtoboard"); + // }, + // ), + // ), + // ), + // Padding( + // padding: const EdgeInsets.only(top: 3.0), + // child: Container( + // color: whiteShade, + // child: ListTile( + // leading: const Text("Archived cards"), + // onTap: () { + // Navigator.pushNamed(context, "/archivedcards"); + // }, + // ), + // ), + // ), + // Padding( + // padding: const EdgeInsets.only(top: 3.0), + // child: Container( + // color: whiteShade, + // child: ListTile( + // leading: const Text("Archived lists"), + // onTap: () { + // Navigator.pushNamed(context, "/archivedlists"); + // }, + // ), + // ), + // ), + Padding( + padding: const EdgeInsets.only(top: 15.0), + child: Container( + color: whiteShade, + child: const ListTile( + leading: Text("Visibility"), + trailing: Text("Public"), + ), + ), + ), + Padding( + padding: const EdgeInsets.only(top: 3.0), + child: Container( + color: whiteShade, + child: const ListTile( + leading: Text("Commenting"), + trailing: Text("Members"), + ), + ), + ), + Padding( + padding: const EdgeInsets.only(top: 3.0), + child: Container( + color: whiteShade, + child: const ListTile( + leading: Text("Adding members"), + trailing: Text("Members"), + ), + ), + ), + Padding( + padding: const EdgeInsets.only(top: 15.0), + child: Container( + color: whiteShade, + child: ListTile( + leading: const Text("Self join"), + trailing: Switch( + value: true, + onChanged: ((value) {}), + )), + ), + ), + const Padding( + padding: EdgeInsets.only(top: 10.0), + child: + Text("Any Workspace member can edit and join the board")), + Padding( + padding: const EdgeInsets.only(top: 15.0, bottom: 50), + child: Container( + color: whiteShade, + child: ListTile( + leading: const Text("Close board"), + onTap: () { + showDialog( + context: context, + builder: (BuildContext context) { + return const CloseBoard(); + }); + }, + ), + ), + ), + ], + ), + ), + ); + } +} diff --git a/demos/supabase-trello/lib/features/carddetails/domain/card_detail_arguments.dart b/demos/supabase-trello/lib/features/carddetails/domain/card_detail_arguments.dart new file mode 100644 index 00000000..b76dfd32 --- /dev/null +++ b/demos/supabase-trello/lib/features/carddetails/domain/card_detail_arguments.dart @@ -0,0 +1,11 @@ +import 'package:trelloappclone_flutter/models/board.dart'; +import 'package:trelloappclone_flutter/models/card.dart'; +import 'package:trelloappclone_flutter/models/listboard.dart'; + +class CardDetailArguments { + final Cardlist crd; + final Board brd; + final Listboard lst; + + CardDetailArguments(this.crd, this.brd, this.lst); +} diff --git a/demos/supabase-trello/lib/features/carddetails/presentation/index.dart b/demos/supabase-trello/lib/features/carddetails/presentation/index.dart new file mode 100644 index 00000000..4249b071 --- /dev/null +++ b/demos/supabase-trello/lib/features/carddetails/presentation/index.dart @@ -0,0 +1,376 @@ +import 'package:flutter/material.dart'; +import 'package:trelloappclone_flutter/features/activity/presentation/index.dart'; +import 'package:trelloappclone_flutter/models/checklist.dart'; +import 'package:trelloappclone_flutter/utils/color.dart'; +import 'package:trelloappclone_flutter/main.dart'; + +import '../../../utils/service.dart'; +import '../../../utils/widgets.dart'; +import '../../editlabels/presentation/index.dart'; +import '../../viewmembers/presentation/index.dart'; +import '../domain/card_detail_arguments.dart'; + +class CardDetails extends StatefulWidget { + const CardDetails({super.key}); + + @override + State createState() => _CardDetailsState(); + + static const routeName = '/carddetail'; +} + +class _CardDetailsState extends State with Service { + final TextEditingController descriptionController = TextEditingController(); + final TextEditingController nameController = TextEditingController(); + final TextEditingController checklistController = TextEditingController(); + bool showChecklist = false; + bool addCardDescription = false; + bool editCardName = false; + Map checked = {}; + + @override + Widget build(BuildContext context) { + final args = + ModalRoute.of(context)!.settings.arguments as CardDetailArguments; + + trello.setSelectedCard(args.crd); + descriptionController.text = args.crd.description ?? " "; + nameController.text = args.crd.name ?? " "; + + return Scaffold( + appBar: (showChecklist || addCardDescription || editCardName) + ? AppBar( + leading: IconButton( + onPressed: () { + setState(() { + showChecklist = false; + addCardDescription = false; + editCardName = false; + }); + }, + icon: const Icon(Icons.close, size: 30), + ), + title: Text(() { + if (showChecklist) { + return "Add Checklist"; + } else if (addCardDescription) { + return "Add card description"; + } else if (editCardName) { + return "Edit card name"; + } else { + return ""; + } + }()), + actions: [ + IconButton( + icon: const Icon(Icons.check), + onPressed: () { + if (showChecklist) { + createChecklist(Checklist( + id: randomUuid(), + workspaceId: args.crd.workspaceId, + cardId: args.crd.id, + name: checklistController.text, + status: false)); + checklistController.clear(); + setState(() { + showChecklist = false; + }); + } else if (addCardDescription || editCardName) { + if (addCardDescription && + descriptionController.text.isNotEmpty) { + args.crd.description = descriptionController.text; + } + + if (editCardName && nameController.text.isNotEmpty) { + args.crd.name = nameController.text; + } + + updateCard(args.crd); + descriptionController.clear(); + nameController.clear(); + setState(() { + addCardDescription = false; + editCardName = false; + }); + } + }, + ) + ]) + : AppBar( + leading: IconButton( + onPressed: () { + Navigator.pop(context); + }, + icon: const Icon(Icons.close, size: 30), + ), + actions: [ + PopupMenuButton( + itemBuilder: (context) { + return [ + PopupMenuItem( + onTap: () => WidgetsBinding?.instance + ?.addPostFrameCallback((_) { + showDialog( + context: context, + builder: (BuildContext context) => AlertDialog( + title: const Text('Delete Card'), + content: const Text( + 'Are you sure you want to delete this card?'), + actions: [ + TextButton( + onPressed: () => + Navigator.pop(context, 'Cancel'), + child: const Text('Cancel'), + ), + TextButton( + onPressed: () => { + deleteCard(args.crd), + // Remove popup + Navigator.pop(context, 'Delete'), + // Go one view back + Navigator.pop(context, 'Delete'), + }, + child: const Text('Delete'), + ), + ], + )); + }), + value: const Text("Delete Card"), + child: const ListTile( + leading: Icon(Icons.delete), + title: Text( + "Delete Card", + ), + ), + ), + ]; + }, + ) + // IconButton( + // icon: const Icon(Icons.more_vert), + // onPressed: () {}, + // ) + ]), + body: SingleChildScrollView( + child: Padding( + padding: const EdgeInsets.all(10.0), + child: + Column(crossAxisAlignment: CrossAxisAlignment.start, children: [ + ListTile( + title: TextField( + style: const TextStyle( + fontSize: 20.0, // Set your desired font size here + ), + controller: nameController, + onTap: () { + setState(() { + editCardName = true; + }); + }, + decoration: const InputDecoration(hintText: "Edit card name"), + ), + ), + RichText( + text: TextSpan( + text: args.brd.name, + style: const TextStyle( + fontWeight: FontWeight.w600, + fontSize: 16, + color: themeColor), + children: [ + const TextSpan( + text: ' in list ', style: TextStyle(fontSize: 12)), + TextSpan(text: args.lst.name) + ])), + const Padding( + padding: EdgeInsets.only(top: 8.0, bottom: 8.0), + child: Text( + "Quick actions", + style: TextStyle(fontWeight: FontWeight.w600), + ), + ), + Padding( + padding: const EdgeInsets.only(left: 8.0, right: 8.0), + child: Row( + children: [ + SizedBox( + width: MediaQuery.of(context).size.width * 0.4, + child: ElevatedButton.icon( + onPressed: () { + setState(() { + showChecklist = true; + }); + }, + label: const Text("Add Checklist"), + icon: const CircleAvatar( + backgroundColor: brandColor, + radius: 15, + child: Icon(Icons.checklist), + ), + ), + ), + const Spacer(), + SizedBox( + width: MediaQuery.of(context).size.width * 0.4, + child: ElevatedButton.icon( + onPressed: null, + label: const Text("Add Attachment"), + icon: const CircleAvatar( + backgroundColor: brandColor, + radius: 15, + child: Icon(Icons.attachment), + ), + ), + ) + ], + ), + ), + ListTile( + leading: const Icon(Icons.short_text), + title: TextField( + controller: descriptionController, + keyboardType: TextInputType.multiline, + minLines: 1, + maxLines: 1024, + onTap: () { + setState(() { + addCardDescription = true; + }); + }, + decoration: + const InputDecoration(hintText: "Add card description"), + ), + ), + ListTile( + leading: const Icon(Icons.label), + title: Row( + children: [ + const Text("Labels"), + // Add a horizontal space + const SizedBox(width: 8), + // Example labels with colored Chips + ...trello.selectedCard!.cardLabels!.map( + (cardLabel) => Padding( + padding: const EdgeInsets.symmetric( + horizontal: 4), // Horizontal margin + child: LabelDiplay( + color: trello.selectedBoard.boardLabels! + .firstWhere((boardLabel) => + boardLabel.id == cardLabel.boardLabelId) + .color, + label: trello.selectedBoard.boardLabels! + .firstWhere((boardLabel) => + boardLabel.id == cardLabel.boardLabelId) + .title)), + ), + ], + ), + onTap: () { + final result = showDialog( + context: context, + builder: (BuildContext context) { + return EditLabels(cardId: args.crd.id); + }); + + result.then((value) { + setState(() {}); + }); + }, + ), + ListTile( + leading: const Icon(Icons.person), + title: const Text("Members"), + onTap: () { + showDialog( + context: context, + builder: (BuildContext context) { + return const ViewMembers(); + }); + }, + ), + ListTile( + leading: const Icon(Icons.date_range_outlined), + title: const Text("Start date"), + onTap: () {}, + ), + ListTile( + leading: const Text("Checklist"), + trailing: IconButton( + onPressed: () { + setState(() { + deleteChecklist(args.crd); + }); + }, + icon: const Icon(Icons.delete)), + ), + FutureBuilder( + future: getChecklists(args.crd), + builder: ((context, snapshot) { + if (snapshot.hasData) { + List children = snapshot.data as List; + + if (children.isNotEmpty) { + return Column(children: buildChecklists(children)); + } + } + return const SizedBox.shrink(); + })), + Visibility( + visible: showChecklist, + child: TextField( + controller: checklistController, + ), + ), + const Text("Activity"), + Activities(args.crd) + ]), + ), + ), + //TODO: Add this back in when we get comments working properly + // bottomNavigationBar: Container( + // padding: const EdgeInsets.only(bottom: 5.0), + // color: whiteShade, + // width: MediaQuery.of(context).size.width * 0.8, + // height: 80, + // child: Row(mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ + // const CircleAvatar(), + // SizedBox( + // width: MediaQuery.of(context).size.width * 0.7, + // child: TextField( + // decoration: InputDecoration( + // hintText: "Add comment", + // suffix: IconButton( + // onPressed: () {}, icon: const Icon(Icons.send))), + // ), + // ), + // IconButton(onPressed: () {}, icon: const Icon(Icons.attachment)) + // ]), + // ), + ); + } + + List buildChecklists(List chcklst) { + List lists = []; + + for (int i = 0; i < chcklst.length; i++) { + checked.putIfAbsent(i, () => false); + checked[i] = chcklst[i].status; + lists.add( + CheckboxListTile( + title: Text(chcklst[i].name), + value: checked[i], + onChanged: (bool? value) { + setState(() { + checked[i] = value!; + }); + chcklst[i].status = value!; + updateChecklist(chcklst[i]); + }, + ), + ); + } + + return lists; + } +} diff --git a/demos/supabase-trello/lib/features/closeboard/presentation/index.dart b/demos/supabase-trello/lib/features/closeboard/presentation/index.dart new file mode 100644 index 00000000..500b196e --- /dev/null +++ b/demos/supabase-trello/lib/features/closeboard/presentation/index.dart @@ -0,0 +1,39 @@ +import 'package:flutter/material.dart'; +import 'package:trelloappclone_flutter/utils/color.dart'; + +class CloseBoard extends StatefulWidget { + const CloseBoard({super.key}); + + @override + State createState() => _CloseBoardState(); +} + +class _CloseBoardState extends State { + @override + Widget build(BuildContext context) { + return AlertDialog( + title: const Text("Board 1 is now closed"), + content: SizedBox( + height: 100, + child: Column( + children: [ + SizedBox( + width: MediaQuery.of(context).size.width * 0.7, + child: ElevatedButton( + onPressed: () {}, child: const Text("Re-open")), + ), + SizedBox( + width: MediaQuery.of(context).size.width * 0.7, + child: OutlinedButton( + onPressed: () {}, + child: const Text( + "Delete", + style: TextStyle(color: dangerColor), + )), + ) + ], + ), + ), + ); + } +} diff --git a/demos/supabase-trello/lib/features/copyboard/presentation/index.dart b/demos/supabase-trello/lib/features/copyboard/presentation/index.dart new file mode 100644 index 00000000..af2c68eb --- /dev/null +++ b/demos/supabase-trello/lib/features/copyboard/presentation/index.dart @@ -0,0 +1,115 @@ +import 'package:flutter/material.dart'; + +import '../../../utils/color.dart'; +import '../../../utils/constant.dart'; + +class CopyBoard extends StatefulWidget { + const CopyBoard({super.key}); + + @override + State createState() => _CopyBoardState(); +} + +class _CopyBoardState extends State { + final TextEditingController nameController = TextEditingController(); + String? dropdownValue; + List workspaces = []; + Map? visibilityDropdownValue; + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + leading: IconButton( + onPressed: () { + Navigator.pop(context); + }, + icon: const Icon( + Icons.close, + size: 30, + )), + ), + body: SingleChildScrollView( + child: Padding( + padding: const EdgeInsets.all(20.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + TextFormField( + controller: nameController, + decoration: const InputDecoration( + border: UnderlineInputBorder(), labelText: "Board name"), + ), + const Text("Workspace"), + Padding( + padding: const EdgeInsets.only(top: 8.0), + child: DropdownButton( + isExpanded: true, + value: dropdownValue, + icon: const Icon(Icons.keyboard_arrow_down), + elevation: 16, + style: const TextStyle(color: brandColor), + underline: Container( + height: 2, + color: brandColor, + ), + onChanged: (String? value) { + // This is called when the user selects an item. + setState(() { + dropdownValue = value!; + }); + }, + items: + workspaces.map>((String value) { + return DropdownMenuItem( + value: value, + child: Text(value), + ); + }).toList(), + ), + ), + const Text("Visibility"), + Padding( + padding: const EdgeInsets.only(top: 8.0), + child: DropdownButton>( + hint: const Text("Visibility"), + isExpanded: true, + value: visibilityDropdownValue, + icon: const Icon(Icons.keyboard_arrow_down), + elevation: 16, + style: const TextStyle(color: brandColor), + underline: Container( + height: 2, + color: brandColor, + ), + onChanged: (Map? value) { + setState(() { + visibilityDropdownValue = value!; + }); + }, + items: visibilityConfigurations + .map>>( + (Map value) { + return DropdownMenuItem>( + value: value, + child: Text(value["type"]!), + ); + }).toList(), + ), + ), + SwitchListTile( + value: false, + onChanged: ((value) {}), + title: const Text("Keep cards"), + ), + const Text( + "Activities and members will not be copied to the new board", + style: TextStyle(fontSize: 12), + ) + ], + ), + ), + ), + ); + } +} diff --git a/demos/supabase-trello/lib/features/createboard/presentation/index.dart b/demos/supabase-trello/lib/features/createboard/presentation/index.dart new file mode 100644 index 00000000..ecc3b997 --- /dev/null +++ b/demos/supabase-trello/lib/features/createboard/presentation/index.dart @@ -0,0 +1,145 @@ +import 'package:flutter/material.dart'; +import 'package:trelloappclone_flutter/main.dart'; +import 'package:trelloappclone_flutter/models/board.dart'; +import 'package:trelloappclone_flutter/models/workspace.dart'; + +import '../../../utils/color.dart'; +import '../../../utils/constant.dart'; +import '../../../utils/service.dart'; + +class CreateBoard extends StatefulWidget { + const CreateBoard({super.key}); + + @override + State createState() => _CreateBoardState(); +} + +class _CreateBoardState extends State with Service { + final TextEditingController nameController = TextEditingController(); + Workspace? dropdownValue; + List workspaces = []; + Map? visibilityDropdownValue; + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + leading: IconButton( + onPressed: () { + Navigator.pop(context); + }, + icon: const Icon(Icons.close)), + title: const Text("Create board"), + centerTitle: false, + ), + body: Padding( + padding: const EdgeInsets.all(30.0), + child: Column( + children: [ + TextField( + controller: nameController, + decoration: const InputDecoration(hintText: "Enter Board name"), + ), + Padding( + padding: const EdgeInsets.only(top: 8.0), + child: DropdownButton( + hint: const Text("Workspace"), + isExpanded: true, + value: dropdownValue, + icon: const Icon(Icons.keyboard_arrow_down), + elevation: 16, + style: const TextStyle(color: brandColor), + underline: Container( + height: 2, + color: brandColor, + ), + onChanged: (Workspace? value) { + setState(() { + dropdownValue = value!; + }); + }, + items: trello.workspaces + .map>((Workspace value) { + return DropdownMenuItem( + value: value, + child: Text(value.name), + ); + }).toList(), + ), + ), + Padding( + padding: const EdgeInsets.only(top: 8.0), + child: DropdownButton>( + hint: const Text("Visibility"), + isExpanded: true, + value: visibilityDropdownValue, + icon: const Icon(Icons.keyboard_arrow_down), + elevation: 16, + style: const TextStyle(color: brandColor), + underline: Container( + height: 2, + color: brandColor, + ), + onChanged: (Map? value) { + setState(() { + visibilityDropdownValue = value!; + }); + }, + items: visibilityConfigurations + .map>>( + (Map value) { + return DropdownMenuItem>( + value: value, + child: Text(value["type"]!), + ); + }).toList(), + ), + ), + Row( + children: [ + const Text("Board backgroud"), + const Spacer(), + GestureDetector( + onTap: () { + Navigator.pushNamed(context, '/boardbackground') + .then((_) => setState(() {})); + }, + child: Container( + width: 50, + height: 50, + decoration: BoxDecoration( + color: Color(int.parse( + trello.selectedBackground.substring(1, 7), + radix: 16) + + 0xFF000000))), + ), + ], + ), + Align( + alignment: Alignment.center, + child: Container( + padding: const EdgeInsets.only(top: 10), + width: MediaQuery.of(context).size.width * 0.8, + height: 60, + child: ElevatedButton( + onPressed: () { + createBoard( + context, + Board( + id: randomUuid(), + workspaceId: dropdownValue!.id, + userId: trello.user.id, + name: nameController.text, + visibility: visibilityDropdownValue!["type"]!, + background: trello.selectedBackground)); + }, + child: const Text("Create board"), + ), + ), + ) + ], + ), + ), + ); + } +} diff --git a/demos/supabase-trello/lib/features/createcard/presentation/index.dart b/demos/supabase-trello/lib/features/createcard/presentation/index.dart new file mode 100644 index 00000000..8b730685 --- /dev/null +++ b/demos/supabase-trello/lib/features/createcard/presentation/index.dart @@ -0,0 +1,137 @@ +import 'package:flutter/material.dart'; + +import '../../../utils/color.dart'; + +class CreateCard extends StatefulWidget { + const CreateCard({super.key}); + + @override + State createState() => _CreateCardState(); +} + +class _CreateCardState extends State { + String? dropdownValue; + List boards = ["Board 1"]; + String? listdropdownvalue; + List lists = ["List 1"]; + final TextEditingController nameController = TextEditingController(); + final TextEditingController descriptionController = TextEditingController(); + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + leading: IconButton( + onPressed: () { + Navigator.pushNamed(context, '/home'); + }, + icon: const Icon(Icons.close), + ), + title: const Text("New card"), + centerTitle: false, + actions: [IconButton(onPressed: () {}, icon: const Icon(Icons.check))], + ), + body: SingleChildScrollView( + child: Padding( + padding: const EdgeInsets.all(10.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Text("Board"), + DropdownButton( + isExpanded: true, + value: dropdownValue, + icon: const Icon(Icons.keyboard_arrow_down), + elevation: 16, + style: const TextStyle(color: brandColor), + underline: Container( + height: 2, + color: brandColor, + ), + onChanged: (String? value) { + // This is called when the user selects an item. + setState(() { + dropdownValue = value!; + }); + }, + items: boards.map>((String value) { + return DropdownMenuItem( + value: value, + child: Text(value), + ); + }).toList(), + ), + const Text("List"), + DropdownButton( + isExpanded: true, + value: dropdownValue, + icon: const Icon(Icons.keyboard_arrow_down), + elevation: 16, + style: const TextStyle(color: brandColor), + underline: Container( + height: 2, + color: brandColor, + ), + onChanged: (String? value) { + // This is called when the user selects an item. + setState(() { + listdropdownvalue = value!; + }); + }, + items: lists.map>((String value) { + return DropdownMenuItem( + value: value, + child: Text(value), + ); + }).toList(), + ), + Container( + color: brandColor, + margin: const EdgeInsets.all(10.0), + child: Card( + child: Column( + children: [ + Padding( + padding: const EdgeInsets.all(8.0), + child: TextField( + controller: nameController, + decoration: + const InputDecoration(hintText: "Card name"), + ), + ), + Padding( + padding: const EdgeInsets.all(8.0), + child: TextField( + controller: descriptionController, + decoration: + const InputDecoration(hintText: "Card description"), + ), + ), + const ListTile( + leading: Icon(Icons.person_add), + title: Text("Jane Doe"), + ), + ListTile( + leading: const Icon(Icons.lock_clock), + title: const Text("Start date..."), + onTap: () {}, + ), + ListTile( + title: const Text("Due date..."), + onTap: () {}, + ), + ListTile( + leading: const Icon(Icons.attachment), + title: const Text("Attachment"), + onTap: () {}, + ), + ], + ), + ), + ) + ], + ), + )), + ); + } +} diff --git a/demos/supabase-trello/lib/features/createworkspace/presentation/index.dart b/demos/supabase-trello/lib/features/createworkspace/presentation/index.dart new file mode 100644 index 00000000..05691cf4 --- /dev/null +++ b/demos/supabase-trello/lib/features/createworkspace/presentation/index.dart @@ -0,0 +1,107 @@ +import 'package:flutter/material.dart'; +import 'package:trelloappclone_flutter/utils/constant.dart'; + +import '../../../utils/color.dart'; +import '../../../utils/service.dart'; + +class CreateWorkspace extends StatefulWidget { + const CreateWorkspace({super.key}); + + @override + State createState() => _CreateWorkspaceState(); +} + +class _CreateWorkspaceState extends State with Service { + final TextEditingController nameController = TextEditingController(); + final TextEditingController descriptionController = TextEditingController(); + Map? dropdownValue; + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: const Text("Create Workspace"), + centerTitle: false, + ), + body: SingleChildScrollView( + child: Padding( + padding: const EdgeInsets.all(20.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Padding( + padding: EdgeInsets.only(bottom: 8.0), + child: Text( + "Let's build a Workspace", + style: TextStyle(fontWeight: FontWeight.bold, fontSize: 18), + ), + ), + const Text( + "Boost your productivity by making it easier for everyone to access boards in one location", + style: TextStyle(fontSize: 16), + ), + TextField( + controller: nameController, + decoration: + const InputDecoration(hintText: "Enter workspace name"), + ), + const Padding( + padding: EdgeInsets.only(top: 8.0), + child: Text("Visibility"), + ), + DropdownButton>( + isExpanded: true, + value: dropdownValue, + icon: const Icon(Icons.keyboard_arrow_down), + elevation: 16, + style: const TextStyle(color: brandColor), + underline: Container( + height: 2, + color: brandColor, + ), + onChanged: (Map? value) { + // This is called when the user selects an item. + setState(() { + dropdownValue = value!; + }); + }, + items: visibilityConfigurations + .map>>( + (Map value) { + return DropdownMenuItem>( + value: value, + child: Text(value["type"]!), + ); + }).toList(), + ), + const Padding( + padding: EdgeInsets.only(top: 10.0), + child: Text("Description"), + ), + TextField( + controller: descriptionController, + maxLines: null, + minLines: 4, + ), + Align( + alignment: Alignment.center, + child: Container( + padding: const EdgeInsets.only(top: 10), + width: MediaQuery.of(context).size.width * 0.8, + height: 60, + child: ElevatedButton( + onPressed: () { + createWorkspace(context, + name: nameController.text, + description: descriptionController.text, + visibility: dropdownValue!["type"] ?? ""); + }, + child: const Text("Create"))), + ) + ], + ), + ), + ), + ); + } +} diff --git a/demos/supabase-trello/lib/features/drawer/presentation/index.dart b/demos/supabase-trello/lib/features/drawer/presentation/index.dart new file mode 100644 index 00000000..3d914278 --- /dev/null +++ b/demos/supabase-trello/lib/features/drawer/presentation/index.dart @@ -0,0 +1,135 @@ +import 'package:flutter/material.dart'; +import 'package:trelloappclone_flutter/features/workspace/domain/workspace_arguments.dart'; +import 'package:trelloappclone_flutter/main.dart'; +import 'package:trelloappclone_flutter/models/workspace.dart'; + +import '../../../utils/color.dart'; +import '../../../utils/service.dart'; +import '../../workspace/presentation/index.dart'; + +class CustomDrawer extends StatefulWidget { + const CustomDrawer({super.key}); + + @override + State createState() => _CustomDrawerState(); +} + +class _CustomDrawerState extends State with Service { + bool active = true; + @override + Widget build(BuildContext context) { + return Drawer( + child: ListView(children: [ + DrawerHeader( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const CircleAvatar( + backgroundColor: brandColor, + ), + Padding( + padding: const EdgeInsets.only(top: 5.0), + child: Text(trello.user.name ?? trello.user.email), + ), + Text("@${trello.user.name!.toLowerCase().replaceAll(" ", "")}"), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text(trello.user.email), + IconButton( + onPressed: () { + setState(() { + active = !active; + }); + }, + icon: Icon((active) + ? Icons.keyboard_arrow_down + : Icons.keyboard_arrow_up)) + ], + ) + ], + )), + (active) + ? Column( + children: [ + ListTile( + leading: const Icon( + Icons.pages, + color: brandColor, + ), + title: const Text( + 'Boards', + style: TextStyle( + color: brandColor, fontWeight: FontWeight.bold), + ), + onTap: () { + Navigator.pushNamed(context, '/home'); + }, + ), + const Divider( + height: 2, + thickness: 2, + color: brandColor, + ), + // TODO: Show Cards assigned to logged in user + // ListTile( + // leading: const Icon(Icons.card_membership), + // title: const Text("My cards"), + // onTap: () { + // Navigator.pushNamed(context, '/mycards'); + // }, + // ), + ListTile( + leading: const Icon(Icons.settings), + enabled: false, + title: const Text("Settings"), + onTap: () { + Navigator.pushNamed(context, '/settings'); + }, + ), + ListTile( + leading: const Icon(Icons.help_outline_rounded), + enabled: false, + title: const Text("Help!"), + onTap: () {}, + ), + ListTile( + leading: const Icon(Icons.logout), + title: const Text("Log Out"), + onTap: () { + logOut(context); + Navigator.pushNamed(context, '/'); + }, + ), + ], + ) + : ListTile( + leading: const Icon(Icons.add), + title: const Text('Add account'), + onTap: () {}, + ) + ]), + ); + } + + List buildWorkspaces(List wkspcs) { + List tiles = []; + for (int i = 0; i < wkspcs.length; i++) { + tiles.add(ListTile( + leading: const Icon(Icons.people), + title: Text(wkspcs[i].name), + trailing: IconButton( + icon: const Icon(Icons.more_horiz), + onPressed: () { + Navigator.pushNamed(context, '/workspacemenu'); + }, + ), + onTap: () { + Navigator.pushNamed(context, WorkspaceScreen.routeName, + arguments: WorkspaceArguments(wkspcs[i])); + }, + )); + } + return tiles; + } +} diff --git a/demos/supabase-trello/lib/features/editlabels/presentation/index.dart b/demos/supabase-trello/lib/features/editlabels/presentation/index.dart new file mode 100644 index 00000000..caa1fa9e --- /dev/null +++ b/demos/supabase-trello/lib/features/editlabels/presentation/index.dart @@ -0,0 +1,140 @@ +import 'package:flutter/material.dart'; +import 'package:trelloappclone_flutter/main.dart'; +import 'package:trelloappclone_flutter/models/card_label.dart'; +import '../../../utils/service.dart'; + +class EditLabels extends StatefulWidget { + final String cardId; + + const EditLabels({Key? key, required this.cardId}) : super(key: key); + + @override + State createState() => _EditLabelsState(); +} + +class _EditLabelsState extends State with Service { + late List switchStates; // List to track the state of each switch + + @override + void initState() { + super.initState(); + // Initialize the switchStates list with default values (e.g., all false) + switchStates = + List.filled(trello.selectedBoard.boardLabels!.length, false); + // Set the switchStates list to true for each label that is already on the card + for (int i = 0; i < trello.selectedBoard.boardLabels!.length; i++) { + for (int j = 0; j < trello.selectedCard!.cardLabels!.length; j++) { + if (trello.selectedBoard.boardLabels![i].id == + trello.selectedCard!.cardLabels![j].boardLabelId) { + switchStates[i] = true; + } + } + } + } + + @override + Widget build(BuildContext context) { + return AlertDialog( + title: const Text("Edit labels"), + content: SizedBox( + height: 200, + child: Column(children: buildWidget()), + ), + ); + } + + List buildWidget() { + // Create and initialize a list of TextEditingControllers + List controllers = trello.selectedBoard.boardLabels! + .map((label) => TextEditingController(text: label.title)) + .toList(); + + List labelContainers = []; + for (int i = 0; i < trello.selectedBoard.boardLabels!.length; i++) { + labelContainers.add(Padding( + padding: const EdgeInsets.only(bottom: 5.0), + child: Container( + height: 35, + decoration: BoxDecoration( + color: Color(int.parse(trello.selectedBoard.boardLabels![i].color, + radix: 16) + + 0xFF000000), + borderRadius: BorderRadius.circular(5), + ), + child: Row( + children: [ + Expanded( + child: Padding( + padding: const EdgeInsets.symmetric(vertical: 4.0), + child: TextField( + controller: controllers[i], + onChanged: (value) { + // Update the label title in the database + trello.selectedBoard.boardLabels![i].title = value; + updateBoardLabel(trello.selectedBoard.boardLabels![i]); + }, + decoration: InputDecoration( + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(5.0), + borderSide: BorderSide.none, + ), + filled: false, + contentPadding: + const EdgeInsets.symmetric(horizontal: 10), + ), + ), + ), + ), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 4.0), + child: Align( + alignment: Alignment.center, + child: Transform.scale( + scale: 0.75, // Adjust the scale to make the switch smaller + child: Switch( + value: switchStates[ + i], // You might want to manage this state properly + onChanged: (bool value) async { + // Handle toggle logic + if (value) { + // Add label to card via service.data + var cardLabel = await addCardLabel( + CardLabel( + id: randomUuid(), + workspaceId: trello.selectedBoard + .boardLabels![i].workspaceId, + boardLabelId: + trello.selectedBoard.boardLabels![i].id, + boardId: trello + .selectedBoard.boardLabels![i].boardId, + cardId: widget.cardId, + dateCreated: DateTime.now()), + trello.selectedBoard.boardLabels![i]); + trello.selectedCard!.cardLabels!.add(cardLabel); + } else { + // Remove label from card + deleteCardLabel(widget.cardId, + trello.selectedBoard.boardLabels![i]); + trello.selectedCard!.cardLabels!.removeWhere( + (element) => + element.boardLabelId == + trello.selectedBoard.boardLabels![i].id); + } + setState(() { + switchStates[i] = + value; // Update the state when the switch is toggled + }); + }, + materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, + ), + ), + ), + ), + ], + ), + ), + )); + } + return labelContainers; + } +} diff --git a/demos/supabase-trello/lib/features/emailtoboard/presentation/index.dart b/demos/supabase-trello/lib/features/emailtoboard/presentation/index.dart new file mode 100644 index 00000000..6e2e4225 --- /dev/null +++ b/demos/supabase-trello/lib/features/emailtoboard/presentation/index.dart @@ -0,0 +1,135 @@ +import 'package:flutter/material.dart'; +import 'package:trelloappclone_flutter/utils/color.dart'; + +class EmailToBoard extends StatefulWidget { + const EmailToBoard({super.key}); + + @override + State createState() => _EmailToBoardState(); +} + +class _EmailToBoardState extends State { + final TextEditingController emailController = TextEditingController(); + String? dropdownValue; + String? dropdownPosition; + List list = ["To Do"]; + List position = ["Bottom"]; + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: const Text("Email-to-board settings"), + centerTitle: false, + ), + body: SingleChildScrollView( + child: Padding( + padding: const EdgeInsets.all(10.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Text("Your email address for this board"), + TextField( + controller: emailController, + ), + ListTile( + leading: const Icon(Icons.copy), + title: const Text("Copy this address"), + onTap: () {}, + ), + ListTile( + leading: const Icon(Icons.email_outlined), + title: const Text("Email me this address"), + onTap: () {}, + ), + ListTile( + leading: const Icon(Icons.mark_email_read_outlined), + title: const Text("Generate a new email address"), + onTap: () {}, + ), + const Divider( + height: 2, + thickness: 1, + ), + const Padding( + padding: EdgeInsets.only(bottom: 8.0, top: 8.0), + child: Text( + "Your emailed cards appear in...", + style: TextStyle(fontWeight: FontWeight.w600), + ), + ), + const Text( + "List", + style: + TextStyle(color: brandColor, fontWeight: FontWeight.bold), + ), + DropdownButton( + isExpanded: true, + value: dropdownValue, + icon: const Icon(Icons.keyboard_arrow_down), + elevation: 16, + style: const TextStyle(color: themeColor), + underline: Container( + height: 2, + color: brandColor, + ), + onChanged: (String? value) { + setState(() { + dropdownValue = value!; + }); + }, + items: list.map>((String value) { + return DropdownMenuItem( + value: value, + child: Text(value), + ); + }).toList(), + ), + const Text( + "Position", + style: + TextStyle(color: brandColor, fontWeight: FontWeight.bold), + ), + DropdownButton( + isExpanded: true, + value: dropdownPosition, + icon: const Icon(Icons.keyboard_arrow_down), + elevation: 16, + style: const TextStyle(color: themeColor), + underline: Container( + height: 2, + color: brandColor, + ), + onChanged: (String? value) { + setState(() { + dropdownPosition = value!; + }); + }, + items: position.map>((String value) { + return DropdownMenuItem( + value: value, + child: Text(value), + ); + }).toList(), + ), + const Padding( + padding: EdgeInsets.only(top: 18.0), + child: Divider( + height: 2, + thickness: 1, + ), + ), + const Padding( + padding: EdgeInsets.only(top: 18.0), + child: Text( + "Tip: Don't share this email address. Anyone who has it can add cards as you. When composing emails , the card title goes in the subject and the card description in the body", + style: TextStyle(fontWeight: FontWeight.bold), + ), + ) + ], + ), + ), + ), + ); + } +} diff --git a/demos/supabase-trello/lib/features/emptywidget/index.dart b/demos/supabase-trello/lib/features/emptywidget/index.dart new file mode 100644 index 00000000..bb7739ad --- /dev/null +++ b/demos/supabase-trello/lib/features/emptywidget/index.dart @@ -0,0 +1,385 @@ +import 'dart:math'; +import 'package:flutter/material.dart'; + +/// {@tool snippet} +/// +/// This example shows how to use [EmptyWidget] +/// +/// ``` dart +/// EmptyWidget( +/// image: null, +/// packageImage: PackageImage.Image_1, +/// title: 'No Notification', +/// subTitle: 'No notification available yet', +/// titleTextStyle: TextStyle( +/// fontSize: 22, +/// color: Color(0xff9da9c7), +/// fontWeight: FontWeight.w500, +/// ), +/// subtitleTextStyle: TextStyle( +/// fontSize: 14, +/// color: Color(0xffabb8d6), +/// ), +/// ) +/// ``` +/// {@end-tool} + +class EmptyWidget extends StatefulWidget { + EmptyWidget({ + this.title, + this.subTitle, + this.image, + this.subtitleTextStyle, + this.titleTextStyle, + this.packageImage, + this.hideBackgroundAnimation = false, + }); + + /// Display images from project assets + final String? image; /*!*/ + + /// Display image from package assets + final PackageImage? packageImage; /*!*/ + + /// Set text for subTitle + final String? subTitle; /*!*/ + + /// Set text style for subTitle + final TextStyle? subtitleTextStyle; /*!*/ + + /// Set text for title + final String? title; /*!*/ + + /// Text style for title + final TextStyle? titleTextStyle; /*!*/ + + /// Hides the background circular ball animation + /// + /// By default `false` value is set + final bool? hideBackgroundAnimation; + + @override + State createState() => _EmptyListWidgetState(); +} + +class _EmptyListWidgetState extends State + with TickerProviderStateMixin { + // String title, subTitle,image = 'assets/images/emptyImage.png'; + + late AnimationController _backgroundController; + + late Animation _imageAnimation; /*!*/ + AnimationController? _imageController; /*!*/ + late PackageImage? _packageImage; /*!*/ + TextStyle? _subtitleTextStyle; /*!*/ + TextStyle? _titleTextStyle; /*!*/ + late AnimationController _widgetController; /*!*/ + + @override + void dispose() { + _backgroundController.dispose(); + _imageController!.dispose(); + _widgetController.dispose(); + super.dispose(); + } + + @override + void initState() { + _backgroundController = AnimationController( + duration: const Duration(minutes: 1), + vsync: this, + lowerBound: 0, + upperBound: 20) + ..repeat(); + _widgetController = AnimationController( + duration: const Duration(seconds: 1), + vsync: this, + lowerBound: 0, + upperBound: 1) + ..forward(); + _imageController = AnimationController( + duration: const Duration(seconds: 4), + vsync: this, + )..repeat(); + _imageAnimation = Tween(begin: 0, end: 10).animate( + CurvedAnimation(parent: _imageController!, curve: Curves.linear), + ); + super.initState(); + } + + animationListner() { + if (_imageController == null) { + return; + } + if (_imageController!.isCompleted) { + setState(() { + _imageController!.reverse(); + }); + } else { + setState(() { + _imageController!.forward(); + }); + } + } + + Widget _imageWidget() { + bool isPackageImage = _packageImage != null; + return Expanded( + flex: 3, + child: AnimatedBuilder( + animation: _imageAnimation, + builder: (BuildContext context, Widget? child) { + return Transform.translate( + offset: Offset( + 0, + sin(_imageAnimation.value > .9 + ? 1 - _imageAnimation.value + : _imageAnimation.value)), + child: child, + ); + }, + child: Padding( + padding: EdgeInsets.all(10), + child: Image.asset( + isPackageImage ? _packageImage.encode()! : widget.image!, + fit: BoxFit.contain, + package: isPackageImage ? 'empty_widget' : null, + ), + ), + ), + ); + } + + Widget _imageBackground() { + return Container( + width: EmptyWidgetUtility.getHeightDimention( + context, EmptyWidgetUtility.fullWidth(context) * .95), + height: EmptyWidgetUtility.getHeightDimention( + context, EmptyWidgetUtility.fullWidth(context) * .95), + decoration: BoxDecoration(boxShadow: [ + BoxShadow( + offset: Offset(0, 0), + color: Color(0xffe2e5ed), + ), + BoxShadow( + blurRadius: 30, + offset: Offset(20, 0), + color: Color(0xffffffff), + spreadRadius: -5), + ], shape: BoxShape.circle), + ); + } + + Widget _shell({Widget? child}) { + return LayoutBuilder( + builder: (BuildContext context, BoxConstraints constraints) { + if (constraints.maxHeight > constraints.maxWidth) { + return Container( + height: constraints.maxWidth, + width: constraints.maxWidth, + child: child, + ); + } else { + return child!; + } + }); + } + + Widget _shellChild() { + _titleTextStyle = widget.titleTextStyle ?? + Theme.of(context) + .typography + .dense + .headlineSmall! + .copyWith(color: Color(0xff9da9c7)); + _subtitleTextStyle = widget.subtitleTextStyle ?? + Theme.of(context) + .typography + .dense + .bodyMedium! + .copyWith(color: Color(0xffabb8d6)); + _packageImage = widget.packageImage; + + bool anyImageProvided = widget.image == null && _packageImage == null; + + return FadeTransition( + opacity: _widgetController, + child: Container( + alignment: Alignment.center, + color: Colors.transparent, + child: Stack( + alignment: Alignment.center, + children: [ + if (!widget.hideBackgroundAnimation!) + RotationTransition( + child: _imageBackground(), + turns: _backgroundController, + ), + LayoutBuilder( + builder: (BuildContext context, BoxConstraints constraints) { + return Container( + height: constraints.maxWidth, + width: constraints.maxWidth - 30, + alignment: Alignment.center, + padding: EdgeInsets.all(10), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + mainAxisSize: MainAxisSize.min, + children: [ + anyImageProvided + ? SizedBox() + : Expanded( + flex: 1, + child: Container(), + ), + anyImageProvided ? SizedBox() : _imageWidget(), + Column( + children: [ + CustomText( + msg: widget.title, + style: _titleTextStyle, + context: context, + overflow: TextOverflow.clip, + textAlign: TextAlign.center, + ), + SizedBox( + height: 10, + ), + CustomText( + msg: widget.subTitle, + style: _subtitleTextStyle, + context: context, + overflow: TextOverflow.clip, + textAlign: TextAlign.center) + ], + ), + anyImageProvided + ? SizedBox() + : Expanded( + flex: 1, + child: Container(), + ) + ], + ), + ); + }), + ], + )), + ); + } + + @override + Widget build(BuildContext context) { + return _shell(child: _shellChild()); + } +} + +// nodoc +enum PackageImage { + Image_1, + Image_2, + Image_3, + Image_4, +} + +const _$PackageImageTypeMap = { + PackageImage.Image_1: 'assets/images/emptyImage.png', + PackageImage.Image_2: 'assets/images/im_emptyIcon_1.png', + PackageImage.Image_3: 'assets/images/im_emptyIcon_2.png', + PackageImage.Image_4: 'assets/images/im_emptyIcon_3.png', +}; + +extension convert on PackageImage? { + String? encode() => _$PackageImageTypeMap[this!]; + + PackageImage? key(String value) => decodePackageImage(value); + + PackageImage? decodePackageImage(String value) { + return _$PackageImageTypeMap.entries + .singleWhere((element) => element.value == value) + .key; + } +} + +class EmptyWidgetUtility { + static double getHeightDimention(BuildContext context, double unit) { + if (fullHeight(context) <= 460.0) { + return unit / 1.5; + } else { + return getDimention(context, unit); + } + } + + static double fullHeight(BuildContext context) { + return MediaQuery.of(context).size.height; + } + + static double getDimention(context, double unit) { + if (fullWidth(context) <= 360.0) { + return unit / 1.3; + } else { + return unit; + } + } + + static double fullWidth(BuildContext context) { + return MediaQuery.of(context).size.width; + } +} + +class CustomText extends StatefulWidget { + const CustomText( + {Key? key, + this.msg, + this.style, + this.textAlign, + this.overflow, + this.context, + this.softwrap}) + : super(key: key); + + final BuildContext? context; + final String? msg; + final TextOverflow? overflow; + final bool? softwrap; + final TextStyle? style; + final TextAlign? textAlign; + + _CustomTextState createState() => _CustomTextState(); +} + +class _CustomTextState extends State { + TextStyle? style; + + @override + @override + void initState() { + style = widget.style; + super.initState(); + } + + Widget customText() { + if (widget.msg == null) { + return Container(); + } + if (widget.context != null && widget.style != null) { + var font = widget.style!.fontSize == null + ? Theme.of(context).textTheme.bodyMedium!.fontSize! + : widget.style!.fontSize!; + style = widget.style!.copyWith( + fontSize: + font - (EmptyWidgetUtility.fullWidth(context) <= 375 ? 2 : 0)); + } + return Text( + widget.msg!, + style: widget.style, + textAlign: widget.textAlign, + overflow: widget.overflow, + ); + } + + @override + Widget build(BuildContext context) { + return customText(); + } +} diff --git a/demos/supabase-trello/lib/features/generateworkspace/presentation/index.dart b/demos/supabase-trello/lib/features/generateworkspace/presentation/index.dart new file mode 100644 index 00000000..34ed35fb --- /dev/null +++ b/demos/supabase-trello/lib/features/generateworkspace/presentation/index.dart @@ -0,0 +1,103 @@ +import 'package:flutter/material.dart'; +import 'package:trelloappclone_flutter/utils/data_generator.dart'; + +import '../../../main.dart'; +import '../../../utils/service.dart'; + +class GenerateWorkspace extends StatefulWidget { + const GenerateWorkspace({super.key}); + + @override + State createState() => _GenerateWorkspaceState(); +} + +class _GenerateWorkspaceState extends State with Service { + final TextEditingController nameController = TextEditingController(); + Map? dropdownValue; + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: const Text("Generate Sample Workspace"), + centerTitle: false, + ), + body: SingleChildScrollView( + child: Padding( + padding: const EdgeInsets.all(20.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Padding( + padding: EdgeInsets.only(bottom: 8.0), + child: Text( + "This will create a Workspace with sample data", + style: TextStyle(fontWeight: FontWeight.bold, fontSize: 18), + ), + ), + TextField( + controller: nameController, + decoration: + const InputDecoration(hintText: "Enter workspace name"), + ), + // const Padding( + // padding: EdgeInsets.only(top: 8.0), + // child: Text("Visibility"), + // ), + // DropdownButton>( + // isExpanded: true, + // value: dropdownValue, + // icon: const Icon(Icons.keyboard_arrow_down), + // elevation: 16, + // style: const TextStyle(color: brandColor), + // underline: Container( + // height: 2, + // color: brandColor, + // ), + // onChanged: (Map? value) { + // // This is called when the user selects an item. + // setState(() { + // dropdownValue = value!; + // }); + // }, + // items: visibilityConfigurations + // .map>>( + // (Map value) { + // return DropdownMenuItem>( + // value: value, + // child: Text(value["type"]!), + // ); + // }).toList(), + // ), + // const Padding( + // padding: EdgeInsets.only(top: 10.0), + // child: Text("Description"), + // ), + // TextField( + // controller: descriptionController, + // maxLines: null, + // minLines: 4, + // ), + Align( + alignment: Alignment.center, + child: Container( + padding: const EdgeInsets.only(top: 10), + width: MediaQuery.of(context).size.width * 0.8, + height: 60, + child: ElevatedButton( + onPressed: () { + DataGenerator().createSampleWorkspace( + nameController.text, + trello, + context + ); + }, + child: const Text("Create"))), + ) + ], + ), + ), + ), + ); + } +} diff --git a/demos/supabase-trello/lib/features/home/presentation/custom_floating_action.dart b/demos/supabase-trello/lib/features/home/presentation/custom_floating_action.dart new file mode 100644 index 00000000..e9532adf --- /dev/null +++ b/demos/supabase-trello/lib/features/home/presentation/custom_floating_action.dart @@ -0,0 +1,42 @@ +import 'package:flutter/material.dart'; + +class CustomFloatingAction extends StatefulWidget { + final String title; + final IconData icon; + final String route; + const CustomFloatingAction(this.title, this.icon, this.route, {super.key}); + + @override + State createState() => _CustomFloatingActionState(); +} + +class _CustomFloatingActionState extends State { + @override + Widget build(BuildContext context) { + return GestureDetector( + onTap: () { + Navigator.pushNamed(context, widget.route); + }, + child: Text.rich(TextSpan(children: [ + WidgetSpan( + child: SizedBox( + width: 150, + height: 30, + child: Card( + child: Center( + child: Text(widget.title), + )), + )), + const WidgetSpan( + child: SizedBox( + width: 20, + )), + WidgetSpan( + child: CircleAvatar( + backgroundColor: Colors.green[400], + child: Icon(widget.icon, color: Colors.white, size: 26), + )) + ])), + ); + } +} diff --git a/demos/supabase-trello/lib/features/home/presentation/custom_search.dart b/demos/supabase-trello/lib/features/home/presentation/custom_search.dart new file mode 100644 index 00000000..ed0394cc --- /dev/null +++ b/demos/supabase-trello/lib/features/home/presentation/custom_search.dart @@ -0,0 +1,81 @@ +import 'package:flutter/material.dart'; +import 'package:trelloappclone_flutter/models/board.dart'; + +class CustomSearchDelegate extends SearchDelegate { + List searchTerms = []; + CustomSearchDelegate(List s) { + searchTerms = s; + } + + @override + List? buildActions(BuildContext context) { + return [ + IconButton( + onPressed: () { + query = ''; + }, + icon: const Icon(Icons.clear), + ), + ]; + } + + @override + Widget? buildLeading(BuildContext context) { + return IconButton( + onPressed: () { + close(context, null); + }, + icon: const Icon(Icons.arrow_back), + ); + } + + @override + Widget buildResults(BuildContext context) { + List matchQuery = []; + for (var brd in searchTerms) { + if (brd.name.toLowerCase().contains(query.toLowerCase())) { + matchQuery.add(brd); + } + } + return ListView.builder( + itemCount: matchQuery.length, + itemBuilder: (context, index) { + var result = matchQuery[index]; + + return ListTile( + onTap: () async { + if (context.mounted) { + Navigator.pushNamed(context, "/board"); + } + }, + title: Text(result.name), + ); + }, + ); + } + + @override + Widget buildSuggestions(BuildContext context) { + List matchQuery = []; + for (var brd in searchTerms) { + if (brd.name.toLowerCase().contains(query.toLowerCase())) { + matchQuery.add(brd); + } + } + return ListView.builder( + itemCount: matchQuery.length, + itemBuilder: (context, index) { + var result = matchQuery[index]; + + return ListTile( + onTap: () async { + if (context.mounted) { + Navigator.pushNamed(context, "/board"); + } + }, + title: Text(result.name), + ); + }, + ); + } +} diff --git a/demos/supabase-trello/lib/features/home/presentation/index.dart b/demos/supabase-trello/lib/features/home/presentation/index.dart new file mode 100644 index 00000000..ab6f6135 --- /dev/null +++ b/demos/supabase-trello/lib/features/home/presentation/index.dart @@ -0,0 +1,187 @@ +import 'dart:async'; + +import 'package:flutter/material.dart'; +import 'package:flutter_expandable_fab/flutter_expandable_fab.dart'; +import 'package:logging/logging.dart'; +import 'package:powersync/powersync.dart' as PowerSync; +import 'package:trelloappclone_flutter/features/emptywidget/index.dart'; +import 'package:trelloappclone_flutter/main.dart'; +import 'package:trelloappclone_flutter/models/board.dart'; +import 'package:trelloappclone_flutter/models/workspace.dart'; +import 'package:trelloappclone_flutter/features/board/domain/board_arguments.dart'; +import 'package:trelloappclone_flutter/features/board/presentation/index.dart'; +import 'package:trelloappclone_flutter/protocol/data_client.dart'; + +import '../../../utils/color.dart'; +import '../../../utils/service.dart'; +import '../../../utils/widgets.dart'; +import '../../drawer/presentation/index.dart'; +import 'custom_floating_action.dart'; + +final log = Logger('powersync-supabase'); + +class Home extends StatefulWidget { + const Home({super.key}); + + @override + State createState() => _HomeState(); +} + +class _HomeState extends State with Service { + late PowerSync.SyncStatus _connectionState; + StreamSubscription? _syncStatusSubscription; + + @override + void initState() { + super.initState(); + + _connectionState = dataClient.getCurrentSyncStatus(); + _syncStatusSubscription = dataClient.getStatusStream().listen((event) { + log.info('Sync Status: $event'); + setState(() { + _connectionState = event; + }); + }); + } + + @override + void dispose() { + super.dispose(); + _syncStatusSubscription?.cancel(); + } + + @override + Widget build(BuildContext context) { + IconButton connectedIcon = IconButton( + icon: const Icon(Icons.wifi), + tooltip: 'Connected', + onPressed: () { + switchToOfflineMode(); + }, + ); + IconButton disconnectedIcon = IconButton( + icon: const Icon(Icons.wifi_off), + tooltip: 'Not connected', + onPressed: () { + switchToOnlineMode(); + }, + ); + + return Scaffold( + appBar: AppBar( + title: const Text("Boards"), + actions: [ + IconButton( + onPressed: () { + search(context); + }, + icon: const Icon(Icons.search)), + _connectionState.connected ? connectedIcon : disconnectedIcon + ], + ), + drawer: const CustomDrawer(), + body: StreamBuilder( + stream: getWorkspacesStream(), + builder: + (BuildContext context, AsyncSnapshot> snapshot) { + if (snapshot.hasData) { + List children = snapshot.data as List; + + if (children.isNotEmpty) { + return SingleChildScrollView( + child: + Column(children: buildWorkspacesAndBoards(children))); + } + } + return Center( + child: Padding( + padding: const EdgeInsets.all(20.0), + child: EmptyWidget( + image: null, + packageImage: PackageImage.Image_1, + title: 'No Boards', + subTitle: 'Create your first Trello board', + titleTextStyle: const TextStyle( + fontSize: 22, + color: Color(0xff9da9c7), + fontWeight: FontWeight.w500, + ), + subtitleTextStyle: const TextStyle( + fontSize: 14, + color: Color(0xffabb8d6), + ), + ), + ), + ); + }), + floatingActionButtonLocation: ExpandableFab.location, + floatingActionButton: ExpandableFab( + openButtonBuilder: RotateFloatingActionButtonBuilder( + child: const Icon(Icons.add), + fabSize: ExpandableFabSize.regular, + backgroundColor: Colors.green[400], + shape: const CircleBorder(), + ), + type: ExpandableFabType.up, + children: const [ + CustomFloatingAction("Workspace", Icons.book, '/createworkspace'), + CustomFloatingAction("Board", Icons.book, '/createboard'), + CustomFloatingAction("Sample Workspace", Icons.dataset_outlined, + '/generateworkspace'), + //CustomFloatingAction("Card", Icons.card_membership, '/createcard') + ]), + ); + } + + List buildWorkspacesAndBoards(List wkspcs) { + List workspacesandboards = []; + Widget workspace; + + for (int i = 0; i < wkspcs.length; i++) { + workspace = ListTile( + tileColor: whiteShade, + leading: Text(wkspcs[i].name), + trailing: IconButton( + onPressed: () { + Navigator.pushNamed(context, '/workspacemenu'); + }, + icon: const Icon(Icons.more_horiz)), + ); + + workspacesandboards.add(workspace); + + workspacesandboards.add(StreamBuilder( + stream: getBoardsStream(wkspcs[i].id), + builder: (BuildContext context, AsyncSnapshot> snapshot) { + if (snapshot.hasData) { + List children = snapshot.data as List; + + if (children.isNotEmpty) { + return Column(children: buildBoards(children, wkspcs[i])); + } + } + return const SizedBox.shrink(); + }, + )); + } + return workspacesandboards; + } + + List buildBoards(List brd, Workspace wkspc) { + List boards = []; + for (int j = 0; j < brd.length; j++) { + boards.add(ListTile( + leading: ColorSquare( + bckgrd: brd[j].background, + ), + title: Text(brd[j].name), + onTap: () { + Navigator.pushNamed(context, BoardScreen.routeName, + arguments: BoardArguments(brd[j], wkspc)); + }, + )); + } + + return boards; + } +} diff --git a/demos/supabase-trello/lib/features/invitemember/presentation/index.dart b/demos/supabase-trello/lib/features/invitemember/presentation/index.dart new file mode 100644 index 00000000..bcb4ad3a --- /dev/null +++ b/demos/supabase-trello/lib/features/invitemember/presentation/index.dart @@ -0,0 +1,144 @@ +import 'package:flutter/material.dart'; +import 'package:status_alert/status_alert.dart'; +import 'package:trelloappclone_flutter/utils/color.dart'; +import 'package:trelloappclone_flutter/utils/service.dart'; +import 'package:trelloappclone_flutter/models/member.dart'; + +import '../../../main.dart'; + +class InviteMember extends StatefulWidget { + const InviteMember({super.key}); + + @override + State createState() => _InviteMemberState(); +} + +class _InviteMemberState extends State with Service { + final TextEditingController emailcontroller = TextEditingController(); + final List _currentMembers = []; + + @override + void initState() { + super.initState(); + _currentMembers.addAll(trello.selectedWorkspace.members ?? []); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + leading: IconButton( + onPressed: () { + Navigator.pop(context); + }, + icon: const Icon(Icons.close, size: 30), + ), + title: Text("Invite to ${trello.selectedWorkspace.name}"), + centerTitle: false, + // actions: [ + // IconButton(onPressed: () {}, icon: const Icon(Icons.contacts)) + // ], + ), + body: SingleChildScrollView( + child: Padding( + padding: const EdgeInsets.all(10.0), + child: Column( + children: [ + Padding( + padding: const EdgeInsets.only(bottom: 8.0), + child: TextField( + controller: emailcontroller, + textCapitalization: TextCapitalization.none, + keyboardType: TextInputType.emailAddress, + decoration: const InputDecoration(hintText: "Email"), + ), + ), + Card( + child: ListTile( + textColor: brandColor, + title: const Text("Add Existing User"), + subtitle: const Text("Add user with email to workspace."), + trailing: IconButton( + icon: const Icon( + Icons.add_circle_outline, + color: brandColor, + ), + onPressed: () { + inviteUserToWorkspace( + emailcontroller.text, trello.selectedWorkspace) + .then((succeeded) { + if (succeeded) { + setState(() { + _currentMembers.clear(); + _currentMembers + .addAll(trello.selectedWorkspace.members ?? []); + }); + StatusAlert.show(context, + duration: const Duration(seconds: 3), + title: 'Added Member', + subtitle: + '${emailcontroller.text} added to workspace.', + configuration: const IconConfiguration( + icon: Icons.check, color: brandColor), + maxWidth: 260); + } else { + StatusAlert.show(context, + duration: const Duration(seconds: 3), + title: 'Add Failed', + subtitle: + '${emailcontroller.text} not an existing user.', + configuration: const IconConfiguration( + icon: Icons.error_outline, color: brandColor), + maxWidth: 260); + } + }); + }, + ), + ), + ), + const Padding( + padding: EdgeInsets.only(top: 18.0, bottom: 18), + child: Align( + alignment: Alignment.topLeft, + child: Text( + "Current Board Members", + style: TextStyle(fontWeight: FontWeight.w600), + ), + ), + ), + _buildMembersList(), + // Padding( + // padding: EdgeInsets.only(bottom: 8.0), + // child: Text( + // "Work together on a board", + // style: TextStyle(fontWeight: FontWeight.bold, fontSize: 18), + // ), + // ), + // Text( + // "Use the search bar or invite link to share this board with others", + // textAlign: TextAlign.center, + // ) + ], + ), + ), + ), + ); + } + + Widget _buildMembersList() { + List memberTiles = []; + for (var member in _currentMembers) { + memberTiles.add(ListTile( + leading: CircleAvatar( + backgroundColor: brandColor, + child: Text(member.name[0].toUpperCase()), + ), + title: Text(member.name), + trailing: const Text("Admin"), + )); + } + return Column( + children: memberTiles, + ); + } +} diff --git a/demos/supabase-trello/lib/features/landing/presentation/bottomsheet.dart b/demos/supabase-trello/lib/features/landing/presentation/bottomsheet.dart new file mode 100644 index 00000000..c58ed811 --- /dev/null +++ b/demos/supabase-trello/lib/features/landing/presentation/bottomsheet.dart @@ -0,0 +1,84 @@ +import 'package:flutter/material.dart'; +import 'package:material_design_icons_flutter/material_design_icons_flutter.dart'; +import 'package:trelloappclone_flutter/features/signtotrello/domain/sign_arguments.dart'; +import 'package:trelloappclone_flutter/features/signtotrello/presentation/index.dart'; + +import '../../../utils/color.dart'; +import '../../../utils/config.dart'; + +class LandingBottomSheet extends StatefulWidget { + final Enum type; + const LandingBottomSheet(this.type, {super.key}); + + @override + State createState() => _LandingBottomSheetState(); +} + +class _LandingBottomSheetState extends State { + @override + Widget build(BuildContext context) { + return SizedBox( + height: 250, + child: ListView( + children: [ + ListTile( + onTap: () { + Navigator.pop(context); + Navigator.pushNamed(context, SignToTrello.routeName, + arguments: SignArguments(widget.type)); + }, + leading: const Icon( + Icons.email, + color: brandColor, + ), + title: Text( + (widget.type == Sign.signUp) + ? " SIGN UP WITH EMAIL" + : "LOG IN WITH EMAIL", + style: const TextStyle(fontWeight: FontWeight.bold), + ), + ), + ListTile( + onTap: null, + leading: Icon( + MdiIcons.google, + color: Colors.grey, + ), + title: Text( + (widget.type == Sign.signUp) + ? " SIGN UP WITH GOOGLE" + : "LOG IN WITH GOOGLE", + style: const TextStyle(fontWeight: FontWeight.bold, color: Colors.grey), + ), + ), + ListTile( + onTap: null, + leading: Icon( + MdiIcons.microsoft, + color: Colors.grey, + ), + title: Text( + (widget.type == Sign.signUp) + ? " SIGN UP WITH MICROSOFT" + : "LOG IN WITH MICROSOFT", + style: const TextStyle(fontWeight: FontWeight.bold, color: Colors.grey), + ), + ), + ListTile( + onTap: null, + leading: Icon( + MdiIcons.apple, + color: Colors.grey, + ), + title: Text( + (widget.type == Sign.signUp) + ? " SIGN UP WITH APPLE" + : "LOG IN WITH APPLE", + style: const TextStyle(fontWeight: FontWeight.bold, color: Colors.grey), + ), + ) + ], + ), + ); + } +} diff --git a/demos/supabase-trello/lib/features/landing/presentation/index.dart b/demos/supabase-trello/lib/features/landing/presentation/index.dart new file mode 100644 index 00000000..6a5b6e6c --- /dev/null +++ b/demos/supabase-trello/lib/features/landing/presentation/index.dart @@ -0,0 +1,91 @@ +import 'package:flutter/material.dart'; +import 'package:trelloappclone_flutter/features/landing/presentation/bottomsheet.dart'; + +import '../../../utils/color.dart'; +import '../../../utils/config.dart'; +import '../../../utils/constant.dart'; +import '../../../utils/service.dart'; + +class Landing extends StatefulWidget { + const Landing({super.key}); + + @override + State createState() => _LandingState(); +} + +class _LandingState extends State with Service { + @override + Widget build(BuildContext context) { + return Scaffold( + body: SafeArea( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Padding( + padding: const EdgeInsets.all(8.0), + child: Image.asset( + logo, + width: 30, + height: 30, + ), + ), + Image.asset( + landingImage, + height: MediaQuery.of(context).size.height * 0.4, + ), + const Padding( + padding: EdgeInsets.all(25.0), + child: Text( + headline, + style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold), + textAlign: TextAlign.center, + ), + ), + Container( + margin: const EdgeInsets.all(8.0), + width: MediaQuery.of(context).size.width * 0.8, + height: 50, + child: ElevatedButton( + onPressed: () { + showModalBottomSheet( + context: context, + builder: (BuildContext context) { + return const LandingBottomSheet(Sign.signUp); + }); + }, + child: const Text("Sign up"), + ), + ), + Container( + margin: const EdgeInsets.all(8.0), + width: MediaQuery.of(context).size.width * 0.8, + height: 50, + child: OutlinedButton( + onPressed: () { + showModalBottomSheet( + context: context, + builder: (BuildContext context) { + return const LandingBottomSheet(Sign.logIn); + }); + }, + style: OutlinedButton.styleFrom( + side: const BorderSide(width: 1.0, color: brandColor)), + child: const Text("Log in"), + ), + ), + const Text( + terms, + textAlign: TextAlign.center, + ), + const SizedBox( + height: 10, + ), + const Text( + contact, + style: TextStyle(decoration: TextDecoration.underline), + ) + ], + )), + ); + } +} diff --git a/demos/supabase-trello/lib/features/members/presentation/index.dart b/demos/supabase-trello/lib/features/members/presentation/index.dart new file mode 100644 index 00000000..c6ae50f1 --- /dev/null +++ b/demos/supabase-trello/lib/features/members/presentation/index.dart @@ -0,0 +1,131 @@ +import 'package:flutter/material.dart'; +import 'package:trelloappclone_flutter/utils/color.dart'; +import 'package:trelloappclone_flutter/utils/service.dart'; +import 'package:trelloappclone_flutter/models/member.dart'; + +import '../../../main.dart'; + +class Members extends StatefulWidget { + const Members({super.key}); + + @override + State createState() => _MembersState(); +} + +class _MembersState extends State with Service { + final List _currentMembers = []; + + @override + void initState() { + super.initState(); + _currentMembers.addAll(trello.selectedWorkspace.members ?? []); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: const Text("Members"), + centerTitle: false, + actions: [ + TextButton( + onPressed: () { + Navigator.pushNamed(context, '/invitemember'); + }, + child: const Text( + "INVITE", + style: TextStyle(color: whiteShade), + )) + ], + ), + body: SingleChildScrollView( + child: Padding( + padding: const EdgeInsets.all(20.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text("Members (${_currentMembers.length})"), + ListView( + shrinkWrap: true, + children: _buildMembersList(), + ) + ], + ), + )), + ); + } + + List _buildMembersList() { + List memberTiles = []; + for (var member in _currentMembers) { + memberTiles.add(ListTile( + leading: CircleAvatar( + backgroundColor: brandColor, + child: Text(member.name[0].toUpperCase()), + ), + title: Text(member.name), + trailing: Text( + member.role, + style: const TextStyle(fontWeight: FontWeight.bold), + ), + onTap: () { + showModalBottomSheet( + context: context, + builder: (BuildContext context) { + return SizedBox( + height: MediaQuery.of(context).size.height * 0.4, + child: Padding( + padding: const EdgeInsets.all(10.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + ListTile( + leading: CircleAvatar( + backgroundColor: brandColor, + child: Text(member.name[0].toUpperCase()), + ), + title: Text(member.name), + ), + Padding( + padding: const EdgeInsets.only(top: 8.0), + child: Text(member.role), + ), + const Text( + "Can view, create and edit Workspace boards, and change settings for the workspace"), + Align( + alignment: Alignment.center, + child: Container( + padding: const EdgeInsets.only(top: 8.0), + width: MediaQuery.of(context).size.width * 0.8, + height: 50, + child: ElevatedButton( + onPressed: () { + removeMemberFromWorkspace( + member, trello.selectedWorkspace) + .then((updatedWorkspace) { + setState(() { + _currentMembers.clear(); + _currentMembers.addAll( + updatedWorkspace.members ?? []); + }); + }); + Navigator.of(context).pop(); + }, + style: ElevatedButton.styleFrom( + backgroundColor: dangerColor), + child: Text(member.userId == trello.user.id + ? "Leave workspace" + : "Remove from workspace")), + ), + ) + ]), + ), + ); + }); + }, + )); + } + + return memberTiles; + } +} diff --git a/demos/supabase-trello/lib/features/mycards/presentation/index.dart b/demos/supabase-trello/lib/features/mycards/presentation/index.dart new file mode 100644 index 00000000..25416bdc --- /dev/null +++ b/demos/supabase-trello/lib/features/mycards/presentation/index.dart @@ -0,0 +1,60 @@ +import 'package:flutter/material.dart'; + +import '../../drawer/presentation/index.dart'; + +class MyCards extends StatefulWidget { + const MyCards({super.key}); + + @override + State createState() => _MyCardsState(); +} + +class _MyCardsState extends State { + String selectedValue = "Board"; + List list = ["Board", "Date"]; + String? dropdownValue; + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Row(children: [ + Text("My cards by $selectedValue"), + SizedBox( + child: DropdownButton( + value: dropdownValue, + icon: const Icon( + Icons.keyboard_arrow_down, + color: Colors.white, + ), + underline: const SizedBox.shrink(), + elevation: 16, + onChanged: (String? value) { + setState(() { + selectedValue = value!; + }); + }, + items: list.map>((String value) { + return DropdownMenuItem( + value: value, + child: Text(value), + ); + }).toList(), + )) + ]), + centerTitle: false, + actions: [IconButton(onPressed: () {}, icon: const Icon(Icons.search))], + ), + drawer: const CustomDrawer(), + body: const Center( + child: Padding( + padding: EdgeInsets.all(10.0), + child: Text( + "When you are assigned to cards they will show up here", + textAlign: TextAlign.center, + style: TextStyle(fontSize: 16), + ), + ), + ), + ); + } +} diff --git a/demos/supabase-trello/lib/features/notifications/presentation/index.dart b/demos/supabase-trello/lib/features/notifications/presentation/index.dart new file mode 100644 index 00000000..a814adea --- /dev/null +++ b/demos/supabase-trello/lib/features/notifications/presentation/index.dart @@ -0,0 +1,127 @@ +import 'package:flutter/material.dart'; + +class Notifications extends StatefulWidget { + const Notifications({super.key}); + + @override + State createState() => _NotificationsState(); +} + +class _NotificationsState extends State { + List popupmenu = ["Push notification settings"]; + late String selectedMenu; + List list = ["All Types", "Me", "Comments", "Join requests"]; + String selected = "All Types"; + bool show = true; + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + leading: IconButton( + onPressed: () { + Navigator.pop(context); + }, + icon: const Icon( + Icons.close, + size: 30, + )), + actions: [ + IconButton( + onPressed: () {}, + icon: const Icon( + Icons.library_add_check_sharp, + size: 30, + )), + PopupMenuButton( + initialValue: popupmenu[0], + onSelected: (String item) { + setState(() { + selectedMenu = item; + }); + }, + itemBuilder: (BuildContext context) => >[ + PopupMenuItem( + value: popupmenu[0], + child: Text(popupmenu[0]), + ) + ]) + ], + ), + body: Stack(children: [ + Row( + children: [ + OutlinedButton( + onPressed: () { + showModalBottomSheet( + context: context, + builder: (BuildContext context) { + return SizedBox( + height: 250, + child: ListView(children: buildWidgets()), + ); + }); + }, + child: Row( + children: [ + Text(selected), + const Icon(Icons.keyboard_arrow_down) + ], + )), + Visibility( + visible: show, + child: OutlinedButton( + onPressed: () { + setState(() { + show = !show; + }); + }, + child: const Text("Unread"), + )), + Visibility( + visible: !show, + child: ElevatedButton.icon( + onPressed: () { + setState(() { + show = !show; + }); + }, + icon: const Icon(Icons.check), + label: const Text("Unread"))), + ], + ), + const Center( + child: Padding( + padding: EdgeInsets.all(10.0), + child: Text( + "You don't have any notifications that match the selected filters", + style: TextStyle(fontSize: 18, fontWeight: FontWeight.w600), + textAlign: TextAlign.center, + ), + ), + ) + ]), + ); + } + + List buildWidgets() { + List dropdownLists = []; + for (int i = 0; i < list.length; i++) { + dropdownLists.add(ListTile( + onTap: () { + setState(() { + selected = list[i]; + }); + Navigator.pop(context); + }, + leading: + (selected == list[i]) ? const Icon(Icons.check) : const SizedBox(), + title: Text( + list[i], + style: const TextStyle(fontWeight: FontWeight.bold), + ), + )); + } + return dropdownLists; + } +} diff --git a/demos/supabase-trello/lib/features/offlineboards/presentation/index.dart b/demos/supabase-trello/lib/features/offlineboards/presentation/index.dart new file mode 100644 index 00000000..39b8be28 --- /dev/null +++ b/demos/supabase-trello/lib/features/offlineboards/presentation/index.dart @@ -0,0 +1,93 @@ +import 'package:flutter/material.dart'; +import 'package:trelloappclone_flutter/models/board.dart'; +import 'package:trelloappclone_flutter/models/workspace.dart'; +import 'package:trelloappclone_flutter/features/drawer/presentation/index.dart'; +import 'package:trelloappclone_flutter/utils/color.dart'; + +import '../../../utils/service.dart'; +import '../../../utils/widgets.dart'; + +class OfflineBoards extends StatefulWidget { + const OfflineBoards({super.key}); + + @override + State createState() => _OfflineBoardsState(); +} + +class _OfflineBoardsState extends State with Service { + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: const Text("Offline boards"), + actions: [IconButton(onPressed: () {}, icon: const Icon(Icons.search))], + ), + drawer: const CustomDrawer(), + body: SingleChildScrollView( + child: StreamBuilder( + stream: getWorkspacesStream(), + builder: (BuildContext context, + AsyncSnapshot> snapshot) { + if (snapshot.hasData) { + List children = snapshot.data as List; + + if (children.isNotEmpty) { + return Column(children: buildWorkspacesAndBoards(children)); + } + } + return const SizedBox.shrink(); + })), + ); + } + + List buildWorkspacesAndBoards(List wkspcs) { + List workspacesboards = []; + Widget workspace; + + for (int i = 0; i < wkspcs.length; i++) { + workspace = ListTile( + tileColor: whiteShade, + leading: Text(wkspcs[i].name), + ); + + workspacesboards.add(workspace); + + workspacesboards.add(StreamBuilder( + stream: getBoardsStream(wkspcs[i].id), + builder: (BuildContext context, AsyncSnapshot> snapshot) { + if (snapshot.hasData) { + List children = snapshot.data as List; + + if (children.isNotEmpty) { + return Column(children: buildBoards(children, wkspcs[i])); + } + } + return const SizedBox.shrink(); + })); + } + // } + return workspacesboards; + } + + List buildBoards(List brd, Workspace wkspcs) { + List boards = []; + for (int j = 0; j < brd.length; j++) { + boards.add(ListTile( + leading: ColorSquare(bckgrd: brd[j].background), + title: Text(brd[j].name), + onTap: () {}, + trailing: Switch( + value: brd[j].availableOffline ?? false, + activeColor: brandColor, + onChanged: (bool value) { + setState(() { + brd[j].availableOffline = value; + updateOfflineStatus(brd[j]); + }); + }, + ), + )); + } + return boards; + } +} diff --git a/demos/supabase-trello/lib/features/powerups/presentation/index.dart b/demos/supabase-trello/lib/features/powerups/presentation/index.dart new file mode 100644 index 00000000..a657bc34 --- /dev/null +++ b/demos/supabase-trello/lib/features/powerups/presentation/index.dart @@ -0,0 +1,38 @@ +import 'package:flutter/material.dart'; + +import '../../../utils/constant.dart'; + +class PowerUps extends StatefulWidget { + const PowerUps({super.key}); + + @override + State createState() => _PowerUpsState(); +} + +class _PowerUpsState extends State { + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: const Text("Power-Ups"), + centerTitle: false, + ), + body: ListView.separated( + itemBuilder: (BuildContext context, index) { + return ListTile( + leading: const CircleAvatar(), + title: Text(powerups[index]["title"]!), + subtitle: Text(powerups[index]["description"]!), + trailing: Switch( + value: false, + onChanged: ((value) {}), + ), + ); + }, + separatorBuilder: (context, index) => const Divider( + color: Colors.black, + ), + itemCount: powerups.length), + ); + } +} diff --git a/demos/supabase-trello/lib/features/settings/presentation/index.dart b/demos/supabase-trello/lib/features/settings/presentation/index.dart new file mode 100644 index 00000000..aa360798 --- /dev/null +++ b/demos/supabase-trello/lib/features/settings/presentation/index.dart @@ -0,0 +1,124 @@ +import 'package:flutter/material.dart'; +import 'package:trelloappclone_flutter/features/drawer/presentation/index.dart'; + +class Settings extends StatefulWidget { + const Settings({super.key}); + + @override + State createState() => _SettingsState(); +} + +class _SettingsState extends State { + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: const Text("Settings"), + ), + drawer: const CustomDrawer(), + body: SingleChildScrollView( + child: Column( + children: [ + const ListTile( + subtitle: Text("Notifications"), + ), + const ListTile( + title: Text("Open system settings"), + ), + const Divider( + height: 2, + thickness: 2, + ), + const ListTile( + subtitle: Text("Application theme"), + ), + const ListTile( + title: Text("Select theme"), + ), + const Divider( + height: 2, + thickness: 2, + ), + const ListTile( + subtitle: Text("Accessibility"), + ), + ListTile( + title: const Text("Color blind friendly mode"), + trailing: Checkbox(value: false, onChanged: ((value) {})), + ), + ListTile( + title: const Text("Enable animations"), + trailing: Checkbox(value: true, onChanged: ((value) {})), + ), + ListTile( + title: const Text("Show label names on card front"), + trailing: Checkbox(value: false, onChanged: ((value) {})), + ), + const ListTile( + subtitle: Text("Sync"), + ), + const ListTile( + title: Text("Sync queue"), + ), + const ListTile( + subtitle: Text("General"), + ), + const ListTile( + title: Text("Profile and visibility"), + ), + const ListTile( + title: Text("Create card details"), + ), + const ListTile( + title: Text("Set app language"), + ), + ListTile( + title: const Text("Delete account"), + onTap: () { + showDialog( + context: context, + builder: (BuildContext context) { + return AlertDialog( + title: const Text( + "Delete account?", + style: TextStyle(fontWeight: FontWeight.bold), + ), + content: const Text( + "You must log in on the web to delete your account"), + actions: [ + TextButton( + onPressed: () { + Navigator.pop(context); + }, + child: const Text("CANCEL")), + TextButton( + onPressed: () {}, child: const Text("GO TO WEB")) + ], + ); + }); + }, + ), + const ListTile( + title: Text("About Trello"), + ), + const ListTile( + title: Text("More Atlassian apps"), + ), + const ListTile( + title: Text("Contact support"), + ), + Padding( + padding: const EdgeInsets.only(bottom: 30.0), + child: ListTile( + title: const Text("Log out"), + onTap: () { + Navigator.pushNamed(context, '/'); + }, + ), + ), + ], + ), + ), + ); + } +} diff --git a/demos/supabase-trello/lib/features/signtotrello/domain/sign_arguments.dart b/demos/supabase-trello/lib/features/signtotrello/domain/sign_arguments.dart new file mode 100644 index 00000000..52fa78a0 --- /dev/null +++ b/demos/supabase-trello/lib/features/signtotrello/domain/sign_arguments.dart @@ -0,0 +1,5 @@ +class SignArguments { + final Enum type; + + SignArguments(this.type); +} \ No newline at end of file diff --git a/demos/supabase-trello/lib/features/signtotrello/presentation/index.dart b/demos/supabase-trello/lib/features/signtotrello/presentation/index.dart new file mode 100644 index 00000000..6eb78bd5 --- /dev/null +++ b/demos/supabase-trello/lib/features/signtotrello/presentation/index.dart @@ -0,0 +1,191 @@ +import 'package:flutter/material.dart'; +import 'package:trelloappclone_flutter/features/signtotrello/domain/sign_arguments.dart'; +import 'package:trelloappclone_flutter/utils/color.dart'; + +import '../../../utils/config.dart'; +import '../../../utils/service.dart'; + +class SignToTrello extends StatefulWidget { + const SignToTrello({super.key}); + + @override + State createState() => _SignToTrelloState(); + + static const routeName = '/sign'; +} + +class _SignToTrelloState extends State with Service { + final TextEditingController emailcontroller = TextEditingController(); + final TextEditingController usernamecontroller = TextEditingController(); + final TextEditingController passwordcontroller = TextEditingController(); + final TextEditingController confirmcontroller = TextEditingController(); + + @override + Widget build(BuildContext context) { + final args = ModalRoute.of(context)!.settings.arguments as SignArguments; + + return Scaffold( + appBar: AppBar( + title: Text( + (args.type == Sign.signUp) ? "Sign up" : " Log in to continue"), + centerTitle: false, + ), + body: SingleChildScrollView( + child: Padding( + padding: const EdgeInsets.only(top: 10.0), + child: Column( + children: [ + Image.asset( + logo, + width: 30, + height: 30, + ), + Padding( + padding: const EdgeInsets.only(bottom: 10.0, top: 10.0), + child: Text( + (args.type == Sign.signUp) + ? "Sign up to continue" + : "Log in to continue", + style: const TextStyle(fontWeight: FontWeight.bold), + ), + ), + Padding( + padding: + const EdgeInsets.only(left: 20.0, right: 20.0, top: 10.0), + child: TextField( + controller: emailcontroller, + textCapitalization: TextCapitalization.none, + keyboardType: TextInputType.emailAddress, + decoration: + const InputDecoration(hintText: "Enter your email"), + ), + ), + (args.type == Sign.signUp) + ? Padding( + padding: const EdgeInsets.only( + left: 20.0, right: 20.0, top: 10.0), + child: TextField( + controller: usernamecontroller, + keyboardType: TextInputType.name, + decoration: + const InputDecoration(hintText: "Enter your name"), + ), + ) + : const SizedBox.shrink(), + Padding( + padding: const EdgeInsets.only( + left: 20.0, right: 20.0, top: 10.0, bottom: 10.0), + child: TextField( + controller: passwordcontroller, + obscureText: true, + decoration: + const InputDecoration(hintText: "Enter your password"), + ), + ), + (args.type == Sign.signUp) + ? Padding( + padding: const EdgeInsets.only( + left: 20.0, right: 20.0, top: 10.0), + child: TextField( + controller: confirmcontroller, + obscureText: true, + decoration: const InputDecoration( + hintText: "Confirm your password"), + )) + : const SizedBox.shrink(), + (args.type == Sign.signUp) + ? const Padding( + padding: EdgeInsets.all(20.0), + child: Text( + "By signing up, I accept the Atlassian Cloud Terms of Service and acknowledge the Privacy Policy"), + ) + : const SizedBox.shrink(), + SizedBox( + width: MediaQuery.of(context).size.width * 0.8, + height: 50, + child: ElevatedButton( + onPressed: () { + if (args.type == Sign.signUp && validateSignUp()) { + signUp( + name: usernamecontroller.text, + email: emailcontroller.text, + password: encryptPassword(passwordcontroller.text), + context: context); + } else if (args.type == Sign.logIn && validateLogin()) { + logIn(emailcontroller.text, + encryptPassword(passwordcontroller.text), context); + } + }, + style: + ElevatedButton.styleFrom(backgroundColor: brandColor), + child: Text( + (args.type == Sign.signUp) ? "Sign up" : "Log in")), + ), + // ListTile( + // onTap: () {}, + // leading: Icon( + // MdiIcons.google, + // color: brandColor, + // ), + // title: const Text( + // "CONTINUE WITH GOOGLE", + // style: TextStyle(fontWeight: FontWeight.bold), + // ), + // ), + // ListTile( + // onTap: () {}, + // leading: Icon( + // MdiIcons.microsoft, + // color: brandColor, + // ), + // title: const Text( + // "CONTINUE WITH MICROSOFT", + // style: TextStyle(fontWeight: FontWeight.bold), + // ), + // ), + // ListTile( + // onTap: () {}, + // leading: Icon( + // MdiIcons.apple, + // color: brandColor, + // ), + // title: const Text( + // "CONTINUE WITH APPLE", + // style: TextStyle(fontWeight: FontWeight.bold), + // ), + // ), + // GestureDetector( + // onTap: () {}, + // child: Text( + // (args.type == Sign.signUp) + // ? "Already have an Atlassian account? Log in" + // : "Can't log in? Create an account", + // style: const TextStyle( + // decoration: TextDecoration.underline, color: brandColor), + // ), + // ) + ], + ), + ), + ), + ); + } + + bool validateSignUp() { + if (emailcontroller.text.isNotEmpty && + emailcontroller.text.isNotEmpty && + passwordcontroller.text.isNotEmpty && + confirmcontroller.text.isNotEmpty && + confirmcontroller.text == passwordcontroller.text) { + return true; + } + return false; + } + + bool validateLogin() { + if (emailcontroller.text.isNotEmpty && passwordcontroller.text.isNotEmpty) { + return true; + } + return false; + } +} diff --git a/demos/supabase-trello/lib/features/viewmembers/presentation/index.dart b/demos/supabase-trello/lib/features/viewmembers/presentation/index.dart new file mode 100644 index 00000000..d35a8b9a --- /dev/null +++ b/demos/supabase-trello/lib/features/viewmembers/presentation/index.dart @@ -0,0 +1,43 @@ +import 'package:flutter/material.dart'; + +class ViewMembers extends StatefulWidget { + const ViewMembers({super.key}); + + @override + State createState() => _ViewMembersState(); +} + +class _ViewMembersState extends State { + List cardMembers = [ + {"name": "Jane Doe", "handle": "@janedoe"} + ]; + @override + Widget build(BuildContext context) { + return AlertDialog( + title: const Text("Card Members"), + content: SizedBox( + height: 80, + child: Column(children: buildWidgets()), + ), + actions: [ + TextButton( + onPressed: () { + Navigator.pop(context); + }, + child: const Text("DONE")) + ], + ); + } + + List buildWidgets() { + List members = []; + for (int i = 0; i < cardMembers.length; i++) { + members.add(ListTile( + leading: const CircleAvatar(), + title: Text(cardMembers[i]["name"]), + subtitle: Text(cardMembers[i]["handle"]), + )); + } + return members; + } +} diff --git a/demos/supabase-trello/lib/features/visibility/presentation/index.dart b/demos/supabase-trello/lib/features/visibility/presentation/index.dart new file mode 100644 index 00000000..a77394bd --- /dev/null +++ b/demos/supabase-trello/lib/features/visibility/presentation/index.dart @@ -0,0 +1,59 @@ +import 'package:flutter/material.dart'; + +import '../../../utils/constant.dart'; + +class BoardVisibility extends StatefulWidget { + const BoardVisibility({super.key}); + + @override + State createState() => _BoardVisibilityState(); +} + +class _BoardVisibilityState extends State { + List checked = [false, false, false]; + + @override + Widget build(BuildContext context) { + return AlertDialog( + title: const Text("Visibility"), + content: SizedBox( + height: 360, + child: Column( + children: [ + Card( + child: ListTile( + leading: Checkbox( + value: checked[0], + onChanged: (bool? value) {}, + ), + title: Text(visibilityConfigurations[0]["type"]!), + subtitle: Text(visibilityConfigurations[0]["description"]!), + ), + ), + Card( + child: ListTile( + leading: Checkbox( + value: checked[1], + onChanged: (bool? value) {}, + ), + title: Text(visibilityConfigurations[1]["type"]!), + subtitle: Text(visibilityConfigurations[1]["description"]!), + ), + ), + Card( + child: ListTile( + leading: Checkbox( + value: checked[2], + onChanged: (bool? value) {}, + ), + title: Text(visibilityConfigurations[2]["type"]!), + subtitle: Text(visibilityConfigurations[2]["description"]!), + ), + ) + ], + ), + ), + actions: [ElevatedButton(onPressed: () {}, child: const Text("Save"))], + ); + } +} diff --git a/demos/supabase-trello/lib/features/workspace/domain/workspace_arguments.dart b/demos/supabase-trello/lib/features/workspace/domain/workspace_arguments.dart new file mode 100644 index 00000000..cdea7d12 --- /dev/null +++ b/demos/supabase-trello/lib/features/workspace/domain/workspace_arguments.dart @@ -0,0 +1,7 @@ +import 'package:trelloappclone_flutter/models/workspace.dart'; + +class WorkspaceArguments { + final Workspace wkspc; + + WorkspaceArguments(this.wkspc); +} diff --git a/demos/supabase-trello/lib/features/workspace/presentation/index.dart b/demos/supabase-trello/lib/features/workspace/presentation/index.dart new file mode 100644 index 00000000..4f23e377 --- /dev/null +++ b/demos/supabase-trello/lib/features/workspace/presentation/index.dart @@ -0,0 +1,161 @@ +import 'package:flutter/material.dart'; +import 'package:trelloappclone_flutter/models/board.dart'; +import 'package:trelloappclone_flutter/features/drawer/presentation/index.dart'; +import 'package:trelloappclone_flutter/utils/color.dart'; + +import '../../../utils/service.dart'; +import '../domain/workspace_arguments.dart'; + +class WorkspaceScreen extends StatefulWidget { + const WorkspaceScreen({super.key}); + + @override + State createState() => _WorkspaceScreenState(); + + static const routeName = '/workspace'; +} + +class _WorkspaceScreenState extends State with Service { + @override + Widget build(BuildContext context) { + final args = + ModalRoute.of(context)!.settings.arguments as WorkspaceArguments; + + return Scaffold( + appBar: AppBar( + title: Text(args.wkspc.name), + actions: [ + IconButton(onPressed: () {}, icon: const Icon(Icons.search)), + IconButton( + onPressed: () {}, + icon: const Icon(Icons.notifications_none_outlined)) + ], + ), + drawer: const CustomDrawer(), + body: DefaultTabController( + length: 2, + initialIndex: 0, + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + const TabBar( + labelColor: brandColor, + unselectedLabelColor: themeColor, + tabs: [ + Tab( + text: "BOARDS", + ), + Tab( + text: "HIGHLIGHTS", + ) + ]), + SizedBox( + height: MediaQuery.of(context).size.height * 0.8, + child: TabBarView(children: [ + Column( + children: [ + Container( + width: MediaQuery.of(context).size.width, + height: 50, + color: whiteShade, + alignment: Alignment.centerLeft, + child: const Padding( + padding: EdgeInsets.only(left: 8.0), + child: Text("Your Workspace boards")), + ), + StreamBuilder( + stream: getBoardsStream(args.wkspc.id), + builder: (context, snapshot) { + if (snapshot.hasData) { + List children = snapshot.data as List; + + if (children.isNotEmpty) { + return Expanded( + child: GridView.builder( + gridDelegate: + const SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: 2, + childAspectRatio: 1 / 0.7), + itemCount: children.length, + itemBuilder: + (BuildContext context, int index) { + return GestureDetector( + onTap: () {}, + child: Card( + shape: RoundedRectangleBorder( + borderRadius: + BorderRadius.circular( + 10.0)), + color: Color(int.parse( + children[index] + .background + .substring(1, 7), + radix: 16) + + 0xFF000000), + child: Align( + alignment: Alignment.bottomLeft, + child: ListTile( + tileColor: themeColor, + title: Text( + children[index].name, + style: const TextStyle( + color: Colors.white), + ), + ), + ), + ), + ); + })); + } + } + return const SizedBox.shrink(); + }, + ) + ], + ), + Padding( + padding: const EdgeInsets.all(20.0), + child: Column( + children: [ + const ListTile( + leading: Icon( + Icons.start, + color: brandColor, + ), + title: Text("GET STARTED"), + ), + Card( + child: Column( + children: [ + Container( + color: brandColor, + height: 100, + ), + const Padding( + padding: EdgeInsets.all(8.0), + child: Text( + "Stay on track and up-to-date", + style: TextStyle( + fontWeight: FontWeight.bold, + fontSize: 18), + ), + ), + const Padding( + padding: EdgeInsets.all(8.0), + child: Text( + "Invite people to boards and cards, add comments, and adjust due dates all from the new Trello Home. We'll show the most important activity here.", + textAlign: TextAlign.center, + ), + ) + ], + ), + ) + ], + )) + ]), + ) + ], + )), + ); + } +} diff --git a/demos/supabase-trello/lib/features/workspacemenu/presentation/index.dart b/demos/supabase-trello/lib/features/workspacemenu/presentation/index.dart new file mode 100644 index 00000000..8cff3ceb --- /dev/null +++ b/demos/supabase-trello/lib/features/workspacemenu/presentation/index.dart @@ -0,0 +1,140 @@ +import 'package:flutter/material.dart'; +import 'package:trelloappclone_flutter/utils/service.dart'; + +import '../../../main.dart'; +import '../../../utils/color.dart'; + +class WorkspaceMenu extends StatefulWidget { + const WorkspaceMenu({super.key}); + + @override + State createState() => _WorkspaceMenuState(); +} + +class _WorkspaceMenuState extends State with Service { + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + leading: IconButton( + onPressed: () { + Navigator.pop(context); + }, + icon: const Icon( + Icons.close, + size: 30, + ), + ), + actions: [ + IconButton( + onPressed: () { + Navigator.pushNamed(context, '/workspacesettings'); + }, + icon: const Icon(Icons.settings)) + ], + title: const Text("Workspace menu"), + centerTitle: false, + ), + body: Padding( + padding: const EdgeInsets.all(10.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + trello.selectedWorkspace.name, + style: const TextStyle( + fontWeight: FontWeight.bold, fontSize: 18), + ), + const Text.rich(TextSpan(children: [ + WidgetSpan( + child: + Icon(Icons.lock, color: dangerColor, size: 15)), + TextSpan( + text: "Public", + style: TextStyle(color: dangerColor)) + ])), + Padding( + padding: const EdgeInsets.only(top: 8.0, bottom: 8.0), + child: Text(trello.selectedWorkspace.description), + ), + ], + ), + const Spacer(), + CircleAvatar( + radius: 30, + backgroundColor: Colors.green[400], + child: Text( + trello.selectedWorkspace.name[0].toUpperCase(), + style: const TextStyle(color: whiteShade), + ), + ) + ], + ), + Container( + padding: const EdgeInsets.only(top: 10.0), + child: ListTile( + tileColor: whiteShade, + leading: const Icon(Icons.person_outline), + title: const Padding( + padding: EdgeInsets.only(top: 10.0, bottom: 15), + child: Text("Members"), + ), + subtitle: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: const EdgeInsets.only(bottom: 18.0), + child: InkWell( + onTap: () { + Navigator.pushNamed(context, '/members'); + }, + child: Row( + children: buildMemberAvatars(), + ), + ), + ), + Padding( + padding: const EdgeInsets.only(bottom: 15.0), + child: SizedBox( + height: 37, + width: MediaQuery.of(context).size.width * 0.7, + child: ElevatedButton( + style: ElevatedButton.styleFrom( + backgroundColor: brandColor), + onPressed: () { + Navigator.pushNamed(context, '/invitemember'); + }, + child: const Text("Invite")), + ), + ) + ], + ), + ), + ) + ], + ), + )); + } + + List buildMemberAvatars() { + List avatars = []; + + trello.selectedWorkspace.members?.forEach((member) { + avatars.add( + CircleAvatar( + backgroundColor: brandColor, + child: Text(member.name[0].toUpperCase()), + ) + ); + avatars.add( + const SizedBox(width: 4,) + ); + }); + return avatars; + } +} diff --git a/demos/supabase-trello/lib/features/workspacesettings/presentation/index.dart b/demos/supabase-trello/lib/features/workspacesettings/presentation/index.dart new file mode 100644 index 00000000..0a286fa1 --- /dev/null +++ b/demos/supabase-trello/lib/features/workspacesettings/presentation/index.dart @@ -0,0 +1,65 @@ +import 'package:flutter/material.dart'; +import 'package:trelloappclone_flutter/utils/color.dart'; + +import '../../../main.dart'; +import '../../visibility/presentation/index.dart'; + +class WorkspaceSettings extends StatefulWidget { + const WorkspaceSettings({super.key}); + + @override + State createState() => _WorkspaceSettingsState(); +} + +class _WorkspaceSettingsState extends State { + final TextEditingController nameController = TextEditingController(); + + @override + Widget build(BuildContext context) { + nameController.text = trello.selectedWorkspace.name; + return Scaffold( + appBar: AppBar( + title: const Text("Workspace settings"), + centerTitle: false, + ), + body: Column( + children: [ + ListTile( + leading: const Text("Name"), + trailing: SizedBox( + width: MediaQuery.of(context).size.width * 0.4, + child: EditableText( + textAlign: TextAlign.end, + controller: nameController, + focusNode: FocusNode(), + style: const TextStyle( + fontWeight: FontWeight.bold, color: brandColor), + cursorColor: brandColor, + backgroundCursorColor: brandColor, + onSubmitted: (value) { + Navigator.pushNamed(context, '/home'); + }, + )), + ), + ListTile( + leading: const Text("Visibility"), + trailing: GestureDetector( + child: const Text("Public"), + onTap: () { + showDialog( + context: context, + builder: (BuildContext context) { + return const BoardVisibility(); + }); + }, + ), + ), + const Align( + alignment: Alignment.center, + child: Text("Not all settings are editable on mobile"), + ) + ], + ), + ); + } +} diff --git a/demos/supabase-trello/lib/main.dart b/demos/supabase-trello/lib/main.dart new file mode 100644 index 00000000..c5534a4c --- /dev/null +++ b/demos/supabase-trello/lib/main.dart @@ -0,0 +1,117 @@ +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:google_fonts/google_fonts.dart'; +import 'package:provider/provider.dart'; +import 'package:trelloappclone_flutter/features/generateworkspace/presentation/index.dart'; +import 'package:trelloappclone_flutter/utils/trello_provider.dart'; +import 'package:trelloappclone_flutter/models/user.dart'; +import 'package:trelloappclone_flutter/protocol/data_client.dart'; +import 'package:logging/logging.dart'; + +import 'features/aboutboard/presentation/index.dart'; +import 'features/archivedcards/presentation/index.dart'; +import 'features/archivedlists/presentation/index.dart'; +import 'features/board/presentation/index.dart'; +import 'features/boardbackground/presentation/index.dart'; +import 'features/boardmenu/presentation/index.dart'; +import 'features/boardsettings/presentation/index.dart'; +import 'features/carddetails/presentation/index.dart'; +import 'features/copyboard/presentation/index.dart'; +import 'features/createboard/presentation/index.dart'; +import 'features/createcard/presentation/index.dart'; +import 'features/createworkspace/presentation/index.dart'; +import 'features/emailtoboard/presentation/index.dart'; +import 'features/home/presentation/index.dart'; +import 'features/invitemember/presentation/index.dart'; +import 'features/landing/presentation/index.dart'; +import 'features/members/presentation/index.dart'; +import 'features/mycards/presentation/index.dart'; +import 'features/notifications/presentation/index.dart'; +import 'features/offlineboards/presentation/index.dart'; +import 'features/powerups/presentation/index.dart'; +import 'features/settings/presentation/index.dart'; +import 'features/signtotrello/presentation/index.dart'; +import 'features/workspace/presentation/index.dart'; +import 'features/workspacemenu/presentation/index.dart'; +import 'features/workspacesettings/presentation/index.dart'; + +// Sets up a singleton client object that can be used to talk to the server from +// anywhere in our app. +// The client is set up to connect to a Powersync project already set up. +var dataClient = DataClient(); + +TrelloProvider trello = TrelloProvider(); + +void main() async { + // Log info from PowerSync + Logger.root.level = Level.ALL; + Logger.root.onRecord.listen((record) { + // if (kDebugMode) { + print( + '[${record.loggerName}] ${record.level.name}: ${record.time}: ${record.message}'); + + if (record.error != null) { + print(record.error); + } + if (record.stackTrace != null) { + print(record.stackTrace); + } + // } + }); + + WidgetsFlutterBinding + .ensureInitialized(); //required to get sqlite filepath from path_provider before UI has initialized + await dataClient.initialize(); + if (dataClient.isLoggedIn()) { + TrelloUser? user = await dataClient.getLoggedInUser(); + trello.setUser(user!); + } + runApp(ChangeNotifierProvider( + create: (context) => TrelloProvider(), child: const MyApp())); +} + +class MyApp extends StatelessWidget { + const MyApp({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return MaterialApp( + debugShowCheckedModeBanner: false, + title: 'Trello App Clone', + theme: ThemeData( + textTheme: Theme.of(context).textTheme.apply( + fontFamily: GoogleFonts.poppins().fontFamily, + ), + ), + initialRoute: dataClient.isLoggedIn() ? '/home' : '/', + routes: { + '/': (context) => const Landing(), + '/home': (context) => const Home(), + '/notifications': (context) => const Notifications(), + '/workspacemenu': (context) => const WorkspaceMenu(), + '/workspacesettings': (context) => const WorkspaceSettings(), + '/members': (context) => const Members(), + '/invitemember': (context) => const InviteMember(), + '/createworkspace': (context) => const CreateWorkspace(), + '/createboard': (context) => const CreateBoard(), + '/generateworkspace': (context) => const GenerateWorkspace(), + '/boardbackground': (context) => const BoardBackground(), + '/createcard': (context) => const CreateCard(), + BoardScreen.routeName: (context) => const BoardScreen(), + '/boardmenu': (context) => const BoardMenu(), + '/copyboard': (context) => const CopyBoard(), + '/boardsettings': (context) => const BoardSettings(), + '/archivedlists': (context) => const ArchivedLists(), + '/archivedcards': (context) => const ArchivedCards(), + '/emailtoboard': (context) => const EmailToBoard(), + '/aboutboard': (context) => const AboutBoard(), + '/powerups': (context) => const PowerUps(), + CardDetails.routeName: (context) => const CardDetails(), + '/mycards': (context) => const MyCards(), + '/offlineboards': (context) => const OfflineBoards(), + '/settings': (context) => const Settings(), + SignToTrello.routeName: (context) => const SignToTrello(), + '/workspace': (context) => const WorkspaceScreen() + }); + } +} diff --git a/demos/supabase-trello/lib/models/activity.dart b/demos/supabase-trello/lib/models/activity.dart new file mode 100644 index 00000000..28a7a380 --- /dev/null +++ b/demos/supabase-trello/lib/models/activity.dart @@ -0,0 +1,39 @@ +import 'package:powersync/sqlite3.dart' as sqlite; + +class Activity { + final String id; + final String workspaceId; + + final String? boardId; + + final String userId; + + final String? cardId; + + final String description; + + final DateTime dateCreated; + + Activity({ + required this.id, + required this.workspaceId, + this.boardId, + required this.userId, + this.cardId, + required this.description, + required this.dateCreated, + }); + + factory Activity.fromRow(sqlite.Row row) { + return Activity( + id: row['id'], + workspaceId: row['workspaceId'], + boardId: row['boardId'], + userId: row['userId'], + cardId: row['cardId'], + description: row['description'], + dateCreated: DateTime.parse(row['dateCreated']) + ); + } + +} diff --git a/demos/supabase-trello/lib/models/attachment.dart b/demos/supabase-trello/lib/models/attachment.dart new file mode 100644 index 00000000..a2cb5b2c --- /dev/null +++ b/demos/supabase-trello/lib/models/attachment.dart @@ -0,0 +1,28 @@ +import 'package:powersync/sqlite3.dart' as sqlite; + +class Attachment { + Attachment({ + required this.id, + required this.workspaceId, + required this.userId, + required this.cardId, + required this.attachment, + }); + + final String id; + final String workspaceId; + + final String userId; + + final String cardId; + + final String attachment; + + factory Attachment.fromRow(sqlite.Row row) { + return Attachment( + id: row['id'], + workspaceId: row['workspaceId'], + userId: row['userId'], + cardId: row['cardId'], + attachment: row['attachment']);} +} diff --git a/demos/supabase-trello/lib/models/board.dart b/demos/supabase-trello/lib/models/board.dart new file mode 100644 index 00000000..a9bbe8f8 --- /dev/null +++ b/demos/supabase-trello/lib/models/board.dart @@ -0,0 +1,86 @@ +import 'package:powersync/sqlite3.dart' as sqlite; +import 'package:trelloappclone_flutter/models/board_label.dart'; + +class Board { + Board( + {required this.id, + required this.workspaceId, + required this.userId, + required this.name, + this.description, + required this.visibility, + required this.background, + this.starred, + this.enableCover, + this.watch, + this.availableOffline, + this.label, + this.emailAddress, + this.commenting, + this.memberType, + this.pinned, + this.selfJoin, + this.close, + this.boardLabels}); + + final String id; + + final String workspaceId; + + final String userId; + + final String name; + + final String? description; + + final String visibility; + + final String background; + + final bool? starred; + + final bool? enableCover; + + final bool? watch; + + bool? availableOffline; + + final String? label; + + final String? emailAddress; + + final int? commenting; + + final int? memberType; + + final bool? pinned; + + final bool? selfJoin; + + final bool? close; + + List? boardLabels; + + factory Board.fromRow(sqlite.Row row) { + return Board( + id: row['id'], + workspaceId: row['workspaceId'], + userId: row['userId'], + name: row['name'], + description: row['description'], + visibility: row['visibility'], + background: row['background'], + starred: row['starred'] == 1, + enableCover: row['enableCover'] == 1, + watch: row['watch'] == 1, + availableOffline: row['availableOffline'] == 1, + label: row['label'], + emailAddress: row['emailAddress'], + commenting: row['commenting'], + memberType: row['memberType'], + pinned: row['pinned'] == 1, + selfJoin: row['selfJoin'] == 1, + close: row['close'] == 1, + boardLabels: []); + } +} diff --git a/demos/supabase-trello/lib/models/board_label.dart b/demos/supabase-trello/lib/models/board_label.dart new file mode 100644 index 00000000..5b63fcee --- /dev/null +++ b/demos/supabase-trello/lib/models/board_label.dart @@ -0,0 +1,34 @@ +import 'package:powersync/sqlite3.dart' as sqlite; + +class BoardLabel { + final String id; + + final String boardId; + + final String workspaceId; + + late String title; + + final String color; + + final DateTime dateCreated; + + BoardLabel({ + required this.id, + required this.boardId, + required this.workspaceId, + required this.title, + required this.color, + required this.dateCreated, + }); + + factory BoardLabel.fromRow(sqlite.Row row) { + return BoardLabel( + id: row['id'], + boardId: row['boardId'], + workspaceId: row['workspaceId'], + title: row['title'], + color: row['color'], + dateCreated: DateTime.parse(row['dateCreated'])); + } +} diff --git a/demos/supabase-trello/lib/models/card.dart b/demos/supabase-trello/lib/models/card.dart new file mode 100644 index 00000000..39ff31f0 --- /dev/null +++ b/demos/supabase-trello/lib/models/card.dart @@ -0,0 +1,68 @@ +import 'package:powersync/sqlite3.dart' as sqlite; +import 'package:trelloappclone_flutter/models/card_label.dart'; + +class Cardlist { + Cardlist({ + required this.id, + required this.workspaceId, + required this.listId, + required this.userId, + required this.name, + this.description, + this.startDate, + this.dueDate, + required this.rank, + this.attachment, + this.archived, + this.checklist, + this.comments, + this.cardLabels, + }); + + final String id; + + final String workspaceId; + + String listId; + + final String userId; + + String name; + + String? description; + + final DateTime? startDate; + + final DateTime? dueDate; + + int rank; + + final bool? attachment; + + final bool? archived; + + final bool? checklist; + + final bool? comments; + + List? cardLabels; + + factory Cardlist.fromRow(sqlite.Row row) { + return Cardlist( + id: row['id'], + workspaceId: row['workspaceId'], + listId: row['listId'], + userId: row['userId'], + name: row['name'], + description: row['description'], + startDate: + row['startDate'] != null ? DateTime.parse(row['startDate']) : null, + dueDate: row['dueDate'] != null ? DateTime.parse(row['dueDate']) : null, + rank: row['rank'], + attachment: row['attachment'] == 1, + archived: row['archived'] == 1, + checklist: row['checklist'] == 1, + comments: row['comments'] == 1, + cardLabels: []); + } +} diff --git a/demos/supabase-trello/lib/models/card_label.dart b/demos/supabase-trello/lib/models/card_label.dart new file mode 100644 index 00000000..6016e150 --- /dev/null +++ b/demos/supabase-trello/lib/models/card_label.dart @@ -0,0 +1,34 @@ +import 'package:powersync/sqlite3.dart' as sqlite; + +class CardLabel { + final String id; + + final String cardId; + + final String boardId; + + final String workspaceId; + + final String boardLabelId; + + final DateTime dateCreated; + + CardLabel({ + required this.id, + required this.cardId, + required this.boardId, + required this.workspaceId, + required this.boardLabelId, + required this.dateCreated, + }); + + factory CardLabel.fromRow(sqlite.Row row) { + return CardLabel( + id: row['id'], + cardId: row['cardId'], + boardId: row['boardId'], + workspaceId: row['workspaceId'], + boardLabelId: row['boardLabelId'], + dateCreated: DateTime.parse(row['dateCreated'])); + } +} diff --git a/demos/supabase-trello/lib/models/checklist.dart b/demos/supabase-trello/lib/models/checklist.dart new file mode 100644 index 00000000..afbc969b --- /dev/null +++ b/demos/supabase-trello/lib/models/checklist.dart @@ -0,0 +1,30 @@ +import 'package:powersync/sqlite3.dart' as sqlite; + +class Checklist { + Checklist({ + required this.id, + required this.workspaceId, + required this.cardId, + required this.name, + required this.status, + }); + + final String id; + + final String workspaceId; + + final String cardId; + + final String name; + + bool status; + + factory Checklist.fromRow(sqlite.Row row) { + return Checklist( + id: row['id'], + workspaceId: row['workspaceId'], + cardId: row['cardId'], + name: row['name'], + status: row['status'] == 1); + } +} diff --git a/demos/supabase-trello/lib/models/comment.dart b/demos/supabase-trello/lib/models/comment.dart new file mode 100644 index 00000000..878f47ae --- /dev/null +++ b/demos/supabase-trello/lib/models/comment.dart @@ -0,0 +1,30 @@ +import 'package:powersync/sqlite3.dart' as sqlite; + +class Comment { + Comment({ + required this.id, + required this.workspaceId, + required this.cardId, + required this.userId, + required this.description, + }); + + final String id; + + final String workspaceId; + + final String cardId; + + final String userId; + + final String description; + + factory Comment.fromRow(sqlite.Row row) { + return Comment( + id: row['id'], + workspaceId: row['workspaceId'], + cardId: row['cardId'], + userId: row['userId'], + description: row['description']); + } +} diff --git a/demos/supabase-trello/lib/models/listboard.dart b/demos/supabase-trello/lib/models/listboard.dart new file mode 100644 index 00000000..cc5c9207 --- /dev/null +++ b/demos/supabase-trello/lib/models/listboard.dart @@ -0,0 +1,44 @@ +import 'package:powersync/sqlite3.dart' as sqlite; +import 'card.dart'; + +class Listboard { + Listboard({ + required this.id, + required this.workspaceId, + required this.boardId, + required this.userId, + required this.name, + this.archived, + this.cards, + required this.order, + }); + + final String id; + + final String workspaceId; + + final String boardId; + + final String userId; + + final String name; + + final bool? archived; + + final int order; + + List? cards; + + factory Listboard.fromRow(sqlite.Row row) { + return Listboard( + id: row['id'], + workspaceId: row['workspaceId'], + boardId: row['boardId'], + userId: row['userId'], + name: row['name'], + archived: row['archived'] == 1, + order: row['listOrder'], + cards: [] + ); + } +} diff --git a/demos/supabase-trello/lib/models/member.dart b/demos/supabase-trello/lib/models/member.dart new file mode 100644 index 00000000..ef90436b --- /dev/null +++ b/demos/supabase-trello/lib/models/member.dart @@ -0,0 +1,30 @@ +import 'package:powersync/sqlite3.dart' as sqlite; + +class Member { + Member({ + required this.id, + required this.workspaceId, + required this.userId, + required this.name, + required this.role, + }); + + final String id; + + final String workspaceId; + + final String userId; + + final String name; + + final String role; + + factory Member.fromRow(sqlite.Row row) { + return Member( + id: row['id'], + workspaceId: row['workspaceId'], + userId: row['userId'], + name: row['name'], + role: row['role']); + } +} diff --git a/demos/supabase-trello/lib/models/models.dart b/demos/supabase-trello/lib/models/models.dart new file mode 100644 index 00000000..c3c8e939 --- /dev/null +++ b/demos/supabase-trello/lib/models/models.dart @@ -0,0 +1,12 @@ +export 'activity.dart'; +export 'attachment.dart'; +export 'board.dart'; +export 'card.dart'; +export 'checklist.dart'; +export 'comment.dart'; +export 'listboard.dart'; +export 'member.dart'; +export 'user.dart'; +export 'workspace.dart'; +export 'board_label.dart'; +export 'card_label.dart'; \ No newline at end of file diff --git a/demos/supabase-trello/lib/models/schema.dart b/demos/supabase-trello/lib/models/schema.dart new file mode 100644 index 00000000..b093680e --- /dev/null +++ b/demos/supabase-trello/lib/models/schema.dart @@ -0,0 +1,149 @@ +import 'package:powersync/powersync.dart'; + +const schema = Schema(([ + //class: Activity + Table('activity', [ + Column.text('workspaceId'), + Column.text('boardId'), + Column.text('userId'), + Column.text('cardId'), + Column.text('description'), + Column.text('dateCreated'), + ], indexes: [ + Index('board', [IndexedColumn('boardId')]), + Index('user', [IndexedColumn('userId')]), + Index('card', [IndexedColumn('cardId')]) + ]), + //class: Attachment + Table('attachment', [ + Column.text('workspaceId'), + Column.text('userId'), + Column.text('cardId'), + Column.text('attachment'), + ], indexes: [ + Index('user', [IndexedColumn('userId')]), + ]), + //class: Board + Table('board', [ + Column.text('workspaceId'), + Column.text('userId'), + Column.text('name'), + Column.text('description'), + Column.text('visibility'), + Column.text('background'), + Column.integer('starred'), + Column.integer('enableCover'), + Column.integer('watch'), + Column.integer('availableOffline'), + Column.text('label'), + Column.text('emailAddress'), + Column.integer('commenting'), + Column.integer('memberType'), + Column.integer('pinned'), + Column.integer('selfJoin'), + Column.integer('close'), + ], indexes: [ + Index('workspace', [IndexedColumn('workspaceId')]), + Index('user', [IndexedColumn('userId')]), + ]), + //class: Cardlist + Table('card', [ + Column.text('workspaceId'), + Column.text('listId'), + Column.text('userId'), + Column.text('name'), + Column.text('description'), + Column.text('startDate'), + Column.text('dueDate'), + Column.integer('rank'), + Column.integer('attachment'), + Column.integer('archived'), + Column.integer('checklist'), + Column.integer('comments'), + ], indexes: [ + Index('list', [IndexedColumn('listId')]), + Index('user', [IndexedColumn('userId')]), + ]), + //class: Checklist + Table('checklist', [ + Column.text('workspaceId'), + Column.text('cardId'), + Column.text('name'), + Column.integer('status'), + ], indexes: [ + Index('card', [IndexedColumn('cardId')]), + ]), + //class: Comment + Table('comment', [ + Column.text('workspaceId'), + Column.text('cardId'), + Column.text('userId'), + Column.text('description'), + ], indexes: [ + Index('card', [IndexedColumn('cardId')]), + Index('user', [IndexedColumn('userId')]), + ]), + //class: Listboard + Table('listboard', [ + Column.text('workspaceId'), + Column.text('boardId'), + Column.text('userId'), + Column.text('name'), + Column.integer('archived'), + Column.integer('listOrder'), + ], indexes: [ + Index('board', [IndexedColumn('boardId')]), + Index('user', [IndexedColumn('userId')]), + ]), + //class: Member + Table('member', [ + Column.text('workspaceId'), + Column.text('userId'), + Column.text('name'), + Column.text('role'), + ], indexes: [ + Index('user', [IndexedColumn('userId')]), + ]), + //class: User + // table: trellouser + // fields: + // name: String? + // email: String + // password: String + Table('trellouser', [ + Column.text('name'), + Column.text('email'), + Column.text('password'), + ], indexes: [ + Index('email', [IndexedColumn('email')]), + ]), + //class: Workspace + Table('workspace', [ + Column.text('userId'), + Column.text('name'), + Column.text('description'), + Column.text('visibility'), + ], indexes: [ + Index('user', [IndexedColumn('userId')]), + ]), + // class: BoardLabel + Table('board_label', [ + Column.text('boardId'), + Column.text('workspaceId'), + Column.text('title'), + Column.text('color'), + Column.text('dateCreated'), + ], indexes: [ + Index('board', [IndexedColumn('boardId')]), + ]), + // class: CardLabel + Table('card_label', [ + Column.text('cardId'), + Column.text('boardLabelId'), + Column.text('boardId'), + Column.text('workspaceId'), + Column.text('dateCreated'), + ], indexes: [ + Index('card', [IndexedColumn('cardId')]), + ]) +])); diff --git a/demos/supabase-trello/lib/models/user.dart b/demos/supabase-trello/lib/models/user.dart new file mode 100644 index 00000000..0eec95dc --- /dev/null +++ b/demos/supabase-trello/lib/models/user.dart @@ -0,0 +1,26 @@ +import 'package:powersync/sqlite3.dart' as sqlite; + +class TrelloUser { + TrelloUser({ + required this.id, + this.name, + required this.email, + required this.password, + }); + + final String id; + + final String? name; + + final String email; + + final String password; + + factory TrelloUser.fromRow(sqlite.Row row) { + return TrelloUser( + id: row['id'], + name: row['name'], + email: row['email'], + password: row['password']); + } +} diff --git a/demos/supabase-trello/lib/models/workspace.dart b/demos/supabase-trello/lib/models/workspace.dart new file mode 100644 index 00000000..67a72574 --- /dev/null +++ b/demos/supabase-trello/lib/models/workspace.dart @@ -0,0 +1,36 @@ +import 'package:powersync/sqlite3.dart' as sqlite; + +import 'member.dart'; + +class Workspace { + Workspace({ + required this.id, + required this.userId, + required this.name, + required this.description, + required this.visibility, + this.members, + }); + + final String id; + + final String userId; + + final String name; + + final String description; + + final String visibility; + + List? members; + + factory Workspace.fromRow(sqlite.Row row) { + return Workspace( + id: row['id'], + userId: row['userId'], + name: row['name'], + description: row['description'], + visibility: row['visibility'], + members: [] + );} +} diff --git a/demos/supabase-trello/lib/protocol/data_client.dart b/demos/supabase-trello/lib/protocol/data_client.dart new file mode 100644 index 00000000..47acf183 --- /dev/null +++ b/demos/supabase-trello/lib/protocol/data_client.dart @@ -0,0 +1,854 @@ +library powersync_client; + +import 'package:powersync/powersync.dart'; + +import "../models/models.dart"; +import 'powersync.dart'; + +export "../models/models.dart"; + +class _Repository { + DataClient client; + + _Repository(this.client); + + int boolAsInt(bool? value) { + if (value == null) { + return 0; + } + return value ? 1 : 0; + } +} + +class _ActivityRepository extends _Repository { + _ActivityRepository(DataClient client) : super(client); + + Future createActivity(Activity activity) async { + final results = await client.getDBExecutor().execute('''INSERT INTO + activity(id, workspaceId, boardId, userId, cardId, description, dateCreated) + VALUES(?, ?, ?, ?, ?, ?, datetime()) + RETURNING *''', [ + activity.id, + activity.workspaceId, + activity.boardId, + activity.userId, + activity.cardId, + activity.description + ]); + return results.isNotEmpty; + } + + Future> getActivities(Cardlist cardlist) async { + final results = await client.getDBExecutor().execute(''' + SELECT * FROM activity WHERE cardId = ? ORDER BY dateCreated DESC + ''', [cardlist.id]); + return results.map((row) => Activity.fromRow(row)).toList(); + } +} + +class _AttachmentRepository extends _Repository { + _AttachmentRepository(DataClient client) : super(client); + + Future addAttachment(Attachment attachment) async { + final results = await client.getDBExecutor().execute('''INSERT INTO + attachment(id, workspaceId, userId, cardId, attachment) + VALUES(?, ?, ?, ?, ?) + RETURNING *''', [ + attachment.id, + attachment.workspaceId, + attachment.userId, + attachment.cardId, + attachment.attachment + ]); + if (results.isEmpty) { + throw Exception("Failed to add attachment"); + } else { + return Attachment.fromRow(results.first); + } + } + + //TODO: need to replace with file upload service calls to Supabase + Future getUploadDescription(String path) => + Future.value('TODO: implement getUploadDescription'); + + Future verifyUpload(String path) => Future.value(false); +} + +class _BoardRepository extends _Repository { + _BoardRepository(DataClient client) : super(client); + + String get insertQuery => ''' + INSERT INTO + board(id, userId, workspaceId, name, description, visibility, background, starred, enableCover, watch, availableOffline, label, emailAddress, commenting, memberType, pinned, selfJoin, close) + VALUES(?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12, ?13, ?14, ?15, ?16, ?17, ?18) + '''; + + String get updateQuery => ''' + UPDATE board + set userId = ?1, workspaceId = ?2, name = ?3, description = ?4, visibility = ?5, background = ?6, starred = ?7, enableCover = ?8, watch = ?9, availableOffline = ?10, label = ?11, emailAddress = ?12, commenting = ?13, memberType = ?14, pinned = ?15, selfJoin = ?16, close = ?17 + WHERE id = ?18 + '''; + + Future createBoard(Board board) async { + final results = await client.getDBExecutor().execute(''' + $insertQuery RETURNING *''', [ + board.id, + board.userId, + board.workspaceId, + board.name, + board.description, + board.visibility, + board.background, + boolAsInt(board.starred), + boolAsInt(board.enableCover), + boolAsInt(board.watch), + boolAsInt(board.availableOffline), + board.label, + board.emailAddress, + board.commenting, + board.memberType, + boolAsInt(board.pinned), + boolAsInt(board.selfJoin), + boolAsInt(board.close) + ]); + if (results.isEmpty) { + throw Exception("Failed to add Board"); + } else { + return Board.fromRow(results.first); + } + } + + Future updateBoard(Board board) async { + await client.getDBExecutor().execute(updateQuery, [ + board.userId, + board.workspaceId, + board.name, + board.description, + board.visibility, + board.background, + boolAsInt(board.starred), + boolAsInt(board.enableCover), + boolAsInt(board.watch), + boolAsInt(board.availableOffline), + board.label, + board.emailAddress, + board.commenting, + board.memberType, + boolAsInt(board.pinned), + boolAsInt(board.selfJoin), + boolAsInt(board.close), + board.id + ]); + return true; + } + + Future deleteBoard(Board board) async { + await client + .getDBExecutor() + .execute('DELETE FROM board WHERE id = ?', [board.id]); + return true; + } + + Future getWorkspaceForBoard(Board board) async { + final results = await client.getDBExecutor().execute(''' + SELECT * FROM workspace WHERE id = ? + ''', [board.workspaceId]); + return results.map((row) => Workspace.fromRow(row)).firstOrNull; + } + + Future> getAllBoards() async { + final results = await client.getDBExecutor().execute(''' + SELECT * FROM board + '''); + return results.map((row) => Board.fromRow(row)).toList(); + } +} + +class _CardlistRepository extends _Repository { + _CardlistRepository(DataClient client) : super(client); + + String get insertQuery => ''' + INSERT INTO + card(id, workspaceId, listId, userId, name, description, startDate, dueDate, attachment, archived, checklist, comments, rank) + VALUES(?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12, ?13) + '''; + + Future createCard(Cardlist cardlist) async { + final results = + await client.getDBExecutor().execute('$insertQuery RETURNING *', [ + cardlist.id, + cardlist.workspaceId, + cardlist.listId, + cardlist.userId, + cardlist.name, + cardlist.description, + cardlist.startDate, + cardlist.dueDate, + boolAsInt(cardlist.attachment), + boolAsInt(cardlist.archived), + boolAsInt(cardlist.checklist), + boolAsInt(cardlist.comments), + cardlist.rank, + ]); + if (results.isEmpty) { + throw Exception("Failed to add Cardlist"); + } else { + return Cardlist.fromRow(results.first); + } + } + + String get updateQuery => ''' + UPDATE card + set listId = ?1, userId = ?2, name = ?3, description = ?4, startDate = ?5, dueDate = ?6, attachment = ?7, archived = ?8, checklist = ?9, comments = ?10, rank = ?11 + WHERE id = ?12 + '''; + + Future updateCard(Cardlist cardlist) async { + await client.getDBExecutor().execute(updateQuery, [ + cardlist.listId, + cardlist.userId, + cardlist.name, + cardlist.description, + cardlist.startDate, + cardlist.dueDate, + boolAsInt(cardlist.attachment), + boolAsInt(cardlist.archived), + boolAsInt(cardlist.checklist), + boolAsInt(cardlist.comments), + cardlist.rank, + cardlist.id + ]); + return true; + } + + Future deleteCard(Cardlist cardlist) async { + await client + .getDBExecutor() + .execute('DELETE FROM card WHERE id = ?', [cardlist.id]); + return true; + } + + Future> getCardsforList(String listId) async { + final results = await client.getDBExecutor().execute(''' + SELECT * FROM card WHERE listId = ? AND archived = 0 ORDER BY rank ASC + ''', [listId]); + return results.map((row) => Cardlist.fromRow(row)).toList(); + } +} + +class _CheckListRepository extends _Repository { + _CheckListRepository(DataClient client) : super(client); + + String get insertQuery => ''' + INSERT INTO + checklist(id, workspaceId, cardId, name, status) + VALUES(?1, ?2, ?3, ?4, ?5) + '''; + + Future createChecklist(Checklist checklist) async { + final results = + await client.getDBExecutor().execute('$insertQuery RETURNING *', [ + checklist.id, + checklist.workspaceId, + checklist.cardId, + checklist.name, + boolAsInt(checklist.status) + ]); + if (results.isEmpty) { + throw Exception("Failed to add Checklist"); + } else { + return Checklist.fromRow(results.first); + } + } + + String get updateQuery => ''' + UPDATE checklist + set cardId = ?1, name = ?2, status = ?3 + WHERE id = ?4 + '''; + + Future updateChecklist(Checklist checklist) async { + await client.getDBExecutor().execute(updateQuery, [ + checklist.cardId, + checklist.name, + boolAsInt(checklist.status), + checklist.id + ]); + return true; + } + + Future deleteChecklistItem(Checklist checklist) async { + await client + .getDBExecutor() + .execute('DELETE FROM checklist WHERE id = ?', [checklist.id]); + return true; + } + + Future> getChecklists(Cardlist crd) async { + final results = await client.getDBExecutor().execute(''' + SELECT * FROM checklist WHERE cardId = ? + ''', [crd.id]); + return results.map((row) => Checklist.fromRow(row)).toList(); + } + + Future deleteChecklist(Cardlist crd) async { + final results = await client.getDBExecutor().execute(''' + SELECT COUNT(*) FROM checklist WHERE cardId = ? + ''', [crd.id]); + await client + .getDBExecutor() + .execute('DELETE FROM checklist WHERE cardId = ?', [crd.id]); + return results.first['count']; + } +} + +class _CommentRepository extends _Repository { + _CommentRepository(DataClient client) : super(client); + + String get insertQuery => ''' + INSERT INTO + comment(id, workspaceId, cardId, userId, description) + VALUES(?1, ?2, ?3, ?4, ?5) + '''; + + Future createComment(Comment comment) async { + final results = + await client.getDBExecutor().execute('$insertQuery RETURNING *', [ + comment.id, + comment.workspaceId, + comment.cardId, + comment.userId, + comment.description + ]); + if (results.isEmpty) { + throw Exception("Failed to add Comment"); + } else { + return Comment.fromRow(results.first); + } + } + + String get updateQuery => ''' + UPDATE comment + set cardId = ?1, userId = ?2, description = ?3 + WHERE id = ?4 + '''; + + Future updateComment(Comment comment) async { + await client.getDBExecutor().execute(updateQuery, + [comment.cardId, comment.userId, comment.description, comment.id]); + return true; + } +} + +class _ListboardRepository extends _Repository { + _ListboardRepository(DataClient client) : super(client); + + Future> getListsByBoard({required String boardId}) async { + //first we get the listboards + final results = await client.getDBExecutor().execute(''' + SELECT * FROM listboard WHERE boardId = ? + ''', [boardId]); + List lists = + results.map((row) => Listboard.fromRow(row)).toList(); + + //then we set the cards for each listboard + for (Listboard list in lists) { + List cards = await client.card.getCardsforList(list.id); + list.cards = cards; + + for (Cardlist card in list.cards!) { + List labels = await client.cardLabel.getCardLabels(card); + card.cardLabels = labels; + } + } + + return lists; + } + + Stream> watchListsByBoard({required String boardId}) { + //first we get the listboards + return client.getDBExecutor().watch(''' + SELECT * FROM listboard WHERE boardId = ? ORDER BY listOrder ASC + ''', parameters: [boardId]).asyncMap((event) async { + List lists = + event.map((row) => Listboard.fromRow(row)).toList(); + + //then we set the cards for each listboard + for (Listboard list in lists) { + List cards = await client.card.getCardsforList(list.id); + list.cards = cards; + + for (Cardlist card in list.cards!) { + List labels = await client.cardLabel.getCardLabels(card); + card.cardLabels = labels; + } + } + + return lists; + }); + } + + String get insertQuery => ''' + INSERT INTO + listboard(id, workspaceId, boardId, userId, name, archived, listOrder) + VALUES(?1, ?2, ?3, ?4, ?5, ?6, ?7) + '''; + + Future createList(Listboard lst) async { + final results = + await client.getDBExecutor().execute('$insertQuery RETURNING *', [ + lst.id, + lst.workspaceId, + lst.boardId, + lst.userId, + lst.name, + boolAsInt(lst.archived), + lst.order + ]); + if (results.isEmpty) { + throw Exception("Failed to add Listboard"); + } else { + return Listboard.fromRow(results.first); + } + } + + String get updateQuery => ''' + UPDATE listboard + set listOrder = ?1 + WHERE id = ?2 + '''; + + Future updateListOrder(String listId, int newOrder) async { + await client.getDBExecutor().execute(updateQuery, [newOrder, listId]); + } + + /// Archive cards in and return how many were archived + /// This happens in a transaction + Future archiveCardsInList(Listboard list) async { + if (list.cards == null || list.cards!.isEmpty) { + return 0; + } + + //start transaction + return client.getDBExecutor().writeTransaction((sqlContext) async { + List cards = list.cards!; + int numCards = cards.length; + + //we set each of the cards in the list to archived = true + sqlContext.executeBatch(''' + UPDATE card + SET archived = 1 + WHERE id = ? + ''', cards.map((card) => [card.id]).toList()); + + //touch listboard to trigger update via stream listeners on Listboard + sqlContext.execute(''' + UPDATE listboard + SET archived = 0 + WHERE id = ? + ''', [list.id]); + + list.cards = []; + return numCards; + //end of transaction + }); + } +} + +class _MemberRepository extends _Repository { + _MemberRepository(DataClient client) : super(client); + + String get insertQuery => ''' + INSERT INTO + member(id, workspaceId, userId, name, role) + VALUES(?1, ?2, ?3, ?4, ?5) + '''; + + Future addMember(Member member) async { + final results = await client.getDBExecutor().execute( + '$insertQuery RETURNING *', [ + member.id, + member.workspaceId, + member.userId, + member.name, + member.role + ]); + if (results.isEmpty) { + throw Exception("Failed to add Member"); + } else { + return Member.fromRow(results.first); + } + } + + Future> getMembersByWorkspace( + {required String workspaceId}) async { + final results = await client.getDBExecutor().execute(''' + SELECT * FROM member WHERE workspaceId = ? + ''', [workspaceId]); + return results.map((row) => Member.fromRow(row)).toList(); + } + + Future> getInformationOfMembers(List members) async { + List users = []; + for (Member member in members) { + TrelloUser? user = await client.user.getUserById(userId: member.userId); + if (user != null) { + users.add(user); + } + } + return users; + } + + Future deleteMember(Member member, Workspace workspace) async { + //delete member + await client.getDBExecutor().execute( + 'DELETE FROM member WHERE workspaceId = ? AND id = ?', + [workspace.id, member.id]); + + //update workspace list with new members + List newMembersList = + await getMembersByWorkspace(workspaceId: workspace.id); + workspace.members = newMembersList; + return workspace; + } +} + +class _UserRepository extends _Repository { + _UserRepository(DataClient client) : super(client); + + String get insertQuery => ''' + INSERT INTO + trellouser(id, name, email, password) + VALUES(?1, ?2, ?3, ?4) + '''; + + Future createUser(TrelloUser user) async { + final results = await client.getDBExecutor().execute( + '$insertQuery RETURNING *', + [user.id, user.name, user.email, user.password]); + if (results.isEmpty) { + throw Exception("Failed to add User"); + } else { + return TrelloUser.fromRow(results.first); + } + } + + /// We excpect only one record in the local trellouser table + /// if somebody has logged in and not logged out again + Future getUser() async { + final results = await client.getDBExecutor().execute(''' + SELECT * FROM trellouser'''); + return results.map((row) => TrelloUser.fromRow(row)).firstOrNull; + } + + Future getUserById({required String userId}) async { + final results = await client.getDBExecutor().execute(''' + SELECT * FROM trellouser WHERE id = ? + ''', [userId]); + return results.map((row) => TrelloUser.fromRow(row)).firstOrNull; + } + + Future checkUserExists(String email) async { + final results = await client.getDBExecutor().execute(''' + SELECT * FROM trellouser WHERE email = ? + ''', [email]); + return results.map((row) => TrelloUser.fromRow(row)).firstOrNull; + } +} + +class _WorkspaceRepository extends _Repository { + _WorkspaceRepository(DataClient client) : super(client); + + String get insertQuery => ''' + INSERT INTO + workspace(id, userId, name, description, visibility) + VALUES(?1, ?2, ?3, ?4, ?5) + '''; + + Future createWorkspace(Workspace workspace) async { + final results = + await client.getDBExecutor().execute('$insertQuery RETURNING *', [ + workspace.id, + workspace.userId, + workspace.name, + workspace.description, + workspace.visibility + ]); + return Workspace.fromRow(results.first); + } + + Future> getWorkspacesByUser({required String userId}) async { + //First we get the workspaces + final results = await client.getDBExecutor().execute(''' + SELECT * FROM workspace WHERE userId = ? + ''', [userId]); + List workspaces = + results.map((row) => Workspace.fromRow(row)).toList(); + + //Then we get the members for each workspace + for (Workspace workspace in workspaces) { + List members = + await client.member.getMembersByWorkspace(workspaceId: workspace.id); + workspace.members = members; + } + + return workspaces; + } + + Stream> watchWorkspacesByUser({required String userId}) { + //First we get the workspaces + return client.getDBExecutor().watch( + ''' + SELECT * FROM workspace + ''', + ).asyncMap((event) async { + List workspaces = + event.map((row) => Workspace.fromRow(row)).toList(); + + //Then we get the members for each workspace + for (Workspace workspace in workspaces) { + List members = await client.member + .getMembersByWorkspace(workspaceId: workspace.id); + workspace.members = members; + } + return workspaces; + }); + } + + Future getWorkspaceById({required String workspaceId}) async { + final results = await client.getDBExecutor().execute(''' + SELECT * FROM workspace WHERE id = ? + ''', [workspaceId]); + Workspace workspace = Workspace.fromRow(results.first); + List members = + await client.member.getMembersByWorkspace(workspaceId: workspaceId); + workspace.members = members; + return workspace; + } + + Future> getBoardsByWorkspace( + {required String workspaceId}) async { + final results = await client.getDBExecutor().execute(''' + SELECT * FROM board WHERE workspaceId = ? + ''', [workspaceId]); + + List boards = results.map((row) => Board.fromRow(row)).toList(); + + for (Board board in boards) { + List labels = await client.boardLabel.getBoardLabels(board); + board.boardLabels = labels; + } + + return boards; + } + + Stream> watchBoardsByWorkspace({required String workspaceId}) { + return client.getDBExecutor().watch(''' + SELECT * FROM board WHERE workspaceId = ? + ''', parameters: [workspaceId]).asyncMap((event) async { + List boards = event.map((row) => Board.fromRow(row)).toList(); + + for (Board board in boards) { + List labels = await client.boardLabel.getBoardLabels(board); + board.boardLabels = labels; + } + + return boards; + }); + } + + Future updateWorkspace(Workspace workspace) async { + await client.getDBExecutor().execute(''' + UPDATE workspace + set userId = ?1, name = ?2, description = ?3, visibility = ?4 + WHERE id = ?5 + ''', [ + workspace.userId, + workspace.name, + workspace.description, + workspace.visibility, + workspace.id + ]); + return true; + } + + Future deleteWorkspace(Workspace workspace) async { + await client + .getDBExecutor() + .execute('DELETE FROM workspace WHERE id = ?', [workspace.id]); + return true; + } +} + +class _BoardLabelRepository extends _Repository { + _BoardLabelRepository(DataClient client) : super(client); + + Future createBoardLabel(BoardLabel boardLabel) async { + final results = await client.getDBExecutor().execute('''INSERT INTO + board_label(id, boardId, workspaceId, title, color, dateCreated) + VALUES(?, ?, ?, ?, ?, datetime()) + RETURNING *''', [ + boardLabel.id, + boardLabel.boardId, + boardLabel.workspaceId, + boardLabel.title, + boardLabel.color + ]); + if (results.isEmpty) { + throw Exception("Failed to add BoardLabel"); + } else { + return BoardLabel.fromRow(results.first); + } + } + + Future updateBoardLabel(BoardLabel boardLabel) async { + await client.getDBExecutor().execute(''' + UPDATE board_label + set title = ?1 + WHERE id = ?2 + ''', [boardLabel.title, boardLabel.id]); + return true; + } + + Future> getBoardLabels(Board board) async { + final results = await client.getDBExecutor().execute(''' + SELECT * FROM board_label WHERE boardId = ? ORDER BY dateCreated DESC + ''', [board.id]); + return results.map((row) => BoardLabel.fromRow(row)).toList(); + } +} + +class _CardLabelRepository extends _Repository { + _CardLabelRepository(DataClient client) : super(client); + + Future createCardLabel(CardLabel cardLabel) async { + final results = await client.getDBExecutor().execute('''INSERT INTO + card_label(id, cardId, boardId, workspaceId, boardLabelId, dateCreated) + VALUES(?, ?, ?, ?, ?, datetime()) + RETURNING *''', [ + cardLabel.id, + cardLabel.cardId, + cardLabel.boardId, + cardLabel.workspaceId, + cardLabel.boardLabelId, + ]); + if (results.isEmpty) { + throw Exception("Failed to add CardLabel"); + } else { + return CardLabel.fromRow(results.first); + } + } + + Future deleteCardLabel(BoardLabel boardLabel) async { + await client.getDBExecutor().execute( + 'DELETE FROM card_label WHERE boardLabelId = ?', [boardLabel.id]); + return true; + } + + Future> getCardLabels(Cardlist card) async { + final results = await client.getDBExecutor().execute(''' + SELECT * FROM card_label WHERE cardId = ? ORDER BY dateCreated DESC + ''', [card.id]); + return results.map((row) => CardLabel.fromRow(row)).toList(); + } +} + +class DataClient { + late final _ActivityRepository activity; + late final _AttachmentRepository attachment; + late final _BoardRepository board; + late final _CardlistRepository card; + late final _CheckListRepository checklist; + late final _CommentRepository comment; + late final _ListboardRepository listboard; + late final _MemberRepository member; + late final _UserRepository user; + late final _WorkspaceRepository workspace; + late final _BoardLabelRepository boardLabel; + late final _CardLabelRepository cardLabel; + + late PowerSyncClient _powerSyncClient; + + DataClient() { + activity = _ActivityRepository(this); + attachment = _AttachmentRepository(this); + board = _BoardRepository(this); + card = _CardlistRepository(this); + checklist = _CheckListRepository(this); + comment = _CommentRepository(this); + listboard = _ListboardRepository(this); + member = _MemberRepository(this); + user = _UserRepository(this); + workspace = _WorkspaceRepository(this); + boardLabel = _BoardLabelRepository(this); + cardLabel = _CardLabelRepository(this); + } + + Future initialize() async { + _powerSyncClient = PowerSyncClient(); + await _powerSyncClient.initialize(); + } + + PowerSyncDatabase getDBExecutor() { + return _powerSyncClient.getDBExecutor(); + } + + bool isLoggedIn() { + return _powerSyncClient.isLoggedIn(); + } + + String? getUserId() { + return _powerSyncClient.getUserId(); + } + + Future getLoggedInUser() async { + String? userId = _powerSyncClient.getUserId(); + if (userId != null) { + return user.getUserById(userId: userId); + } else + return null; + } + + Future logOut() async { + await _powerSyncClient.logout(); + } + + Future loginWithEmail(String email, String password) async { + String userId = await _powerSyncClient.loginWithEmail(email, password); + + TrelloUser? storedUser = await user.getUserById(userId: userId); + if (storedUser == null) { + storedUser = await user.createUser(TrelloUser( + id: userId, + name: email.split('@')[0], + email: email, + password: password)); + } + return storedUser; + } + + Future signupWithEmail( + String name, String email, String password) async { + TrelloUser? storedUser = await user.checkUserExists(email); + if (storedUser != null) { + throw new Exception('User for email already exists. Use Login instead.'); + } + return _powerSyncClient.signupWithEmail(name, email, password); + } + + SyncStatus getCurrentSyncStatus() { + return _powerSyncClient.currentStatus; + } + + Stream getStatusStream() { + return _powerSyncClient.statusStream; + } + + Future switchToOfflineMode() async { + await _powerSyncClient.switchToOfflineMode(); + } + + Future switchToOnlineMode() async { + await _powerSyncClient.switchToOnlineMode(); + } +} diff --git a/demos/supabase-trello/lib/protocol/powersync.dart b/demos/supabase-trello/lib/protocol/powersync.dart new file mode 100644 index 00000000..af7d0a56 --- /dev/null +++ b/demos/supabase-trello/lib/protocol/powersync.dart @@ -0,0 +1,269 @@ +// This file performs setup of the PowerSync database +import 'package:flutter_dotenv/flutter_dotenv.dart'; +import 'package:logging/logging.dart'; +import 'package:path/path.dart'; +import 'package:path_provider/path_provider.dart'; +import 'package:powersync/powersync.dart'; +import 'package:supabase_flutter/supabase_flutter.dart'; +import 'package:trelloappclone_flutter/models/user.dart'; + +import '../models/schema.dart'; + +final log = Logger('powersync-supabase'); + +/// Postgres Response codes that we cannot recover from by retrying. +final List fatalResponseCodes = [ + // Class 22 — Data Exception + // Examples include data type mismatch. + RegExp(r'^22...$'), + // Class 23 — Integrity Constraint Violation. + // Examples include NOT NULL, FOREIGN KEY and UNIQUE violations. + RegExp(r'^23...$'), + // INSUFFICIENT PRIVILEGE - typically a row-level security violation + RegExp(r'^42501$'), +]; + +/// Use Supabase for authentication and data upload. +class SupabaseConnector extends PowerSyncBackendConnector { + PowerSyncDatabase db; + + Future? _refreshFuture; + + SupabaseConnector(this.db); + + /// Get a Supabase token to authenticate against the PowerSync instance. + @override + Future fetchCredentials() async { + // Wait for pending session refresh if any + await _refreshFuture; + + // Use Supabase token for PowerSync + final existingSession = Supabase.instance.client.auth.currentSession; + if (existingSession?.accessToken == null) { + // Not logged in + return null; + } + + // Force session refresh. + final authResponse = await Supabase.instance.client.auth.refreshSession(); + final session = authResponse.session; + if (session == null) { + // Probably shouldn't happen + return null; + } + + // Use the access token to authenticate against PowerSync + final token = session.accessToken; + + // userId and expiresAt are for debugging purposes only + final userId = session.user.id; + final expiresAt = session.expiresAt == null + ? null + : DateTime.fromMillisecondsSinceEpoch(session.expiresAt! * 1000); + return PowerSyncCredentials( + endpoint: dotenv.env['POWERSYNC_URL']!, + token: token, + userId: userId, + expiresAt: expiresAt); + } + + @override + void invalidateCredentials() { + // Trigger a session refresh if auth fails on PowerSync. + // Generally, sessions should be refreshed automatically by Supabase. + // However, in some cases it can be a while before the session refresh is + // retried. We attempt to trigger the refresh as soon as we get an auth + // failure on PowerSync. + // + // This could happen if the device was offline for a while and the session + // expired, and nothing else attempt to use the session it in the meantime. + // + // Timeout the refresh call to avoid waiting for long retries, + // and ignore any errors. Errors will surface as expired tokens. + _refreshFuture = Supabase.instance.client.auth + .refreshSession() + .timeout(const Duration(seconds: 5)) + .then((response) => null, onError: (error) => null); + } + + // Upload pending changes to Supabase. + @override + Future uploadData(PowerSyncDatabase database) async { + // This function is called whenever there is data to upload, whether the + // device is online or offline. + // If this call throws an error, it is retried periodically. + final transaction = await database.getNextCrudTransaction(); + if (transaction == null) { + return; + } + + final rest = Supabase.instance.client.rest; + CrudEntry? lastOp; + try { + // Note: If transactional consistency is important, use database functions + // or edge functions to process the entire transaction in a single call. + for (var op in transaction.crud) { + lastOp = op; + + final table = rest.from(op.table); + if (op.op == UpdateType.put) { + var data = Map.of(op.opData!); + data['id'] = op.id; + await table.upsert(data); + } else if (op.op == UpdateType.patch) { + await table.update(op.opData!).eq('id', op.id); + } else if (op.op == UpdateType.delete) { + await table.delete().eq('id', op.id); + } + } + + // All operations successful. + await transaction.complete(); + } on PostgrestException catch (e) { + if (e.code != null && + fatalResponseCodes.any((re) => re.hasMatch(e.code!))) { + /// Instead of blocking the queue with these errors, + /// discard the (rest of the) transaction. + /// + /// Note that these errors typically indicate a bug in the application. + /// If protecting against data loss is important, save the failing records + /// elsewhere instead of discarding, and/or notify the user. + log.severe('Data upload error - discarding $lastOp', e); + await transaction.complete(); + } else { + // Error may be retryable - e.g. network error or temporary server error. + // Throwing an error here causes this call to be retried after a delay. + rethrow; + } + } + } +} + +class PowerSyncClient { + PowerSyncClient._(); + + static final PowerSyncClient _instance = PowerSyncClient._(); + + bool _isInitialized = false; + bool _offlineMode = false; + + late final PowerSyncDatabase _db; + + factory PowerSyncClient() { + return _instance; + } + + Future initialize({bool offlineMode = false}) async { + if (!_isInitialized) { + _offlineMode = offlineMode; + await dotenv.load(fileName: '.env'); + await _openDatabase(); + _isInitialized = true; + } + } + + PowerSyncDatabase getDBExecutor() { + if (!_isInitialized) { + throw Exception( + 'PowerSyncDatabase not initialized. Call initialize() first.'); + } + return _db; + } + + bool isLoggedIn() { + return Supabase.instance.client.auth.currentSession?.accessToken != null; + } + + /// id of the user currently logged in + String? getUserId() { + return Supabase.instance.client.auth.currentSession?.user.id; + } + + Future getDatabasePath() async { + final dir = await getApplicationSupportDirectory(); + return join(dir.path, 'powersync-trello-demo.db'); + } + + _loadSupabase() async { + await Supabase.initialize( + url: dotenv.env['SUPABASE_URL']!, + anonKey: dotenv.env['SUPABASE_ANON_KEY']!, + ); + } + + Future _openDatabase() async { + // Open the local database + _db = PowerSyncDatabase(schema: schema, path: await getDatabasePath()); + await _db.initialize(); + + await _loadSupabase(); + + if (isLoggedIn() && !_offlineMode) { + // If the user is already logged in, connect immediately. + // Otherwise, connect once logged in. + _db.connect(connector: SupabaseConnector(_db)); + } + + Supabase.instance.client.auth.onAuthStateChange.listen((data) async { + final AuthChangeEvent event = data.event; + if (event == AuthChangeEvent.signedIn) { + // Connect to PowerSync when the user is signed in + _db.connect(connector: SupabaseConnector(_db)); + } else if (event == AuthChangeEvent.signedOut) { + // Implicit sign out - disconnect, but don't delete data + await _db.disconnect(); + } + }); + } + + bool isOfflineMode() { + return _offlineMode; + } + + Future switchToOfflineMode() async { + log.info('Switching to Offline mode'); + _offlineMode = true; + await _db.disconnect(); + } + + Future switchToOnlineMode() async { + log.info('Switching to Online mode'); + _offlineMode = false; + if (isLoggedIn()) { + _db.connect(connector: SupabaseConnector(_db)); + } + } + + Future signupWithEmail( + String name, String email, String password) async { + AuthResponse authResponse = await Supabase.instance.client.auth + .signUp(email: email, password: password); + + return TrelloUser( + id: authResponse.user!.id, + name: name, + email: email, + password: password); + } + + Future loginWithEmail(String email, String password) async { + AuthResponse authResponse = await Supabase.instance.client.auth + .signInWithPassword(email: email, password: password); + + return authResponse.user!.id; + } + + /// Explicit sign out - clear database and log out. + Future logout() async { + if (!_isInitialized) { + throw Exception( + 'PowerSyncClient not initialized. Call initialize() first.'); + } + await Supabase.instance.client.auth.signOut(); + await _db.disconnectAndClear(); + } + + /// Getting current connection status + SyncStatus get currentStatus => _db.currentStatus; + Stream get statusStream => _db.statusStream; +} diff --git a/demos/supabase-trello/lib/utils/color.dart b/demos/supabase-trello/lib/utils/color.dart new file mode 100644 index 00000000..d4ea5f21 --- /dev/null +++ b/demos/supabase-trello/lib/utils/color.dart @@ -0,0 +1,6 @@ +import 'package:flutter/material.dart'; + +const brandColor = Color(0xff38b6ff); +const whiteShade = Color(0xfff0f0f0); +const dangerColor = Color(0xff800200); +const themeColor = Color(0xff02457a); diff --git a/demos/supabase-trello/lib/utils/config.dart b/demos/supabase-trello/lib/utils/config.dart new file mode 100644 index 00000000..7b10fea7 --- /dev/null +++ b/demos/supabase-trello/lib/utils/config.dart @@ -0,0 +1,44 @@ +import 'package:flutter/painting.dart'; + +const logo = "assets/trello-logo.png"; +const landingImage = "assets/landing.jpg"; +const backgrounds = [ + "#ADD8E6" + "#89CFF0", + "#0000FF", + "#7393B3", + "#088F8F", + "#0096FF", + "#5F9EA0", + "#0047AB", + "#6495ED", + "#00FFFF", + "#00008B", + "#6F8FAF", + "#1434A4", + "#7DF9FF", + "#6082B6", + "#00A36C", + "#3F00FF", + "#5D3FD3" +]; + +const listMenu = [ + "Add Card", + "Copy list", + "Move list", + "Watch", + "Sort by", + "Move all cards in this list", + "Archive all cards in this list", + "Archive list" +]; + +const labels = [ + Color(0xffADD8E6), + Color(0xff89CFF0), + Color(0xff0000FF), + Color(0xff7393B3) +]; + +enum Sign { signUp, logIn } diff --git a/demos/supabase-trello/lib/utils/constant.dart b/demos/supabase-trello/lib/utils/constant.dart new file mode 100644 index 00000000..7c04692f --- /dev/null +++ b/demos/supabase-trello/lib/utils/constant.dart @@ -0,0 +1,40 @@ +const headline = "Move teamwork forward - even on the go"; +const terms = + "By signing up, you agree to our Terms of service and Privacy Policy"; +const contact = "Contact support"; +const visibilityConfigurations = [ + { + "type": "Private", + "description": + "The board is private. Only people added to the board can view and edit it" + }, + {"type": "Workspace", "description": "Anyone at BOARDNAME can see this file"}, + { + "type": "Public", + "description": + "The board is public. It's visible to anyone with the link and will show up in search engines like Google. Only people added to the board can edit it" + }, +]; +const defaultDescription = + "It's your board's time to shine! Let people know what this board is used for and what they can expect to see"; +const powerups = [ + { + "title": "Calendar Power-Up", + "description": + "See your work over time! The Trello Calendar Power-Up displays all cards with due dates by month" + }, + { + "title": "Card Aging", + "description": + "Quickly visualize inactive cards on your board, and keep tasks from going incomplete" + }, + { + "title": "Voting", + "description": "Give power to the people, and allow users to vote on cards" + }, + { + "title": "List limits", + "description": + "Set a limit on your lists and we'll highlight the list if the number of cards in it passes the limit" + } +]; \ No newline at end of file diff --git a/demos/supabase-trello/lib/utils/data_generator.dart b/demos/supabase-trello/lib/utils/data_generator.dart new file mode 100644 index 00000000..9c821fbd --- /dev/null +++ b/demos/supabase-trello/lib/utils/data_generator.dart @@ -0,0 +1,123 @@ +import 'dart:math'; + +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:random_name_generator/random_name_generator.dart'; +import 'package:status_alert/status_alert.dart'; +import 'package:trelloappclone_flutter/utils/color.dart'; +import 'package:trelloappclone_flutter/utils/config.dart'; +import 'package:trelloappclone_flutter/utils/service.dart'; +import 'package:trelloappclone_flutter/utils/trello_provider.dart'; +import 'package:trelloappclone_flutter/models/listboard.dart'; +import 'package:trelloappclone_flutter/models/board.dart'; +import 'package:trelloappclone_flutter/models/workspace.dart'; +import 'package:trelloappclone_flutter/models/card.dart'; +import 'package:trelloappclone_flutter/models/checklist.dart'; +import 'package:trelloappclone_flutter/models/comment.dart'; + +/// This class generates an example workspace with some boards, cards, etc for each +class DataGenerator with Service { + Random random = Random(); + var randomNames = RandomNames(Zone.us); + + List _generateBoardNames(String workspaceName) { + String prepend = workspaceName.splitMapJoin(' ', + onMatch: (match) => '', + onNonMatch: (text) => text.substring(0, 1).toUpperCase()); + return [ + '$prepend MVP App', + '$prepend User Auth Service', + '$prepend Transactions Service', + '$prepend Reporting Service', + '$prepend DevOps' + ]; + } + + List _generateListNames() { + return ['To Do', 'In Progress', 'To Test', 'Testing', 'To Release', 'Done']; + } + + List _generateCardNames(String prepend, int nrOfCards) { + return List.generate(nrOfCards, (index) => '$prepend Card $index'); + } + + createSampleWorkspace( + String workspaceName, TrelloProvider trello, BuildContext context) async { + StatusAlert.show(context, + duration: const Duration(seconds: 3), + title: 'Generating Workspace Data...', + configuration: + const IconConfiguration(icon: Icons.sync, color: brandColor), + maxWidth: 260); + + Workspace workspace = await createWorkspace(context, + name: workspaceName, + description: 'Example workspace', + visibility: 'Public'); + for (String boardName in _generateBoardNames(workspaceName)) { + //create board + Board newBoard = Board( + id: randomUuid(), + workspaceId: workspace.id, + userId: trello.user.id, + name: boardName, + visibility: 'Workspace', + background: backgrounds[random.nextInt(16)]); + await createBoard(context, newBoard); + + int listIndex = 1; + //create lists for each board + for (String listName in _generateListNames()) { + Listboard newList = Listboard( + id: randomUuid(), + workspaceId: workspace.id, + boardId: newBoard.id, + userId: trello.user.id, + name: listName, + order: listIndex++); + await addList(newList); + + //create cards per list + int cardIndex = 1; + for (String cardName + in _generateCardNames(listName, random.nextInt(10))) { + Cardlist newCard = Cardlist( + id: randomUuid(), + workspaceId: workspace.id, + listId: newList.id, + userId: trello.user.id, + name: cardName, + rank: cardIndex++); + await addCard(newCard); + await createComment(Comment( + id: randomUuid(), + workspaceId: workspace.id, + cardId: newCard.id, + userId: trello.user.id, + description: '${randomNames.name()} said something interesting', + )); + await createChecklist(Checklist( + id: randomUuid(), + workspaceId: workspace.id, + cardId: newCard.id, + name: '${randomNames.name()} need to check this', + status: false)); + await createChecklist(Checklist( + id: randomUuid(), + workspaceId: workspace.id, + cardId: newCard.id, + name: '${randomNames.name()} need to check this', + status: false)); + await createActivity( + workspaceId: workspace.id, + boardId: newBoard.id, + card: newCard.id, + description: '${randomNames.name()} updated this card'); + } + ; + } + ; + } + ; + } +} diff --git a/demos/supabase-trello/lib/utils/service.dart b/demos/supabase-trello/lib/utils/service.dart new file mode 100644 index 00000000..d9727abc --- /dev/null +++ b/demos/supabase-trello/lib/utils/service.dart @@ -0,0 +1,465 @@ +import 'dart:convert'; +import 'dart:developer'; + +import 'package:crypto/crypto.dart'; +import 'package:file_picker/file_picker.dart'; +import 'package:flutter/material.dart' hide Card; +import 'package:status_alert/status_alert.dart'; +import 'package:trelloappclone_flutter/features/home/presentation/custom_search.dart'; +import 'package:trelloappclone_flutter/utils/color.dart'; +import 'package:trelloappclone_flutter/models/listboard.dart'; +import 'package:trelloappclone_flutter/models/board.dart'; +import 'package:trelloappclone_flutter/models/workspace.dart'; +import 'package:trelloappclone_flutter/models/user.dart'; +import 'package:trelloappclone_flutter/models/card.dart'; +import 'package:trelloappclone_flutter/models/member.dart'; +import 'package:trelloappclone_flutter/models/checklist.dart'; +import 'package:trelloappclone_flutter/models/comment.dart'; +import 'package:trelloappclone_flutter/models/activity.dart'; +import 'package:trelloappclone_flutter/models/board_label.dart'; +import 'package:trelloappclone_flutter/models/card_label.dart'; +import 'package:trelloappclone_flutter/models/attachment.dart'; + +import 'package:uuid/uuid.dart'; + +import '../main.dart'; + +var uuid = Uuid(); + +mixin Service { + randomUuid() { + return uuid.v4(); + } + + //sign up new user + signUp( + {required String name, + required String email, + required String password, + required BuildContext context}) async { + try { + TrelloUser user = await dataClient.signupWithEmail(name, email, password); + await dataClient.user.createUser(user); + + if (context.mounted) { + Navigator.pushNamed(context, '/'); + StatusAlert.show(context, + duration: const Duration(seconds: 3), + title: 'Account Created', + subtitle: 'Log in with your new credentials', + subtitleOptions: StatusAlertTextConfiguration( + softWrap: true, maxLines: 3, overflow: TextOverflow.ellipsis), + configuration: + const IconConfiguration(icon: Icons.check, color: brandColor), + maxWidth: 260); + } + } on Exception catch (e) { + log('Error with signup: $e', error: e); + StatusAlert.show(context, + duration: const Duration(seconds: 5), + title: 'Sign Up Error', + subtitle: e.toString(), + subtitleOptions: StatusAlertTextConfiguration( + softWrap: true, maxLines: 3, overflow: TextOverflow.ellipsis), + configuration: + const IconConfiguration(icon: Icons.check, color: brandColor), + maxWidth: 260); + } + } + + //log in existing user + logIn(String email, String password, BuildContext context) async { + try { + TrelloUser user = await dataClient.loginWithEmail(email, password); + trello.setUser(user); + + if (context.mounted) { + Navigator.pushNamed(context, '/home'); + StatusAlert.show(context, + duration: const Duration(seconds: 5), + title: 'Syncing Workspaces...', + configuration: + const IconConfiguration(icon: Icons.sync, color: brandColor), + maxWidth: 260); + } + } on Exception catch (e) { + log('Error with login: $e', error: e); + StatusAlert.show(context, + duration: const Duration(seconds: 5), + title: 'Login Error', + subtitle: e.toString(), + subtitleOptions: StatusAlertTextConfiguration( + softWrap: true, maxLines: 3, overflow: TextOverflow.ellipsis), + configuration: + const IconConfiguration(icon: Icons.check, color: brandColor), + maxWidth: 260); + } + } + + //log out user + logOut(BuildContext context) async { + try { + await dataClient.logOut(); + } on Exception catch (e) { + StatusAlert.show(context, + duration: const Duration(seconds: 5), + title: 'Logout Error', + subtitle: e.toString(), + subtitleOptions: StatusAlertTextConfiguration( + softWrap: true, maxLines: 3, overflow: TextOverflow.ellipsis), + configuration: + const IconConfiguration(icon: Icons.check, color: brandColor), + maxWidth: 260); + } + } + + switchToOfflineMode() async { + dataClient.switchToOfflineMode(); + } + + switchToOnlineMode() async { + dataClient.switchToOnlineMode(); + } + + //search for a board + search(BuildContext context) async { + List allboards = await dataClient.board.getAllBoards(); + + if (context.mounted) { + showSearch(context: context, delegate: CustomSearchDelegate(allboards)); + } + } + + //encrypt password + String encryptPassword(String password) { + final bytes = utf8.encode(password); + final hash = sha256.convert(bytes); + return hash.toString(); + } + + //create workspace + createWorkspace(BuildContext context, + {required String name, + required String description, + required String visibility}) async { + Workspace workspace = Workspace( + id: randomUuid(), + userId: trello.user.id, + name: name, + description: description, + visibility: visibility); + + try { + Workspace addedWorkspace = + await dataClient.workspace.createWorkspace(workspace); + + Member newMember = Member( + id: randomUuid(), + workspaceId: addedWorkspace.id, + userId: trello.user.id, + name: trello.user.name ?? trello.user.email, + role: "Admin"); + + await dataClient.member.addMember(newMember); + + if (context.mounted) { + Navigator.pushNamed(context, "/home"); + } + + return addedWorkspace; + } on Exception catch (e) { + StatusAlert.show(context, + duration: const Duration(seconds: 5), + title: 'Trello Clone', + subtitle: e.toString(), + configuration: + const IconConfiguration(icon: Icons.check, color: brandColor), + maxWidth: 260); + } + } + + //get workspaces of a specific user using user ID + Future> getWorkspaces() async { + List workspaces = + await dataClient.workspace.getWorkspacesByUser(userId: trello.user.id); + trello.setWorkspaces(workspaces); + return workspaces; + } + + //get a stream of workspaces for user, so we can react on distributed changes to it + Stream> getWorkspacesStream() { + return dataClient.workspace + .watchWorkspacesByUser(userId: trello.user.id) + .map((workspaces) { + trello.setWorkspaces(workspaces); + return workspaces; + }); + } + + //create board + createBoard(BuildContext context, Board brd) async { + try { + var labelColors = [{}]; + labelColors = [ + {"color": "fd6267", "name": "Bug"}, + {"color": "67ddf3", "name": "Feature"}, + {"color": "a282ff", "name": "Enhancement"}, + {"color": "f7b94a", "name": "Documentation"}, + {"color": "f8ff6e", "name": "Marketing"} + ]; + + await dataClient.board.createBoard(brd); + // Add the default labels to the board + for (var label in labelColors) { + await dataClient.boardLabel.createBoardLabel(BoardLabel( + id: randomUuid(), + boardId: brd.id, + workspaceId: brd.workspaceId, + title: label["name"] ?? "", + color: label["color"] ?? "", + dateCreated: DateTime.now())); + } + + if (context.mounted) { + Navigator.pushNamed(context, "/home"); + } + } on Exception catch (e) { + StatusAlert.show(context, + duration: const Duration(seconds: 5), + title: 'Trello Clone', + subtitle: e.toString(), + configuration: + const IconConfiguration(icon: Icons.check, color: brandColor), + maxWidth: 260); + } + } + + //get boards of a specific workspace by Workspace ID + Future> getBoards(String workspaceId) async { + List boards = await dataClient.workspace + .getBoardsByWorkspace(workspaceId: workspaceId); + trello.setBoards(boards); + return boards; + } + + //watch boards of a specific workspace by Workspace ID via a stream + Stream> getBoardsStream(String workspaceId) { + return dataClient.workspace + .watchBoardsByWorkspace(workspaceId: workspaceId) + .map((boards) { + trello.setBoards(boards); + return boards; + }); + } + + //update workspace + Future updateWorkspace(Workspace wkspc) async { + return await dataClient.workspace.updateWorkspace(wkspc); + } + + //get user by Id + Future getUserById(String userId) async { + TrelloUser? user = await dataClient.user.getUserById(userId: userId); + return user; + } + + //get information of members + Future> getMembersInformation(List mmbrs) async { + List usrs = + await dataClient.member.getInformationOfMembers(mmbrs); + return usrs; + } + + Future inviteUserToWorkspace(String email, Workspace workspace) async { + TrelloUser? user = await dataClient.user.checkUserExists(email); + if (user != null) { + Member member = Member( + id: randomUuid(), + workspaceId: workspace.id, + userId: user.id, + name: user.name ?? user.email, + role: "Admin"); + await dataClient.member.addMember(member); + workspace.members?.add(member); + return true; + } + return false; + } + + //remove Member from Workspace + Future removeMemberFromWorkspace( + Member mmbr, Workspace wkspc) async { + Workspace updatedWorkspace = + await dataClient.member.deleteMember(mmbr, wkspc); + return updatedWorkspace; + } + + //update offline status + Future updateOfflineStatus(Board brd) async { + return await dataClient.board.updateBoard(brd); + } + + //get lists by board + Future> getListsByBoard(Board brd) async { + List brdlist = + await dataClient.listboard.getListsByBoard(boardId: brd.id); + trello.setListBoard(brdlist); + return brdlist; + } + + //watch lists by board via Stream + Stream> getListsByBoardStream(Board brd) { + return dataClient.listboard.watchListsByBoard(boardId: brd.id).map((lists) { + trello.setListBoard(lists); + return lists; + }); + } + + //add list + Future addList(Listboard lst) async { + await dataClient.listboard.createList(lst); + createActivity( + workspaceId: lst.workspaceId, + description: "${trello.user.name} added a new list ${lst.name}"); + } + + //add list + Future updateListOrder(String listId, int newOrder) async { + await dataClient.listboard.updateListOrder(listId, newOrder); + } + + //add card + Future addCard(Cardlist crd) async { + Cardlist newcrd = await dataClient.card.createCard(crd); + createActivity( + card: newcrd.id, + workspaceId: newcrd.workspaceId, + description: "${trello.user.name} added a new card ${crd.name}"); + } + + //update card + Future updateCard(Cardlist crd) async { + await dataClient.card.updateCard(crd); + + createActivity( + card: crd.id, + workspaceId: crd.workspaceId, + description: "${trello.user.name} updated the card ${crd.name}"); + } + + //delete card + Future deleteCard(Cardlist crd) async { + await dataClient.card.deleteCard(crd); + + createActivity( + card: crd.id, + workspaceId: crd.workspaceId, + description: "${trello.user.name} deleted the card ${crd.name}"); + } + + Future archiveCardsInList(Listboard list) async { + return dataClient.listboard.archiveCardsInList(list); + } + + //add card + Future addCardLabel(CardLabel crdlbl, BoardLabel brdlbl) async { + final newCardLabel = await dataClient.cardLabel.createCardLabel(crdlbl); + createActivity( + card: crdlbl.cardId, + workspaceId: brdlbl.workspaceId, + description: "${trello.user.name} added a new label '${brdlbl.title}'"); + + return newCardLabel; + } + + //add card + Future deleteCardLabel(cardId, BoardLabel brdlbl) async { + await dataClient.cardLabel.deleteCardLabel(brdlbl); + createActivity( + card: cardId, + workspaceId: brdlbl.workspaceId, + description: "${trello.user.name} deleted the label '${brdlbl.title}'"); + } + + //updateBoardLabel + Future updateBoardLabel(BoardLabel brdlbl) async { + await dataClient.boardLabel.updateBoardLabel(brdlbl); + } + + //create activity + Future createActivity( + {required String workspaceId, + String? boardId, + required String description, + String? card}) async { + await dataClient.activity.createActivity(Activity( + id: randomUuid(), + workspaceId: workspaceId, + boardId: boardId, + userId: trello.user.id, + cardId: card, + description: description, + dateCreated: DateTime.now())); + } + + //get activities of a specific card + Future> getActivities(Cardlist crd) async { + return dataClient.activity.getActivities(crd); + } + + //create comment + Future createComment(Comment cmmt) async { + await dataClient.comment.createComment(cmmt); + } + + //create checklist + Future createChecklist(Checklist chcklst) async { + await dataClient.checklist.createChecklist(chcklst); + } + + Future> getChecklists(Cardlist crd) async { + List chcklsts = await dataClient.checklist.getChecklists(crd); + return chcklsts; + } + + Future updateChecklist(Checklist chcklst) async { + await dataClient.checklist.updateChecklist(chcklst); + } + + Future deleteChecklist(Cardlist crd) async { + await dataClient.checklist.deleteChecklist(crd); + } + + Future uploadFile(Cardlist crd) async { + FilePickerResult? result = + await FilePicker.platform.pickFiles(allowMultiple: false); + if (result != null) { + addAttachment(result.files[0].path ?? "", crd); + } + } + + Future addAttachment(String path, Cardlist crd) async { + //TODO: fix uploads + // var uploadDescription = await client.attachment.getUploadDescription(path); + bool success = false; + // if (uploadDescription != null) { + // var uploader = FileUploader(uploadDescription); + // await uploader.upload( + // File(path).readAsBytes().asStream(), File(path).lengthSync()); + // success = await client.attachment.verifyUpload(path); + // } + // if (success) { + // insertAttachment(crd, path); + // } + return success; + } + + Future insertAttachment(Cardlist crd, String path) async { + await dataClient.attachment.addAttachment(Attachment( + id: randomUuid(), + workspaceId: crd.workspaceId, + userId: trello.user.id, + cardId: crd.id, + attachment: path)); + } +} diff --git a/demos/supabase-trello/lib/utils/trello_provider.dart b/demos/supabase-trello/lib/utils/trello_provider.dart new file mode 100644 index 00000000..16830e39 --- /dev/null +++ b/demos/supabase-trello/lib/utils/trello_provider.dart @@ -0,0 +1,74 @@ +import 'package:flutter/material.dart'; +import 'package:trelloappclone_flutter/models/listboard.dart'; +import 'package:trelloappclone_flutter/models/board.dart'; +import 'package:trelloappclone_flutter/models/workspace.dart'; +import 'package:trelloappclone_flutter/models/user.dart'; +import 'package:trelloappclone_flutter/models/card.dart'; + +import 'config.dart'; + +class TrelloProvider extends ChangeNotifier { + late TrelloUser _user; + TrelloUser get user => _user; + + List _workspaces = []; + List get workspaces => _workspaces; + + List _boards = []; + List get boards => _boards; + + String _selectedBackground = backgrounds[0]; + String get selectedBackground => _selectedBackground; + + List _lstbrd = []; + List get lstbrd => _lstbrd; + + late Board _selectedBoard; + Board get selectedBoard => _selectedBoard; + + late Workspace _selectedWorkspace; + Workspace get selectedWorkspace => _selectedWorkspace; + + Cardlist? _selectedCard; + Cardlist? get selectedCard => _selectedCard; + + void setUser(TrelloUser user) { + _user = user; + notifyListeners(); + } + + void setWorkspaces(List wkspcs) { + _workspaces = wkspcs; + notifyListeners(); + } + + void setBoards(List brd) { + _boards = brd; + notifyListeners(); + } + + void setSelectedBg(String slctbg) { + _selectedBackground = slctbg; + notifyListeners(); + } + + void setListBoard(List lstbrd) { + _lstbrd = lstbrd; + notifyListeners(); + } + + void setSelectedBoard(Board brd) { + _selectedBoard = brd; + notifyListeners(); + } + + void setSelectedWorkspace(Workspace workspace) { + _selectedWorkspace = workspace; + notifyListeners(); + } + + void setSelectedCard(Cardlist? card) { + _selectedCard = card; + notifyListeners(); + } +} diff --git a/demos/supabase-trello/lib/utils/widgets.dart b/demos/supabase-trello/lib/utils/widgets.dart new file mode 100644 index 00000000..4d0e45a8 --- /dev/null +++ b/demos/supabase-trello/lib/utils/widgets.dart @@ -0,0 +1,75 @@ +import 'package:flutter/material.dart'; +import 'package:trelloappclone_flutter/utils/color.dart'; + +class LabelDiplay extends StatefulWidget { + final String label; + final String color; + const LabelDiplay({required this.label, required this.color, super.key}); + + @override + State createState() => _LabelDiplayState(); +} + +class _LabelDiplayState extends State { + @override + Widget build(BuildContext context) { + return DecoratedBox( + decoration: BoxDecoration( + color: Color(int.parse(widget.color, radix: 16) + 0xFF000000), + borderRadius: const BorderRadius.all(Radius.circular(5.0))), + child: Center( + child: Padding( + padding: const EdgeInsets.all(4.0), + child: Text( + widget.label, + style: TextStyle( + color: ((int.parse(widget.color, radix: 16)) > 186 + ? Colors.black + : Colors.white)), + ), + ), + )); + } +} + +class ColorSquare extends StatefulWidget { + final String bckgrd; + const ColorSquare({required this.bckgrd, super.key}); + + @override + State createState() => _ColorSquareState(); +} + +class _ColorSquareState extends State { + @override + Widget build(BuildContext context) { + return Container( + height: 40.0, + width: 40.0, + decoration: BoxDecoration( + color: Color( + int.parse(widget.bckgrd.substring(1, 7), radix: 16) + 0xFF000000), + borderRadius: const BorderRadius.all(Radius.circular(5.0))), + ); + } +} + +class BlueRectangle extends StatefulWidget { + const BlueRectangle({super.key}); + + @override + State createState() => _BlueRectangleState(); +} + +class _BlueRectangleState extends State { + @override + Widget build(BuildContext context) { + return Container( + height: 100.0, + width: 300.0, + decoration: const BoxDecoration( + color: brandColor, + borderRadius: BorderRadius.all(Radius.circular(5.0))), + ); + } +} diff --git a/demos/supabase-trello/lib/widgets/thirdparty/README.md b/demos/supabase-trello/lib/widgets/thirdparty/README.md new file mode 100644 index 00000000..c1a4c771 --- /dev/null +++ b/demos/supabase-trello/lib/widgets/thirdparty/README.md @@ -0,0 +1,5 @@ +# BoardView + +The code for this BoardView widget comes from this repo: https://github.com/jakebonk/FlutterBoardView + +However, since that project is not being maintained anymore, and somehow the latest code in the `master` repo does not match the actual lib code from pub.dev, we pulled in the code directly in this project in order to make it compilable again with latest Flutter version. \ No newline at end of file diff --git a/demos/supabase-trello/lib/widgets/thirdparty/board_item.dart b/demos/supabase-trello/lib/widgets/thirdparty/board_item.dart new file mode 100644 index 00000000..da106d62 --- /dev/null +++ b/demos/supabase-trello/lib/widgets/thirdparty/board_item.dart @@ -0,0 +1,150 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/widgets.dart'; + +import 'board_list.dart'; + +typedef void OnDropItem(int? listIndex, int? itemIndex, int? oldListIndex, + int? oldItemIndex, BoardItemState state); +typedef void OnTapItem(int listIndex, int itemIndex, BoardItemState state); +typedef void OnStartDragItem( + int? listIndex, int? itemIndex, BoardItemState state); +typedef void OnDragItem(int oldListIndex, int oldItemIndex, int newListIndex, + int newItemIndex, BoardItemState state); + +class BoardItem extends StatefulWidget { + final BoardListState? boardList; + final Widget? item; + final int? index; + final OnDropItem? onDropItem; + final OnTapItem? onTapItem; + final OnStartDragItem? onStartDragItem; + final OnDragItem? onDragItem; + final bool draggable; + + const BoardItem( + {Key? key, + this.boardList, + this.item, + this.index, + this.onDropItem, + this.onTapItem, + this.onStartDragItem, + this.draggable = true, + this.onDragItem}) + : super(key: key); + + @override + State createState() { + return BoardItemState(); + } +} + +class BoardItemState extends State + with AutomaticKeepAliveClientMixin { + late double height; + double? width; + + @override + bool get wantKeepAlive => true; + + void onDropItem(int? listIndex, int? itemIndex) { + if (widget.onDropItem != null) { + // check if itemIndex == items.length + // log everything + widget.onDropItem!( + listIndex, + itemIndex, + widget.boardList!.widget.boardView!.startListIndex, + widget.boardList!.widget.boardView!.startItemIndex, + this); + } + widget.boardList!.widget.boardView!.draggedItemIndex = null; + widget.boardList!.widget.boardView!.draggedListIndex = null; + if (widget.boardList!.widget.boardView!.listStates[listIndex!].mounted) { + widget.boardList!.widget.boardView!.listStates[listIndex].setState(() {}); + } + } + + void _startDrag(Widget item, BuildContext context) { + if (widget.boardList!.widget.boardView != null) { + widget.boardList!.widget.boardView!.onDropItem = onDropItem; + if (widget.boardList!.mounted) { + widget.boardList!.setState(() {}); + } + widget.boardList!.widget.boardView!.draggedItemIndex = widget.index; + widget.boardList!.widget.boardView!.height = context.size!.height; + widget.boardList!.widget.boardView!.draggedListIndex = + widget.boardList!.widget.index; + widget.boardList!.widget.boardView!.startListIndex = + widget.boardList!.widget.index; + widget.boardList!.widget.boardView!.startItemIndex = widget.index; + widget.boardList!.widget.boardView!.draggedItem = item; + if (widget.onStartDragItem != null) { + widget.onStartDragItem!( + widget.boardList!.widget.index, widget.index, this); + } + widget.boardList!.widget.boardView!.run(); + if (widget.boardList!.widget.boardView!.mounted) { + widget.boardList!.widget.boardView!.setState(() {}); + } + } + } + + void afterFirstLayout(BuildContext context) { + try { + height = context.size!.height; + width = context.size!.width; + } catch (e) {} + } + + @override + Widget build(BuildContext context) { + WidgetsBinding.instance! + .addPostFrameCallback((_) => afterFirstLayout(context)); + if (widget.boardList!.itemStates.length > widget.index!) { + widget.boardList!.itemStates.removeAt(widget.index!); + } + widget.boardList!.itemStates.insert(widget.index!, this); + return GestureDetector( + onTapDown: (otd) { + if (widget.draggable) { + RenderBox object = context.findRenderObject() as RenderBox; + Offset pos = object.localToGlobal(Offset.zero); + RenderBox box = + widget.boardList!.context.findRenderObject() as RenderBox; + Offset listPos = box.localToGlobal(Offset.zero); + widget.boardList!.widget.boardView!.leftListX = listPos.dx; + widget.boardList!.widget.boardView!.topListY = listPos.dy; + widget.boardList!.widget.boardView!.topItemY = pos.dy; + widget.boardList!.widget.boardView!.bottomItemY = + pos.dy + object.size.height; + widget.boardList!.widget.boardView!.bottomListY = + listPos.dy + box.size.height; + widget.boardList!.widget.boardView!.rightListX = + listPos.dx + box.size.width; + + widget.boardList!.widget.boardView!.initialX = pos.dx; + widget.boardList!.widget.boardView!.initialY = pos.dy; + } + }, + onTapCancel: () {}, + onTap: () { + if (widget.onTapItem != null) { + if (widget.boardList != null && + widget.boardList!.widget.index != null && + widget.index != null) { + widget.onTapItem!( + widget.boardList!.widget.index!, widget.index!, this); + } else {} + } + }, + onLongPress: () { + if (!widget.boardList!.widget.boardView!.widget.isSelecting && + widget.draggable) { + _startDrag(widget, context); + } + }, + child: widget.item, + ); + } +} diff --git a/demos/supabase-trello/lib/widgets/thirdparty/board_list.dart b/demos/supabase-trello/lib/widgets/thirdparty/board_list.dart new file mode 100644 index 00000000..5ccdadf3 --- /dev/null +++ b/demos/supabase-trello/lib/widgets/thirdparty/board_list.dart @@ -0,0 +1,188 @@ +import 'board_item.dart'; +import 'boardview.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/widgets.dart'; + +typedef void OnDropList(int? listIndex,int? oldListIndex); +typedef void OnTapList(int? listIndex); +typedef void OnStartDragList(int? listIndex); + +class BoardList extends StatefulWidget { + final List? header; + final Widget? footer; + final List? items; + final Color? backgroundColor; + final Color? headerBackgroundColor; + final BoardViewState? boardView; + final OnDropList? onDropList; + final OnTapList? onTapList; + final OnStartDragList? onStartDragList; + final bool draggable; + + const BoardList({ + Key? key, + this.header, + this.items, + this.footer, + this.backgroundColor, + this.headerBackgroundColor, + this.boardView, + this.draggable = true, + this.index, this.onDropList, this.onTapList, this.onStartDragList, + }) : super(key: key); + + final int? index; + + @override + State createState() { + return BoardListState(); + } +} + +class BoardListState extends State with AutomaticKeepAliveClientMixin{ + List itemStates = []; + ScrollController boardListController = new ScrollController(); + + void onDropList(int? listIndex) { + if(widget.onDropList != null){ + widget.onDropList!(listIndex,widget.boardView!.startListIndex); + } + widget.boardView!.draggedListIndex = null; + if(widget.boardView!.mounted) { + widget.boardView!.setState(() { + + }); + } + } + + void _startDrag(Widget item, BuildContext context) { + if (widget.boardView != null && widget.draggable) { + if(widget.onStartDragList != null){ + widget.onStartDragList!(widget.index); + } + widget.boardView!.startListIndex = widget.index; + widget.boardView!.height = context.size!.height; + widget.boardView!.draggedListIndex = widget.index!; + widget.boardView!.draggedItemIndex = null; + widget.boardView!.draggedItem = item; + widget.boardView!.onDropList = onDropList; + widget.boardView!.run(); + if(widget.boardView!.mounted) { + widget.boardView!.setState(() {}); + } + } + } + + @override + bool get wantKeepAlive => true; + + @override + Widget build(BuildContext context) { + List listWidgets = []; + if (widget.header != null) { + Color? headerBackgroundColor = Color.fromARGB(255, 255, 255, 255); + if (widget.headerBackgroundColor != null) { + headerBackgroundColor = widget.headerBackgroundColor; + } + listWidgets.add(GestureDetector( + onTap: (){ + if(widget.onTapList != null){ + widget.onTapList!(widget.index); + } + }, + onTapDown: (otd) { + if(widget.draggable) { + RenderBox object = context.findRenderObject() as RenderBox; + Offset pos = object.localToGlobal(Offset.zero); + widget.boardView!.initialX = pos.dx; + widget.boardView!.initialY = pos.dy; + + widget.boardView!.rightListX = pos.dx + object.size.width; + widget.boardView!.leftListX = pos.dx; + } + }, + onTapCancel: () {}, + onLongPress: () { + if(!widget.boardView!.widget.isSelecting && widget.draggable) { + _startDrag(widget, context); + } + }, + child: Container( + color: widget.headerBackgroundColor, + child: Row( + mainAxisSize: MainAxisSize.max, + mainAxisAlignment: MainAxisAlignment.center, + children: widget.header!), + ))); + + } + if (widget.items != null) { + listWidgets.add(Flexible( + fit: FlexFit.loose, + child: ListView.builder( + shrinkWrap: true, + physics: const ClampingScrollPhysics(), + controller: boardListController, + itemCount: widget.items!.length, + itemBuilder: (ctx, index) { + // if index does not exist + if (widget.items!.length <= index) { + //set index to the last index + return Opacity( + opacity: 0.0, + child: widget.boardView!.draggedItem!, + ); + } + + if (widget.items![index].boardList == null || + widget.items![index].index != index || + widget.items![index].boardList!.widget.index != widget.index || + widget.items![index].boardList != this) { + widget.items![index] = BoardItem( + boardList: this, + item: widget.items![index].item, + draggable: widget.items![index].draggable, + index: index, + onDropItem: widget.items![index].onDropItem, + onTapItem: widget.items![index].onTapItem, + onDragItem: widget.items![index].onDragItem, + onStartDragItem: widget.items![index].onStartDragItem, + ); + } + if (widget.boardView!.draggedItemIndex == index && + widget.boardView!.draggedListIndex == widget.index) { + return Opacity( + opacity: 0.0, + child: widget.items![index], + ); + } else { + return widget.items![index]; + } + }, + ))); + } + + if (widget.footer != null) { + listWidgets.add(widget.footer!); + } + + Color? backgroundColor = const Color.fromARGB(255, 255, 255, 255); + + if (widget.backgroundColor != null) { + backgroundColor = widget.backgroundColor; + } + if (widget.boardView!.listStates.length > widget.index!) { + widget.boardView!.listStates.removeAt(widget.index!); + } + widget.boardView!.listStates.insert(widget.index!, this); + + return Container( + margin: const EdgeInsets.all(8), + decoration: BoxDecoration(color: backgroundColor), + child: Column( + mainAxisSize: MainAxisSize.min, + mainAxisAlignment: MainAxisAlignment.start, + children: listWidgets as List, + )); + } +} diff --git a/demos/supabase-trello/lib/widgets/thirdparty/boardview.dart b/demos/supabase-trello/lib/widgets/thirdparty/boardview.dart new file mode 100644 index 00000000..d50faf90 --- /dev/null +++ b/demos/supabase-trello/lib/widgets/thirdparty/boardview.dart @@ -0,0 +1,683 @@ +library boardview; + +import 'boardview_controller.dart'; +import 'vs_scrollbar.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/widgets.dart'; +import 'dart:core'; +import 'board_list.dart'; + +class BoardView extends StatefulWidget { + final List? lists; + final double width; + Widget? middleWidget; + double? bottomPadding; + bool isSelecting; + bool? scrollbar; + ScrollbarStyle? scrollbarStyle; + BoardViewController? boardViewController; + int dragDelay; + + Function(bool)? itemInMiddleWidget; + OnDropBottomWidget? onDropItemInMiddleWidget; + BoardView({Key? key, this.itemInMiddleWidget,this.scrollbar,this.scrollbarStyle,this.boardViewController,this.dragDelay=300,this.onDropItemInMiddleWidget, this.isSelecting = false, this.lists, this.width = 280, this.middleWidget, this.bottomPadding}) : super(key: key); + + @override + State createState() { + return BoardViewState(); + } +} + +typedef void OnDropBottomWidget(int? listIndex, int? itemIndex,double percentX); +typedef void OnDropItem(int? listIndex, int? itemIndex); +typedef void OnDropList(int? listIndex); + +class BoardViewState extends State with AutomaticKeepAliveClientMixin { + Widget? draggedItem; + int? draggedItemIndex; + int? draggedListIndex; + double? dx; + double? dxInit; + double? dyInit; + double? dy; + double? offsetX; + double? offsetY; + double? initialX = 0; + double? initialY = 0; + double? rightListX; + double? leftListX; + double? topListY; + double? bottomListY; + double? topItemY; + double? bottomItemY; + double? height; + int? startListIndex; + int? startItemIndex; + + bool canDrag = true; + + ScrollController boardViewController = new ScrollController(); + + List listStates = []; + + OnDropItem? onDropItem; + OnDropList? onDropList; + + bool isScrolling = false; + + bool _isInWidget = false; + + GlobalKey _middleWidgetKey = GlobalKey(); + + var pointer; + + @override + bool get wantKeepAlive => true; + + @override + void initState() { + super.initState(); + if(widget.boardViewController != null){ + widget.boardViewController!.state = this; + } + } + + void moveDown() { + if(topItemY != null){ + topItemY = topItemY! + listStates[draggedListIndex!].itemStates[draggedItemIndex! + 1].height; + } + if(bottomItemY != null){ + bottomItemY = bottomItemY! + listStates[draggedListIndex!].itemStates[draggedItemIndex! + 1].height; + } + var item = widget.lists![draggedListIndex!].items![draggedItemIndex!]; + widget.lists![draggedListIndex!].items!.removeAt(draggedItemIndex!); + var itemState = listStates[draggedListIndex!].itemStates[draggedItemIndex!]; + listStates[draggedListIndex!].itemStates.removeAt(draggedItemIndex!); + if(draggedItemIndex != null){ + draggedItemIndex = draggedItemIndex! + 1; + } + widget.lists![draggedListIndex!].items!.insert(draggedItemIndex!, item); + listStates[draggedListIndex!].itemStates.insert(draggedItemIndex!, itemState); + if(listStates[draggedListIndex!].mounted) { + listStates[draggedListIndex!].setState(() {}); + } + } + + void moveUp() { + if(topItemY != null){ + topItemY = topItemY! - listStates[draggedListIndex!].itemStates[draggedItemIndex! - 1].height; + } + if(bottomItemY != null){ + bottomItemY = bottomItemY!-listStates[draggedListIndex!].itemStates[draggedItemIndex! - 1].height; + } + var item = widget.lists![draggedListIndex!].items![draggedItemIndex!]; + widget.lists![draggedListIndex!].items!.removeAt(draggedItemIndex!); + var itemState = listStates[draggedListIndex!].itemStates[draggedItemIndex!]; + listStates[draggedListIndex!].itemStates.removeAt(draggedItemIndex!); + if(draggedItemIndex != null){ + draggedItemIndex = draggedItemIndex! - 1; + } + widget.lists![draggedListIndex!].items!.insert(draggedItemIndex!, item); + listStates[draggedListIndex!].itemStates.insert(draggedItemIndex!, itemState); + if(listStates[draggedListIndex!].mounted) { + listStates[draggedListIndex!].setState(() {}); + } + } + + void moveListRight() { + var list = widget.lists![draggedListIndex!]; + var listState = listStates[draggedListIndex!]; + widget.lists!.removeAt(draggedListIndex!); + listStates.removeAt(draggedListIndex!); + if(draggedListIndex != null){ + draggedListIndex = draggedListIndex! + 1; + } + widget.lists!.insert(draggedListIndex!, list); + listStates.insert(draggedListIndex!, listState); + canDrag = false; + if (boardViewController != null && boardViewController.hasClients) { + int? tempListIndex = draggedListIndex; + boardViewController + .animateTo(draggedListIndex! * widget.width, duration: new Duration(milliseconds: 400), curve: Curves.ease) + .whenComplete(() { + RenderBox object = listStates[tempListIndex!].context.findRenderObject() as RenderBox; + Offset pos = object.localToGlobal(Offset.zero); + leftListX = pos.dx; + rightListX = pos.dx + object.size.width; + Future.delayed(new Duration(milliseconds: widget.dragDelay), () { + canDrag = true; + }); + }); + } + if(mounted){ + setState(() {}); + } + } + + void moveRight() { + var item = widget.lists![draggedListIndex!].items![draggedItemIndex!]; + var itemState = listStates[draggedListIndex!].itemStates[draggedItemIndex!]; + widget.lists![draggedListIndex!].items!.removeAt(draggedItemIndex!); + listStates[draggedListIndex!].itemStates.removeAt(draggedItemIndex!); + if(listStates[draggedListIndex!].mounted) { + listStates[draggedListIndex!].setState(() {}); + } + if(draggedListIndex != null){ + draggedListIndex = draggedListIndex! + 1; + } + double closestValue = 10000; + draggedItemIndex = 0; + for (int i = 0; i < listStates[draggedListIndex!].itemStates.length; i++) { + if (listStates[draggedListIndex!].itemStates[i].mounted && listStates[draggedListIndex!].itemStates[i].context != null) { + RenderBox box = listStates[draggedListIndex!].itemStates[i].context.findRenderObject() as RenderBox; + Offset pos = box.localToGlobal(Offset.zero); + var temp = (pos.dy - dy! + (box.size.height / 2)).abs(); + if (temp < closestValue) { + closestValue = temp; + draggedItemIndex = i; + dyInit = dy; + } + } + } + widget.lists![draggedListIndex!].items!.insert(draggedItemIndex!, item); + listStates[draggedListIndex!].itemStates.insert(draggedItemIndex!, itemState); + canDrag = false; + if(listStates[draggedListIndex!].mounted) { + listStates[draggedListIndex!].setState(() {}); + } + if (boardViewController != null && boardViewController.hasClients) { + int? tempListIndex = draggedListIndex; + int? tempItemIndex = draggedItemIndex; + boardViewController + .animateTo(draggedListIndex! * widget.width, duration: new Duration(milliseconds: 400), curve: Curves.ease) + .whenComplete(() { + RenderBox object = listStates[tempListIndex!].context.findRenderObject() as RenderBox; + Offset pos = object.localToGlobal(Offset.zero); + leftListX = pos.dx; + rightListX = pos.dx + object.size.width; + RenderBox box = listStates[tempListIndex].itemStates[tempItemIndex!].context.findRenderObject() as RenderBox; + Offset itemPos = box.localToGlobal(Offset.zero); + topItemY = itemPos.dy; + bottomItemY = itemPos.dy + box.size.height; + Future.delayed(new Duration(milliseconds: widget.dragDelay), () { + canDrag = true; + }); + }); + } + if(mounted){ + setState(() { }); + } + } + + void moveListLeft() { + var list = widget.lists![draggedListIndex!]; + var listState = listStates[draggedListIndex!]; + widget.lists!.removeAt(draggedListIndex!); + listStates.removeAt(draggedListIndex!); + if(draggedListIndex != null){ + draggedListIndex = draggedListIndex! - 1; + } + widget.lists!.insert(draggedListIndex!, list); + listStates.insert(draggedListIndex!, listState); + canDrag = false; + if (boardViewController != null && boardViewController.hasClients) { + int? tempListIndex = draggedListIndex; + boardViewController + .animateTo(draggedListIndex! * widget.width, duration: new Duration(milliseconds: widget.dragDelay), curve: Curves.ease) + .whenComplete(() { + RenderBox object = listStates[tempListIndex!].context.findRenderObject() as RenderBox; + Offset pos = object.localToGlobal(Offset.zero); + leftListX = pos.dx; + rightListX = pos.dx + object.size.width; + Future.delayed(new Duration(milliseconds: widget.dragDelay), () { + canDrag = true; + }); + }); + } + if(mounted) { + setState(() {}); + } + } + + void moveLeft() { + var item = widget.lists![draggedListIndex!].items![draggedItemIndex!]; + var itemState = listStates[draggedListIndex!].itemStates[draggedItemIndex!]; + widget.lists![draggedListIndex!].items!.removeAt(draggedItemIndex!); + listStates[draggedListIndex!].itemStates.removeAt(draggedItemIndex!); + if(listStates[draggedListIndex!].mounted) { + listStates[draggedListIndex!].setState(() {}); + } + if(draggedListIndex != null){ + draggedListIndex = draggedListIndex! - 1; + } + double closestValue = 10000; + draggedItemIndex = 0; + for (int i = 0; i < listStates[draggedListIndex!].itemStates.length; i++) { + if (listStates[draggedListIndex!].itemStates[i].mounted && listStates[draggedListIndex!].itemStates[i].context != null) { + RenderBox box = listStates[draggedListIndex!].itemStates[i].context.findRenderObject() as RenderBox; + Offset pos = box.localToGlobal(Offset.zero); + var temp = (pos.dy - dy! + (box.size.height / 2)).abs(); + if (temp < closestValue) { + closestValue = temp; + draggedItemIndex = i; + dyInit = dy; + } + } + } + widget.lists![draggedListIndex!].items!.insert(draggedItemIndex!, item); + listStates[draggedListIndex!].itemStates.insert(draggedItemIndex!, itemState); + canDrag = false; + if(listStates[draggedListIndex!].mounted) { + listStates[draggedListIndex!].setState(() {}); + } + if (boardViewController != null && boardViewController.hasClients) { + int? tempListIndex = draggedListIndex; + int? tempItemIndex = draggedItemIndex; + boardViewController + .animateTo(draggedListIndex! * widget.width, duration: new Duration(milliseconds: 400), curve: Curves.ease) + .whenComplete(() { + RenderBox object = listStates[tempListIndex!].context.findRenderObject() as RenderBox; + Offset pos = object.localToGlobal(Offset.zero); + leftListX = pos.dx; + rightListX = pos.dx + object.size.width; + RenderBox box = listStates[tempListIndex].itemStates[tempItemIndex!].context.findRenderObject() as RenderBox; + Offset itemPos = box.localToGlobal(Offset.zero); + topItemY = itemPos.dy; + bottomItemY = itemPos.dy + box.size.height; + Future.delayed(new Duration(milliseconds: widget.dragDelay), () { + canDrag = true; + }); + }); + } + if(mounted) { + setState(() {}); + } + } + + bool shown = true; + + @override + Widget build(BuildContext context) { + // print("dy:${dy}"); + // print("topListY:${topListY}"); + // print("bottomListY:${bottomListY}"); + if(boardViewController.hasClients) { + WidgetsBinding.instance!.addPostFrameCallback((Duration duration) { + try { + boardViewController.position.didUpdateScrollPositionBy(0); + }catch(e){} + bool _shown = boardViewController.position.maxScrollExtent!=0; + if(_shown != shown){ + setState(() { + shown = _shown; + }); + } + }); + } + Widget listWidget = ListView.builder( + physics: ClampingScrollPhysics(), + itemCount: widget.lists!.length, + scrollDirection: Axis.horizontal, + controller: boardViewController, + itemBuilder: (BuildContext context, int index) { + // if index does not exist on lists + if (widget.lists!.length <= index) { + print('Returned empty container'); + return Container(); + } + + if (widget.lists![index].boardView == null) { + widget.lists![index] = BoardList( + items: widget.lists![index].items, + headerBackgroundColor: widget.lists![index].headerBackgroundColor, + backgroundColor: widget.lists![index].backgroundColor, + footer: widget.lists![index].footer, + header: widget.lists![index].header, + boardView: this, + draggable: widget.lists![index].draggable, + onDropList: widget.lists![index].onDropList, + onTapList: widget.lists![index].onTapList, + onStartDragList: widget.lists![index].onStartDragList, + ); + } + if (widget.lists![index].index != index) { + widget.lists![index] = BoardList( + items: widget.lists![index].items, + headerBackgroundColor: widget.lists![index].headerBackgroundColor, + backgroundColor: widget.lists![index].backgroundColor, + footer: widget.lists![index].footer, + header: widget.lists![index].header, + boardView: this, + draggable: widget.lists![index].draggable, + index: index, + onDropList: widget.lists![index].onDropList, + onTapList: widget.lists![index].onTapList, + onStartDragList: widget.lists![index].onStartDragList, + ); + } + + var temp = Container( + width: widget.width, + padding: EdgeInsets.fromLTRB(0, 0, 0, widget.bottomPadding ?? 0), + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.start, + children: [Expanded(child: widget.lists![index])], + )); + if (draggedListIndex == index && draggedItemIndex == null) { + return Opacity( + opacity: 0.0, + child: temp, + ); + } else { + return temp; + } + }, + ); + if(widget.scrollbar == true){ + listWidget = VsScrollbar( + controller: boardViewController, + showTrackOnHover: true,// default false + isAlwaysShown: shown&&widget.lists!.length>1, // default false + scrollbarFadeDuration: Duration(milliseconds: 500), // default : Duration(milliseconds: 300) + scrollbarTimeToFade: Duration(milliseconds: 800),// default : Duration(milliseconds: 600) + style: widget.scrollbarStyle!=null?VsScrollbarStyle( + hoverThickness: widget.scrollbarStyle!.hoverThickness, + radius: widget.scrollbarStyle!.radius, + thickness: widget.scrollbarStyle!.thickness, + color: widget.scrollbarStyle!.color + ):VsScrollbarStyle(), + child:listWidget); + } + List stackWidgets = [ + listWidget + ]; + bool isInBottomWidget = false; + if (dy != null) { + if (MediaQuery.of(context).size.height - dy! < 80) { + isInBottomWidget = true; + } + } + if(widget.itemInMiddleWidget != null && _isInWidget != isInBottomWidget) { + widget.itemInMiddleWidget!(isInBottomWidget); + _isInWidget = isInBottomWidget; + } + if (initialX != null && + initialY != null && + offsetX != null && + offsetY != null && + dx != null && + dy != null && + height != null && + widget.width != null) { + if (canDrag && dxInit != null && dyInit != null && !isInBottomWidget) { + if (draggedItemIndex != null && draggedItem != null && topItemY != null && bottomItemY != null) { + //dragging item + if (0 <= draggedListIndex! - 1 && dx! < leftListX! + 45) { + //scroll left + if (boardViewController != null && boardViewController.hasClients) { + boardViewController.animateTo(boardViewController.position.pixels - 5, + duration: new Duration(milliseconds: 10), curve: Curves.ease); + if(listStates[draggedListIndex!].mounted) { + RenderBox object = listStates[draggedListIndex!].context + .findRenderObject() as RenderBox; + Offset pos = object.localToGlobal(Offset.zero); + leftListX = pos.dx; + rightListX = pos.dx + object.size.width; + } + } + } + if (widget.lists!.length > draggedListIndex! + 1 && dx! > rightListX! - 45) { + //scroll right + if (boardViewController != null && boardViewController.hasClients) { + boardViewController.animateTo(boardViewController.position.pixels + 5, + duration: new Duration(milliseconds: 10), curve: Curves.ease); + if(listStates[draggedListIndex!].mounted) { + RenderBox object = listStates[draggedListIndex!].context + .findRenderObject() as RenderBox; + Offset pos = object.localToGlobal(Offset.zero); + leftListX = pos.dx; + rightListX = pos.dx + object.size.width; + } + } + } + if (0 <= draggedListIndex! - 1 && dx! < leftListX!) { + //move left + moveLeft(); + } + if (widget.lists!.length > draggedListIndex! + 1 && dx! > rightListX!) { + //move right + moveRight(); + } + if (dy! < topListY! + 70) { + //scroll up + if (listStates[draggedListIndex!].boardListController != null && + listStates[draggedListIndex!].boardListController.hasClients && !isScrolling) { + isScrolling = true; + double pos = listStates[draggedListIndex!].boardListController.position.pixels; + listStates[draggedListIndex!].boardListController.animateTo( + listStates[draggedListIndex!].boardListController.position.pixels - 5, + duration: new Duration(milliseconds: 10), + curve: Curves.ease).whenComplete((){ + + pos -= listStates[draggedListIndex!].boardListController.position.pixels; + if(initialY == null) + initialY = 0; +// if(widget.boardViewController != null) { +// initialY -= pos; +// } + isScrolling = false; + if(topItemY != null) { + topItemY = topItemY! + pos; + } + if(bottomItemY != null) { + bottomItemY = bottomItemY! + pos; + } + if(mounted){ + setState(() { }); + } + }); + } + } + if (0 <= draggedItemIndex! - 1 && + dy! < topItemY! - listStates[draggedListIndex!].itemStates[draggedItemIndex! - 1].height / 2) { + //move up + moveUp(); + } + double? tempBottom = bottomListY; + if(widget.middleWidget != null){ + if(_middleWidgetKey.currentContext != null) { + RenderBox _box = _middleWidgetKey.currentContext! + .findRenderObject() as RenderBox; + tempBottom = _box.size.height; + print("tempBottom:${tempBottom}"); + } + } + if (dy! > tempBottom! - 70) { + //scroll down + + if (listStates.length < draggedListIndex! && listStates[draggedListIndex!].boardListController != null && + listStates[draggedListIndex!].boardListController.hasClients) { + isScrolling = true; + double pos = listStates[draggedListIndex!].boardListController.position.pixels; + listStates[draggedListIndex!].boardListController.animateTo( + listStates[draggedListIndex!].boardListController.position.pixels + 5, + duration: new Duration(milliseconds: 10), + curve: Curves.ease).whenComplete((){ + pos -= listStates[draggedListIndex!].boardListController.position.pixels; + initialY ??= 0; +// if(widget.boardViewController != null) { +// initialY -= pos; +// } + isScrolling = false; + if(topItemY != null) { + topItemY = topItemY! + pos; + } + if(bottomItemY != null) { + bottomItemY = bottomItemY! + pos; + } + if(mounted){ + setState(() {}); + } + }); + } + } + if (widget.lists![draggedListIndex!].items!.length > draggedItemIndex! + 1 && + dy! > bottomItemY! + listStates[draggedListIndex!].itemStates[draggedItemIndex! + 1].height / 2) { + //move down + moveDown(); + } + } else { + //dragging list + if (0 <= draggedListIndex! - 1 && dx! < leftListX! + 45) { + //scroll left + if (boardViewController != null && boardViewController.hasClients) { + boardViewController.animateTo(boardViewController.position.pixels - 5, + duration: new Duration(milliseconds: 10), curve: Curves.ease); + if(leftListX != null){ + leftListX = leftListX! + 5; + } + if(rightListX != null){ + rightListX = rightListX! + 5; + } + } + } + + if (widget.lists!.length > draggedListIndex! + 1 && dx! > rightListX! - 45) { + //scroll right + if (boardViewController != null && boardViewController.hasClients) { + boardViewController.animateTo(boardViewController.position.pixels + 5, + duration: new Duration(milliseconds: 10), curve: Curves.ease); + if(leftListX != null){ + leftListX = leftListX! - 5; + } + if(rightListX != null){ + rightListX = rightListX! - 5; + } + } + } + if (widget.lists!.length > draggedListIndex! + 1 && dx! > rightListX!) { + //move right + moveListRight(); + } + if (0 <= draggedListIndex! - 1 && dx! < leftListX!) { + //move left + moveListLeft(); + } + } + } + if (widget.middleWidget != null) { + stackWidgets.add(Container(key:_middleWidgetKey,child:widget.middleWidget)); + } + WidgetsBinding.instance!.addPostFrameCallback((timeStamp) { + if(mounted){ + setState(() {}); + } + }); + stackWidgets.add(Positioned( + width: widget.width, + height: height, + child: Opacity(opacity: .7, child: draggedItem), + left: (dx! - offsetX!) + initialX!, + top: (dy! - offsetY!) + initialY!, + )); + } + + return Container( + child: Listener( + onPointerMove: (opm) { + if (draggedItem != null) { + if (dxInit == null) { + dxInit = opm.position.dx; + } + if (dyInit == null) { + dyInit = opm.position.dy; + } + dx = opm.position.dx; + dy = opm.position.dy; + if(mounted) { + setState(() {}); + } + } + }, + onPointerDown: (opd) { + RenderBox box = context.findRenderObject() as RenderBox; + Offset pos = box.localToGlobal(opd.position); + offsetX = pos.dx; + offsetY = pos.dy; + pointer = opd; + if(mounted) { + setState(() {}); + } + }, + onPointerUp: (opu) { + if (onDropItem != null) { + int? tempDraggedItemIndex = draggedItemIndex; + int? tempDraggedListIndex = draggedListIndex; + int? startDraggedItemIndex = startItemIndex; + int? startDraggedListIndex = startListIndex; + + if(_isInWidget && widget.onDropItemInMiddleWidget != null){ + onDropItem!(startDraggedListIndex, startDraggedItemIndex); + widget.onDropItemInMiddleWidget!(startDraggedListIndex, startDraggedItemIndex,opu.position.dx/MediaQuery.of(context).size.width); + }else{ + onDropItem!(tempDraggedListIndex, tempDraggedItemIndex); + } + } + if (onDropList != null) { + int? tempDraggedListIndex = draggedListIndex; + if(_isInWidget && widget.onDropItemInMiddleWidget != null){ + onDropList!(tempDraggedListIndex); + widget.onDropItemInMiddleWidget!(tempDraggedListIndex,null,opu.position.dx/MediaQuery.of(context).size.width); + }else{ + onDropList!(tempDraggedListIndex); + } + } + draggedItem = null; + offsetX = null; + offsetY = null; + initialX = null; + initialY = null; + dx = null; + dy = null; + draggedItemIndex = null; + draggedListIndex = null; + onDropItem = null; + onDropList = null; + dxInit = null; + dyInit = null; + leftListX = null; + rightListX = null; + topListY = null; + bottomListY = null; + topItemY = null; + bottomItemY = null; + startListIndex = null; + startItemIndex = null; + if(mounted) { + setState(() {}); + } + }, + child: new Stack( + children: stackWidgets, + ))); + } + + void run() { + if (pointer != null) { + dx = pointer.position.dx; + dy = pointer.position.dy; + if(mounted) { + setState(() {}); + } + } + } +} + +class ScrollbarStyle{ + double hoverThickness; + double thickness; + Radius radius; + Color color; + ScrollbarStyle({this.radius = const Radius.circular(10),this.hoverThickness = 10,this.thickness = 10,this.color = Colors.black}); +} diff --git a/demos/supabase-trello/lib/widgets/thirdparty/boardview_controller.dart b/demos/supabase-trello/lib/widgets/thirdparty/boardview_controller.dart new file mode 100644 index 00000000..74c5af04 --- /dev/null +++ b/demos/supabase-trello/lib/widgets/thirdparty/boardview_controller.dart @@ -0,0 +1,18 @@ +import 'package:flutter/animation.dart'; + +import 'boardview.dart'; + +class BoardViewController{ + + BoardViewController(); + + late BoardViewState state; + + Future animateTo(int index,{Duration? duration,Curve? curve})async{ + double offset = index * state.widget.width; + if (state.boardViewController != null && state.boardViewController.hasClients) { + await state.boardViewController.animateTo( + offset, duration: duration!, curve: curve!); + } + } +} \ No newline at end of file diff --git a/demos/supabase-trello/lib/widgets/thirdparty/vs_scrollbar.dart b/demos/supabase-trello/lib/widgets/thirdparty/vs_scrollbar.dart new file mode 100644 index 00000000..85aa58bb --- /dev/null +++ b/demos/supabase-trello/lib/widgets/thirdparty/vs_scrollbar.dart @@ -0,0 +1,348 @@ +library vs_scrollbar; + +import 'package:flutter/cupertino.dart'; +import 'package:flutter/gestures.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/widgets.dart'; + +class VsScrollbarStyle { + /// The hoverThickness of the VsScrollbar thumb. + /// default value is 12.0 pixels. + final double hoverThickness; + + /// The thickness of the VsScrollbar thumb. + /// default thickness of 8.0 pixels. + final double thickness; + + /// The radius of the VsScrollbar thumb. + /// default [Radius.circular] of 8.0 pixels. + final Radius radius; + + /// The color of the VsScrollbar thumb. + final Color? color; + + const VsScrollbarStyle( + {this.radius = _kScrollbarRadius, + this.thickness = _kScrollbarThickness, + this.hoverThickness = _kScrollbarThicknessWithTrack, + this.color}); +} + +const VsScrollbarStyle _kScrollbarStyle = const VsScrollbarStyle(); +const double _kScrollbarThickness = 8.0; +const double _kScrollbarThicknessWithTrack = 12.0; +const double _kScrollbarMargin = 2.0; +const double _kScrollbarMinLength = 48.0; +const Radius _kScrollbarRadius = Radius.circular(8.0); +const Duration _kScrollbarFadeDuration = Duration(milliseconds: 300); +const Duration _kScrollbarTimeToFade = Duration(milliseconds: 600); + +/// To add a VsScrollbar to a [ScrollView], wrap the scroll view +/// widget in a [VsScrollbar] widget. +/// +/// The color of the VsScrollbar will change when dragged. A hover animation is +/// also triggered when used on web and desktop platforms. A VsScrollbar track +/// can also been drawn when triggered by a hover event, which is controlled by +/// [showTrackOnHover]. The thickness of the track and VsScrollbar thumb will +/// become larger when hovering, unless overridden by [hoverThickness]. +/// +/// See also: +/// +/// * [RawScrollbar], a basic VsScrollbar that fades in and out, extended +/// by this class to add more animations and behaviors. +/// * [ScrollbarTheme], which configures the VsScrollbar's appearance. +/// * [ListView], which displays a linear, scrollable list of children. +/// * [GridView], which displays a 2 dimensional, scrollable array of children. +class VsScrollbar extends StatefulWidget { + /// Creates a material design VsScrollbar that by default will connect to the + /// closest Scrollable descendant of [child]. + /// + /// The [child] should be a source of [ScrollNotification] notifications, + /// typically a [Scrollable] widget. + /// + /// If the [controller] is null, the default behavior is to + /// enable VsScrollbar dragging using the [PrimaryScrollController]. + /// + const VsScrollbar({ + Key? key, + required this.child, + this.controller, + this.style = _kScrollbarStyle, + this.scrollbarFadeDuration, + this.scrollbarTimeToFade, + this.isAlwaysShown, + this.showTrackOnHover, + this.notificationPredicate, + }) : super(key: key); + + /// {@macro flutter.widgets.VsScrollbar.child} + final Widget child; + + /// {@macro flutter.widgets.VsScrollbar.controller} + final ScrollController? controller; + + /// {@macro flutter.widgets.VsScrollbar.isAlwaysShown} + final bool? isAlwaysShown; + + /// If this property is null, then [ScrollbarThemeData.showTrackOnHover] of + /// [ThemeData.scrollbarTheme] is used. If that is also null, the default value + /// is false. + final bool? showTrackOnHover; + + ///Style Property for VsScrollbar + final VsScrollbarStyle style; + + /// {@macro flutter.widgets.VsScrollbar.notificationPredicate} + final ScrollNotificationPredicate? notificationPredicate; + + /// default 600ms + final Duration? scrollbarTimeToFade; + + /// default 300ms + final Duration? scrollbarFadeDuration; + + @override + _ScrollbarState createState() => _ScrollbarState(); +} + +class _ScrollbarState extends State { + @override + Widget build(BuildContext context) { + return _MaterialScrollbar( + child: widget.child, + controller: widget.controller, + isAlwaysShown: widget.isAlwaysShown, + showTrackOnHover: widget.showTrackOnHover, + hoverThickness: widget.style.hoverThickness, + thickness: widget.style.thickness, + radius: widget.style.radius, + color: widget.style.color, + notificationPredicate: widget.notificationPredicate, + ); + } +} + +class _MaterialScrollbar extends RawScrollbar { + const _MaterialScrollbar({ + Key? key, + required Widget child, + ScrollController? controller, + bool? isAlwaysShown, + this.showTrackOnHover, + this.hoverThickness, + this.color, + this.scrollbarFadeDuration, + this.scrollbarTimeToFade, + double? thickness, + Radius? radius, + ScrollNotificationPredicate? notificationPredicate, + }) : super( + key: key, + child: child, + controller: controller, + thumbVisibility: isAlwaysShown, + thickness: thickness, + radius: radius, + fadeDuration: scrollbarFadeDuration ?? _kScrollbarFadeDuration, + timeToFade: scrollbarTimeToFade ?? _kScrollbarTimeToFade, + pressDuration: Duration.zero, + notificationPredicate: + notificationPredicate ?? defaultScrollNotificationPredicate, + ); + final Duration? scrollbarTimeToFade; + final Duration? scrollbarFadeDuration; + + final Color? color; + final bool? showTrackOnHover; + final double? hoverThickness; + + @override + _MaterialScrollbarState createState() => _MaterialScrollbarState(); +} + +class _MaterialScrollbarState extends RawScrollbarState<_MaterialScrollbar> { + late AnimationController _hoverAnimationController; + bool _dragIsActive = true; + bool _hoverIsActive = false; + late ColorScheme _colorScheme; + late ScrollbarThemeData _scrollbarTheme; + // On Android, scrollbars should match native appearance. + late bool _useAndroidScrollbar; + + @override + bool get showScrollbar => + widget.thumbVisibility ?? + _scrollbarTheme.thumbVisibility + ?.resolve(Set.of([MaterialState.disabled])) ?? + false; + + bool get _showTrackOnHover => widget.showTrackOnHover ?? false; + + Set get _states => { + if (_dragIsActive) MaterialState.dragged, + if (_hoverIsActive) MaterialState.hovered, + }; + + MaterialStateProperty get _thumbColor { + final Color onSurface = widget.color ?? _colorScheme.onSurface; + late Color dragColor; + late Color hoverColor; + late Color idleColor; + dragColor = onSurface.withOpacity(0.9); + hoverColor = onSurface.withOpacity(0.75); + idleColor = onSurface.withOpacity(0.5); + + return MaterialStateProperty.resolveWith((Set states) { + if (states.contains(MaterialState.dragged)) + return _scrollbarTheme.thumbColor?.resolve(states) ?? dragColor; + + // If the track is visible, the thumb color hover animation is ignored and + // changes immediately. + if (states.contains(MaterialState.hovered) && _showTrackOnHover) + return _scrollbarTheme.thumbColor?.resolve(states) ?? hoverColor; + + return Color.lerp( + _scrollbarTheme.thumbColor?.resolve(states) ?? idleColor, + _scrollbarTheme.thumbColor?.resolve(states) ?? hoverColor, + _hoverAnimationController.value, + )!; + }); + } + + MaterialStateProperty get _trackColor { + final Color onSurface = widget.color ?? _colorScheme.onSurface; + + return MaterialStateProperty.resolveWith((Set states) { + if (states.contains(MaterialState.hovered) && _showTrackOnHover) { + return _scrollbarTheme.trackColor?.resolve(states) ?? + onSurface.withOpacity(0.05); + } + return const Color(0x00000000); + }); + } + + MaterialStateProperty get _trackBorderColor { + final Color onSurface = widget.color ?? _colorScheme.onSurface; + + return MaterialStateProperty.resolveWith((Set states) { + if (states.contains(MaterialState.hovered) && _showTrackOnHover) { + return _scrollbarTheme.trackBorderColor?.resolve(states) ?? + onSurface.withOpacity(0.1); + } + return const Color(0x00000000); + }); + } + + MaterialStateProperty get _thickness { + return MaterialStateProperty.resolveWith((Set states) { + if (states.contains(MaterialState.hovered) && _showTrackOnHover) + return widget.hoverThickness ?? + _scrollbarTheme.thickness?.resolve(states) ?? + _kScrollbarThicknessWithTrack; + // The default VsScrollbar thickness is smaller on mobile. + return widget.thickness ?? + _scrollbarTheme.thickness?.resolve(states) ?? + (_kScrollbarThickness / (_useAndroidScrollbar ? 2 : 1)); + }); + } + + @override + void initState() { + super.initState(); + _hoverAnimationController = AnimationController( + vsync: this, + duration: const Duration(milliseconds: 200), + ); + _hoverAnimationController.addListener(() { + updateScrollbarPainter(); + }); + } + + @override + void didChangeDependencies() { + final ThemeData theme = Theme.of(context); + _colorScheme = theme.colorScheme; + _scrollbarTheme = theme.scrollbarTheme; + switch (theme.platform) { + case TargetPlatform.android: + _useAndroidScrollbar = true; + break; + case TargetPlatform.iOS: + case TargetPlatform.linux: + case TargetPlatform.fuchsia: + case TargetPlatform.macOS: + case TargetPlatform.windows: + _useAndroidScrollbar = false; + break; + } + super.didChangeDependencies(); + } + + @override + void updateScrollbarPainter() { + scrollbarPainter + ..color = _thumbColor.resolve(_states) + ..trackColor = _trackColor.resolve(_states) + ..trackBorderColor = _trackBorderColor.resolve(_states) + ..textDirection = Directionality.of(context) + ..thickness = _thickness.resolve(_states) + ..radius = widget.radius ?? + _scrollbarTheme.radius ?? + (_useAndroidScrollbar ? null : _kScrollbarRadius) + ..crossAxisMargin = _scrollbarTheme.crossAxisMargin ?? + (_useAndroidScrollbar ? 0.0 : _kScrollbarMargin) + ..mainAxisMargin = _scrollbarTheme.mainAxisMargin ?? 0.0 + ..minLength = _scrollbarTheme.minThumbLength ?? _kScrollbarMinLength + ..padding = EdgeInsets.all(0); + } + + @override + void handleThumbPressStart(Offset localPosition) { + super.handleThumbPressStart(localPosition); + setState(() { + _dragIsActive = true; + }); + } + + @override + void handleThumbPressEnd(Offset localPosition, Velocity velocity) { + super.handleThumbPressEnd(localPosition, velocity); + setState(() { + _dragIsActive = false; + }); + } + + @override + void handleHover(PointerHoverEvent event) { + super.handleHover(event); + // Check if the position of the pointer falls over the painted VsScrollbar + if (isPointerOverScrollbar(event.position, PointerDeviceKind.mouse)) { + // Pointer is hovering over the VsScrollbar + setState(() { + _hoverIsActive = true; + }); + _hoverAnimationController.forward(); + } else if (_hoverIsActive) { + // Pointer was, but is no longer over painted VsScrollbar. + setState(() { + _hoverIsActive = false; + }); + _hoverAnimationController.reverse(); + } + } + + @override + void handleHoverExit(PointerExitEvent event) { + super.handleHoverExit(event); + setState(() { + _hoverIsActive = false; + }); + _hoverAnimationController.reverse(); + } + + @override + void dispose() { + _hoverAnimationController.dispose(); + super.dispose(); + } +} diff --git a/demos/supabase-trello/linux/.gitignore b/demos/supabase-trello/linux/.gitignore new file mode 100644 index 00000000..d3896c98 --- /dev/null +++ b/demos/supabase-trello/linux/.gitignore @@ -0,0 +1 @@ +flutter/ephemeral diff --git a/demos/supabase-trello/linux/CMakeLists.txt b/demos/supabase-trello/linux/CMakeLists.txt new file mode 100644 index 00000000..edd5d8f3 --- /dev/null +++ b/demos/supabase-trello/linux/CMakeLists.txt @@ -0,0 +1,139 @@ +# Project-level configuration. +cmake_minimum_required(VERSION 3.10) +project(runner LANGUAGES CXX) + +# The name of the executable created for the application. Change this to change +# the on-disk name of your application. +set(BINARY_NAME "trelloappclone_flutter") +# The unique GTK application identifier for this application. See: +# https://wiki.gnome.org/HowDoI/ChooseApplicationID +set(APPLICATION_ID "com.example.trelloappclone_flutter") + +# Explicitly opt in to modern CMake behaviors to avoid warnings with recent +# versions of CMake. +cmake_policy(SET CMP0063 NEW) + +# Load bundled libraries from the lib/ directory relative to the binary. +set(CMAKE_INSTALL_RPATH "$ORIGIN/lib") + +# Root filesystem for cross-building. +if(FLUTTER_TARGET_PLATFORM_SYSROOT) + set(CMAKE_SYSROOT ${FLUTTER_TARGET_PLATFORM_SYSROOT}) + set(CMAKE_FIND_ROOT_PATH ${CMAKE_SYSROOT}) + set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) + set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) + set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) + set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) +endif() + +# Define build configuration options. +if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) + set(CMAKE_BUILD_TYPE "Debug" CACHE + STRING "Flutter build mode" FORCE) + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS + "Debug" "Profile" "Release") +endif() + +# Compilation settings that should be applied to most targets. +# +# Be cautious about adding new options here, as plugins use this function by +# default. In most cases, you should add new options to specific targets instead +# of modifying this function. +function(APPLY_STANDARD_SETTINGS TARGET) + target_compile_features(${TARGET} PUBLIC cxx_std_14) + target_compile_options(${TARGET} PRIVATE -Wall -Werror) + target_compile_options(${TARGET} PRIVATE "$<$>:-O3>") + target_compile_definitions(${TARGET} PRIVATE "$<$>:NDEBUG>") +endfunction() + +# Flutter library and tool build rules. +set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") +add_subdirectory(${FLUTTER_MANAGED_DIR}) + +# System-level dependencies. +find_package(PkgConfig REQUIRED) +pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) + +add_definitions(-DAPPLICATION_ID="${APPLICATION_ID}") + +# Define the application target. To change its name, change BINARY_NAME above, +# not the value here, or `flutter run` will no longer work. +# +# Any new source files that you add to the application should be added here. +add_executable(${BINARY_NAME} + "main.cc" + "my_application.cc" + "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" +) + +# Apply the standard set of build settings. This can be removed for applications +# that need different build settings. +apply_standard_settings(${BINARY_NAME}) + +# Add dependency libraries. Add any application-specific dependencies here. +target_link_libraries(${BINARY_NAME} PRIVATE flutter) +target_link_libraries(${BINARY_NAME} PRIVATE PkgConfig::GTK) + +# Run the Flutter tool portions of the build. This must not be removed. +add_dependencies(${BINARY_NAME} flutter_assemble) + +# Only the install-generated bundle's copy of the executable will launch +# correctly, since the resources must in the right relative locations. To avoid +# people trying to run the unbundled copy, put it in a subdirectory instead of +# the default top-level location. +set_target_properties(${BINARY_NAME} + PROPERTIES + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/intermediates_do_not_run" +) + + +# Generated plugin build rules, which manage building the plugins and adding +# them to the application. +include(flutter/generated_plugins.cmake) + + +# === Installation === +# By default, "installing" just makes a relocatable bundle in the build +# directory. +set(BUILD_BUNDLE_DIR "${PROJECT_BINARY_DIR}/bundle") +if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) + set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE) +endif() + +# Start with a clean build bundle directory every time. +install(CODE " + file(REMOVE_RECURSE \"${BUILD_BUNDLE_DIR}/\") + " COMPONENT Runtime) + +set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data") +set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib") + +install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) + +foreach(bundled_library ${PLUGIN_BUNDLED_LIBRARIES}) + install(FILES "${bundled_library}" + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endforeach(bundled_library) + +# Fully re-copy the assets directory on each build to avoid having stale files +# from a previous install. +set(FLUTTER_ASSET_DIR_NAME "flutter_assets") +install(CODE " + file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\") + " COMPONENT Runtime) +install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}" + DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) + +# Install the AOT library on non-Debug builds only. +if(NOT CMAKE_BUILD_TYPE MATCHES "Debug") + install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endif() diff --git a/demos/supabase-trello/linux/flutter/CMakeLists.txt b/demos/supabase-trello/linux/flutter/CMakeLists.txt new file mode 100644 index 00000000..d5bd0164 --- /dev/null +++ b/demos/supabase-trello/linux/flutter/CMakeLists.txt @@ -0,0 +1,88 @@ +# This file controls Flutter-level build steps. It should not be edited. +cmake_minimum_required(VERSION 3.10) + +set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral") + +# Configuration provided via flutter tool. +include(${EPHEMERAL_DIR}/generated_config.cmake) + +# TODO: Move the rest of this into files in ephemeral. See +# https://github.com/flutter/flutter/issues/57146. + +# Serves the same purpose as list(TRANSFORM ... PREPEND ...), +# which isn't available in 3.10. +function(list_prepend LIST_NAME PREFIX) + set(NEW_LIST "") + foreach(element ${${LIST_NAME}}) + list(APPEND NEW_LIST "${PREFIX}${element}") + endforeach(element) + set(${LIST_NAME} "${NEW_LIST}" PARENT_SCOPE) +endfunction() + +# === Flutter Library === +# System-level dependencies. +find_package(PkgConfig REQUIRED) +pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) +pkg_check_modules(GLIB REQUIRED IMPORTED_TARGET glib-2.0) +pkg_check_modules(GIO REQUIRED IMPORTED_TARGET gio-2.0) + +set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/libflutter_linux_gtk.so") + +# Published to parent scope for install step. +set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE) +set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE) +set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE) +set(AOT_LIBRARY "${PROJECT_DIR}/build/lib/libapp.so" PARENT_SCOPE) + +list(APPEND FLUTTER_LIBRARY_HEADERS + "fl_basic_message_channel.h" + "fl_binary_codec.h" + "fl_binary_messenger.h" + "fl_dart_project.h" + "fl_engine.h" + "fl_json_message_codec.h" + "fl_json_method_codec.h" + "fl_message_codec.h" + "fl_method_call.h" + "fl_method_channel.h" + "fl_method_codec.h" + "fl_method_response.h" + "fl_plugin_registrar.h" + "fl_plugin_registry.h" + "fl_standard_message_codec.h" + "fl_standard_method_codec.h" + "fl_string_codec.h" + "fl_value.h" + "fl_view.h" + "flutter_linux.h" +) +list_prepend(FLUTTER_LIBRARY_HEADERS "${EPHEMERAL_DIR}/flutter_linux/") +add_library(flutter INTERFACE) +target_include_directories(flutter INTERFACE + "${EPHEMERAL_DIR}" +) +target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}") +target_link_libraries(flutter INTERFACE + PkgConfig::GTK + PkgConfig::GLIB + PkgConfig::GIO +) +add_dependencies(flutter flutter_assemble) + +# === Flutter tool backend === +# _phony_ is a non-existent file to force this command to run every time, +# since currently there's no way to get a full input/output list from the +# flutter tool. +add_custom_command( + OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} + ${CMAKE_CURRENT_BINARY_DIR}/_phony_ + COMMAND ${CMAKE_COMMAND} -E env + ${FLUTTER_TOOL_ENVIRONMENT} + "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.sh" + ${FLUTTER_TARGET_PLATFORM} ${CMAKE_BUILD_TYPE} + VERBATIM +) +add_custom_target(flutter_assemble DEPENDS + "${FLUTTER_LIBRARY}" + ${FLUTTER_LIBRARY_HEADERS} +) diff --git a/demos/supabase-trello/linux/flutter/generated_plugin_registrant.cc b/demos/supabase-trello/linux/flutter/generated_plugin_registrant.cc new file mode 100644 index 00000000..129b6b2f --- /dev/null +++ b/demos/supabase-trello/linux/flutter/generated_plugin_registrant.cc @@ -0,0 +1,31 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#include "generated_plugin_registrant.h" + +#include +#include +#include +#include +#include + +void fl_register_plugins(FlPluginRegistry* registry) { + g_autoptr(FlPluginRegistrar) file_selector_linux_registrar = + fl_plugin_registry_get_registrar_for_plugin(registry, "FileSelectorPlugin"); + file_selector_plugin_register_with_registrar(file_selector_linux_registrar); + g_autoptr(FlPluginRegistrar) gtk_registrar = + fl_plugin_registry_get_registrar_for_plugin(registry, "GtkPlugin"); + gtk_plugin_register_with_registrar(gtk_registrar); + g_autoptr(FlPluginRegistrar) powersync_flutter_libs_registrar = + fl_plugin_registry_get_registrar_for_plugin(registry, "PowersyncFlutterLibsPlugin"); + powersync_flutter_libs_plugin_register_with_registrar(powersync_flutter_libs_registrar); + g_autoptr(FlPluginRegistrar) sqlite3_flutter_libs_registrar = + fl_plugin_registry_get_registrar_for_plugin(registry, "Sqlite3FlutterLibsPlugin"); + sqlite3_flutter_libs_plugin_register_with_registrar(sqlite3_flutter_libs_registrar); + g_autoptr(FlPluginRegistrar) url_launcher_linux_registrar = + fl_plugin_registry_get_registrar_for_plugin(registry, "UrlLauncherPlugin"); + url_launcher_plugin_register_with_registrar(url_launcher_linux_registrar); +} diff --git a/demos/supabase-trello/linux/flutter/generated_plugin_registrant.h b/demos/supabase-trello/linux/flutter/generated_plugin_registrant.h new file mode 100644 index 00000000..e0f0a47b --- /dev/null +++ b/demos/supabase-trello/linux/flutter/generated_plugin_registrant.h @@ -0,0 +1,15 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#ifndef GENERATED_PLUGIN_REGISTRANT_ +#define GENERATED_PLUGIN_REGISTRANT_ + +#include + +// Registers Flutter plugins. +void fl_register_plugins(FlPluginRegistry* registry); + +#endif // GENERATED_PLUGIN_REGISTRANT_ diff --git a/demos/supabase-trello/linux/flutter/generated_plugins.cmake b/demos/supabase-trello/linux/flutter/generated_plugins.cmake new file mode 100644 index 00000000..c9e9c841 --- /dev/null +++ b/demos/supabase-trello/linux/flutter/generated_plugins.cmake @@ -0,0 +1,28 @@ +# +# Generated file, do not edit. +# + +list(APPEND FLUTTER_PLUGIN_LIST + file_selector_linux + gtk + powersync_flutter_libs + sqlite3_flutter_libs + url_launcher_linux +) + +list(APPEND FLUTTER_FFI_PLUGIN_LIST +) + +set(PLUGIN_BUNDLED_LIBRARIES) + +foreach(plugin ${FLUTTER_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/linux plugins/${plugin}) + target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) + list(APPEND PLUGIN_BUNDLED_LIBRARIES $) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) +endforeach(plugin) + +foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/linux plugins/${ffi_plugin}) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) +endforeach(ffi_plugin) diff --git a/demos/supabase-trello/linux/main.cc b/demos/supabase-trello/linux/main.cc new file mode 100644 index 00000000..e7c5c543 --- /dev/null +++ b/demos/supabase-trello/linux/main.cc @@ -0,0 +1,6 @@ +#include "my_application.h" + +int main(int argc, char** argv) { + g_autoptr(MyApplication) app = my_application_new(); + return g_application_run(G_APPLICATION(app), argc, argv); +} diff --git a/demos/supabase-trello/linux/my_application.cc b/demos/supabase-trello/linux/my_application.cc new file mode 100644 index 00000000..e91e0138 --- /dev/null +++ b/demos/supabase-trello/linux/my_application.cc @@ -0,0 +1,104 @@ +#include "my_application.h" + +#include +#ifdef GDK_WINDOWING_X11 +#include +#endif + +#include "flutter/generated_plugin_registrant.h" + +struct _MyApplication { + GtkApplication parent_instance; + char** dart_entrypoint_arguments; +}; + +G_DEFINE_TYPE(MyApplication, my_application, GTK_TYPE_APPLICATION) + +// Implements GApplication::activate. +static void my_application_activate(GApplication* application) { + MyApplication* self = MY_APPLICATION(application); + GtkWindow* window = + GTK_WINDOW(gtk_application_window_new(GTK_APPLICATION(application))); + + // Use a header bar when running in GNOME as this is the common style used + // by applications and is the setup most users will be using (e.g. Ubuntu + // desktop). + // If running on X and not using GNOME then just use a traditional title bar + // in case the window manager does more exotic layout, e.g. tiling. + // If running on Wayland assume the header bar will work (may need changing + // if future cases occur). + gboolean use_header_bar = TRUE; +#ifdef GDK_WINDOWING_X11 + GdkScreen* screen = gtk_window_get_screen(window); + if (GDK_IS_X11_SCREEN(screen)) { + const gchar* wm_name = gdk_x11_screen_get_window_manager_name(screen); + if (g_strcmp0(wm_name, "GNOME Shell") != 0) { + use_header_bar = FALSE; + } + } +#endif + if (use_header_bar) { + GtkHeaderBar* header_bar = GTK_HEADER_BAR(gtk_header_bar_new()); + gtk_widget_show(GTK_WIDGET(header_bar)); + gtk_header_bar_set_title(header_bar, "trelloappclone_flutter"); + gtk_header_bar_set_show_close_button(header_bar, TRUE); + gtk_window_set_titlebar(window, GTK_WIDGET(header_bar)); + } else { + gtk_window_set_title(window, "trelloappclone_flutter"); + } + + gtk_window_set_default_size(window, 1280, 720); + gtk_widget_show(GTK_WIDGET(window)); + + g_autoptr(FlDartProject) project = fl_dart_project_new(); + fl_dart_project_set_dart_entrypoint_arguments(project, self->dart_entrypoint_arguments); + + FlView* view = fl_view_new(project); + gtk_widget_show(GTK_WIDGET(view)); + gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(view)); + + fl_register_plugins(FL_PLUGIN_REGISTRY(view)); + + gtk_widget_grab_focus(GTK_WIDGET(view)); +} + +// Implements GApplication::local_command_line. +static gboolean my_application_local_command_line(GApplication* application, gchar*** arguments, int* exit_status) { + MyApplication* self = MY_APPLICATION(application); + // Strip out the first argument as it is the binary name. + self->dart_entrypoint_arguments = g_strdupv(*arguments + 1); + + g_autoptr(GError) error = nullptr; + if (!g_application_register(application, nullptr, &error)) { + g_warning("Failed to register: %s", error->message); + *exit_status = 1; + return TRUE; + } + + g_application_activate(application); + *exit_status = 0; + + return TRUE; +} + +// Implements GObject::dispose. +static void my_application_dispose(GObject* object) { + MyApplication* self = MY_APPLICATION(object); + g_clear_pointer(&self->dart_entrypoint_arguments, g_strfreev); + G_OBJECT_CLASS(my_application_parent_class)->dispose(object); +} + +static void my_application_class_init(MyApplicationClass* klass) { + G_APPLICATION_CLASS(klass)->activate = my_application_activate; + G_APPLICATION_CLASS(klass)->local_command_line = my_application_local_command_line; + G_OBJECT_CLASS(klass)->dispose = my_application_dispose; +} + +static void my_application_init(MyApplication* self) {} + +MyApplication* my_application_new() { + return MY_APPLICATION(g_object_new(my_application_get_type(), + "application-id", APPLICATION_ID, + "flags", G_APPLICATION_NON_UNIQUE, + nullptr)); +} diff --git a/demos/supabase-trello/linux/my_application.h b/demos/supabase-trello/linux/my_application.h new file mode 100644 index 00000000..72271d5e --- /dev/null +++ b/demos/supabase-trello/linux/my_application.h @@ -0,0 +1,18 @@ +#ifndef FLUTTER_MY_APPLICATION_H_ +#define FLUTTER_MY_APPLICATION_H_ + +#include + +G_DECLARE_FINAL_TYPE(MyApplication, my_application, MY, APPLICATION, + GtkApplication) + +/** + * my_application_new: + * + * Creates a new Flutter-based application. + * + * Returns: a new #MyApplication. + */ +MyApplication* my_application_new(); + +#endif // FLUTTER_MY_APPLICATION_H_ diff --git a/demos/supabase-trello/macos/.gitignore b/demos/supabase-trello/macos/.gitignore new file mode 100644 index 00000000..746adbb6 --- /dev/null +++ b/demos/supabase-trello/macos/.gitignore @@ -0,0 +1,7 @@ +# Flutter-related +**/Flutter/ephemeral/ +**/Pods/ + +# Xcode-related +**/dgph +**/xcuserdata/ diff --git a/demos/supabase-trello/macos/Flutter/Flutter-Debug.xcconfig b/demos/supabase-trello/macos/Flutter/Flutter-Debug.xcconfig new file mode 100644 index 00000000..4b81f9b2 --- /dev/null +++ b/demos/supabase-trello/macos/Flutter/Flutter-Debug.xcconfig @@ -0,0 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" +#include "ephemeral/Flutter-Generated.xcconfig" diff --git a/demos/supabase-trello/macos/Flutter/Flutter-Release.xcconfig b/demos/supabase-trello/macos/Flutter/Flutter-Release.xcconfig new file mode 100644 index 00000000..5caa9d15 --- /dev/null +++ b/demos/supabase-trello/macos/Flutter/Flutter-Release.xcconfig @@ -0,0 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" +#include "ephemeral/Flutter-Generated.xcconfig" diff --git a/demos/supabase-trello/macos/Flutter/GeneratedPluginRegistrant.swift b/demos/supabase-trello/macos/Flutter/GeneratedPluginRegistrant.swift new file mode 100644 index 00000000..6bf5ce92 --- /dev/null +++ b/demos/supabase-trello/macos/Flutter/GeneratedPluginRegistrant.swift @@ -0,0 +1,24 @@ +// +// Generated file. Do not edit. +// + +import FlutterMacOS +import Foundation + +import app_links +import file_selector_macos +import path_provider_foundation +import powersync_flutter_libs +import shared_preferences_foundation +import sqlite3_flutter_libs +import url_launcher_macos + +func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { + AppLinksMacosPlugin.register(with: registry.registrar(forPlugin: "AppLinksMacosPlugin")) + FileSelectorPlugin.register(with: registry.registrar(forPlugin: "FileSelectorPlugin")) + PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) + PowersyncFlutterLibsPlugin.register(with: registry.registrar(forPlugin: "PowersyncFlutterLibsPlugin")) + SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) + Sqlite3FlutterLibsPlugin.register(with: registry.registrar(forPlugin: "Sqlite3FlutterLibsPlugin")) + UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin")) +} diff --git a/demos/supabase-trello/macos/Podfile b/demos/supabase-trello/macos/Podfile new file mode 100644 index 00000000..c795730d --- /dev/null +++ b/demos/supabase-trello/macos/Podfile @@ -0,0 +1,43 @@ +platform :osx, '10.14' + +# CocoaPods analytics sends network stats synchronously affecting flutter build latency. +ENV['COCOAPODS_DISABLE_STATS'] = 'true' + +project 'Runner', { + 'Debug' => :debug, + 'Profile' => :release, + 'Release' => :release, +} + +def flutter_root + generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'ephemeral', 'Flutter-Generated.xcconfig'), __FILE__) + unless File.exist?(generated_xcode_build_settings_path) + raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure \"flutter pub get\" is executed first" + end + + File.foreach(generated_xcode_build_settings_path) do |line| + matches = line.match(/FLUTTER_ROOT\=(.*)/) + return matches[1].strip if matches + end + raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Flutter-Generated.xcconfig, then run \"flutter pub get\"" +end + +require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) + +flutter_macos_podfile_setup + +target 'Runner' do + use_frameworks! + use_modular_headers! + + flutter_install_all_macos_pods File.dirname(File.realpath(__FILE__)) + target 'RunnerTests' do + inherit! :search_paths + end +end + +post_install do |installer| + installer.pods_project.targets.each do |target| + flutter_additional_macos_build_settings(target) + end +end diff --git a/demos/supabase-trello/macos/Podfile.lock b/demos/supabase-trello/macos/Podfile.lock new file mode 100644 index 00000000..db99ed48 --- /dev/null +++ b/demos/supabase-trello/macos/Podfile.lock @@ -0,0 +1,78 @@ +PODS: + - app_links (1.0.0): + - FlutterMacOS + - file_selector_macos (0.0.1): + - FlutterMacOS + - FlutterMacOS (1.0.0) + - path_provider_foundation (0.0.1): + - Flutter + - FlutterMacOS + - shared_preferences_foundation (0.0.1): + - Flutter + - FlutterMacOS + - sign_in_with_apple (0.0.1): + - FlutterMacOS + - sqlite3 (3.44.0): + - sqlite3/common (= 3.44.0) + - sqlite3/common (3.44.0) + - sqlite3/fts5 (3.44.0): + - sqlite3/common + - sqlite3/perf-threadsafe (3.44.0): + - sqlite3/common + - sqlite3/rtree (3.44.0): + - sqlite3/common + - sqlite3_flutter_libs (0.0.1): + - FlutterMacOS + - sqlite3 (~> 3.44.0) + - sqlite3/fts5 + - sqlite3/perf-threadsafe + - sqlite3/rtree + - url_launcher_macos (0.0.1): + - FlutterMacOS + +DEPENDENCIES: + - app_links (from `Flutter/ephemeral/.symlinks/plugins/app_links/macos`) + - file_selector_macos (from `Flutter/ephemeral/.symlinks/plugins/file_selector_macos/macos`) + - FlutterMacOS (from `Flutter/ephemeral`) + - path_provider_foundation (from `Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin`) + - shared_preferences_foundation (from `Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin`) + - sign_in_with_apple (from `Flutter/ephemeral/.symlinks/plugins/sign_in_with_apple/macos`) + - sqlite3_flutter_libs (from `Flutter/ephemeral/.symlinks/plugins/sqlite3_flutter_libs/macos`) + - url_launcher_macos (from `Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos`) + +SPEC REPOS: + trunk: + - sqlite3 + +EXTERNAL SOURCES: + app_links: + :path: Flutter/ephemeral/.symlinks/plugins/app_links/macos + file_selector_macos: + :path: Flutter/ephemeral/.symlinks/plugins/file_selector_macos/macos + FlutterMacOS: + :path: Flutter/ephemeral + path_provider_foundation: + :path: Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin + shared_preferences_foundation: + :path: Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin + sign_in_with_apple: + :path: Flutter/ephemeral/.symlinks/plugins/sign_in_with_apple/macos + sqlite3_flutter_libs: + :path: Flutter/ephemeral/.symlinks/plugins/sqlite3_flutter_libs/macos + url_launcher_macos: + :path: Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos + +SPEC CHECKSUMS: + app_links: 4481ed4d71f384b0c3ae5016f4633aa73d32ff67 + file_selector_macos: 468fb6b81fac7c0e88d71317f3eec34c3b008ff9 + FlutterMacOS: 8f6f14fa908a6fb3fba0cd85dbd81ec4b251fb24 + path_provider_foundation: 29f094ae23ebbca9d3d0cec13889cd9060c0e943 + shared_preferences_foundation: 5b919d13b803cadd15ed2dc053125c68730e5126 + sign_in_with_apple: a9e97e744e8edc36aefc2723111f652102a7a727 + sqlite3: 6e2d4a4879854d0ec86b476bf3c3e30870bac273 + sqlite3_flutter_libs: a25f3a0f522fdcd8fef6a4a50a3d681dd43d8dea + url_launcher_macos: d2691c7dd33ed713bf3544850a623080ec693d95 + +PODFILE CHECKSUM: 236401fc2c932af29a9fcf0e97baeeb2d750d367 + +COCOAPODS: 1.13.0 diff --git a/demos/supabase-trello/macos/Runner.xcodeproj/project.pbxproj b/demos/supabase-trello/macos/Runner.xcodeproj/project.pbxproj new file mode 100644 index 00000000..410d47d9 --- /dev/null +++ b/demos/supabase-trello/macos/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,791 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 54; + objects = { + +/* Begin PBXAggregateTarget section */ + 33CC111A2044C6BA0003C045 /* Flutter Assemble */ = { + isa = PBXAggregateTarget; + buildConfigurationList = 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */; + buildPhases = ( + 33CC111E2044C6BF0003C045 /* ShellScript */, + ); + dependencies = ( + ); + name = "Flutter Assemble"; + productName = FLX; + }; +/* End PBXAggregateTarget section */ + +/* Begin PBXBuildFile section */ + 331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C80D7294CF71000263BE5 /* RunnerTests.swift */; }; + 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */; }; + 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC10F02044A3C60003C045 /* AppDelegate.swift */; }; + 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; }; + 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; }; + 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; }; + 4E4963C86BC785F23F648E0B /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A80D2BD607CA38846657D9B0 /* Pods_RunnerTests.framework */; }; + 9E95FABB7D4E5912BF4FE47B /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D41298BB1DE04D5251142AE7 /* Pods_Runner.framework */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 331C80D9294CF71000263BE5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 33CC10E52044A3C60003C045 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 33CC10EC2044A3C60003C045; + remoteInfo = Runner; + }; + 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 33CC10E52044A3C60003C045 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 33CC111A2044C6BA0003C045; + remoteInfo = FLX; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 33CC110E2044A8840003C045 /* Bundle Framework */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Bundle Framework"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 2D2712CAF1EB5DE8C09B8534 /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = ""; }; + 331C80D5294CF71000263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 331C80D7294CF71000263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; + 333000ED22D3DE5D00554162 /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = ""; }; + 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneratedPluginRegistrant.swift; sourceTree = ""; }; + 33CC10ED2044A3C60003C045 /* trelloappclone_flutter.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = trelloappclone_flutter.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 33CC10F02044A3C60003C045 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 33CC10F22044A3C60003C045 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = Runner/Assets.xcassets; sourceTree = ""; }; + 33CC10F52044A3C60003C045 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; + 33CC10F72044A3C60003C045 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Info.plist; path = Runner/Info.plist; sourceTree = ""; }; + 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainFlutterWindow.swift; sourceTree = ""; }; + 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Debug.xcconfig"; sourceTree = ""; }; + 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Release.xcconfig"; sourceTree = ""; }; + 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = "Flutter-Generated.xcconfig"; path = "ephemeral/Flutter-Generated.xcconfig"; sourceTree = ""; }; + 33E51913231747F40026EE4D /* DebugProfile.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DebugProfile.entitlements; sourceTree = ""; }; + 33E51914231749380026EE4D /* Release.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Release.entitlements; sourceTree = ""; }; + 33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = ""; }; + 4D2CF99A3C595901E898A5A1 /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = ""; }; + 5E01E450DF23BB04BA05D6DF /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = ""; }; + 7D86C2AB85DE03E2BC92BD82 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; + 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = ""; }; + 9F1765F95B32AB229EDC81A4 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; + A80D2BD607CA38846657D9B0 /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + D1E469A34757CC55006C694C /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = ""; }; + D41298BB1DE04D5251142AE7 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 331C80D2294CF70F00263BE5 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 4E4963C86BC785F23F648E0B /* Pods_RunnerTests.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 33CC10EA2044A3C60003C045 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 9E95FABB7D4E5912BF4FE47B /* Pods_Runner.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 28F54DBEE7BF5990E862A72B /* Pods */ = { + isa = PBXGroup; + children = ( + 9F1765F95B32AB229EDC81A4 /* Pods-Runner.debug.xcconfig */, + 7D86C2AB85DE03E2BC92BD82 /* Pods-Runner.release.xcconfig */, + 5E01E450DF23BB04BA05D6DF /* Pods-Runner.profile.xcconfig */, + 2D2712CAF1EB5DE8C09B8534 /* Pods-RunnerTests.debug.xcconfig */, + 4D2CF99A3C595901E898A5A1 /* Pods-RunnerTests.release.xcconfig */, + D1E469A34757CC55006C694C /* Pods-RunnerTests.profile.xcconfig */, + ); + name = Pods; + path = Pods; + sourceTree = ""; + }; + 331C80D6294CF71000263BE5 /* RunnerTests */ = { + isa = PBXGroup; + children = ( + 331C80D7294CF71000263BE5 /* RunnerTests.swift */, + ); + path = RunnerTests; + sourceTree = ""; + }; + 33BA886A226E78AF003329D5 /* Configs */ = { + isa = PBXGroup; + children = ( + 33E5194F232828860026EE4D /* AppInfo.xcconfig */, + 9740EEB21CF90195004384FC /* Debug.xcconfig */, + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, + 333000ED22D3DE5D00554162 /* Warnings.xcconfig */, + ); + path = Configs; + sourceTree = ""; + }; + 33CC10E42044A3C60003C045 = { + isa = PBXGroup; + children = ( + 33FAB671232836740065AC1E /* Runner */, + 33CEB47122A05771004F2AC0 /* Flutter */, + 331C80D6294CF71000263BE5 /* RunnerTests */, + 33CC10EE2044A3C60003C045 /* Products */, + D73912EC22F37F3D000D13A0 /* Frameworks */, + 28F54DBEE7BF5990E862A72B /* Pods */, + ); + sourceTree = ""; + }; + 33CC10EE2044A3C60003C045 /* Products */ = { + isa = PBXGroup; + children = ( + 33CC10ED2044A3C60003C045 /* trelloappclone_flutter.app */, + 331C80D5294CF71000263BE5 /* RunnerTests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + 33CC11242044D66E0003C045 /* Resources */ = { + isa = PBXGroup; + children = ( + 33CC10F22044A3C60003C045 /* Assets.xcassets */, + 33CC10F42044A3C60003C045 /* MainMenu.xib */, + 33CC10F72044A3C60003C045 /* Info.plist */, + ); + name = Resources; + path = ..; + sourceTree = ""; + }; + 33CEB47122A05771004F2AC0 /* Flutter */ = { + isa = PBXGroup; + children = ( + 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */, + 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */, + 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */, + 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */, + ); + path = Flutter; + sourceTree = ""; + }; + 33FAB671232836740065AC1E /* Runner */ = { + isa = PBXGroup; + children = ( + 33CC10F02044A3C60003C045 /* AppDelegate.swift */, + 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */, + 33E51913231747F40026EE4D /* DebugProfile.entitlements */, + 33E51914231749380026EE4D /* Release.entitlements */, + 33CC11242044D66E0003C045 /* Resources */, + 33BA886A226E78AF003329D5 /* Configs */, + ); + path = Runner; + sourceTree = ""; + }; + D73912EC22F37F3D000D13A0 /* Frameworks */ = { + isa = PBXGroup; + children = ( + D41298BB1DE04D5251142AE7 /* Pods_Runner.framework */, + A80D2BD607CA38846657D9B0 /* Pods_RunnerTests.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 331C80D4294CF70F00263BE5 /* RunnerTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; + buildPhases = ( + 125EE0D4B5332F47B3E8DC59 /* [CP] Check Pods Manifest.lock */, + 331C80D1294CF70F00263BE5 /* Sources */, + 331C80D2294CF70F00263BE5 /* Frameworks */, + 331C80D3294CF70F00263BE5 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 331C80DA294CF71000263BE5 /* PBXTargetDependency */, + ); + name = RunnerTests; + productName = RunnerTests; + productReference = 331C80D5294CF71000263BE5 /* RunnerTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; + 33CC10EC2044A3C60003C045 /* Runner */ = { + isa = PBXNativeTarget; + buildConfigurationList = 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */; + buildPhases = ( + 95B0EDBAFB4503A28905DD2B /* [CP] Check Pods Manifest.lock */, + 33CC10E92044A3C60003C045 /* Sources */, + 33CC10EA2044A3C60003C045 /* Frameworks */, + 33CC10EB2044A3C60003C045 /* Resources */, + 33CC110E2044A8840003C045 /* Bundle Framework */, + 3399D490228B24CF009A79C7 /* ShellScript */, + DFB0D194C13543172E694703 /* [CP] Embed Pods Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + 33CC11202044C79F0003C045 /* PBXTargetDependency */, + ); + name = Runner; + productName = Runner; + productReference = 33CC10ED2044A3C60003C045 /* trelloappclone_flutter.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 33CC10E52044A3C60003C045 /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 0920; + LastUpgradeCheck = 1430; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 331C80D4294CF70F00263BE5 = { + CreatedOnToolsVersion = 14.0; + TestTargetID = 33CC10EC2044A3C60003C045; + }; + 33CC10EC2044A3C60003C045 = { + CreatedOnToolsVersion = 9.2; + LastSwiftMigration = 1100; + ProvisioningStyle = Automatic; + SystemCapabilities = { + com.apple.Sandbox = { + enabled = 1; + }; + }; + }; + 33CC111A2044C6BA0003C045 = { + CreatedOnToolsVersion = 9.2; + ProvisioningStyle = Manual; + }; + }; + }; + buildConfigurationList = 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 33CC10E42044A3C60003C045; + productRefGroup = 33CC10EE2044A3C60003C045 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 33CC10EC2044A3C60003C045 /* Runner */, + 331C80D4294CF70F00263BE5 /* RunnerTests */, + 33CC111A2044C6BA0003C045 /* Flutter Assemble */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 331C80D3294CF70F00263BE5 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 33CC10EB2044A3C60003C045 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */, + 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 125EE0D4B5332F47B3E8DC59 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-RunnerTests-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; + 3399D490228B24CF009A79C7 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + ); + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "echo \"$PRODUCT_NAME.app\" > \"$PROJECT_DIR\"/Flutter/ephemeral/.app_filename && \"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh embed\n"; + }; + 33CC111E2044C6BF0003C045 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + Flutter/ephemeral/FlutterInputs.xcfilelist, + ); + inputPaths = ( + Flutter/ephemeral/tripwire, + ); + outputFileListPaths = ( + Flutter/ephemeral/FlutterOutputs.xcfilelist, + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh && touch Flutter/ephemeral/tripwire"; + }; + 95B0EDBAFB4503A28905DD2B /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; + DFB0D194C13543172E694703 /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Embed Pods Frameworks"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 331C80D1294CF70F00263BE5 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 33CC10E92044A3C60003C045 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */, + 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */, + 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 331C80DA294CF71000263BE5 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 33CC10EC2044A3C60003C045 /* Runner */; + targetProxy = 331C80D9294CF71000263BE5 /* PBXContainerItemProxy */; + }; + 33CC11202044C79F0003C045 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 33CC111A2044C6BA0003C045 /* Flutter Assemble */; + targetProxy = 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin PBXVariantGroup section */ + 33CC10F42044A3C60003C045 /* MainMenu.xib */ = { + isa = PBXVariantGroup; + children = ( + 33CC10F52044A3C60003C045 /* Base */, + ); + name = MainMenu.xib; + path = Runner; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 331C80DB294CF71000263BE5 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 2D2712CAF1EB5DE8C09B8534 /* Pods-RunnerTests.debug.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.trelloappcloneFlutter.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/trelloappclone_flutter.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/trelloappclone_flutter"; + }; + name = Debug; + }; + 331C80DC294CF71000263BE5 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 4D2CF99A3C595901E898A5A1 /* Pods-RunnerTests.release.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.trelloappcloneFlutter.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/trelloappclone_flutter.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/trelloappclone_flutter"; + }; + name = Release; + }; + 331C80DD294CF71000263BE5 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = D1E469A34757CC55006C694C /* Pods-RunnerTests.profile.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.trelloappcloneFlutter.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/trelloappclone_flutter.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/trelloappclone_flutter"; + }; + name = Profile; + }; + 338D0CE9231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.14; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = macosx; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + }; + name = Profile; + }; + 338D0CEA231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_VERSION = 5.0; + }; + name = Profile; + }; + 338D0CEB231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Manual; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Profile; + }; + 33CC10F92044A3C60003C045 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.14; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = macosx; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + 33CC10FA2044A3C60003C045 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.14; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = macosx; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + }; + name = Release; + }; + 33CC10FC2044A3C60003C045 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + }; + name = Debug; + }; + 33CC10FD2044A3C60003C045 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/Release.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_VERSION = 5.0; + }; + name = Release; + }; + 33CC111C2044C6BA0003C045 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Manual; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + 33CC111D2044C6BA0003C045 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 331C80DB294CF71000263BE5 /* Debug */, + 331C80DC294CF71000263BE5 /* Release */, + 331C80DD294CF71000263BE5 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC10F92044A3C60003C045 /* Debug */, + 33CC10FA2044A3C60003C045 /* Release */, + 338D0CE9231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC10FC2044A3C60003C045 /* Debug */, + 33CC10FD2044A3C60003C045 /* Release */, + 338D0CEA231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC111C2044C6BA0003C045 /* Debug */, + 33CC111D2044C6BA0003C045 /* Release */, + 338D0CEB231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 33CC10E52044A3C60003C045 /* Project object */; +} diff --git a/demos/supabase-trello/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/demos/supabase-trello/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 00000000..18d98100 --- /dev/null +++ b/demos/supabase-trello/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/demos/supabase-trello/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/demos/supabase-trello/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme new file mode 100644 index 00000000..9a756df2 --- /dev/null +++ b/demos/supabase-trello/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,98 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/demos/supabase-trello/macos/Runner.xcworkspace/contents.xcworkspacedata b/demos/supabase-trello/macos/Runner.xcworkspace/contents.xcworkspacedata new file mode 100644 index 00000000..21a3cc14 --- /dev/null +++ b/demos/supabase-trello/macos/Runner.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/demos/supabase-trello/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/demos/supabase-trello/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 00000000..18d98100 --- /dev/null +++ b/demos/supabase-trello/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/demos/supabase-trello/macos/Runner/AppDelegate.swift b/demos/supabase-trello/macos/Runner/AppDelegate.swift new file mode 100644 index 00000000..d53ef643 --- /dev/null +++ b/demos/supabase-trello/macos/Runner/AppDelegate.swift @@ -0,0 +1,9 @@ +import Cocoa +import FlutterMacOS + +@NSApplicationMain +class AppDelegate: FlutterAppDelegate { + override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { + return true + } +} diff --git a/demos/supabase-trello/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/demos/supabase-trello/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 00000000..a2ec33f1 --- /dev/null +++ b/demos/supabase-trello/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,68 @@ +{ + "images" : [ + { + "size" : "16x16", + "idiom" : "mac", + "filename" : "app_icon_16.png", + "scale" : "1x" + }, + { + "size" : "16x16", + "idiom" : "mac", + "filename" : "app_icon_32.png", + "scale" : "2x" + }, + { + "size" : "32x32", + "idiom" : "mac", + "filename" : "app_icon_32.png", + "scale" : "1x" + }, + { + "size" : "32x32", + "idiom" : "mac", + "filename" : "app_icon_64.png", + "scale" : "2x" + }, + { + "size" : "128x128", + "idiom" : "mac", + "filename" : "app_icon_128.png", + "scale" : "1x" + }, + { + "size" : "128x128", + "idiom" : "mac", + "filename" : "app_icon_256.png", + "scale" : "2x" + }, + { + "size" : "256x256", + "idiom" : "mac", + "filename" : "app_icon_256.png", + "scale" : "1x" + }, + { + "size" : "256x256", + "idiom" : "mac", + "filename" : "app_icon_512.png", + "scale" : "2x" + }, + { + "size" : "512x512", + "idiom" : "mac", + "filename" : "app_icon_512.png", + "scale" : "1x" + }, + { + "size" : "512x512", + "idiom" : "mac", + "filename" : "app_icon_1024.png", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/demos/supabase-trello/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png b/demos/supabase-trello/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png new file mode 100644 index 0000000000000000000000000000000000000000..82b6f9d9a33e198f5747104729e1fcef999772a5 GIT binary patch literal 102994 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ⅅ8MglG&ER{i5lN315cO?EdHNLrg? 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 z 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 Pe7HEdAEg|=c=LY&YVNkY literal 0 HcmV?d00001 diff --git a/demos/supabase-trello/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png b/demos/supabase-trello/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png new file mode 100644 index 0000000000000000000000000000000000000000..13b35eba55c6dabc3aac36f33d859266c18fa0d0 GIT binary patch literal 5680 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 literal 0 HcmV?d00001 diff --git a/demos/supabase-trello/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png b/demos/supabase-trello/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png new file mode 100644 index 0000000000000000000000000000000000000000..0a3f5fa40fb3d1e0710331a48de5d256da3f275d GIT binary patch literal 520 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 literal 0 HcmV?d00001 diff --git a/demos/supabase-trello/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png b/demos/supabase-trello/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png new file mode 100644 index 0000000000000000000000000000000000000000..2f1632cfddf3d9dade342351e627a0a75609fb46 GIT binary patch literal 2218 zcmV;b2vzrqP)Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91K%fHv1ONa40RR91KmY&$07g+lumAuE6iGxuRCodHTWf3-RTMruyW6Fu zQYeUM04eX6D5c0FCjKKPrco1(K`<0SL=crI{PC3-^hZU0kQie$gh-5!7z6SH6Q0J% zqot*`H1q{R5fHFYS}dje@;kG=v$L0(yY0?wY2%*c?A&{2?!D*x?m71{of2gv!$5|C z3>qG_BW}7K_yUcT3A5C6QD<+{aq?x;MAUyAiJn#Jv8_zZtQ{P zTRzbL3U9!qVuZzS$xKU10KiW~Bgdcv1-!uAhQxf3a7q+dU6lj?yoO4Lq4TUN4}h{N z*fIM=SS8|C2$(T>w$`t@3Tka!(r!7W`x z-isCVgQD^mG-MJ;XtJuK3V{Vy72GQ83KRWsHU?e*wrhKk=ApIYeDqLi;JI1e zuvv}5^Dc=k7F7?nm3nIw$NVmU-+R>> zyqOR$-2SDpJ}Pt;^RkJytDVXNTsu|mI1`~G7yw`EJR?VkGfNdqK9^^8P`JdtTV&tX4CNcV4 z&N06nZa??Fw1AgQOUSE2AmPE@WO(Fvo`%m`cDgiv(fAeRA%3AGXUbsGw{7Q`cY;1BI#ac3iN$$Hw z0LT0;xc%=q)me?Y*$xI@GRAw?+}>=9D+KTk??-HJ4=A>`V&vKFS75@MKdSF1JTq{S zc1!^8?YA|t+uKigaq!sT;Z!&0F2=k7F0PIU;F$leJLaw2UI6FL^w}OG&!;+b%ya1c z1n+6-inU<0VM-Y_s5iTElq)ThyF?StVcebpGI znw#+zLx2@ah{$_2jn+@}(zJZ{+}_N9BM;z)0yr|gF-4=Iyu@hI*Lk=-A8f#bAzc9f z`Kd6K--x@t04swJVC3JK1cHY-Hq+=|PN-VO;?^_C#;coU6TDP7Bt`;{JTG;!+jj(` zw5cLQ-(Cz-Tlb`A^w7|R56Ce;Wmr0)$KWOUZ6ai0PhzPeHwdl0H(etP zUV`va_i0s-4#DkNM8lUlqI7>YQLf)(lz9Q3Uw`)nc(z3{m5ZE77Ul$V%m)E}3&8L0 z-XaU|eB~Is08eORPk;=<>!1w)Kf}FOVS2l&9~A+@R#koFJ$Czd%Y(ENTV&A~U(IPI z;UY+gf+&6ioZ=roly<0Yst8ck>(M=S?B-ys3mLdM&)ex!hbt+ol|T6CTS+Sc0jv(& z7ijdvFwBq;0a{%3GGwkDKTeG`b+lyj0jjS1OMkYnepCdoosNY`*zmBIo*981BU%%U z@~$z0V`OVtIbEx5pa|Tct|Lg#ZQf5OYMUMRD>Wdxm5SAqV2}3!ceE-M2 z@O~lQ0OiKQp}o9I;?uxCgYVV?FH|?Riri*U$Zi_`V2eiA>l zdSm6;SEm6#T+SpcE8Ro_f2AwxzI z44hfe^WE3!h@W3RDyA_H440cpmYkv*)6m1XazTqw%=E5Xv7^@^^T7Q2wxr+Z2kVYr + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/demos/supabase-trello/macos/Runner/Configs/AppInfo.xcconfig b/demos/supabase-trello/macos/Runner/Configs/AppInfo.xcconfig new file mode 100644 index 00000000..47fffa43 --- /dev/null +++ b/demos/supabase-trello/macos/Runner/Configs/AppInfo.xcconfig @@ -0,0 +1,14 @@ +// Application-level settings for the Runner target. +// +// This may be replaced with something auto-generated from metadata (e.g., pubspec.yaml) in the +// future. If not, the values below would default to using the project name when this becomes a +// 'flutter create' template. + +// The application's name. By default this is also the title of the Flutter window. +PRODUCT_NAME = trelloappclone_flutter + +// The application's bundle identifier +PRODUCT_BUNDLE_IDENTIFIER = com.example.trelloappcloneFlutter + +// The copyright displayed in application information +PRODUCT_COPYRIGHT = Copyright © 2023 com.example. All rights reserved. diff --git a/demos/supabase-trello/macos/Runner/Configs/Debug.xcconfig b/demos/supabase-trello/macos/Runner/Configs/Debug.xcconfig new file mode 100644 index 00000000..36b0fd94 --- /dev/null +++ b/demos/supabase-trello/macos/Runner/Configs/Debug.xcconfig @@ -0,0 +1,2 @@ +#include "../../Flutter/Flutter-Debug.xcconfig" +#include "Warnings.xcconfig" diff --git a/demos/supabase-trello/macos/Runner/Configs/Release.xcconfig b/demos/supabase-trello/macos/Runner/Configs/Release.xcconfig new file mode 100644 index 00000000..dff4f495 --- /dev/null +++ b/demos/supabase-trello/macos/Runner/Configs/Release.xcconfig @@ -0,0 +1,2 @@ +#include "../../Flutter/Flutter-Release.xcconfig" +#include "Warnings.xcconfig" diff --git a/demos/supabase-trello/macos/Runner/Configs/Warnings.xcconfig b/demos/supabase-trello/macos/Runner/Configs/Warnings.xcconfig new file mode 100644 index 00000000..42bcbf47 --- /dev/null +++ b/demos/supabase-trello/macos/Runner/Configs/Warnings.xcconfig @@ -0,0 +1,13 @@ +WARNING_CFLAGS = -Wall -Wconditional-uninitialized -Wnullable-to-nonnull-conversion -Wmissing-method-return-type -Woverlength-strings +GCC_WARN_UNDECLARED_SELECTOR = YES +CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES +CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE +CLANG_WARN__DUPLICATE_METHOD_MATCH = YES +CLANG_WARN_PRAGMA_PACK = YES +CLANG_WARN_STRICT_PROTOTYPES = YES +CLANG_WARN_COMMA = YES +GCC_WARN_STRICT_SELECTOR_MATCH = YES +CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES +CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES +GCC_WARN_SHADOW = YES +CLANG_WARN_UNREACHABLE_CODE = YES diff --git a/demos/supabase-trello/macos/Runner/DebugProfile.entitlements b/demos/supabase-trello/macos/Runner/DebugProfile.entitlements new file mode 100644 index 00000000..08c3ab17 --- /dev/null +++ b/demos/supabase-trello/macos/Runner/DebugProfile.entitlements @@ -0,0 +1,14 @@ + + + + + com.apple.security.app-sandbox + + com.apple.security.cs.allow-jit + + com.apple.security.network.server + + com.apple.security.network.client + + + diff --git a/demos/supabase-trello/macos/Runner/Info.plist b/demos/supabase-trello/macos/Runner/Info.plist new file mode 100644 index 00000000..4789daa6 --- /dev/null +++ b/demos/supabase-trello/macos/Runner/Info.plist @@ -0,0 +1,32 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIconFile + + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + $(FLUTTER_BUILD_NAME) + CFBundleVersion + $(FLUTTER_BUILD_NUMBER) + LSMinimumSystemVersion + $(MACOSX_DEPLOYMENT_TARGET) + NSHumanReadableCopyright + $(PRODUCT_COPYRIGHT) + NSMainNibFile + MainMenu + NSPrincipalClass + NSApplication + + diff --git a/demos/supabase-trello/macos/Runner/MainFlutterWindow.swift b/demos/supabase-trello/macos/Runner/MainFlutterWindow.swift new file mode 100644 index 00000000..3cc05eb2 --- /dev/null +++ b/demos/supabase-trello/macos/Runner/MainFlutterWindow.swift @@ -0,0 +1,15 @@ +import Cocoa +import FlutterMacOS + +class MainFlutterWindow: NSWindow { + override func awakeFromNib() { + let flutterViewController = FlutterViewController() + let windowFrame = self.frame + self.contentViewController = flutterViewController + self.setFrame(windowFrame, display: true) + + RegisterGeneratedPlugins(registry: flutterViewController) + + super.awakeFromNib() + } +} diff --git a/demos/supabase-trello/macos/Runner/Release.entitlements b/demos/supabase-trello/macos/Runner/Release.entitlements new file mode 100644 index 00000000..779a1789 --- /dev/null +++ b/demos/supabase-trello/macos/Runner/Release.entitlements @@ -0,0 +1,10 @@ + + + + + com.apple.security.app-sandbox + + com.apple.security.network.client + + + diff --git a/demos/supabase-trello/macos/RunnerTests/RunnerTests.swift b/demos/supabase-trello/macos/RunnerTests/RunnerTests.swift new file mode 100644 index 00000000..5418c9f5 --- /dev/null +++ b/demos/supabase-trello/macos/RunnerTests/RunnerTests.swift @@ -0,0 +1,12 @@ +import FlutterMacOS +import Cocoa +import XCTest + +class RunnerTests: XCTestCase { + + func testExample() { + // If you add code to the Runner application, consider adding tests here. + // See https://developer.apple.com/documentation/xctest for more information about using XCTest. + } + +} diff --git a/demos/supabase-trello/pubspec.lock b/demos/supabase-trello/pubspec.lock new file mode 100644 index 00000000..d3a96f89 --- /dev/null +++ b/demos/supabase-trello/pubspec.lock @@ -0,0 +1,991 @@ +# Generated by pub +# See https://dart.dev/tools/pub/glossary#lockfile +packages: + app_links: + dependency: transitive + description: + name: app_links + sha256: "433df2e61b10519407475d7f69e470789d23d593f28224c38ba1068597be7950" + url: "https://pub.dev" + source: hosted + version: "6.3.3" + app_links_linux: + dependency: transitive + description: + name: app_links_linux + sha256: f5f7173a78609f3dfd4c2ff2c95bd559ab43c80a87dc6a095921d96c05688c81 + url: "https://pub.dev" + source: hosted + version: "1.0.3" + app_links_platform_interface: + dependency: transitive + description: + name: app_links_platform_interface + sha256: "05f5379577c513b534a29ddea68176a4d4802c46180ee8e2e966257158772a3f" + url: "https://pub.dev" + source: hosted + version: "2.0.2" + app_links_web: + dependency: transitive + description: + name: app_links_web + sha256: af060ed76183f9e2b87510a9480e56a5352b6c249778d07bd2c95fc35632a555 + url: "https://pub.dev" + source: hosted + version: "1.0.4" + args: + dependency: transitive + description: + name: args + sha256: bf9f5caeea8d8fe6721a9c358dd8a5c1947b27f1cfaa18b39c301273594919e6 + url: "https://pub.dev" + source: hosted + version: "2.6.0" + async: + dependency: transitive + description: + name: async + sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" + url: "https://pub.dev" + source: hosted + version: "2.11.0" + boolean_selector: + dependency: transitive + description: + name: boolean_selector + sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" + url: "https://pub.dev" + source: hosted + version: "2.1.1" + characters: + dependency: transitive + description: + name: characters + sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605" + url: "https://pub.dev" + source: hosted + version: "1.3.0" + checked_yaml: + dependency: transitive + description: + name: checked_yaml + sha256: feb6bed21949061731a7a75fc5d2aa727cf160b91af9a3e464c5e3a32e28b5ff + url: "https://pub.dev" + source: hosted + version: "2.0.3" + clock: + dependency: transitive + description: + name: clock + sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf + url: "https://pub.dev" + source: hosted + version: "1.1.1" + collection: + dependency: transitive + description: + name: collection + sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a + url: "https://pub.dev" + source: hosted + version: "1.18.0" + cross_file: + dependency: transitive + description: + name: cross_file + sha256: "7caf6a750a0c04effbb52a676dce9a4a592e10ad35c34d6d2d0e4811160d5670" + url: "https://pub.dev" + source: hosted + version: "0.3.4+2" + crypto: + dependency: "direct main" + description: + name: crypto + sha256: "1e445881f28f22d6140f181e07737b22f1e099a5e1ff94b0af2f9e4a463f4855" + url: "https://pub.dev" + source: hosted + version: "3.0.6" + cupertino_icons: + dependency: "direct main" + description: + name: cupertino_icons + sha256: ba631d1c7f7bef6b729a622b7b752645a2d076dba9976925b8f25725a30e1ee6 + url: "https://pub.dev" + source: hosted + version: "1.0.8" + fake_async: + dependency: transitive + description: + name: fake_async + sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78" + url: "https://pub.dev" + source: hosted + version: "1.3.1" + fetch_api: + dependency: transitive + description: + name: fetch_api + sha256: "97f46c25b480aad74f7cc2ad7ccba2c5c6f08d008e68f95c1077286ce243d0e6" + url: "https://pub.dev" + source: hosted + version: "2.2.0" + fetch_client: + dependency: transitive + description: + name: fetch_client + sha256: "9666ee14536778474072245ed5cba07db81ae8eb5de3b7bf4a2d1e2c49696092" + url: "https://pub.dev" + source: hosted + version: "1.1.2" + ffi: + dependency: transitive + description: + name: ffi + sha256: "16ed7b077ef01ad6170a3d0c57caa4a112a38d7a2ed5602e0aca9ca6f3d98da6" + url: "https://pub.dev" + source: hosted + version: "2.1.3" + file: + dependency: transitive + description: + name: file + sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4 + url: "https://pub.dev" + source: hosted + version: "7.0.1" + file_picker: + dependency: "direct main" + description: + name: file_picker + sha256: "1bbf65dd997458a08b531042ec3794112a6c39c07c37ff22113d2e7e4f81d4e4" + url: "https://pub.dev" + source: hosted + version: "6.2.1" + file_selector_linux: + dependency: transitive + description: + name: file_selector_linux + sha256: "54cbbd957e1156d29548c7d9b9ec0c0ebb6de0a90452198683a7d23aed617a33" + url: "https://pub.dev" + source: hosted + version: "0.9.3+2" + file_selector_macos: + dependency: transitive + description: + name: file_selector_macos + sha256: "271ab9986df0c135d45c3cdb6bd0faa5db6f4976d3e4b437cf7d0f258d941bfc" + url: "https://pub.dev" + source: hosted + version: "0.9.4+2" + file_selector_platform_interface: + dependency: transitive + description: + name: file_selector_platform_interface + sha256: a3994c26f10378a039faa11de174d7b78eb8f79e4dd0af2a451410c1a5c3f66b + url: "https://pub.dev" + source: hosted + version: "2.6.2" + file_selector_windows: + dependency: transitive + description: + name: file_selector_windows + sha256: "8f5d2f6590d51ecd9179ba39c64f722edc15226cc93dcc8698466ad36a4a85a4" + url: "https://pub.dev" + source: hosted + version: "0.9.3+3" + fixnum: + dependency: transitive + description: + name: fixnum + sha256: b6dc7065e46c974bc7c5f143080a6764ec7a4be6da1285ececdc37be96de53be + url: "https://pub.dev" + source: hosted + version: "1.1.1" + flare_flutter: + dependency: transitive + description: + name: flare_flutter + sha256: "99d63c60f00fac81249ce6410ee015d7b125c63d8278a30da81edf3317a1f6a0" + url: "https://pub.dev" + source: hosted + version: "3.0.2" + flutter: + dependency: "direct main" + description: flutter + source: sdk + version: "0.0.0" + flutter_dotenv: + dependency: "direct main" + description: + name: flutter_dotenv + sha256: b7c7be5cd9f6ef7a78429cabd2774d3c4af50e79cb2b7593e3d5d763ef95c61b + url: "https://pub.dev" + source: hosted + version: "5.2.1" + flutter_expandable_fab: + dependency: "direct main" + description: + name: flutter_expandable_fab + sha256: "85275279d19faf4fbe5639dc1f139b4555b150e079d056f085601a45688af12c" + url: "https://pub.dev" + source: hosted + version: "2.3.0" + flutter_lints: + dependency: "direct dev" + description: + name: flutter_lints + sha256: "9e8c3858111da373efc5aa341de011d9bd23e2c5c5e0c62bccf32438e192d7b1" + url: "https://pub.dev" + source: hosted + version: "3.0.2" + flutter_plugin_android_lifecycle: + dependency: transitive + description: + name: flutter_plugin_android_lifecycle + sha256: "9ee02950848f61c4129af3d6ec84a1cfc0e47931abc746b03e7a3bc3e8ff6eda" + url: "https://pub.dev" + source: hosted + version: "2.0.22" + flutter_test: + dependency: "direct dev" + description: flutter + source: sdk + version: "0.0.0" + flutter_web_plugins: + dependency: transitive + description: flutter + source: sdk + version: "0.0.0" + functions_client: + dependency: transitive + description: + name: functions_client + sha256: "61597ed93be197b1be6387855e4b760e6aac2355fcfc4df6d20d2b4579982158" + url: "https://pub.dev" + source: hosted + version: "2.4.0" + google_fonts: + dependency: "direct main" + description: + name: google_fonts + sha256: b1ac0fe2832c9cc95e5e88b57d627c5e68c223b9657f4b96e1487aa9098c7b82 + url: "https://pub.dev" + source: hosted + version: "6.2.1" + gotrue: + dependency: transitive + description: + name: gotrue + sha256: d6362dff9a54f8c1c372bb137c858b4024c16407324d34e6473e59623c9b9f50 + url: "https://pub.dev" + source: hosted + version: "2.11.1" + gtk: + dependency: transitive + description: + name: gtk + sha256: e8ce9ca4b1df106e4d72dad201d345ea1a036cc12c360f1a7d5a758f78ffa42c + url: "https://pub.dev" + source: hosted + version: "2.1.0" + http: + dependency: transitive + description: + name: http + sha256: b9c29a161230ee03d3ccf545097fccd9b87a5264228c5d348202e0f0c28f9010 + url: "https://pub.dev" + source: hosted + version: "1.2.2" + http_parser: + dependency: transitive + description: + name: http_parser + sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b" + url: "https://pub.dev" + source: hosted + version: "4.0.2" + image_picker: + dependency: "direct main" + description: + name: image_picker + sha256: "021834d9c0c3de46bf0fe40341fa07168407f694d9b2bb18d532dc1261867f7a" + url: "https://pub.dev" + source: hosted + version: "1.1.2" + image_picker_android: + dependency: transitive + description: + name: image_picker_android + sha256: "8c5abf0dcc24fe6e8e0b4a5c0b51a5cf30cefdf6407a3213dae61edc75a70f56" + url: "https://pub.dev" + source: hosted + version: "0.8.12+12" + image_picker_for_web: + dependency: transitive + description: + name: image_picker_for_web + sha256: "717eb042ab08c40767684327be06a5d8dbb341fe791d514e4b92c7bbe1b7bb83" + url: "https://pub.dev" + source: hosted + version: "3.0.6" + image_picker_ios: + dependency: transitive + description: + name: image_picker_ios + sha256: "4f0568120c6fcc0aaa04511cb9f9f4d29fc3d0139884b1d06be88dcec7641d6b" + url: "https://pub.dev" + source: hosted + version: "0.8.12+1" + image_picker_linux: + dependency: transitive + description: + name: image_picker_linux + sha256: "4ed1d9bb36f7cd60aa6e6cd479779cc56a4cb4e4de8f49d487b1aaad831300fa" + url: "https://pub.dev" + source: hosted + version: "0.2.1+1" + image_picker_macos: + dependency: transitive + description: + name: image_picker_macos + sha256: "3f5ad1e8112a9a6111c46d0b57a7be2286a9a07fc6e1976fdf5be2bd31d4ff62" + url: "https://pub.dev" + source: hosted + version: "0.2.1+1" + image_picker_platform_interface: + dependency: transitive + description: + name: image_picker_platform_interface + sha256: "9ec26d410ff46f483c5519c29c02ef0e02e13a543f882b152d4bfd2f06802f80" + url: "https://pub.dev" + source: hosted + version: "2.10.0" + image_picker_windows: + dependency: transitive + description: + name: image_picker_windows + sha256: "6ad07afc4eb1bc25f3a01084d28520496c4a3bb0cb13685435838167c9dcedeb" + url: "https://pub.dev" + source: hosted + version: "0.2.1+1" + js: + dependency: transitive + description: + name: js + sha256: c1b2e9b5ea78c45e1a0788d29606ba27dc5f71f019f32ca5140f61ef071838cf + url: "https://pub.dev" + source: hosted + version: "0.7.1" + json_annotation: + dependency: transitive + description: + name: json_annotation + sha256: "1ce844379ca14835a50d2f019a3099f419082cfdd231cd86a142af94dd5c6bb1" + url: "https://pub.dev" + source: hosted + version: "4.9.0" + jwt_decode: + dependency: transitive + description: + name: jwt_decode + sha256: d2e9f68c052b2225130977429d30f187aa1981d789c76ad104a32243cfdebfbb + url: "https://pub.dev" + source: hosted + version: "0.3.1" + leak_tracker: + dependency: transitive + description: + name: leak_tracker + sha256: "7f0df31977cb2c0b88585095d168e689669a2cc9b97c309665e3386f3e9d341a" + url: "https://pub.dev" + source: hosted + version: "10.0.4" + leak_tracker_flutter_testing: + dependency: transitive + description: + name: leak_tracker_flutter_testing + sha256: "06e98f569d004c1315b991ded39924b21af84cf14cc94791b8aea337d25b57f8" + url: "https://pub.dev" + source: hosted + version: "3.0.3" + leak_tracker_testing: + dependency: transitive + description: + name: leak_tracker_testing + sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3" + url: "https://pub.dev" + source: hosted + version: "3.0.1" + lints: + dependency: transitive + description: + name: lints + sha256: cbf8d4b858bb0134ef3ef87841abdf8d63bfc255c266b7bf6b39daa1085c4290 + url: "https://pub.dev" + source: hosted + version: "3.0.0" + logging: + dependency: "direct main" + description: + name: logging + sha256: c8245ada5f1717ed44271ed1c26b8ce85ca3228fd2ffdb75468ab01979309d61 + url: "https://pub.dev" + source: hosted + version: "1.3.0" + matcher: + dependency: transitive + description: + name: matcher + sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb + url: "https://pub.dev" + source: hosted + version: "0.12.16+1" + material_color_utilities: + dependency: transitive + description: + name: material_color_utilities + sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a" + url: "https://pub.dev" + source: hosted + version: "0.8.0" + material_design_icons_flutter: + dependency: "direct main" + description: + name: material_design_icons_flutter + sha256: "6f986b7a51f3ad4c00e33c5c84e8de1bdd140489bbcdc8b66fc1283dad4dea5a" + url: "https://pub.dev" + source: hosted + version: "7.0.7296" + meta: + dependency: transitive + description: + name: meta + sha256: "7687075e408b093f36e6bbf6c91878cc0d4cd10f409506f7bc996f68220b9136" + url: "https://pub.dev" + source: hosted + version: "1.12.0" + mime: + dependency: transitive + description: + name: mime + sha256: "41a20518f0cb1256669420fdba0cd90d21561e560ac240f26ef8322e45bb7ed6" + url: "https://pub.dev" + source: hosted + version: "2.0.0" + mutex: + dependency: transitive + description: + name: mutex + sha256: "8827da25de792088eb33e572115a5eb0d61d61a3c01acbc8bcbe76ed78f1a1f2" + url: "https://pub.dev" + source: hosted + version: "3.1.0" + nested: + dependency: transitive + description: + name: nested + sha256: "03bac4c528c64c95c722ec99280375a6f2fc708eec17c7b3f07253b626cd2a20" + url: "https://pub.dev" + source: hosted + version: "1.0.0" + path: + dependency: "direct main" + description: + name: path + sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af" + url: "https://pub.dev" + source: hosted + version: "1.9.0" + path_provider: + dependency: "direct main" + description: + name: path_provider + sha256: "50c5dd5b6e1aaf6fb3a78b33f6aa3afca52bf903a8a5298f53101fdaee55bbcd" + url: "https://pub.dev" + source: hosted + version: "2.1.5" + path_provider_android: + dependency: transitive + description: + name: path_provider_android + sha256: "6f01f8e37ec30b07bc424b4deabac37cacb1bc7e2e515ad74486039918a37eb7" + url: "https://pub.dev" + source: hosted + version: "2.2.10" + path_provider_foundation: + dependency: transitive + description: + name: path_provider_foundation + sha256: "4843174df4d288f5e29185bd6e72a6fbdf5a4a4602717eed565497429f179942" + url: "https://pub.dev" + source: hosted + version: "2.4.1" + path_provider_linux: + dependency: transitive + description: + name: path_provider_linux + sha256: f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279 + url: "https://pub.dev" + source: hosted + version: "2.2.1" + path_provider_platform_interface: + dependency: transitive + description: + name: path_provider_platform_interface + sha256: "88f5779f72ba699763fa3a3b06aa4bf6de76c8e5de842cf6f29e2e06476c2334" + url: "https://pub.dev" + source: hosted + version: "2.1.2" + path_provider_windows: + dependency: transitive + description: + name: path_provider_windows + sha256: bd6f00dbd873bfb70d0761682da2b3a2c2fccc2b9e84c495821639601d81afe7 + url: "https://pub.dev" + source: hosted + version: "2.3.0" + platform: + dependency: transitive + description: + name: platform + sha256: "5d6b1b0036a5f331ebc77c850ebc8506cbc1e9416c27e59b439f917a902a4984" + url: "https://pub.dev" + source: hosted + version: "3.1.6" + plugin_platform_interface: + dependency: transitive + description: + name: plugin_platform_interface + sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02" + url: "https://pub.dev" + source: hosted + version: "2.1.8" + postgrest: + dependency: transitive + description: + name: postgrest + sha256: "9f759ac497a24839addbed69d9569ea6d51d2e4834c672b8c2a73752fb6945c8" + url: "https://pub.dev" + source: hosted + version: "2.4.0" + powersync: + dependency: "direct main" + description: + path: "../../packages/powersync" + relative: true + source: path + version: "1.10.0" + powersync_core: + dependency: "direct overridden" + description: + path: "../../packages/powersync_core" + relative: true + source: path + version: "1.0.0" + powersync_flutter_libs: + dependency: "direct overridden" + description: + path: "../../packages/powersync_flutter_libs" + relative: true + source: path + version: "0.4.3" + provider: + dependency: "direct main" + description: + name: provider + sha256: c8a055ee5ce3fd98d6fc872478b03823ffdb448699c6ebdbbc71d59b596fd48c + url: "https://pub.dev" + source: hosted + version: "6.1.2" + pub_semver: + dependency: transitive + description: + name: pub_semver + sha256: "7b3cfbf654f3edd0c6298ecd5be782ce997ddf0e00531b9464b55245185bbbbd" + url: "https://pub.dev" + source: hosted + version: "2.1.5" + pubspec_parse: + dependency: transitive + description: + name: pubspec_parse + sha256: "81876843eb50dc2e1e5b151792c9a985c5ed2536914115ed04e9c8528f6647b0" + url: "https://pub.dev" + source: hosted + version: "1.4.0" + random_name_generator: + dependency: "direct main" + description: + name: random_name_generator + sha256: "7c5b91d60f68b30e7b4c53006047cab8474f06563f7d0cab70fb409a0cb5ff61" + url: "https://pub.dev" + source: hosted + version: "1.5.0" + realtime_client: + dependency: transitive + description: + name: realtime_client + sha256: "1bfcb7455fdcf15953bf18ac2817634ea5b8f7f350c7e8c9873141a3ee2c3e9c" + url: "https://pub.dev" + source: hosted + version: "2.4.1" + retry: + dependency: transitive + description: + name: retry + sha256: "822e118d5b3aafed083109c72d5f484c6dc66707885e07c0fbcb8b986bba7efc" + url: "https://pub.dev" + source: hosted + version: "3.1.2" + rxdart: + dependency: transitive + description: + name: rxdart + sha256: "5c3004a4a8dbb94bd4bf5412a4def4acdaa12e12f269737a5751369e12d1a962" + url: "https://pub.dev" + source: hosted + version: "0.28.0" + shared_preferences: + dependency: transitive + description: + name: shared_preferences + sha256: "95f9997ca1fb9799d494d0cb2a780fd7be075818d59f00c43832ed112b158a82" + url: "https://pub.dev" + source: hosted + version: "2.3.3" + shared_preferences_android: + dependency: transitive + description: + name: shared_preferences_android + sha256: "480ba4345773f56acda9abf5f50bd966f581dac5d514e5fc4a18c62976bbba7e" + url: "https://pub.dev" + source: hosted + version: "2.3.2" + shared_preferences_foundation: + dependency: transitive + description: + name: shared_preferences_foundation + sha256: "6a52cfcdaeac77cad8c97b539ff688ccfc458c007b4db12be584fbe5c0e49e03" + url: "https://pub.dev" + source: hosted + version: "2.5.4" + shared_preferences_linux: + dependency: transitive + description: + name: shared_preferences_linux + sha256: "580abfd40f415611503cae30adf626e6656dfb2f0cee8f465ece7b6defb40f2f" + url: "https://pub.dev" + source: hosted + version: "2.4.1" + shared_preferences_platform_interface: + dependency: transitive + description: + name: shared_preferences_platform_interface + sha256: "57cbf196c486bc2cf1f02b85784932c6094376284b3ad5779d1b1c6c6a816b80" + url: "https://pub.dev" + source: hosted + version: "2.4.1" + shared_preferences_web: + dependency: transitive + description: + name: shared_preferences_web + sha256: d2ca4132d3946fec2184261726b355836a82c33d7d5b67af32692aff18a4684e + url: "https://pub.dev" + source: hosted + version: "2.4.2" + shared_preferences_windows: + dependency: transitive + description: + name: shared_preferences_windows + sha256: "94ef0f72b2d71bc3e700e025db3710911bd51a71cefb65cc609dd0d9a982e3c1" + url: "https://pub.dev" + source: hosted + version: "2.4.1" + sky_engine: + dependency: transitive + description: flutter + source: sdk + version: "0.0.99" + source_span: + dependency: transitive + description: + name: source_span + sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" + url: "https://pub.dev" + source: hosted + version: "1.10.0" + sprintf: + dependency: transitive + description: + name: sprintf + sha256: "1fc9ffe69d4df602376b52949af107d8f5703b77cda567c4d7d86a0693120f23" + url: "https://pub.dev" + source: hosted + version: "7.0.0" + sqlite3: + dependency: transitive + description: + name: sqlite3 + sha256: bb174b3ec2527f9c5f680f73a89af8149dd99782fbb56ea88ad0807c5638f2ed + url: "https://pub.dev" + source: hosted + version: "2.4.7" + sqlite3_flutter_libs: + dependency: transitive + description: + name: sqlite3_flutter_libs + sha256: "73016db8419f019e807b7a5e5fbf2a7bd45c165fed403b8e7681230f3a102785" + url: "https://pub.dev" + source: hosted + version: "0.5.28" + sqlite3_web: + dependency: transitive + description: + name: sqlite3_web + sha256: f22d1dda7a40be0867984f55cdf5c2d599e5f05d3be4a642d78f38b38983f554 + url: "https://pub.dev" + source: hosted + version: "0.2.0" + sqlite_async: + dependency: "direct main" + description: + name: sqlite_async + sha256: d66fb6e6d07c1a834743326c033029f75becbb1fad6823d709f921872abc3d5b + url: "https://pub.dev" + source: hosted + version: "0.11.0" + stack_trace: + dependency: transitive + description: + name: stack_trace + sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b" + url: "https://pub.dev" + source: hosted + version: "1.11.1" + status_alert: + dependency: "direct main" + description: + name: status_alert + sha256: "220ce6c1400d19d817665ac5a87f772e87c901677ac37b93320f4764edf4d23f" + url: "https://pub.dev" + source: hosted + version: "1.0.1" + storage_client: + dependency: transitive + description: + name: storage_client + sha256: d80d34f0aa60e5199646bc301f5750767ee37310c2ecfe8d4bbdd29351e09ab0 + url: "https://pub.dev" + source: hosted + version: "2.3.0" + stream_channel: + dependency: transitive + description: + name: stream_channel + sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7 + url: "https://pub.dev" + source: hosted + version: "2.1.2" + string_scanner: + dependency: transitive + description: + name: string_scanner + sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" + url: "https://pub.dev" + source: hosted + version: "1.2.0" + supabase: + dependency: transitive + description: + name: supabase + sha256: ea3daaf4fc76df9bf42ca00142f8d07b94400943a93d563e87f5575ea78f1c2c + url: "https://pub.dev" + source: hosted + version: "2.6.1" + supabase_flutter: + dependency: "direct main" + description: + name: supabase_flutter + sha256: e8b321706a9b88c60f5fe695305f34917ad2ee55aea0b3af987638c7b0793e13 + url: "https://pub.dev" + source: hosted + version: "2.8.2" + term_glyph: + dependency: transitive + description: + name: term_glyph + sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 + url: "https://pub.dev" + source: hosted + version: "1.2.1" + test_api: + dependency: transitive + description: + name: test_api + sha256: "9955ae474176f7ac8ee4e989dadfb411a58c30415bcfb648fa04b2b8a03afa7f" + url: "https://pub.dev" + source: hosted + version: "0.7.0" + typed_data: + dependency: transitive + description: + name: typed_data + sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c + url: "https://pub.dev" + source: hosted + version: "1.3.2" + universal_io: + dependency: transitive + description: + name: universal_io + sha256: "1722b2dcc462b4b2f3ee7d188dad008b6eb4c40bbd03a3de451d82c78bba9aad" + url: "https://pub.dev" + source: hosted + version: "2.2.2" + url_launcher: + dependency: transitive + description: + name: url_launcher + sha256: "9d06212b1362abc2f0f0d78e6f09f726608c74e3b9462e8368bb03314aa8d603" + url: "https://pub.dev" + source: hosted + version: "6.3.1" + url_launcher_android: + dependency: transitive + description: + name: url_launcher_android + sha256: f0c73347dfcfa5b3db8bc06e1502668265d39c08f310c29bff4e28eea9699f79 + url: "https://pub.dev" + source: hosted + version: "6.3.9" + url_launcher_ios: + dependency: transitive + description: + name: url_launcher_ios + sha256: "16a513b6c12bb419304e72ea0ae2ab4fed569920d1c7cb850263fe3acc824626" + url: "https://pub.dev" + source: hosted + version: "6.3.2" + url_launcher_linux: + dependency: transitive + description: + name: url_launcher_linux + sha256: "4e9ba368772369e3e08f231d2301b4ef72b9ff87c31192ef471b380ef29a4935" + url: "https://pub.dev" + source: hosted + version: "3.2.1" + url_launcher_macos: + dependency: transitive + description: + name: url_launcher_macos + sha256: "17ba2000b847f334f16626a574c702b196723af2a289e7a93ffcb79acff855c2" + url: "https://pub.dev" + source: hosted + version: "3.2.2" + url_launcher_platform_interface: + dependency: transitive + description: + name: url_launcher_platform_interface + sha256: "552f8a1e663569be95a8190206a38187b531910283c3e982193e4f2733f01029" + url: "https://pub.dev" + source: hosted + version: "2.3.2" + url_launcher_web: + dependency: transitive + description: + name: url_launcher_web + sha256: "772638d3b34c779ede05ba3d38af34657a05ac55b06279ea6edd409e323dca8e" + url: "https://pub.dev" + source: hosted + version: "2.3.3" + url_launcher_windows: + dependency: transitive + description: + name: url_launcher_windows + sha256: "44cf3aabcedde30f2dba119a9dea3b0f2672fbe6fa96e85536251d678216b3c4" + url: "https://pub.dev" + source: hosted + version: "3.1.3" + uuid: + dependency: transitive + description: + name: uuid + sha256: a5be9ef6618a7ac1e964353ef476418026db906c4facdedaa299b7a2e71690ff + url: "https://pub.dev" + source: hosted + version: "4.5.1" + vector_math: + dependency: transitive + description: + name: vector_math + sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" + url: "https://pub.dev" + source: hosted + version: "2.1.4" + vm_service: + dependency: transitive + description: + name: vm_service + sha256: "3923c89304b715fb1eb6423f017651664a03bf5f4b29983627c4da791f74a4ec" + url: "https://pub.dev" + source: hosted + version: "14.2.1" + web: + dependency: transitive + description: + name: web + sha256: cd3543bd5798f6ad290ea73d210f423502e71900302dde696f8bff84bf89a1cb + url: "https://pub.dev" + source: hosted + version: "1.1.0" + web_socket: + dependency: transitive + description: + name: web_socket + sha256: "3c12d96c0c9a4eec095246debcea7b86c0324f22df69893d538fcc6f1b8cce83" + url: "https://pub.dev" + source: hosted + version: "0.1.6" + web_socket_channel: + dependency: transitive + description: + name: web_socket_channel + sha256: "9f187088ed104edd8662ca07af4b124465893caf063ba29758f97af57e61da8f" + url: "https://pub.dev" + source: hosted + version: "3.0.1" + win32: + dependency: transitive + description: + name: win32 + sha256: "68d1e89a91ed61ad9c370f9f8b6effed9ae5e0ede22a270bdfa6daf79fc2290a" + url: "https://pub.dev" + source: hosted + version: "5.5.4" + xdg_directories: + dependency: transitive + description: + name: xdg_directories + sha256: "7a3f37b05d989967cdddcbb571f1ea834867ae2faa29725fd085180e0883aa15" + url: "https://pub.dev" + source: hosted + version: "1.1.0" + yaml: + dependency: transitive + description: + name: yaml + sha256: b9da305ac7c39faa3f030eccd175340f968459dae4af175130b3fc47e40d76ce + url: "https://pub.dev" + source: hosted + version: "3.1.3" + yet_another_json_isolate: + dependency: transitive + description: + name: yet_another_json_isolate + sha256: "56155e9e0002cc51ea7112857bbcdc714d4c35e176d43e4d3ee233009ff410c9" + url: "https://pub.dev" + source: hosted + version: "2.0.3" +sdks: + dart: ">=3.4.0 <4.0.0" + flutter: ">=3.22.0" diff --git a/demos/supabase-trello/pubspec.yaml b/demos/supabase-trello/pubspec.yaml new file mode 100644 index 00000000..26fc55e7 --- /dev/null +++ b/demos/supabase-trello/pubspec.yaml @@ -0,0 +1,67 @@ +name: trelloappclone_flutter +description: A Flutter clone of Trello. + +# The following line prevents the package from being accidentally published to +# pub.dev using `pub publish`. This is preferred for private packages. +publish_to: 'none' # Remove this line if you wish to publish to pub.dev + +# The following defines the version and build number for your application. +# A version number is three numbers separated by dots, like 1.2.43 +# followed by an optional build number separated by a +. +# Both the version and the builder number may be overridden in flutter +# build by specifying --build-name and --build-number, respectively. +# In Android, build-name is used as versionName while build-number used as versionCode. +# Read more about Android versioning at https://developer.android.com/studio/publish/versioning +# In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. +# Read more about iOS versioning at +# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html +version: 1.0.3+1 + +environment: + sdk: ^3.4.0 + +dependencies: + flutter: + sdk: flutter + + # The following adds the Cupertino Icons font to your application. + # Use with the CupertinoIcons class for iOS style icons. + cupertino_icons: ^1.0.5 + google_fonts: ^6.1.0 + flutter_expandable_fab: ^2.0.0 + material_design_icons_flutter: ^7.0.7296 + crypto: ^3.0.3 + provider: ^6.0.5 + status_alert: ^1.0.1 + image_picker: ^1.0.4 + file_picker: ^6.1.1 + random_name_generator: ^1.2.0 + flutter_dotenv: ^5.1.0 + logging: ^1.1.1 + powersync: ^1.10.0 + sqlite_async: ^0.11.0 + path_provider: ^2.0.12 + supabase_flutter: ^2.8.2 + path: ^1.8.2 + +dev_dependencies: + flutter_lints: ^3.0.1 + flutter_test: + sdk: flutter + +# For information on the generic Dart part of this file, see the +# following page: https://dart.dev/tools/pub/pubspec + +# The following section is specific to Flutter. +flutter: + + # The following line ensures that the Material Icons font is + # included with your application, so that you can use the icons in + # the material Icons class. + uses-material-design: true + + # To add assets to your application, add an assets section, like this: + assets: + - assets/landing.jpg + - assets/trello-logo.png + - .env diff --git a/demos/supabase-trello/sample_workspace.png b/demos/supabase-trello/sample_workspace.png new file mode 100644 index 0000000000000000000000000000000000000000..7b92ef892a0790ab453448e1668f4b849e39575c GIT binary patch literal 133244 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 z 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Δ)Z!XZzhBe^8E{UMP3dK!+T^ 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 literal 0 HcmV?d00001 diff --git a/demos/supabase-trello/showcase.png b/demos/supabase-trello/showcase.png new file mode 100644 index 0000000000000000000000000000000000000000..322044b83db15c2a55b44fc2f06a6b4b3a86fcd3 GIT binary patch literal 181022 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 literal 0 HcmV?d00001 diff --git a/demos/supabase-trello/web/icons/Icon-192.png b/demos/supabase-trello/web/icons/Icon-192.png new file mode 100644 index 0000000000000000000000000000000000000000..b749bfef07473333cf1dd31e9eed89862a5d52aa GIT binary patch literal 5292 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 literal 0 HcmV?d00001 diff --git a/demos/supabase-trello/web/icons/Icon-512.png b/demos/supabase-trello/web/icons/Icon-512.png new file mode 100644 index 0000000000000000000000000000000000000000..88cfd48dff1169879ba46840804b412fe02fefd6 GIT binary patch literal 8252 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 literal 0 HcmV?d00001 diff --git a/demos/supabase-trello/web/icons/Icon-maskable-192.png b/demos/supabase-trello/web/icons/Icon-maskable-192.png new file mode 100644 index 0000000000000000000000000000000000000000..eb9b4d76e525556d5d89141648c724331630325d GIT binary patch literal 5594 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 X>c!)3PgKfL&lX^$Z>Cpu&6)6jvi^Z! literal 0 HcmV?d00001 diff --git a/demos/supabase-trello/web/icons/Icon-maskable-512.png b/demos/supabase-trello/web/icons/Icon-maskable-512.png new file mode 100644 index 0000000000000000000000000000000000000000..d69c56691fbdb0b7efa65097c7cc1edac12a6d3e GIT binary patch literal 20998 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 MPgg&ebxsLQ025IeI{*Lx literal 0 HcmV?d00001 diff --git a/demos/supabase-trello/web/index.html b/demos/supabase-trello/web/index.html new file mode 100644 index 00000000..3b048eea --- /dev/null +++ b/demos/supabase-trello/web/index.html @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + trelloappclone_flutter + + + + + + + + + + diff --git a/demos/supabase-trello/web/manifest.json b/demos/supabase-trello/web/manifest.json new file mode 100644 index 00000000..a2531a89 --- /dev/null +++ b/demos/supabase-trello/web/manifest.json @@ -0,0 +1,35 @@ +{ + "name": "trelloappclone_flutter", + "short_name": "trelloappclone_flutter", + "start_url": ".", + "display": "standalone", + "background_color": "#0175C2", + "theme_color": "#0175C2", + "description": "A new Flutter project.", + "orientation": "portrait-primary", + "prefer_related_applications": false, + "icons": [ + { + "src": "icons/Icon-192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "icons/Icon-512.png", + "sizes": "512x512", + "type": "image/png" + }, + { + "src": "icons/Icon-maskable-192.png", + "sizes": "192x192", + "type": "image/png", + "purpose": "maskable" + }, + { + "src": "icons/Icon-maskable-512.png", + "sizes": "512x512", + "type": "image/png", + "purpose": "maskable" + } + ] +} diff --git a/demos/supabase-trello/windows/.gitignore b/demos/supabase-trello/windows/.gitignore new file mode 100644 index 00000000..d492d0d9 --- /dev/null +++ b/demos/supabase-trello/windows/.gitignore @@ -0,0 +1,17 @@ +flutter/ephemeral/ + +# Visual Studio user-specific files. +*.suo +*.user +*.userosscache +*.sln.docstates + +# Visual Studio build-related files. +x64/ +x86/ + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ diff --git a/demos/supabase-trello/windows/CMakeLists.txt b/demos/supabase-trello/windows/CMakeLists.txt new file mode 100644 index 00000000..c5b3a9b4 --- /dev/null +++ b/demos/supabase-trello/windows/CMakeLists.txt @@ -0,0 +1,102 @@ +# Project-level configuration. +cmake_minimum_required(VERSION 3.14) +project(trelloappclone_flutter LANGUAGES CXX) + +# The name of the executable created for the application. Change this to change +# the on-disk name of your application. +set(BINARY_NAME "trelloappclone_flutter") + +# Explicitly opt in to modern CMake behaviors to avoid warnings with recent +# versions of CMake. +cmake_policy(SET CMP0063 NEW) + +# Define build configuration option. +get_property(IS_MULTICONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) +if(IS_MULTICONFIG) + set(CMAKE_CONFIGURATION_TYPES "Debug;Profile;Release" + CACHE STRING "" FORCE) +else() + if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) + set(CMAKE_BUILD_TYPE "Debug" CACHE + STRING "Flutter build mode" FORCE) + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS + "Debug" "Profile" "Release") + endif() +endif() +# Define settings for the Profile build mode. +set(CMAKE_EXE_LINKER_FLAGS_PROFILE "${CMAKE_EXE_LINKER_FLAGS_RELEASE}") +set(CMAKE_SHARED_LINKER_FLAGS_PROFILE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE}") +set(CMAKE_C_FLAGS_PROFILE "${CMAKE_C_FLAGS_RELEASE}") +set(CMAKE_CXX_FLAGS_PROFILE "${CMAKE_CXX_FLAGS_RELEASE}") + +# Use Unicode for all projects. +add_definitions(-DUNICODE -D_UNICODE) + +# Compilation settings that should be applied to most targets. +# +# Be cautious about adding new options here, as plugins use this function by +# default. In most cases, you should add new options to specific targets instead +# of modifying this function. +function(APPLY_STANDARD_SETTINGS TARGET) + target_compile_features(${TARGET} PUBLIC cxx_std_17) + target_compile_options(${TARGET} PRIVATE /W4 /WX /wd"4100") + target_compile_options(${TARGET} PRIVATE /EHsc) + target_compile_definitions(${TARGET} PRIVATE "_HAS_EXCEPTIONS=0") + target_compile_definitions(${TARGET} PRIVATE "$<$:_DEBUG>") +endfunction() + +# Flutter library and tool build rules. +set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") +add_subdirectory(${FLUTTER_MANAGED_DIR}) + +# Application build; see runner/CMakeLists.txt. +add_subdirectory("runner") + + +# Generated plugin build rules, which manage building the plugins and adding +# them to the application. +include(flutter/generated_plugins.cmake) + + +# === Installation === +# Support files are copied into place next to the executable, so that it can +# run in place. This is done instead of making a separate bundle (as on Linux) +# so that building and running from within Visual Studio will work. +set(BUILD_BUNDLE_DIR "$") +# Make the "install" step default, as it's required to run. +set(CMAKE_VS_INCLUDE_INSTALL_TO_DEFAULT_BUILD 1) +if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) + set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE) +endif() + +set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data") +set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}") + +install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) + +if(PLUGIN_BUNDLED_LIBRARIES) + install(FILES "${PLUGIN_BUNDLED_LIBRARIES}" + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endif() + +# Fully re-copy the assets directory on each build to avoid having stale files +# from a previous install. +set(FLUTTER_ASSET_DIR_NAME "flutter_assets") +install(CODE " + file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\") + " COMPONENT Runtime) +install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}" + DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) + +# Install the AOT library on non-Debug builds only. +install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" + CONFIGURATIONS Profile;Release + COMPONENT Runtime) diff --git a/demos/supabase-trello/windows/flutter/CMakeLists.txt b/demos/supabase-trello/windows/flutter/CMakeLists.txt new file mode 100644 index 00000000..930d2071 --- /dev/null +++ b/demos/supabase-trello/windows/flutter/CMakeLists.txt @@ -0,0 +1,104 @@ +# This file controls Flutter-level build steps. It should not be edited. +cmake_minimum_required(VERSION 3.14) + +set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral") + +# Configuration provided via flutter tool. +include(${EPHEMERAL_DIR}/generated_config.cmake) + +# TODO: Move the rest of this into files in ephemeral. See +# https://github.com/flutter/flutter/issues/57146. +set(WRAPPER_ROOT "${EPHEMERAL_DIR}/cpp_client_wrapper") + +# === Flutter Library === +set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/flutter_windows.dll") + +# Published to parent scope for install step. +set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE) +set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE) +set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE) +set(AOT_LIBRARY "${PROJECT_DIR}/build/windows/app.so" PARENT_SCOPE) + +list(APPEND FLUTTER_LIBRARY_HEADERS + "flutter_export.h" + "flutter_windows.h" + "flutter_messenger.h" + "flutter_plugin_registrar.h" + "flutter_texture_registrar.h" +) +list(TRANSFORM FLUTTER_LIBRARY_HEADERS PREPEND "${EPHEMERAL_DIR}/") +add_library(flutter INTERFACE) +target_include_directories(flutter INTERFACE + "${EPHEMERAL_DIR}" +) +target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}.lib") +add_dependencies(flutter flutter_assemble) + +# === Wrapper === +list(APPEND CPP_WRAPPER_SOURCES_CORE + "core_implementations.cc" + "standard_codec.cc" +) +list(TRANSFORM CPP_WRAPPER_SOURCES_CORE PREPEND "${WRAPPER_ROOT}/") +list(APPEND CPP_WRAPPER_SOURCES_PLUGIN + "plugin_registrar.cc" +) +list(TRANSFORM CPP_WRAPPER_SOURCES_PLUGIN PREPEND "${WRAPPER_ROOT}/") +list(APPEND CPP_WRAPPER_SOURCES_APP + "flutter_engine.cc" + "flutter_view_controller.cc" +) +list(TRANSFORM CPP_WRAPPER_SOURCES_APP PREPEND "${WRAPPER_ROOT}/") + +# Wrapper sources needed for a plugin. +add_library(flutter_wrapper_plugin STATIC + ${CPP_WRAPPER_SOURCES_CORE} + ${CPP_WRAPPER_SOURCES_PLUGIN} +) +apply_standard_settings(flutter_wrapper_plugin) +set_target_properties(flutter_wrapper_plugin PROPERTIES + POSITION_INDEPENDENT_CODE ON) +set_target_properties(flutter_wrapper_plugin PROPERTIES + CXX_VISIBILITY_PRESET hidden) +target_link_libraries(flutter_wrapper_plugin PUBLIC flutter) +target_include_directories(flutter_wrapper_plugin PUBLIC + "${WRAPPER_ROOT}/include" +) +add_dependencies(flutter_wrapper_plugin flutter_assemble) + +# Wrapper sources needed for the runner. +add_library(flutter_wrapper_app STATIC + ${CPP_WRAPPER_SOURCES_CORE} + ${CPP_WRAPPER_SOURCES_APP} +) +apply_standard_settings(flutter_wrapper_app) +target_link_libraries(flutter_wrapper_app PUBLIC flutter) +target_include_directories(flutter_wrapper_app PUBLIC + "${WRAPPER_ROOT}/include" +) +add_dependencies(flutter_wrapper_app flutter_assemble) + +# === Flutter tool backend === +# _phony_ is a non-existent file to force this command to run every time, +# since currently there's no way to get a full input/output list from the +# flutter tool. +set(PHONY_OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/_phony_") +set_source_files_properties("${PHONY_OUTPUT}" PROPERTIES SYMBOLIC TRUE) +add_custom_command( + OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} + ${CPP_WRAPPER_SOURCES_CORE} ${CPP_WRAPPER_SOURCES_PLUGIN} + ${CPP_WRAPPER_SOURCES_APP} + ${PHONY_OUTPUT} + COMMAND ${CMAKE_COMMAND} -E env + ${FLUTTER_TOOL_ENVIRONMENT} + "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.bat" + windows-x64 $ + VERBATIM +) +add_custom_target(flutter_assemble DEPENDS + "${FLUTTER_LIBRARY}" + ${FLUTTER_LIBRARY_HEADERS} + ${CPP_WRAPPER_SOURCES_CORE} + ${CPP_WRAPPER_SOURCES_PLUGIN} + ${CPP_WRAPPER_SOURCES_APP} +) diff --git a/demos/supabase-trello/windows/flutter/generated_plugin_registrant.cc b/demos/supabase-trello/windows/flutter/generated_plugin_registrant.cc new file mode 100644 index 00000000..2a044a64 --- /dev/null +++ b/demos/supabase-trello/windows/flutter/generated_plugin_registrant.cc @@ -0,0 +1,26 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#include "generated_plugin_registrant.h" + +#include +#include +#include +#include +#include + +void RegisterPlugins(flutter::PluginRegistry* registry) { + AppLinksPluginCApiRegisterWithRegistrar( + registry->GetRegistrarForPlugin("AppLinksPluginCApi")); + FileSelectorWindowsRegisterWithRegistrar( + registry->GetRegistrarForPlugin("FileSelectorWindows")); + PowersyncFlutterLibsPluginRegisterWithRegistrar( + registry->GetRegistrarForPlugin("PowersyncFlutterLibsPlugin")); + Sqlite3FlutterLibsPluginRegisterWithRegistrar( + registry->GetRegistrarForPlugin("Sqlite3FlutterLibsPlugin")); + UrlLauncherWindowsRegisterWithRegistrar( + registry->GetRegistrarForPlugin("UrlLauncherWindows")); +} diff --git a/demos/supabase-trello/windows/flutter/generated_plugin_registrant.h b/demos/supabase-trello/windows/flutter/generated_plugin_registrant.h new file mode 100644 index 00000000..dc139d85 --- /dev/null +++ b/demos/supabase-trello/windows/flutter/generated_plugin_registrant.h @@ -0,0 +1,15 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#ifndef GENERATED_PLUGIN_REGISTRANT_ +#define GENERATED_PLUGIN_REGISTRANT_ + +#include + +// Registers Flutter plugins. +void RegisterPlugins(flutter::PluginRegistry* registry); + +#endif // GENERATED_PLUGIN_REGISTRANT_ diff --git a/demos/supabase-trello/windows/flutter/generated_plugins.cmake b/demos/supabase-trello/windows/flutter/generated_plugins.cmake new file mode 100644 index 00000000..18c83191 --- /dev/null +++ b/demos/supabase-trello/windows/flutter/generated_plugins.cmake @@ -0,0 +1,28 @@ +# +# Generated file, do not edit. +# + +list(APPEND FLUTTER_PLUGIN_LIST + app_links + file_selector_windows + powersync_flutter_libs + sqlite3_flutter_libs + url_launcher_windows +) + +list(APPEND FLUTTER_FFI_PLUGIN_LIST +) + +set(PLUGIN_BUNDLED_LIBRARIES) + +foreach(plugin ${FLUTTER_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/windows plugins/${plugin}) + target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) + list(APPEND PLUGIN_BUNDLED_LIBRARIES $) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) +endforeach(plugin) + +foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/windows plugins/${ffi_plugin}) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) +endforeach(ffi_plugin) diff --git a/demos/supabase-trello/windows/runner/CMakeLists.txt b/demos/supabase-trello/windows/runner/CMakeLists.txt new file mode 100644 index 00000000..394917c0 --- /dev/null +++ b/demos/supabase-trello/windows/runner/CMakeLists.txt @@ -0,0 +1,40 @@ +cmake_minimum_required(VERSION 3.14) +project(runner LANGUAGES CXX) + +# Define the application target. To change its name, change BINARY_NAME in the +# top-level CMakeLists.txt, not the value here, or `flutter run` will no longer +# work. +# +# Any new source files that you add to the application should be added here. +add_executable(${BINARY_NAME} WIN32 + "flutter_window.cpp" + "main.cpp" + "utils.cpp" + "win32_window.cpp" + "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" + "Runner.rc" + "runner.exe.manifest" +) + +# Apply the standard set of build settings. This can be removed for applications +# that need different build settings. +apply_standard_settings(${BINARY_NAME}) + +# Add preprocessor definitions for the build version. +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION=\"${FLUTTER_VERSION}\"") +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MAJOR=${FLUTTER_VERSION_MAJOR}") +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MINOR=${FLUTTER_VERSION_MINOR}") +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_PATCH=${FLUTTER_VERSION_PATCH}") +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_BUILD=${FLUTTER_VERSION_BUILD}") + +# Disable Windows macros that collide with C++ standard library functions. +target_compile_definitions(${BINARY_NAME} PRIVATE "NOMINMAX") + +# Add dependency libraries and include directories. Add any application-specific +# dependencies here. +target_link_libraries(${BINARY_NAME} PRIVATE flutter flutter_wrapper_app) +target_link_libraries(${BINARY_NAME} PRIVATE "dwmapi.lib") +target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}") + +# Run the Flutter tool portions of the build. This must not be removed. +add_dependencies(${BINARY_NAME} flutter_assemble) diff --git a/demos/supabase-trello/windows/runner/Runner.rc b/demos/supabase-trello/windows/runner/Runner.rc new file mode 100644 index 00000000..58312f4e --- /dev/null +++ b/demos/supabase-trello/windows/runner/Runner.rc @@ -0,0 +1,121 @@ +// Microsoft Visual C++ generated resource script. +// +#pragma code_page(65001) +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "winres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (United States) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""winres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDI_APP_ICON ICON "resources\\app_icon.ico" + + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +#if defined(FLUTTER_VERSION_MAJOR) && defined(FLUTTER_VERSION_MINOR) && defined(FLUTTER_VERSION_PATCH) && defined(FLUTTER_VERSION_BUILD) +#define VERSION_AS_NUMBER FLUTTER_VERSION_MAJOR,FLUTTER_VERSION_MINOR,FLUTTER_VERSION_PATCH,FLUTTER_VERSION_BUILD +#else +#define VERSION_AS_NUMBER 1,0,0,0 +#endif + +#if defined(FLUTTER_VERSION) +#define VERSION_AS_STRING FLUTTER_VERSION +#else +#define VERSION_AS_STRING "1.0.0" +#endif + +VS_VERSION_INFO VERSIONINFO + FILEVERSION VERSION_AS_NUMBER + PRODUCTVERSION VERSION_AS_NUMBER + FILEFLAGSMASK VS_FFI_FILEFLAGSMASK +#ifdef _DEBUG + FILEFLAGS VS_FF_DEBUG +#else + FILEFLAGS 0x0L +#endif + FILEOS VOS__WINDOWS32 + FILETYPE VFT_APP + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904e4" + BEGIN + VALUE "CompanyName", "com.example" "\0" + VALUE "FileDescription", "trelloappclone_flutter" "\0" + VALUE "FileVersion", VERSION_AS_STRING "\0" + VALUE "InternalName", "trelloappclone_flutter" "\0" + VALUE "LegalCopyright", "Copyright (C) 2023 com.example. All rights reserved." "\0" + VALUE "OriginalFilename", "trelloappclone_flutter.exe" "\0" + VALUE "ProductName", "trelloappclone_flutter" "\0" + VALUE "ProductVersion", VERSION_AS_STRING "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1252 + END +END + +#endif // English (United States) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED diff --git a/demos/supabase-trello/windows/runner/flutter_window.cpp b/demos/supabase-trello/windows/runner/flutter_window.cpp new file mode 100644 index 00000000..b25e363e --- /dev/null +++ b/demos/supabase-trello/windows/runner/flutter_window.cpp @@ -0,0 +1,66 @@ +#include "flutter_window.h" + +#include + +#include "flutter/generated_plugin_registrant.h" + +FlutterWindow::FlutterWindow(const flutter::DartProject& project) + : project_(project) {} + +FlutterWindow::~FlutterWindow() {} + +bool FlutterWindow::OnCreate() { + if (!Win32Window::OnCreate()) { + return false; + } + + RECT frame = GetClientArea(); + + // The size here must match the window dimensions to avoid unnecessary surface + // creation / destruction in the startup path. + flutter_controller_ = std::make_unique( + frame.right - frame.left, frame.bottom - frame.top, project_); + // Ensure that basic setup of the controller was successful. + if (!flutter_controller_->engine() || !flutter_controller_->view()) { + return false; + } + RegisterPlugins(flutter_controller_->engine()); + SetChildContent(flutter_controller_->view()->GetNativeWindow()); + + flutter_controller_->engine()->SetNextFrameCallback([&]() { + this->Show(); + }); + + return true; +} + +void FlutterWindow::OnDestroy() { + if (flutter_controller_) { + flutter_controller_ = nullptr; + } + + Win32Window::OnDestroy(); +} + +LRESULT +FlutterWindow::MessageHandler(HWND hwnd, UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept { + // Give Flutter, including plugins, an opportunity to handle window messages. + if (flutter_controller_) { + std::optional result = + flutter_controller_->HandleTopLevelWindowProc(hwnd, message, wparam, + lparam); + if (result) { + return *result; + } + } + + switch (message) { + case WM_FONTCHANGE: + flutter_controller_->engine()->ReloadSystemFonts(); + break; + } + + return Win32Window::MessageHandler(hwnd, message, wparam, lparam); +} diff --git a/demos/supabase-trello/windows/runner/flutter_window.h b/demos/supabase-trello/windows/runner/flutter_window.h new file mode 100644 index 00000000..6da0652f --- /dev/null +++ b/demos/supabase-trello/windows/runner/flutter_window.h @@ -0,0 +1,33 @@ +#ifndef RUNNER_FLUTTER_WINDOW_H_ +#define RUNNER_FLUTTER_WINDOW_H_ + +#include +#include + +#include + +#include "win32_window.h" + +// A window that does nothing but host a Flutter view. +class FlutterWindow : public Win32Window { + public: + // Creates a new FlutterWindow hosting a Flutter view running |project|. + explicit FlutterWindow(const flutter::DartProject& project); + virtual ~FlutterWindow(); + + protected: + // Win32Window: + bool OnCreate() override; + void OnDestroy() override; + LRESULT MessageHandler(HWND window, UINT const message, WPARAM const wparam, + LPARAM const lparam) noexcept override; + + private: + // The project to run. + flutter::DartProject project_; + + // The Flutter instance hosted by this window. + std::unique_ptr flutter_controller_; +}; + +#endif // RUNNER_FLUTTER_WINDOW_H_ diff --git a/demos/supabase-trello/windows/runner/main.cpp b/demos/supabase-trello/windows/runner/main.cpp new file mode 100644 index 00000000..8dfa412e --- /dev/null +++ b/demos/supabase-trello/windows/runner/main.cpp @@ -0,0 +1,43 @@ +#include +#include +#include + +#include "flutter_window.h" +#include "utils.h" + +int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev, + _In_ wchar_t *command_line, _In_ int show_command) { + // Attach to console when present (e.g., 'flutter run') or create a + // new console when running with a debugger. + if (!::AttachConsole(ATTACH_PARENT_PROCESS) && ::IsDebuggerPresent()) { + CreateAndAttachConsole(); + } + + // Initialize COM, so that it is available for use in the library and/or + // plugins. + ::CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED); + + flutter::DartProject project(L"data"); + + std::vector command_line_arguments = + GetCommandLineArguments(); + + project.set_dart_entrypoint_arguments(std::move(command_line_arguments)); + + FlutterWindow window(project); + Win32Window::Point origin(10, 10); + Win32Window::Size size(1280, 720); + if (!window.Create(L"trelloappclone_flutter", origin, size)) { + return EXIT_FAILURE; + } + window.SetQuitOnClose(true); + + ::MSG msg; + while (::GetMessage(&msg, nullptr, 0, 0)) { + ::TranslateMessage(&msg); + ::DispatchMessage(&msg); + } + + ::CoUninitialize(); + return EXIT_SUCCESS; +} diff --git a/demos/supabase-trello/windows/runner/resource.h b/demos/supabase-trello/windows/runner/resource.h new file mode 100644 index 00000000..66a65d1e --- /dev/null +++ b/demos/supabase-trello/windows/runner/resource.h @@ -0,0 +1,16 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by Runner.rc +// +#define IDI_APP_ICON 101 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 102 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/demos/supabase-trello/windows/runner/resources/app_icon.ico b/demos/supabase-trello/windows/runner/resources/app_icon.ico new file mode 100644 index 0000000000000000000000000000000000000000..c04e20caf6370ebb9253ad831cc31de4a9c965f6 GIT binary patch literal 33772 zcmeHQc|26z|35SKE&G-*mXah&B~fFkXr)DEO&hIfqby^T&>|8^_Ub8Vp#`BLl3lbZ zvPO!8k!2X>cg~Elr=IVxo~J*a`+9wR=A83c-k-DFd(XM&UI1VKCqM@V;DDtJ09WB} zRaHKiW(GT00brH|0EeTeKVbpbGZg?nK6-j827q-+NFM34gXjqWxJ*a#{b_apGN<-L_m3#8Z26atkEn& ze87Bvv^6vVmM+p+cQ~{u%=NJF>#(d;8{7Q{^rWKWNtf14H}>#&y7$lqmY6xmZryI& z($uy?c5-+cPnt2%)R&(KIWEXww>Cnz{OUpT>W$CbO$h1= z#4BPMkFG1Y)x}Ui+WXr?Z!w!t_hjRq8qTaWpu}FH{MsHlU{>;08goVLm{V<&`itk~ zE_Ys=D(hjiy+5=?=$HGii=Y5)jMe9|wWoD_K07(}edAxh`~LBorOJ!Cf@f{_gNCC| z%{*04ViE!#>@hc1t5bb+NO>ncf@@Dv01K!NxH$3Eg1%)|wLyMDF8^d44lV!_Sr}iEWefOaL z8f?ud3Q%Sen39u|%00W<#!E=-RpGa+H8}{ulxVl4mwpjaU+%2pzmi{3HM)%8vb*~-M9rPUAfGCSos8GUXp02|o~0BTV2l#`>>aFV&_P$ejS;nGwSVP8 zMbOaG7<7eKD>c12VdGH;?2@q7535sa7MN*L@&!m?L`ASG%boY7(&L5imY#EQ$KrBB z4@_tfP5m50(T--qv1BJcD&aiH#b-QC>8#7Fx@3yXlonJI#aEIi=8&ChiVpc#N=5le zM*?rDIdcpawoc5kizv$GEjnveyrp3sY>+5_R5;>`>erS%JolimF=A^EIsAK zsPoVyyUHCgf0aYr&alx`<)eb6Be$m&`JYSuBu=p8j%QlNNp$-5C{b4#RubPb|CAIS zGE=9OFLP7?Hgc{?k45)84biT0k&-C6C%Q}aI~q<(7BL`C#<6HyxaR%!dFx7*o^laG z=!GBF^cwK$IA(sn9y6>60Rw{mYRYkp%$jH z*xQM~+bp)G$_RhtFPYx2HTsWk80+p(uqv9@I9)y{b$7NK53rYL$ezbmRjdXS?V}fj zWxX_feWoLFNm3MG7pMUuFPs$qrQWO9!l2B(SIuy2}S|lHNbHzoE+M2|Zxhjq9+Ws8c{*}x^VAib7SbxJ*Q3EnY5lgI9 z=U^f3IW6T=TWaVj+2N%K3<%Un;CF(wUp`TC&Y|ZjyFu6co^uqDDB#EP?DV5v_dw~E zIRK*BoY9y-G_ToU2V_XCX4nJ32~`czdjT!zwme zGgJ0nOk3U4@IE5JwtM}pwimLjk{ln^*4HMU%Fl4~n(cnsLB}Ja-jUM>xIB%aY;Nq8 z)Fp8dv1tkqKanv<68o@cN|%thj$+f;zGSO7H#b+eMAV8xH$hLggtt?O?;oYEgbq@= zV(u9bbd12^%;?nyk6&$GPI%|+<_mEpJGNfl*`!KV;VfmZWw{n{rnZ51?}FDh8we_L z8OI9nE31skDqJ5Oa_ybn7|5@ui>aC`s34p4ZEu6-s!%{uU45$Zd1=p$^^dZBh zu<*pDDPLW+c>iWO$&Z_*{VSQKg7=YEpS3PssPn1U!lSm6eZIho*{@&20e4Y_lRklKDTUCKI%o4Pc<|G^Xgu$J^Q|B87U;`c1zGwf^-zH*VQ^x+i^OUWE0yd z;{FJq)2w!%`x7yg@>uGFFf-XJl4H`YtUG%0slGKOlXV`q?RP>AEWg#x!b{0RicxGhS!3$p7 zij;{gm!_u@D4$Ox%>>bPtLJ> zwKtYz?T_DR1jN>DkkfGU^<#6sGz|~p*I{y`aZ>^Di#TC|Z!7j_O1=Wo8thuit?WxR zh9_S>kw^{V^|g}HRUF=dcq>?q(pHxw!8rx4dC6vbQVmIhmICF#zU!HkHpQ>9S%Uo( zMw{eC+`&pb=GZRou|3;Po1}m46H6NGd$t<2mQh}kaK-WFfmj_66_17BX0|j-E2fe3Jat}ijpc53 zJV$$;PC<5aW`{*^Z6e5##^`Ed#a0nwJDT#Qq~^e8^JTA=z^Kl>La|(UQ!bI@#ge{Dzz@61p-I)kc2?ZxFt^QQ}f%ldLjO*GPj(5)V9IyuUakJX=~GnTgZ4$5!3E=V#t`yOG4U z(gphZB6u2zsj=qNFLYShhg$}lNpO`P9xOSnO*$@@UdMYES*{jJVj|9z-}F^riksLK zbsU+4-{281P9e2UjY6tse^&a)WM1MFw;p#_dHhWI7p&U*9TR0zKdVuQed%6{otTsq z$f~S!;wg#Bd9kez=Br{m|66Wv z#g1xMup<0)H;c2ZO6su_ii&m8j&+jJz4iKnGZ&wxoQX|5a>v&_e#6WA!MB_4asTxLRGQCC5cI(em z%$ZfeqP>!*q5kU>a+BO&ln=4Jm>Ef(QE8o&RgLkk%2}4Tf}U%IFP&uS7}&|Q-)`5< z+e>;s#4cJ-z%&-^&!xsYx777Wt(wZY9(3(avmr|gRe4cD+a8&!LY`1^T?7x{E<=kdY9NYw>A;FtTvQ=Y&1M%lyZPl$ss1oY^Sl8we}n}Aob#6 zl4jERwnt9BlSoWb@3HxYgga(752Vu6Y)k4yk9u~Kw>cA5&LHcrvn1Y-HoIuFWg~}4 zEw4bR`mXZQIyOAzo)FYqg?$5W<;^+XX%Uz61{-L6@eP|lLH%|w?g=rFc;OvEW;^qh z&iYXGhVt(G-q<+_j}CTbPS_=K>RKN0&;dubh0NxJyDOHFF;<1k!{k#7b{|Qok9hac z;gHz}6>H6C6RnB`Tt#oaSrX0p-j-oRJ;_WvS-qS--P*8}V943RT6kou-G=A+7QPGQ z!ze^UGxtW3FC0$|(lY9^L!Lx^?Q8cny(rR`es5U;-xBhphF%_WNu|aO<+e9%6LuZq zt(0PoagJG<%hyuf;te}n+qIl_Ej;czWdc{LX^pS>77s9t*2b4s5dvP_!L^3cwlc)E!(!kGrg~FescVT zZCLeua3f4;d;Tk4iXzt}g}O@nlK3?_o91_~@UMIl?@77Qc$IAlLE95#Z=TES>2E%z zxUKpK{_HvGF;5%Q7n&vA?`{%8ohlYT_?(3A$cZSi)MvIJygXD}TS-3UwyUxGLGiJP znblO~G|*uA^|ac8E-w#}uBtg|s_~s&t>-g0X%zIZ@;o_wNMr_;{KDg^O=rg`fhDZu zFp(VKd1Edj%F zWHPl+)FGj%J1BO3bOHVfH^3d1F{)*PL&sRX`~(-Zy3&9UQX)Z;c51tvaI2E*E7!)q zcz|{vpK7bjxix(k&6=OEIBJC!9lTkUbgg?4-yE{9+pFS)$Ar@vrIf`D0Bnsed(Cf? zObt2CJ>BKOl>q8PyFO6w)+6Iz`LW%T5^R`U_NIW0r1dWv6OY=TVF?N=EfA(k(~7VBW(S;Tu5m4Lg8emDG-(mOSSs=M9Q&N8jc^Y4&9RqIsk(yO_P(mcCr}rCs%1MW1VBrn=0-oQN(Xj!k%iKV zb%ricBF3G4S1;+8lzg5PbZ|$Se$)I=PwiK=cDpHYdov2QO1_a-*dL4KUi|g&oh>(* zq$<`dQ^fat`+VW?m)?_KLn&mp^-@d=&7yGDt<=XwZZC=1scwxO2^RRI7n@g-1o8ps z)&+et_~)vr8aIF1VY1Qrq~Xe``KJrQSnAZ{CSq3yP;V*JC;mmCT6oRLSs7=GA?@6g zUooM}@tKtx(^|aKK8vbaHlUQqwE0}>j&~YlN3H#vKGm@u)xxS?n9XrOWUfCRa< z`20Fld2f&;gg7zpo{Adh+mqNntMc-D$N^yWZAZRI+u1T1zWHPxk{+?vcS1D>08>@6 zLhE@`gt1Y9mAK6Z4p|u(5I%EkfU7rKFSM=E4?VG9tI;a*@?6!ey{lzN5=Y-!$WFSe z&2dtO>^0@V4WRc#L&P%R(?@KfSblMS+N+?xUN$u3K4Ys%OmEh+tq}fnU}i>6YHM?< zlnL2gl~sF!j!Y4E;j3eIU-lfa`RsOL*Tt<%EFC0gPzoHfNWAfKFIKZN8}w~(Yi~=q z>=VNLO2|CjkxP}RkutxjV#4fWYR1KNrPYq5ha9Wl+u>ipsk*I(HS@iLnmGH9MFlTU zaFZ*KSR0px>o+pL7BbhB2EC1%PJ{67_ z#kY&#O4@P=OV#-79y_W>Gv2dxL*@G7%LksNSqgId9v;2xJ zrh8uR!F-eU$NMx@S*+sk=C~Dxr9Qn7TfWnTupuHKuQ$;gGiBcU>GF5sWx(~4IP3`f zWE;YFO*?jGwYh%C3X<>RKHC-DZ!*r;cIr}GLOno^3U4tFSSoJp%oHPiSa%nh=Zgn% z14+8v@ygy0>UgEN1bczD6wK45%M>psM)y^)IfG*>3ItX|TzV*0i%@>L(VN!zdKb8S?Qf7BhjNpziA zR}?={-eu>9JDcl*R=OP9B8N$IcCETXah9SUDhr{yrld{G;PnCWRsPD7!eOOFBTWUQ=LrA_~)mFf&!zJX!Oc-_=kT<}m|K52 z)M=G#;p;Rdb@~h5D{q^K;^fX-m5V}L%!wVC2iZ1uu401Ll}#rocTeK|7FAeBRhNdQ zCc2d^aQnQp=MpOmak60N$OgS}a;p(l9CL`o4r(e-nN}mQ?M&isv-P&d$!8|1D1I(3-z!wi zTgoo)*Mv`gC?~bm?S|@}I|m-E2yqPEvYybiD5azInexpK8?9q*$9Yy9-t%5jU8~ym zgZDx>!@ujQ=|HJnwp^wv-FdD{RtzO9SnyfB{mH_(c!jHL*$>0o-(h(eqe*ZwF6Lvu z{7rkk%PEqaA>o+f{H02tzZ@TWy&su?VNw43! z-X+rN`6llvpUms3ZiSt)JMeztB~>9{J8SPmYs&qohxdYFi!ra8KR$35Zp9oR)eFC4 zE;P31#3V)n`w$fZ|4X-|%MX`xZDM~gJyl2W;O$H25*=+1S#%|53>|LyH za@yh+;325%Gq3;J&a)?%7X%t@WXcWL*BaaR*7UEZad4I8iDt7^R_Fd`XeUo256;sAo2F!HcIQKk;h})QxEsPE5BcKc7WyerTchgKmrfRX z!x#H_%cL#B9TWAqkA4I$R^8{%do3Y*&(;WFmJ zU7Dih{t1<{($VtJRl9|&EB?|cJ)xse!;}>6mSO$o5XIx@V|AA8ZcoD88ZM?C*;{|f zZVmf94_l1OmaICt`2sTyG!$^UeTHx9YuUP!omj(r|7zpm5475|yXI=rR>>fteLI+| z)MoiGho0oEt=*J(;?VY0QzwCqw@cVm?d7Y!z0A@u#H?sCJ*ecvyhj& z-F77lO;SH^dmf?L>3i>?Z*U}Em4ZYV_CjgfvzYsRZ+1B!Uo6H6mbS<-FFL`ytqvb& zE7+)2ahv-~dz(Hs+f})z{*4|{)b=2!RZK;PWwOnO=hG7xG`JU5>bAvUbdYd_CjvtHBHgtGdlO+s^9ca^Bv3`t@VRX2_AD$Ckg36OcQRF zXD6QtGfHdw*hx~V(MV-;;ZZF#dJ-piEF+s27z4X1qi5$!o~xBnvf=uopcn7ftfsZc zy@(PuOk`4GL_n(H9(E2)VUjqRCk9kR?w)v@xO6Jm_Mx})&WGEl=GS0#)0FAq^J*o! zAClhvoTsNP*-b~rN{8Yym3g{01}Ep^^Omf=SKqvN?{Q*C4HNNAcrowIa^mf+3PRy! z*_G-|3i8a;+q;iP@~Of_$(vtFkB8yOyWt2*K)vAn9El>=D;A$CEx6b*XF@4y_6M+2 zpeW`RHoI_p(B{%(&jTHI->hmNmZjHUj<@;7w0mx3&koy!2$@cfX{sN19Y}euYJFn& z1?)+?HCkD0MRI$~uB2UWri})0bru_B;klFdwsLc!ne4YUE;t41JqfG# zZJq6%vbsdx!wYeE<~?>o4V`A3?lN%MnKQ`z=uUivQN^vzJ|C;sdQ37Qn?;lpzg})y z)_2~rUdH}zNwX;Tp0tJ78+&I=IwOQ-fl30R79O8@?Ub8IIA(6I`yHn%lARVL`%b8+ z4$8D-|MZZWxc_)vu6@VZN!HsI$*2NOV&uMxBNzIbRgy%ob_ zhwEH{J9r$!dEix9XM7n&c{S(h>nGm?el;gaX0@|QnzFD@bne`el^CO$yXC?BDJ|Qg z+y$GRoR`?ST1z^e*>;!IS@5Ovb7*RlN>BV_UC!7E_F;N#ky%1J{+iixp(dUJj93aK zzHNN>R-oN7>kykHClPnoPTIj7zc6KM(Pnlb(|s??)SMb)4!sMHU^-ntJwY5Big7xv zb1Ew`Xj;|D2kzGja*C$eS44(d&RMU~c_Y14V9_TLTz0J#uHlsx`S6{nhsA0dWZ#cG zJ?`fO50E>*X4TQLv#nl%3GOk*UkAgt=IY+u0LNXqeln3Z zv$~&Li`ZJOKkFuS)dJRA>)b_Da%Q~axwA_8zNK{BH{#}#m}zGcuckz}riDE-z_Ms> zR8-EqAMcfyGJCtvTpaUVQtajhUS%c@Yj}&6Zz;-M7MZzqv3kA7{SuW$oW#=0az2wQ zg-WG@Vb4|D`pl~Il54N7Hmsauc_ne-a!o5#j3WaBBh@Wuefb!QJIOn5;d)%A#s+5% zuD$H=VNux9bE-}1&bcYGZ+>1Fo;3Z@e&zX^n!?JK*adSbONm$XW9z;Q^L>9U!}Toj2WdafJ%oL#h|yWWwyAGxzfrAWdDTtaKl zK4`5tDpPg5>z$MNv=X0LZ0d6l%D{(D8oT@+w0?ce$DZ6pv>{1&Ok67Ix1 zH}3=IEhPJEhItCC8E=`T`N5(k?G=B4+xzZ?<4!~ ze~z6Wk9!CHTI(0rLJ4{JU?E-puc;xusR?>G?;4vt;q~iI9=kDL=z0Rr%O$vU`30X$ zDZRFyZ`(omOy@u|i6h;wtJlP;+}$|Ak|k2dea7n?U1*$T!sXqqOjq^NxLPMmk~&qI zYg0W?yK8T(6+Ea+$YyspKK?kP$+B`~t3^Pib_`!6xCs32!i@pqXfFV6PmBIR<-QW= zN8L{pt0Vap0x`Gzn#E@zh@H)0FfVfA_Iu4fjYZ+umO1LXIbVc$pY+E234u)ttcrl$ z>s92z4vT%n6cMb>=XT6;l0+9e(|CZG)$@C7t7Z7Ez@a)h)!hyuV&B5K%%)P5?Lk|C zZZSVzdXp{@OXSP0hoU-gF8s8Um(#xzjP2Vem zec#-^JqTa&Y#QJ>-FBxd7tf`XB6e^JPUgagB8iBSEps;92KG`!#mvVcPQ5yNC-GEG zTiHEDYfH+0O15}r^+ z#jxj=@x8iNHWALe!P3R67TwmhItn**0JwnzSV2O&KE8KcT+0hWH^OPD1pwiuyx=b@ zNf5Jh0{9X)8;~Es)$t@%(3!OnbY+`@?i{mGX7Yy}8T_*0a6g;kaFPq;*=px5EhO{Cp%1kI<0?*|h8v!6WnO3cCJRF2-CRrU3JiLJnj@6;L)!0kWYAc_}F{2P))3HmCrz zQ&N&gE70;`!6*eJ4^1IR{f6j4(-l&X!tjHxkbHA^Zhrnhr9g{exN|xrS`5Pq=#Xf& zG%P=#ra-TyVFfgW%cZo5OSIwFL9WtXAlFOa+ubmI5t*3=g#Y zF%;70p5;{ZeFL}&}yOY1N1*Q;*<(kTB!7vM$QokF)yr2FlIU@$Ph58$Bz z0J?xQG=MlS4L6jA22eS42g|9*9pX@$#*sUeM(z+t?hr@r5J&D1rx}2pW&m*_`VDCW zUYY@v-;bAO0HqoAgbbiGGC<=ryf96}3pouhy3XJrX+!!u*O_>Si38V{uJmQ&USptX zKp#l(?>%^7;2%h(q@YWS#9;a!JhKlkR#Vd)ERILlgu!Hr@jA@V;sk4BJ-H#p*4EqC zDGjC*tl=@3Oi6)Bn^QwFpul18fpkbpg0+peH$xyPBqb%`$OUhPKyWb32o7clB*9Z< zN=i~NLjavrLtwgJ01bufP+>p-jR2I95|TpmKpQL2!oV>g(4RvS2pK4*ou%m(h6r3A zX#s&`9LU1ZG&;{CkOK!4fLDTnBys`M!vuz>Q&9OZ0hGQl!~!jSDg|~s*w52opC{sB ze|Cf2luD(*G13LcOAGA!s2FjSK8&IE5#W%J25w!vM0^VyQM!t)inj&RTiJ!wXzFgz z3^IqzB7I0L$llljsGq})thBy9UOyjtFO_*hYM_sgcMk>44jeH0V1FDyELc{S1F-;A zS;T^k^~4biG&V*Irq}O;e}j$$+E_#G?HKIn05iP3j|87TkGK~SqG!-KBg5+mN(aLm z8ybhIM`%C19UX$H$KY6JgXbY$0AT%rEpHC;u`rQ$Y=rxUdsc5*Kvc8jaYaO$^)cI6){P6K0r)I6DY4Wr4&B zLQUBraey#0HV|&c4v7PVo3n$zHj99(TZO^3?Ly%C4nYvJTL9eLBLHsM3WKKD>5!B` zQ=BsR3aR6PD(Fa>327E2HAu5TM~Wusc!)>~(gM)+3~m;92Jd;FnSib=M5d6;;5{%R zb4V7DEJ0V!CP-F*oU?gkc>ksUtAYP&V4ND5J>J2^jt*vcFflQWCrB&fLdT%O59PVJ zhid#toR=FNgD!q3&r8#wEBr`!wzvQu5zX?Q>nlSJ4i@WC*CN*-xU66F^V5crWevQ9gsq$I@z1o(a=k7LL~ z7m_~`o;_Ozha1$8Q}{WBehvAlO4EL60y5}8GDrZ< zXh&F}71JbW2A~8KfEWj&UWV#4+Z4p`b{uAj4&WC zha`}X@3~+Iz^WRlOHU&KngK>#j}+_o@LdBC1H-`gT+krWX3-;!)6?{FBp~%20a}FL zFP9%Emqcwa#(`=G>BBZ0qZDQhmZKJg_g8<=bBFKWr!dyg(YkpE+|R*SGpDVU!+VlU zFC54^DLv}`qa%49T>nNiA9Q7Ips#!Xx90tCU2gvK`(F+GPcL=J^>No{)~we#o@&mUb6c$ zCc*<|NJBk-#+{j9xkQ&ujB zI~`#kN~7W!f*-}wkG~Ld!JqZ@tK}eeSnsS5J1fMFXm|`LJx&}5`@dK3W^7#Wnm+_P zBZkp&j1fa2Y=eIjJ0}gh85jt43kaIXXv?xmo@eHrka!Z|vQv12HN#+!I5E z`(fbuW>gFiJL|uXJ!vKt#z3e3HlVdboH7;e#i3(2<)Fg-I@BR!qY#eof3MFZ&*Y@l zI|KJf&ge@p2Dq09Vu$$Qxb7!}{m-iRk@!)%KL)txi3;~Z4Pb}u@GsW;ELiWeG9V51 znX#}B&4Y2E7-H=OpNE@q{%hFLxwIpBF2t{vPREa8_{linXT;#1vMRWjOzLOP$-hf( z>=?$0;~~PnkqY;~K{EM6Vo-T(0K{A0}VUGmu*hR z{tw3hvBN%N3G3Yw`X5Te+F{J`(3w1s3-+1EbnFQKcrgrX1Jqvs@ADGe%M0s$EbK$$ zK)=y=upBc6SjGYAACCcI=Y*6Fi8_jgwZlLxD26fnQfJmb8^gHRN5(TemhX@0e=vr> zg`W}6U>x6VhoA3DqsGGD9uL1DhB3!OXO=k}59TqD@(0Nb{)Ut_luTioK_>7wjc!5C zIr@w}b`Fez3)0wQfKl&bae7;PcTA7%?f2xucM0G)wt_KO!Ewx>F~;=BI0j=Fb4>pp zv}0R^xM4eti~+^+gE$6b81p(kwzuDti(-K9bc|?+pJEl@H+jSYuxZQV8rl8 zjp@M{#%qItIUFN~KcO9Hed*`$5A-2~pAo~K&<-Q+`9`$CK>rzqAI4w~$F%vs9s{~x zg4BP%Gy*@m?;D6=SRX?888Q6peF@_4Z->8wAH~Cn!R$|Hhq2cIzFYqT_+cDourHbY z0qroxJnrZ4Gh+Ay+F`_c%+KRT>y3qw{)89?=hJ@=KO=@ep)aBJ$c!JHfBMJpsP*3G za7|)VJJ8B;4?n{~ldJF7%jmb`-ftIvNd~ekoufG(`K(3=LNc;HBY& z(lp#q8XAD#cIf}k49zX_i`*fO+#!zKA&%T3j@%)R+#yag067CU%yUEe47>wzGU8^` z1EXFT^@I!{J!F8!X?S6ph8J=gUi5tl93*W>7}_uR<2N2~e}FaG?}KPyugQ=-OGEZs z!GBoyYY+H*ANn4?Z)X4l+7H%`17i5~zRlRIX?t)6_eu=g2Q`3WBhxSUeea+M-S?RL zX9oBGKn%a!H+*hx4d2(I!gsi+@SQK%<{X22M~2tMulJoa)0*+z9=-YO+;DFEm5eE1U9b^B(Z}2^9!Qk`!A$wUE z7$Ar5?NRg2&G!AZqnmE64eh^Anss3i!{}%6@Et+4rr!=}!SBF8eZ2*J3ujCWbl;3; z48H~goPSv(8X61fKKdpP!Z7$88NL^Z?j`!^*I?-P4X^pMxyWz~@$(UeAcTSDd(`vO z{~rc;9|GfMJcApU3k}22a!&)k4{CU!e_ny^Y3cO;tOvOMKEyWz!vG(Kp*;hB?d|R3`2X~=5a6#^o5@qn?J-bI8Ppip{-yG z!k|VcGsq!jF~}7DMr49Wap-s&>o=U^T0!Lcy}!(bhtYsPQy z4|EJe{12QL#=c(suQ89Mhw9<`bui%nx7Nep`C&*M3~vMEACmcRYYRGtANq$F%zh&V zc)cEVeHz*Z1N)L7k-(k3np#{GcDh2Q@ya0YHl*n7fl*ZPAsbU-a94MYYtA#&!c`xGIaV;yzsmrjfieTEtqB_WgZp2*NplHx=$O{M~2#i_vJ{ps-NgK zQsxKK_CBM2PP_je+Xft`(vYfXXgIUr{=PA=7a8`2EHk)Ym2QKIforz# tySWtj{oF3N9@_;i*Fv5S)9x^z=nlWP>jpp-9)52ZmLVA=i*%6g{{fxOO~wEK literal 0 HcmV?d00001 diff --git a/demos/supabase-trello/windows/runner/runner.exe.manifest b/demos/supabase-trello/windows/runner/runner.exe.manifest new file mode 100644 index 00000000..a42ea768 --- /dev/null +++ b/demos/supabase-trello/windows/runner/runner.exe.manifest @@ -0,0 +1,20 @@ + + + + + PerMonitorV2 + + + + + + + + + + + + + + + diff --git a/demos/supabase-trello/windows/runner/utils.cpp b/demos/supabase-trello/windows/runner/utils.cpp new file mode 100644 index 00000000..b2b08734 --- /dev/null +++ b/demos/supabase-trello/windows/runner/utils.cpp @@ -0,0 +1,65 @@ +#include "utils.h" + +#include +#include +#include +#include + +#include + +void CreateAndAttachConsole() { + if (::AllocConsole()) { + FILE *unused; + if (freopen_s(&unused, "CONOUT$", "w", stdout)) { + _dup2(_fileno(stdout), 1); + } + if (freopen_s(&unused, "CONOUT$", "w", stderr)) { + _dup2(_fileno(stdout), 2); + } + std::ios::sync_with_stdio(); + FlutterDesktopResyncOutputStreams(); + } +} + +std::vector GetCommandLineArguments() { + // Convert the UTF-16 command line arguments to UTF-8 for the Engine to use. + int argc; + wchar_t** argv = ::CommandLineToArgvW(::GetCommandLineW(), &argc); + if (argv == nullptr) { + return std::vector(); + } + + std::vector command_line_arguments; + + // Skip the first argument as it's the binary name. + for (int i = 1; i < argc; i++) { + command_line_arguments.push_back(Utf8FromUtf16(argv[i])); + } + + ::LocalFree(argv); + + return command_line_arguments; +} + +std::string Utf8FromUtf16(const wchar_t* utf16_string) { + if (utf16_string == nullptr) { + return std::string(); + } + int target_length = ::WideCharToMultiByte( + CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, + -1, nullptr, 0, nullptr, nullptr) + -1; // remove the trailing null character + int input_length = (int)wcslen(utf16_string); + std::string utf8_string; + if (target_length <= 0 || target_length > utf8_string.max_size()) { + return utf8_string; + } + utf8_string.resize(target_length); + int converted_length = ::WideCharToMultiByte( + CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, + input_length, utf8_string.data(), target_length, nullptr, nullptr); + if (converted_length == 0) { + return std::string(); + } + return utf8_string; +} diff --git a/demos/supabase-trello/windows/runner/utils.h b/demos/supabase-trello/windows/runner/utils.h new file mode 100644 index 00000000..3879d547 --- /dev/null +++ b/demos/supabase-trello/windows/runner/utils.h @@ -0,0 +1,19 @@ +#ifndef RUNNER_UTILS_H_ +#define RUNNER_UTILS_H_ + +#include +#include + +// Creates a console for the process, and redirects stdout and stderr to +// it for both the runner and the Flutter library. +void CreateAndAttachConsole(); + +// Takes a null-terminated wchar_t* encoded in UTF-16 and returns a std::string +// encoded in UTF-8. Returns an empty std::string on failure. +std::string Utf8FromUtf16(const wchar_t* utf16_string); + +// Gets the command line arguments passed in as a std::vector, +// encoded in UTF-8. Returns an empty std::vector on failure. +std::vector GetCommandLineArguments(); + +#endif // RUNNER_UTILS_H_ diff --git a/demos/supabase-trello/windows/runner/win32_window.cpp b/demos/supabase-trello/windows/runner/win32_window.cpp new file mode 100644 index 00000000..60608d0f --- /dev/null +++ b/demos/supabase-trello/windows/runner/win32_window.cpp @@ -0,0 +1,288 @@ +#include "win32_window.h" + +#include +#include + +#include "resource.h" + +namespace { + +/// Window attribute that enables dark mode window decorations. +/// +/// Redefined in case the developer's machine has a Windows SDK older than +/// version 10.0.22000.0. +/// See: https://docs.microsoft.com/windows/win32/api/dwmapi/ne-dwmapi-dwmwindowattribute +#ifndef DWMWA_USE_IMMERSIVE_DARK_MODE +#define DWMWA_USE_IMMERSIVE_DARK_MODE 20 +#endif + +constexpr const wchar_t kWindowClassName[] = L"FLUTTER_RUNNER_WIN32_WINDOW"; + +/// Registry key for app theme preference. +/// +/// A value of 0 indicates apps should use dark mode. A non-zero or missing +/// value indicates apps should use light mode. +constexpr const wchar_t kGetPreferredBrightnessRegKey[] = + L"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize"; +constexpr const wchar_t kGetPreferredBrightnessRegValue[] = L"AppsUseLightTheme"; + +// The number of Win32Window objects that currently exist. +static int g_active_window_count = 0; + +using EnableNonClientDpiScaling = BOOL __stdcall(HWND hwnd); + +// Scale helper to convert logical scaler values to physical using passed in +// scale factor +int Scale(int source, double scale_factor) { + return static_cast(source * scale_factor); +} + +// Dynamically loads the |EnableNonClientDpiScaling| from the User32 module. +// This API is only needed for PerMonitor V1 awareness mode. +void EnableFullDpiSupportIfAvailable(HWND hwnd) { + HMODULE user32_module = LoadLibraryA("User32.dll"); + if (!user32_module) { + return; + } + auto enable_non_client_dpi_scaling = + reinterpret_cast( + GetProcAddress(user32_module, "EnableNonClientDpiScaling")); + if (enable_non_client_dpi_scaling != nullptr) { + enable_non_client_dpi_scaling(hwnd); + } + FreeLibrary(user32_module); +} + +} // namespace + +// Manages the Win32Window's window class registration. +class WindowClassRegistrar { + public: + ~WindowClassRegistrar() = default; + + // Returns the singleton registrar instance. + static WindowClassRegistrar* GetInstance() { + if (!instance_) { + instance_ = new WindowClassRegistrar(); + } + return instance_; + } + + // Returns the name of the window class, registering the class if it hasn't + // previously been registered. + const wchar_t* GetWindowClass(); + + // Unregisters the window class. Should only be called if there are no + // instances of the window. + void UnregisterWindowClass(); + + private: + WindowClassRegistrar() = default; + + static WindowClassRegistrar* instance_; + + bool class_registered_ = false; +}; + +WindowClassRegistrar* WindowClassRegistrar::instance_ = nullptr; + +const wchar_t* WindowClassRegistrar::GetWindowClass() { + if (!class_registered_) { + WNDCLASS window_class{}; + window_class.hCursor = LoadCursor(nullptr, IDC_ARROW); + window_class.lpszClassName = kWindowClassName; + window_class.style = CS_HREDRAW | CS_VREDRAW; + window_class.cbClsExtra = 0; + window_class.cbWndExtra = 0; + window_class.hInstance = GetModuleHandle(nullptr); + window_class.hIcon = + LoadIcon(window_class.hInstance, MAKEINTRESOURCE(IDI_APP_ICON)); + window_class.hbrBackground = 0; + window_class.lpszMenuName = nullptr; + window_class.lpfnWndProc = Win32Window::WndProc; + RegisterClass(&window_class); + class_registered_ = true; + } + return kWindowClassName; +} + +void WindowClassRegistrar::UnregisterWindowClass() { + UnregisterClass(kWindowClassName, nullptr); + class_registered_ = false; +} + +Win32Window::Win32Window() { + ++g_active_window_count; +} + +Win32Window::~Win32Window() { + --g_active_window_count; + Destroy(); +} + +bool Win32Window::Create(const std::wstring& title, + const Point& origin, + const Size& size) { + Destroy(); + + const wchar_t* window_class = + WindowClassRegistrar::GetInstance()->GetWindowClass(); + + const POINT target_point = {static_cast(origin.x), + static_cast(origin.y)}; + HMONITOR monitor = MonitorFromPoint(target_point, MONITOR_DEFAULTTONEAREST); + UINT dpi = FlutterDesktopGetDpiForMonitor(monitor); + double scale_factor = dpi / 96.0; + + HWND window = CreateWindow( + window_class, title.c_str(), WS_OVERLAPPEDWINDOW, + Scale(origin.x, scale_factor), Scale(origin.y, scale_factor), + Scale(size.width, scale_factor), Scale(size.height, scale_factor), + nullptr, nullptr, GetModuleHandle(nullptr), this); + + if (!window) { + return false; + } + + UpdateTheme(window); + + return OnCreate(); +} + +bool Win32Window::Show() { + return ShowWindow(window_handle_, SW_SHOWNORMAL); +} + +// static +LRESULT CALLBACK Win32Window::WndProc(HWND const window, + UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept { + if (message == WM_NCCREATE) { + auto window_struct = reinterpret_cast(lparam); + SetWindowLongPtr(window, GWLP_USERDATA, + reinterpret_cast(window_struct->lpCreateParams)); + + auto that = static_cast(window_struct->lpCreateParams); + EnableFullDpiSupportIfAvailable(window); + that->window_handle_ = window; + } else if (Win32Window* that = GetThisFromHandle(window)) { + return that->MessageHandler(window, message, wparam, lparam); + } + + return DefWindowProc(window, message, wparam, lparam); +} + +LRESULT +Win32Window::MessageHandler(HWND hwnd, + UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept { + switch (message) { + case WM_DESTROY: + window_handle_ = nullptr; + Destroy(); + if (quit_on_close_) { + PostQuitMessage(0); + } + return 0; + + case WM_DPICHANGED: { + auto newRectSize = reinterpret_cast(lparam); + LONG newWidth = newRectSize->right - newRectSize->left; + LONG newHeight = newRectSize->bottom - newRectSize->top; + + SetWindowPos(hwnd, nullptr, newRectSize->left, newRectSize->top, newWidth, + newHeight, SWP_NOZORDER | SWP_NOACTIVATE); + + return 0; + } + case WM_SIZE: { + RECT rect = GetClientArea(); + if (child_content_ != nullptr) { + // Size and position the child window. + MoveWindow(child_content_, rect.left, rect.top, rect.right - rect.left, + rect.bottom - rect.top, TRUE); + } + return 0; + } + + case WM_ACTIVATE: + if (child_content_ != nullptr) { + SetFocus(child_content_); + } + return 0; + + case WM_DWMCOLORIZATIONCOLORCHANGED: + UpdateTheme(hwnd); + return 0; + } + + return DefWindowProc(window_handle_, message, wparam, lparam); +} + +void Win32Window::Destroy() { + OnDestroy(); + + if (window_handle_) { + DestroyWindow(window_handle_); + window_handle_ = nullptr; + } + if (g_active_window_count == 0) { + WindowClassRegistrar::GetInstance()->UnregisterWindowClass(); + } +} + +Win32Window* Win32Window::GetThisFromHandle(HWND const window) noexcept { + return reinterpret_cast( + GetWindowLongPtr(window, GWLP_USERDATA)); +} + +void Win32Window::SetChildContent(HWND content) { + child_content_ = content; + SetParent(content, window_handle_); + RECT frame = GetClientArea(); + + MoveWindow(content, frame.left, frame.top, frame.right - frame.left, + frame.bottom - frame.top, true); + + SetFocus(child_content_); +} + +RECT Win32Window::GetClientArea() { + RECT frame; + GetClientRect(window_handle_, &frame); + return frame; +} + +HWND Win32Window::GetHandle() { + return window_handle_; +} + +void Win32Window::SetQuitOnClose(bool quit_on_close) { + quit_on_close_ = quit_on_close; +} + +bool Win32Window::OnCreate() { + // No-op; provided for subclasses. + return true; +} + +void Win32Window::OnDestroy() { + // No-op; provided for subclasses. +} + +void Win32Window::UpdateTheme(HWND const window) { + DWORD light_mode; + DWORD light_mode_size = sizeof(light_mode); + LSTATUS result = RegGetValue(HKEY_CURRENT_USER, kGetPreferredBrightnessRegKey, + kGetPreferredBrightnessRegValue, + RRF_RT_REG_DWORD, nullptr, &light_mode, + &light_mode_size); + + if (result == ERROR_SUCCESS) { + BOOL enable_dark_mode = light_mode == 0; + DwmSetWindowAttribute(window, DWMWA_USE_IMMERSIVE_DARK_MODE, + &enable_dark_mode, sizeof(enable_dark_mode)); + } +} diff --git a/demos/supabase-trello/windows/runner/win32_window.h b/demos/supabase-trello/windows/runner/win32_window.h new file mode 100644 index 00000000..e901dde6 --- /dev/null +++ b/demos/supabase-trello/windows/runner/win32_window.h @@ -0,0 +1,102 @@ +#ifndef RUNNER_WIN32_WINDOW_H_ +#define RUNNER_WIN32_WINDOW_H_ + +#include + +#include +#include +#include + +// A class abstraction for a high DPI-aware Win32 Window. Intended to be +// inherited from by classes that wish to specialize with custom +// rendering and input handling +class Win32Window { + public: + struct Point { + unsigned int x; + unsigned int y; + Point(unsigned int x, unsigned int y) : x(x), y(y) {} + }; + + struct Size { + unsigned int width; + unsigned int height; + Size(unsigned int width, unsigned int height) + : width(width), height(height) {} + }; + + Win32Window(); + virtual ~Win32Window(); + + // Creates a win32 window with |title| that is positioned and sized using + // |origin| and |size|. New windows are created on the default monitor. Window + // sizes are specified to the OS in physical pixels, hence to ensure a + // consistent size this function will scale the inputted width and height as + // as appropriate for the default monitor. The window is invisible until + // |Show| is called. Returns true if the window was created successfully. + bool Create(const std::wstring& title, const Point& origin, const Size& size); + + // Show the current window. Returns true if the window was successfully shown. + bool Show(); + + // Release OS resources associated with window. + void Destroy(); + + // Inserts |content| into the window tree. + void SetChildContent(HWND content); + + // Returns the backing Window handle to enable clients to set icon and other + // window properties. Returns nullptr if the window has been destroyed. + HWND GetHandle(); + + // If true, closing this window will quit the application. + void SetQuitOnClose(bool quit_on_close); + + // Return a RECT representing the bounds of the current client area. + RECT GetClientArea(); + + protected: + // Processes and route salient window messages for mouse handling, + // size change and DPI. Delegates handling of these to member overloads that + // inheriting classes can handle. + virtual LRESULT MessageHandler(HWND window, + UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept; + + // Called when CreateAndShow is called, allowing subclass window-related + // setup. Subclasses should return false if setup fails. + virtual bool OnCreate(); + + // Called when Destroy is called. + virtual void OnDestroy(); + + private: + friend class WindowClassRegistrar; + + // OS callback called by message pump. Handles the WM_NCCREATE message which + // is passed when the non-client area is being created and enables automatic + // non-client DPI scaling so that the non-client area automatically + // responds to changes in DPI. All other messages are handled by + // MessageHandler. + static LRESULT CALLBACK WndProc(HWND const window, + UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept; + + // Retrieves a class instance pointer for |window| + static Win32Window* GetThisFromHandle(HWND const window) noexcept; + + // Update the window frame's theme to match the system theme. + static void UpdateTheme(HWND const window); + + bool quit_on_close_ = false; + + // window handle for top level window. + HWND window_handle_ = nullptr; + + // window handle for hosted content. + HWND child_content_ = nullptr; +}; + +#endif // RUNNER_WIN32_WINDOW_H_ From 6ecb6f187ea652b3f6d79748ba903dc711e3b8a3 Mon Sep 17 00:00:00 2001 From: DominicGBauer Date: Thu, 9 Jan 2025 11:29:23 +0200 Subject: [PATCH 02/10] fix: formatting --- .../board/presentation/boardlistobject.dart | 2 +- .../generateworkspace/presentation/index.dart | 5 +- .../landing/presentation/bottomsheet.dart | 9 +- .../signtotrello/domain/sign_arguments.dart | 2 +- .../workspacemenu/presentation/index.dart | 18 +- .../supabase-trello/lib/models/activity.dart | 4 +- .../lib/models/attachment.dart | 3 +- .../supabase-trello/lib/models/listboard.dart | 3 +- demos/supabase-trello/lib/models/models.dart | 2 +- .../supabase-trello/lib/models/workspace.dart | 4 +- demos/supabase-trello/lib/utils/constant.dart | 2 +- demos/supabase-trello/lib/utils/widgets.dart | 2 +- .../lib/widgets/thirdparty/board_list.dart | 36 +- .../lib/widgets/thirdparty/boardview.dart | 392 ++++++++++++------ .../thirdparty/boardview_controller.dart | 14 +- 15 files changed, 309 insertions(+), 189 deletions(-) diff --git a/demos/supabase-trello/lib/features/board/presentation/boardlistobject.dart b/demos/supabase-trello/lib/features/board/presentation/boardlistobject.dart index 0b19b482..1a234877 100644 --- a/demos/supabase-trello/lib/features/board/presentation/boardlistobject.dart +++ b/demos/supabase-trello/lib/features/board/presentation/boardlistobject.dart @@ -6,7 +6,7 @@ class BoardListObject { List? items; BoardListObject({this.title, this.listId, this.items}) { - listId ??="0"; + listId ??= "0"; title ??= ""; items ??= []; } diff --git a/demos/supabase-trello/lib/features/generateworkspace/presentation/index.dart b/demos/supabase-trello/lib/features/generateworkspace/presentation/index.dart index 34ed35fb..f45307a4 100644 --- a/demos/supabase-trello/lib/features/generateworkspace/presentation/index.dart +++ b/demos/supabase-trello/lib/features/generateworkspace/presentation/index.dart @@ -87,10 +87,7 @@ class _GenerateWorkspaceState extends State with Service { child: ElevatedButton( onPressed: () { DataGenerator().createSampleWorkspace( - nameController.text, - trello, - context - ); + nameController.text, trello, context); }, child: const Text("Create"))), ) diff --git a/demos/supabase-trello/lib/features/landing/presentation/bottomsheet.dart b/demos/supabase-trello/lib/features/landing/presentation/bottomsheet.dart index c58ed811..cd217feb 100644 --- a/demos/supabase-trello/lib/features/landing/presentation/bottomsheet.dart +++ b/demos/supabase-trello/lib/features/landing/presentation/bottomsheet.dart @@ -48,7 +48,8 @@ class _LandingBottomSheetState extends State { (widget.type == Sign.signUp) ? " SIGN UP WITH GOOGLE" : "LOG IN WITH GOOGLE", - style: const TextStyle(fontWeight: FontWeight.bold, color: Colors.grey), + style: const TextStyle( + fontWeight: FontWeight.bold, color: Colors.grey), ), ), ListTile( @@ -61,7 +62,8 @@ class _LandingBottomSheetState extends State { (widget.type == Sign.signUp) ? " SIGN UP WITH MICROSOFT" : "LOG IN WITH MICROSOFT", - style: const TextStyle(fontWeight: FontWeight.bold, color: Colors.grey), + style: const TextStyle( + fontWeight: FontWeight.bold, color: Colors.grey), ), ), ListTile( @@ -74,7 +76,8 @@ class _LandingBottomSheetState extends State { (widget.type == Sign.signUp) ? " SIGN UP WITH APPLE" : "LOG IN WITH APPLE", - style: const TextStyle(fontWeight: FontWeight.bold, color: Colors.grey), + style: const TextStyle( + fontWeight: FontWeight.bold, color: Colors.grey), ), ) ], diff --git a/demos/supabase-trello/lib/features/signtotrello/domain/sign_arguments.dart b/demos/supabase-trello/lib/features/signtotrello/domain/sign_arguments.dart index 52fa78a0..e6fceb51 100644 --- a/demos/supabase-trello/lib/features/signtotrello/domain/sign_arguments.dart +++ b/demos/supabase-trello/lib/features/signtotrello/domain/sign_arguments.dart @@ -2,4 +2,4 @@ class SignArguments { final Enum type; SignArguments(this.type); -} \ No newline at end of file +} diff --git a/demos/supabase-trello/lib/features/workspacemenu/presentation/index.dart b/demos/supabase-trello/lib/features/workspacemenu/presentation/index.dart index 8cff3ceb..051d3d8b 100644 --- a/demos/supabase-trello/lib/features/workspacemenu/presentation/index.dart +++ b/demos/supabase-trello/lib/features/workspacemenu/presentation/index.dart @@ -50,7 +50,7 @@ class _WorkspaceMenuState extends State with Service { style: const TextStyle( fontWeight: FontWeight.bold, fontSize: 18), ), - const Text.rich(TextSpan(children: [ + const Text.rich(TextSpan(children: [ WidgetSpan( child: Icon(Icons.lock, color: dangerColor, size: 15)), @@ -125,15 +125,13 @@ class _WorkspaceMenuState extends State with Service { List avatars = []; trello.selectedWorkspace.members?.forEach((member) { - avatars.add( - CircleAvatar( - backgroundColor: brandColor, - child: Text(member.name[0].toUpperCase()), - ) - ); - avatars.add( - const SizedBox(width: 4,) - ); + avatars.add(CircleAvatar( + backgroundColor: brandColor, + child: Text(member.name[0].toUpperCase()), + )); + avatars.add(const SizedBox( + width: 4, + )); }); return avatars; } diff --git a/demos/supabase-trello/lib/models/activity.dart b/demos/supabase-trello/lib/models/activity.dart index 28a7a380..ce85f190 100644 --- a/demos/supabase-trello/lib/models/activity.dart +++ b/demos/supabase-trello/lib/models/activity.dart @@ -32,8 +32,6 @@ class Activity { userId: row['userId'], cardId: row['cardId'], description: row['description'], - dateCreated: DateTime.parse(row['dateCreated']) - ); + dateCreated: DateTime.parse(row['dateCreated'])); } - } diff --git a/demos/supabase-trello/lib/models/attachment.dart b/demos/supabase-trello/lib/models/attachment.dart index a2cb5b2c..1ef86d15 100644 --- a/demos/supabase-trello/lib/models/attachment.dart +++ b/demos/supabase-trello/lib/models/attachment.dart @@ -24,5 +24,6 @@ class Attachment { workspaceId: row['workspaceId'], userId: row['userId'], cardId: row['cardId'], - attachment: row['attachment']);} + attachment: row['attachment']); + } } diff --git a/demos/supabase-trello/lib/models/listboard.dart b/demos/supabase-trello/lib/models/listboard.dart index cc5c9207..887ddcd9 100644 --- a/demos/supabase-trello/lib/models/listboard.dart +++ b/demos/supabase-trello/lib/models/listboard.dart @@ -38,7 +38,6 @@ class Listboard { name: row['name'], archived: row['archived'] == 1, order: row['listOrder'], - cards: [] - ); + cards: []); } } diff --git a/demos/supabase-trello/lib/models/models.dart b/demos/supabase-trello/lib/models/models.dart index c3c8e939..d824c549 100644 --- a/demos/supabase-trello/lib/models/models.dart +++ b/demos/supabase-trello/lib/models/models.dart @@ -9,4 +9,4 @@ export 'member.dart'; export 'user.dart'; export 'workspace.dart'; export 'board_label.dart'; -export 'card_label.dart'; \ No newline at end of file +export 'card_label.dart'; diff --git a/demos/supabase-trello/lib/models/workspace.dart b/demos/supabase-trello/lib/models/workspace.dart index 67a72574..d5e194a6 100644 --- a/demos/supabase-trello/lib/models/workspace.dart +++ b/demos/supabase-trello/lib/models/workspace.dart @@ -31,6 +31,6 @@ class Workspace { name: row['name'], description: row['description'], visibility: row['visibility'], - members: [] - );} + members: []); + } } diff --git a/demos/supabase-trello/lib/utils/constant.dart b/demos/supabase-trello/lib/utils/constant.dart index 7c04692f..2a1a9bd0 100644 --- a/demos/supabase-trello/lib/utils/constant.dart +++ b/demos/supabase-trello/lib/utils/constant.dart @@ -37,4 +37,4 @@ const powerups = [ "description": "Set a limit on your lists and we'll highlight the list if the number of cards in it passes the limit" } -]; \ No newline at end of file +]; diff --git a/demos/supabase-trello/lib/utils/widgets.dart b/demos/supabase-trello/lib/utils/widgets.dart index 4d0e45a8..bfebae06 100644 --- a/demos/supabase-trello/lib/utils/widgets.dart +++ b/demos/supabase-trello/lib/utils/widgets.dart @@ -14,7 +14,7 @@ class _LabelDiplayState extends State { @override Widget build(BuildContext context) { return DecoratedBox( - decoration: BoxDecoration( + decoration: BoxDecoration( color: Color(int.parse(widget.color, radix: 16) + 0xFF000000), borderRadius: const BorderRadius.all(Radius.circular(5.0))), child: Center( diff --git a/demos/supabase-trello/lib/widgets/thirdparty/board_list.dart b/demos/supabase-trello/lib/widgets/thirdparty/board_list.dart index 5ccdadf3..7e9c1d66 100644 --- a/demos/supabase-trello/lib/widgets/thirdparty/board_list.dart +++ b/demos/supabase-trello/lib/widgets/thirdparty/board_list.dart @@ -3,7 +3,7 @@ import 'boardview.dart'; import 'package:flutter/material.dart'; import 'package:flutter/widgets.dart'; -typedef void OnDropList(int? listIndex,int? oldListIndex); +typedef void OnDropList(int? listIndex, int? oldListIndex); typedef void OnTapList(int? listIndex); typedef void OnStartDragList(int? listIndex); @@ -28,7 +28,10 @@ class BoardList extends StatefulWidget { this.headerBackgroundColor, this.boardView, this.draggable = true, - this.index, this.onDropList, this.onTapList, this.onStartDragList, + this.index, + this.onDropList, + this.onTapList, + this.onStartDragList, }) : super(key: key); final int? index; @@ -39,25 +42,24 @@ class BoardList extends StatefulWidget { } } -class BoardListState extends State with AutomaticKeepAliveClientMixin{ +class BoardListState extends State + with AutomaticKeepAliveClientMixin { List itemStates = []; ScrollController boardListController = new ScrollController(); void onDropList(int? listIndex) { - if(widget.onDropList != null){ - widget.onDropList!(listIndex,widget.boardView!.startListIndex); + if (widget.onDropList != null) { + widget.onDropList!(listIndex, widget.boardView!.startListIndex); } widget.boardView!.draggedListIndex = null; - if(widget.boardView!.mounted) { - widget.boardView!.setState(() { - - }); + if (widget.boardView!.mounted) { + widget.boardView!.setState(() {}); } } void _startDrag(Widget item, BuildContext context) { if (widget.boardView != null && widget.draggable) { - if(widget.onStartDragList != null){ + if (widget.onStartDragList != null) { widget.onStartDragList!(widget.index); } widget.boardView!.startListIndex = widget.index; @@ -67,7 +69,7 @@ class BoardListState extends State with AutomaticKeepAliveClientMixin widget.boardView!.draggedItem = item; widget.boardView!.onDropList = onDropList; widget.boardView!.run(); - if(widget.boardView!.mounted) { + if (widget.boardView!.mounted) { widget.boardView!.setState(() {}); } } @@ -85,13 +87,13 @@ class BoardListState extends State with AutomaticKeepAliveClientMixin headerBackgroundColor = widget.headerBackgroundColor; } listWidgets.add(GestureDetector( - onTap: (){ - if(widget.onTapList != null){ + onTap: () { + if (widget.onTapList != null) { widget.onTapList!(widget.index); } }, onTapDown: (otd) { - if(widget.draggable) { + if (widget.draggable) { RenderBox object = context.findRenderObject() as RenderBox; Offset pos = object.localToGlobal(Offset.zero); widget.boardView!.initialX = pos.dx; @@ -103,7 +105,7 @@ class BoardListState extends State with AutomaticKeepAliveClientMixin }, onTapCancel: () {}, onLongPress: () { - if(!widget.boardView!.widget.isSelecting && widget.draggable) { + if (!widget.boardView!.widget.isSelecting && widget.draggable) { _startDrag(widget, context); } }, @@ -114,7 +116,6 @@ class BoardListState extends State with AutomaticKeepAliveClientMixin mainAxisAlignment: MainAxisAlignment.center, children: widget.header!), ))); - } if (widget.items != null) { listWidgets.add(Flexible( @@ -136,7 +137,8 @@ class BoardListState extends State with AutomaticKeepAliveClientMixin if (widget.items![index].boardList == null || widget.items![index].index != index || - widget.items![index].boardList!.widget.index != widget.index || + widget.items![index].boardList!.widget.index != + widget.index || widget.items![index].boardList != this) { widget.items![index] = BoardItem( boardList: this, diff --git a/demos/supabase-trello/lib/widgets/thirdparty/boardview.dart b/demos/supabase-trello/lib/widgets/thirdparty/boardview.dart index d50faf90..73db6ef3 100644 --- a/demos/supabase-trello/lib/widgets/thirdparty/boardview.dart +++ b/demos/supabase-trello/lib/widgets/thirdparty/boardview.dart @@ -20,7 +20,20 @@ class BoardView extends StatefulWidget { Function(bool)? itemInMiddleWidget; OnDropBottomWidget? onDropItemInMiddleWidget; - BoardView({Key? key, this.itemInMiddleWidget,this.scrollbar,this.scrollbarStyle,this.boardViewController,this.dragDelay=300,this.onDropItemInMiddleWidget, this.isSelecting = false, this.lists, this.width = 280, this.middleWidget, this.bottomPadding}) : super(key: key); + BoardView( + {Key? key, + this.itemInMiddleWidget, + this.scrollbar, + this.scrollbarStyle, + this.boardViewController, + this.dragDelay = 300, + this.onDropItemInMiddleWidget, + this.isSelecting = false, + this.lists, + this.width = 280, + this.middleWidget, + this.bottomPadding}) + : super(key: key); @override State createState() { @@ -28,11 +41,13 @@ class BoardView extends StatefulWidget { } } -typedef void OnDropBottomWidget(int? listIndex, int? itemIndex,double percentX); +typedef void OnDropBottomWidget( + int? listIndex, int? itemIndex, double percentX); typedef void OnDropItem(int? listIndex, int? itemIndex); typedef void OnDropList(int? listIndex); -class BoardViewState extends State with AutomaticKeepAliveClientMixin { +class BoardViewState extends State + with AutomaticKeepAliveClientMixin { Widget? draggedItem; int? draggedItemIndex; int? draggedListIndex; @@ -77,49 +92,65 @@ class BoardViewState extends State with AutomaticKeepAliveClientMixin @override void initState() { super.initState(); - if(widget.boardViewController != null){ + if (widget.boardViewController != null) { widget.boardViewController!.state = this; } } void moveDown() { - if(topItemY != null){ - topItemY = topItemY! + listStates[draggedListIndex!].itemStates[draggedItemIndex! + 1].height; - } - if(bottomItemY != null){ - bottomItemY = bottomItemY! + listStates[draggedListIndex!].itemStates[draggedItemIndex! + 1].height; + if (topItemY != null) { + topItemY = topItemY! + + listStates[draggedListIndex!] + .itemStates[draggedItemIndex! + 1] + .height; + } + if (bottomItemY != null) { + bottomItemY = bottomItemY! + + listStates[draggedListIndex!] + .itemStates[draggedItemIndex! + 1] + .height; } var item = widget.lists![draggedListIndex!].items![draggedItemIndex!]; widget.lists![draggedListIndex!].items!.removeAt(draggedItemIndex!); var itemState = listStates[draggedListIndex!].itemStates[draggedItemIndex!]; listStates[draggedListIndex!].itemStates.removeAt(draggedItemIndex!); - if(draggedItemIndex != null){ + if (draggedItemIndex != null) { draggedItemIndex = draggedItemIndex! + 1; } widget.lists![draggedListIndex!].items!.insert(draggedItemIndex!, item); - listStates[draggedListIndex!].itemStates.insert(draggedItemIndex!, itemState); - if(listStates[draggedListIndex!].mounted) { + listStates[draggedListIndex!] + .itemStates + .insert(draggedItemIndex!, itemState); + if (listStates[draggedListIndex!].mounted) { listStates[draggedListIndex!].setState(() {}); } } void moveUp() { - if(topItemY != null){ - topItemY = topItemY! - listStates[draggedListIndex!].itemStates[draggedItemIndex! - 1].height; - } - if(bottomItemY != null){ - bottomItemY = bottomItemY!-listStates[draggedListIndex!].itemStates[draggedItemIndex! - 1].height; + if (topItemY != null) { + topItemY = topItemY! - + listStates[draggedListIndex!] + .itemStates[draggedItemIndex! - 1] + .height; + } + if (bottomItemY != null) { + bottomItemY = bottomItemY! - + listStates[draggedListIndex!] + .itemStates[draggedItemIndex! - 1] + .height; } var item = widget.lists![draggedListIndex!].items![draggedItemIndex!]; widget.lists![draggedListIndex!].items!.removeAt(draggedItemIndex!); var itemState = listStates[draggedListIndex!].itemStates[draggedItemIndex!]; listStates[draggedListIndex!].itemStates.removeAt(draggedItemIndex!); - if(draggedItemIndex != null){ + if (draggedItemIndex != null) { draggedItemIndex = draggedItemIndex! - 1; } widget.lists![draggedListIndex!].items!.insert(draggedItemIndex!, item); - listStates[draggedListIndex!].itemStates.insert(draggedItemIndex!, itemState); - if(listStates[draggedListIndex!].mounted) { + listStates[draggedListIndex!] + .itemStates + .insert(draggedItemIndex!, itemState); + if (listStates[draggedListIndex!].mounted) { listStates[draggedListIndex!].setState(() {}); } } @@ -129,7 +160,7 @@ class BoardViewState extends State with AutomaticKeepAliveClientMixin var listState = listStates[draggedListIndex!]; widget.lists!.removeAt(draggedListIndex!); listStates.removeAt(draggedListIndex!); - if(draggedListIndex != null){ + if (draggedListIndex != null) { draggedListIndex = draggedListIndex! + 1; } widget.lists!.insert(draggedListIndex!, list); @@ -138,9 +169,11 @@ class BoardViewState extends State with AutomaticKeepAliveClientMixin if (boardViewController != null && boardViewController.hasClients) { int? tempListIndex = draggedListIndex; boardViewController - .animateTo(draggedListIndex! * widget.width, duration: new Duration(milliseconds: 400), curve: Curves.ease) + .animateTo(draggedListIndex! * widget.width, + duration: new Duration(milliseconds: 400), curve: Curves.ease) .whenComplete(() { - RenderBox object = listStates[tempListIndex!].context.findRenderObject() as RenderBox; + RenderBox object = + listStates[tempListIndex!].context.findRenderObject() as RenderBox; Offset pos = object.localToGlobal(Offset.zero); leftListX = pos.dx; rightListX = pos.dx + object.size.width; @@ -149,7 +182,7 @@ class BoardViewState extends State with AutomaticKeepAliveClientMixin }); }); } - if(mounted){ + if (mounted) { setState(() {}); } } @@ -159,17 +192,21 @@ class BoardViewState extends State with AutomaticKeepAliveClientMixin var itemState = listStates[draggedListIndex!].itemStates[draggedItemIndex!]; widget.lists![draggedListIndex!].items!.removeAt(draggedItemIndex!); listStates[draggedListIndex!].itemStates.removeAt(draggedItemIndex!); - if(listStates[draggedListIndex!].mounted) { + if (listStates[draggedListIndex!].mounted) { listStates[draggedListIndex!].setState(() {}); } - if(draggedListIndex != null){ + if (draggedListIndex != null) { draggedListIndex = draggedListIndex! + 1; } double closestValue = 10000; draggedItemIndex = 0; for (int i = 0; i < listStates[draggedListIndex!].itemStates.length; i++) { - if (listStates[draggedListIndex!].itemStates[i].mounted && listStates[draggedListIndex!].itemStates[i].context != null) { - RenderBox box = listStates[draggedListIndex!].itemStates[i].context.findRenderObject() as RenderBox; + if (listStates[draggedListIndex!].itemStates[i].mounted && + listStates[draggedListIndex!].itemStates[i].context != null) { + RenderBox box = listStates[draggedListIndex!] + .itemStates[i] + .context + .findRenderObject() as RenderBox; Offset pos = box.localToGlobal(Offset.zero); var temp = (pos.dy - dy! + (box.size.height / 2)).abs(); if (temp < closestValue) { @@ -180,22 +217,29 @@ class BoardViewState extends State with AutomaticKeepAliveClientMixin } } widget.lists![draggedListIndex!].items!.insert(draggedItemIndex!, item); - listStates[draggedListIndex!].itemStates.insert(draggedItemIndex!, itemState); + listStates[draggedListIndex!] + .itemStates + .insert(draggedItemIndex!, itemState); canDrag = false; - if(listStates[draggedListIndex!].mounted) { + if (listStates[draggedListIndex!].mounted) { listStates[draggedListIndex!].setState(() {}); } if (boardViewController != null && boardViewController.hasClients) { int? tempListIndex = draggedListIndex; int? tempItemIndex = draggedItemIndex; boardViewController - .animateTo(draggedListIndex! * widget.width, duration: new Duration(milliseconds: 400), curve: Curves.ease) + .animateTo(draggedListIndex! * widget.width, + duration: new Duration(milliseconds: 400), curve: Curves.ease) .whenComplete(() { - RenderBox object = listStates[tempListIndex!].context.findRenderObject() as RenderBox; + RenderBox object = + listStates[tempListIndex!].context.findRenderObject() as RenderBox; Offset pos = object.localToGlobal(Offset.zero); leftListX = pos.dx; rightListX = pos.dx + object.size.width; - RenderBox box = listStates[tempListIndex].itemStates[tempItemIndex!].context.findRenderObject() as RenderBox; + RenderBox box = listStates[tempListIndex] + .itemStates[tempItemIndex!] + .context + .findRenderObject() as RenderBox; Offset itemPos = box.localToGlobal(Offset.zero); topItemY = itemPos.dy; bottomItemY = itemPos.dy + box.size.height; @@ -204,8 +248,8 @@ class BoardViewState extends State with AutomaticKeepAliveClientMixin }); }); } - if(mounted){ - setState(() { }); + if (mounted) { + setState(() {}); } } @@ -214,7 +258,7 @@ class BoardViewState extends State with AutomaticKeepAliveClientMixin var listState = listStates[draggedListIndex!]; widget.lists!.removeAt(draggedListIndex!); listStates.removeAt(draggedListIndex!); - if(draggedListIndex != null){ + if (draggedListIndex != null) { draggedListIndex = draggedListIndex! - 1; } widget.lists!.insert(draggedListIndex!, list); @@ -223,9 +267,12 @@ class BoardViewState extends State with AutomaticKeepAliveClientMixin if (boardViewController != null && boardViewController.hasClients) { int? tempListIndex = draggedListIndex; boardViewController - .animateTo(draggedListIndex! * widget.width, duration: new Duration(milliseconds: widget.dragDelay), curve: Curves.ease) + .animateTo(draggedListIndex! * widget.width, + duration: new Duration(milliseconds: widget.dragDelay), + curve: Curves.ease) .whenComplete(() { - RenderBox object = listStates[tempListIndex!].context.findRenderObject() as RenderBox; + RenderBox object = + listStates[tempListIndex!].context.findRenderObject() as RenderBox; Offset pos = object.localToGlobal(Offset.zero); leftListX = pos.dx; rightListX = pos.dx + object.size.width; @@ -234,7 +281,7 @@ class BoardViewState extends State with AutomaticKeepAliveClientMixin }); }); } - if(mounted) { + if (mounted) { setState(() {}); } } @@ -244,17 +291,21 @@ class BoardViewState extends State with AutomaticKeepAliveClientMixin var itemState = listStates[draggedListIndex!].itemStates[draggedItemIndex!]; widget.lists![draggedListIndex!].items!.removeAt(draggedItemIndex!); listStates[draggedListIndex!].itemStates.removeAt(draggedItemIndex!); - if(listStates[draggedListIndex!].mounted) { + if (listStates[draggedListIndex!].mounted) { listStates[draggedListIndex!].setState(() {}); } - if(draggedListIndex != null){ + if (draggedListIndex != null) { draggedListIndex = draggedListIndex! - 1; } double closestValue = 10000; draggedItemIndex = 0; for (int i = 0; i < listStates[draggedListIndex!].itemStates.length; i++) { - if (listStates[draggedListIndex!].itemStates[i].mounted && listStates[draggedListIndex!].itemStates[i].context != null) { - RenderBox box = listStates[draggedListIndex!].itemStates[i].context.findRenderObject() as RenderBox; + if (listStates[draggedListIndex!].itemStates[i].mounted && + listStates[draggedListIndex!].itemStates[i].context != null) { + RenderBox box = listStates[draggedListIndex!] + .itemStates[i] + .context + .findRenderObject() as RenderBox; Offset pos = box.localToGlobal(Offset.zero); var temp = (pos.dy - dy! + (box.size.height / 2)).abs(); if (temp < closestValue) { @@ -265,22 +316,29 @@ class BoardViewState extends State with AutomaticKeepAliveClientMixin } } widget.lists![draggedListIndex!].items!.insert(draggedItemIndex!, item); - listStates[draggedListIndex!].itemStates.insert(draggedItemIndex!, itemState); + listStates[draggedListIndex!] + .itemStates + .insert(draggedItemIndex!, itemState); canDrag = false; - if(listStates[draggedListIndex!].mounted) { + if (listStates[draggedListIndex!].mounted) { listStates[draggedListIndex!].setState(() {}); } if (boardViewController != null && boardViewController.hasClients) { int? tempListIndex = draggedListIndex; int? tempItemIndex = draggedItemIndex; boardViewController - .animateTo(draggedListIndex! * widget.width, duration: new Duration(milliseconds: 400), curve: Curves.ease) + .animateTo(draggedListIndex! * widget.width, + duration: new Duration(milliseconds: 400), curve: Curves.ease) .whenComplete(() { - RenderBox object = listStates[tempListIndex!].context.findRenderObject() as RenderBox; + RenderBox object = + listStates[tempListIndex!].context.findRenderObject() as RenderBox; Offset pos = object.localToGlobal(Offset.zero); leftListX = pos.dx; rightListX = pos.dx + object.size.width; - RenderBox box = listStates[tempListIndex].itemStates[tempItemIndex!].context.findRenderObject() as RenderBox; + RenderBox box = listStates[tempListIndex] + .itemStates[tempItemIndex!] + .context + .findRenderObject() as RenderBox; Offset itemPos = box.localToGlobal(Offset.zero); topItemY = itemPos.dy; bottomItemY = itemPos.dy + box.size.height; @@ -289,7 +347,7 @@ class BoardViewState extends State with AutomaticKeepAliveClientMixin }); }); } - if(mounted) { + if (mounted) { setState(() {}); } } @@ -301,13 +359,13 @@ class BoardViewState extends State with AutomaticKeepAliveClientMixin // print("dy:${dy}"); // print("topListY:${topListY}"); // print("bottomListY:${bottomListY}"); - if(boardViewController.hasClients) { + if (boardViewController.hasClients) { WidgetsBinding.instance!.addPostFrameCallback((Duration duration) { try { boardViewController.position.didUpdateScrollPositionBy(0); - }catch(e){} - bool _shown = boardViewController.position.maxScrollExtent!=0; - if(_shown != shown){ + } catch (e) {} + bool _shown = boardViewController.position.maxScrollExtent != 0; + if (_shown != shown) { setState(() { shown = _shown; }); @@ -325,7 +383,7 @@ class BoardViewState extends State with AutomaticKeepAliveClientMixin print('Returned empty container'); return Container(); } - + if (widget.lists![index].boardView == null) { widget.lists![index] = BoardList( items: widget.lists![index].items, @@ -374,31 +432,32 @@ class BoardViewState extends State with AutomaticKeepAliveClientMixin } }, ); - if(widget.scrollbar == true){ + if (widget.scrollbar == true) { listWidget = VsScrollbar( controller: boardViewController, - showTrackOnHover: true,// default false - isAlwaysShown: shown&&widget.lists!.length>1, // default false - scrollbarFadeDuration: Duration(milliseconds: 500), // default : Duration(milliseconds: 300) - scrollbarTimeToFade: Duration(milliseconds: 800),// default : Duration(milliseconds: 600) - style: widget.scrollbarStyle!=null?VsScrollbarStyle( - hoverThickness: widget.scrollbarStyle!.hoverThickness, - radius: widget.scrollbarStyle!.radius, - thickness: widget.scrollbarStyle!.thickness, - color: widget.scrollbarStyle!.color - ):VsScrollbarStyle(), - child:listWidget); - } - List stackWidgets = [ - listWidget - ]; + showTrackOnHover: true, // default false + isAlwaysShown: shown && widget.lists!.length > 1, // default false + scrollbarFadeDuration: Duration( + milliseconds: 500), // default : Duration(milliseconds: 300) + scrollbarTimeToFade: Duration( + milliseconds: 800), // default : Duration(milliseconds: 600) + style: widget.scrollbarStyle != null + ? VsScrollbarStyle( + hoverThickness: widget.scrollbarStyle!.hoverThickness, + radius: widget.scrollbarStyle!.radius, + thickness: widget.scrollbarStyle!.thickness, + color: widget.scrollbarStyle!.color) + : VsScrollbarStyle(), + child: listWidget); + } + List stackWidgets = [listWidget]; bool isInBottomWidget = false; if (dy != null) { if (MediaQuery.of(context).size.height - dy! < 80) { isInBottomWidget = true; } } - if(widget.itemInMiddleWidget != null && _isInWidget != isInBottomWidget) { + if (widget.itemInMiddleWidget != null && _isInWidget != isInBottomWidget) { widget.itemInMiddleWidget!(isInBottomWidget); _isInWidget = isInBottomWidget; } @@ -411,15 +470,21 @@ class BoardViewState extends State with AutomaticKeepAliveClientMixin height != null && widget.width != null) { if (canDrag && dxInit != null && dyInit != null && !isInBottomWidget) { - if (draggedItemIndex != null && draggedItem != null && topItemY != null && bottomItemY != null) { + if (draggedItemIndex != null && + draggedItem != null && + topItemY != null && + bottomItemY != null) { //dragging item if (0 <= draggedListIndex! - 1 && dx! < leftListX! + 45) { //scroll left if (boardViewController != null && boardViewController.hasClients) { - boardViewController.animateTo(boardViewController.position.pixels - 5, - duration: new Duration(milliseconds: 10), curve: Curves.ease); - if(listStates[draggedListIndex!].mounted) { - RenderBox object = listStates[draggedListIndex!].context + boardViewController.animateTo( + boardViewController.position.pixels - 5, + duration: new Duration(milliseconds: 10), + curve: Curves.ease); + if (listStates[draggedListIndex!].mounted) { + RenderBox object = listStates[draggedListIndex!] + .context .findRenderObject() as RenderBox; Offset pos = object.localToGlobal(Offset.zero); leftListX = pos.dx; @@ -427,13 +492,17 @@ class BoardViewState extends State with AutomaticKeepAliveClientMixin } } } - if (widget.lists!.length > draggedListIndex! + 1 && dx! > rightListX! - 45) { + if (widget.lists!.length > draggedListIndex! + 1 && + dx! > rightListX! - 45) { //scroll right if (boardViewController != null && boardViewController.hasClients) { - boardViewController.animateTo(boardViewController.position.pixels + 5, - duration: new Duration(milliseconds: 10), curve: Curves.ease); - if(listStates[draggedListIndex!].mounted) { - RenderBox object = listStates[draggedListIndex!].context + boardViewController.animateTo( + boardViewController.position.pixels + 5, + duration: new Duration(milliseconds: 10), + curve: Curves.ease); + if (listStates[draggedListIndex!].mounted) { + RenderBox object = listStates[draggedListIndex!] + .context .findRenderObject() as RenderBox; Offset pos = object.localToGlobal(Offset.zero); leftListX = pos.dx; @@ -445,48 +514,66 @@ class BoardViewState extends State with AutomaticKeepAliveClientMixin //move left moveLeft(); } - if (widget.lists!.length > draggedListIndex! + 1 && dx! > rightListX!) { + if (widget.lists!.length > draggedListIndex! + 1 && + dx! > rightListX!) { //move right moveRight(); } if (dy! < topListY! + 70) { //scroll up if (listStates[draggedListIndex!].boardListController != null && - listStates[draggedListIndex!].boardListController.hasClients && !isScrolling) { + listStates[draggedListIndex!].boardListController.hasClients && + !isScrolling) { isScrolling = true; - double pos = listStates[draggedListIndex!].boardListController.position.pixels; - listStates[draggedListIndex!].boardListController.animateTo( - listStates[draggedListIndex!].boardListController.position.pixels - 5, - duration: new Duration(milliseconds: 10), - curve: Curves.ease).whenComplete((){ - - pos -= listStates[draggedListIndex!].boardListController.position.pixels; - if(initialY == null) - initialY = 0; + double pos = listStates[draggedListIndex!] + .boardListController + .position + .pixels; + listStates[draggedListIndex!] + .boardListController + .animateTo( + listStates[draggedListIndex!] + .boardListController + .position + .pixels - + 5, + duration: new Duration(milliseconds: 10), + curve: Curves.ease) + .whenComplete(() { + pos -= listStates[draggedListIndex!] + .boardListController + .position + .pixels; + if (initialY == null) initialY = 0; // if(widget.boardViewController != null) { // initialY -= pos; // } isScrolling = false; - if(topItemY != null) { + if (topItemY != null) { topItemY = topItemY! + pos; } - if(bottomItemY != null) { + if (bottomItemY != null) { bottomItemY = bottomItemY! + pos; } - if(mounted){ - setState(() { }); + if (mounted) { + setState(() {}); } }); } } if (0 <= draggedItemIndex! - 1 && - dy! < topItemY! - listStates[draggedListIndex!].itemStates[draggedItemIndex! - 1].height / 2) { + dy! < + topItemY! - + listStates[draggedListIndex!] + .itemStates[draggedItemIndex! - 1] + .height / + 2) { //move up moveUp(); } double? tempBottom = bottomListY; - if(widget.middleWidget != null){ - if(_middleWidgetKey.currentContext != null) { + if (widget.middleWidget != null) { + if (_middleWidgetKey.currentContext != null) { RenderBox _box = _middleWidgetKey.currentContext! .findRenderObject() as RenderBox; tempBottom = _box.size.height; @@ -496,34 +583,54 @@ class BoardViewState extends State with AutomaticKeepAliveClientMixin if (dy! > tempBottom! - 70) { //scroll down - if (listStates.length < draggedListIndex! && listStates[draggedListIndex!].boardListController != null && + if (listStates.length < draggedListIndex! && + listStates[draggedListIndex!].boardListController != null && listStates[draggedListIndex!].boardListController.hasClients) { isScrolling = true; - double pos = listStates[draggedListIndex!].boardListController.position.pixels; - listStates[draggedListIndex!].boardListController.animateTo( - listStates[draggedListIndex!].boardListController.position.pixels + 5, - duration: new Duration(milliseconds: 10), - curve: Curves.ease).whenComplete((){ - pos -= listStates[draggedListIndex!].boardListController.position.pixels; + double pos = listStates[draggedListIndex!] + .boardListController + .position + .pixels; + listStates[draggedListIndex!] + .boardListController + .animateTo( + listStates[draggedListIndex!] + .boardListController + .position + .pixels + + 5, + duration: new Duration(milliseconds: 10), + curve: Curves.ease) + .whenComplete(() { + pos -= listStates[draggedListIndex!] + .boardListController + .position + .pixels; initialY ??= 0; // if(widget.boardViewController != null) { // initialY -= pos; // } isScrolling = false; - if(topItemY != null) { + if (topItemY != null) { topItemY = topItemY! + pos; } - if(bottomItemY != null) { + if (bottomItemY != null) { bottomItemY = bottomItemY! + pos; } - if(mounted){ + if (mounted) { setState(() {}); } }); } } - if (widget.lists![draggedListIndex!].items!.length > draggedItemIndex! + 1 && - dy! > bottomItemY! + listStates[draggedListIndex!].itemStates[draggedItemIndex! + 1].height / 2) { + if (widget.lists![draggedListIndex!].items!.length > + draggedItemIndex! + 1 && + dy! > + bottomItemY! + + listStates[draggedListIndex!] + .itemStates[draggedItemIndex! + 1] + .height / + 2) { //move down moveDown(); } @@ -532,31 +639,37 @@ class BoardViewState extends State with AutomaticKeepAliveClientMixin if (0 <= draggedListIndex! - 1 && dx! < leftListX! + 45) { //scroll left if (boardViewController != null && boardViewController.hasClients) { - boardViewController.animateTo(boardViewController.position.pixels - 5, - duration: new Duration(milliseconds: 10), curve: Curves.ease); - if(leftListX != null){ + boardViewController.animateTo( + boardViewController.position.pixels - 5, + duration: new Duration(milliseconds: 10), + curve: Curves.ease); + if (leftListX != null) { leftListX = leftListX! + 5; } - if(rightListX != null){ + if (rightListX != null) { rightListX = rightListX! + 5; } } } - if (widget.lists!.length > draggedListIndex! + 1 && dx! > rightListX! - 45) { + if (widget.lists!.length > draggedListIndex! + 1 && + dx! > rightListX! - 45) { //scroll right if (boardViewController != null && boardViewController.hasClients) { - boardViewController.animateTo(boardViewController.position.pixels + 5, - duration: new Duration(milliseconds: 10), curve: Curves.ease); - if(leftListX != null){ + boardViewController.animateTo( + boardViewController.position.pixels + 5, + duration: new Duration(milliseconds: 10), + curve: Curves.ease); + if (leftListX != null) { leftListX = leftListX! - 5; } - if(rightListX != null){ + if (rightListX != null) { rightListX = rightListX! - 5; } } } - if (widget.lists!.length > draggedListIndex! + 1 && dx! > rightListX!) { + if (widget.lists!.length > draggedListIndex! + 1 && + dx! > rightListX!) { //move right moveListRight(); } @@ -567,10 +680,11 @@ class BoardViewState extends State with AutomaticKeepAliveClientMixin } } if (widget.middleWidget != null) { - stackWidgets.add(Container(key:_middleWidgetKey,child:widget.middleWidget)); + stackWidgets + .add(Container(key: _middleWidgetKey, child: widget.middleWidget)); } WidgetsBinding.instance!.addPostFrameCallback((timeStamp) { - if(mounted){ + if (mounted) { setState(() {}); } }); @@ -595,7 +709,7 @@ class BoardViewState extends State with AutomaticKeepAliveClientMixin } dx = opm.position.dx; dy = opm.position.dy; - if(mounted) { + if (mounted) { setState(() {}); } } @@ -606,7 +720,7 @@ class BoardViewState extends State with AutomaticKeepAliveClientMixin offsetX = pos.dx; offsetY = pos.dy; pointer = opd; - if(mounted) { + if (mounted) { setState(() {}); } }, @@ -617,19 +731,23 @@ class BoardViewState extends State with AutomaticKeepAliveClientMixin int? startDraggedItemIndex = startItemIndex; int? startDraggedListIndex = startListIndex; - if(_isInWidget && widget.onDropItemInMiddleWidget != null){ + if (_isInWidget && widget.onDropItemInMiddleWidget != null) { onDropItem!(startDraggedListIndex, startDraggedItemIndex); - widget.onDropItemInMiddleWidget!(startDraggedListIndex, startDraggedItemIndex,opu.position.dx/MediaQuery.of(context).size.width); - }else{ + widget.onDropItemInMiddleWidget!( + startDraggedListIndex, + startDraggedItemIndex, + opu.position.dx / MediaQuery.of(context).size.width); + } else { onDropItem!(tempDraggedListIndex, tempDraggedItemIndex); } } if (onDropList != null) { int? tempDraggedListIndex = draggedListIndex; - if(_isInWidget && widget.onDropItemInMiddleWidget != null){ + if (_isInWidget && widget.onDropItemInMiddleWidget != null) { onDropList!(tempDraggedListIndex); - widget.onDropItemInMiddleWidget!(tempDraggedListIndex,null,opu.position.dx/MediaQuery.of(context).size.width); - }else{ + widget.onDropItemInMiddleWidget!(tempDraggedListIndex, null, + opu.position.dx / MediaQuery.of(context).size.width); + } else { onDropList!(tempDraggedListIndex); } } @@ -654,7 +772,7 @@ class BoardViewState extends State with AutomaticKeepAliveClientMixin bottomItemY = null; startListIndex = null; startItemIndex = null; - if(mounted) { + if (mounted) { setState(() {}); } }, @@ -667,17 +785,21 @@ class BoardViewState extends State with AutomaticKeepAliveClientMixin if (pointer != null) { dx = pointer.position.dx; dy = pointer.position.dy; - if(mounted) { + if (mounted) { setState(() {}); } } } } -class ScrollbarStyle{ +class ScrollbarStyle { double hoverThickness; double thickness; Radius radius; Color color; - ScrollbarStyle({this.radius = const Radius.circular(10),this.hoverThickness = 10,this.thickness = 10,this.color = Colors.black}); + ScrollbarStyle( + {this.radius = const Radius.circular(10), + this.hoverThickness = 10, + this.thickness = 10, + this.color = Colors.black}); } diff --git a/demos/supabase-trello/lib/widgets/thirdparty/boardview_controller.dart b/demos/supabase-trello/lib/widgets/thirdparty/boardview_controller.dart index 74c5af04..72457e11 100644 --- a/demos/supabase-trello/lib/widgets/thirdparty/boardview_controller.dart +++ b/demos/supabase-trello/lib/widgets/thirdparty/boardview_controller.dart @@ -2,17 +2,17 @@ import 'package:flutter/animation.dart'; import 'boardview.dart'; -class BoardViewController{ - +class BoardViewController { BoardViewController(); late BoardViewState state; - Future animateTo(int index,{Duration? duration,Curve? curve})async{ + Future animateTo(int index, {Duration? duration, Curve? curve}) async { double offset = index * state.widget.width; - if (state.boardViewController != null && state.boardViewController.hasClients) { - await state.boardViewController.animateTo( - offset, duration: duration!, curve: curve!); + if (state.boardViewController != null && + state.boardViewController.hasClients) { + await state.boardViewController + .animateTo(offset, duration: duration!, curve: curve!); } } -} \ No newline at end of file +} From ed02337329e4583bdd8c195354e72078cee8f151 Mon Sep 17 00:00:00 2001 From: DominicGBauer Date: Thu, 9 Jan 2025 13:55:27 +0200 Subject: [PATCH 03/10] fix: linting --- .../features/board/presentation/index.dart | 6 +- .../carddetails/presentation/index.dart | 6 +- .../editlabels/presentation/index.dart | 2 +- .../lib/features/emptywidget/index.dart | 34 +- .../lib/features/home/presentation/index.dart | 16 +- demos/supabase-trello/lib/main.dart | 6 +- .../lib/protocol/data_client.dart | 300 +++++++++++------- .../lib/utils/data_generator.dart | 6 +- demos/supabase-trello/lib/utils/service.dart | 5 +- .../lib/widgets/thirdparty/board_item.dart | 27 +- .../lib/widgets/thirdparty/board_list.dart | 18 +- .../lib/widgets/thirdparty/boardview.dart | 265 ++++++++-------- .../thirdparty/boardview_controller.dart | 3 +- .../lib/widgets/thirdparty/vs_scrollbar.dart | 65 ++-- 14 files changed, 404 insertions(+), 355 deletions(-) diff --git a/demos/supabase-trello/lib/features/board/presentation/index.dart b/demos/supabase-trello/lib/features/board/presentation/index.dart index b71b38a8..f1092bda 100644 --- a/demos/supabase-trello/lib/features/board/presentation/index.dart +++ b/demos/supabase-trello/lib/features/board/presentation/index.dart @@ -1,5 +1,3 @@ -import 'dart:ffi'; - import 'package:flutter/material.dart'; import 'package:status_alert/status_alert.dart'; import 'package:trelloappclone_flutter/features/carddetails/domain/card_detail_arguments.dart'; @@ -48,6 +46,7 @@ class _BoardScreenState extends State with Service { trello.setSelectedBoard(args.board); trello.setSelectedWorkspace(args.workspace); + // ignore: deprecated_member_use return WillPopScope( onWillPop: () async { Navigator.pushNamed(context, "/home"); @@ -239,7 +238,7 @@ class _BoardScreenState extends State with Service { BoardItem( onTapItem: (listIndex, itemIndex, state) { setState(() { - selectedList = listIndex!; + selectedList = listIndex; selectedCard = index; showCard = true; showtheCard[index] = true; @@ -423,6 +422,7 @@ class _BoardScreenState extends State with Service { return items; } + // ignore: non_constant_identifier_names List loadBoardView(List Listboards) { List data = generateBoardListObject(Listboards); lists = []; diff --git a/demos/supabase-trello/lib/features/carddetails/presentation/index.dart b/demos/supabase-trello/lib/features/carddetails/presentation/index.dart index 4249b071..ef820c40 100644 --- a/demos/supabase-trello/lib/features/carddetails/presentation/index.dart +++ b/demos/supabase-trello/lib/features/carddetails/presentation/index.dart @@ -35,7 +35,7 @@ class _CardDetailsState extends State with Service { trello.setSelectedCard(args.crd); descriptionController.text = args.crd.description ?? " "; - nameController.text = args.crd.name ?? " "; + nameController.text = args.crd.name; return Scaffold( appBar: (showChecklist || addCardDescription || editCardName) @@ -109,8 +109,8 @@ class _CardDetailsState extends State with Service { itemBuilder: (context) { return [ PopupMenuItem( - onTap: () => WidgetsBinding?.instance - ?.addPostFrameCallback((_) { + onTap: () => + WidgetsBinding.instance.addPostFrameCallback((_) { showDialog( context: context, builder: (BuildContext context) => AlertDialog( diff --git a/demos/supabase-trello/lib/features/editlabels/presentation/index.dart b/demos/supabase-trello/lib/features/editlabels/presentation/index.dart index caa1fa9e..df6cec5a 100644 --- a/demos/supabase-trello/lib/features/editlabels/presentation/index.dart +++ b/demos/supabase-trello/lib/features/editlabels/presentation/index.dart @@ -6,7 +6,7 @@ import '../../../utils/service.dart'; class EditLabels extends StatefulWidget { final String cardId; - const EditLabels({Key? key, required this.cardId}) : super(key: key); + const EditLabels({super.key, required this.cardId}); @override State createState() => _EditLabelsState(); diff --git a/demos/supabase-trello/lib/features/emptywidget/index.dart b/demos/supabase-trello/lib/features/emptywidget/index.dart index bb7739ad..3bda2c34 100644 --- a/demos/supabase-trello/lib/features/emptywidget/index.dart +++ b/demos/supabase-trello/lib/features/emptywidget/index.dart @@ -1,3 +1,5 @@ +// ignore_for_file: constant_identifier_names, camel_case_extensions + import 'dart:math'; import 'package:flutter/material.dart'; @@ -25,7 +27,8 @@ import 'package:flutter/material.dart'; /// {@end-tool} class EmptyWidget extends StatefulWidget { - EmptyWidget({ + const EmptyWidget({ + super.key, this.title, this.subTitle, this.image, @@ -139,7 +142,7 @@ class _EmptyListWidgetState extends State ); }, child: Padding( - padding: EdgeInsets.all(10), + padding: const EdgeInsets.all(10), child: Image.asset( isPackageImage ? _packageImage.encode()! : widget.image!, fit: BoxFit.contain, @@ -156,7 +159,7 @@ class _EmptyListWidgetState extends State context, EmptyWidgetUtility.fullWidth(context) * .95), height: EmptyWidgetUtility.getHeightDimention( context, EmptyWidgetUtility.fullWidth(context) * .95), - decoration: BoxDecoration(boxShadow: [ + decoration: const BoxDecoration(boxShadow: [ BoxShadow( offset: Offset(0, 0), color: Color(0xffe2e5ed), @@ -174,7 +177,7 @@ class _EmptyListWidgetState extends State return LayoutBuilder( builder: (BuildContext context, BoxConstraints constraints) { if (constraints.maxHeight > constraints.maxWidth) { - return Container( + return SizedBox( height: constraints.maxWidth, width: constraints.maxWidth, child: child, @@ -191,13 +194,13 @@ class _EmptyListWidgetState extends State .typography .dense .headlineSmall! - .copyWith(color: Color(0xff9da9c7)); + .copyWith(color: const Color(0xff9da9c7)); _subtitleTextStyle = widget.subtitleTextStyle ?? Theme.of(context) .typography .dense .bodyMedium! - .copyWith(color: Color(0xffabb8d6)); + .copyWith(color: const Color(0xffabb8d6)); _packageImage = widget.packageImage; bool anyImageProvided = widget.image == null && _packageImage == null; @@ -212,8 +215,8 @@ class _EmptyListWidgetState extends State children: [ if (!widget.hideBackgroundAnimation!) RotationTransition( - child: _imageBackground(), turns: _backgroundController, + child: _imageBackground(), ), LayoutBuilder( builder: (BuildContext context, BoxConstraints constraints) { @@ -221,18 +224,18 @@ class _EmptyListWidgetState extends State height: constraints.maxWidth, width: constraints.maxWidth - 30, alignment: Alignment.center, - padding: EdgeInsets.all(10), + padding: const EdgeInsets.all(10), child: Column( mainAxisAlignment: MainAxisAlignment.center, mainAxisSize: MainAxisSize.min, children: [ anyImageProvided - ? SizedBox() + ? const SizedBox() : Expanded( flex: 1, child: Container(), ), - anyImageProvided ? SizedBox() : _imageWidget(), + anyImageProvided ? const SizedBox() : _imageWidget(), Column( children: [ CustomText( @@ -242,7 +245,7 @@ class _EmptyListWidgetState extends State overflow: TextOverflow.clip, textAlign: TextAlign.center, ), - SizedBox( + const SizedBox( height: 10, ), CustomText( @@ -254,7 +257,7 @@ class _EmptyListWidgetState extends State ], ), anyImageProvided - ? SizedBox() + ? const SizedBox() : Expanded( flex: 1, child: Container(), @@ -329,14 +332,13 @@ class EmptyWidgetUtility { class CustomText extends StatefulWidget { const CustomText( - {Key? key, + {super.key, this.msg, this.style, this.textAlign, this.overflow, this.context, - this.softwrap}) - : super(key: key); + this.softwrap}); final BuildContext? context; final String? msg; @@ -345,6 +347,8 @@ class CustomText extends StatefulWidget { final TextStyle? style; final TextAlign? textAlign; + @override + // ignore: library_private_types_in_public_api _CustomTextState createState() => _CustomTextState(); } diff --git a/demos/supabase-trello/lib/features/home/presentation/index.dart b/demos/supabase-trello/lib/features/home/presentation/index.dart index ab6f6135..ec0287a7 100644 --- a/demos/supabase-trello/lib/features/home/presentation/index.dart +++ b/demos/supabase-trello/lib/features/home/presentation/index.dart @@ -3,11 +3,9 @@ import 'dart:async'; import 'package:flutter/material.dart'; import 'package:flutter_expandable_fab/flutter_expandable_fab.dart'; import 'package:logging/logging.dart'; -import 'package:powersync/powersync.dart' as PowerSync; +import 'package:powersync/powersync.dart' as power_sync; import 'package:trelloappclone_flutter/features/emptywidget/index.dart'; import 'package:trelloappclone_flutter/main.dart'; -import 'package:trelloappclone_flutter/models/board.dart'; -import 'package:trelloappclone_flutter/models/workspace.dart'; import 'package:trelloappclone_flutter/features/board/domain/board_arguments.dart'; import 'package:trelloappclone_flutter/features/board/presentation/index.dart'; import 'package:trelloappclone_flutter/protocol/data_client.dart'; @@ -28,8 +26,8 @@ class Home extends StatefulWidget { } class _HomeState extends State with Service { - late PowerSync.SyncStatus _connectionState; - StreamSubscription? _syncStatusSubscription; + late power_sync.SyncStatus _connectionState; + StreamSubscription? _syncStatusSubscription; @override void initState() { @@ -93,20 +91,20 @@ class _HomeState extends State with Service { Column(children: buildWorkspacesAndBoards(children))); } } - return Center( + return const Center( child: Padding( - padding: const EdgeInsets.all(20.0), + padding: EdgeInsets.all(20.0), child: EmptyWidget( image: null, packageImage: PackageImage.Image_1, title: 'No Boards', subTitle: 'Create your first Trello board', - titleTextStyle: const TextStyle( + titleTextStyle: TextStyle( fontSize: 22, color: Color(0xff9da9c7), fontWeight: FontWeight.w500, ), - subtitleTextStyle: const TextStyle( + subtitleTextStyle: TextStyle( fontSize: 14, color: Color(0xffabb8d6), ), diff --git a/demos/supabase-trello/lib/main.dart b/demos/supabase-trello/lib/main.dart index c5534a4c..139e95fb 100644 --- a/demos/supabase-trello/lib/main.dart +++ b/demos/supabase-trello/lib/main.dart @@ -1,10 +1,10 @@ -import 'package:flutter/foundation.dart'; +// ignore_for_file: avoid_print + import 'package:flutter/material.dart'; import 'package:google_fonts/google_fonts.dart'; import 'package:provider/provider.dart'; import 'package:trelloappclone_flutter/features/generateworkspace/presentation/index.dart'; import 'package:trelloappclone_flutter/utils/trello_provider.dart'; -import 'package:trelloappclone_flutter/models/user.dart'; import 'package:trelloappclone_flutter/protocol/data_client.dart'; import 'package:logging/logging.dart'; @@ -71,7 +71,7 @@ void main() async { } class MyApp extends StatelessWidget { - const MyApp({Key? key}) : super(key: key); + const MyApp({super.key}); @override Widget build(BuildContext context) { diff --git a/demos/supabase-trello/lib/protocol/data_client.dart b/demos/supabase-trello/lib/protocol/data_client.dart index 47acf183..5afa61f1 100644 --- a/demos/supabase-trello/lib/protocol/data_client.dart +++ b/demos/supabase-trello/lib/protocol/data_client.dart @@ -1,3 +1,5 @@ +// ignore_for_file: library_private_types_in_public_api + library powersync_client; import 'package:powersync/powersync.dart'; @@ -21,45 +23,51 @@ class _Repository { } class _ActivityRepository extends _Repository { - _ActivityRepository(DataClient client) : super(client); + _ActivityRepository(super.client); Future createActivity(Activity activity) async { - final results = await client.getDBExecutor().execute('''INSERT INTO + final results = await client.getDBExecutor().execute( + '''INSERT INTO activity(id, workspaceId, boardId, userId, cardId, description, dateCreated) VALUES(?, ?, ?, ?, ?, ?, datetime()) - RETURNING *''', [ - activity.id, - activity.workspaceId, - activity.boardId, - activity.userId, - activity.cardId, - activity.description - ]); + RETURNING *''', + [ + activity.id, + activity.workspaceId, + activity.boardId, + activity.userId, + activity.cardId, + activity.description + ]); return results.isNotEmpty; } Future> getActivities(Cardlist cardlist) async { - final results = await client.getDBExecutor().execute(''' + final results = await client.getDBExecutor().execute( + ''' SELECT * FROM activity WHERE cardId = ? ORDER BY dateCreated DESC - ''', [cardlist.id]); + ''', + [cardlist.id]); return results.map((row) => Activity.fromRow(row)).toList(); } } class _AttachmentRepository extends _Repository { - _AttachmentRepository(DataClient client) : super(client); + _AttachmentRepository(super.client); Future addAttachment(Attachment attachment) async { - final results = await client.getDBExecutor().execute('''INSERT INTO + final results = await client.getDBExecutor().execute( + '''INSERT INTO attachment(id, workspaceId, userId, cardId, attachment) VALUES(?, ?, ?, ?, ?) - RETURNING *''', [ - attachment.id, - attachment.workspaceId, - attachment.userId, - attachment.cardId, - attachment.attachment - ]); + RETURNING *''', + [ + attachment.id, + attachment.workspaceId, + attachment.userId, + attachment.cardId, + attachment.attachment + ]); if (results.isEmpty) { throw Exception("Failed to add attachment"); } else { @@ -75,22 +83,26 @@ class _AttachmentRepository extends _Repository { } class _BoardRepository extends _Repository { - _BoardRepository(DataClient client) : super(client); + _BoardRepository(super.client); - String get insertQuery => ''' + String get insertQuery => + ''' INSERT INTO board(id, userId, workspaceId, name, description, visibility, background, starred, enableCover, watch, availableOffline, label, emailAddress, commenting, memberType, pinned, selfJoin, close) VALUES(?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12, ?13, ?14, ?15, ?16, ?17, ?18) '''; - String get updateQuery => ''' + String get updateQuery => + ''' UPDATE board set userId = ?1, workspaceId = ?2, name = ?3, description = ?4, visibility = ?5, background = ?6, starred = ?7, enableCover = ?8, watch = ?9, availableOffline = ?10, label = ?11, emailAddress = ?12, commenting = ?13, memberType = ?14, pinned = ?15, selfJoin = ?16, close = ?17 WHERE id = ?18 '''; Future createBoard(Board board) async { - final results = await client.getDBExecutor().execute(''' + final results = await client + .getDBExecutor() + .execute(''' $insertQuery RETURNING *''', [ board.id, board.userId, @@ -150,14 +162,18 @@ class _BoardRepository extends _Repository { } Future getWorkspaceForBoard(Board board) async { - final results = await client.getDBExecutor().execute(''' + final results = await client.getDBExecutor().execute( + ''' SELECT * FROM workspace WHERE id = ? - ''', [board.workspaceId]); + ''', + [board.workspaceId]); return results.map((row) => Workspace.fromRow(row)).firstOrNull; } Future> getAllBoards() async { - final results = await client.getDBExecutor().execute(''' + final results = await client + .getDBExecutor() + .execute(''' SELECT * FROM board '''); return results.map((row) => Board.fromRow(row)).toList(); @@ -165,9 +181,10 @@ class _BoardRepository extends _Repository { } class _CardlistRepository extends _Repository { - _CardlistRepository(DataClient client) : super(client); + _CardlistRepository(super.client); - String get insertQuery => ''' + String get insertQuery => + ''' INSERT INTO card(id, workspaceId, listId, userId, name, description, startDate, dueDate, attachment, archived, checklist, comments, rank) VALUES(?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12, ?13) @@ -197,7 +214,8 @@ class _CardlistRepository extends _Repository { } } - String get updateQuery => ''' + String get updateQuery => + ''' UPDATE card set listId = ?1, userId = ?2, name = ?3, description = ?4, startDate = ?5, dueDate = ?6, attachment = ?7, archived = ?8, checklist = ?9, comments = ?10, rank = ?11 WHERE id = ?12 @@ -229,17 +247,20 @@ class _CardlistRepository extends _Repository { } Future> getCardsforList(String listId) async { - final results = await client.getDBExecutor().execute(''' + final results = await client.getDBExecutor().execute( + ''' SELECT * FROM card WHERE listId = ? AND archived = 0 ORDER BY rank ASC - ''', [listId]); + ''', + [listId]); return results.map((row) => Cardlist.fromRow(row)).toList(); } } class _CheckListRepository extends _Repository { - _CheckListRepository(DataClient client) : super(client); + _CheckListRepository(super.client); - String get insertQuery => ''' + String get insertQuery => + ''' INSERT INTO checklist(id, workspaceId, cardId, name, status) VALUES(?1, ?2, ?3, ?4, ?5) @@ -261,7 +282,8 @@ class _CheckListRepository extends _Repository { } } - String get updateQuery => ''' + String get updateQuery => + ''' UPDATE checklist set cardId = ?1, name = ?2, status = ?3 WHERE id = ?4 @@ -285,16 +307,20 @@ class _CheckListRepository extends _Repository { } Future> getChecklists(Cardlist crd) async { - final results = await client.getDBExecutor().execute(''' + final results = await client.getDBExecutor().execute( + ''' SELECT * FROM checklist WHERE cardId = ? - ''', [crd.id]); + ''', + [crd.id]); return results.map((row) => Checklist.fromRow(row)).toList(); } Future deleteChecklist(Cardlist crd) async { - final results = await client.getDBExecutor().execute(''' + final results = await client.getDBExecutor().execute( + ''' SELECT COUNT(*) FROM checklist WHERE cardId = ? - ''', [crd.id]); + ''', + [crd.id]); await client .getDBExecutor() .execute('DELETE FROM checklist WHERE cardId = ?', [crd.id]); @@ -303,9 +329,10 @@ class _CheckListRepository extends _Repository { } class _CommentRepository extends _Repository { - _CommentRepository(DataClient client) : super(client); + _CommentRepository(super.client); - String get insertQuery => ''' + String get insertQuery => + ''' INSERT INTO comment(id, workspaceId, cardId, userId, description) VALUES(?1, ?2, ?3, ?4, ?5) @@ -327,7 +354,8 @@ class _CommentRepository extends _Repository { } } - String get updateQuery => ''' + String get updateQuery => + ''' UPDATE comment set cardId = ?1, userId = ?2, description = ?3 WHERE id = ?4 @@ -341,13 +369,15 @@ class _CommentRepository extends _Repository { } class _ListboardRepository extends _Repository { - _ListboardRepository(DataClient client) : super(client); + _ListboardRepository(super.client); Future> getListsByBoard({required String boardId}) async { //first we get the listboards - final results = await client.getDBExecutor().execute(''' + final results = await client.getDBExecutor().execute( + ''' SELECT * FROM listboard WHERE boardId = ? - ''', [boardId]); + ''', + [boardId]); List lists = results.map((row) => Listboard.fromRow(row)).toList(); @@ -367,9 +397,11 @@ class _ListboardRepository extends _Repository { Stream> watchListsByBoard({required String boardId}) { //first we get the listboards - return client.getDBExecutor().watch(''' + return client.getDBExecutor().watch( + ''' SELECT * FROM listboard WHERE boardId = ? ORDER BY listOrder ASC - ''', parameters: [boardId]).asyncMap((event) async { + ''', + parameters: [boardId]).asyncMap((event) async { List lists = event.map((row) => Listboard.fromRow(row)).toList(); @@ -388,7 +420,8 @@ class _ListboardRepository extends _Repository { }); } - String get insertQuery => ''' + String get insertQuery => + ''' INSERT INTO listboard(id, workspaceId, boardId, userId, name, archived, listOrder) VALUES(?1, ?2, ?3, ?4, ?5, ?6, ?7) @@ -412,7 +445,8 @@ class _ListboardRepository extends _Repository { } } - String get updateQuery => ''' + String get updateQuery => + ''' UPDATE listboard set listOrder = ?1 WHERE id = ?2 @@ -435,18 +469,22 @@ class _ListboardRepository extends _Repository { int numCards = cards.length; //we set each of the cards in the list to archived = true - sqlContext.executeBatch(''' + sqlContext.executeBatch( + ''' UPDATE card SET archived = 1 WHERE id = ? - ''', cards.map((card) => [card.id]).toList()); + ''', + cards.map((card) => [card.id]).toList()); //touch listboard to trigger update via stream listeners on Listboard - sqlContext.execute(''' + sqlContext.execute( + ''' UPDATE listboard SET archived = 0 WHERE id = ? - ''', [list.id]); + ''', + [list.id]); list.cards = []; return numCards; @@ -456,9 +494,10 @@ class _ListboardRepository extends _Repository { } class _MemberRepository extends _Repository { - _MemberRepository(DataClient client) : super(client); + _MemberRepository(super.client); - String get insertQuery => ''' + String get insertQuery => + ''' INSERT INTO member(id, workspaceId, userId, name, role) VALUES(?1, ?2, ?3, ?4, ?5) @@ -482,9 +521,11 @@ class _MemberRepository extends _Repository { Future> getMembersByWorkspace( {required String workspaceId}) async { - final results = await client.getDBExecutor().execute(''' + final results = await client.getDBExecutor().execute( + ''' SELECT * FROM member WHERE workspaceId = ? - ''', [workspaceId]); + ''', + [workspaceId]); return results.map((row) => Member.fromRow(row)).toList(); } @@ -514,9 +555,10 @@ class _MemberRepository extends _Repository { } class _UserRepository extends _Repository { - _UserRepository(DataClient client) : super(client); + _UserRepository(super.client); - String get insertQuery => ''' + String get insertQuery => + ''' INSERT INTO trellouser(id, name, email, password) VALUES(?1, ?2, ?3, ?4) @@ -536,30 +578,37 @@ class _UserRepository extends _Repository { /// We excpect only one record in the local trellouser table /// if somebody has logged in and not logged out again Future getUser() async { - final results = await client.getDBExecutor().execute(''' + final results = await client + .getDBExecutor() + .execute(''' SELECT * FROM trellouser'''); return results.map((row) => TrelloUser.fromRow(row)).firstOrNull; } Future getUserById({required String userId}) async { - final results = await client.getDBExecutor().execute(''' + final results = await client.getDBExecutor().execute( + ''' SELECT * FROM trellouser WHERE id = ? - ''', [userId]); + ''', + [userId]); return results.map((row) => TrelloUser.fromRow(row)).firstOrNull; } Future checkUserExists(String email) async { - final results = await client.getDBExecutor().execute(''' + final results = await client.getDBExecutor().execute( + ''' SELECT * FROM trellouser WHERE email = ? - ''', [email]); + ''', + [email]); return results.map((row) => TrelloUser.fromRow(row)).firstOrNull; } } class _WorkspaceRepository extends _Repository { - _WorkspaceRepository(DataClient client) : super(client); + _WorkspaceRepository(super.client); - String get insertQuery => ''' + String get insertQuery => + ''' INSERT INTO workspace(id, userId, name, description, visibility) VALUES(?1, ?2, ?3, ?4, ?5) @@ -579,9 +628,11 @@ class _WorkspaceRepository extends _Repository { Future> getWorkspacesByUser({required String userId}) async { //First we get the workspaces - final results = await client.getDBExecutor().execute(''' + final results = await client.getDBExecutor().execute( + ''' SELECT * FROM workspace WHERE userId = ? - ''', [userId]); + ''', + [userId]); List workspaces = results.map((row) => Workspace.fromRow(row)).toList(); @@ -616,9 +667,11 @@ class _WorkspaceRepository extends _Repository { } Future getWorkspaceById({required String workspaceId}) async { - final results = await client.getDBExecutor().execute(''' + final results = await client.getDBExecutor().execute( + ''' SELECT * FROM workspace WHERE id = ? - ''', [workspaceId]); + ''', + [workspaceId]); Workspace workspace = Workspace.fromRow(results.first); List members = await client.member.getMembersByWorkspace(workspaceId: workspaceId); @@ -628,9 +681,11 @@ class _WorkspaceRepository extends _Repository { Future> getBoardsByWorkspace( {required String workspaceId}) async { - final results = await client.getDBExecutor().execute(''' + final results = await client.getDBExecutor().execute( + ''' SELECT * FROM board WHERE workspaceId = ? - ''', [workspaceId]); + ''', + [workspaceId]); List boards = results.map((row) => Board.fromRow(row)).toList(); @@ -643,9 +698,11 @@ class _WorkspaceRepository extends _Repository { } Stream> watchBoardsByWorkspace({required String workspaceId}) { - return client.getDBExecutor().watch(''' + return client.getDBExecutor().watch( + ''' SELECT * FROM board WHERE workspaceId = ? - ''', parameters: [workspaceId]).asyncMap((event) async { + ''', + parameters: [workspaceId]).asyncMap((event) async { List boards = event.map((row) => Board.fromRow(row)).toList(); for (Board board in boards) { @@ -658,17 +715,19 @@ class _WorkspaceRepository extends _Repository { } Future updateWorkspace(Workspace workspace) async { - await client.getDBExecutor().execute(''' + await client.getDBExecutor().execute( + ''' UPDATE workspace set userId = ?1, name = ?2, description = ?3, visibility = ?4 WHERE id = ?5 - ''', [ - workspace.userId, - workspace.name, - workspace.description, - workspace.visibility, - workspace.id - ]); + ''', + [ + workspace.userId, + workspace.name, + workspace.description, + workspace.visibility, + workspace.id + ]); return true; } @@ -681,19 +740,21 @@ class _WorkspaceRepository extends _Repository { } class _BoardLabelRepository extends _Repository { - _BoardLabelRepository(DataClient client) : super(client); + _BoardLabelRepository(super.client); Future createBoardLabel(BoardLabel boardLabel) async { - final results = await client.getDBExecutor().execute('''INSERT INTO + final results = await client.getDBExecutor().execute( + '''INSERT INTO board_label(id, boardId, workspaceId, title, color, dateCreated) VALUES(?, ?, ?, ?, ?, datetime()) - RETURNING *''', [ - boardLabel.id, - boardLabel.boardId, - boardLabel.workspaceId, - boardLabel.title, - boardLabel.color - ]); + RETURNING *''', + [ + boardLabel.id, + boardLabel.boardId, + boardLabel.workspaceId, + boardLabel.title, + boardLabel.color + ]); if (results.isEmpty) { throw Exception("Failed to add BoardLabel"); } else { @@ -702,36 +763,42 @@ class _BoardLabelRepository extends _Repository { } Future updateBoardLabel(BoardLabel boardLabel) async { - await client.getDBExecutor().execute(''' + await client.getDBExecutor().execute( + ''' UPDATE board_label set title = ?1 WHERE id = ?2 - ''', [boardLabel.title, boardLabel.id]); + ''', + [boardLabel.title, boardLabel.id]); return true; } Future> getBoardLabels(Board board) async { - final results = await client.getDBExecutor().execute(''' + final results = await client.getDBExecutor().execute( + ''' SELECT * FROM board_label WHERE boardId = ? ORDER BY dateCreated DESC - ''', [board.id]); + ''', + [board.id]); return results.map((row) => BoardLabel.fromRow(row)).toList(); } } class _CardLabelRepository extends _Repository { - _CardLabelRepository(DataClient client) : super(client); + _CardLabelRepository(super.client); Future createCardLabel(CardLabel cardLabel) async { - final results = await client.getDBExecutor().execute('''INSERT INTO + final results = await client.getDBExecutor().execute( + '''INSERT INTO card_label(id, cardId, boardId, workspaceId, boardLabelId, dateCreated) VALUES(?, ?, ?, ?, ?, datetime()) - RETURNING *''', [ - cardLabel.id, - cardLabel.cardId, - cardLabel.boardId, - cardLabel.workspaceId, - cardLabel.boardLabelId, - ]); + RETURNING *''', + [ + cardLabel.id, + cardLabel.cardId, + cardLabel.boardId, + cardLabel.workspaceId, + cardLabel.boardLabelId, + ]); if (results.isEmpty) { throw Exception("Failed to add CardLabel"); } else { @@ -746,9 +813,11 @@ class _CardLabelRepository extends _Repository { } Future> getCardLabels(Cardlist card) async { - final results = await client.getDBExecutor().execute(''' + final results = await client.getDBExecutor().execute( + ''' SELECT * FROM card_label WHERE cardId = ? ORDER BY dateCreated DESC - ''', [card.id]); + ''', + [card.id]); return results.map((row) => CardLabel.fromRow(row)).toList(); } } @@ -805,8 +874,9 @@ class DataClient { String? userId = _powerSyncClient.getUserId(); if (userId != null) { return user.getUserById(userId: userId); - } else + } else { return null; + } } Future logOut() async { @@ -817,13 +887,11 @@ class DataClient { String userId = await _powerSyncClient.loginWithEmail(email, password); TrelloUser? storedUser = await user.getUserById(userId: userId); - if (storedUser == null) { - storedUser = await user.createUser(TrelloUser( - id: userId, - name: email.split('@')[0], - email: email, - password: password)); - } + storedUser ??= await user.createUser(TrelloUser( + id: userId, + name: email.split('@')[0], + email: email, + password: password)); return storedUser; } @@ -831,7 +899,7 @@ class DataClient { String name, String email, String password) async { TrelloUser? storedUser = await user.checkUserExists(email); if (storedUser != null) { - throw new Exception('User for email already exists. Use Login instead.'); + throw Exception('User for email already exists. Use Login instead.'); } return _powerSyncClient.signupWithEmail(name, email, password); } diff --git a/demos/supabase-trello/lib/utils/data_generator.dart b/demos/supabase-trello/lib/utils/data_generator.dart index 9c821fbd..5a7c6f37 100644 --- a/demos/supabase-trello/lib/utils/data_generator.dart +++ b/demos/supabase-trello/lib/utils/data_generator.dart @@ -1,6 +1,7 @@ +// ignore_for_file: use_build_context_synchronously + import 'dart:math'; -import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:random_name_generator/random_name_generator.dart'; import 'package:status_alert/status_alert.dart'; @@ -114,10 +115,7 @@ class DataGenerator with Service { card: newCard.id, description: '${randomNames.name()} updated this card'); } - ; } - ; } - ; } } diff --git a/demos/supabase-trello/lib/utils/service.dart b/demos/supabase-trello/lib/utils/service.dart index d9727abc..c32fc85f 100644 --- a/demos/supabase-trello/lib/utils/service.dart +++ b/demos/supabase-trello/lib/utils/service.dart @@ -1,3 +1,5 @@ +// ignore_for_file: use_build_context_synchronously + import 'dart:convert'; import 'dart:developer'; @@ -20,11 +22,12 @@ import 'package:trelloappclone_flutter/models/board_label.dart'; import 'package:trelloappclone_flutter/models/card_label.dart'; import 'package:trelloappclone_flutter/models/attachment.dart'; +// ignore: depend_on_referenced_packages import 'package:uuid/uuid.dart'; import '../main.dart'; -var uuid = Uuid(); +var uuid = const Uuid(); mixin Service { randomUuid() { diff --git a/demos/supabase-trello/lib/widgets/thirdparty/board_item.dart b/demos/supabase-trello/lib/widgets/thirdparty/board_item.dart index da106d62..4b660d33 100644 --- a/demos/supabase-trello/lib/widgets/thirdparty/board_item.dart +++ b/demos/supabase-trello/lib/widgets/thirdparty/board_item.dart @@ -3,13 +3,14 @@ import 'package:flutter/widgets.dart'; import 'board_list.dart'; -typedef void OnDropItem(int? listIndex, int? itemIndex, int? oldListIndex, - int? oldItemIndex, BoardItemState state); -typedef void OnTapItem(int listIndex, int itemIndex, BoardItemState state); -typedef void OnStartDragItem( +typedef OnDropItem = void Function(int? listIndex, int? itemIndex, + int? oldListIndex, int? oldItemIndex, BoardItemState state); +typedef OnTapItem = void Function( + int listIndex, int itemIndex, BoardItemState state); +typedef OnStartDragItem = void Function( int? listIndex, int? itemIndex, BoardItemState state); -typedef void OnDragItem(int oldListIndex, int oldItemIndex, int newListIndex, - int newItemIndex, BoardItemState state); +typedef OnDragItem = void Function(int oldListIndex, int oldItemIndex, + int newListIndex, int newItemIndex, BoardItemState state); class BoardItem extends StatefulWidget { final BoardListState? boardList; @@ -22,7 +23,7 @@ class BoardItem extends StatefulWidget { final bool draggable; const BoardItem( - {Key? key, + {super.key, this.boardList, this.item, this.index, @@ -30,8 +31,7 @@ class BoardItem extends StatefulWidget { this.onTapItem, this.onStartDragItem, this.draggable = true, - this.onDragItem}) - : super(key: key); + this.onDragItem}); @override State createState() { @@ -91,15 +91,14 @@ class BoardItemState extends State } void afterFirstLayout(BuildContext context) { - try { - height = context.size!.height; - width = context.size!.width; - } catch (e) {} + height = context.size!.height; + width = context.size!.width; } @override Widget build(BuildContext context) { - WidgetsBinding.instance! + super.build(context); + WidgetsBinding.instance .addPostFrameCallback((_) => afterFirstLayout(context)); if (widget.boardList!.itemStates.length > widget.index!) { widget.boardList!.itemStates.removeAt(widget.index!); diff --git a/demos/supabase-trello/lib/widgets/thirdparty/board_list.dart b/demos/supabase-trello/lib/widgets/thirdparty/board_list.dart index 7e9c1d66..65a04692 100644 --- a/demos/supabase-trello/lib/widgets/thirdparty/board_list.dart +++ b/demos/supabase-trello/lib/widgets/thirdparty/board_list.dart @@ -3,9 +3,9 @@ import 'boardview.dart'; import 'package:flutter/material.dart'; import 'package:flutter/widgets.dart'; -typedef void OnDropList(int? listIndex, int? oldListIndex); -typedef void OnTapList(int? listIndex); -typedef void OnStartDragList(int? listIndex); +typedef OnDropList = void Function(int? listIndex, int? oldListIndex); +typedef OnTapList = void Function(int? listIndex); +typedef OnStartDragList = void Function(int? listIndex); class BoardList extends StatefulWidget { final List? header; @@ -20,7 +20,7 @@ class BoardList extends StatefulWidget { final bool draggable; const BoardList({ - Key? key, + super.key, this.header, this.items, this.footer, @@ -32,7 +32,7 @@ class BoardList extends StatefulWidget { this.onDropList, this.onTapList, this.onStartDragList, - }) : super(key: key); + }); final int? index; @@ -45,7 +45,7 @@ class BoardList extends StatefulWidget { class BoardListState extends State with AutomaticKeepAliveClientMixin { List itemStates = []; - ScrollController boardListController = new ScrollController(); + ScrollController boardListController = ScrollController(); void onDropList(int? listIndex) { if (widget.onDropList != null) { @@ -80,10 +80,12 @@ class BoardListState extends State @override Widget build(BuildContext context) { + super.build(context); List listWidgets = []; if (widget.header != null) { - Color? headerBackgroundColor = Color.fromARGB(255, 255, 255, 255); if (widget.headerBackgroundColor != null) { + // ignore: unused_local_variable + Color? headerBackgroundColor = const Color.fromARGB(255, 255, 255, 255); headerBackgroundColor = widget.headerBackgroundColor; } listWidgets.add(GestureDetector( @@ -184,7 +186,7 @@ class BoardListState extends State child: Column( mainAxisSize: MainAxisSize.min, mainAxisAlignment: MainAxisAlignment.start, - children: listWidgets as List, + children: listWidgets, )); } } diff --git a/demos/supabase-trello/lib/widgets/thirdparty/boardview.dart b/demos/supabase-trello/lib/widgets/thirdparty/boardview.dart index 73db6ef3..94d90ad5 100644 --- a/demos/supabase-trello/lib/widgets/thirdparty/boardview.dart +++ b/demos/supabase-trello/lib/widgets/thirdparty/boardview.dart @@ -3,10 +3,10 @@ library boardview; import 'boardview_controller.dart'; import 'vs_scrollbar.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/widgets.dart'; import 'dart:core'; import 'board_list.dart'; +// ignore: must_be_immutable class BoardView extends StatefulWidget { final List? lists; final double width; @@ -21,7 +21,7 @@ class BoardView extends StatefulWidget { Function(bool)? itemInMiddleWidget; OnDropBottomWidget? onDropItemInMiddleWidget; BoardView( - {Key? key, + {super.key, this.itemInMiddleWidget, this.scrollbar, this.scrollbarStyle, @@ -32,8 +32,7 @@ class BoardView extends StatefulWidget { this.lists, this.width = 280, this.middleWidget, - this.bottomPadding}) - : super(key: key); + this.bottomPadding}); @override State createState() { @@ -41,10 +40,10 @@ class BoardView extends StatefulWidget { } } -typedef void OnDropBottomWidget( +typedef OnDropBottomWidget = void Function( int? listIndex, int? itemIndex, double percentX); -typedef void OnDropItem(int? listIndex, int? itemIndex); -typedef void OnDropList(int? listIndex); +typedef OnDropItem = void Function(int? listIndex, int? itemIndex); +typedef OnDropList = void Function(int? listIndex); class BoardViewState extends State with AutomaticKeepAliveClientMixin { @@ -71,7 +70,7 @@ class BoardViewState extends State bool canDrag = true; - ScrollController boardViewController = new ScrollController(); + ScrollController boardViewController = ScrollController(); List listStates = []; @@ -82,8 +81,9 @@ class BoardViewState extends State bool _isInWidget = false; - GlobalKey _middleWidgetKey = GlobalKey(); + final GlobalKey _middleWidgetKey = GlobalKey(); + // ignore: prefer_typing_uninitialized_variables var pointer; @override @@ -166,18 +166,18 @@ class BoardViewState extends State widget.lists!.insert(draggedListIndex!, list); listStates.insert(draggedListIndex!, listState); canDrag = false; - if (boardViewController != null && boardViewController.hasClients) { + if (boardViewController.hasClients) { int? tempListIndex = draggedListIndex; boardViewController .animateTo(draggedListIndex! * widget.width, - duration: new Duration(milliseconds: 400), curve: Curves.ease) + duration: const Duration(milliseconds: 400), curve: Curves.ease) .whenComplete(() { RenderBox object = listStates[tempListIndex!].context.findRenderObject() as RenderBox; Offset pos = object.localToGlobal(Offset.zero); leftListX = pos.dx; rightListX = pos.dx + object.size.width; - Future.delayed(new Duration(milliseconds: widget.dragDelay), () { + Future.delayed(Duration(milliseconds: widget.dragDelay), () { canDrag = true; }); }); @@ -201,8 +201,7 @@ class BoardViewState extends State double closestValue = 10000; draggedItemIndex = 0; for (int i = 0; i < listStates[draggedListIndex!].itemStates.length; i++) { - if (listStates[draggedListIndex!].itemStates[i].mounted && - listStates[draggedListIndex!].itemStates[i].context != null) { + if (listStates[draggedListIndex!].itemStates[i].mounted) { RenderBox box = listStates[draggedListIndex!] .itemStates[i] .context @@ -224,12 +223,12 @@ class BoardViewState extends State if (listStates[draggedListIndex!].mounted) { listStates[draggedListIndex!].setState(() {}); } - if (boardViewController != null && boardViewController.hasClients) { + if (boardViewController.hasClients) { int? tempListIndex = draggedListIndex; int? tempItemIndex = draggedItemIndex; boardViewController .animateTo(draggedListIndex! * widget.width, - duration: new Duration(milliseconds: 400), curve: Curves.ease) + duration: const Duration(milliseconds: 400), curve: Curves.ease) .whenComplete(() { RenderBox object = listStates[tempListIndex!].context.findRenderObject() as RenderBox; @@ -243,7 +242,7 @@ class BoardViewState extends State Offset itemPos = box.localToGlobal(Offset.zero); topItemY = itemPos.dy; bottomItemY = itemPos.dy + box.size.height; - Future.delayed(new Duration(milliseconds: widget.dragDelay), () { + Future.delayed(Duration(milliseconds: widget.dragDelay), () { canDrag = true; }); }); @@ -264,11 +263,11 @@ class BoardViewState extends State widget.lists!.insert(draggedListIndex!, list); listStates.insert(draggedListIndex!, listState); canDrag = false; - if (boardViewController != null && boardViewController.hasClients) { + if (boardViewController.hasClients) { int? tempListIndex = draggedListIndex; boardViewController .animateTo(draggedListIndex! * widget.width, - duration: new Duration(milliseconds: widget.dragDelay), + duration: Duration(milliseconds: widget.dragDelay), curve: Curves.ease) .whenComplete(() { RenderBox object = @@ -276,7 +275,7 @@ class BoardViewState extends State Offset pos = object.localToGlobal(Offset.zero); leftListX = pos.dx; rightListX = pos.dx + object.size.width; - Future.delayed(new Duration(milliseconds: widget.dragDelay), () { + Future.delayed(Duration(milliseconds: widget.dragDelay), () { canDrag = true; }); }); @@ -300,8 +299,7 @@ class BoardViewState extends State double closestValue = 10000; draggedItemIndex = 0; for (int i = 0; i < listStates[draggedListIndex!].itemStates.length; i++) { - if (listStates[draggedListIndex!].itemStates[i].mounted && - listStates[draggedListIndex!].itemStates[i].context != null) { + if (listStates[draggedListIndex!].itemStates[i].mounted) { RenderBox box = listStates[draggedListIndex!] .itemStates[i] .context @@ -323,12 +321,12 @@ class BoardViewState extends State if (listStates[draggedListIndex!].mounted) { listStates[draggedListIndex!].setState(() {}); } - if (boardViewController != null && boardViewController.hasClients) { + if (boardViewController.hasClients) { int? tempListIndex = draggedListIndex; int? tempItemIndex = draggedItemIndex; boardViewController .animateTo(draggedListIndex! * widget.width, - duration: new Duration(milliseconds: 400), curve: Curves.ease) + duration: const Duration(milliseconds: 400), curve: Curves.ease) .whenComplete(() { RenderBox object = listStates[tempListIndex!].context.findRenderObject() as RenderBox; @@ -342,7 +340,7 @@ class BoardViewState extends State Offset itemPos = box.localToGlobal(Offset.zero); topItemY = itemPos.dy; bottomItemY = itemPos.dy + box.size.height; - Future.delayed(new Duration(milliseconds: widget.dragDelay), () { + Future.delayed(Duration(milliseconds: widget.dragDelay), () { canDrag = true; }); }); @@ -356,14 +354,11 @@ class BoardViewState extends State @override Widget build(BuildContext context) { - // print("dy:${dy}"); - // print("topListY:${topListY}"); - // print("bottomListY:${bottomListY}"); + super.build(context); if (boardViewController.hasClients) { - WidgetsBinding.instance!.addPostFrameCallback((Duration duration) { - try { - boardViewController.position.didUpdateScrollPositionBy(0); - } catch (e) {} + WidgetsBinding.instance.addPostFrameCallback((Duration duration) { + boardViewController.position.didUpdateScrollPositionBy(0); + // ignore: no_leading_underscores_for_local_identifiers bool _shown = boardViewController.position.maxScrollExtent != 0; if (_shown != shown) { setState(() { @@ -373,14 +368,13 @@ class BoardViewState extends State }); } Widget listWidget = ListView.builder( - physics: ClampingScrollPhysics(), + physics: const ClampingScrollPhysics(), itemCount: widget.lists!.length, scrollDirection: Axis.horizontal, controller: boardViewController, itemBuilder: (BuildContext context, int index) { // if index does not exist on lists if (widget.lists!.length <= index) { - print('Returned empty container'); return Container(); } @@ -437,9 +431,9 @@ class BoardViewState extends State controller: boardViewController, showTrackOnHover: true, // default false isAlwaysShown: shown && widget.lists!.length > 1, // default false - scrollbarFadeDuration: Duration( + scrollbarFadeDuration: const Duration( milliseconds: 500), // default : Duration(milliseconds: 300) - scrollbarTimeToFade: Duration( + scrollbarTimeToFade: const Duration( milliseconds: 800), // default : Duration(milliseconds: 600) style: widget.scrollbarStyle != null ? VsScrollbarStyle( @@ -447,7 +441,7 @@ class BoardViewState extends State radius: widget.scrollbarStyle!.radius, thickness: widget.scrollbarStyle!.thickness, color: widget.scrollbarStyle!.color) - : VsScrollbarStyle(), + : const VsScrollbarStyle(), child: listWidget); } List stackWidgets = [listWidget]; @@ -467,8 +461,7 @@ class BoardViewState extends State offsetY != null && dx != null && dy != null && - height != null && - widget.width != null) { + height != null) { if (canDrag && dxInit != null && dyInit != null && !isInBottomWidget) { if (draggedItemIndex != null && draggedItem != null && @@ -477,10 +470,10 @@ class BoardViewState extends State //dragging item if (0 <= draggedListIndex! - 1 && dx! < leftListX! + 45) { //scroll left - if (boardViewController != null && boardViewController.hasClients) { + if (boardViewController.hasClients) { boardViewController.animateTo( boardViewController.position.pixels - 5, - duration: new Duration(milliseconds: 10), + duration: const Duration(milliseconds: 10), curve: Curves.ease); if (listStates[draggedListIndex!].mounted) { RenderBox object = listStates[draggedListIndex!] @@ -495,10 +488,10 @@ class BoardViewState extends State if (widget.lists!.length > draggedListIndex! + 1 && dx! > rightListX! - 45) { //scroll right - if (boardViewController != null && boardViewController.hasClients) { + if (boardViewController.hasClients) { boardViewController.animateTo( boardViewController.position.pixels + 5, - duration: new Duration(milliseconds: 10), + duration: const Duration(milliseconds: 10), curve: Curves.ease); if (listStates[draggedListIndex!].mounted) { RenderBox object = listStates[draggedListIndex!] @@ -521,8 +514,7 @@ class BoardViewState extends State } if (dy! < topListY! + 70) { //scroll up - if (listStates[draggedListIndex!].boardListController != null && - listStates[draggedListIndex!].boardListController.hasClients && + if (listStates[draggedListIndex!].boardListController.hasClients && !isScrolling) { isScrolling = true; double pos = listStates[draggedListIndex!] @@ -537,14 +529,14 @@ class BoardViewState extends State .position .pixels - 5, - duration: new Duration(milliseconds: 10), + duration: const Duration(milliseconds: 10), curve: Curves.ease) .whenComplete(() { pos -= listStates[draggedListIndex!] .boardListController .position .pixels; - if (initialY == null) initialY = 0; + initialY ??= 0; // if(widget.boardViewController != null) { // initialY -= pos; // } @@ -574,17 +566,16 @@ class BoardViewState extends State double? tempBottom = bottomListY; if (widget.middleWidget != null) { if (_middleWidgetKey.currentContext != null) { + // ignore: no_leading_underscores_for_local_identifiers RenderBox _box = _middleWidgetKey.currentContext! .findRenderObject() as RenderBox; tempBottom = _box.size.height; - print("tempBottom:${tempBottom}"); } } if (dy! > tempBottom! - 70) { //scroll down if (listStates.length < draggedListIndex! && - listStates[draggedListIndex!].boardListController != null && listStates[draggedListIndex!].boardListController.hasClients) { isScrolling = true; double pos = listStates[draggedListIndex!] @@ -599,7 +590,7 @@ class BoardViewState extends State .position .pixels + 5, - duration: new Duration(milliseconds: 10), + duration: const Duration(milliseconds: 10), curve: Curves.ease) .whenComplete(() { pos -= listStates[draggedListIndex!] @@ -607,9 +598,6 @@ class BoardViewState extends State .position .pixels; initialY ??= 0; -// if(widget.boardViewController != null) { -// initialY -= pos; -// } isScrolling = false; if (topItemY != null) { topItemY = topItemY! + pos; @@ -638,10 +626,10 @@ class BoardViewState extends State //dragging list if (0 <= draggedListIndex! - 1 && dx! < leftListX! + 45) { //scroll left - if (boardViewController != null && boardViewController.hasClients) { + if (boardViewController.hasClients) { boardViewController.animateTo( boardViewController.position.pixels - 5, - duration: new Duration(milliseconds: 10), + duration: const Duration(milliseconds: 10), curve: Curves.ease); if (leftListX != null) { leftListX = leftListX! + 5; @@ -655,10 +643,10 @@ class BoardViewState extends State if (widget.lists!.length > draggedListIndex! + 1 && dx! > rightListX! - 45) { //scroll right - if (boardViewController != null && boardViewController.hasClients) { + if (boardViewController.hasClients) { boardViewController.animateTo( boardViewController.position.pixels + 5, - duration: new Duration(milliseconds: 10), + duration: const Duration(milliseconds: 10), curve: Curves.ease); if (leftListX != null) { leftListX = leftListX! - 5; @@ -683,7 +671,7 @@ class BoardViewState extends State stackWidgets .add(Container(key: _middleWidgetKey, child: widget.middleWidget)); } - WidgetsBinding.instance!.addPostFrameCallback((timeStamp) { + WidgetsBinding.instance.addPostFrameCallback((timeStamp) { if (mounted) { setState(() {}); } @@ -691,94 +679,89 @@ class BoardViewState extends State stackWidgets.add(Positioned( width: widget.width, height: height, - child: Opacity(opacity: .7, child: draggedItem), left: (dx! - offsetX!) + initialX!, top: (dy! - offsetY!) + initialY!, + child: Opacity(opacity: .7, child: draggedItem), )); } - return Container( - child: Listener( - onPointerMove: (opm) { - if (draggedItem != null) { - if (dxInit == null) { - dxInit = opm.position.dx; - } - if (dyInit == null) { - dyInit = opm.position.dy; - } - dx = opm.position.dx; - dy = opm.position.dy; - if (mounted) { - setState(() {}); - } - } - }, - onPointerDown: (opd) { - RenderBox box = context.findRenderObject() as RenderBox; - Offset pos = box.localToGlobal(opd.position); - offsetX = pos.dx; - offsetY = pos.dy; - pointer = opd; - if (mounted) { - setState(() {}); - } - }, - onPointerUp: (opu) { - if (onDropItem != null) { - int? tempDraggedItemIndex = draggedItemIndex; - int? tempDraggedListIndex = draggedListIndex; - int? startDraggedItemIndex = startItemIndex; - int? startDraggedListIndex = startListIndex; - - if (_isInWidget && widget.onDropItemInMiddleWidget != null) { - onDropItem!(startDraggedListIndex, startDraggedItemIndex); - widget.onDropItemInMiddleWidget!( - startDraggedListIndex, - startDraggedItemIndex, - opu.position.dx / MediaQuery.of(context).size.width); - } else { - onDropItem!(tempDraggedListIndex, tempDraggedItemIndex); - } - } - if (onDropList != null) { - int? tempDraggedListIndex = draggedListIndex; - if (_isInWidget && widget.onDropItemInMiddleWidget != null) { - onDropList!(tempDraggedListIndex); - widget.onDropItemInMiddleWidget!(tempDraggedListIndex, null, - opu.position.dx / MediaQuery.of(context).size.width); - } else { - onDropList!(tempDraggedListIndex); - } - } - draggedItem = null; - offsetX = null; - offsetY = null; - initialX = null; - initialY = null; - dx = null; - dy = null; - draggedItemIndex = null; - draggedListIndex = null; - onDropItem = null; - onDropList = null; - dxInit = null; - dyInit = null; - leftListX = null; - rightListX = null; - topListY = null; - bottomListY = null; - topItemY = null; - bottomItemY = null; - startListIndex = null; - startItemIndex = null; - if (mounted) { - setState(() {}); - } - }, - child: new Stack( - children: stackWidgets, - ))); + return Listener( + onPointerMove: (opm) { + if (draggedItem != null) { + dxInit ??= opm.position.dx; + dyInit ??= opm.position.dy; + dx = opm.position.dx; + dy = opm.position.dy; + if (mounted) { + setState(() {}); + } + } + }, + onPointerDown: (opd) { + RenderBox box = context.findRenderObject() as RenderBox; + Offset pos = box.localToGlobal(opd.position); + offsetX = pos.dx; + offsetY = pos.dy; + pointer = opd; + if (mounted) { + setState(() {}); + } + }, + onPointerUp: (opu) { + if (onDropItem != null) { + int? tempDraggedItemIndex = draggedItemIndex; + int? tempDraggedListIndex = draggedListIndex; + int? startDraggedItemIndex = startItemIndex; + int? startDraggedListIndex = startListIndex; + + if (_isInWidget && widget.onDropItemInMiddleWidget != null) { + onDropItem!(startDraggedListIndex, startDraggedItemIndex); + widget.onDropItemInMiddleWidget!( + startDraggedListIndex, + startDraggedItemIndex, + opu.position.dx / MediaQuery.of(context).size.width); + } else { + onDropItem!(tempDraggedListIndex, tempDraggedItemIndex); + } + } + if (onDropList != null) { + int? tempDraggedListIndex = draggedListIndex; + if (_isInWidget && widget.onDropItemInMiddleWidget != null) { + onDropList!(tempDraggedListIndex); + widget.onDropItemInMiddleWidget!(tempDraggedListIndex, null, + opu.position.dx / MediaQuery.of(context).size.width); + } else { + onDropList!(tempDraggedListIndex); + } + } + draggedItem = null; + offsetX = null; + offsetY = null; + initialX = null; + initialY = null; + dx = null; + dy = null; + draggedItemIndex = null; + draggedListIndex = null; + onDropItem = null; + onDropList = null; + dxInit = null; + dyInit = null; + leftListX = null; + rightListX = null; + topListY = null; + bottomListY = null; + topItemY = null; + bottomItemY = null; + startListIndex = null; + startItemIndex = null; + if (mounted) { + setState(() {}); + } + }, + child: Stack( + children: stackWidgets, + )); } void run() { diff --git a/demos/supabase-trello/lib/widgets/thirdparty/boardview_controller.dart b/demos/supabase-trello/lib/widgets/thirdparty/boardview_controller.dart index 72457e11..8c93bd7e 100644 --- a/demos/supabase-trello/lib/widgets/thirdparty/boardview_controller.dart +++ b/demos/supabase-trello/lib/widgets/thirdparty/boardview_controller.dart @@ -9,8 +9,7 @@ class BoardViewController { Future animateTo(int index, {Duration? duration, Curve? curve}) async { double offset = index * state.widget.width; - if (state.boardViewController != null && - state.boardViewController.hasClients) { + if (state.boardViewController.hasClients) { await state.boardViewController .animateTo(offset, duration: duration!, curve: curve!); } diff --git a/demos/supabase-trello/lib/widgets/thirdparty/vs_scrollbar.dart b/demos/supabase-trello/lib/widgets/thirdparty/vs_scrollbar.dart index 85aa58bb..db594963 100644 --- a/demos/supabase-trello/lib/widgets/thirdparty/vs_scrollbar.dart +++ b/demos/supabase-trello/lib/widgets/thirdparty/vs_scrollbar.dart @@ -1,9 +1,7 @@ library vs_scrollbar; -import 'package:flutter/cupertino.dart'; import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/widgets.dart'; class VsScrollbarStyle { /// The hoverThickness of the VsScrollbar thumb. @@ -28,7 +26,7 @@ class VsScrollbarStyle { this.color}); } -const VsScrollbarStyle _kScrollbarStyle = const VsScrollbarStyle(); +const VsScrollbarStyle _kScrollbarStyle = VsScrollbarStyle(); const double _kScrollbarThickness = 8.0; const double _kScrollbarThicknessWithTrack = 12.0; const double _kScrollbarMargin = 2.0; @@ -64,7 +62,7 @@ class VsScrollbar extends StatefulWidget { /// enable VsScrollbar dragging using the [PrimaryScrollController]. /// const VsScrollbar({ - Key? key, + super.key, required this.child, this.controller, this.style = _kScrollbarStyle, @@ -73,7 +71,7 @@ class VsScrollbar extends StatefulWidget { this.isAlwaysShown, this.showTrackOnHover, this.notificationPredicate, - }) : super(key: key); + }); /// {@macro flutter.widgets.VsScrollbar.child} final Widget child; @@ -102,6 +100,7 @@ class VsScrollbar extends StatefulWidget { final Duration? scrollbarFadeDuration; @override + // ignore: library_private_types_in_public_api _ScrollbarState createState() => _ScrollbarState(); } @@ -109,7 +108,6 @@ class _ScrollbarState extends State { @override Widget build(BuildContext context) { return _MaterialScrollbar( - child: widget.child, controller: widget.controller, isAlwaysShown: widget.isAlwaysShown, showTrackOnHover: widget.showTrackOnHover, @@ -118,31 +116,26 @@ class _ScrollbarState extends State { radius: widget.style.radius, color: widget.style.color, notificationPredicate: widget.notificationPredicate, + child: widget.child, ); } } class _MaterialScrollbar extends RawScrollbar { const _MaterialScrollbar({ - Key? key, - required Widget child, - ScrollController? controller, + required super.child, + super.controller, bool? isAlwaysShown, this.showTrackOnHover, this.hoverThickness, this.color, this.scrollbarFadeDuration, this.scrollbarTimeToFade, - double? thickness, - Radius? radius, + super.thickness, + super.radius, ScrollNotificationPredicate? notificationPredicate, }) : super( - key: key, - child: child, - controller: controller, thumbVisibility: isAlwaysShown, - thickness: thickness, - radius: radius, fadeDuration: scrollbarFadeDuration ?? _kScrollbarFadeDuration, timeToFade: scrollbarTimeToFade ?? _kScrollbarTimeToFade, pressDuration: Duration.zero, @@ -172,18 +165,17 @@ class _MaterialScrollbarState extends RawScrollbarState<_MaterialScrollbar> { @override bool get showScrollbar => widget.thumbVisibility ?? - _scrollbarTheme.thumbVisibility - ?.resolve(Set.of([MaterialState.disabled])) ?? + _scrollbarTheme.thumbVisibility?.resolve({WidgetState.disabled}) ?? false; bool get _showTrackOnHover => widget.showTrackOnHover ?? false; - Set get _states => { - if (_dragIsActive) MaterialState.dragged, - if (_hoverIsActive) MaterialState.hovered, + Set get _states => { + if (_dragIsActive) WidgetState.dragged, + if (_hoverIsActive) WidgetState.hovered, }; - MaterialStateProperty get _thumbColor { + WidgetStateProperty get _thumbColor { final Color onSurface = widget.color ?? _colorScheme.onSurface; late Color dragColor; late Color hoverColor; @@ -192,14 +184,16 @@ class _MaterialScrollbarState extends RawScrollbarState<_MaterialScrollbar> { hoverColor = onSurface.withOpacity(0.75); idleColor = onSurface.withOpacity(0.5); - return MaterialStateProperty.resolveWith((Set states) { - if (states.contains(MaterialState.dragged)) + return WidgetStateProperty.resolveWith((Set states) { + if (states.contains(WidgetState.dragged)) { return _scrollbarTheme.thumbColor?.resolve(states) ?? dragColor; + } // If the track is visible, the thumb color hover animation is ignored and // changes immediately. - if (states.contains(MaterialState.hovered) && _showTrackOnHover) + if (states.contains(WidgetState.hovered) && _showTrackOnHover) { return _scrollbarTheme.thumbColor?.resolve(states) ?? hoverColor; + } return Color.lerp( _scrollbarTheme.thumbColor?.resolve(states) ?? idleColor, @@ -209,11 +203,11 @@ class _MaterialScrollbarState extends RawScrollbarState<_MaterialScrollbar> { }); } - MaterialStateProperty get _trackColor { + WidgetStateProperty get _trackColor { final Color onSurface = widget.color ?? _colorScheme.onSurface; - return MaterialStateProperty.resolveWith((Set states) { - if (states.contains(MaterialState.hovered) && _showTrackOnHover) { + return WidgetStateProperty.resolveWith((Set states) { + if (states.contains(WidgetState.hovered) && _showTrackOnHover) { return _scrollbarTheme.trackColor?.resolve(states) ?? onSurface.withOpacity(0.05); } @@ -221,11 +215,11 @@ class _MaterialScrollbarState extends RawScrollbarState<_MaterialScrollbar> { }); } - MaterialStateProperty get _trackBorderColor { + WidgetStateProperty get _trackBorderColor { final Color onSurface = widget.color ?? _colorScheme.onSurface; - return MaterialStateProperty.resolveWith((Set states) { - if (states.contains(MaterialState.hovered) && _showTrackOnHover) { + return WidgetStateProperty.resolveWith((Set states) { + if (states.contains(WidgetState.hovered) && _showTrackOnHover) { return _scrollbarTheme.trackBorderColor?.resolve(states) ?? onSurface.withOpacity(0.1); } @@ -233,12 +227,13 @@ class _MaterialScrollbarState extends RawScrollbarState<_MaterialScrollbar> { }); } - MaterialStateProperty get _thickness { - return MaterialStateProperty.resolveWith((Set states) { - if (states.contains(MaterialState.hovered) && _showTrackOnHover) + WidgetStateProperty get _thickness { + return WidgetStateProperty.resolveWith((Set states) { + if (states.contains(WidgetState.hovered) && _showTrackOnHover) { return widget.hoverThickness ?? _scrollbarTheme.thickness?.resolve(states) ?? _kScrollbarThicknessWithTrack; + } // The default VsScrollbar thickness is smaller on mobile. return widget.thickness ?? _scrollbarTheme.thickness?.resolve(states) ?? @@ -293,7 +288,7 @@ class _MaterialScrollbarState extends RawScrollbarState<_MaterialScrollbar> { (_useAndroidScrollbar ? 0.0 : _kScrollbarMargin) ..mainAxisMargin = _scrollbarTheme.mainAxisMargin ?? 0.0 ..minLength = _scrollbarTheme.minThumbLength ?? _kScrollbarMinLength - ..padding = EdgeInsets.all(0); + ..padding = const EdgeInsets.all(0); } @override From 93d6e178965bb163a77c1d9a10ca1bb8e14a79ae Mon Sep 17 00:00:00 2001 From: DominicGBauer Date: Thu, 9 Jan 2025 14:26:32 +0200 Subject: [PATCH 04/10] fix: formatting --- .../lib/protocol/data_client.dart | 257 +++++++----------- 1 file changed, 95 insertions(+), 162 deletions(-) diff --git a/demos/supabase-trello/lib/protocol/data_client.dart b/demos/supabase-trello/lib/protocol/data_client.dart index 5afa61f1..c7af10d5 100644 --- a/demos/supabase-trello/lib/protocol/data_client.dart +++ b/demos/supabase-trello/lib/protocol/data_client.dart @@ -26,28 +26,24 @@ class _ActivityRepository extends _Repository { _ActivityRepository(super.client); Future createActivity(Activity activity) async { - final results = await client.getDBExecutor().execute( - '''INSERT INTO + final results = await client.getDBExecutor().execute('''INSERT INTO activity(id, workspaceId, boardId, userId, cardId, description, dateCreated) VALUES(?, ?, ?, ?, ?, ?, datetime()) - RETURNING *''', - [ - activity.id, - activity.workspaceId, - activity.boardId, - activity.userId, - activity.cardId, - activity.description - ]); + RETURNING *''', [ + activity.id, + activity.workspaceId, + activity.boardId, + activity.userId, + activity.cardId, + activity.description + ]); return results.isNotEmpty; } Future> getActivities(Cardlist cardlist) async { - final results = await client.getDBExecutor().execute( - ''' + final results = await client.getDBExecutor().execute(''' SELECT * FROM activity WHERE cardId = ? ORDER BY dateCreated DESC - ''', - [cardlist.id]); + ''', [cardlist.id]); return results.map((row) => Activity.fromRow(row)).toList(); } } @@ -56,18 +52,16 @@ class _AttachmentRepository extends _Repository { _AttachmentRepository(super.client); Future addAttachment(Attachment attachment) async { - final results = await client.getDBExecutor().execute( - '''INSERT INTO + final results = await client.getDBExecutor().execute('''INSERT INTO attachment(id, workspaceId, userId, cardId, attachment) VALUES(?, ?, ?, ?, ?) - RETURNING *''', - [ - attachment.id, - attachment.workspaceId, - attachment.userId, - attachment.cardId, - attachment.attachment - ]); + RETURNING *''', [ + attachment.id, + attachment.workspaceId, + attachment.userId, + attachment.cardId, + attachment.attachment + ]); if (results.isEmpty) { throw Exception("Failed to add attachment"); } else { @@ -85,24 +79,20 @@ class _AttachmentRepository extends _Repository { class _BoardRepository extends _Repository { _BoardRepository(super.client); - String get insertQuery => - ''' + String get insertQuery => ''' INSERT INTO board(id, userId, workspaceId, name, description, visibility, background, starred, enableCover, watch, availableOffline, label, emailAddress, commenting, memberType, pinned, selfJoin, close) VALUES(?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12, ?13, ?14, ?15, ?16, ?17, ?18) '''; - String get updateQuery => - ''' + String get updateQuery => ''' UPDATE board set userId = ?1, workspaceId = ?2, name = ?3, description = ?4, visibility = ?5, background = ?6, starred = ?7, enableCover = ?8, watch = ?9, availableOffline = ?10, label = ?11, emailAddress = ?12, commenting = ?13, memberType = ?14, pinned = ?15, selfJoin = ?16, close = ?17 WHERE id = ?18 '''; Future createBoard(Board board) async { - final results = await client - .getDBExecutor() - .execute(''' + final results = await client.getDBExecutor().execute(''' $insertQuery RETURNING *''', [ board.id, board.userId, @@ -162,18 +152,14 @@ class _BoardRepository extends _Repository { } Future getWorkspaceForBoard(Board board) async { - final results = await client.getDBExecutor().execute( - ''' + final results = await client.getDBExecutor().execute(''' SELECT * FROM workspace WHERE id = ? - ''', - [board.workspaceId]); + ''', [board.workspaceId]); return results.map((row) => Workspace.fromRow(row)).firstOrNull; } Future> getAllBoards() async { - final results = await client - .getDBExecutor() - .execute(''' + final results = await client.getDBExecutor().execute(''' SELECT * FROM board '''); return results.map((row) => Board.fromRow(row)).toList(); @@ -183,8 +169,7 @@ class _BoardRepository extends _Repository { class _CardlistRepository extends _Repository { _CardlistRepository(super.client); - String get insertQuery => - ''' + String get insertQuery => ''' INSERT INTO card(id, workspaceId, listId, userId, name, description, startDate, dueDate, attachment, archived, checklist, comments, rank) VALUES(?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12, ?13) @@ -214,8 +199,7 @@ class _CardlistRepository extends _Repository { } } - String get updateQuery => - ''' + String get updateQuery => ''' UPDATE card set listId = ?1, userId = ?2, name = ?3, description = ?4, startDate = ?5, dueDate = ?6, attachment = ?7, archived = ?8, checklist = ?9, comments = ?10, rank = ?11 WHERE id = ?12 @@ -247,11 +231,9 @@ class _CardlistRepository extends _Repository { } Future> getCardsforList(String listId) async { - final results = await client.getDBExecutor().execute( - ''' + final results = await client.getDBExecutor().execute(''' SELECT * FROM card WHERE listId = ? AND archived = 0 ORDER BY rank ASC - ''', - [listId]); + ''', [listId]); return results.map((row) => Cardlist.fromRow(row)).toList(); } } @@ -259,8 +241,7 @@ class _CardlistRepository extends _Repository { class _CheckListRepository extends _Repository { _CheckListRepository(super.client); - String get insertQuery => - ''' + String get insertQuery => ''' INSERT INTO checklist(id, workspaceId, cardId, name, status) VALUES(?1, ?2, ?3, ?4, ?5) @@ -282,8 +263,7 @@ class _CheckListRepository extends _Repository { } } - String get updateQuery => - ''' + String get updateQuery => ''' UPDATE checklist set cardId = ?1, name = ?2, status = ?3 WHERE id = ?4 @@ -307,20 +287,16 @@ class _CheckListRepository extends _Repository { } Future> getChecklists(Cardlist crd) async { - final results = await client.getDBExecutor().execute( - ''' + final results = await client.getDBExecutor().execute(''' SELECT * FROM checklist WHERE cardId = ? - ''', - [crd.id]); + ''', [crd.id]); return results.map((row) => Checklist.fromRow(row)).toList(); } Future deleteChecklist(Cardlist crd) async { - final results = await client.getDBExecutor().execute( - ''' + final results = await client.getDBExecutor().execute(''' SELECT COUNT(*) FROM checklist WHERE cardId = ? - ''', - [crd.id]); + ''', [crd.id]); await client .getDBExecutor() .execute('DELETE FROM checklist WHERE cardId = ?', [crd.id]); @@ -331,8 +307,7 @@ class _CheckListRepository extends _Repository { class _CommentRepository extends _Repository { _CommentRepository(super.client); - String get insertQuery => - ''' + String get insertQuery => ''' INSERT INTO comment(id, workspaceId, cardId, userId, description) VALUES(?1, ?2, ?3, ?4, ?5) @@ -354,8 +329,7 @@ class _CommentRepository extends _Repository { } } - String get updateQuery => - ''' + String get updateQuery => ''' UPDATE comment set cardId = ?1, userId = ?2, description = ?3 WHERE id = ?4 @@ -373,11 +347,9 @@ class _ListboardRepository extends _Repository { Future> getListsByBoard({required String boardId}) async { //first we get the listboards - final results = await client.getDBExecutor().execute( - ''' + final results = await client.getDBExecutor().execute(''' SELECT * FROM listboard WHERE boardId = ? - ''', - [boardId]); + ''', [boardId]); List lists = results.map((row) => Listboard.fromRow(row)).toList(); @@ -397,11 +369,9 @@ class _ListboardRepository extends _Repository { Stream> watchListsByBoard({required String boardId}) { //first we get the listboards - return client.getDBExecutor().watch( - ''' + return client.getDBExecutor().watch(''' SELECT * FROM listboard WHERE boardId = ? ORDER BY listOrder ASC - ''', - parameters: [boardId]).asyncMap((event) async { + ''', parameters: [boardId]).asyncMap((event) async { List lists = event.map((row) => Listboard.fromRow(row)).toList(); @@ -420,8 +390,7 @@ class _ListboardRepository extends _Repository { }); } - String get insertQuery => - ''' + String get insertQuery => ''' INSERT INTO listboard(id, workspaceId, boardId, userId, name, archived, listOrder) VALUES(?1, ?2, ?3, ?4, ?5, ?6, ?7) @@ -445,8 +414,7 @@ class _ListboardRepository extends _Repository { } } - String get updateQuery => - ''' + String get updateQuery => ''' UPDATE listboard set listOrder = ?1 WHERE id = ?2 @@ -469,22 +437,18 @@ class _ListboardRepository extends _Repository { int numCards = cards.length; //we set each of the cards in the list to archived = true - sqlContext.executeBatch( - ''' + sqlContext.executeBatch(''' UPDATE card SET archived = 1 WHERE id = ? - ''', - cards.map((card) => [card.id]).toList()); + ''', cards.map((card) => [card.id]).toList()); //touch listboard to trigger update via stream listeners on Listboard - sqlContext.execute( - ''' + sqlContext.execute(''' UPDATE listboard SET archived = 0 WHERE id = ? - ''', - [list.id]); + ''', [list.id]); list.cards = []; return numCards; @@ -496,8 +460,7 @@ class _ListboardRepository extends _Repository { class _MemberRepository extends _Repository { _MemberRepository(super.client); - String get insertQuery => - ''' + String get insertQuery => ''' INSERT INTO member(id, workspaceId, userId, name, role) VALUES(?1, ?2, ?3, ?4, ?5) @@ -521,11 +484,9 @@ class _MemberRepository extends _Repository { Future> getMembersByWorkspace( {required String workspaceId}) async { - final results = await client.getDBExecutor().execute( - ''' + final results = await client.getDBExecutor().execute(''' SELECT * FROM member WHERE workspaceId = ? - ''', - [workspaceId]); + ''', [workspaceId]); return results.map((row) => Member.fromRow(row)).toList(); } @@ -557,8 +518,7 @@ class _MemberRepository extends _Repository { class _UserRepository extends _Repository { _UserRepository(super.client); - String get insertQuery => - ''' + String get insertQuery => ''' INSERT INTO trellouser(id, name, email, password) VALUES(?1, ?2, ?3, ?4) @@ -578,28 +538,22 @@ class _UserRepository extends _Repository { /// We excpect only one record in the local trellouser table /// if somebody has logged in and not logged out again Future getUser() async { - final results = await client - .getDBExecutor() - .execute(''' + final results = await client.getDBExecutor().execute(''' SELECT * FROM trellouser'''); return results.map((row) => TrelloUser.fromRow(row)).firstOrNull; } Future getUserById({required String userId}) async { - final results = await client.getDBExecutor().execute( - ''' + final results = await client.getDBExecutor().execute(''' SELECT * FROM trellouser WHERE id = ? - ''', - [userId]); + ''', [userId]); return results.map((row) => TrelloUser.fromRow(row)).firstOrNull; } Future checkUserExists(String email) async { - final results = await client.getDBExecutor().execute( - ''' + final results = await client.getDBExecutor().execute(''' SELECT * FROM trellouser WHERE email = ? - ''', - [email]); + ''', [email]); return results.map((row) => TrelloUser.fromRow(row)).firstOrNull; } } @@ -607,8 +561,7 @@ class _UserRepository extends _Repository { class _WorkspaceRepository extends _Repository { _WorkspaceRepository(super.client); - String get insertQuery => - ''' + String get insertQuery => ''' INSERT INTO workspace(id, userId, name, description, visibility) VALUES(?1, ?2, ?3, ?4, ?5) @@ -628,11 +581,9 @@ class _WorkspaceRepository extends _Repository { Future> getWorkspacesByUser({required String userId}) async { //First we get the workspaces - final results = await client.getDBExecutor().execute( - ''' + final results = await client.getDBExecutor().execute(''' SELECT * FROM workspace WHERE userId = ? - ''', - [userId]); + ''', [userId]); List workspaces = results.map((row) => Workspace.fromRow(row)).toList(); @@ -667,11 +618,9 @@ class _WorkspaceRepository extends _Repository { } Future getWorkspaceById({required String workspaceId}) async { - final results = await client.getDBExecutor().execute( - ''' + final results = await client.getDBExecutor().execute(''' SELECT * FROM workspace WHERE id = ? - ''', - [workspaceId]); + ''', [workspaceId]); Workspace workspace = Workspace.fromRow(results.first); List members = await client.member.getMembersByWorkspace(workspaceId: workspaceId); @@ -681,11 +630,9 @@ class _WorkspaceRepository extends _Repository { Future> getBoardsByWorkspace( {required String workspaceId}) async { - final results = await client.getDBExecutor().execute( - ''' + final results = await client.getDBExecutor().execute(''' SELECT * FROM board WHERE workspaceId = ? - ''', - [workspaceId]); + ''', [workspaceId]); List boards = results.map((row) => Board.fromRow(row)).toList(); @@ -698,11 +645,9 @@ class _WorkspaceRepository extends _Repository { } Stream> watchBoardsByWorkspace({required String workspaceId}) { - return client.getDBExecutor().watch( - ''' + return client.getDBExecutor().watch(''' SELECT * FROM board WHERE workspaceId = ? - ''', - parameters: [workspaceId]).asyncMap((event) async { + ''', parameters: [workspaceId]).asyncMap((event) async { List boards = event.map((row) => Board.fromRow(row)).toList(); for (Board board in boards) { @@ -715,19 +660,17 @@ class _WorkspaceRepository extends _Repository { } Future updateWorkspace(Workspace workspace) async { - await client.getDBExecutor().execute( - ''' + await client.getDBExecutor().execute(''' UPDATE workspace set userId = ?1, name = ?2, description = ?3, visibility = ?4 WHERE id = ?5 - ''', - [ - workspace.userId, - workspace.name, - workspace.description, - workspace.visibility, - workspace.id - ]); + ''', [ + workspace.userId, + workspace.name, + workspace.description, + workspace.visibility, + workspace.id + ]); return true; } @@ -743,18 +686,16 @@ class _BoardLabelRepository extends _Repository { _BoardLabelRepository(super.client); Future createBoardLabel(BoardLabel boardLabel) async { - final results = await client.getDBExecutor().execute( - '''INSERT INTO + final results = await client.getDBExecutor().execute('''INSERT INTO board_label(id, boardId, workspaceId, title, color, dateCreated) VALUES(?, ?, ?, ?, ?, datetime()) - RETURNING *''', - [ - boardLabel.id, - boardLabel.boardId, - boardLabel.workspaceId, - boardLabel.title, - boardLabel.color - ]); + RETURNING *''', [ + boardLabel.id, + boardLabel.boardId, + boardLabel.workspaceId, + boardLabel.title, + boardLabel.color + ]); if (results.isEmpty) { throw Exception("Failed to add BoardLabel"); } else { @@ -763,22 +704,18 @@ class _BoardLabelRepository extends _Repository { } Future updateBoardLabel(BoardLabel boardLabel) async { - await client.getDBExecutor().execute( - ''' + await client.getDBExecutor().execute(''' UPDATE board_label set title = ?1 WHERE id = ?2 - ''', - [boardLabel.title, boardLabel.id]); + ''', [boardLabel.title, boardLabel.id]); return true; } Future> getBoardLabels(Board board) async { - final results = await client.getDBExecutor().execute( - ''' + final results = await client.getDBExecutor().execute(''' SELECT * FROM board_label WHERE boardId = ? ORDER BY dateCreated DESC - ''', - [board.id]); + ''', [board.id]); return results.map((row) => BoardLabel.fromRow(row)).toList(); } } @@ -787,18 +724,16 @@ class _CardLabelRepository extends _Repository { _CardLabelRepository(super.client); Future createCardLabel(CardLabel cardLabel) async { - final results = await client.getDBExecutor().execute( - '''INSERT INTO + final results = await client.getDBExecutor().execute('''INSERT INTO card_label(id, cardId, boardId, workspaceId, boardLabelId, dateCreated) VALUES(?, ?, ?, ?, ?, datetime()) - RETURNING *''', - [ - cardLabel.id, - cardLabel.cardId, - cardLabel.boardId, - cardLabel.workspaceId, - cardLabel.boardLabelId, - ]); + RETURNING *''', [ + cardLabel.id, + cardLabel.cardId, + cardLabel.boardId, + cardLabel.workspaceId, + cardLabel.boardLabelId, + ]); if (results.isEmpty) { throw Exception("Failed to add CardLabel"); } else { @@ -813,11 +748,9 @@ class _CardLabelRepository extends _Repository { } Future> getCardLabels(Cardlist card) async { - final results = await client.getDBExecutor().execute( - ''' + final results = await client.getDBExecutor().execute(''' SELECT * FROM card_label WHERE cardId = ? ORDER BY dateCreated DESC - ''', - [card.id]); + ''', [card.id]); return results.map((row) => CardLabel.fromRow(row)).toList(); } } From abddbac40d52551bd9d5106b6be53f2823f21846 Mon Sep 17 00:00:00 2001 From: DominicGBauer Date: Thu, 9 Jan 2025 15:29:38 +0200 Subject: [PATCH 05/10] chore: remove test --- demos/supabase-trello/test/widget_test.dart | 15 --------------- 1 file changed, 15 deletions(-) delete mode 100644 demos/supabase-trello/test/widget_test.dart diff --git a/demos/supabase-trello/test/widget_test.dart b/demos/supabase-trello/test/widget_test.dart deleted file mode 100644 index ac1458c1..00000000 --- a/demos/supabase-trello/test/widget_test.dart +++ /dev/null @@ -1,15 +0,0 @@ -// This is a basic Flutter widget test. -// -// To perform an interaction with a widget in your test, use the WidgetTester -// utility that Flutter provides. For example, you can send tap and scroll -// gestures. You can also use WidgetTester to find child widgets in the widget -// tree, read text, and verify that the values of widget properties are correct. - -// import 'package:flutter/material.dart'; -// import 'package:flutter_test/flutter_test.dart'; -// -// import 'package:PROJECTNAME_flutter/main.dart'; - -void main() { - // Add your app tests here -} From c822e8f7e3f923866575e1bd934e3e6e0e5dc83d Mon Sep 17 00:00:00 2001 From: DominicGBauer Date: Thu, 9 Jan 2025 17:25:02 +0200 Subject: [PATCH 06/10] fix: issues --- demos/benchmarks/pubspec.lock | 6 +-- demos/django-todolist/pubspec.lock | 6 +-- demos/firebase-nodejs-todolist/pubspec.lock | 6 +-- demos/supabase-anonymous-auth/pubspec.lock | 6 +-- .../supabase-edge-function-auth/pubspec.lock | 6 +-- demos/supabase-simple-chat/pubspec.lock | 6 +-- demos/supabase-todolist-drift/pubspec.lock | 8 ++-- .../pubspec.lock | 6 +-- demos/supabase-todolist/pubspec.lock | 8 ++-- .../features/board/presentation/index.dart | 2 + .../invitemember/presentation/index.dart | 2 + .../lib/widgets/thirdparty/boardview.dart | 6 +++ .../lib/widgets/thirdparty/vs_scrollbar.dart | 2 + demos/supabase-trello/pubspec.lock | 44 +++++++++---------- 14 files changed, 63 insertions(+), 51 deletions(-) diff --git a/demos/benchmarks/pubspec.lock b/demos/benchmarks/pubspec.lock index daa4d79c..eb68f19e 100644 --- a/demos/benchmarks/pubspec.lock +++ b/demos/benchmarks/pubspec.lock @@ -305,21 +305,21 @@ packages: path: "../../packages/powersync" relative: true source: path - version: "1.10.0" + version: "1.11.0" powersync_core: dependency: "direct overridden" description: path: "../../packages/powersync_core" relative: true source: path - version: "1.0.0" + version: "1.1.0" powersync_flutter_libs: dependency: "direct overridden" description: path: "../../packages/powersync_flutter_libs" relative: true source: path - version: "0.4.3" + version: "0.4.4" pub_semver: dependency: transitive description: diff --git a/demos/django-todolist/pubspec.lock b/demos/django-todolist/pubspec.lock index 5ae7bd20..d6eaaaee 100644 --- a/demos/django-todolist/pubspec.lock +++ b/demos/django-todolist/pubspec.lock @@ -318,21 +318,21 @@ packages: path: "../../packages/powersync" relative: true source: path - version: "1.10.0" + version: "1.11.0" powersync_core: dependency: "direct overridden" description: path: "../../packages/powersync_core" relative: true source: path - version: "1.0.0" + version: "1.1.0" powersync_flutter_libs: dependency: "direct overridden" description: path: "../../packages/powersync_flutter_libs" relative: true source: path - version: "0.4.3" + version: "0.4.4" pub_semver: dependency: transitive description: diff --git a/demos/firebase-nodejs-todolist/pubspec.lock b/demos/firebase-nodejs-todolist/pubspec.lock index d17ed358..b261c5f5 100644 --- a/demos/firebase-nodejs-todolist/pubspec.lock +++ b/demos/firebase-nodejs-todolist/pubspec.lock @@ -454,21 +454,21 @@ packages: path: "../../packages/powersync" relative: true source: path - version: "1.10.0" + version: "1.11.0" powersync_core: dependency: "direct overridden" description: path: "../../packages/powersync_core" relative: true source: path - version: "1.0.0" + version: "1.1.0" powersync_flutter_libs: dependency: "direct overridden" description: path: "../../packages/powersync_flutter_libs" relative: true source: path - version: "0.4.3" + version: "0.4.4" pub_semver: dependency: transitive description: diff --git a/demos/supabase-anonymous-auth/pubspec.lock b/demos/supabase-anonymous-auth/pubspec.lock index a9209796..57773b47 100644 --- a/demos/supabase-anonymous-auth/pubspec.lock +++ b/demos/supabase-anonymous-auth/pubspec.lock @@ -374,21 +374,21 @@ packages: path: "../../packages/powersync" relative: true source: path - version: "1.10.0" + version: "1.11.0" powersync_core: dependency: "direct overridden" description: path: "../../packages/powersync_core" relative: true source: path - version: "1.0.0" + version: "1.1.0" powersync_flutter_libs: dependency: "direct overridden" description: path: "../../packages/powersync_flutter_libs" relative: true source: path - version: "0.4.3" + version: "0.4.4" pub_semver: dependency: transitive description: diff --git a/demos/supabase-edge-function-auth/pubspec.lock b/demos/supabase-edge-function-auth/pubspec.lock index e8a2bbfc..5867b17c 100644 --- a/demos/supabase-edge-function-auth/pubspec.lock +++ b/demos/supabase-edge-function-auth/pubspec.lock @@ -398,21 +398,21 @@ packages: path: "../../packages/powersync" relative: true source: path - version: "1.10.0" + version: "1.11.0" powersync_core: dependency: "direct overridden" description: path: "../../packages/powersync_core" relative: true source: path - version: "1.0.0" + version: "1.1.0" powersync_flutter_libs: dependency: "direct overridden" description: path: "../../packages/powersync_flutter_libs" relative: true source: path - version: "0.4.3" + version: "0.4.4" pub_semver: dependency: transitive description: diff --git a/demos/supabase-simple-chat/pubspec.lock b/demos/supabase-simple-chat/pubspec.lock index 3c09e7d2..e686ad46 100644 --- a/demos/supabase-simple-chat/pubspec.lock +++ b/demos/supabase-simple-chat/pubspec.lock @@ -414,21 +414,21 @@ packages: path: "../../packages/powersync" relative: true source: path - version: "1.10.0" + version: "1.11.0" powersync_core: dependency: "direct overridden" description: path: "../../packages/powersync_core" relative: true source: path - version: "1.0.0" + version: "1.1.0" powersync_flutter_libs: dependency: "direct overridden" description: path: "../../packages/powersync_flutter_libs" relative: true source: path - version: "0.4.3" + version: "0.4.4" pub_semver: dependency: transitive description: diff --git a/demos/supabase-todolist-drift/pubspec.lock b/demos/supabase-todolist-drift/pubspec.lock index 51a1048f..dcc9e73c 100644 --- a/demos/supabase-todolist-drift/pubspec.lock +++ b/demos/supabase-todolist-drift/pubspec.lock @@ -686,28 +686,28 @@ packages: path: "../../packages/powersync" relative: true source: path - version: "1.10.0" + version: "1.11.0" powersync_attachments_helper: dependency: "direct main" description: path: "../../packages/powersync_attachments_helper" relative: true source: path - version: "0.6.16" + version: "0.6.17" powersync_core: dependency: "direct overridden" description: path: "../../packages/powersync_core" relative: true source: path - version: "1.0.0" + version: "1.1.0" powersync_flutter_libs: dependency: "direct overridden" description: path: "../../packages/powersync_flutter_libs" relative: true source: path - version: "0.4.3" + version: "0.4.4" pub_semver: dependency: transitive description: diff --git a/demos/supabase-todolist-optional-sync/pubspec.lock b/demos/supabase-todolist-optional-sync/pubspec.lock index aae3d692..99c005d8 100644 --- a/demos/supabase-todolist-optional-sync/pubspec.lock +++ b/demos/supabase-todolist-optional-sync/pubspec.lock @@ -478,21 +478,21 @@ packages: path: "../../packages/powersync" relative: true source: path - version: "1.10.0" + version: "1.11.0" powersync_core: dependency: "direct overridden" description: path: "../../packages/powersync_core" relative: true source: path - version: "1.0.0" + version: "1.1.0" powersync_flutter_libs: dependency: "direct overridden" description: path: "../../packages/powersync_flutter_libs" relative: true source: path - version: "0.4.3" + version: "0.4.4" pub_semver: dependency: transitive description: diff --git a/demos/supabase-todolist/pubspec.lock b/demos/supabase-todolist/pubspec.lock index d92f3608..28d725da 100644 --- a/demos/supabase-todolist/pubspec.lock +++ b/demos/supabase-todolist/pubspec.lock @@ -478,28 +478,28 @@ packages: path: "../../packages/powersync" relative: true source: path - version: "1.10.0" + version: "1.11.0" powersync_attachments_helper: dependency: "direct main" description: path: "../../packages/powersync_attachments_helper" relative: true source: path - version: "0.6.16" + version: "0.6.17" powersync_core: dependency: "direct overridden" description: path: "../../packages/powersync_core" relative: true source: path - version: "1.0.0" + version: "1.1.0" powersync_flutter_libs: dependency: "direct overridden" description: path: "../../packages/powersync_flutter_libs" relative: true source: path - version: "0.4.3" + version: "0.4.4" pub_semver: dependency: transitive description: diff --git a/demos/supabase-trello/lib/features/board/presentation/index.dart b/demos/supabase-trello/lib/features/board/presentation/index.dart index f1092bda..251131a9 100644 --- a/demos/supabase-trello/lib/features/board/presentation/index.dart +++ b/demos/supabase-trello/lib/features/board/presentation/index.dart @@ -372,6 +372,7 @@ class _BoardScreenState extends State with Service { onTap: () { archiveCardsInList(trello.lstbrd[index]) .then((numCardsArchived) { + // ignore: use_build_context_synchronously StatusAlert.show(context, duration: const Duration(seconds: 2), title: @@ -380,6 +381,7 @@ class _BoardScreenState extends State with Service { icon: Icons.archive_outlined, color: brandColor), maxWidth: 260); + // ignore: use_build_context_synchronously Navigator.of(context).pop(); }); }, diff --git a/demos/supabase-trello/lib/features/invitemember/presentation/index.dart b/demos/supabase-trello/lib/features/invitemember/presentation/index.dart index bcb4ad3a..24d57602 100644 --- a/demos/supabase-trello/lib/features/invitemember/presentation/index.dart +++ b/demos/supabase-trello/lib/features/invitemember/presentation/index.dart @@ -73,6 +73,7 @@ class _InviteMemberState extends State with Service { _currentMembers .addAll(trello.selectedWorkspace.members ?? []); }); + // ignore: use_build_context_synchronously StatusAlert.show(context, duration: const Duration(seconds: 3), title: 'Added Member', @@ -82,6 +83,7 @@ class _InviteMemberState extends State with Service { icon: Icons.check, color: brandColor), maxWidth: 260); } else { + // ignore: use_build_context_synchronously StatusAlert.show(context, duration: const Duration(seconds: 3), title: 'Add Failed', diff --git a/demos/supabase-trello/lib/widgets/thirdparty/boardview.dart b/demos/supabase-trello/lib/widgets/thirdparty/boardview.dart index 94d90ad5..7e6f9478 100644 --- a/demos/supabase-trello/lib/widgets/thirdparty/boardview.dart +++ b/demos/supabase-trello/lib/widgets/thirdparty/boardview.dart @@ -173,6 +173,7 @@ class BoardViewState extends State duration: const Duration(milliseconds: 400), curve: Curves.ease) .whenComplete(() { RenderBox object = + // ignore: use_build_context_synchronously listStates[tempListIndex!].context.findRenderObject() as RenderBox; Offset pos = object.localToGlobal(Offset.zero); leftListX = pos.dx; @@ -231,10 +232,12 @@ class BoardViewState extends State duration: const Duration(milliseconds: 400), curve: Curves.ease) .whenComplete(() { RenderBox object = + // ignore: use_build_context_synchronously listStates[tempListIndex!].context.findRenderObject() as RenderBox; Offset pos = object.localToGlobal(Offset.zero); leftListX = pos.dx; rightListX = pos.dx + object.size.width; + // ignore: use_build_context_synchronously RenderBox box = listStates[tempListIndex] .itemStates[tempItemIndex!] .context @@ -271,6 +274,7 @@ class BoardViewState extends State curve: Curves.ease) .whenComplete(() { RenderBox object = + // ignore: use_build_context_synchronously listStates[tempListIndex!].context.findRenderObject() as RenderBox; Offset pos = object.localToGlobal(Offset.zero); leftListX = pos.dx; @@ -329,10 +333,12 @@ class BoardViewState extends State duration: const Duration(milliseconds: 400), curve: Curves.ease) .whenComplete(() { RenderBox object = + // ignore: use_build_context_synchronously listStates[tempListIndex!].context.findRenderObject() as RenderBox; Offset pos = object.localToGlobal(Offset.zero); leftListX = pos.dx; rightListX = pos.dx + object.size.width; + // ignore: use_build_context_synchronously RenderBox box = listStates[tempListIndex] .itemStates[tempItemIndex!] .context diff --git a/demos/supabase-trello/lib/widgets/thirdparty/vs_scrollbar.dart b/demos/supabase-trello/lib/widgets/thirdparty/vs_scrollbar.dart index db594963..18cd4fc8 100644 --- a/demos/supabase-trello/lib/widgets/thirdparty/vs_scrollbar.dart +++ b/demos/supabase-trello/lib/widgets/thirdparty/vs_scrollbar.dart @@ -1,3 +1,5 @@ +// ignore_for_file: deprecated_member_use + library vs_scrollbar; import 'package:flutter/gestures.dart'; diff --git a/demos/supabase-trello/pubspec.lock b/demos/supabase-trello/pubspec.lock index d3a96f89..564a44d3 100644 --- a/demos/supabase-trello/pubspec.lock +++ b/demos/supabase-trello/pubspec.lock @@ -85,10 +85,10 @@ packages: dependency: transitive description: name: collection - sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a + sha256: a1ace0a119f20aabc852d165077c036cd864315bd99b7eaa10a60100341941bf url: "https://pub.dev" source: hosted - version: "1.18.0" + version: "1.19.0" cross_file: dependency: transitive description: @@ -396,18 +396,18 @@ packages: dependency: transitive description: name: leak_tracker - sha256: "7f0df31977cb2c0b88585095d168e689669a2cc9b97c309665e3386f3e9d341a" + sha256: "7bb2830ebd849694d1ec25bf1f44582d6ac531a57a365a803a6034ff751d2d06" url: "https://pub.dev" source: hosted - version: "10.0.4" + version: "10.0.7" leak_tracker_flutter_testing: dependency: transitive description: name: leak_tracker_flutter_testing - sha256: "06e98f569d004c1315b991ded39924b21af84cf14cc94791b8aea337d25b57f8" + sha256: "9491a714cca3667b60b5c420da8217e6de0d1ba7a5ec322fab01758f6998f379" url: "https://pub.dev" source: hosted - version: "3.0.3" + version: "3.0.8" leak_tracker_testing: dependency: transitive description: @@ -444,10 +444,10 @@ packages: dependency: transitive description: name: material_color_utilities - sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a" + sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec url: "https://pub.dev" source: hosted - version: "0.8.0" + version: "0.11.1" material_design_icons_flutter: dependency: "direct main" description: @@ -460,10 +460,10 @@ packages: dependency: transitive description: name: meta - sha256: "7687075e408b093f36e6bbf6c91878cc0d4cd10f409506f7bc996f68220b9136" + sha256: bdb68674043280c3428e9ec998512fb681678676b3c54e773629ffe74419f8c7 url: "https://pub.dev" source: hosted - version: "1.12.0" + version: "1.15.0" mime: dependency: transitive description: @@ -574,21 +574,21 @@ packages: path: "../../packages/powersync" relative: true source: path - version: "1.10.0" + version: "1.11.0" powersync_core: dependency: "direct overridden" description: path: "../../packages/powersync_core" relative: true source: path - version: "1.0.0" + version: "1.1.0" powersync_flutter_libs: dependency: "direct overridden" description: path: "../../packages/powersync_flutter_libs" relative: true source: path - version: "0.4.3" + version: "0.4.4" provider: dependency: "direct main" description: @@ -705,7 +705,7 @@ packages: dependency: transitive description: flutter source: sdk - version: "0.0.99" + version: "0.0.0" source_span: dependency: transitive description: @@ -758,10 +758,10 @@ packages: dependency: transitive description: name: stack_trace - sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b" + sha256: "9f47fd3630d76be3ab26f0ee06d213679aa425996925ff3feffdec504931c377" url: "https://pub.dev" source: hosted - version: "1.11.1" + version: "1.12.0" status_alert: dependency: "direct main" description: @@ -790,10 +790,10 @@ packages: dependency: transitive description: name: string_scanner - sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" + sha256: "688af5ed3402a4bde5b3a6c15fd768dbf2621a614950b17f04626c431ab3c4c3" url: "https://pub.dev" source: hosted - version: "1.2.0" + version: "1.3.0" supabase: dependency: transitive description: @@ -822,10 +822,10 @@ packages: dependency: transitive description: name: test_api - sha256: "9955ae474176f7ac8ee4e989dadfb411a58c30415bcfb648fa04b2b8a03afa7f" + sha256: "664d3a9a64782fcdeb83ce9c6b39e78fd2971d4e37827b9b06c3aa1edc5e760c" url: "https://pub.dev" source: hosted - version: "0.7.0" + version: "0.7.3" typed_data: dependency: transitive description: @@ -926,10 +926,10 @@ packages: dependency: transitive description: name: vm_service - sha256: "3923c89304b715fb1eb6423f017651664a03bf5f4b29983627c4da791f74a4ec" + sha256: f6be3ed8bd01289b34d679c2b62226f63c0e69f9fd2e50a6b3c1c729a961041b url: "https://pub.dev" source: hosted - version: "14.2.1" + version: "14.3.0" web: dependency: transitive description: From 9c512dfd933adf0343d50bc5155b7fc3423deb05 Mon Sep 17 00:00:00 2001 From: DominicGBauer Date: Thu, 9 Jan 2025 17:39:33 +0200 Subject: [PATCH 07/10] fix: issues --- .github/workflows/scripts/copy-config.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/scripts/copy-config.sh b/.github/workflows/scripts/copy-config.sh index 21457486..33b591b4 100755 --- a/.github/workflows/scripts/copy-config.sh +++ b/.github/workflows/scripts/copy-config.sh @@ -19,6 +19,9 @@ copy_config_files() { echo "Copied contents of $template_config to ${template_config%/*}/$TARGET_CONFIG_FILE" fi done + + # Create a new file .env fro supabase-trello demo + echo -n > demos/supabase-trello/.env } # Call the function for the single demos folder From 3ec819935ee48739f151506c5e4f2c6508c83908 Mon Sep 17 00:00:00 2001 From: DominicGBauer Date: Fri, 10 Jan 2025 15:28:01 +0200 Subject: [PATCH 08/10] chore: fix package issue --- .github/workflows/scripts/copy-config.sh | 2 +- demos/supabase-trello/ios/Podfile.lock | 10 +- .../ios/Runner/AppDelegate.swift | 2 +- .../features/board/presentation/index.dart | 31 ++- .../invitemember/presentation/index.dart | 71 +++-- .../signtotrello/presentation/index.dart | 6 +- .../lib/utils/data_generator.dart | 24 +- demos/supabase-trello/lib/utils/service.dart | 246 +++++++++++++----- demos/supabase-trello/pubspec.lock | 32 +-- demos/supabase-trello/pubspec.yaml | 29 +-- 10 files changed, 317 insertions(+), 136 deletions(-) diff --git a/.github/workflows/scripts/copy-config.sh b/.github/workflows/scripts/copy-config.sh index 33b591b4..f2c0a00d 100755 --- a/.github/workflows/scripts/copy-config.sh +++ b/.github/workflows/scripts/copy-config.sh @@ -20,7 +20,7 @@ copy_config_files() { fi done - # Create a new file .env fro supabase-trello demo + # Create a new file .env for supabase-trello demo echo -n > demos/supabase-trello/.env } diff --git a/demos/supabase-trello/ios/Podfile.lock b/demos/supabase-trello/ios/Podfile.lock index 4ca14fbb..d216c1c2 100644 --- a/demos/supabase-trello/ios/Podfile.lock +++ b/demos/supabase-trello/ios/Podfile.lock @@ -41,10 +41,10 @@ PODS: - path_provider_foundation (0.0.1): - Flutter - FlutterMacOS - - powersync-sqlite-core (0.3.7) + - powersync-sqlite-core (0.3.8) - powersync_flutter_libs (0.0.1): - Flutter - - powersync-sqlite-core (~> 0.3.6) + - powersync-sqlite-core (~> 0.3.8) - SDWebImage (5.20.0): - SDWebImage/Core (= 5.20.0) - SDWebImage/Core (5.20.0) @@ -118,12 +118,12 @@ SPEC CHECKSUMS: app_links: e7a6750a915a9e161c58d91bc610e8cd1d4d0ad0 DKImagePickerController: 946cec48c7873164274ecc4624d19e3da4c1ef3c DKPhotoGallery: b3834fecb755ee09a593d7c9e389d8b5d6deed60 - file_picker: 15fd9539e4eb735dc54bae8c0534a7a9511a03de + file_picker: 09aa5ec1ab24135ccd7a1621c46c84134bfd6655 Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7 image_picker_ios: c560581cceedb403a6ff17f2f816d7fea1421fc1 path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46 - powersync-sqlite-core: b9bcd19fa191d3d6f3f85c0573c41799d654cfa7 - powersync_flutter_libs: eb2694b322e1e4ef9a0f1e32dee600847f21ccbc + powersync-sqlite-core: 3b1cc184e277776aaf22e221fd0336575c7173c4 + powersync_flutter_libs: d3772510135d3eec09848015f8516f8b2689c794 SDWebImage: 73c6079366fea25fa4bb9640d5fb58f0893facd8 shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78 sqlite3: 7559e33dae4c78538df563795af3a86fc887ee71 diff --git a/demos/supabase-trello/ios/Runner/AppDelegate.swift b/demos/supabase-trello/ios/Runner/AppDelegate.swift index 70693e4a..b6363034 100644 --- a/demos/supabase-trello/ios/Runner/AppDelegate.swift +++ b/demos/supabase-trello/ios/Runner/AppDelegate.swift @@ -1,7 +1,7 @@ import UIKit import Flutter -@UIApplicationMain +@main @objc class AppDelegate: FlutterAppDelegate { override func application( _ application: UIApplication, diff --git a/demos/supabase-trello/lib/features/board/presentation/index.dart b/demos/supabase-trello/lib/features/board/presentation/index.dart index 251131a9..2623dac5 100644 --- a/demos/supabase-trello/lib/features/board/presentation/index.dart +++ b/demos/supabase-trello/lib/features/board/presentation/index.dart @@ -1,5 +1,4 @@ import 'package:flutter/material.dart'; -import 'package:status_alert/status_alert.dart'; import 'package:trelloappclone_flutter/features/carddetails/domain/card_detail_arguments.dart'; import 'package:trelloappclone_flutter/features/carddetails/presentation/index.dart'; import 'package:trelloappclone_flutter/utils/color.dart'; @@ -373,14 +372,30 @@ class _BoardScreenState extends State with Service { archiveCardsInList(trello.lstbrd[index]) .then((numCardsArchived) { // ignore: use_build_context_synchronously - StatusAlert.show(context, + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( duration: const Duration(seconds: 2), - title: - '$numCardsArchived Cards Archived', - configuration: const IconConfiguration( - icon: Icons.archive_outlined, - color: brandColor), - maxWidth: 260); + margin: EdgeInsets.only( + bottom: MediaQuery.of(context) + .size + .height * + 0.1, // 10% from bottom + right: 20, + left: 20, + ), + content: Row( + children: [ + const Icon(Icons.archive_outlined, + color: brandColor), + const SizedBox(width: 12), + Text( + '$numCardsArchived Cards Archived'), + ], + ), + width: 260, + behavior: SnackBarBehavior.floating, + ), + ); // ignore: use_build_context_synchronously Navigator.of(context).pop(); }); diff --git a/demos/supabase-trello/lib/features/invitemember/presentation/index.dart b/demos/supabase-trello/lib/features/invitemember/presentation/index.dart index 24d57602..62be7d6f 100644 --- a/demos/supabase-trello/lib/features/invitemember/presentation/index.dart +++ b/demos/supabase-trello/lib/features/invitemember/presentation/index.dart @@ -1,5 +1,4 @@ import 'package:flutter/material.dart'; -import 'package:status_alert/status_alert.dart'; import 'package:trelloappclone_flutter/utils/color.dart'; import 'package:trelloappclone_flutter/utils/service.dart'; import 'package:trelloappclone_flutter/models/member.dart'; @@ -74,24 +73,66 @@ class _InviteMemberState extends State with Service { .addAll(trello.selectedWorkspace.members ?? []); }); // ignore: use_build_context_synchronously - StatusAlert.show(context, + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( duration: const Duration(seconds: 3), - title: 'Added Member', - subtitle: - '${emailcontroller.text} added to workspace.', - configuration: const IconConfiguration( - icon: Icons.check, color: brandColor), - maxWidth: 260); + margin: EdgeInsets.only( + bottom: MediaQuery.of(context).size.height * + 0.1, // 10% from bottom + right: 20, + left: 20, + ), + content: Column( + mainAxisSize: MainAxisSize.min, + children: [ + const Row( + children: [ + Icon(Icons.check, color: brandColor), + SizedBox(width: 12), + Text('Added Member'), + ], + ), + const SizedBox(height: 4), + Text( + '${emailcontroller.text} added to workspace.'), + ], + ), + width: 260, + behavior: SnackBarBehavior.floating, + ), + ); } else { // ignore: use_build_context_synchronously - StatusAlert.show(context, + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( duration: const Duration(seconds: 3), - title: 'Add Failed', - subtitle: - '${emailcontroller.text} not an existing user.', - configuration: const IconConfiguration( - icon: Icons.error_outline, color: brandColor), - maxWidth: 260); + margin: EdgeInsets.only( + bottom: MediaQuery.of(context).size.height * + 0.1, // 10% from bottom + right: 20, + left: 20, + ), + backgroundColor: Colors.red[100], + content: Column( + mainAxisSize: MainAxisSize.min, + children: [ + const Row( + children: [ + Icon(Icons.error_outline, + color: Colors.red), + SizedBox(width: 12), + Text('Add Failed'), + ], + ), + const SizedBox(height: 4), + Text( + '${emailcontroller.text} not an existing user.'), + ], + ), + width: 260, + behavior: SnackBarBehavior.floating, + ), + ); } }); }, diff --git a/demos/supabase-trello/lib/features/signtotrello/presentation/index.dart b/demos/supabase-trello/lib/features/signtotrello/presentation/index.dart index 6eb78bd5..7dc3f026 100644 --- a/demos/supabase-trello/lib/features/signtotrello/presentation/index.dart +++ b/demos/supabase-trello/lib/features/signtotrello/presentation/index.dart @@ -109,11 +109,11 @@ class _SignToTrelloState extends State with Service { signUp( name: usernamecontroller.text, email: emailcontroller.text, - password: encryptPassword(passwordcontroller.text), + password: passwordcontroller.text, context: context); } else if (args.type == Sign.logIn && validateLogin()) { - logIn(emailcontroller.text, - encryptPassword(passwordcontroller.text), context); + logIn(emailcontroller.text, passwordcontroller.text, + context); } }, style: diff --git a/demos/supabase-trello/lib/utils/data_generator.dart b/demos/supabase-trello/lib/utils/data_generator.dart index 5a7c6f37..387ace81 100644 --- a/demos/supabase-trello/lib/utils/data_generator.dart +++ b/demos/supabase-trello/lib/utils/data_generator.dart @@ -4,7 +4,6 @@ import 'dart:math'; import 'package:flutter/material.dart'; import 'package:random_name_generator/random_name_generator.dart'; -import 'package:status_alert/status_alert.dart'; import 'package:trelloappclone_flutter/utils/color.dart'; import 'package:trelloappclone_flutter/utils/config.dart'; import 'package:trelloappclone_flutter/utils/service.dart'; @@ -44,12 +43,25 @@ class DataGenerator with Service { createSampleWorkspace( String workspaceName, TrelloProvider trello, BuildContext context) async { - StatusAlert.show(context, + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( duration: const Duration(seconds: 3), - title: 'Generating Workspace Data...', - configuration: - const IconConfiguration(icon: Icons.sync, color: brandColor), - maxWidth: 260); + margin: EdgeInsets.only( + bottom: MediaQuery.of(context).size.height * 0.1, // 10% from bottom + right: 20, + left: 20, + ), + content: const Row( + children: [ + Icon(Icons.sync, color: brandColor), + SizedBox(width: 12), + Text('Generating Workspace Data...'), + ], + ), + width: 260, + behavior: SnackBarBehavior.floating, + ), + ); Workspace workspace = await createWorkspace(context, name: workspaceName, diff --git a/demos/supabase-trello/lib/utils/service.dart b/demos/supabase-trello/lib/utils/service.dart index c32fc85f..ecbd6311 100644 --- a/demos/supabase-trello/lib/utils/service.dart +++ b/demos/supabase-trello/lib/utils/service.dart @@ -6,7 +6,6 @@ import 'dart:developer'; import 'package:crypto/crypto.dart'; import 'package:file_picker/file_picker.dart'; import 'package:flutter/material.dart' hide Card; -import 'package:status_alert/status_alert.dart'; import 'package:trelloappclone_flutter/features/home/presentation/custom_search.dart'; import 'package:trelloappclone_flutter/utils/color.dart'; import 'package:trelloappclone_flutter/models/listboard.dart'; @@ -46,27 +45,73 @@ mixin Service { if (context.mounted) { Navigator.pushNamed(context, '/'); - StatusAlert.show(context, + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( duration: const Duration(seconds: 3), - title: 'Account Created', - subtitle: 'Log in with your new credentials', - subtitleOptions: StatusAlertTextConfiguration( - softWrap: true, maxLines: 3, overflow: TextOverflow.ellipsis), - configuration: - const IconConfiguration(icon: Icons.check, color: brandColor), - maxWidth: 260); + margin: EdgeInsets.only( + bottom: + MediaQuery.of(context).size.height * 0.1, // 10% from bottom + right: 20, + left: 20, + ), + content: const Column( + mainAxisSize: MainAxisSize.min, + children: [ + Row( + children: [ + Icon(Icons.check, color: brandColor), + SizedBox(width: 12), + Text('Account Created'), + ], + ), + SizedBox(height: 4), + Text( + 'Log in with your new credentials', + softWrap: true, + maxLines: 3, + overflow: TextOverflow.ellipsis, + ), + ], + ), + width: 260, + behavior: SnackBarBehavior.floating, + ), + ); } } on Exception catch (e) { log('Error with signup: $e', error: e); - StatusAlert.show(context, + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( duration: const Duration(seconds: 5), - title: 'Sign Up Error', - subtitle: e.toString(), - subtitleOptions: StatusAlertTextConfiguration( - softWrap: true, maxLines: 3, overflow: TextOverflow.ellipsis), - configuration: - const IconConfiguration(icon: Icons.check, color: brandColor), - maxWidth: 260); + margin: EdgeInsets.only( + bottom: MediaQuery.of(context).size.height * 0.1, // 10% from bottom + right: 20, + left: 20, + ), + backgroundColor: Colors.red[100], + content: Column( + mainAxisSize: MainAxisSize.min, + children: [ + const Row( + children: [ + Icon(Icons.error, color: Colors.red), + SizedBox(width: 12), + Text('Sign Up Error'), + ], + ), + const SizedBox(height: 4), + Text( + e.toString(), + softWrap: true, + maxLines: 3, + overflow: TextOverflow.ellipsis, + ), + ], + ), + width: 260, + behavior: SnackBarBehavior.floating, + ), + ); } } @@ -78,24 +123,55 @@ mixin Service { if (context.mounted) { Navigator.pushNamed(context, '/home'); - StatusAlert.show(context, - duration: const Duration(seconds: 5), - title: 'Syncing Workspaces...', - configuration: - const IconConfiguration(icon: Icons.sync, color: brandColor), - maxWidth: 260); + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + duration: Duration(seconds: 5), + content: Row( + children: [ + Icon(Icons.sync, color: brandColor), + SizedBox(width: 12), + Text('Syncing Workspaces...'), + ], + ), + width: 260, + behavior: SnackBarBehavior.floating, + ), + ); } } on Exception catch (e) { log('Error with login: $e', error: e); - StatusAlert.show(context, + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( duration: const Duration(seconds: 5), - title: 'Login Error', - subtitle: e.toString(), - subtitleOptions: StatusAlertTextConfiguration( - softWrap: true, maxLines: 3, overflow: TextOverflow.ellipsis), - configuration: - const IconConfiguration(icon: Icons.check, color: brandColor), - maxWidth: 260); + margin: EdgeInsets.only( + bottom: MediaQuery.of(context).size.height * 0.1, // 10% from bottom + right: 20, + left: 20, + ), + backgroundColor: Colors.red[100], + content: Column( + mainAxisSize: MainAxisSize.min, + children: [ + const Row( + children: [ + Icon(Icons.error, color: Colors.red), + SizedBox(width: 12), + Text('Login Error'), + ], + ), + const SizedBox(height: 4), + Text( + e.toString(), + softWrap: true, + maxLines: 3, + overflow: TextOverflow.ellipsis, + ), + ], + ), + width: 260, + behavior: SnackBarBehavior.floating, + ), + ); } } @@ -104,15 +180,38 @@ mixin Service { try { await dataClient.logOut(); } on Exception catch (e) { - StatusAlert.show(context, + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( duration: const Duration(seconds: 5), - title: 'Logout Error', - subtitle: e.toString(), - subtitleOptions: StatusAlertTextConfiguration( - softWrap: true, maxLines: 3, overflow: TextOverflow.ellipsis), - configuration: - const IconConfiguration(icon: Icons.check, color: brandColor), - maxWidth: 260); + margin: EdgeInsets.only( + bottom: MediaQuery.of(context).size.height * 0.1, // 10% from bottom + right: 20, + left: 20, + ), + backgroundColor: Colors.red[100], + content: Column( + mainAxisSize: MainAxisSize.min, + children: [ + const Row( + children: [ + Icon(Icons.error, color: Colors.red), + SizedBox(width: 12), + Text('Logout Error'), + ], + ), + const SizedBox(height: 4), + Text( + e.toString(), + softWrap: true, + maxLines: 3, + overflow: TextOverflow.ellipsis, + ), + ], + ), + width: 260, + behavior: SnackBarBehavior.floating, + ), + ); } } @@ -133,13 +232,6 @@ mixin Service { } } - //encrypt password - String encryptPassword(String password) { - final bytes = utf8.encode(password); - final hash = sha256.convert(bytes); - return hash.toString(); - } - //create workspace createWorkspace(BuildContext context, {required String name, @@ -171,13 +263,32 @@ mixin Service { return addedWorkspace; } on Exception catch (e) { - StatusAlert.show(context, + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( duration: const Duration(seconds: 5), - title: 'Trello Clone', - subtitle: e.toString(), - configuration: - const IconConfiguration(icon: Icons.check, color: brandColor), - maxWidth: 260); + margin: EdgeInsets.only( + bottom: MediaQuery.of(context).size.height * 0.1, // 10% from bottom + right: 20, + left: 20, + ), + content: Column( + mainAxisSize: MainAxisSize.min, + children: [ + const Row( + children: [ + Icon(Icons.check, color: brandColor), + SizedBox(width: 12), + Text('Trello Clone'), + ], + ), + const SizedBox(height: 4), + Text(e.toString()), + ], + ), + width: 260, + behavior: SnackBarBehavior.floating, + ), + ); } } @@ -227,13 +338,32 @@ mixin Service { Navigator.pushNamed(context, "/home"); } } on Exception catch (e) { - StatusAlert.show(context, + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( duration: const Duration(seconds: 5), - title: 'Trello Clone', - subtitle: e.toString(), - configuration: - const IconConfiguration(icon: Icons.check, color: brandColor), - maxWidth: 260); + margin: EdgeInsets.only( + bottom: MediaQuery.of(context).size.height * 0.1, // 10% from bottom + right: 20, + left: 20, + ), + content: Column( + mainAxisSize: MainAxisSize.min, + children: [ + const Row( + children: [ + Icon(Icons.check, color: brandColor), + SizedBox(width: 12), + Text('Trello Clone'), + ], + ), + const SizedBox(height: 4), + Text(e.toString()), + ], + ), + width: 260, + behavior: SnackBarBehavior.floating, + ), + ); } } diff --git a/demos/supabase-trello/pubspec.lock b/demos/supabase-trello/pubspec.lock index 564a44d3..28987d55 100644 --- a/demos/supabase-trello/pubspec.lock +++ b/demos/supabase-trello/pubspec.lock @@ -157,10 +157,10 @@ packages: dependency: "direct main" description: name: file_picker - sha256: "1bbf65dd997458a08b531042ec3794112a6c39c07c37ff22113d2e7e4f81d4e4" + sha256: c904b4ab56d53385563c7c39d8e9fa9af086f91495dfc48717ad84a42c3cf204 url: "https://pub.dev" source: hosted - version: "6.2.1" + version: "8.1.7" file_selector_linux: dependency: transitive description: @@ -201,14 +201,6 @@ packages: url: "https://pub.dev" source: hosted version: "1.1.1" - flare_flutter: - dependency: transitive - description: - name: flare_flutter - sha256: "99d63c60f00fac81249ce6410ee015d7b125c63d8278a30da81edf3317a1f6a0" - url: "https://pub.dev" - source: hosted - version: "3.0.2" flutter: dependency: "direct main" description: flutter @@ -564,10 +556,10 @@ packages: dependency: transitive description: name: postgrest - sha256: "9f759ac497a24839addbed69d9569ea6d51d2e4834c672b8c2a73752fb6945c8" + sha256: b74dc0f57b5dca5ce9f57a54b08110bf41d6fc8a0483c0fec10c79e9aa0fb2bb url: "https://pub.dev" source: hosted - version: "2.4.0" + version: "2.4.1" powersync: dependency: "direct main" description: @@ -762,14 +754,6 @@ packages: url: "https://pub.dev" source: hosted version: "1.12.0" - status_alert: - dependency: "direct main" - description: - name: status_alert - sha256: "220ce6c1400d19d817665ac5a87f772e87c901677ac37b93320f4764edf4d23f" - url: "https://pub.dev" - source: hosted - version: "1.0.1" storage_client: dependency: transitive description: @@ -798,18 +782,18 @@ packages: dependency: transitive description: name: supabase - sha256: ea3daaf4fc76df9bf42ca00142f8d07b94400943a93d563e87f5575ea78f1c2c + sha256: "270f63cd87a16578fee87e40cbf61062e8cdbce68d5e723e665f4651d70ddd8c" url: "https://pub.dev" source: hosted - version: "2.6.1" + version: "2.6.2" supabase_flutter: dependency: "direct main" description: name: supabase_flutter - sha256: e8b321706a9b88c60f5fe695305f34917ad2ee55aea0b3af987638c7b0793e13 + sha256: ca8dfe3d4b109e7338cdf7778f3ec2c660a0178006876bfac343eb39b0f3d1e3 url: "https://pub.dev" source: hosted - version: "2.8.2" + version: "2.8.3" term_glyph: dependency: transitive description: diff --git a/demos/supabase-trello/pubspec.yaml b/demos/supabase-trello/pubspec.yaml index 26fc55e7..df7341bc 100644 --- a/demos/supabase-trello/pubspec.yaml +++ b/demos/supabase-trello/pubspec.yaml @@ -26,23 +26,22 @@ dependencies: # The following adds the Cupertino Icons font to your application. # Use with the CupertinoIcons class for iOS style icons. - cupertino_icons: ^1.0.5 - google_fonts: ^6.1.0 - flutter_expandable_fab: ^2.0.0 + cupertino_icons: ^1.0.8 + google_fonts: ^6.2.1 + flutter_expandable_fab: ^2.3.0 material_design_icons_flutter: ^7.0.7296 - crypto: ^3.0.3 - provider: ^6.0.5 - status_alert: ^1.0.1 - image_picker: ^1.0.4 - file_picker: ^6.1.1 - random_name_generator: ^1.2.0 - flutter_dotenv: ^5.1.0 - logging: ^1.1.1 - powersync: ^1.10.0 + crypto: ^3.0.6 + provider: ^6.1.2 + image_picker: ^1.1.2 + file_picker: ^8.1.7 + random_name_generator: ^1.5.0 + flutter_dotenv: ^5.2.1 + logging: ^1.3.0 + powersync: ^1.11.0 sqlite_async: ^0.11.0 - path_provider: ^2.0.12 - supabase_flutter: ^2.8.2 - path: ^1.8.2 + path_provider: ^2.1.5 + supabase_flutter: ^2.8.3 + path: 1.9.0 dev_dependencies: flutter_lints: ^3.0.1 From b284b07f1fa8fbd2850a32efd3b299e22a3ab0b0 Mon Sep 17 00:00:00 2001 From: DominicGBauer Date: Fri, 10 Jan 2025 16:53:16 +0200 Subject: [PATCH 09/10] fix: image --- demos/supabase-trello/lib/features/home/presentation/index.dart | 2 -- 1 file changed, 2 deletions(-) diff --git a/demos/supabase-trello/lib/features/home/presentation/index.dart b/demos/supabase-trello/lib/features/home/presentation/index.dart index ec0287a7..3cb27211 100644 --- a/demos/supabase-trello/lib/features/home/presentation/index.dart +++ b/demos/supabase-trello/lib/features/home/presentation/index.dart @@ -35,7 +35,6 @@ class _HomeState extends State with Service { _connectionState = dataClient.getCurrentSyncStatus(); _syncStatusSubscription = dataClient.getStatusStream().listen((event) { - log.info('Sync Status: $event'); setState(() { _connectionState = event; }); @@ -96,7 +95,6 @@ class _HomeState extends State with Service { padding: EdgeInsets.all(20.0), child: EmptyWidget( image: null, - packageImage: PackageImage.Image_1, title: 'No Boards', subTitle: 'Create your first Trello board', titleTextStyle: TextStyle( From 1ace367d6771e19956ca7bf4de32f0df579f56a5 Mon Sep 17 00:00:00 2001 From: DominicGBauer Date: Fri, 10 Jan 2025 17:17:33 +0200 Subject: [PATCH 10/10] chore: fix lint --- .../lib/features/board/presentation/index.dart | 2 +- .../lib/features/invitemember/presentation/index.dart | 4 ++-- demos/supabase-trello/lib/utils/data_generator.dart | 1 - demos/supabase-trello/lib/utils/service.dart | 9 --------- demos/supabase-trello/pubspec.yaml | 1 - 5 files changed, 3 insertions(+), 14 deletions(-) diff --git a/demos/supabase-trello/lib/features/board/presentation/index.dart b/demos/supabase-trello/lib/features/board/presentation/index.dart index 2623dac5..cf9b7309 100644 --- a/demos/supabase-trello/lib/features/board/presentation/index.dart +++ b/demos/supabase-trello/lib/features/board/presentation/index.dart @@ -376,6 +376,7 @@ class _BoardScreenState extends State with Service { SnackBar( duration: const Duration(seconds: 2), margin: EdgeInsets.only( + // ignore: use_build_context_synchronously bottom: MediaQuery.of(context) .size .height * @@ -392,7 +393,6 @@ class _BoardScreenState extends State with Service { '$numCardsArchived Cards Archived'), ], ), - width: 260, behavior: SnackBarBehavior.floating, ), ); diff --git a/demos/supabase-trello/lib/features/invitemember/presentation/index.dart b/demos/supabase-trello/lib/features/invitemember/presentation/index.dart index 62be7d6f..cb63d80f 100644 --- a/demos/supabase-trello/lib/features/invitemember/presentation/index.dart +++ b/demos/supabase-trello/lib/features/invitemember/presentation/index.dart @@ -77,6 +77,7 @@ class _InviteMemberState extends State with Service { SnackBar( duration: const Duration(seconds: 3), margin: EdgeInsets.only( + // ignore: use_build_context_synchronously bottom: MediaQuery.of(context).size.height * 0.1, // 10% from bottom right: 20, @@ -97,7 +98,6 @@ class _InviteMemberState extends State with Service { '${emailcontroller.text} added to workspace.'), ], ), - width: 260, behavior: SnackBarBehavior.floating, ), ); @@ -107,6 +107,7 @@ class _InviteMemberState extends State with Service { SnackBar( duration: const Duration(seconds: 3), margin: EdgeInsets.only( + // ignore: use_build_context_synchronously bottom: MediaQuery.of(context).size.height * 0.1, // 10% from bottom right: 20, @@ -129,7 +130,6 @@ class _InviteMemberState extends State with Service { '${emailcontroller.text} not an existing user.'), ], ), - width: 260, behavior: SnackBarBehavior.floating, ), ); diff --git a/demos/supabase-trello/lib/utils/data_generator.dart b/demos/supabase-trello/lib/utils/data_generator.dart index 387ace81..e85c2cdb 100644 --- a/demos/supabase-trello/lib/utils/data_generator.dart +++ b/demos/supabase-trello/lib/utils/data_generator.dart @@ -58,7 +58,6 @@ class DataGenerator with Service { Text('Generating Workspace Data...'), ], ), - width: 260, behavior: SnackBarBehavior.floating, ), ); diff --git a/demos/supabase-trello/lib/utils/service.dart b/demos/supabase-trello/lib/utils/service.dart index ecbd6311..a1f46a6a 100644 --- a/demos/supabase-trello/lib/utils/service.dart +++ b/demos/supabase-trello/lib/utils/service.dart @@ -1,9 +1,7 @@ // ignore_for_file: use_build_context_synchronously -import 'dart:convert'; import 'dart:developer'; -import 'package:crypto/crypto.dart'; import 'package:file_picker/file_picker.dart'; import 'package:flutter/material.dart' hide Card; import 'package:trelloappclone_flutter/features/home/presentation/custom_search.dart'; @@ -73,7 +71,6 @@ mixin Service { ), ], ), - width: 260, behavior: SnackBarBehavior.floating, ), ); @@ -108,7 +105,6 @@ mixin Service { ), ], ), - width: 260, behavior: SnackBarBehavior.floating, ), ); @@ -133,7 +129,6 @@ mixin Service { Text('Syncing Workspaces...'), ], ), - width: 260, behavior: SnackBarBehavior.floating, ), ); @@ -168,7 +163,6 @@ mixin Service { ), ], ), - width: 260, behavior: SnackBarBehavior.floating, ), ); @@ -208,7 +202,6 @@ mixin Service { ), ], ), - width: 260, behavior: SnackBarBehavior.floating, ), ); @@ -285,7 +278,6 @@ mixin Service { Text(e.toString()), ], ), - width: 260, behavior: SnackBarBehavior.floating, ), ); @@ -360,7 +352,6 @@ mixin Service { Text(e.toString()), ], ), - width: 260, behavior: SnackBarBehavior.floating, ), ); diff --git a/demos/supabase-trello/pubspec.yaml b/demos/supabase-trello/pubspec.yaml index df7341bc..6036085e 100644 --- a/demos/supabase-trello/pubspec.yaml +++ b/demos/supabase-trello/pubspec.yaml @@ -30,7 +30,6 @@ dependencies: google_fonts: ^6.2.1 flutter_expandable_fab: ^2.3.0 material_design_icons_flutter: ^7.0.7296 - crypto: ^3.0.6 provider: ^6.1.2 image_picker: ^1.1.2 file_picker: ^8.1.7