├── linux ├── .gitignore ├── main.cc ├── flutter │ ├── generated_plugin_registrant.h │ ├── generated_plugins.cmake │ ├── generated_plugin_registrant.cc │ └── CMakeLists.txt ├── my_application.h ├── my_application.cc └── CMakeLists.txt ├── ios ├── Flutter │ ├── Debug.xcconfig │ ├── Release.xcconfig │ └── AppFrameworkInfo.plist ├── Runner │ ├── Runner-Bridging-Header.h │ ├── Assets.xcassets │ │ ├── LaunchImage.imageset │ │ │ ├── LaunchImage.png │ │ │ ├── LaunchImage@2x.png │ │ │ ├── LaunchImage@3x.png │ │ │ ├── README.md │ │ │ └── Contents.json │ │ └── AppIcon.appiconset │ │ │ ├── Icon-App-20x20@1x.png │ │ │ ├── Icon-App-20x20@2x.png │ │ │ ├── Icon-App-20x20@3x.png │ │ │ ├── Icon-App-29x29@1x.png │ │ │ ├── Icon-App-29x29@2x.png │ │ │ ├── Icon-App-29x29@3x.png │ │ │ ├── Icon-App-40x40@1x.png │ │ │ ├── Icon-App-40x40@2x.png │ │ │ ├── Icon-App-40x40@3x.png │ │ │ ├── Icon-App-60x60@2x.png │ │ │ ├── Icon-App-60x60@3x.png │ │ │ ├── Icon-App-76x76@1x.png │ │ │ ├── Icon-App-76x76@2x.png │ │ │ ├── Icon-App-1024x1024@1x.png │ │ │ ├── Icon-App-83.5x83.5@2x.png │ │ │ └── Contents.json │ ├── AppDelegate.swift │ ├── Base.lproj │ │ ├── Main.storyboard │ │ └── LaunchScreen.storyboard │ └── Info.plist ├── Runner.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ ├── WorkspaceSettings.xcsettings │ │ └── IDEWorkspaceChecks.plist ├── Runner.xcodeproj │ ├── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ ├── WorkspaceSettings.xcsettings │ │ │ └── IDEWorkspaceChecks.plist │ └── xcshareddata │ │ └── xcschemes │ │ └── Runner.xcscheme └── .gitignore ├── plugins ├── menubar │ ├── .gitignore │ ├── analysis_options.yaml │ ├── ios │ │ ├── Classes │ │ │ ├── MenubarPlugin.h │ │ │ └── MenubarPlugin.m │ │ ├── .gitignore │ │ └── menubar.podspec │ ├── pubspec.yaml │ ├── linux │ │ ├── CMakeLists.txt │ │ └── include │ │ │ └── menubar │ │ │ └── menubar_plugin.h │ ├── lib │ │ ├── menubar.dart │ │ └── src │ │ │ ├── set_application_menu.dart │ │ │ └── menu_item.dart │ ├── README.md │ └── macos │ │ ├── Classes │ │ ├── MenubarPlugin.swift │ │ ├── FLEMenubarPlugin.h │ │ └── FLEMenubarPlugin.m │ │ └── menubar.podspec ├── color_panel │ ├── .gitignore │ ├── analysis_options.yaml │ ├── ios │ │ ├── Classes │ │ │ ├── ColorPanelPlugin.h │ │ │ └── ColorPanelPlugin.m │ │ ├── .gitignore │ │ └── color_panel.podspec │ ├── README.md │ ├── pubspec.yaml │ ├── linux │ │ ├── CMakeLists.txt │ │ ├── include │ │ │ └── color_panel │ │ │ │ └── color_panel_plugin.h │ │ └── color_panel_plugin.cc │ ├── macos │ │ ├── color_panel.podspec │ │ └── Classes │ │ │ ├── ColorPanelPlugin.swift │ │ │ ├── FLEColorPanelPlugin.h │ │ │ └── FLEColorPanelPlugin.m │ └── lib │ │ └── color_panel.dart ├── file_chooser │ ├── analysis_options.yaml │ ├── .gitignore │ ├── ios │ │ ├── Classes │ │ │ ├── FileChooserPlugin.h │ │ │ └── FileChooserPlugin.m │ │ ├── .gitignore │ │ └── file_chooser.podspec │ ├── windows │ │ ├── .gitignore │ │ ├── CMakeLists.txt │ │ └── include │ │ │ └── file_chooser │ │ │ └── file_chooser_plugin.h │ ├── pubspec.yaml │ ├── linux │ │ ├── CMakeLists.txt │ │ ├── include │ │ │ └── file_chooser │ │ │ │ └── file_chooser_plugin.h │ │ └── file_chooser_plugin.cc │ ├── lib │ │ ├── file_chooser.dart │ │ └── src │ │ │ ├── result.dart │ │ │ ├── filter_group.dart │ │ │ ├── utilities.dart │ │ │ └── channel_controller.dart │ ├── macos │ │ ├── file_chooser.podspec │ │ └── Classes │ │ │ ├── FileChooserPlugin.swift │ │ │ ├── FLEFileChooserPlugin.h │ │ │ └── FLEFileChooserPlugin.m │ └── README.md ├── window_size │ ├── .gitignore │ ├── analysis_options.yaml │ ├── ios │ │ ├── Classes │ │ │ ├── WindowSizePlugin.h │ │ │ └── WindowSizePlugin.m │ │ ├── .gitignore │ │ └── window_size.podspec │ ├── windows │ │ ├── .gitignore │ │ ├── CMakeLists.txt │ │ ├── include │ │ │ └── window_size │ │ │ │ └── window_size_plugin.h │ │ └── window_size_plugin.cpp │ ├── pubspec.yaml │ ├── linux │ │ ├── CMakeLists.txt │ │ └── include │ │ │ └── window_size │ │ │ └── window_size_plugin.h │ ├── lib │ │ ├── window_size.dart │ │ └── src │ │ │ ├── screen.dart │ │ │ ├── platform_window.dart │ │ │ └── window_size_utils.dart │ ├── README.md │ └── macos │ │ ├── Classes │ │ ├── WindowSizePlugin.swift │ │ ├── FLEWindowSizePlugin.h │ │ └── FLEWindowSizePlugin.m │ │ └── window_size.podspec ├── flutter_plugins │ ├── url_launcher_fde │ │ ├── .gitignore │ │ ├── windows │ │ │ ├── .gitignore │ │ │ ├── CMakeLists.txt │ │ │ ├── include │ │ │ │ └── url_launcher_fde │ │ │ │ │ └── url_launcher_plugin.h │ │ │ └── url_launcher_plugin.cpp │ │ ├── pubspec.yaml │ │ ├── README.md │ │ └── ios │ │ │ └── url_launcher_fde.podspec │ ├── path_provider_fde │ │ ├── .gitignore │ │ ├── windows │ │ │ ├── .gitignore │ │ │ ├── CMakeLists.txt │ │ │ ├── include │ │ │ │ └── path_provider_fde │ │ │ │ │ └── path_provider_plugin.h │ │ │ └── path_provider_plugin.cpp │ │ ├── pubspec.yaml │ │ ├── README.md │ │ └── ios │ │ │ └── path_provider_fde.podspec │ └── README.md └── README.md ├── README.md ├── android ├── gradle.properties ├── app │ ├── src │ │ ├── main │ │ │ ├── res │ │ │ │ ├── mipmap-hdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-mdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-xhdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-xxhdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-xxxhdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ ├── drawable │ │ │ │ │ └── launch_background.xml │ │ │ │ └── values │ │ │ │ │ └── styles.xml │ │ │ ├── kotlin │ │ │ │ └── com │ │ │ │ │ └── example │ │ │ │ │ └── counter │ │ │ │ │ └── MainActivity.kt │ │ │ └── AndroidManifest.xml │ │ ├── debug │ │ │ └── AndroidManifest.xml │ │ └── profile │ │ │ └── AndroidManifest.xml │ └── build.gradle ├── gradle │ └── wrapper │ │ └── gradle-wrapper.properties ├── .gitignore ├── settings.gradle └── build.gradle ├── .metadata ├── .gitignore ├── pubspec.yaml ├── test └── widget_test.dart └── lib └── countdown_timer.dart /linux/.gitignore: -------------------------------------------------------------------------------- 1 | flutter/ephemeral 2 | -------------------------------------------------------------------------------- /ios/Flutter/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Generated.xcconfig" 2 | -------------------------------------------------------------------------------- /ios/Flutter/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Generated.xcconfig" 2 | -------------------------------------------------------------------------------- /ios/Runner/Runner-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | #import "GeneratedPluginRegistrant.h" 2 | -------------------------------------------------------------------------------- /plugins/menubar/.gitignore: -------------------------------------------------------------------------------- 1 | .packages 2 | .flutter-plugins 3 | pubspec.lock 4 | -------------------------------------------------------------------------------- /plugins/menubar/analysis_options.yaml: -------------------------------------------------------------------------------- 1 | include: ../../analysis_options.yaml 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![](https://s7.gifyu.com/images/Screencast-2020-07-11-112652.gif) 2 | -------------------------------------------------------------------------------- /plugins/color_panel/.gitignore: -------------------------------------------------------------------------------- 1 | .packages 2 | .flutter-plugins 3 | pubspec.lock 4 | -------------------------------------------------------------------------------- /plugins/color_panel/analysis_options.yaml: -------------------------------------------------------------------------------- 1 | include: ../../analysis_options.yaml 2 | -------------------------------------------------------------------------------- /plugins/file_chooser/analysis_options.yaml: -------------------------------------------------------------------------------- 1 | include: ../../analysis_options.yaml 2 | -------------------------------------------------------------------------------- /plugins/window_size/.gitignore: -------------------------------------------------------------------------------- 1 | .packages 2 | .flutter-plugins 3 | pubspec.lock 4 | -------------------------------------------------------------------------------- /plugins/window_size/analysis_options.yaml: -------------------------------------------------------------------------------- 1 | include: ../../analysis_options.yaml 2 | -------------------------------------------------------------------------------- /plugins/flutter_plugins/url_launcher_fde/.gitignore: -------------------------------------------------------------------------------- 1 | .packages 2 | .flutter-plugins 3 | pubspec.lock 4 | -------------------------------------------------------------------------------- /plugins/file_chooser/.gitignore: -------------------------------------------------------------------------------- 1 | .dart_tool 2 | .packages 3 | .flutter-plugins 4 | .flutter-plugins-dependencies 5 | pubspec.lock 6 | -------------------------------------------------------------------------------- /android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx1536M 2 | android.enableR8=true 3 | android.useAndroidX=true 4 | android.enableJetifier=true 5 | -------------------------------------------------------------------------------- /plugins/menubar/ios/Classes/MenubarPlugin.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @interface MenubarPlugin : NSObject 4 | @end 5 | -------------------------------------------------------------------------------- /plugins/flutter_plugins/path_provider_fde/.gitignore: -------------------------------------------------------------------------------- 1 | .dart_tool 2 | .packages 3 | .flutter-plugins 4 | .flutter-plugins-dependencies 5 | pubspec.lock 6 | -------------------------------------------------------------------------------- /plugins/color_panel/ios/Classes/ColorPanelPlugin.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @interface ColorPanelPlugin : NSObject 4 | @end 5 | -------------------------------------------------------------------------------- /plugins/file_chooser/ios/Classes/FileChooserPlugin.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @interface FileChooserPlugin : NSObject 4 | @end 5 | -------------------------------------------------------------------------------- /plugins/window_size/ios/Classes/WindowSizePlugin.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @interface WindowSizePlugin : NSObject 4 | @end 5 | -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AliAnilKocak/PomodoroTimerLinuxDesktop/HEAD/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AliAnilKocak/PomodoroTimerLinuxDesktop/HEAD/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AliAnilKocak/PomodoroTimerLinuxDesktop/HEAD/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AliAnilKocak/PomodoroTimerLinuxDesktop/HEAD/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AliAnilKocak/PomodoroTimerLinuxDesktop/HEAD/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AliAnilKocak/PomodoroTimerLinuxDesktop/HEAD/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AliAnilKocak/PomodoroTimerLinuxDesktop/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AliAnilKocak/PomodoroTimerLinuxDesktop/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AliAnilKocak/PomodoroTimerLinuxDesktop/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AliAnilKocak/PomodoroTimerLinuxDesktop/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AliAnilKocak/PomodoroTimerLinuxDesktop/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AliAnilKocak/PomodoroTimerLinuxDesktop/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AliAnilKocak/PomodoroTimerLinuxDesktop/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AliAnilKocak/PomodoroTimerLinuxDesktop/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AliAnilKocak/PomodoroTimerLinuxDesktop/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AliAnilKocak/PomodoroTimerLinuxDesktop/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AliAnilKocak/PomodoroTimerLinuxDesktop/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AliAnilKocak/PomodoroTimerLinuxDesktop/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AliAnilKocak/PomodoroTimerLinuxDesktop/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AliAnilKocak/PomodoroTimerLinuxDesktop/HEAD/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AliAnilKocak/PomodoroTimerLinuxDesktop/HEAD/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png -------------------------------------------------------------------------------- /plugins/menubar/ios/Classes/MenubarPlugin.m: -------------------------------------------------------------------------------- 1 | #import "MenubarPlugin.h" 2 | 3 | @implementation MenubarPlugin 4 | + (void)registerWithRegistrar:(NSObject*)registrar {} 5 | 6 | @end 7 | -------------------------------------------------------------------------------- /android/app/src/main/kotlin/com/example/counter/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.example.counter 2 | 3 | import io.flutter.embedding.android.FlutterActivity 4 | 5 | class MainActivity: FlutterActivity() { 6 | } 7 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AliAnilKocak/PomodoroTimerLinuxDesktop/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AliAnilKocak/PomodoroTimerLinuxDesktop/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png -------------------------------------------------------------------------------- /linux/main.cc: -------------------------------------------------------------------------------- 1 | #include "my_application.h" 2 | 3 | int main(int argc, char** argv) { 4 | g_autoptr(MyApplication) app = my_application_new(); 5 | return g_application_run(G_APPLICATION(app), argc, argv); 6 | } 7 | -------------------------------------------------------------------------------- /plugins/color_panel/ios/Classes/ColorPanelPlugin.m: -------------------------------------------------------------------------------- 1 | #import "ColorPanelPlugin.h" 2 | 3 | @implementation ColorPanelPlugin 4 | + (void)registerWithRegistrar:(NSObject*)registrar {} 5 | 6 | @end 7 | -------------------------------------------------------------------------------- /plugins/window_size/ios/Classes/WindowSizePlugin.m: -------------------------------------------------------------------------------- 1 | #import "WindowSizePlugin.h" 2 | 3 | @implementation WindowSizePlugin 4 | + (void)registerWithRegistrar:(NSObject*)registrar {} 5 | 6 | @end 7 | -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /plugins/file_chooser/ios/Classes/FileChooserPlugin.m: -------------------------------------------------------------------------------- 1 | #import "FileChooserPlugin.h" 2 | 3 | @implementation FileChooserPlugin 4 | + (void)registerWithRegistrar:(NSObject*)registrar {} 5 | 6 | @end 7 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Fri Jun 23 08:50:38 CEST 2017 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip 7 | -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /android/.gitignore: -------------------------------------------------------------------------------- 1 | gradle-wrapper.jar 2 | /.gradle 3 | /captures/ 4 | /gradlew 5 | /gradlew.bat 6 | /local.properties 7 | GeneratedPluginRegistrant.java 8 | 9 | # Remember to never publicly share your keystore. 10 | # See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app 11 | key.properties 12 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /.metadata: -------------------------------------------------------------------------------- 1 | # This file tracks properties of this Flutter project. 2 | # Used by Flutter tool to assess capabilities and perform upgrades etc. 3 | # 4 | # This file should be version controlled and should not be manually edited. 5 | 6 | version: 7 | revision: 61477b5949401d26af6194c8b1e727903c7a8c7c 8 | channel: master 9 | 10 | project_type: app 11 | -------------------------------------------------------------------------------- /linux/flutter/generated_plugin_registrant.h: -------------------------------------------------------------------------------- 1 | // 2 | // Generated file. Do not edit. 3 | // 4 | 5 | #ifndef GENERATED_PLUGIN_REGISTRANT_ 6 | #define GENERATED_PLUGIN_REGISTRANT_ 7 | 8 | #include 9 | 10 | // Registers Flutter plugins. 11 | void fl_register_plugins(FlPluginRegistry* registry); 12 | 13 | #endif // GENERATED_PLUGIN_REGISTRANT_ 14 | -------------------------------------------------------------------------------- /android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /android/app/src/profile/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md: -------------------------------------------------------------------------------- 1 | # Launch Screen Assets 2 | 3 | You can customize the launch screen with your own desired assets by replacing the image files in this directory. 4 | 5 | You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. -------------------------------------------------------------------------------- /plugins/file_chooser/windows/.gitignore: -------------------------------------------------------------------------------- 1 | flutter/ 2 | 3 | # Visual Studio user-specific files. 4 | *.suo 5 | *.user 6 | *.userosscache 7 | *.sln.docstates 8 | 9 | # Visual Studio build-related files. 10 | x64/ 11 | x86/ 12 | 13 | # Visual Studio cache files 14 | # files ending in .cache can be ignored 15 | *.[Cc]ache 16 | # but keep track of directories ending in .cache 17 | !*.[Cc]ache/ 18 | -------------------------------------------------------------------------------- /plugins/window_size/windows/.gitignore: -------------------------------------------------------------------------------- 1 | flutter/ 2 | 3 | # Visual Studio user-specific files. 4 | *.suo 5 | *.user 6 | *.userosscache 7 | *.sln.docstates 8 | 9 | # Visual Studio build-related files. 10 | x64/ 11 | x86/ 12 | 13 | # Visual Studio cache files 14 | # files ending in .cache can be ignored 15 | *.[Cc]ache 16 | # but keep track of directories ending in .cache 17 | !*.[Cc]ache/ 18 | -------------------------------------------------------------------------------- /plugins/flutter_plugins/url_launcher_fde/windows/.gitignore: -------------------------------------------------------------------------------- 1 | flutter/ 2 | 3 | # Visual Studio user-specific files. 4 | *.suo 5 | *.user 6 | *.userosscache 7 | *.sln.docstates 8 | 9 | # Visual Studio build-related files. 10 | x64/ 11 | x86/ 12 | 13 | # Visual Studio cache files 14 | # files ending in .cache can be ignored 15 | *.[Cc]ache 16 | # but keep track of directories ending in .cache 17 | !*.[Cc]ache/ 18 | -------------------------------------------------------------------------------- /plugins/flutter_plugins/path_provider_fde/windows/.gitignore: -------------------------------------------------------------------------------- 1 | flutter/ 2 | 3 | # Visual Studio user-specific files. 4 | *.suo 5 | *.user 6 | *.userosscache 7 | *.sln.docstates 8 | 9 | # Visual Studio build-related files. 10 | x64/ 11 | x86/ 12 | 13 | # Visual Studio cache files 14 | # files ending in .cache can be ignored 15 | *.[Cc]ache 16 | # but keep track of directories ending in .cache 17 | !*.[Cc]ache/ 18 | -------------------------------------------------------------------------------- /ios/Runner/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | import Flutter 3 | 4 | @UIApplicationMain 5 | @objc class AppDelegate: FlutterAppDelegate { 6 | override func application( 7 | _ application: UIApplication, 8 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? 9 | ) -> Bool { 10 | GeneratedPluginRegistrant.register(with: self) 11 | return super.application(application, didFinishLaunchingWithOptions: launchOptions) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /linux/my_application.h: -------------------------------------------------------------------------------- 1 | #ifndef FLUTTER_MY_APPLICATION_H_ 2 | #define FLUTTER_MY_APPLICATION_H_ 3 | 4 | #include 5 | 6 | G_DECLARE_FINAL_TYPE(MyApplication, my_application, MY, APPLICATION, 7 | GtkApplication) 8 | 9 | /** 10 | * my_application_new: 11 | * 12 | * Creates a new Flutter-based application. 13 | * 14 | * Returns: a new #MyApplication. 15 | */ 16 | MyApplication* my_application_new(); 17 | 18 | #endif // FLUTTER_MY_APPLICATION_H_ 19 | -------------------------------------------------------------------------------- /plugins/color_panel/README.md: -------------------------------------------------------------------------------- 1 | # color_panel 2 | 3 | This plugin provides access to a native color picker. 4 | 5 | It exists primarily to serve as an example of using native UI in a desktop plugin, 6 | and may be removed at some point in the future. 7 | 8 | ## Supported Platforms 9 | 10 | - [x] macOS 11 | - [ ] [Windows](https://github.com/google/flutter-desktop-embedding/issues/105) 12 | - [x] Linux 13 | 14 | ## Use 15 | 16 | See [the plugin README](../README.md) for general instructions on using FDE plugins. 17 | -------------------------------------------------------------------------------- /android/settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | 3 | def localPropertiesFile = new File(rootProject.projectDir, "local.properties") 4 | def properties = new Properties() 5 | 6 | assert localPropertiesFile.exists() 7 | localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) } 8 | 9 | def flutterSdkPath = properties.getProperty("flutter.sdk") 10 | assert flutterSdkPath != null, "flutter.sdk not set in local.properties" 11 | apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle" 12 | -------------------------------------------------------------------------------- /android/app/src/main/res/drawable/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "LaunchImage.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "LaunchImage@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "LaunchImage@3x.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /plugins/menubar/ios/.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | .vagrant/ 3 | .sconsign.dblite 4 | .svn/ 5 | 6 | .DS_Store 7 | *.swp 8 | profile 9 | 10 | DerivedData/ 11 | build/ 12 | GeneratedPluginRegistrant.h 13 | GeneratedPluginRegistrant.m 14 | 15 | .generated/ 16 | 17 | *.pbxuser 18 | *.mode1v3 19 | *.mode2v3 20 | *.perspectivev3 21 | 22 | !default.pbxuser 23 | !default.mode1v3 24 | !default.mode2v3 25 | !default.perspectivev3 26 | 27 | xcuserdata 28 | 29 | *.moved-aside 30 | 31 | *.pyc 32 | *sync/ 33 | Icon? 34 | .tags* 35 | 36 | /Flutter/Generated.xcconfig 37 | -------------------------------------------------------------------------------- /plugins/color_panel/ios/.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | .vagrant/ 3 | .sconsign.dblite 4 | .svn/ 5 | 6 | .DS_Store 7 | *.swp 8 | profile 9 | 10 | DerivedData/ 11 | build/ 12 | GeneratedPluginRegistrant.h 13 | GeneratedPluginRegistrant.m 14 | 15 | .generated/ 16 | 17 | *.pbxuser 18 | *.mode1v3 19 | *.mode2v3 20 | *.perspectivev3 21 | 22 | !default.pbxuser 23 | !default.mode1v3 24 | !default.mode2v3 25 | !default.perspectivev3 26 | 27 | xcuserdata 28 | 29 | *.moved-aside 30 | 31 | *.pyc 32 | *sync/ 33 | Icon? 34 | .tags* 35 | 36 | /Flutter/Generated.xcconfig 37 | -------------------------------------------------------------------------------- /plugins/file_chooser/ios/.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | .vagrant/ 3 | .sconsign.dblite 4 | .svn/ 5 | 6 | .DS_Store 7 | *.swp 8 | profile 9 | 10 | DerivedData/ 11 | build/ 12 | GeneratedPluginRegistrant.h 13 | GeneratedPluginRegistrant.m 14 | 15 | .generated/ 16 | 17 | *.pbxuser 18 | *.mode1v3 19 | *.mode2v3 20 | *.perspectivev3 21 | 22 | !default.pbxuser 23 | !default.mode1v3 24 | !default.mode2v3 25 | !default.perspectivev3 26 | 27 | xcuserdata 28 | 29 | *.moved-aside 30 | 31 | *.pyc 32 | *sync/ 33 | Icon? 34 | .tags* 35 | 36 | /Flutter/Generated.xcconfig 37 | -------------------------------------------------------------------------------- /plugins/window_size/ios/.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | .vagrant/ 3 | .sconsign.dblite 4 | .svn/ 5 | 6 | .DS_Store 7 | *.swp 8 | profile 9 | 10 | DerivedData/ 11 | build/ 12 | GeneratedPluginRegistrant.h 13 | GeneratedPluginRegistrant.m 14 | 15 | .generated/ 16 | 17 | *.pbxuser 18 | *.mode1v3 19 | *.mode2v3 20 | *.perspectivev3 21 | 22 | !default.pbxuser 23 | !default.mode1v3 24 | !default.mode2v3 25 | !default.perspectivev3 26 | 27 | xcuserdata 28 | 29 | *.moved-aside 30 | 31 | *.pyc 32 | *sync/ 33 | Icon? 34 | .tags* 35 | 36 | /Flutter/Generated.xcconfig 37 | -------------------------------------------------------------------------------- /plugins/flutter_plugins/url_launcher_fde/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: url_launcher_fde 2 | description: Temporary desktop implmentations of url_launcher from flutter/plugins 3 | version: 0.1.0 4 | 5 | # Do not publish this plugin. See: 6 | # https://github.com/google/flutter-desktop-embedding/blob/master/plugins/README.md#using-plugins 7 | publish_to: none 8 | 9 | flutter: 10 | plugin: 11 | platforms: 12 | windows: 13 | pluginClass: UrlLauncherPlugin 14 | 15 | environment: 16 | sdk: ">=2.1.0 <3.0.0" 17 | 18 | dependencies: 19 | flutter: 20 | sdk: flutter 21 | -------------------------------------------------------------------------------- /plugins/flutter_plugins/path_provider_fde/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: path_provider_fde 2 | description: Temporary desktop implmentations of path_provider from flutter/plugins 3 | version: 0.0.1 4 | 5 | # Do not publish this plugin. See: 6 | # https://github.com/google/flutter-desktop-embedding/blob/master/plugins/README.md#using-plugins 7 | publish_to: none 8 | 9 | flutter: 10 | plugin: 11 | platforms: 12 | windows: 13 | pluginClass: PathProviderPlugin 14 | 15 | environment: 16 | sdk: ">=2.1.0 <3.0.0" 17 | 18 | dependencies: 19 | flutter: 20 | sdk: flutter 21 | -------------------------------------------------------------------------------- /plugins/flutter_plugins/url_launcher_fde/README.md: -------------------------------------------------------------------------------- 1 | # url_launcher_fde 2 | 3 | Prototype Windows implementation of 4 | [url_launcher](https://pub.dev/packages/url_launcher) 5 | 6 | See [the main flutter_plugins README](../README.md) for general information about what 7 | this plugin is and how to use it. 8 | 9 | ## Supported Platforms 10 | 11 | - [x] Windows 12 | 13 | macOS and Linux are already supported by `url_launcher`. 14 | 15 | ## Caveats 16 | 17 | Only `launch` is implemented, so the common pattern of calling `launch` only if 18 | `canLaunch` returns true will not work. 19 | -------------------------------------------------------------------------------- /plugins/color_panel/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: color_panel 2 | description: Provides access to the platform's native color picker. 3 | version: 0.1.0 4 | 5 | # Do not publish this plugin. See: 6 | # https://github.com/google/flutter-desktop-embedding/blob/master/plugins/README.md#using-plugins 7 | publish_to: none 8 | 9 | flutter: 10 | plugin: 11 | platforms: 12 | linux: 13 | pluginClass: ColorPanelPlugin 14 | macos: 15 | pluginClass: ColorPanelPlugin 16 | 17 | environment: 18 | sdk: ">=2.1.0 <3.0.0" 19 | 20 | dependencies: 21 | flutter: 22 | sdk: flutter 23 | -------------------------------------------------------------------------------- /plugins/menubar/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: menubar 2 | description: Provides the ability to add native menubar items with Dart callbacks. 3 | version: 0.1.0 4 | 5 | # Do not publish this plugin. See: 6 | # https://github.com/google/flutter-desktop-embedding/blob/master/plugins/README.md#using-plugins 7 | publish_to: none 8 | 9 | flutter: 10 | plugin: 11 | platforms: 12 | linux: 13 | pluginClass: MenubarPlugin 14 | macos: 15 | pluginClass: MenubarPlugin 16 | 17 | environment: 18 | sdk: ">=2.1.0 <3.0.0" 19 | 20 | dependencies: 21 | flutter: 22 | sdk: flutter 23 | -------------------------------------------------------------------------------- /plugins/flutter_plugins/path_provider_fde/README.md: -------------------------------------------------------------------------------- 1 | # path_provider_fde 2 | 3 | Prototype Windows implementation of 4 | [path_provider](https://pub.dev/packages/path_provider) 5 | 6 | See [the main flutter_plugins README](../README.md) for general information about what 7 | this plugin is and how to use it. 8 | 9 | ## Supported Platforms 10 | 11 | - [x] Windows 12 | 13 | macOS and Linux are already supported by `path_provider`. 14 | 15 | ## Caveats 16 | 17 | The paths returned by this plugin may change in the future. Most notably, 18 | `getApplicationSupportDirectory` will likely return a different path in the 19 | future. 20 | -------------------------------------------------------------------------------- /linux/flutter/generated_plugins.cmake: -------------------------------------------------------------------------------- 1 | # 2 | # Generated file, do not edit. 3 | # 4 | 5 | list(APPEND FLUTTER_PLUGIN_LIST 6 | url_launcher_linux 7 | color_panel 8 | file_chooser 9 | menubar 10 | window_size 11 | ) 12 | 13 | set(PLUGIN_BUNDLED_LIBRARIES) 14 | 15 | foreach(plugin ${FLUTTER_PLUGIN_LIST}) 16 | add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/linux plugins/${plugin}) 17 | target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) 18 | list(APPEND PLUGIN_BUNDLED_LIBRARIES $) 19 | list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) 20 | endforeach(plugin) 21 | -------------------------------------------------------------------------------- /plugins/file_chooser/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: file_chooser 2 | description: Displays native platform open and save panels. 3 | version: 0.2.0 4 | 5 | # Do not publish this plugin. See: 6 | # https://github.com/google/flutter-desktop-embedding/blob/master/plugins/README.md#using-plugins 7 | publish_to: none 8 | 9 | flutter: 10 | plugin: 11 | platforms: 12 | linux: 13 | pluginClass: FileChooserPlugin 14 | macos: 15 | pluginClass: FileChooserPlugin 16 | windows: 17 | pluginClass: FileChooserPlugin 18 | 19 | environment: 20 | sdk: ">=2.1.0 <3.0.0" 21 | 22 | dependencies: 23 | flutter: 24 | sdk: flutter 25 | -------------------------------------------------------------------------------- /plugins/window_size/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: window_size 2 | description: Allows resizing and repositioning the window containing Flutter. 3 | version: 0.1.0 4 | 5 | # Do not publish this plugin. See: 6 | # https://github.com/google/flutter-desktop-embedding/blob/master/plugins/README.md#using-plugins 7 | publish_to: none 8 | 9 | flutter: 10 | plugin: 11 | platforms: 12 | linux: 13 | pluginClass: WindowSizePlugin 14 | macos: 15 | pluginClass: WindowSizePlugin 16 | windows: 17 | pluginClass: WindowSizePlugin 18 | 19 | environment: 20 | sdk: ">=2.1.0 <3.0.0" 21 | 22 | dependencies: 23 | flutter: 24 | sdk: flutter 25 | -------------------------------------------------------------------------------- /ios/.gitignore: -------------------------------------------------------------------------------- 1 | *.mode1v3 2 | *.mode2v3 3 | *.moved-aside 4 | *.pbxuser 5 | *.perspectivev3 6 | **/*sync/ 7 | .sconsign.dblite 8 | .tags* 9 | **/.vagrant/ 10 | **/DerivedData/ 11 | Icon? 12 | **/Pods/ 13 | **/.symlinks/ 14 | profile 15 | xcuserdata 16 | **/.generated/ 17 | Flutter/App.framework 18 | Flutter/Flutter.framework 19 | Flutter/Flutter.podspec 20 | Flutter/Generated.xcconfig 21 | Flutter/app.flx 22 | Flutter/app.zip 23 | Flutter/flutter_assets/ 24 | Flutter/flutter_export_environment.sh 25 | ServiceDefinitions.json 26 | Runner/GeneratedPluginRegistrant.* 27 | 28 | # Exceptions to above rules. 29 | !default.mode1v3 30 | !default.mode2v3 31 | !default.pbxuser 32 | !default.perspectivev3 33 | -------------------------------------------------------------------------------- /plugins/menubar/linux/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.10) 2 | set(PROJECT_NAME "menubar") 3 | project(${PROJECT_NAME} LANGUAGES CXX) 4 | 5 | set(PLUGIN_NAME "${PROJECT_NAME}_plugin") 6 | 7 | add_library(${PLUGIN_NAME} SHARED 8 | "${PLUGIN_NAME}.cc" 9 | ) 10 | apply_standard_settings(${PLUGIN_NAME}) 11 | set_target_properties(${PLUGIN_NAME} PROPERTIES 12 | CXX_VISIBILITY_PRESET hidden) 13 | target_compile_definitions(${PLUGIN_NAME} PRIVATE FLUTTER_PLUGIN_IMPL) 14 | target_include_directories(${PLUGIN_NAME} INTERFACE 15 | "${CMAKE_CURRENT_SOURCE_DIR}/include") 16 | target_link_libraries(${PLUGIN_NAME} PRIVATE flutter) 17 | target_link_libraries(${PLUGIN_NAME} PRIVATE PkgConfig::GTK) 18 | -------------------------------------------------------------------------------- /plugins/color_panel/linux/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.10) 2 | set(PROJECT_NAME "color_panel") 3 | project(${PROJECT_NAME} LANGUAGES CXX) 4 | 5 | set(PLUGIN_NAME "${PROJECT_NAME}_plugin") 6 | 7 | add_library(${PLUGIN_NAME} SHARED 8 | "${PLUGIN_NAME}.cc" 9 | ) 10 | apply_standard_settings(${PLUGIN_NAME}) 11 | set_target_properties(${PLUGIN_NAME} PROPERTIES 12 | CXX_VISIBILITY_PRESET hidden) 13 | target_compile_definitions(${PLUGIN_NAME} PRIVATE FLUTTER_PLUGIN_IMPL) 14 | target_include_directories(${PLUGIN_NAME} INTERFACE 15 | "${CMAKE_CURRENT_SOURCE_DIR}/include") 16 | target_link_libraries(${PLUGIN_NAME} PRIVATE flutter) 17 | target_link_libraries(${PLUGIN_NAME} PRIVATE PkgConfig::GTK) 18 | -------------------------------------------------------------------------------- /plugins/file_chooser/linux/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.10) 2 | set(PROJECT_NAME "file_chooser") 3 | project(${PROJECT_NAME} LANGUAGES CXX) 4 | 5 | set(PLUGIN_NAME "${PROJECT_NAME}_plugin") 6 | 7 | add_library(${PLUGIN_NAME} SHARED 8 | "${PLUGIN_NAME}.cc" 9 | ) 10 | apply_standard_settings(${PLUGIN_NAME}) 11 | set_target_properties(${PLUGIN_NAME} PROPERTIES 12 | CXX_VISIBILITY_PRESET hidden) 13 | target_compile_definitions(${PLUGIN_NAME} PRIVATE FLUTTER_PLUGIN_IMPL) 14 | target_include_directories(${PLUGIN_NAME} INTERFACE 15 | "${CMAKE_CURRENT_SOURCE_DIR}/include") 16 | target_link_libraries(${PLUGIN_NAME} PRIVATE flutter) 17 | target_link_libraries(${PLUGIN_NAME} PRIVATE PkgConfig::GTK) 18 | -------------------------------------------------------------------------------- /plugins/window_size/linux/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.10) 2 | set(PROJECT_NAME "window_size") 3 | project(${PROJECT_NAME} LANGUAGES CXX) 4 | 5 | set(PLUGIN_NAME "${PROJECT_NAME}_plugin") 6 | 7 | add_library(${PLUGIN_NAME} SHARED 8 | "${PLUGIN_NAME}.cc" 9 | ) 10 | apply_standard_settings(${PLUGIN_NAME}) 11 | set_target_properties(${PLUGIN_NAME} PROPERTIES 12 | CXX_VISIBILITY_PRESET hidden) 13 | target_compile_definitions(${PLUGIN_NAME} PRIVATE FLUTTER_PLUGIN_IMPL) 14 | target_include_directories(${PLUGIN_NAME} INTERFACE 15 | "${CMAKE_CURRENT_SOURCE_DIR}/include") 16 | target_link_libraries(${PLUGIN_NAME} PRIVATE flutter) 17 | target_link_libraries(${PLUGIN_NAME} PRIVATE PkgConfig::GTK) 18 | -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | ext.kotlin_version = '1.3.50' 3 | repositories { 4 | google() 5 | jcenter() 6 | } 7 | 8 | dependencies { 9 | classpath 'com.android.tools.build:gradle:3.5.0' 10 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 11 | } 12 | } 13 | 14 | allprojects { 15 | repositories { 16 | google() 17 | jcenter() 18 | } 19 | } 20 | 21 | rootProject.buildDir = '../build' 22 | subprojects { 23 | project.buildDir = "${rootProject.buildDir}/${project.name}" 24 | } 25 | subprojects { 26 | project.evaluationDependsOn(':app') 27 | } 28 | 29 | task clean(type: Delete) { 30 | delete rootProject.buildDir 31 | } 32 | -------------------------------------------------------------------------------- /plugins/menubar/lib/menubar.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | export 'src/menu_item.dart'; 15 | export 'src/set_application_menu.dart'; 16 | -------------------------------------------------------------------------------- /plugins/file_chooser/lib/file_chooser.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | export 'src/filter_group.dart'; 15 | export 'src/result.dart'; 16 | export 'src/utilities.dart'; 17 | -------------------------------------------------------------------------------- /plugins/window_size/lib/window_size.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | export 'src/platform_window.dart'; 15 | export 'src/screen.dart'; 16 | export 'src/window_size_utils.dart'; 17 | -------------------------------------------------------------------------------- /plugins/menubar/README.md: -------------------------------------------------------------------------------- 1 | # menubar 2 | 3 | This plugin provides access to a native menubar. 4 | 5 | This is a prototype, and in the long term will either be replaced by functionality 6 | within the Flutter framework itself, or a published plugin (likely part of 7 | flutter/plugins). Either way, the API will change significantly. 8 | 9 | ## Supported Platforms 10 | 11 | - [x] macOS 12 | - [ ] [Windows](https://github.com/google/flutter-desktop-embedding/issues/105) 13 | - [x] Linux 14 | 15 | ## Caveats 16 | 17 | ### macOS 18 | 19 | Currently there is no way to interact with existing top-level menus, only add new ones. 20 | E.g., the Window menu cannot be extended from Flutter code. 21 | 22 | ## Use 23 | 24 | See [the plugin README](../README.md) for general instructions on using FDE plugins. 25 | -------------------------------------------------------------------------------- /plugins/flutter_plugins/url_launcher_fde/windows/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.10) 2 | set(PROJECT_NAME "url_launcher_fde") 3 | project(${PROJECT_NAME} LANGUAGES CXX) 4 | 5 | set(PLUGIN_NAME "${PROJECT_NAME}_plugin") 6 | 7 | add_library(${PLUGIN_NAME} SHARED 8 | "url_launcher_plugin.cpp" 9 | ) 10 | apply_standard_settings(${PLUGIN_NAME}) 11 | set_target_properties(${PLUGIN_NAME} PROPERTIES 12 | CXX_VISIBILITY_PRESET hidden) 13 | target_compile_definitions(${PLUGIN_NAME} PRIVATE FLUTTER_PLUGIN_IMPL) 14 | target_include_directories(${PLUGIN_NAME} INTERFACE 15 | "${CMAKE_CURRENT_SOURCE_DIR}/include") 16 | target_link_libraries(${PLUGIN_NAME} PRIVATE flutter flutter_wrapper_plugin) 17 | 18 | # List of absolute paths to libraries that should be bundled with the plugin 19 | set(file_chooser_bundled_libraries 20 | "" 21 | PARENT_SCOPE 22 | ) 23 | -------------------------------------------------------------------------------- /plugins/file_chooser/macos/file_chooser.podspec: -------------------------------------------------------------------------------- 1 | # 2 | # To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html 3 | # 4 | Pod::Spec.new do |s| 5 | s.name = 'file_chooser' 6 | s.version = '0.0.2' 7 | s.summary = 'Displays macOS open and save panels.' 8 | s.description = <<-DESC 9 | Displays macOS open and save panels. 10 | DESC 11 | s.homepage = 'https://github.com/google/flutter-desktop-embedding/tree/master/plugins/file_chooser' 12 | s.license = { :file => '../LICENSE' } 13 | s.author = { 'Flutter Desktop Embedding Developers' => 'flutter-desktop-embedding-dev@googlegroups.com' } 14 | s.source = { :path => '.' } 15 | s.source_files = 'Classes/**/*' 16 | s.dependency 'FlutterMacOS' 17 | 18 | s.platform = :osx 19 | s.osx.deployment_target = '10.11' 20 | end 21 | 22 | -------------------------------------------------------------------------------- /plugins/color_panel/macos/color_panel.podspec: -------------------------------------------------------------------------------- 1 | # 2 | # To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html 3 | # 4 | Pod::Spec.new do |s| 5 | s.name = 'color_panel' 6 | s.version = '0.0.2' 7 | s.summary = 'Provides access to the macOS color picker.' 8 | s.description = <<-DESC 9 | Provides access to the macOS color picker. 10 | DESC 11 | s.homepage = 'https://github.com/google/flutter-desktop-embedding/tree/master/plugins/color_panel' 12 | s.license = { :file => '../LICENSE' } 13 | s.author = { 'Flutter Desktop Embedding Developers' => 'flutter-desktop-embedding-dev@googlegroups.com' } 14 | s.source = { :path => '.' } 15 | s.source_files = 'Classes/**/*' 16 | s.dependency 'FlutterMacOS' 17 | 18 | s.platform = :osx 19 | s.osx.deployment_target = '10.11' 20 | end 21 | 22 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .buildlog/ 9 | .history 10 | .svn/ 11 | 12 | # IntelliJ related 13 | *.iml 14 | *.ipr 15 | *.iws 16 | .idea/ 17 | 18 | # The .vscode folder contains launch configuration and tasks you configure in 19 | # VS Code which you may wish to be included in version control, so this line 20 | # is commented out by default. 21 | #.vscode/ 22 | 23 | # Flutter/Dart/Pub related 24 | **/doc/api/ 25 | **/ios/Flutter/.last_build_id 26 | .dart_tool/ 27 | .flutter-plugins 28 | .flutter-plugins-dependencies 29 | .packages 30 | .pub-cache/ 31 | .pub/ 32 | /build/ 33 | 34 | # Web related 35 | lib/generated_plugin_registrant.dart 36 | 37 | # Symbolication related 38 | app.*.symbols 39 | 40 | # Obfuscation related 41 | app.*.map.json 42 | 43 | # Exceptions to above rules. 44 | !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages 45 | -------------------------------------------------------------------------------- /plugins/menubar/ios/menubar.podspec: -------------------------------------------------------------------------------- 1 | # 2 | # To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html 3 | # 4 | Pod::Spec.new do |s| 5 | s.name = 'menubar' 6 | s.version = '0.0.1' 7 | s.summary = 'No-op implementation of menubar desktop plugin to avoid build issues on iOS' 8 | s.description = <<-DESC 9 | temp fake menubar plugin 10 | DESC 11 | s.homepage = 'https://github.com/google/flutter-desktop-embedding/tree/master/plugins/color_panel' 12 | s.license = { :file => '../LICENSE' } 13 | s.author = { 'Flutter Desktop Embedding Developers' => 'flutter-desktop-embedding-dev@googlegroups.com' } 14 | s.source = { :path => '.' } 15 | s.source_files = 'Classes/**/*' 16 | s.public_header_files = 'Classes/**/*.h' 17 | s.dependency 'Flutter' 18 | 19 | s.ios.deployment_target = '8.0' 20 | end 21 | 22 | -------------------------------------------------------------------------------- /ios/Flutter/AppFrameworkInfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | App 9 | CFBundleIdentifier 10 | io.flutter.flutter.app 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | App 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1.0 23 | MinimumOSVersion 24 | 8.0 25 | 26 | 27 | -------------------------------------------------------------------------------- /plugins/menubar/macos/Classes/MenubarPlugin.swift: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | import FlutterMacOS 16 | import Foundation 17 | 18 | public class MenubarPlugin: NSObject, FlutterPlugin { 19 | public static func register(with registrar: FlutterPluginRegistrar) { 20 | FLEMenubarPlugin.register(with: registrar) 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /plugins/menubar/macos/menubar.podspec: -------------------------------------------------------------------------------- 1 | # 2 | # To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html 3 | # 4 | Pod::Spec.new do |s| 5 | s.name = 'menubar' 6 | s.version = '0.0.2' 7 | s.summary = 'Provides the ability to add menubar items with Dart callbacks.' 8 | s.description = <<-DESC 9 | Provides the ability to add menubar items with Dart callbacks. 10 | DESC 11 | s.homepage = 'https://github.com/google/flutter-desktop-embedding/tree/master/plugins/menubar' 12 | s.license = { :file => '../LICENSE' } 13 | s.author = { 'Flutter Desktop Embedding Developers' => 'flutter-desktop-embedding-dev@googlegroups.com' } 14 | s.source = { :path => '.' } 15 | s.source_files = 'Classes/**/*' 16 | s.dependency 'FlutterMacOS' 17 | 18 | s.platform = :osx 19 | s.osx.deployment_target = '10.11' 20 | end 21 | 22 | -------------------------------------------------------------------------------- /pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: Pomodoro 2 | description: A new Flutter project. 3 | publish_to: 'none' 4 | 5 | version: 1.0.0+1 6 | 7 | environment: 8 | sdk: ">=2.7.0 <3.0.0" 9 | 10 | dependencies: 11 | flutter: 12 | sdk: flutter 13 | 14 | cupertino_icons: ^0.1.3 15 | google_fonts: ^1.1.0 16 | flutter_icons: ^1.1.0 17 | animated_text_kit: ^2.2.0 18 | 19 | color_panel: 20 | path: plugins/color_panel 21 | file_chooser: 22 | path: plugins/file_chooser 23 | menubar: 24 | path: plugins/menubar 25 | window_size: 26 | path: plugins/window_size 27 | 28 | path_provider: ^1.6.5 29 | path_provider_fde: 30 | path: plugins/flutter_plugins/path_provider_fde 31 | shared_preferences: ^0.5.6 32 | url_launcher: ^5.5.0 33 | url_launcher_fde: 34 | path: plugins/flutter_plugins/url_launcher_fde 35 | dev_dependencies: 36 | flutter_test: 37 | sdk: flutter 38 | 39 | flutter: 40 | uses-material-design: true -------------------------------------------------------------------------------- /plugins/window_size/README.md: -------------------------------------------------------------------------------- 1 | # window_size 2 | 3 | This plugin allows resizing and repositioning the window containing the Flutter 4 | content, as well as querying screen information. 5 | 6 | This is a prototype, and in the long term will likely be replaced by functionality 7 | within the Flutter framework itself. The API will likely change significantly. 8 | 9 | **Note**: Further related functionality, such as window minimization and maximization, 10 | will likely be added to this plugin in the future. PRs are welcome to add functionality 11 | of that kind to any or all platforms. 12 | 13 | ## Supported Platforms 14 | 15 | - [x] macOS 16 | - [x] Windows 17 | - [x] Linux 18 | 19 | Not all operations have been implemented on all platforms, but the core functionality 20 | of resizing and repositioning is available for all three. 21 | 22 | ## Use 23 | 24 | See [the plugin README](../README.md) for general instructions on using FDE plugins. 25 | -------------------------------------------------------------------------------- /plugins/color_panel/ios/color_panel.podspec: -------------------------------------------------------------------------------- 1 | # 2 | # To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html 3 | # 4 | Pod::Spec.new do |s| 5 | s.name = 'color_panel' 6 | s.version = '0.0.1' 7 | s.summary = 'No-op implementation of color_panel desktop plugin to avoid build issues on iOS' 8 | s.description = <<-DESC 9 | temp fake color_panel plugin 10 | DESC 11 | s.homepage = 'https://github.com/google/flutter-desktop-embedding/tree/master/plugins/color_panel' 12 | s.license = { :file => '../LICENSE' } 13 | s.author = { 'Flutter Desktop Embedding Developers' => 'flutter-desktop-embedding-dev@googlegroups.com' } 14 | s.source = { :path => '.' } 15 | s.source_files = 'Classes/**/*' 16 | s.public_header_files = 'Classes/**/*.h' 17 | s.dependency 'Flutter' 18 | 19 | s.ios.deployment_target = '8.0' 20 | end 21 | 22 | -------------------------------------------------------------------------------- /plugins/window_size/ios/window_size.podspec: -------------------------------------------------------------------------------- 1 | # 2 | # To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html 3 | # 4 | Pod::Spec.new do |s| 5 | s.name = 'window_size' 6 | s.version = '0.0.1' 7 | s.summary = 'No-op implementation of window_size desktop plugin to avoid build issues on iOS' 8 | s.description = <<-DESC 9 | temp fake window_size plugin 10 | DESC 11 | s.homepage = 'https://github.com/google/flutter-desktop-embedding/tree/master/plugins/color_panel' 12 | s.license = { :file => '../LICENSE' } 13 | s.author = { 'Flutter Desktop Embedding Developers' => 'flutter-desktop-embedding-dev@googlegroups.com' } 14 | s.source = { :path => '.' } 15 | s.source_files = 'Classes/**/*' 16 | s.public_header_files = 'Classes/**/*.h' 17 | s.dependency 'Flutter' 18 | 19 | s.ios.deployment_target = '8.0' 20 | end 21 | 22 | -------------------------------------------------------------------------------- /plugins/color_panel/macos/Classes/ColorPanelPlugin.swift: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | import FlutterMacOS 16 | import Foundation 17 | 18 | public class ColorPanelPlugin: NSObject, FlutterPlugin { 19 | public static func register(with registrar: FlutterPluginRegistrar) { 20 | FLEColorPanelPlugin.register(with: registrar) 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /plugins/file_chooser/ios/file_chooser.podspec: -------------------------------------------------------------------------------- 1 | # 2 | # To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html 3 | # 4 | Pod::Spec.new do |s| 5 | s.name = 'file_chooser' 6 | s.version = '0.0.1' 7 | s.summary = 'No-op implementation of file_chooser desktop plugin to avoid build issues on iOS' 8 | s.description = <<-DESC 9 | temp fake file_chooser plugin 10 | DESC 11 | s.homepage = 'https://github.com/google/flutter-desktop-embedding/tree/master/plugins/file_chooser' 12 | s.license = { :file => '../LICENSE' } 13 | s.author = { 'Flutter Desktop Embedding Developers' => 'flutter-desktop-embedding-dev@googlegroups.com' } 14 | s.source = { :path => '.' } 15 | s.source_files = 'Classes/**/*' 16 | s.public_header_files = 'Classes/**/*.h' 17 | s.dependency 'Flutter' 18 | 19 | s.ios.deployment_target = '8.0' 20 | end 21 | 22 | -------------------------------------------------------------------------------- /plugins/window_size/macos/Classes/WindowSizePlugin.swift: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | import FlutterMacOS 16 | import Foundation 17 | 18 | public class WindowSizePlugin: NSObject, FlutterPlugin { 19 | public static func register(with registrar: FlutterPluginRegistrar) { 20 | FLEWindowSizePlugin.register(with: registrar) 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /plugins/file_chooser/macos/Classes/FileChooserPlugin.swift: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | import FlutterMacOS 16 | import Foundation 17 | 18 | public class FileChooserPlugin: NSObject, FlutterPlugin { 19 | public static func register(with registrar: FlutterPluginRegistrar) { 20 | FLEFileChooserPlugin.register(with: registrar) 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /plugins/window_size/macos/window_size.podspec: -------------------------------------------------------------------------------- 1 | # 2 | # To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html 3 | # 4 | Pod::Spec.new do |s| 5 | s.name = 'window_size' 6 | s.version = '0.0.2' 7 | s.summary = 'Allows resizing and repositioning the window containing Flutter.' 8 | s.description = <<-DESC 9 | Allows resizing and repositioning the window containing Flutter. 10 | DESC 11 | s.homepage = 'https://github.com/google/flutter-desktop-embedding/tree/master/plugins/window_size' 12 | s.license = { :file => '../LICENSE' } 13 | s.author = { 'Flutter Desktop Embedding Developers' => 'flutter-desktop-embedding-dev@googlegroups.com' } 14 | s.source = { :path => '.' } 15 | s.source_files = 'Classes/**/*' 16 | s.dependency 'FlutterMacOS' 17 | 18 | s.platform = :osx 19 | s.osx.deployment_target = '10.11' 20 | end 21 | 22 | -------------------------------------------------------------------------------- /plugins/window_size/windows/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.10) 2 | set(PROJECT_NAME "window_size") 3 | project(${PROJECT_NAME} LANGUAGES CXX) 4 | 5 | set(PLUGIN_NAME "${PROJECT_NAME}_plugin") 6 | 7 | add_library(${PLUGIN_NAME} SHARED 8 | "${PLUGIN_NAME}.cpp" 9 | ) 10 | apply_standard_settings(${PLUGIN_NAME}) 11 | set_target_properties(${PLUGIN_NAME} PROPERTIES 12 | CXX_VISIBILITY_PRESET hidden) 13 | target_compile_definitions(${PLUGIN_NAME} PRIVATE FLUTTER_PLUGIN_IMPL) 14 | target_compile_definitions(${PLUGIN_NAME} PRIVATE _SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING) 15 | target_include_directories(${PLUGIN_NAME} INTERFACE 16 | "${CMAKE_CURRENT_SOURCE_DIR}/include") 17 | target_link_libraries(${PLUGIN_NAME} PRIVATE flutter flutter_wrapper_plugin) 18 | 19 | # List of absolute paths to libraries that should be bundled with the plugin 20 | set(window_size_bundled_libraries 21 | "" 22 | PARENT_SCOPE 23 | ) 24 | -------------------------------------------------------------------------------- /plugins/file_chooser/windows/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.10) 2 | set(PROJECT_NAME "file_chooser") 3 | project(${PROJECT_NAME} LANGUAGES CXX) 4 | 5 | set(PLUGIN_NAME "${PROJECT_NAME}_plugin") 6 | 7 | add_library(${PLUGIN_NAME} SHARED 8 | "${PLUGIN_NAME}.cpp" 9 | ) 10 | apply_standard_settings(${PLUGIN_NAME}) 11 | set_target_properties(${PLUGIN_NAME} PROPERTIES 12 | CXX_VISIBILITY_PRESET hidden) 13 | target_compile_definitions(${PLUGIN_NAME} PRIVATE FLUTTER_PLUGIN_IMPL) 14 | target_compile_definitions(${PLUGIN_NAME} PRIVATE _SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING) 15 | target_include_directories(${PLUGIN_NAME} INTERFACE 16 | "${CMAKE_CURRENT_SOURCE_DIR}/include") 17 | target_link_libraries(${PLUGIN_NAME} PRIVATE flutter flutter_wrapper_plugin) 18 | 19 | # List of absolute paths to libraries that should be bundled with the plugin 20 | set(file_chooser_bundled_libraries 21 | "" 22 | PARENT_SCOPE 23 | ) 24 | -------------------------------------------------------------------------------- /plugins/flutter_plugins/url_launcher_fde/ios/url_launcher_fde.podspec: -------------------------------------------------------------------------------- 1 | # 2 | # To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html 3 | # 4 | Pod::Spec.new do |s| 5 | s.name = 'url_launcher_fde' 6 | s.version = '0.0.1' 7 | s.summary = 'No-op implementation of url_launcher_fde desktop plugin to avoid build issues on iOS' 8 | s.description = <<-DESC 9 | temp fake url_launcher_fde plugin 10 | DESC 11 | s.homepage = 'https://github.com/google/flutter-desktop-embedding/tree/master/plugins/url_launcher_fde' 12 | s.license = { :file => '../LICENSE' } 13 | s.author = { 'Flutter Desktop Embedding Developers' => 'flutter-desktop-embedding-dev@googlegroups.com' } 14 | s.source = { :path => '.' } 15 | s.source_files = 'Classes/**/*' 16 | s.public_header_files = 'Classes/**/*.h' 17 | s.dependency 'Flutter' 18 | 19 | s.ios.deployment_target = '8.0' 20 | end 21 | 22 | -------------------------------------------------------------------------------- /plugins/flutter_plugins/path_provider_fde/windows/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.10) 2 | set(PROJECT_NAME "path_provider_fde") 3 | project(${PROJECT_NAME} LANGUAGES CXX) 4 | 5 | set(PLUGIN_NAME "${PROJECT_NAME}_plugin") 6 | 7 | add_library(${PLUGIN_NAME} SHARED 8 | "path_provider_plugin.cpp" 9 | ) 10 | apply_standard_settings(${PLUGIN_NAME}) 11 | set_target_properties(${PLUGIN_NAME} PROPERTIES 12 | CXX_VISIBILITY_PRESET hidden) 13 | target_compile_definitions(${PLUGIN_NAME} PRIVATE FLUTTER_PLUGIN_IMPL) 14 | target_compile_definitions(${PLUGIN_NAME} PRIVATE _SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING) 15 | target_include_directories(${PLUGIN_NAME} INTERFACE 16 | "${CMAKE_CURRENT_SOURCE_DIR}/include") 17 | target_link_libraries(${PLUGIN_NAME} PRIVATE flutter flutter_wrapper_plugin) 18 | 19 | # List of absolute paths to libraries that should be bundled with the plugin 20 | set(path_provider_fde_bundled_libraries 21 | "" 22 | PARENT_SCOPE 23 | ) 24 | -------------------------------------------------------------------------------- /plugins/flutter_plugins/path_provider_fde/ios/path_provider_fde.podspec: -------------------------------------------------------------------------------- 1 | # 2 | # To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html 3 | # 4 | Pod::Spec.new do |s| 5 | s.name = 'path_provider_fde' 6 | s.version = '0.0.1' 7 | s.summary = 'No-op implementation of path_provider_fde desktop plugin to avoid build issues on iOS' 8 | s.description = <<-DESC 9 | temp fake path_provider_fde plugin 10 | DESC 11 | s.homepage = 'https://github.com/google/flutter-desktop-embedding/tree/master/plugins/path_provider_fde' 12 | s.license = { :file => '../LICENSE' } 13 | s.author = { 'Flutter Desktop Embedding Developers' => 'flutter-desktop-embedding-dev@googlegroups.com' } 14 | s.source = { :path => '.' } 15 | s.source_files = 'Classes/**/*' 16 | s.public_header_files = 'Classes/**/*.h' 17 | s.dependency 'Flutter' 18 | 19 | s.ios.deployment_target = '8.0' 20 | end 21 | 22 | -------------------------------------------------------------------------------- /plugins/file_chooser/README.md: -------------------------------------------------------------------------------- 1 | # file_chooser 2 | 3 | This plugin provides access to a native file chooser for Open and Save operations. 4 | 5 | This is a prototype, and in the long term will either be replaced by functionality 6 | within the Flutter framework itself, or a published plugin (likely part of 7 | flutter/plugins). Either way, the API may change significantly. 8 | 9 | ## Supported Platforms 10 | 11 | - [x] macOS 12 | - [x] Windows 13 | - [x] Linux 14 | 15 | ## Use 16 | 17 | See [the plugin README](../README.md) for general instructions on using FDE plugins. 18 | 19 | ### macOS 20 | 21 | You will need to [add an 22 | entitlement](https://github.com/google/flutter-desktop-embedding/blob/master/macOS-Security.md) 23 | for either read-only access: 24 | ``` 25 | com.apple.security.files.user-selected.read-only 26 | 27 | ``` 28 | or read/write access: 29 | ``` 30 | com.apple.security.files.user-selected.read-write 31 | 32 | ``` 33 | depending on your use case. 34 | -------------------------------------------------------------------------------- /android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /plugins/color_panel/macos/Classes/FLEColorPanelPlugin.h: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #import 16 | 17 | #import 18 | 19 | /** 20 | * A FlutterPlugin to manage macOS's shared NSColorPanel singleton. 21 | * Responsible for managing the panel's display state and sending selected color data to Flutter. 22 | */ 23 | @interface FLEColorPanelPlugin : NSObject 24 | 25 | @end 26 | -------------------------------------------------------------------------------- /plugins/window_size/macos/Classes/FLEWindowSizePlugin.h: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #import 16 | 17 | #import 18 | 19 | /** 20 | * A FlutterPlugin to manage macOS's shared NSColorPanel singleton. 21 | * Responsible for managing the panel's display state and sending selected color data to Flutter. 22 | */ 23 | @interface FLEWindowSizePlugin : NSObject 24 | 25 | @end 26 | -------------------------------------------------------------------------------- /plugins/menubar/lib/src/set_application_menu.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | import 'dart:async'; 15 | 16 | import 'menu_channel.dart'; 17 | import 'menu_item.dart'; 18 | 19 | /// Sets the application menu for the app based on the [menuSpec]. 20 | /// 21 | /// Adjacent [MenuDivider]s will be coalesced, leading and/or trailing 22 | /// [MenuDivider]s will be removed. 23 | Future setApplicationMenu(List menuSpec) async { 24 | await MenuChannel.instance.setMenu(menuSpec); 25 | } 26 | -------------------------------------------------------------------------------- /plugins/file_chooser/macos/Classes/FLEFileChooserPlugin.h: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #import 16 | 17 | #import 18 | 19 | /** 20 | * A FlutterPlugin to handle file choosing affordances. Owned by the FlutterViewController. 21 | * Responsible for creating and showing instances of NSSavePanel or NSOpenPanel and sending 22 | * selected file paths to flutter clients, via system channels. 23 | */ 24 | @interface FLEFileChooserPlugin : NSObject 25 | 26 | @end 27 | -------------------------------------------------------------------------------- /test/widget_test.dart: -------------------------------------------------------------------------------- 1 | // This is a basic Flutter widget test. 2 | // 3 | // To perform an interaction with a widget in your test, use the WidgetTester 4 | // utility that Flutter provides. For example, you can send tap and scroll 5 | // gestures. You can also use WidgetTester to find child widgets in the widget 6 | // tree, read text, and verify that the values of widget properties are correct. 7 | 8 | import 'package:flutter/material.dart'; 9 | import 'package:flutter_test/flutter_test.dart'; 10 | 11 | 12 | void main() { 13 | testWidgets('Counter increments smoke test', (WidgetTester tester) async { 14 | // Build our app and trigger a frame. 15 | // await tester.pumpWidget(MyApp()); 16 | 17 | // Verify that our counter starts at 0. 18 | expect(find.text('0'), findsOneWidget); 19 | expect(find.text('1'), findsNothing); 20 | 21 | // Tap the '+' icon and trigger a frame. 22 | await tester.tap(find.byIcon(Icons.add)); 23 | await tester.pump(); 24 | 25 | // Verify that our counter has incremented. 26 | expect(find.text('0'), findsNothing); 27 | expect(find.text('1'), findsOneWidget); 28 | }); 29 | } 30 | -------------------------------------------------------------------------------- /plugins/file_chooser/lib/src/result.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | /// The result of a file chooser operation. 16 | class FileChooserResult { 17 | /// Creates a new result object with the given state and paths. 18 | const FileChooserResult({this.paths, this.canceled}); 19 | 20 | /// Whether or not the file chooser operation was canceled by the user. 21 | final bool canceled; 22 | 23 | /// A list of file paths chosen by the user. If [canceled] is true, the list 24 | /// should always be empty. 25 | final List paths; 26 | } 27 | -------------------------------------------------------------------------------- /plugins/menubar/macos/Classes/FLEMenubarPlugin.h: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #import 16 | 17 | #import 18 | 19 | /** 20 | * A Flutter plugin to control the native menu bar. 21 | */ 22 | @interface FLEMenubarPlugin : NSObject 23 | 24 | /** 25 | * The menu item that Flutter-provided menus should be inserted after. If unset, Flutter-provided 26 | * menus will be inserted after the application menu (i.e., starting at index 1). 27 | */ 28 | @property(nonatomic) NSMenuItem *insertAfterMenuItem; 29 | 30 | @end 31 | -------------------------------------------------------------------------------- /plugins/file_chooser/lib/src/filter_group.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | /// A set of allowed file types. 16 | class FileTypeFilterGroup { 17 | /// Creates a new group with the given label and file extensions. 18 | const FileTypeFilterGroup({this.label, this.fileExtensions}); 19 | 20 | /// The label for the grouping. On platforms that support selectable groups, 21 | /// this will be visible to the user for selecting the group. 22 | final String label; 23 | 24 | /// A list of allowed file extensions. E.g., ['png', 'jpg', 'jpeg', 'gif']. 25 | /// 26 | /// A null or empty list indicates any type is allowed. 27 | final List fileExtensions; 28 | } 29 | -------------------------------------------------------------------------------- /plugins/window_size/lib/src/screen.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | import 'dart:ui'; 15 | 16 | /// Represents a screen, containing information about its size, position, and 17 | /// properties. 18 | class Screen { 19 | /// Create a new screen. 20 | Screen(this.frame, this.visibleFrame, this.scaleFactor); 21 | 22 | /// The frame of the screen, in screen coordinates. 23 | final Rect frame; 24 | 25 | /// The portion of the screen's frame that is available for use by application 26 | /// windows. E.g., on macOS, this excludes the menu bar. 27 | final Rect visibleFrame; 28 | 29 | /// The number of pixels per screen coordinate for this screen. 30 | final double scaleFactor; 31 | } 32 | -------------------------------------------------------------------------------- /plugins/flutter_plugins/path_provider_fde/windows/include/path_provider_fde/path_provider_plugin.h: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | #ifndef PLUGINS_PATH_PROVIDER_PLUGIN_WINDOWS_H_ 15 | #define PLUGINS_PATH_PROVIDER_PLUGIN_WINDOWS_H_ 16 | 17 | #include 18 | 19 | #ifdef FLUTTER_PLUGIN_IMPL 20 | #define FLUTTER_PLUGIN_EXPORT __declspec(dllexport) 21 | #else 22 | #define FLUTTER_PLUGIN_EXPORT __declspec(dllimport) 23 | #endif 24 | 25 | #if defined(__cplusplus) 26 | extern "C" { 27 | #endif 28 | 29 | FLUTTER_PLUGIN_EXPORT void PathProviderPluginRegisterWithRegistrar( 30 | FlutterDesktopPluginRegistrarRef registrar); 31 | 32 | #if defined(__cplusplus) 33 | } // extern "C" 34 | #endif 35 | 36 | #endif // PLUGINS_PATH_PROVIDER_PLUGIN_WINDOWS_H_ 37 | -------------------------------------------------------------------------------- /plugins/flutter_plugins/url_launcher_fde/windows/include/url_launcher_fde/url_launcher_plugin.h: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | #ifndef PLUGINS_URL_LAUNCHER_PLUGIN_WINDOWS_H_ 15 | #define PLUGINS_URL_LAUNCHER_PLUGIN_WINDOWS_H_ 16 | 17 | #include 18 | 19 | #ifdef FLUTTER_PLUGIN_IMPL 20 | #define FLUTTER_PLUGIN_EXPORT __declspec(dllexport) 21 | #else 22 | #define FLUTTER_PLUGIN_EXPORT __declspec(dllimport) 23 | #endif 24 | 25 | #if defined(__cplusplus) 26 | extern "C" { 27 | #endif 28 | 29 | FLUTTER_PLUGIN_EXPORT void UrlLauncherPluginRegisterWithRegistrar( 30 | FlutterDesktopPluginRegistrarRef registrar); 31 | 32 | #if defined(__cplusplus) 33 | } // extern "C" 34 | #endif 35 | 36 | #endif // PLUGINS_EXAMPLE_EXAMPLE_PLUGIN_WINDOWS_H_ 37 | -------------------------------------------------------------------------------- /plugins/window_size/lib/src/platform_window.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | import 'dart:ui'; 15 | 16 | import 'screen.dart'; 17 | 18 | /// Represents a window, containing information about its size, position, and 19 | /// properties. 20 | /// 21 | /// TODO: Evaluate how to reconcile this with the highly mobile-centric Window 22 | /// class in dart::ui 23 | class PlatformWindow { 24 | /// Create a new window. 25 | PlatformWindow(this.frame, this.scaleFactor, this.screen); 26 | 27 | /// The frame of the screen, in screen coordinates. 28 | final Rect frame; 29 | 30 | /// The number of pixels per screen coordinate for this screen. 31 | final double scaleFactor; 32 | 33 | /// The (or a) screen containing this window, if any. 34 | final Screen screen; 35 | } 36 | -------------------------------------------------------------------------------- /plugins/window_size/windows/include/window_size/window_size_plugin.h: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | #ifndef PLUGINS_WINDOW_SIZE_WINDOWS_WINDOW_SIZE_PLUGIN_H_ 15 | #define PLUGINS_WINDOW_SIZE_WINDOWS_WINDOW_SIZE_PLUGIN_H_ 16 | 17 | // A plugin to allow resizing the window. 18 | 19 | #include 20 | 21 | #ifdef FLUTTER_PLUGIN_IMPL 22 | #define FLUTTER_PLUGIN_EXPORT __declspec(dllexport) 23 | #else 24 | #define FLUTTER_PLUGIN_EXPORT __declspec(dllimport) 25 | #endif 26 | 27 | #if defined(__cplusplus) 28 | extern "C" { 29 | #endif 30 | 31 | FLUTTER_PLUGIN_EXPORT void WindowSizePluginRegisterWithRegistrar( 32 | FlutterDesktopPluginRegistrarRef registrar); 33 | 34 | #if defined(__cplusplus) 35 | } // extern "C" 36 | #endif 37 | 38 | #endif // PLUGINS_WINDOW_SIZE_WINDOWS_WINDOW_SIZE_PLUGIN_H_ 39 | -------------------------------------------------------------------------------- /plugins/file_chooser/windows/include/file_chooser/file_chooser_plugin.h: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | #ifndef PLUGINS_FILE_CHOOSER_WINDOWS_FILE_CHOOSER_PLUGIN_H_ 15 | #define PLUGINS_FILE_CHOOSER_WINDOWS_FILE_CHOOSER_PLUGIN_H_ 16 | 17 | // A plugin to allow resizing the window. 18 | 19 | #include 20 | 21 | #ifdef FLUTTER_PLUGIN_IMPL 22 | #define FLUTTER_PLUGIN_EXPORT __declspec(dllexport) 23 | #else 24 | #define FLUTTER_PLUGIN_EXPORT __declspec(dllimport) 25 | #endif 26 | 27 | #if defined(__cplusplus) 28 | extern "C" { 29 | #endif 30 | 31 | FLUTTER_PLUGIN_EXPORT void FileChooserPluginRegisterWithRegistrar( 32 | FlutterDesktopPluginRegistrarRef registrar); 33 | 34 | #if defined(__cplusplus) 35 | } // extern "C" 36 | #endif 37 | 38 | #endif // PLUGINS_FILE_CHOOSER_WINDOWS_FILE_CHOOSER_PLUGIN_H_ 39 | -------------------------------------------------------------------------------- /plugins/flutter_plugins/README.md: -------------------------------------------------------------------------------- 1 | # Windows and Linux Implementation of flutter/plugins Plugins 2 | 3 | Each plugin in this directory corresponds to a 4 | [`flutter/plugins`](https://github.com/flutter/plugins) plugin with the 5 | same name, minus the `_fde` suffix. 6 | 7 | These implementations exist here only as a temporary solution to use these 8 | plugins while the plugin APIs on Windows and Linux stabilize enough that 9 | they can move to the official location and be distributed as normal Flutter 10 | plugins. macOS plugin APIs and tooling are stable, so are already hosted 11 | normally rather than here. 12 | 13 | ## Using These Plugins 14 | 15 | For these plugins, the Dart code comes from the official plugin, so you 16 | must include that in your `pubspec.yaml` as well. For instance, to use 17 | url\_launcher on desktop, you would include both `url_launcher` and 18 | `url_launcher_fde` in your pubspec.yaml (see [the main plugin 19 | README](../README.md) for instructions on adding these plugins to your 20 | `pubspec.yaml`). 21 | 22 | Since the Dart code for those plugins comes from the official plugin, you 23 | do not need to add any `import` in the Dart code other than the main 24 | plugin's `import`. For instance, you would just 25 | `import 'package:url_launcher/url_launcher.dart';` to use url\_launcher\_fde. 26 | 27 | ## Contributing 28 | 29 | If you are interested in implementing a flutter/plugins plugin for Windows 30 | and/or Linux, please open a PR! 31 | -------------------------------------------------------------------------------- /plugins/menubar/linux/include/menubar/menubar_plugin.h: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | #ifndef PLUGINS_MENUBAR_LINUX_MENUBAR_PLUGIN_H_ 15 | #define PLUGINS_MENUBAR_LINUX_MENUBAR_PLUGIN_H_ 16 | 17 | // A plugin to control a native menubar. 18 | 19 | #include 20 | 21 | G_BEGIN_DECLS 22 | 23 | #ifdef FLUTTER_PLUGIN_IMPL 24 | #define FLUTTER_PLUGIN_EXPORT __attribute__((visibility("default"))) 25 | #else 26 | #define FLUTTER_PLUGIN_EXPORT 27 | #endif 28 | 29 | G_DECLARE_FINAL_TYPE(FlMenubarPlugin, fl_menubar_plugin, FL, MENUBAR_PLUGIN, 30 | GObject) 31 | 32 | FLUTTER_PLUGIN_EXPORT FlMenubarPlugin* fl_menubar_plugin_new( 33 | FlPluginRegistrar* registrar); 34 | 35 | FLUTTER_PLUGIN_EXPORT void menubar_plugin_register_with_registrar( 36 | FlPluginRegistrar* registrar); 37 | 38 | G_END_DECLS 39 | 40 | #endif // PLUGINS_MENUBAR_LINUX_MENUBAR_PLUGIN_H_ 41 | -------------------------------------------------------------------------------- /linux/flutter/generated_plugin_registrant.cc: -------------------------------------------------------------------------------- 1 | // 2 | // Generated file. Do not edit. 3 | // 4 | 5 | #include "generated_plugin_registrant.h" 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | void fl_register_plugins(FlPluginRegistry* registry) { 14 | g_autoptr(FlPluginRegistrar) url_launcher_linux_registrar = 15 | fl_plugin_registry_get_registrar_for_plugin(registry, "UrlLauncherPlugin"); 16 | url_launcher_plugin_register_with_registrar(url_launcher_linux_registrar); 17 | g_autoptr(FlPluginRegistrar) color_panel_registrar = 18 | fl_plugin_registry_get_registrar_for_plugin(registry, "ColorPanelPlugin"); 19 | color_panel_plugin_register_with_registrar(color_panel_registrar); 20 | g_autoptr(FlPluginRegistrar) file_chooser_registrar = 21 | fl_plugin_registry_get_registrar_for_plugin(registry, "FileChooserPlugin"); 22 | file_chooser_plugin_register_with_registrar(file_chooser_registrar); 23 | g_autoptr(FlPluginRegistrar) menubar_registrar = 24 | fl_plugin_registry_get_registrar_for_plugin(registry, "MenubarPlugin"); 25 | menubar_plugin_register_with_registrar(menubar_registrar); 26 | g_autoptr(FlPluginRegistrar) window_size_registrar = 27 | fl_plugin_registry_get_registrar_for_plugin(registry, "WindowSizePlugin"); 28 | window_size_plugin_register_with_registrar(window_size_registrar); 29 | } 30 | -------------------------------------------------------------------------------- /plugins/README.md: -------------------------------------------------------------------------------- 1 | # Desktop Plugins 2 | 3 | See [the Flutter desktop 4 | page](https://github.com/flutter/flutter/wiki/Desktop-shells#plugins) 5 | for an overview of the current state of plugin development on desktop. 6 | 7 | This directory contains two types of plugins: 8 | * `flutter_plugins`, which contain Windows and Linux implementations of plugins 9 | from [the flutter/plugins repository](https://github.com/flutter/plugins). 10 | They are expected to move to that repository once the plugin APIs for those 11 | platforms are sufficiently stable. 12 | * Plugins that prototype functionality that will likely become part of 13 | Flutter itself. 14 | 15 | ## Using Plugins 16 | 17 | Since the plugins in this repository are not intended to live here long term, 18 | and the `flutter` tool's plugin support isn't finalized on all platforms yet, 19 | these plugins are not published on pub.dev like normal Flutter plugins. Instead, 20 | you should include them directly from this repository: 21 | 22 | ``` 23 | dependencies: 24 | ... 25 | file_chooser: 26 | git: 27 | url: git://github.com/google/flutter-desktop-embedding.git 28 | path: plugins/file_chooser 29 | ref: INSERT_HASH_HERE 30 | ``` 31 | 32 | Replace `INSERT_HASH_HERE` with the hash of commit you want to pin to, 33 | usually the latest commit to the repository at the time you add the plugin. 34 | While omitting the `ref` is possible, it is **strongly** discouraged, as 35 | without it any breaking change to the plugin would break your project 36 | without warning. 37 | -------------------------------------------------------------------------------- /plugins/window_size/linux/include/window_size/window_size_plugin.h: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | #ifndef PLUGINS_WINDOW_SIZE_LINUX_WINDOW_SIZE_PLUGIN_H_ 15 | #define PLUGINS_WINDOW_SIZE_LINUX_WINDOW_SIZE_PLUGIN_H_ 16 | 17 | // A plugin to allow resizing the window. 18 | 19 | #include 20 | 21 | G_BEGIN_DECLS 22 | 23 | #ifdef FLUTTER_PLUGIN_IMPL 24 | #define FLUTTER_PLUGIN_EXPORT __attribute__((visibility("default"))) 25 | #else 26 | #define FLUTTER_PLUGIN_EXPORT 27 | #endif 28 | 29 | G_DECLARE_FINAL_TYPE(FlWindowSizePlugin, fl_window_size_plugin, FL, 30 | WINDOW_SIZE_PLUGIN, GObject) 31 | 32 | FLUTTER_PLUGIN_EXPORT FlWindowSizePlugin* fl_window_size_plugin_new( 33 | FlPluginRegistrar* registrar); 34 | 35 | FLUTTER_PLUGIN_EXPORT void window_size_plugin_register_with_registrar( 36 | FlPluginRegistrar* registrar); 37 | 38 | G_END_DECLS 39 | 40 | #endif // PLUGINS_WINDOW_SIZE_LINUX_WINDOW_SIZE_PLUGIN_H_ 41 | -------------------------------------------------------------------------------- /plugins/color_panel/linux/include/color_panel/color_panel_plugin.h: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | #ifndef PLUGINS_COLOR_PANEL_LINUX_COLOR_PANEL_PLUGIN_H_ 15 | #define PLUGINS_COLOR_PANEL_LINUX_COLOR_PANEL_PLUGIN_H_ 16 | 17 | // A plugin for communicating with a native color picker panel. 18 | 19 | #include 20 | 21 | G_BEGIN_DECLS 22 | 23 | #ifdef FLUTTER_PLUGIN_IMPL 24 | #define FLUTTER_PLUGIN_EXPORT __attribute__((visibility("default"))) 25 | #else 26 | #define FLUTTER_PLUGIN_EXPORT 27 | #endif 28 | 29 | G_DECLARE_FINAL_TYPE(FlColorPanelPlugin, fl_color_panel_plugin, FL, 30 | COLOR_PANEL_PLUGIN, GObject) 31 | 32 | FLUTTER_PLUGIN_EXPORT FlColorPanelPlugin* fl_color_panel_plugin_new( 33 | FlPluginRegistrar* registrar); 34 | 35 | FLUTTER_PLUGIN_EXPORT void color_panel_plugin_register_with_registrar( 36 | FlPluginRegistrar* registrar); 37 | 38 | G_END_DECLS 39 | 40 | #endif // PLUGINS_COLOR_PANEL_LINUX_COLOR_PANEL_PLUGIN_H_ 41 | -------------------------------------------------------------------------------- /plugins/file_chooser/linux/include/file_chooser/file_chooser_plugin.h: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | #ifndef PLUGINS_FILE_CHOOSER_LINUX_FILE_CHOOSER_PLUGIN_H_ 15 | #define PLUGINS_FILE_CHOOSER_LINUX_FILE_CHOOSER_PLUGIN_H_ 16 | 17 | // A plugin to show native save/open file choosers. 18 | 19 | #include 20 | 21 | G_BEGIN_DECLS 22 | 23 | #ifdef FLUTTER_PLUGIN_IMPL 24 | #define FLUTTER_PLUGIN_EXPORT __attribute__((visibility("default"))) 25 | #else 26 | #define FLUTTER_PLUGIN_EXPORT 27 | #endif 28 | 29 | G_DECLARE_FINAL_TYPE(FlFileChooserPlugin, fl_file_chooser_plugin, FL, 30 | FILE_CHOOSER_PLUGIN, GObject) 31 | 32 | FLUTTER_PLUGIN_EXPORT FlFileChooserPlugin* fl_file_chooser_plugin_new( 33 | FlPluginRegistrar* registrar); 34 | 35 | FLUTTER_PLUGIN_EXPORT void file_chooser_plugin_register_with_registrar( 36 | FlPluginRegistrar* registrar); 37 | 38 | G_END_DECLS 39 | 40 | #endif // PLUGINS_FILE_CHOOSER_LINUX_FILE_CHOOSER_PLUGIN_H_ 41 | -------------------------------------------------------------------------------- /linux/my_application.cc: -------------------------------------------------------------------------------- 1 | #include "my_application.h" 2 | 3 | #include 4 | 5 | #include "flutter/generated_plugin_registrant.h" 6 | 7 | struct _MyApplication { 8 | GtkApplication parent_instance; 9 | }; 10 | 11 | G_DEFINE_TYPE(MyApplication, my_application, GTK_TYPE_APPLICATION) 12 | 13 | // Implements GApplication::activate. 14 | static void my_application_activate(GApplication* application) { 15 | GtkWindow* window = 16 | GTK_WINDOW(gtk_application_window_new(GTK_APPLICATION(application))); 17 | GtkHeaderBar *header_bar = GTK_HEADER_BAR(gtk_header_bar_new()); 18 | gtk_widget_show(GTK_WIDGET(header_bar)); 19 | gtk_header_bar_set_title(header_bar, "counter"); 20 | gtk_header_bar_set_show_close_button(header_bar, TRUE); 21 | gtk_window_set_titlebar(window, GTK_WIDGET(header_bar)); 22 | gtk_window_set_default_size(window, 1280, 720); 23 | gtk_widget_show(GTK_WIDGET(window)); 24 | 25 | g_autoptr(FlDartProject) project = fl_dart_project_new(); 26 | 27 | FlView* view = fl_view_new(project); 28 | gtk_widget_show(GTK_WIDGET(view)); 29 | gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(view)); 30 | 31 | fl_register_plugins(FL_PLUGIN_REGISTRY(view)); 32 | 33 | gtk_widget_grab_focus(GTK_WIDGET(view)); 34 | } 35 | 36 | static void my_application_class_init(MyApplicationClass* klass) { 37 | G_APPLICATION_CLASS(klass)->activate = my_application_activate; 38 | } 39 | 40 | static void my_application_init(MyApplication* self) {} 41 | 42 | MyApplication* my_application_new() { 43 | return MY_APPLICATION(g_object_new(my_application_get_type(), nullptr)); 44 | } 45 | -------------------------------------------------------------------------------- /ios/Runner/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /ios/Runner/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | counter 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | $(FLUTTER_BUILD_NAME) 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(FLUTTER_BUILD_NUMBER) 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UISupportedInterfaceOrientations 30 | 31 | UIInterfaceOrientationPortrait 32 | UIInterfaceOrientationLandscapeLeft 33 | UIInterfaceOrientationLandscapeRight 34 | 35 | UISupportedInterfaceOrientations~ipad 36 | 37 | UIInterfaceOrientationPortrait 38 | UIInterfaceOrientationPortraitUpsideDown 39 | UIInterfaceOrientationLandscapeLeft 40 | UIInterfaceOrientationLandscapeRight 41 | 42 | UIViewControllerBasedStatusBarAppearance 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /android/app/build.gradle: -------------------------------------------------------------------------------- 1 | def localProperties = new Properties() 2 | def localPropertiesFile = rootProject.file('local.properties') 3 | if (localPropertiesFile.exists()) { 4 | localPropertiesFile.withReader('UTF-8') { reader -> 5 | localProperties.load(reader) 6 | } 7 | } 8 | 9 | def flutterRoot = localProperties.getProperty('flutter.sdk') 10 | if (flutterRoot == null) { 11 | throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") 12 | } 13 | 14 | def flutterVersionCode = localProperties.getProperty('flutter.versionCode') 15 | if (flutterVersionCode == null) { 16 | flutterVersionCode = '1' 17 | } 18 | 19 | def flutterVersionName = localProperties.getProperty('flutter.versionName') 20 | if (flutterVersionName == null) { 21 | flutterVersionName = '1.0' 22 | } 23 | 24 | apply plugin: 'com.android.application' 25 | apply plugin: 'kotlin-android' 26 | apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" 27 | 28 | android { 29 | compileSdkVersion 28 30 | 31 | sourceSets { 32 | main.java.srcDirs += 'src/main/kotlin' 33 | } 34 | 35 | lintOptions { 36 | disable 'InvalidPackage' 37 | } 38 | 39 | defaultConfig { 40 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). 41 | applicationId "com.example.counter" 42 | minSdkVersion 16 43 | targetSdkVersion 28 44 | versionCode flutterVersionCode.toInteger() 45 | versionName flutterVersionName 46 | } 47 | 48 | buildTypes { 49 | release { 50 | // TODO: Add your own signing config for the release build. 51 | // Signing with the debug keys for now, so `flutter run --release` works. 52 | signingConfig signingConfigs.debug 53 | } 54 | } 55 | } 56 | 57 | flutter { 58 | source '../..' 59 | } 60 | 61 | dependencies { 62 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" 63 | } 64 | -------------------------------------------------------------------------------- /ios/Runner/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 8 | 12 | 19 | 23 | 27 | 32 | 36 | 37 | 38 | 39 | 40 | 41 | 43 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /plugins/menubar/lib/src/menu_item.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | import 'package:flutter/widgets.dart'; 15 | import 'package:meta/meta.dart'; 16 | 17 | /// A callback provided to [MenuItem] to handle menu selection. 18 | typedef MenuSelectedCallback = void Function(); 19 | 20 | /// The base type for an individual menu item that can be shown in a menu. 21 | abstract class AbstractMenuItem { 22 | /// Creates a new menu item with the give label. 23 | const AbstractMenuItem(this.label); 24 | 25 | /// The displayed label for the menu item. 26 | final String label; 27 | } 28 | 29 | /// A standard menu item, with no submenus. 30 | class MenuItem extends AbstractMenuItem { 31 | /// Creates a new menu item with the given [label] and options. 32 | /// 33 | /// Note that onClicked should generally be set unless [enabled] is false, 34 | /// or the menu item will be selectable but not do anything. 35 | const MenuItem({ 36 | @required String label, 37 | this.shortcut, 38 | this.enabled = true, 39 | this.onClicked, 40 | }) : super(label); 41 | 42 | /// The callback to call whenever the menu item is selected. 43 | final MenuSelectedCallback onClicked; 44 | 45 | /// Whether or not the menu item is enabled. 46 | final bool enabled; 47 | 48 | /// The shortcut/accelerator for the menu item, if any. 49 | /// 50 | /// Note: Currently modifiers have only Left or Right variants, so must be 51 | /// specified with one of those. The actual left/right distinction will be 52 | /// ignored. This part of the API is likely to change in the future. 53 | /// 54 | /// Example: a Save menu item would likely use: 55 | /// LogicalKeySet(LogicalKeyboardKey.meta, LogicalKeyboardKey.keyS) 56 | final LogicalKeySet shortcut; 57 | } 58 | 59 | /// A menu item continaing a submenu. 60 | /// 61 | /// The item itself can't be selected, it just displays the submenu. 62 | class Submenu extends AbstractMenuItem { 63 | /// Creates a new submenu with the given [label] and [children]. 64 | const Submenu({@required String label, @required this.children}) 65 | : super(label); 66 | 67 | /// The menu items contained in the submenu. 68 | final List children; 69 | } 70 | 71 | /// A menu item that serves as a divider, generally drawn as a line. 72 | class MenuDivider extends AbstractMenuItem { 73 | /// Creates a new divider item. 74 | const MenuDivider() : super(null); 75 | } 76 | -------------------------------------------------------------------------------- /plugins/file_chooser/lib/src/utilities.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | import 'channel_controller.dart'; 15 | import 'filter_group.dart'; 16 | import 'result.dart'; 17 | 18 | /// Shows a file chooser for selecting paths to one or more existing files. 19 | /// 20 | /// A number of configuration options are available: 21 | /// - [initialDirectory] defaults the panel to the given directory path. 22 | /// - [allowedFileTypes] restricts selection to the given file types. 23 | /// - [allowsMultipleSelection] controls whether or not more than one file 24 | /// can be selected. Defaults to single file selection if unset. 25 | /// - [canSelectDirectories] allows choosing directories instead of files. 26 | /// Defaults to file selection if unset. 27 | /// - [confirmButtonText] overrides the button that confirms selection. 28 | Future showOpenPanel({ 29 | String initialDirectory, 30 | List allowedFileTypes, 31 | bool allowsMultipleSelection, 32 | bool canSelectDirectories, 33 | String confirmButtonText, 34 | }) async { 35 | final options = FileChooserConfigurationOptions( 36 | initialDirectory: initialDirectory, 37 | allowedFileTypes: allowedFileTypes, 38 | allowsMultipleSelection: allowsMultipleSelection, 39 | canSelectDirectories: canSelectDirectories, 40 | confirmButtonText: confirmButtonText); 41 | return FileChooserChannelController.instance 42 | .show(FileChooserType.open, options); 43 | } 44 | 45 | /// Shows a file chooser for selecting a save path. 46 | /// 47 | /// A number of configuration options are available: 48 | /// - [initialDirectory] defaults the panel to the given directory path. 49 | /// - [suggestedFileName] provides an initial value for the save filename. 50 | /// - [allowedFileTypes] restricts selection to the given file types. 51 | /// - [confirmButtonText] overrides the button that confirms selection. 52 | Future showSavePanel( 53 | {String initialDirectory, 54 | String suggestedFileName, 55 | List allowedFileTypes, 56 | String confirmButtonText}) async { 57 | final options = FileChooserConfigurationOptions( 58 | initialDirectory: initialDirectory, 59 | initialFileName: suggestedFileName, 60 | allowedFileTypes: allowedFileTypes, 61 | confirmButtonText: confirmButtonText); 62 | return FileChooserChannelController.instance 63 | .show(FileChooserType.save, options); 64 | } 65 | -------------------------------------------------------------------------------- /linux/flutter/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.10) 2 | 3 | set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral") 4 | 5 | # Configuration provided via flutter tool. 6 | include(${EPHEMERAL_DIR}/generated_config.cmake) 7 | 8 | # TODO: Move the rest of this into files in ephemeral. See 9 | # https://github.com/flutter/flutter/issues/57146. 10 | 11 | # Serves the same purpose as list(TRANSFORM ... PREPEND ...), 12 | # which isn't available in 3.10. 13 | function(list_prepend LIST_NAME PREFIX) 14 | set(NEW_LIST "") 15 | foreach(element ${${LIST_NAME}}) 16 | list(APPEND NEW_LIST "${PREFIX}${element}") 17 | endforeach(element) 18 | set(${LIST_NAME} "${NEW_LIST}" PARENT_SCOPE) 19 | endfunction() 20 | 21 | # === Flutter Library === 22 | # System-level dependencies. 23 | find_package(PkgConfig REQUIRED) 24 | pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) 25 | pkg_check_modules(GLIB REQUIRED IMPORTED_TARGET glib-2.0) 26 | pkg_check_modules(GIO REQUIRED IMPORTED_TARGET gio-2.0) 27 | 28 | set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/libflutter_linux_gtk.so") 29 | 30 | # Published to parent scope for install step. 31 | set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE) 32 | set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE) 33 | set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE) 34 | set(AOT_LIBRARY "${PROJECT_DIR}/build/lib/libapp.so" PARENT_SCOPE) 35 | 36 | list(APPEND FLUTTER_LIBRARY_HEADERS 37 | "fl_basic_message_channel.h" 38 | "fl_binary_codec.h" 39 | "fl_binary_messenger.h" 40 | "fl_dart_project.h" 41 | "fl_engine.h" 42 | "fl_json_message_codec.h" 43 | "fl_json_method_codec.h" 44 | "fl_message_codec.h" 45 | "fl_method_call.h" 46 | "fl_method_channel.h" 47 | "fl_method_codec.h" 48 | "fl_method_response.h" 49 | "fl_plugin_registrar.h" 50 | "fl_plugin_registry.h" 51 | "fl_standard_message_codec.h" 52 | "fl_standard_method_codec.h" 53 | "fl_string_codec.h" 54 | "fl_value.h" 55 | "fl_view.h" 56 | "flutter_linux.h" 57 | ) 58 | list_prepend(FLUTTER_LIBRARY_HEADERS "${EPHEMERAL_DIR}/flutter_linux/") 59 | add_library(flutter INTERFACE) 60 | target_include_directories(flutter INTERFACE 61 | "${EPHEMERAL_DIR}" 62 | ) 63 | target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}") 64 | target_link_libraries(flutter INTERFACE 65 | PkgConfig::GTK 66 | PkgConfig::GLIB 67 | PkgConfig::GIO 68 | ) 69 | add_dependencies(flutter flutter_assemble) 70 | 71 | # === Flutter tool backend === 72 | # _phony_ is a non-existent file to force this command to run every time, 73 | # since currently there's no way to get a full input/output list from the 74 | # flutter tool. 75 | add_custom_command( 76 | OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} 77 | ${CMAKE_CURRENT_BINARY_DIR}/_phony_ 78 | COMMAND ${CMAKE_COMMAND} -E env 79 | ${FLUTTER_TOOL_ENVIRONMENT} 80 | "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.sh" 81 | linux-x64 ${CMAKE_BUILD_TYPE} 82 | ) 83 | add_custom_target(flutter_assemble DEPENDS 84 | "${FLUTTER_LIBRARY}" 85 | ${FLUTTER_LIBRARY_HEADERS} 86 | ) 87 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "20x20", 5 | "idiom" : "iphone", 6 | "filename" : "Icon-App-20x20@2x.png", 7 | "scale" : "2x" 8 | }, 9 | { 10 | "size" : "20x20", 11 | "idiom" : "iphone", 12 | "filename" : "Icon-App-20x20@3x.png", 13 | "scale" : "3x" 14 | }, 15 | { 16 | "size" : "29x29", 17 | "idiom" : "iphone", 18 | "filename" : "Icon-App-29x29@1x.png", 19 | "scale" : "1x" 20 | }, 21 | { 22 | "size" : "29x29", 23 | "idiom" : "iphone", 24 | "filename" : "Icon-App-29x29@2x.png", 25 | "scale" : "2x" 26 | }, 27 | { 28 | "size" : "29x29", 29 | "idiom" : "iphone", 30 | "filename" : "Icon-App-29x29@3x.png", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "size" : "40x40", 35 | "idiom" : "iphone", 36 | "filename" : "Icon-App-40x40@2x.png", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "size" : "40x40", 41 | "idiom" : "iphone", 42 | "filename" : "Icon-App-40x40@3x.png", 43 | "scale" : "3x" 44 | }, 45 | { 46 | "size" : "60x60", 47 | "idiom" : "iphone", 48 | "filename" : "Icon-App-60x60@2x.png", 49 | "scale" : "2x" 50 | }, 51 | { 52 | "size" : "60x60", 53 | "idiom" : "iphone", 54 | "filename" : "Icon-App-60x60@3x.png", 55 | "scale" : "3x" 56 | }, 57 | { 58 | "size" : "20x20", 59 | "idiom" : "ipad", 60 | "filename" : "Icon-App-20x20@1x.png", 61 | "scale" : "1x" 62 | }, 63 | { 64 | "size" : "20x20", 65 | "idiom" : "ipad", 66 | "filename" : "Icon-App-20x20@2x.png", 67 | "scale" : "2x" 68 | }, 69 | { 70 | "size" : "29x29", 71 | "idiom" : "ipad", 72 | "filename" : "Icon-App-29x29@1x.png", 73 | "scale" : "1x" 74 | }, 75 | { 76 | "size" : "29x29", 77 | "idiom" : "ipad", 78 | "filename" : "Icon-App-29x29@2x.png", 79 | "scale" : "2x" 80 | }, 81 | { 82 | "size" : "40x40", 83 | "idiom" : "ipad", 84 | "filename" : "Icon-App-40x40@1x.png", 85 | "scale" : "1x" 86 | }, 87 | { 88 | "size" : "40x40", 89 | "idiom" : "ipad", 90 | "filename" : "Icon-App-40x40@2x.png", 91 | "scale" : "2x" 92 | }, 93 | { 94 | "size" : "76x76", 95 | "idiom" : "ipad", 96 | "filename" : "Icon-App-76x76@1x.png", 97 | "scale" : "1x" 98 | }, 99 | { 100 | "size" : "76x76", 101 | "idiom" : "ipad", 102 | "filename" : "Icon-App-76x76@2x.png", 103 | "scale" : "2x" 104 | }, 105 | { 106 | "size" : "83.5x83.5", 107 | "idiom" : "ipad", 108 | "filename" : "Icon-App-83.5x83.5@2x.png", 109 | "scale" : "2x" 110 | }, 111 | { 112 | "size" : "1024x1024", 113 | "idiom" : "ios-marketing", 114 | "filename" : "Icon-App-1024x1024@1x.png", 115 | "scale" : "1x" 116 | } 117 | ], 118 | "info" : { 119 | "version" : 1, 120 | "author" : "xcode" 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /plugins/window_size/lib/src/window_size_utils.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | import 'dart:async'; 15 | import 'dart:ui'; 16 | 17 | import 'platform_window.dart'; 18 | import 'screen.dart'; 19 | import 'window_size_channel.dart'; 20 | 21 | /// Returns a list of [Screen]s for the current screen configuration. 22 | /// 23 | /// It is possible for this list to be empty, if the machine is running in 24 | /// a headless mode. 25 | Future> getScreenList() async { 26 | return await WindowSizeChannel.instance.getScreenList(); 27 | } 28 | 29 | /// Returns the [Screen] showing the window that contains this Flutter instance. 30 | /// 31 | /// If the window is not being displayed, returns null. If the window is being 32 | /// displayed on multiple screens, the platform can return any of those screens. 33 | Future getCurrentScreen() async { 34 | final windowInfo = await WindowSizeChannel.instance.getWindowInfo(); 35 | return windowInfo.screen; 36 | } 37 | 38 | /// Returns information about the window containing this Flutter instance. 39 | Future getWindowInfo() async { 40 | return await WindowSizeChannel.instance.getWindowInfo(); 41 | } 42 | 43 | /// Sets the frame of the window containing this Flutter instance, in 44 | /// screen coordinates. 45 | /// 46 | /// The platform may adjust the frame as necessary if the provided frame would 47 | /// cause significant usability issues (e.g., a window with no visible portion 48 | /// that can be used to move the window). 49 | void setWindowFrame(Rect frame) async { 50 | WindowSizeChannel.instance.setWindowFrame(frame); 51 | } 52 | 53 | /// Sets the minimum [Size] of the window containing this Flutter instance. 54 | void setWindowMinSize(Size size) async { 55 | WindowSizeChannel.instance.setWindowMinSize(size); 56 | } 57 | 58 | /// Sets the maximum [Size] of the window containing this Flutter instance. 59 | void setWindowMaxSize(Size size) async { 60 | WindowSizeChannel.instance.setWindowMaxSize(size); 61 | } 62 | 63 | /// Sets the window title, as a [String], of the window containing this Flutter instance. 64 | void setWindowTitle(String title) async { 65 | WindowSizeChannel.instance.setWindowTitle(title); 66 | } 67 | 68 | /// Sets the window title's represented [Uri], of the window containing this Flutter instance. 69 | /// 70 | /// Only implemented for macOS. If the URL is a file URL, the 71 | /// window shows an icon in its title bar. 72 | void setWindowTitleRepresentedUrl(Uri url) async { 73 | WindowSizeChannel.instance.setWindowTitleRepresentedUrl(url); 74 | } 75 | 76 | /// Gets the minimum [Size] of the window containing this Flutter instance. 77 | Future getWindowMinSize() async { 78 | return WindowSizeChannel.instance.getWindowMinSize(); 79 | } 80 | 81 | /// Gets the maximum [Size] of the window containing this Flutter instance. 82 | Future getWindowMaxSize() async { 83 | return WindowSizeChannel.instance.getWindowMaxSize(); 84 | } 85 | -------------------------------------------------------------------------------- /linux/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.10) 2 | project(runner LANGUAGES CXX) 3 | 4 | set(BINARY_NAME "counter") 5 | 6 | cmake_policy(SET CMP0063 NEW) 7 | 8 | set(CMAKE_INSTALL_RPATH "$ORIGIN/lib") 9 | 10 | # Configure build options. 11 | if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) 12 | set(CMAKE_BUILD_TYPE "Debug" CACHE 13 | STRING "Flutter build mode" FORCE) 14 | set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS 15 | "Debug" "Profile" "Release") 16 | endif() 17 | 18 | # Compilation settings that should be applied to most targets. 19 | function(APPLY_STANDARD_SETTINGS TARGET) 20 | target_compile_features(${TARGET} PUBLIC cxx_std_14) 21 | target_compile_options(${TARGET} PRIVATE -Wall -Werror) 22 | target_compile_options(${TARGET} PRIVATE "$<$>:-O3>") 23 | target_compile_definitions(${TARGET} PRIVATE "$<$>:NDEBUG>") 24 | endfunction() 25 | 26 | set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") 27 | 28 | # Flutter library and tool build rules. 29 | add_subdirectory(${FLUTTER_MANAGED_DIR}) 30 | 31 | # System-level dependencies. 32 | find_package(PkgConfig REQUIRED) 33 | pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) 34 | 35 | # Application build 36 | add_executable(${BINARY_NAME} 37 | "main.cc" 38 | "my_application.cc" 39 | "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" 40 | ) 41 | apply_standard_settings(${BINARY_NAME}) 42 | target_link_libraries(${BINARY_NAME} PRIVATE flutter) 43 | target_link_libraries(${BINARY_NAME} PRIVATE PkgConfig::GTK) 44 | add_dependencies(${BINARY_NAME} flutter_assemble) 45 | 46 | # Generated plugin build rules, which manage building the plugins and adding 47 | # them to the application. 48 | include(flutter/generated_plugins.cmake) 49 | 50 | 51 | # === Installation === 52 | # By default, "installing" just makes a relocatable bundle in the build 53 | # directory. 54 | set(BUILD_BUNDLE_DIR "${PROJECT_BINARY_DIR}/bundle") 55 | if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) 56 | set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE) 57 | endif() 58 | 59 | # Start with a clean build bundle directory every time. 60 | install(CODE " 61 | file(REMOVE_RECURSE \"${BUILD_BUNDLE_DIR}/\") 62 | " COMPONENT Runtime) 63 | 64 | set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data") 65 | set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib") 66 | 67 | install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}" 68 | COMPONENT Runtime) 69 | 70 | install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" 71 | COMPONENT Runtime) 72 | 73 | install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" 74 | COMPONENT Runtime) 75 | 76 | if(PLUGIN_BUNDLED_LIBRARIES) 77 | install(FILES "${PLUGIN_BUNDLED_LIBRARIES}" 78 | DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" 79 | COMPONENT Runtime) 80 | endif() 81 | 82 | # Fully re-copy the assets directory on each build to avoid having stale files 83 | # from a previous install. 84 | set(FLUTTER_ASSET_DIR_NAME "flutter_assets") 85 | install(CODE " 86 | file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\") 87 | " COMPONENT Runtime) 88 | install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}" 89 | DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) 90 | 91 | # Install the AOT library on non-Debug builds only. 92 | if(NOT CMAKE_BUILD_TYPE MATCHES "Debug") 93 | install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" 94 | COMPONENT Runtime) 95 | endif() 96 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 39 | 40 | 41 | 42 | 43 | 44 | 54 | 56 | 62 | 63 | 64 | 65 | 66 | 67 | 73 | 75 | 81 | 82 | 83 | 84 | 86 | 87 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /plugins/flutter_plugins/url_launcher_fde/windows/url_launcher_plugin.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | #include "include/url_launcher_fde/url_launcher_plugin.h" 15 | 16 | // Must be before VersionHelpers.h 17 | #include 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | #include 25 | #include 26 | 27 | namespace { 28 | 29 | using flutter::EncodableMap; 30 | using flutter::EncodableValue; 31 | 32 | class UrlLauncherPlugin : public flutter::Plugin { 33 | public: 34 | static void RegisterWithRegistrar(flutter::PluginRegistrar *registrar); 35 | 36 | virtual ~UrlLauncherPlugin(); 37 | 38 | private: 39 | UrlLauncherPlugin(); 40 | 41 | // Called when a method is called on plugin channel; 42 | void HandleMethodCall( 43 | const flutter::MethodCall &method_call, 44 | std::unique_ptr> result); 45 | }; 46 | 47 | // static 48 | void UrlLauncherPlugin::RegisterWithRegistrar( 49 | flutter::PluginRegistrar *registrar) { 50 | auto channel = std::make_unique>( 51 | registrar->messenger(), "plugins.flutter.io/url_launcher", 52 | &flutter::StandardMethodCodec::GetInstance()); 53 | 54 | // Uses new instead of make_unique due to private constructor. 55 | std::unique_ptr plugin(new UrlLauncherPlugin()); 56 | 57 | channel->SetMethodCallHandler( 58 | [plugin_pointer = plugin.get()](const auto &call, auto result) { 59 | plugin_pointer->HandleMethodCall(call, std::move(result)); 60 | }); 61 | 62 | registrar->AddPlugin(std::move(plugin)); 63 | } 64 | 65 | UrlLauncherPlugin::UrlLauncherPlugin() = default; 66 | 67 | UrlLauncherPlugin::~UrlLauncherPlugin() = default; 68 | 69 | void UrlLauncherPlugin::HandleMethodCall( 70 | const flutter::MethodCall &method_call, 71 | std::unique_ptr> result) { 72 | if (method_call.method_name().compare("launch") == 0) { 73 | std::string url; 74 | if (method_call.arguments() && method_call.arguments()->IsMap()) { 75 | const EncodableMap &arguments = method_call.arguments()->MapValue(); 76 | auto url_it = arguments.find(EncodableValue("url")); 77 | if (url_it != arguments.end()) { 78 | url = url_it->second.StringValue(); 79 | } 80 | } 81 | if (url.empty()) { 82 | result->Error("argument_error", "No URL provided"); 83 | return; 84 | } 85 | 86 | // launch a URL on Windows 87 | size_t size = url.length() + 1; 88 | std::wstring wurl; 89 | wurl.reserve(size); 90 | size_t outSize; 91 | mbstowcs_s(&outSize, &wurl[0], size, url.c_str(), size - 1); 92 | 93 | int status = static_cast(reinterpret_cast(ShellExecute( 94 | nullptr, TEXT("open"), wurl.c_str(), nullptr, nullptr, SW_SHOWNORMAL))); 95 | 96 | if (status <= 32) { 97 | std::ostringstream error_message; 98 | error_message << "Failed to open " << url << ": ShellExecute error code " 99 | << status; 100 | result->Error("open_error", error_message.str()); 101 | return; 102 | } 103 | result->Success(); 104 | } else { 105 | result->NotImplemented(); 106 | } 107 | } 108 | 109 | } // namespace 110 | 111 | void UrlLauncherPluginRegisterWithRegistrar( 112 | FlutterDesktopPluginRegistrarRef registrar) { 113 | UrlLauncherPlugin::RegisterWithRegistrar( 114 | flutter::PluginRegistrarManager::GetInstance() 115 | ->GetRegistrar(registrar)); 116 | } 117 | -------------------------------------------------------------------------------- /plugins/color_panel/lib/color_panel.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | import 'dart:async'; 15 | import 'dart:ui'; 16 | 17 | import 'package:flutter/services.dart'; 18 | 19 | /// The name of the plugin's platform channel. 20 | const String _kColorPanelChannel = 'flutter/colorpanel'; 21 | 22 | /// The method name to instruct the native plugin to show the panel. 23 | const String _kShowColorPanelMethod = 'ColorPanel.Show'; 24 | /// The method name to instruct the native plugin to hide the panel. 25 | const String _kHideColorPanelMethod = 'ColorPanel.Hide'; 26 | /// The method name for the Dart-side callback that receives color values. 27 | const String _kColorPanelColorSelectedCallback = 28 | 'ColorPanel.ColorSelectedCallback'; 29 | /// The method name for the Dart-side callback that is called if the panel is 30 | /// closed from the UI, rather than via a call to kHideColorPanelMethod. 31 | const String _kColorPanelClosedCallback = 'ColorPanel.ClosedCallback'; 32 | 33 | /// The argument to show an opacity modifier on the panel. Default is true. 34 | const String _kColorPanelShowAlpha = 'ColorPanel.ShowAlpha'; 35 | 36 | // Keys for the ARGB color map sent to kColorPanelCallback. 37 | // The values should be numbers between 0 and 1. 38 | const String _kRedKey = 'red'; 39 | const String _kGreenKey = 'green'; 40 | const String _kBlueKey = 'blue'; 41 | // Platform implementations should return 1 if the opacity slider is not shown. 42 | const String _kAlphaKey = 'alpha'; 43 | 44 | const MethodChannel _platformChannel = const MethodChannel(_kColorPanelChannel); 45 | 46 | /// A callback to pass to [ColorPanel] to receive user-selected colors. 47 | typedef ColorPanelCallback = void Function(Color color); 48 | 49 | /// Provides access to an OS-provided color chooser. 50 | /// 51 | /// This class is a singleton, since the OS may not allow multiple color panels 52 | /// simultaneously. 53 | class ColorPanel { 54 | /// Private constructor. 55 | ColorPanel._() { 56 | _platformChannel.setMethodCallHandler(_wrappedColorPanelCallback); 57 | } 58 | 59 | ColorPanelCallback _callback; 60 | 61 | /// The static instance of the panel. 62 | static ColorPanel instance = new ColorPanel._(); 63 | 64 | /// Whether or not the panel is showing. 65 | bool get showing => _callback != null; 66 | 67 | /// Shows the color panel. 68 | /// 69 | /// [callback] will be called when the user selects a color; it can be called 70 | /// an number of times depending on the interaction model of the native 71 | /// panel. Set [showAlpha] to false to hide the color opacity modifier UI. 72 | /// 73 | /// It is an error to call [show] if the panel is already showing. 74 | void show(ColorPanelCallback callback, {bool showAlpha = true}) { 75 | try { 76 | if (!showing) { 77 | _callback = callback; 78 | _platformChannel.invokeMethod( 79 | _kShowColorPanelMethod, {_kColorPanelShowAlpha: showAlpha}); 80 | } else { 81 | throw new StateError('Color panel is already shown'); 82 | } 83 | } on PlatformException catch (e) { 84 | print('PLATFORM ERROR: ${e.message}'); 85 | } 86 | } 87 | 88 | /// Hides the color panel. 89 | /// 90 | /// It is an error to call [hide] if the panel is not showing. Since 91 | /// the panel can be closed by the user, you should always check 92 | /// [showing] before calling [hide]. 93 | void hide() { 94 | try { 95 | if (showing) { 96 | _platformChannel.invokeMethod(_kHideColorPanelMethod); 97 | _callback = null; 98 | } else { 99 | throw new StateError('Color panel is already hidden'); 100 | } 101 | } on PlatformException catch (e) { 102 | print('PLATFORM ERROR: ${e.message}'); 103 | } 104 | } 105 | 106 | /// Given a color component value from 0-1, converts it to an int 107 | /// from 0-255. 108 | int _colorComponentFloatToInt(num value) { 109 | const colorMax = 255; 110 | return (value * colorMax).round(); 111 | } 112 | 113 | /// Mediates between the platform channel callback and the client callback. 114 | Future _wrappedColorPanelCallback(MethodCall methodCall) async { 115 | if (methodCall.method == _kColorPanelClosedCallback) { 116 | _callback = null; 117 | } else if (_callback != null && 118 | methodCall.method == _kColorPanelColorSelectedCallback) { 119 | try { 120 | final Map arg = 121 | methodCall.arguments.cast(); 122 | if (arg != null) { 123 | _callback(Color.fromARGB( 124 | _colorComponentFloatToInt(arg[_kAlphaKey]), 125 | _colorComponentFloatToInt(arg[_kRedKey]), 126 | _colorComponentFloatToInt(arg[_kGreenKey]), 127 | _colorComponentFloatToInt(arg[_kBlueKey]))); 128 | } 129 | } on Exception catch (e, s) { 130 | print('Exception in callback handler: $e\n$s'); 131 | } 132 | } 133 | } 134 | } 135 | -------------------------------------------------------------------------------- /plugins/file_chooser/macos/Classes/FLEFileChooserPlugin.m: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #import "FLEFileChooserPlugin.h" 16 | 17 | #import 18 | 19 | // See channel_controller.dart for documentation. 20 | static NSString *const kChannelName = @"flutter/filechooser"; 21 | static NSString *const kShowOpenPanelMethod = @"FileChooser.Show.Open"; 22 | static NSString *const kShowSavePanelMethod = @"FileChooser.Show.Save"; 23 | static NSString *const kInitialDirectoryKey = @"initialDirectory"; 24 | static NSString *const kInitialFileNameKey = @"initialFileName"; 25 | static NSString *const kAllowedFileTypesKey = @"allowedFileTypes"; 26 | static NSString *const kConfirmButtonTextKey = @"confirmButtonText"; 27 | static NSString *const kAllowsMultipleSelectionKey = @"allowsMultipleSelection"; 28 | static NSString *const kCanChooseDirectoriesKey = @"canChooseDirectories"; 29 | 30 | @implementation FLEFileChooserPlugin { 31 | // The plugin registrar, for obtaining the view. 32 | NSObject *_registrar; 33 | } 34 | 35 | - (instancetype)initWithRegistrar:(NSObject *)registrar { 36 | self = [super init]; 37 | if (self != nil) { 38 | _registrar = registrar; 39 | } 40 | return self; 41 | } 42 | 43 | /** 44 | * Configures an NSSavePanel instance on behalf of a flutter client. 45 | * 46 | * @param panel - The panel to configure. 47 | * @param arguments - A dictionary of method arguments used to configure a panel instance. 48 | */ 49 | - (void)configureSavePanel:(nonnull NSSavePanel *)panel 50 | withArguments:(nonnull NSDictionary *)arguments { 51 | NSSet *argKeys = [NSSet setWithArray:arguments.allKeys]; 52 | if ([argKeys containsObject:kInitialDirectoryKey]) { 53 | panel.directoryURL = [NSURL URLWithString:arguments[kInitialDirectoryKey]]; 54 | } 55 | if ([argKeys containsObject:kAllowedFileTypesKey]) { 56 | // macOS doesn't support filter groups, so combine all allowed types into a flat list. 57 | NSMutableArray *allowedTypes = [NSMutableArray array]; 58 | for (NSArray *filter in arguments[kAllowedFileTypesKey]) { 59 | NSArray *extensions = filter[1]; 60 | // If any group allows all extensions, don't do any filtering. 61 | if (extensions.count == 0) { 62 | allowedTypes = nil; 63 | break; 64 | } 65 | [allowedTypes addObjectsFromArray:extensions]; 66 | } 67 | panel.allowedFileTypes = allowedTypes; 68 | } 69 | if ([argKeys containsObject:kInitialFileNameKey]) { 70 | panel.nameFieldStringValue = arguments[kInitialFileNameKey]; 71 | } 72 | if ([argKeys containsObject:kConfirmButtonTextKey]) { 73 | panel.prompt = arguments[kConfirmButtonTextKey]; 74 | } 75 | } 76 | 77 | /** 78 | * Configures an NSOpenPanel instance on behalf of a flutter client. 79 | * 80 | * @param panel - The open panel to configure. 81 | * @param arguments - A dictionary of method arguments used to configure a panel instance. 82 | */ 83 | - (void)configureOpenPanel:(nonnull NSOpenPanel *)panel 84 | withArguments:(nonnull NSDictionary *)arguments { 85 | NSSet *argKeys = [NSSet setWithArray:arguments.allKeys]; 86 | if ([argKeys containsObject:kAllowsMultipleSelectionKey]) { 87 | panel.allowsMultipleSelection = [arguments[kAllowsMultipleSelectionKey] boolValue]; 88 | } 89 | if ([argKeys containsObject:kCanChooseDirectoriesKey]) { 90 | BOOL canChooseDirectories = [arguments[kCanChooseDirectoriesKey] boolValue]; 91 | panel.canChooseDirectories = canChooseDirectories; 92 | panel.canChooseFiles = !canChooseDirectories; 93 | } 94 | } 95 | 96 | #pragma FlutterPlugin implementation 97 | 98 | + (void)registerWithRegistrar:(id)registrar { 99 | FlutterMethodChannel *channel = [FlutterMethodChannel methodChannelWithName:kChannelName 100 | binaryMessenger:registrar.messenger]; 101 | FLEFileChooserPlugin *instance = [[FLEFileChooserPlugin alloc] initWithRegistrar:registrar]; 102 | [registrar addMethodCallDelegate:instance channel:channel]; 103 | } 104 | 105 | - (void)handleMethodCall:(FlutterMethodCall *)call result:(FlutterResult)result { 106 | NSDictionary *arguments = call.arguments; 107 | 108 | if ([call.method isEqualToString:kShowSavePanelMethod]) { 109 | NSSavePanel *savePanel = [NSSavePanel savePanel]; 110 | savePanel.canCreateDirectories = YES; 111 | [self configureSavePanel:savePanel withArguments:arguments]; 112 | [savePanel beginSheetModalForWindow:_registrar.view.window 113 | completionHandler:^(NSModalResponse panelResult) { 114 | NSArray *URLs = 115 | (panelResult == NSModalResponseOK) ? @[ savePanel.URL ] : nil; 116 | result([URLs valueForKey:@"path"]); 117 | }]; 118 | 119 | } else if ([call.method isEqualToString:kShowOpenPanelMethod]) { 120 | NSOpenPanel *openPanel = [NSOpenPanel openPanel]; 121 | [self configureSavePanel:openPanel withArguments:arguments]; 122 | [self configureOpenPanel:openPanel withArguments:arguments]; 123 | [openPanel beginSheetModalForWindow:_registrar.view.window 124 | completionHandler:^(NSModalResponse panelResult) { 125 | NSArray *URLs = 126 | (panelResult == NSModalResponseOK) ? openPanel.URLs : nil; 127 | result([URLs valueForKey:@"path"]); 128 | }]; 129 | } else { 130 | result(FlutterMethodNotImplemented); 131 | } 132 | } 133 | 134 | @end 135 | -------------------------------------------------------------------------------- /plugins/color_panel/macos/Classes/FLEColorPanelPlugin.m: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #import "FLEColorPanelPlugin.h" 16 | 17 | #import 18 | 19 | // See color_panel.dart for descriptions. 20 | static NSString *const kChannelName = @"flutter/colorpanel"; 21 | static NSString *const kShowColorPanelMethod = @"ColorPanel.Show"; 22 | static NSString *const kColorPanelShowAlpha = @"ColorPanel.ShowAlpha"; 23 | static NSString *const kHideColorPanelMethod = @"ColorPanel.Hide"; 24 | static NSString *const kColorSelectedCallbackMethod = @"ColorPanel.ColorSelectedCallback"; 25 | static NSString *const kClosedCallbackMethod = @"ColorPanel.ClosedCallback"; 26 | static NSString *const kColorComponentAlphaKey = @"alpha"; 27 | static NSString *const kColorComponentRedKey = @"red"; 28 | static NSString *const kColorComponentGreenKey = @"green"; 29 | static NSString *const kColorComponentBlueKey = @"blue"; 30 | 31 | @implementation FLEColorPanelPlugin { 32 | // The channel used to communicate with Flutter. 33 | FlutterMethodChannel *_channel; 34 | } 35 | 36 | + (void)registerWithRegistrar:(id)registrar { 37 | FlutterMethodChannel *channel = [FlutterMethodChannel methodChannelWithName:kChannelName 38 | binaryMessenger:registrar.messenger]; 39 | FLEColorPanelPlugin *instance = [[FLEColorPanelPlugin alloc] initWithChannel:channel]; 40 | [registrar addMethodCallDelegate:instance channel:channel]; 41 | } 42 | 43 | - (instancetype)initWithChannel:(FlutterMethodChannel *)channel { 44 | self = [super init]; 45 | if (self) { 46 | _channel = channel; 47 | } 48 | return self; 49 | } 50 | 51 | /** 52 | * Handles platform messages generated by the Flutter framework on the color 53 | * panel channel. 54 | */ 55 | - (void)handleMethodCall:(FlutterMethodCall *)call result:(FlutterResult)result { 56 | id methodResult = nil; 57 | if ([call.method isEqualToString:kShowColorPanelMethod]) { 58 | if ([call.arguments isKindOfClass:[NSDictionary class]]) { 59 | BOOL showAlpha = [[call.arguments valueForKey:kColorPanelShowAlpha] boolValue]; 60 | [self showColorPanelWithAlpha:showAlpha]; 61 | } else { 62 | NSString *errorString = [NSString 63 | stringWithFormat:@"Malformed call for %@. Expected an NSDictionary but got %@", 64 | kShowColorPanelMethod, NSStringFromClass([call.arguments class])]; 65 | methodResult = [FlutterError errorWithCode:@"Bad arguments" message:errorString details:nil]; 66 | } 67 | } else if ([call.method isEqualToString:kHideColorPanelMethod]) { 68 | [self hideColorPanel]; 69 | } else { 70 | methodResult = FlutterMethodNotImplemented; 71 | } 72 | // If no errors are generated, send an immediate empty success message for handled messages, since 73 | // the actual color data will be provided in follow-up messages. 74 | result(methodResult); 75 | } 76 | 77 | /** 78 | * Configures the shared instance of NSColorPanel and makes it the frontmost & key window. 79 | */ 80 | - (void)showColorPanelWithAlpha:(BOOL)showAlpha { 81 | NSColorPanel *sharedColor = [NSColorPanel sharedColorPanel]; 82 | sharedColor.delegate = self; 83 | [sharedColor setShowsAlpha:showAlpha]; 84 | [sharedColor setTarget:self]; 85 | [sharedColor setAction:@selector(selectedColorDidChange)]; 86 | if (!sharedColor.isKeyWindow) { 87 | [sharedColor makeKeyAndOrderFront:nil]; 88 | } 89 | } 90 | 91 | /** 92 | * Closes the shared color panel. 93 | */ 94 | - (void)hideColorPanel { 95 | if (![NSColorPanel sharedColorPanelExists]) { 96 | return; 97 | } 98 | 99 | // Disconnect before closing to prevent invoking the close callback. 100 | [self removeColorPanelConnections]; 101 | 102 | NSColorPanel *sharedColor = [NSColorPanel sharedColorPanel]; 103 | [sharedColor close]; 104 | } 105 | 106 | /** 107 | * Removes the connections from the shared color panel back to this instance. 108 | */ 109 | - (void)removeColorPanelConnections { 110 | NSColorPanel *sharedColor = [NSColorPanel sharedColorPanel]; 111 | [sharedColor setTarget:nil]; 112 | [sharedColor setAction:nil]; 113 | sharedColor.delegate = nil; 114 | } 115 | 116 | /** 117 | * Called when the user selects a color in the color panel. Grabs the selected color from the 118 | * panel and sends it to Flutter via the '_channel'. 119 | */ 120 | - (void)selectedColorDidChange { 121 | NSColor *color = [NSColorPanel sharedColorPanel].color; 122 | NSDictionary *colorDictionary = [self dictionaryWithColor:color]; 123 | [_channel invokeMethod:kColorSelectedCallbackMethod arguments:colorDictionary]; 124 | } 125 | 126 | /** 127 | * Converts an instance of NSColor to a dictionary representation suitable for Flutter channel 128 | * messages. 129 | * 130 | * @param color An instance of NSColor. 131 | * @return An instance of NSDictionary representing the color. 132 | */ 133 | - (NSDictionary *)dictionaryWithColor:(NSColor *)color { 134 | NSMutableDictionary *result = [NSMutableDictionary dictionary]; 135 | // TODO: Consider being able to pass other type of color space (Gray scale, CMYK, etc). 136 | NSColor *rgbColor = [color colorUsingColorSpace:[NSColorSpace genericRGBColorSpace]]; 137 | result[kColorComponentAlphaKey] = @(rgbColor.alphaComponent); 138 | result[kColorComponentRedKey] = @(rgbColor.redComponent); 139 | result[kColorComponentGreenKey] = @(rgbColor.greenComponent); 140 | result[kColorComponentBlueKey] = @(rgbColor.blueComponent); 141 | return result; 142 | } 143 | 144 | #pragma mark - NSWindowDelegate 145 | 146 | - (void)windowWillClose:(NSNotification *)notification { 147 | [self removeColorPanelConnections]; 148 | [_channel invokeMethod:kClosedCallbackMethod arguments:nil]; 149 | } 150 | 151 | @end 152 | -------------------------------------------------------------------------------- /plugins/file_chooser/lib/src/channel_controller.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | import 'package:flutter/services.dart'; 15 | 16 | import 'filter_group.dart'; 17 | import 'result.dart'; 18 | 19 | /// The name of the plugin's platform channel. 20 | const String _kChannelName = 'flutter/filechooser'; 21 | 22 | /// The method name to instruct the native plugin to show an open panel. 23 | const String _kShowOpenPanelMethod = 'FileChooser.Show.Open'; 24 | 25 | /// The method name to instruct the native plugin to show a save panel. 26 | const String _kShowSavePanelMethod = 'FileChooser.Show.Save'; 27 | 28 | // Configuration parameters for file chooser panels: 29 | 30 | /// The path, as a string, for initial directory to display. Default behavior is 31 | /// left to the OS if not provided.] 32 | const String _kInitialDirectoryKey = 'initialDirectory'; 33 | 34 | /// The initial file name that should appears in the file chooser. Defaults to 35 | /// an empty string if not provided. 36 | const String _kInitialFileNameKey = 'initialFileName'; 37 | 38 | /// An array of UTI or file extension groups a user should be able to select. 39 | /// 40 | /// The format is: 41 | /// [ 42 | /// [ label, [extension, extension, ...] ], 43 | /// [ label, [extension, extension, ...] ], 44 | /// ... 45 | /// ] 46 | /// 47 | /// On platforms that don't support selectable groups (e.g., macOS), the 48 | /// extension lists can be merged. An empty extension array indicates that any 49 | /// type is allowed; when merging, this should cause all other arrays to be 50 | /// ignored. 51 | const String _kAllowedFileTypesKey = 'allowedFileTypes'; 52 | 53 | /// The text that appears on the panel's confirmation button. If not provided, 54 | /// the OS default is used. 55 | const String _kConfirmButtonTextKey = 'confirmButtonText'; 56 | 57 | // Configuration parameters that only apply to open panels: 58 | 59 | /// A boolean indicating whether a panel should allow choosing multiple file 60 | /// paths. Defaults to false if not set. 61 | const String _kAllowsMultipleSelectionKey = 'allowsMultipleSelection'; 62 | 63 | /// A boolean indicating whether a panel should allow choosing directories 64 | /// instead of files. Defaults to false if not set. 65 | const String _kCanChooseDirectoriesKey = 'canChooseDirectories'; 66 | 67 | /// A File chooser type. 68 | enum FileChooserType { 69 | /// An open panel, for choosing one or more files to open. 70 | open, 71 | 72 | /// A save panel, for choosing where to save a file. 73 | save, 74 | } 75 | 76 | /// A set of configuration options for a file chooser. 77 | class FileChooserConfigurationOptions { 78 | /// Creates a new configuration options object with the given settings. 79 | const FileChooserConfigurationOptions( 80 | {this.initialDirectory, 81 | this.initialFileName, 82 | this.allowedFileTypes, 83 | this.allowsMultipleSelection, 84 | this.canSelectDirectories, 85 | this.confirmButtonText}); 86 | 87 | // See the constants above for documentation; these correspond exactly to 88 | // the configuration parameters defined in the channel protocol. 89 | final String initialDirectory; // ignore: public_member_api_docs 90 | final String initialFileName; // ignore: public_member_api_docs 91 | final List 92 | allowedFileTypes; // ignore: public_member_api_docs 93 | final bool allowsMultipleSelection; // ignore: public_member_api_docs 94 | final bool canSelectDirectories; // ignore: public_member_api_docs 95 | final String confirmButtonText; // ignore: public_member_api_docs 96 | 97 | /// Returns the configuration as a map that can be passed as the 98 | /// arguments to invokeMethod for [_kShowOpenPanelMethod] or 99 | /// [_kShowSavePanelMethod]. 100 | Map asInvokeMethodArguments() { 101 | final args = {}; 102 | if (initialDirectory != null && initialDirectory.isNotEmpty) { 103 | args[_kInitialDirectoryKey] = initialDirectory; 104 | } 105 | if (allowsMultipleSelection != null) { 106 | args[_kAllowsMultipleSelectionKey] = allowsMultipleSelection; 107 | } 108 | if (canSelectDirectories != null) { 109 | args[_kCanChooseDirectoriesKey] = canSelectDirectories; 110 | } 111 | if (allowedFileTypes != null && allowedFileTypes.isNotEmpty) { 112 | args[_kAllowedFileTypesKey] = allowedFileTypes 113 | .map((filter) => [filter.label ?? '', filter.fileExtensions ?? []]) 114 | .toList(); 115 | } 116 | if (confirmButtonText != null && confirmButtonText.isNotEmpty) { 117 | args[_kConfirmButtonTextKey] = confirmButtonText; 118 | } 119 | if (confirmButtonText != null && confirmButtonText.isNotEmpty) { 120 | args[_kConfirmButtonTextKey] = confirmButtonText; 121 | } 122 | if (initialFileName != null && initialFileName.isNotEmpty) { 123 | args[_kInitialFileNameKey] = initialFileName; 124 | } 125 | return args; 126 | } 127 | } 128 | 129 | /// A singleton object that controls file-choosing interactions with macOS. 130 | class FileChooserChannelController { 131 | FileChooserChannelController._(); 132 | 133 | /// The platform channel used to manage native file chooser affordances. 134 | final _channel = new MethodChannel(_kChannelName); 135 | 136 | /// A reference to the singleton instance of the class. 137 | static final FileChooserChannelController instance = 138 | new FileChooserChannelController._(); 139 | 140 | /// Shows a file chooser of [type] configured with [options], returning a 141 | /// [FileChooserResult] when complete. 142 | Future show( 143 | FileChooserType type, 144 | FileChooserConfigurationOptions options, 145 | ) async { 146 | final methodName = type == FileChooserType.open 147 | ? _kShowOpenPanelMethod 148 | : _kShowSavePanelMethod; 149 | final paths = await _channel.invokeListMethod( 150 | methodName, options.asInvokeMethodArguments()); 151 | return FileChooserResult(paths: paths ?? [], canceled: paths == null); 152 | } 153 | } 154 | -------------------------------------------------------------------------------- /lib/countdown_timer.dart: -------------------------------------------------------------------------------- 1 | library flutter_package; 2 | 3 | import 'dart:async'; 4 | import 'package:flutter/widgets.dart'; 5 | 6 | /// A Countdown. 7 | class CountdownTimer extends StatefulWidget { 8 | final int endTime; 9 | final String defaultDays; 10 | final String defaultHours; 11 | final String defaultMin; 12 | final String defaultSec; 13 | final String daysSymbol; 14 | final String hoursSymbol; 15 | final String minSymbol; 16 | final String secSymbol; 17 | final TextStyle textStyle; 18 | final TextStyle daysTextStyle; 19 | final TextStyle hoursTextStyle; 20 | final TextStyle minTextStyle; 21 | final TextStyle secTextStyle; 22 | final TextStyle daysSymbolTextStyle; 23 | final TextStyle hoursSymbolTextStyle; 24 | final TextStyle minSymbolTextStyle; 25 | final TextStyle secSymbolTextStyle; 26 | final void Function() onEnd; 27 | 28 | CountdownTimer({ 29 | this.endTime, 30 | this.defaultDays = "--", 31 | this.defaultHours = "--", 32 | this.defaultMin = "--", 33 | this.defaultSec = "--", 34 | this.daysSymbol = "天", 35 | this.hoursSymbol = ":", 36 | this.minSymbol = ":", 37 | this.secSymbol = "", 38 | this.textStyle, 39 | this.daysTextStyle, 40 | this.hoursTextStyle, 41 | this.minTextStyle, 42 | this.secTextStyle, 43 | this.daysSymbolTextStyle, 44 | this.hoursSymbolTextStyle, 45 | this.minSymbolTextStyle, 46 | this.secSymbolTextStyle, 47 | this.onEnd, 48 | }); 49 | 50 | @override 51 | _CountDownState createState() => _CountDownState(); 52 | } 53 | 54 | class _CountDownState extends State { 55 | DiffDate diffDate; 56 | Timer _diffTimer; 57 | final defaultTextStyle = TextStyle(fontSize: 20); 58 | 59 | DiffDate getDateData() { 60 | if (widget.endTime == null) return null; 61 | int diff = ((widget.endTime - DateTime 62 | .now() 63 | .millisecondsSinceEpoch) / 1000).floor(); 64 | if (diff < 0) { 65 | return null; 66 | } 67 | int days, 68 | hours, 69 | min, 70 | sec = 0; 71 | if (diff >= 86400) { 72 | days = (diff / 86400).floor(); 73 | diff -= days * 86400; 74 | } else { 75 | // if days = -1 => Don't show; 76 | days = -1; 77 | } 78 | if (diff >= 3600) { 79 | hours = (diff / 3600).floor(); 80 | diff -= hours * 3600; 81 | } else { 82 | // hours = days == -1 ? -1 : 0; 83 | hours = 0; 84 | } 85 | if (diff >= 60) { 86 | min = (diff / 60).floor(); 87 | diff -= min * 60; 88 | } else { 89 | // min = hours == -1 ? -1 : 0; 90 | min = 0; 91 | } 92 | sec = diff.toInt(); 93 | return DiffDate(days: days, hours: hours, min: min, sec: sec); 94 | } 95 | 96 | @override 97 | void initState() { 98 | timerDiffDate(); 99 | super.initState(); 100 | } 101 | 102 | timerDiffDate() { 103 | DiffDate data = getDateData(); 104 | if (data != null) { 105 | setState(() { 106 | diffDate = data; 107 | }); 108 | } else { 109 | return null; 110 | } 111 | disposeDiffTimer(); 112 | const period = const Duration(seconds: 1); 113 | _diffTimer = Timer.periodic(period, (timer) { 114 | //到时回调 115 | DiffDate data = getDateData(); 116 | if (data != null) { 117 | setState(() { 118 | diffDate = data; 119 | }); 120 | checkDateEnd(data); 121 | } else { 122 | disposeDiffTimer(); 123 | } 124 | }); 125 | } 126 | 127 | @override 128 | void dispose() { 129 | disposeDiffTimer(); 130 | super.dispose(); 131 | } 132 | 133 | disposeDiffTimer() { 134 | _diffTimer?.cancel(); 135 | _diffTimer = null; 136 | } 137 | 138 | @override 139 | void didUpdateWidget(CountdownTimer oldWidget) { 140 | if (oldWidget.endTime != widget.endTime) { 141 | timerDiffDate(); 142 | } 143 | super.didUpdateWidget(oldWidget); 144 | } 145 | 146 | @override 147 | Widget build(BuildContext context) { 148 | return Row( 149 | crossAxisAlignment: CrossAxisAlignment.center, 150 | mainAxisAlignment: MainAxisAlignment.center, 151 | children: _items(), 152 | ); 153 | } 154 | 155 | _getTextStyle(textStyle) { 156 | return textStyle ?? widget.textStyle ?? defaultTextStyle; 157 | } 158 | 159 | _items() { 160 | List list = []; 161 | if (diffDate == null) { 162 | return list; 163 | } 164 | if (diffDate.days != -1) { 165 | var days = _getNumberAddZero(diffDate.days); 166 | list.add(Text( 167 | '${days ?? widget.defaultDays}', 168 | style: _getTextStyle(widget.daysTextStyle), 169 | )); 170 | list.add(Text( 171 | widget.daysSymbol, 172 | style: _getTextStyle(widget.daysSymbolTextStyle), 173 | )); 174 | } 175 | // if (diffDate.hours != -1) { 176 | // var hours = _getNumberAddZero(diffDate.hours); 177 | // list.add(Text( 178 | // '${hours ?? widget.defaultHours}', 179 | // style: _getTextStyle(widget.hoursTextStyle), 180 | // )); 181 | // list.add(Text( 182 | // widget.hoursSymbol, 183 | // style: _getTextStyle(widget.hoursSymbolTextStyle), 184 | // )); 185 | // } 186 | if (diffDate.min != -1) { 187 | var min = _getNumberAddZero(diffDate.min); 188 | list.add(Text( 189 | '${min ?? widget.defaultMin}', 190 | style: _getTextStyle(widget.minTextStyle), 191 | )); 192 | list.add(Text( 193 | widget.minSymbol, 194 | style: _getTextStyle(widget.minSymbolTextStyle), 195 | )); 196 | } 197 | if (diffDate.sec != -1) { 198 | var sec = _getNumberAddZero(diffDate.sec); 199 | list.add(Text( 200 | '${sec ?? widget.defaultSec}', 201 | style: _getTextStyle(widget.secTextStyle), 202 | )); 203 | list.add(Text( 204 | widget.secSymbol, 205 | style: _getTextStyle(widget.secSymbolTextStyle), 206 | )); 207 | } 208 | return list; 209 | } 210 | 211 | String _getNumberAddZero(int number) { 212 | if (number == null) { 213 | return null; 214 | } 215 | if (number < 10) { 216 | return "0" + number.toString(); 217 | } 218 | return number.toString(); 219 | } 220 | 221 | void checkDateEnd(DiffDate data) { 222 | if(data.days == -1 && data.hours == 0 && data.min == 0 && data.sec == 0) { 223 | widget.onEnd(); 224 | disposeDiffTimer(); 225 | } 226 | } 227 | } 228 | 229 | class DiffDate { 230 | final int days; 231 | final int hours; 232 | final int min; 233 | final int sec; 234 | 235 | DiffDate({this.days, this.hours, this.min, this.sec}); 236 | } 237 | -------------------------------------------------------------------------------- /plugins/flutter_plugins/path_provider_fde/windows/path_provider_plugin.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | #include "include/path_provider_fde/path_provider_plugin.h" 15 | 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | namespace { 28 | 29 | using flutter::EncodableValue; 30 | 31 | // Converts an null-terminated array of wchar_t's to a std::string. 32 | std::string StdStringFromWideChars(wchar_t *wide_chars) { 33 | std::wstring_convert> wide_to_utf8; 34 | return wide_to_utf8.to_bytes(wide_chars); 35 | } 36 | 37 | // Gets the path to the given folder ID, without verifying that it exists, 38 | // or an empty string on failure. 39 | std::string GetFolderPath(REFKNOWNFOLDERID folder_id) { 40 | wchar_t *wide_path = nullptr; 41 | if (!SUCCEEDED(SHGetKnownFolderPath(folder_id, KF_FLAG_DONT_VERIFY, nullptr, 42 | &wide_path))) { 43 | return ""; 44 | } 45 | std::string path = StdStringFromWideChars(wide_path); 46 | CoTaskMemFree(wide_path); 47 | return path; 48 | } 49 | 50 | // Returns the name of the executable, without the .exe extension, or an empty 51 | // string on failure. 52 | std::string GetExecutableName() { 53 | wchar_t buffer[MAX_PATH]; 54 | if (GetModuleFileName(nullptr, buffer, MAX_PATH) == 0) { 55 | return ""; 56 | } 57 | std::string executable_path = StdStringFromWideChars(buffer); 58 | size_t last_separator_position = executable_path.find_last_of('\\'); 59 | std::string executable_name; 60 | if (last_separator_position == std::string::npos) { 61 | executable_name = executable_path; 62 | } else { 63 | executable_name = executable_path.substr(last_separator_position + 1); 64 | } 65 | // Strip the .exe extension, if present. 66 | std::string extension = ".exe"; 67 | if (executable_name.compare(executable_name.size() - extension.size(), 68 | extension.size(), extension) == 0) { 69 | executable_name = 70 | executable_name.substr(0, executable_name.size() - extension.size()); 71 | } 72 | return executable_name; 73 | } 74 | 75 | class PathProviderPlugin : public flutter::Plugin { 76 | public: 77 | static void RegisterWithRegistrar(flutter::PluginRegistrar *registrar); 78 | 79 | virtual ~PathProviderPlugin(); 80 | 81 | private: 82 | PathProviderPlugin(); 83 | 84 | // Called when a method is called on plugin channel; 85 | void HandleMethodCall( 86 | const flutter::MethodCall &method_call, 87 | std::unique_ptr> result); 88 | }; 89 | 90 | // static 91 | void PathProviderPlugin::RegisterWithRegistrar( 92 | flutter::PluginRegistrar *registrar) { 93 | auto channel = std::make_unique>( 94 | registrar->messenger(), "plugins.flutter.io/path_provider", 95 | &flutter::StandardMethodCodec::GetInstance()); 96 | 97 | // Uses new instead of make_unique due to private constructor. 98 | std::unique_ptr plugin(new PathProviderPlugin()); 99 | 100 | channel->SetMethodCallHandler( 101 | [plugin_pointer = plugin.get()](const auto &call, auto result) { 102 | plugin_pointer->HandleMethodCall(call, std::move(result)); 103 | }); 104 | 105 | registrar->AddPlugin(std::move(plugin)); 106 | } 107 | 108 | PathProviderPlugin::PathProviderPlugin() = default; 109 | 110 | PathProviderPlugin::~PathProviderPlugin() = default; 111 | 112 | void PathProviderPlugin::HandleMethodCall( 113 | const flutter::MethodCall &method_call, 114 | std::unique_ptr> result) { 115 | if (method_call.method_name().compare("getTemporaryDirectory") == 0) { 116 | wchar_t path_buffer[MAX_PATH]; 117 | DWORD length = GetTempPath(MAX_PATH, path_buffer); 118 | if (length == 0 || length > MAX_PATH) { 119 | result->Error("Unable to get temporary path"); 120 | return; 121 | } 122 | std::string result_path = StdStringFromWideChars(path_buffer); 123 | flutter::EncodableValue response(result_path); 124 | result->Success(&response); 125 | } else if (method_call.method_name().compare( 126 | "getApplicationSupportDirectory") == 0) { 127 | std::string path = GetFolderPath(FOLDERID_RoamingAppData); 128 | if (path.empty()) { 129 | result->Error("Unable to get application data path"); 130 | return; 131 | } 132 | // Use the executable name as the subdirectory for now. 133 | std::string exe_name = GetExecutableName(); 134 | if (exe_name.empty()) { 135 | result->Error("Unable to get exe name"); 136 | return; 137 | } 138 | std::ostringstream response_stream; 139 | response_stream << path << "\\" << exe_name; 140 | flutter::EncodableValue response(response_stream.str()); 141 | result->Success(&response); 142 | } else if (method_call.method_name().compare( 143 | "getApplicationDocumentsDirectory") == 0) { 144 | std::string path = GetFolderPath(FOLDERID_Documents); 145 | if (path.empty()) { 146 | result->Error("Unable to get documents path"); 147 | return; 148 | } 149 | flutter::EncodableValue response(path); 150 | result->Success(&response); 151 | } else if (method_call.method_name().compare( 152 | "getDownloadsDirectory") == 0) { 153 | std::string path = GetFolderPath(FOLDERID_Downloads); 154 | if (path.empty()) { 155 | result->Error("Unable to get downloads path"); 156 | return; 157 | } 158 | flutter::EncodableValue response(path); 159 | result->Success(&response); 160 | } else { 161 | result->NotImplemented(); 162 | } 163 | } 164 | 165 | } // namespace 166 | 167 | void PathProviderPluginRegisterWithRegistrar( 168 | FlutterDesktopPluginRegistrarRef registrar) { 169 | PathProviderPlugin::RegisterWithRegistrar( 170 | flutter::PluginRegistrarManager::GetInstance() 171 | ->GetRegistrar(registrar)); 172 | } 173 | -------------------------------------------------------------------------------- /plugins/color_panel/linux/color_panel_plugin.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | #include "include/color_panel/color_panel_plugin.h" 15 | 16 | #include 17 | #include 18 | 19 | // See color_panel.dart for documentation. 20 | const char kChannelName[] = "flutter/colorpanel"; 21 | const char kNoScreenError[] = "No Screen"; 22 | const char kShowColorPanelMethod[] = "ColorPanel.Show"; 23 | const char kColorPanelShowAlpha[] = "ColorPanel.ShowAlpha"; 24 | const char kHideColorPanelMethod[] = "ColorPanel.Hide"; 25 | const char kColorSelectedCallbackMethod[] = "ColorPanel.ColorSelectedCallback"; 26 | const char kClosedCallbackMethod[] = "ColorPanel.ClosedCallback"; 27 | const char kColorComponentAlphaKey[] = "alpha"; 28 | const char kColorComponentRedKey[] = "red"; 29 | const char kColorComponentGreenKey[] = "green"; 30 | const char kColorComponentBlueKey[] = "blue"; 31 | 32 | static constexpr char kWindowTitle[] = "Flutter Color Picker"; 33 | 34 | struct _FlColorPanelPlugin { 35 | GObject parent_instance; 36 | 37 | FlPluginRegistrar* registrar; 38 | 39 | // Connection to Flutter engine. 40 | FlMethodChannel* channel; 41 | 42 | // Dialog currently being shown. 43 | GtkColorChooserDialog* color_chooser_dialog; 44 | }; 45 | 46 | G_DEFINE_TYPE(FlColorPanelPlugin, fl_color_panel_plugin, g_object_get_type()) 47 | 48 | // Destroys any open color chooser dialog. 49 | static void destroy_color_chooser_dialog(FlColorPanelPlugin* self) { 50 | if (self->color_chooser_dialog == nullptr) return; 51 | 52 | gtk_widget_destroy(GTK_WIDGET(self->color_chooser_dialog)); 53 | self->color_chooser_dialog = nullptr; 54 | } 55 | 56 | // Called when a color chooser dialog responds. 57 | static void color_chooser_response_cb(FlColorPanelPlugin* self, 58 | gint response_id) { 59 | if (response_id == GTK_RESPONSE_OK) { 60 | GdkRGBA color; 61 | gtk_color_chooser_get_rgba(GTK_COLOR_CHOOSER(self->color_chooser_dialog), 62 | &color); 63 | g_autoptr(FlValue) result = fl_value_new_map(); 64 | fl_value_set_string_take(result, kColorComponentAlphaKey, 65 | fl_value_new_float(color.alpha)); 66 | fl_value_set_string_take(result, kColorComponentRedKey, 67 | fl_value_new_float(color.red)); 68 | fl_value_set_string_take(result, kColorComponentGreenKey, 69 | fl_value_new_float(color.green)); 70 | fl_value_set_string_take(result, kColorComponentBlueKey, 71 | fl_value_new_float(color.blue)); 72 | fl_method_channel_invoke_method(self->channel, kColorSelectedCallbackMethod, 73 | result, nullptr, nullptr, nullptr); 74 | } 75 | 76 | fl_method_channel_invoke_method(self->channel, kClosedCallbackMethod, nullptr, 77 | nullptr, nullptr, nullptr); 78 | 79 | destroy_color_chooser_dialog(self); 80 | } 81 | 82 | // Shows a color panel. 83 | static FlMethodResponse* show_color_panel(FlColorPanelPlugin* self, 84 | FlValue* args) { 85 | // There is only one color panel that can be displayed at once. 86 | // There are no channels to use the color panel, so just return. 87 | if (self->color_chooser_dialog != nullptr) 88 | return FL_METHOD_RESPONSE(fl_method_success_response_new(nullptr)); 89 | 90 | FlValue* use_alpha_value = nullptr; 91 | if (fl_value_get_type(args) == FL_VALUE_TYPE_MAP) 92 | use_alpha_value = fl_value_lookup_string(args, kColorPanelShowAlpha); 93 | gboolean use_alpha = 94 | use_alpha_value != nullptr ? fl_value_get_bool(use_alpha_value) : FALSE; 95 | 96 | FlView* view = fl_plugin_registrar_get_view(self->registrar); 97 | if (view == nullptr) { 98 | return FL_METHOD_RESPONSE( 99 | fl_method_error_response_new(kNoScreenError, nullptr, nullptr)); 100 | } 101 | 102 | self->color_chooser_dialog = GTK_COLOR_CHOOSER_DIALOG( 103 | gtk_color_chooser_dialog_new(kWindowTitle, nullptr)); 104 | GtkWindow* window = GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(view))); 105 | gtk_window_set_transient_for(GTK_WINDOW(self->color_chooser_dialog), window); 106 | gtk_color_chooser_set_use_alpha(GTK_COLOR_CHOOSER(self->color_chooser_dialog), 107 | use_alpha); 108 | g_signal_connect_object(self->color_chooser_dialog, "response", 109 | G_CALLBACK(color_chooser_response_cb), self, 110 | G_CONNECT_SWAPPED); 111 | gtk_widget_show(GTK_WIDGET(self->color_chooser_dialog)); 112 | 113 | return FL_METHOD_RESPONSE(fl_method_success_response_new(nullptr)); 114 | } 115 | 116 | // Hides the color panel. 117 | static FlMethodResponse* hide_color_panel(FlColorPanelPlugin* self) { 118 | destroy_color_chooser_dialog(self); 119 | return FL_METHOD_RESPONSE(fl_method_success_response_new(nullptr)); 120 | } 121 | 122 | // Called when a method call is received from Flutter. 123 | static void method_call_cb(FlMethodChannel* channel, FlMethodCall* method_call, 124 | gpointer user_data) { 125 | FlColorPanelPlugin* self = FL_COLOR_PANEL_PLUGIN(user_data); 126 | 127 | const gchar* method = fl_method_call_get_name(method_call); 128 | FlValue* args = fl_method_call_get_args(method_call); 129 | 130 | g_autoptr(FlMethodResponse) response = nullptr; 131 | if (strcmp(method, kShowColorPanelMethod) == 0) { 132 | response = show_color_panel(self, args); 133 | } else if (strcmp(method, kHideColorPanelMethod) == 0) { 134 | response = hide_color_panel(self); 135 | } else { 136 | response = FL_METHOD_RESPONSE(fl_method_not_implemented_response_new()); 137 | } 138 | 139 | g_autoptr(GError) error = nullptr; 140 | if (!fl_method_call_respond(method_call, response, &error)) 141 | g_warning("Failed to send method call response: %s", error->message); 142 | } 143 | 144 | static void fl_color_panel_plugin_dispose(GObject* object) { 145 | FlColorPanelPlugin* self = FL_COLOR_PANEL_PLUGIN(object); 146 | 147 | g_clear_object(&self->registrar); 148 | g_clear_object(&self->channel); 149 | destroy_color_chooser_dialog(self); 150 | 151 | G_OBJECT_CLASS(fl_color_panel_plugin_parent_class)->dispose(object); 152 | } 153 | 154 | static void fl_color_panel_plugin_class_init(FlColorPanelPluginClass* klass) { 155 | G_OBJECT_CLASS(klass)->dispose = fl_color_panel_plugin_dispose; 156 | } 157 | 158 | static void fl_color_panel_plugin_init(FlColorPanelPlugin* self) {} 159 | 160 | FlColorPanelPlugin* fl_color_panel_plugin_new(FlPluginRegistrar* registrar) { 161 | FlColorPanelPlugin* self = FL_COLOR_PANEL_PLUGIN( 162 | g_object_new(fl_color_panel_plugin_get_type(), nullptr)); 163 | 164 | self->registrar = FL_PLUGIN_REGISTRAR(g_object_ref(registrar)); 165 | 166 | g_autoptr(FlStandardMethodCodec) codec = fl_standard_method_codec_new(); 167 | self->channel = 168 | fl_method_channel_new(fl_plugin_registrar_get_messenger(registrar), 169 | kChannelName, FL_METHOD_CODEC(codec)); 170 | fl_method_channel_set_method_call_handler(self->channel, method_call_cb, 171 | g_object_ref(self), g_object_unref); 172 | 173 | return self; 174 | } 175 | 176 | void color_panel_plugin_register_with_registrar(FlPluginRegistrar* registrar) { 177 | FlColorPanelPlugin* plugin = fl_color_panel_plugin_new(registrar); 178 | g_object_unref(plugin); 179 | } 180 | -------------------------------------------------------------------------------- /plugins/window_size/windows/window_size_plugin.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | #include "include/window_size/window_size_plugin.h" 15 | 16 | // windows.h must be imported before VersionHelpers.h or it will break 17 | // compilation. 18 | #include 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | #include 28 | #include 29 | #include 30 | 31 | namespace { 32 | 33 | using flutter::EncodableList; 34 | using flutter::EncodableMap; 35 | using flutter::EncodableValue; 36 | 37 | // See window_size_channel.dart for documentation. 38 | const char kChannelName[] = "flutter/windowsize"; 39 | const char kGetScreenListMethod[] = "getScreenList"; 40 | const char kGetWindowInfoMethod[] = "getWindowInfo"; 41 | const char kSetWindowFrameMethod[] = "setWindowFrame"; 42 | const char kSetWindowTitleMethod[] = "setWindowTitle"; 43 | const char kFrameKey[] = "frame"; 44 | const char kVisibleFrameKey[] = "visibleFrame"; 45 | const char kScaleFactorKey[] = "scaleFactor"; 46 | const char kScreenKey[] = "screen"; 47 | 48 | const double kBaseDpi = 96.0; 49 | 50 | // Returns the serializable form of |frame| expected by the platform channel. 51 | EncodableValue GetPlatformChannelRepresentationForRect(const RECT &rect) { 52 | return EncodableValue(EncodableList{ 53 | EncodableValue(static_cast(rect.left)), 54 | EncodableValue(static_cast(rect.top)), 55 | EncodableValue(static_cast(rect.right) - 56 | static_cast(rect.left)), 57 | EncodableValue(static_cast(rect.bottom) - 58 | static_cast(rect.top)), 59 | }); 60 | } 61 | 62 | // Extracts information from monitor |monitor| and returns the 63 | // serializable form expected by the platform channel. 64 | EncodableValue GetPlatformChannelRepresentationForMonitor(HMONITOR monitor) { 65 | if (!monitor) { 66 | return EncodableValue(); 67 | } 68 | 69 | MONITORINFO info; 70 | info.cbSize = sizeof(MONITORINFO); 71 | GetMonitorInfo(monitor, &info); 72 | UINT dpi = FlutterDesktopGetDpiForMonitor(monitor); 73 | double scale_factor = dpi / kBaseDpi; 74 | return EncodableValue(EncodableMap{ 75 | {EncodableValue(kFrameKey), 76 | GetPlatformChannelRepresentationForRect(info.rcMonitor)}, 77 | {EncodableValue(kVisibleFrameKey), 78 | GetPlatformChannelRepresentationForRect(info.rcWork)}, 79 | {EncodableValue(kScaleFactorKey), EncodableValue(scale_factor)}, 80 | }); 81 | } 82 | 83 | BOOL CALLBACK MonitorRepresentationEnumProc(HMONITOR monitor, HDC hdc, 84 | LPRECT clip, LPARAM list_ref) { 85 | EncodableValue *monitors = reinterpret_cast(list_ref); 86 | monitors->ListValue().push_back( 87 | GetPlatformChannelRepresentationForMonitor(monitor)); 88 | return TRUE; 89 | } 90 | 91 | // Extracts information from |window| and returns the serializable form expected 92 | // by the platform channel. 93 | EncodableValue GetPlatformChannelRepresentationForWindow(HWND window) { 94 | if (!window) { 95 | return EncodableValue(); 96 | } 97 | RECT frame; 98 | GetWindowRect(window, &frame); 99 | HMONITOR window_monitor = MonitorFromWindow(window, MONITOR_DEFAULTTOPRIMARY); 100 | double scale_factor = FlutterDesktopGetDpiForHWND(window) / kBaseDpi; 101 | 102 | return EncodableValue(EncodableMap{ 103 | {EncodableValue(kFrameKey), 104 | GetPlatformChannelRepresentationForRect(frame)}, 105 | {EncodableValue(kScreenKey), 106 | GetPlatformChannelRepresentationForMonitor(window_monitor)}, 107 | {EncodableValue(kScaleFactorKey), EncodableValue(scale_factor)}, 108 | }); 109 | } 110 | 111 | HWND GetRootWindow(flutter::FlutterView *view) { 112 | return GetAncestor(view->GetNativeWindow(), GA_ROOT); 113 | } 114 | 115 | class WindowSizePlugin : public flutter::Plugin { 116 | public: 117 | static void RegisterWithRegistrar(flutter::PluginRegistrarWindows *registrar); 118 | 119 | // Creates a plugin that communicates on the given channel. 120 | WindowSizePlugin(flutter::PluginRegistrarWindows *registrar); 121 | 122 | virtual ~WindowSizePlugin(); 123 | 124 | private: 125 | // Called when a method is called on the plugin channel; 126 | void HandleMethodCall( 127 | const flutter::MethodCall &method_call, 128 | std::unique_ptr> result); 129 | 130 | // The registrar for this plugin, for accessing the window. 131 | flutter::PluginRegistrarWindows *registrar_; 132 | }; 133 | 134 | // static 135 | void WindowSizePlugin::RegisterWithRegistrar( 136 | flutter::PluginRegistrarWindows *registrar) { 137 | auto channel = 138 | std::make_unique>( 139 | registrar->messenger(), kChannelName, 140 | &flutter::StandardMethodCodec::GetInstance()); 141 | 142 | auto plugin = std::make_unique(registrar); 143 | 144 | channel->SetMethodCallHandler( 145 | [plugin_pointer = plugin.get()](const auto &call, auto result) { 146 | plugin_pointer->HandleMethodCall(call, std::move(result)); 147 | }); 148 | 149 | registrar->AddPlugin(std::move(plugin)); 150 | } 151 | 152 | WindowSizePlugin::WindowSizePlugin(flutter::PluginRegistrarWindows *registrar) 153 | : registrar_(registrar) {} 154 | 155 | WindowSizePlugin::~WindowSizePlugin(){}; 156 | 157 | void WindowSizePlugin::HandleMethodCall( 158 | const flutter::MethodCall &method_call, 159 | std::unique_ptr> result) { 160 | if (method_call.method_name().compare(kGetScreenListMethod) == 0) { 161 | EncodableValue screens(EncodableValue::Type::kList); 162 | EnumDisplayMonitors(nullptr, nullptr, MonitorRepresentationEnumProc, 163 | reinterpret_cast(&screens)); 164 | result->Success(&screens); 165 | } else if (method_call.method_name().compare(kGetWindowInfoMethod) == 0) { 166 | EncodableValue window_info = GetPlatformChannelRepresentationForWindow( 167 | GetRootWindow(registrar_->GetView())); 168 | result->Success(&window_info); 169 | } else if (method_call.method_name().compare(kSetWindowFrameMethod) == 0) { 170 | if (!method_call.arguments() || !method_call.arguments()->IsList() || 171 | method_call.arguments()->ListValue().size() != 4) { 172 | result->Error("Bad arguments", "Expected 4-element list"); 173 | return; 174 | } 175 | // Frame validity (e.g., non-zero size) is assumed to be checked on the Dart 176 | // side of the call. 177 | const auto &frame_list = method_call.arguments()->ListValue(); 178 | int x = static_cast(frame_list[0].DoubleValue()); 179 | int y = static_cast(frame_list[1].DoubleValue()); 180 | int width = static_cast(frame_list[2].DoubleValue()); 181 | int height = static_cast(frame_list[3].DoubleValue()); 182 | SetWindowPos(GetRootWindow(registrar_->GetView()), nullptr, x, y, width, 183 | height, SWP_NOACTIVATE | SWP_NOOWNERZORDER); 184 | result->Success(); 185 | } else if (method_call.method_name().compare(kSetWindowTitleMethod) == 0) { 186 | if (!method_call.arguments() || !method_call.arguments()->IsString()) { 187 | result->Error("Bad arguments", "Expected string"); 188 | return; 189 | } 190 | const auto &title = method_call.arguments()->StringValue(); 191 | std::wstring wstr = 192 | std::wstring_convert, wchar_t>{} 193 | .from_bytes(title); 194 | SetWindowText(GetRootWindow(registrar_->GetView()), wstr.c_str()); 195 | result->Success(); 196 | } else { 197 | result->NotImplemented(); 198 | } 199 | } 200 | 201 | } // namespace 202 | 203 | void WindowSizePluginRegisterWithRegistrar( 204 | FlutterDesktopPluginRegistrarRef registrar) { 205 | WindowSizePlugin::RegisterWithRegistrar( 206 | flutter::PluginRegistrarManager::GetInstance() 207 | ->GetRegistrar(registrar)); 208 | } 209 | -------------------------------------------------------------------------------- /plugins/window_size/macos/Classes/FLEWindowSizePlugin.m: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #import "FLEWindowSizePlugin.h" 16 | 17 | #import 18 | 19 | // See window_size_channel.dart for documentation. 20 | static NSString *const kChannelName = @"flutter/windowsize"; 21 | static NSString *const kGetScreenListMethod = @"getScreenList"; 22 | static NSString *const kGetWindowInfoMethod = @"getWindowInfo"; 23 | static NSString *const kSetWindowFrameMethod = @"setWindowFrame"; 24 | static NSString *const kSetWindowMinimumSizeMethod = @"setWindowMinimumSize"; 25 | static NSString *const kSetWindowMaximumSizeMethod = @"setWindowMaximumSize"; 26 | static NSString *const kSetWindowTitleMethod = @"setWindowTitle"; 27 | static NSString *const kSetWindowTitleRepresentedUrlMethod = @"setWindowTitleRepresentedUrl"; 28 | static NSString *const kGetWindowMinimumSizeMethod = @"getWindowMinimumSize"; 29 | static NSString *const kGetWindowMaximumSizeMethod = @"getWindowMaximumSize"; 30 | static NSString *const kFrameKey = @"frame"; 31 | static NSString *const kVisibleFrameKey = @"visibleFrame"; 32 | static NSString *const kScaleFactorKey = @"scaleFactor"; 33 | static NSString *const kScreenKey = @"screen"; 34 | 35 | /** 36 | * Returns the max Y coordinate across all screens. 37 | */ 38 | CGFloat GetMaxScreenY() { 39 | CGFloat maxY = 0; 40 | for (NSScreen *screen in [NSScreen screens]) { 41 | maxY = MAX(maxY, CGRectGetMaxY(screen.frame)); 42 | } 43 | return maxY; 44 | } 45 | 46 | /** 47 | * Given |frame| in screen coordinates, returns a frame flipped relative to 48 | * GetMaxScreenY(). 49 | */ 50 | NSRect GetFlippedRect(NSRect frame) { 51 | CGFloat maxY = GetMaxScreenY(); 52 | return NSMakeRect(frame.origin.x, maxY - frame.origin.y - frame.size.height, frame.size.width, 53 | frame.size.height); 54 | } 55 | 56 | @interface FLEWindowSizePlugin () 57 | 58 | /// The view displaying Flutter content. 59 | @property(nonatomic, readonly) NSView *flutterView; 60 | 61 | /** 62 | * Extracts information from |screen| and returns the serializable form expected 63 | * by the platform channel. 64 | */ 65 | - (NSDictionary *)platformChannelRepresentationForScreen:(NSScreen *)screen; 66 | 67 | /** 68 | * Extracts information from |window| and returns the serializable form expected 69 | * by the platform channel. 70 | */ 71 | - (NSDictionary *)platformChannelRepresentationForWindow:(NSWindow *)window; 72 | 73 | /** 74 | * Returns the serializable form of |frame| expected by the platform channel. 75 | */ 76 | - (NSArray *)platformChannelRepresentationForFrame:(NSRect)frame; 77 | 78 | @end 79 | 80 | /** 81 | * Converts the channel representation for unconstrained maximum size `-1` to Cocoa's specific maximum size of `FLT_MAX`. 82 | */ 83 | static double MaxDimensionFromChannelRepresentation(double size) { 84 | return size == -1.0 ? FLT_MAX : size; 85 | } 86 | 87 | /** 88 | * Converts Cocoa's specific maximum size of `FLT_MAX` to channel representation for unconstrained maximum size `-1`. 89 | */ 90 | static double ChannelRepresentationForMaxDimension(double size) { 91 | return size == FLT_MAX ? -1 : size; 92 | } 93 | 94 | @implementation FLEWindowSizePlugin { 95 | // The channel used to communicate with Flutter. 96 | FlutterMethodChannel *_channel; 97 | 98 | // A reference to the registrar holding the NSView used by the plugin. Holding a reference 99 | // since the view might be nil at the time the plugin is created. 100 | id _registrar; 101 | } 102 | 103 | - (NSView *)flutterView { 104 | return _registrar.view; 105 | } 106 | 107 | + (void)registerWithRegistrar:(id)registrar { 108 | FlutterMethodChannel *channel = [FlutterMethodChannel methodChannelWithName:kChannelName 109 | binaryMessenger:registrar.messenger]; 110 | FLEWindowSizePlugin *instance = [[FLEWindowSizePlugin alloc] initWithChannel:channel 111 | registrar:registrar]; 112 | [registrar addMethodCallDelegate:instance channel:channel]; 113 | } 114 | 115 | - (instancetype)initWithChannel:(FlutterMethodChannel *)channel 116 | registrar:(id)registrar { 117 | self = [super init]; 118 | if (self) { 119 | _channel = channel; 120 | _registrar = registrar; 121 | } 122 | return self; 123 | } 124 | 125 | /** 126 | * Handles platform messages generated by the Flutter framework on the platform channel. 127 | */ 128 | - (void)handleMethodCall:(FlutterMethodCall *)call result:(FlutterResult)result { 129 | id methodResult = nil; 130 | if ([call.method isEqualToString:kGetScreenListMethod]) { 131 | NSMutableArray *screenList = 132 | [NSMutableArray arrayWithCapacity:[NSScreen screens].count]; 133 | for (NSScreen *screen in [NSScreen screens]) { 134 | [screenList addObject:[self platformChannelRepresentationForScreen:screen]]; 135 | } 136 | methodResult = screenList; 137 | } else if ([call.method isEqualToString:kGetWindowInfoMethod]) { 138 | methodResult = [self platformChannelRepresentationForWindow:self.flutterView.window]; 139 | } else if ([call.method isEqualToString:kSetWindowFrameMethod]) { 140 | NSArray *arguments = call.arguments; 141 | [self.flutterView.window 142 | setFrame:GetFlippedRect(NSMakeRect(arguments[0].doubleValue, arguments[1].doubleValue, 143 | arguments[2].doubleValue, arguments[3].doubleValue)) 144 | display:YES]; 145 | methodResult = nil; 146 | } else if ([call.method isEqualToString:kSetWindowMinimumSizeMethod]) { 147 | NSArray *arguments = call.arguments; 148 | self.flutterView.window.minSize = 149 | NSMakeSize(arguments[0].doubleValue, arguments[1].doubleValue); 150 | methodResult = nil; 151 | } else if ([call.method isEqualToString:kSetWindowMaximumSizeMethod]) { 152 | NSArray *arguments = call.arguments; 153 | self.flutterView.window.maxSize = 154 | NSMakeSize(MaxDimensionFromChannelRepresentation(arguments[0].doubleValue), 155 | MaxDimensionFromChannelRepresentation(arguments[1].doubleValue)); 156 | methodResult = nil; 157 | } else if ([call.method isEqualToString:kGetWindowMinimumSizeMethod]) { 158 | NSSize size = self.flutterView.window.minSize; 159 | methodResult = @[ @(size.width), @(size.height) ]; 160 | } else if ([call.method isEqualToString:kGetWindowMaximumSizeMethod]) { 161 | NSSize size = self.flutterView.window.maxSize; 162 | methodResult = @[ 163 | @(ChannelRepresentationForMaxDimension(size.width)), 164 | @(ChannelRepresentationForMaxDimension(size.height)) ]; 165 | } else if ([call.method isEqualToString:kSetWindowTitleMethod]) { 166 | NSString *title = call.arguments; 167 | self.flutterView.window.title = title; 168 | methodResult = nil; 169 | } else if ([call.method isEqualToString:kSetWindowTitleRepresentedUrlMethod]) { 170 | NSURL *representedURL = [NSURL URLWithString:call.arguments]; 171 | self.flutterView.window.representedURL = representedURL; 172 | methodResult = nil; 173 | } else { 174 | methodResult = FlutterMethodNotImplemented; 175 | } 176 | result(methodResult); 177 | } 178 | 179 | #pragma mark - Private methods 180 | 181 | - (NSDictionary *)platformChannelRepresentationForScreen:(NSScreen *)screen { 182 | return @{ 183 | kFrameKey : [self platformChannelRepresentationForFrame:GetFlippedRect(screen.frame)], 184 | kVisibleFrameKey : 185 | [self platformChannelRepresentationForFrame:GetFlippedRect(screen.visibleFrame)], 186 | kScaleFactorKey : @(screen.backingScaleFactor), 187 | }; 188 | } 189 | 190 | - (NSDictionary *)platformChannelRepresentationForWindow:(NSWindow *)window { 191 | return @{ 192 | kFrameKey : [self platformChannelRepresentationForFrame:GetFlippedRect(window.frame)], 193 | kScreenKey : [self platformChannelRepresentationForScreen:window.screen], 194 | kScaleFactorKey : @(window.backingScaleFactor), 195 | }; 196 | } 197 | 198 | - (NSArray *)platformChannelRepresentationForFrame:(NSRect)frame { 199 | return @[ @(frame.origin.x), @(frame.origin.y), @(frame.size.width), @(frame.size.height) ]; 200 | } 201 | 202 | @end 203 | -------------------------------------------------------------------------------- /plugins/menubar/macos/Classes/FLEMenubarPlugin.m: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #import "FLEMenubarPlugin.h" 16 | 17 | // See menu_channel.dart for documentation. 18 | static NSString *const kChannelName = @"flutter/menubar"; 19 | static NSString *const kMenuSetMethod = @"Menubar.SetMenu"; 20 | static NSString *const kMenuItemSelectedCallbackMethod = @"Menubar.SelectedCallback"; 21 | static NSString *const kIdKey = @"id"; 22 | static NSString *const kLabelKey = @"label"; 23 | static NSString *const kShortcutKeyEquivalent = @"keyEquivalent"; 24 | static NSString *const kShortcutSpecialKey = @"specialKey"; 25 | static NSString *const kShortcutKeyModifiers = @"keyModifiers"; 26 | static NSString *const kEnabledKey = @"enabled"; 27 | static NSString *const kChildrenKey = @"children"; 28 | static NSString *const kDividerKey = @"isDivider"; 29 | 30 | static const int kFlutterShortcutModifierMeta = 1 << 0; 31 | static const int kFlutterShortcutModifierShift = 1 << 1; 32 | static const int kFlutterShortcutModifierAlt = 1 << 2; 33 | static const int kFlutterShortcutModifierControl = 1 << 3; 34 | 35 | // Returns the string used by NSMenuItem for the given special key. 36 | // See _shortcutSpecialKeyValues in menu_channel.dart for values. 37 | static NSString *KeyEquivalentCharacterForSpecialKey(int specialKey) { 38 | unichar character; 39 | switch (specialKey) { 40 | case 1: 41 | character = NSF1FunctionKey; 42 | break; 43 | case 2: 44 | character = NSF2FunctionKey; 45 | break; 46 | case 3: 47 | character = NSF3FunctionKey; 48 | break; 49 | case 4: 50 | character = NSF4FunctionKey; 51 | break; 52 | case 5: 53 | character = NSF5FunctionKey; 54 | break; 55 | case 6: 56 | character = NSF6FunctionKey; 57 | break; 58 | case 7: 59 | character = NSF7FunctionKey; 60 | break; 61 | case 8: 62 | character = NSF8FunctionKey; 63 | break; 64 | case 9: 65 | character = NSF9FunctionKey; 66 | break; 67 | case 10: 68 | character = NSF10FunctionKey; 69 | break; 70 | case 11: 71 | character = NSF11FunctionKey; 72 | break; 73 | case 12: 74 | character = NSF12FunctionKey; 75 | break; 76 | case 13: 77 | character = NSBackspaceCharacter; 78 | break; 79 | case 14: 80 | character = NSDeleteCharacter; 81 | break; 82 | default: 83 | return nil; 84 | } 85 | return [NSString stringWithCharacters:&character length:1]; 86 | } 87 | 88 | // Returns the NSEventModifierFlags of |modifiers|, a value from kShortcutKeyModifiers. 89 | static NSEventModifierFlags KeyEquivalentModifierMaskForModifiers(NSNumber *modifiers) { 90 | int flutterModifierFlags = modifiers.intValue; 91 | NSEventModifierFlags flags = 0; 92 | if (flutterModifierFlags & kFlutterShortcutModifierMeta) flags |= NSEventModifierFlagCommand; 93 | if (flutterModifierFlags & kFlutterShortcutModifierShift) flags |= NSEventModifierFlagShift; 94 | if (flutterModifierFlags & kFlutterShortcutModifierAlt) flags |= NSEventModifierFlagOption; 95 | if (flutterModifierFlags & kFlutterShortcutModifierControl) flags |= NSEventModifierFlagControl; 96 | return flags; 97 | } 98 | 99 | @implementation FLEMenubarPlugin { 100 | // The channel used to communicate with Flutter. 101 | FlutterMethodChannel *_channel; 102 | } 103 | 104 | - (instancetype)initWithChannel:(FlutterMethodChannel *)channel { 105 | self = [super init]; 106 | if (self) { 107 | _channel = channel; 108 | } 109 | return self; 110 | } 111 | 112 | /** 113 | * Removes any top-level menus added by this plugin. 114 | */ 115 | - (void)removeFlutterMenus { 116 | NSMenu *mainMenu = NSApp.mainMenu; 117 | // Remove in reverse order to simplify iteration while removing. 118 | for (NSInteger i = mainMenu.numberOfItems - 1; i >= 0; --i) { 119 | if ([mainMenu itemAtIndex:i].representedObject == self) { 120 | [mainMenu removeItemAtIndex:i]; 121 | } 122 | } 123 | } 124 | 125 | /** 126 | * Returns the index in the application's mainMenu where Flutter menu items should be inserted. 127 | */ 128 | - (NSInteger)menuInsertionIndex { 129 | NSMenu *mainMenu = NSApp.mainMenu; 130 | NSInteger index = self.insertAfterMenuItem ? [mainMenu indexOfItem:self.insertAfterMenuItem] : -1; 131 | // If there's no (valid) insert-after, insert after the application menu at index zero. 132 | if (index == -1) { 133 | index = 0; 134 | } 135 | return index + 1; 136 | } 137 | 138 | /** 139 | * Removes an Flutter menu items that were previously added, then builds and adds new top-level menu 140 | * items constructed from |representation|. 141 | */ 142 | - (void)rebuildFlutterMenusFromRepresentation:(NSArray *)representation { 143 | [self removeFlutterMenus]; 144 | NSMenu *mainMenu = NSApp.mainMenu; 145 | NSInteger insertionIndex = [self menuInsertionIndex]; 146 | for (NSDictionary *item in representation.reverseObjectEnumerator) { 147 | NSMenuItem *menuItem = [self menuItemFromFlutterRepresentation:item]; 148 | menuItem.representedObject = self; 149 | [mainMenu insertItem:menuItem atIndex:insertionIndex]; 150 | } 151 | } 152 | 153 | /** 154 | * Constructs and returns an NSMenuItem corresponding to the item in |representation|, including 155 | * recursively creating children if it has a submenu. 156 | */ 157 | - (NSMenuItem *)menuItemFromFlutterRepresentation:(NSDictionary *)representation { 158 | if (representation[kDividerKey]) { 159 | return [NSMenuItem separatorItem]; 160 | } else { 161 | NSString *title = representation[kLabelKey]; 162 | NSNumber *boxedID = representation[kIdKey]; 163 | 164 | NSString *keyEquivalent = nil; 165 | if (representation[kShortcutKeyEquivalent]) { 166 | keyEquivalent = representation[kShortcutKeyEquivalent]; 167 | } else if (representation[kShortcutSpecialKey]) { 168 | int specialKey = ((NSNumber *)representation[kShortcutSpecialKey]).intValue; 169 | keyEquivalent = KeyEquivalentCharacterForSpecialKey(specialKey); 170 | } 171 | 172 | SEL action = (boxedID ? @selector(flutterMenuItemSelected:) : NULL); 173 | NSMenuItem *item = [[NSMenuItem alloc] initWithTitle:title 174 | action:action 175 | keyEquivalent:(keyEquivalent ?: @"")]; 176 | if (keyEquivalent) { 177 | item.keyEquivalentModifierMask = 178 | KeyEquivalentModifierMaskForModifiers(representation[kShortcutKeyModifiers]); 179 | } 180 | if (boxedID) { 181 | item.tag = boxedID.intValue; 182 | item.target = self; 183 | } 184 | NSNumber *enabled = representation[kEnabledKey]; 185 | if (enabled) { 186 | item.enabled = enabled.boolValue; 187 | } 188 | 189 | NSArray *children = representation[kChildrenKey]; 190 | if (children) { 191 | NSMenu *submenu = [[NSMenu alloc] initWithTitle:title]; 192 | submenu.autoenablesItems = NO; 193 | for (NSDictionary *child in children) { 194 | [submenu addItem:[self menuItemFromFlutterRepresentation:child]]; 195 | } 196 | item.submenu = submenu; 197 | } 198 | return item; 199 | } 200 | } 201 | 202 | /** 203 | * Invokes kMenuItemSelectedCallbackMethod with the senders ID. 204 | * 205 | * Used as the callback for all Flutter-created menu items that have IDs. 206 | */ 207 | - (void)flutterMenuItemSelected:(id)sender { 208 | NSMenuItem *item = sender; 209 | [_channel invokeMethod:kMenuItemSelectedCallbackMethod arguments:@(item.tag)]; 210 | } 211 | 212 | #pragma FlutterPlugin implementation 213 | 214 | + (void)registerWithRegistrar:(id)registrar { 215 | FlutterMethodChannel *channel = [FlutterMethodChannel methodChannelWithName:kChannelName 216 | binaryMessenger:registrar.messenger]; 217 | FLEMenubarPlugin *instance = [[FLEMenubarPlugin alloc] initWithChannel:channel]; 218 | [registrar addMethodCallDelegate:instance channel:channel]; 219 | } 220 | 221 | - (void)handleMethodCall:(FlutterMethodCall *)call result:(FlutterResult)result { 222 | if ([call.method isEqualToString:kMenuSetMethod]) { 223 | NSArray *menus = call.arguments; 224 | [self rebuildFlutterMenusFromRepresentation:menus]; 225 | result(nil); 226 | } else { 227 | result(FlutterMethodNotImplemented); 228 | } 229 | } 230 | 231 | @end 232 | -------------------------------------------------------------------------------- /plugins/file_chooser/linux/file_chooser_plugin.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | #include "include/file_chooser/file_chooser_plugin.h" 15 | 16 | #include 17 | #include 18 | 19 | // See channel_controller.dart for documentation. 20 | const char kChannelName[] = "flutter/filechooser"; 21 | const char kBadArgumentsError[] = "Bad Arguments"; 22 | const char kNoScreenError[] = "No Screen"; 23 | const char kShowOpenPanelMethod[] = "FileChooser.Show.Open"; 24 | const char kShowSavePanelMethod[] = "FileChooser.Show.Save"; 25 | const char kInitialDirectoryKey[] = "initialDirectory"; 26 | const char kInitialFileNameKey[] = "initialFileName"; 27 | const char kAllowedFileTypesKey[] = "allowedFileTypes"; 28 | const char kConfirmButtonTextKey[] = "confirmButtonText"; 29 | const char kAllowsMultipleSelectionKey[] = "allowsMultipleSelection"; 30 | const char kCanChooseDirectoriesKey[] = "canChooseDirectories"; 31 | 32 | struct _FlFileChooserPlugin { 33 | GObject parent_instance; 34 | 35 | FlPluginRegistrar* registrar; 36 | 37 | // Connection to Flutter engine. 38 | FlMethodChannel* channel; 39 | }; 40 | 41 | G_DEFINE_TYPE(FlFileChooserPlugin, fl_file_chooser_plugin, G_TYPE_OBJECT) 42 | 43 | // Converts a file type received from Flutter into a GTK file filter. 44 | static GtkFileFilter* file_type_to_filter(FlValue* value) { 45 | if (fl_value_get_type(value) != FL_VALUE_TYPE_LIST || 46 | fl_value_get_length(value) != 2 || 47 | fl_value_get_type(fl_value_get_list_value(value, 0)) != 48 | FL_VALUE_TYPE_STRING || 49 | fl_value_get_type(fl_value_get_list_value(value, 1)) != 50 | FL_VALUE_TYPE_LIST) 51 | return nullptr; 52 | 53 | const gchar* name = fl_value_get_string(fl_value_get_list_value(value, 0)); 54 | 55 | g_autoptr(GtkFileFilter) filter = gtk_file_filter_new(); 56 | gtk_file_filter_set_name(filter, name); 57 | FlValue* extensions = fl_value_get_list_value(value, 1); 58 | for (size_t j = 0; j < fl_value_get_length(extensions); j++) { 59 | FlValue* v = fl_value_get_list_value(extensions, j); 60 | if (fl_value_get_type(v) != FL_VALUE_TYPE_STRING) return nullptr; 61 | 62 | g_autofree gchar* pattern = g_strdup_printf("*.%s", fl_value_get_string(v)); 63 | gtk_file_filter_add_pattern(filter, pattern); 64 | } 65 | if (fl_value_get_length(extensions) == 0) 66 | gtk_file_filter_add_pattern(filter, "*"); 67 | 68 | return GTK_FILE_FILTER(g_object_ref(filter)); 69 | } 70 | 71 | // Shows the requested dialog type. 72 | static FlMethodResponse* show_dialog(FlFileChooserPlugin* self, 73 | GtkFileChooserAction action, 74 | const gchar* title, 75 | const gchar* default_confirm_button_text, 76 | FlValue* properties) { 77 | if (fl_value_get_type(properties) != FL_VALUE_TYPE_MAP) { 78 | return FL_METHOD_RESPONSE(fl_method_error_response_new( 79 | kBadArgumentsError, "Argument map missing or malformed", nullptr)); 80 | } 81 | 82 | const gchar* confirm_button_text = default_confirm_button_text; 83 | FlValue* value = fl_value_lookup_string(properties, kConfirmButtonTextKey); 84 | if (value != nullptr && fl_value_get_type(value) == FL_VALUE_TYPE_STRING) 85 | confirm_button_text = fl_value_get_string(value); 86 | 87 | FlView* view = fl_plugin_registrar_get_view(self->registrar); 88 | if (view == nullptr) { 89 | return FL_METHOD_RESPONSE( 90 | fl_method_error_response_new(kNoScreenError, nullptr, nullptr)); 91 | } 92 | 93 | GtkWindow* window = GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(view))); 94 | g_autoptr(GtkFileChooserNative) dialog = 95 | GTK_FILE_CHOOSER_NATIVE(gtk_file_chooser_native_new( 96 | title, window, action, confirm_button_text, "_Cancel")); 97 | 98 | value = fl_value_lookup_string(properties, kAllowsMultipleSelectionKey); 99 | if (value != nullptr && fl_value_get_type(value) == FL_VALUE_TYPE_BOOL) { 100 | gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(dialog), 101 | fl_value_get_bool(value)); 102 | } 103 | 104 | value = fl_value_lookup_string(properties, kCanChooseDirectoriesKey); 105 | if (value != nullptr && fl_value_get_type(value) == FL_VALUE_TYPE_BOOL && 106 | fl_value_get_bool(value)) { 107 | gtk_file_chooser_set_action(GTK_FILE_CHOOSER(dialog), 108 | GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER); 109 | } 110 | 111 | value = fl_value_lookup_string(properties, kInitialDirectoryKey); 112 | if (value != nullptr && fl_value_get_type(value) == FL_VALUE_TYPE_STRING) { 113 | gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), 114 | fl_value_get_string(value)); 115 | } 116 | 117 | value = fl_value_lookup_string(properties, kInitialFileNameKey); 118 | if (value != nullptr && fl_value_get_type(value) == FL_VALUE_TYPE_STRING) { 119 | gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(dialog), 120 | fl_value_get_string(value)); 121 | } 122 | 123 | value = fl_value_lookup_string(properties, kAllowedFileTypesKey); 124 | if (value != nullptr && fl_value_get_type(value) == FL_VALUE_TYPE_LIST) { 125 | for (size_t i = 0; i < fl_value_get_length(value); i++) { 126 | FlValue* file_type = fl_value_get_list_value(value, i); 127 | g_autoptr(GtkFileFilter) filter = file_type_to_filter(file_type); 128 | if (filter == nullptr) { 129 | return FL_METHOD_RESPONSE(fl_method_error_response_new( 130 | kBadArgumentsError, "Allowed file types malformed", nullptr)); 131 | } 132 | gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), filter); 133 | } 134 | } 135 | 136 | gint response = gtk_native_dialog_run(GTK_NATIVE_DIALOG(dialog)); 137 | g_autoptr(FlValue) result = nullptr; 138 | if (response == GTK_RESPONSE_ACCEPT) { 139 | result = fl_value_new_list(); 140 | g_autoptr(GSList) filenames = 141 | gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(dialog)); 142 | for (GSList* link = filenames; link != nullptr; link = link->next) { 143 | g_autofree gchar* filename = static_cast(link->data); 144 | fl_value_append_take(result, fl_value_new_string(filename)); 145 | } 146 | } 147 | 148 | return FL_METHOD_RESPONSE(fl_method_success_response_new(result)); 149 | } 150 | 151 | // Called when a method call is received from Flutter. 152 | static void method_call_cb(FlMethodChannel* channel, FlMethodCall* method_call, 153 | gpointer user_data) { 154 | FlFileChooserPlugin* self = FL_FILE_CHOOSER_PLUGIN(user_data); 155 | 156 | const gchar* method = fl_method_call_get_name(method_call); 157 | FlValue* args = fl_method_call_get_args(method_call); 158 | 159 | g_autoptr(FlMethodResponse) response = nullptr; 160 | if (strcmp(method, kShowOpenPanelMethod) == 0) { 161 | response = show_dialog(self, GTK_FILE_CHOOSER_ACTION_OPEN, "Open File", 162 | "_Open", args); 163 | } else if (strcmp(method, kShowSavePanelMethod) == 0) { 164 | response = show_dialog(self, GTK_FILE_CHOOSER_ACTION_SAVE, "Save File", 165 | "_Save", args); 166 | } else { 167 | response = FL_METHOD_RESPONSE(fl_method_not_implemented_response_new()); 168 | } 169 | 170 | g_autoptr(GError) error = nullptr; 171 | if (!fl_method_call_respond(method_call, response, &error)) 172 | g_warning("Failed to send method call response: %s", error->message); 173 | } 174 | 175 | static void fl_file_chooser_plugin_dispose(GObject* object) { 176 | FlFileChooserPlugin* self = FL_FILE_CHOOSER_PLUGIN(object); 177 | 178 | g_clear_object(&self->registrar); 179 | g_clear_object(&self->channel); 180 | 181 | G_OBJECT_CLASS(fl_file_chooser_plugin_parent_class)->dispose(object); 182 | } 183 | 184 | static void fl_file_chooser_plugin_class_init(FlFileChooserPluginClass* klass) { 185 | G_OBJECT_CLASS(klass)->dispose = fl_file_chooser_plugin_dispose; 186 | } 187 | 188 | static void fl_file_chooser_plugin_init(FlFileChooserPlugin* self) {} 189 | 190 | FlFileChooserPlugin* fl_file_chooser_plugin_new(FlPluginRegistrar* registrar) { 191 | FlFileChooserPlugin* self = FL_FILE_CHOOSER_PLUGIN( 192 | g_object_new(fl_file_chooser_plugin_get_type(), nullptr)); 193 | 194 | self->registrar = FL_PLUGIN_REGISTRAR(g_object_ref(registrar)); 195 | 196 | g_autoptr(FlStandardMethodCodec) codec = fl_standard_method_codec_new(); 197 | self->channel = 198 | fl_method_channel_new(fl_plugin_registrar_get_messenger(registrar), 199 | kChannelName, FL_METHOD_CODEC(codec)); 200 | fl_method_channel_set_method_call_handler(self->channel, method_call_cb, 201 | g_object_ref(self), g_object_unref); 202 | 203 | return self; 204 | } 205 | 206 | void file_chooser_plugin_register_with_registrar(FlPluginRegistrar* registrar) { 207 | FlFileChooserPlugin* plugin = fl_file_chooser_plugin_new(registrar); 208 | g_object_unref(plugin); 209 | } 210 | --------------------------------------------------------------------------------