Skip to content

Commit

Permalink
Make the file chooser a standalone plugin (#71)
Browse files Browse the repository at this point in the history
This extracts the file chooser out of the embedder frameworks and into
a standalone plugin. As part of that, adds the Dart side of the plugin
to the respository. The overall structure duplicates that of the color
panel plugin.

Includes some adjustments to the color panel plugin due to issues that
weren't apparent until there was a second plugin:
- The channel constants need (distinct) namespaces to avoid runtime
  collision of identical constant names (e.g., kChannelName).
- To match those namespaces, the Linux plugin code now uses distinct
  namespaces for all of the code in each plugin instead of sharing the
  flutter_desktop_embedding namespace.
- Since the common headers are now C++, the macOS plugin implementations
  are now .mm instead of .m.
- That in turn surfaced latent errors due to missing Framework link
  commands (for the dependencies on AppKit and the embedding framework).

Since the Dart code is now part of the repository, this patch also
does some queued cleanup that required two-sided changes:
- Removes the callback, providing the response using the result of
  the initial method call now that the API for that is available.
  This simplifies the Dart code significantly.
- Removes the status code from the response, since it can be inferred
  by whether or not the array is null. Since there is now only one
  response element, it is returned directly instead of as part of
  an array.

Also restructures the Dart code into multiple files so that all
of the internal details of the channel controller class are not
mixed in with the public API. Some public API adjustments as well.

Lastly, updates the example Flutter app to have simple tests for
save and open: buttons that trigger each type of panel, and a
snackbar that shows the responses. No actual file reading/writing
happens since it's not relevant to exercising the panels.
  • Loading branch information
stuartmorgan committed Jun 16, 2018
1 parent 263bdc2 commit f9075fb
Show file tree
Hide file tree
Showing 45 changed files with 1,287 additions and 688 deletions.
132 changes: 132 additions & 0 deletions analysis_options.yaml
@@ -0,0 +1,132 @@
# Copyright 2017 The Fuchsia Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

# Root analysis options shared among all Dart code in the respository. Based
# on the Fuchsia standard analysis options, with some changes.
analyzer:
strong-mode: true
language:
enableSuperMixins: true
linter:
# Full list available at http://dart-lang.github.io/linter/lints/options/options.html.
rules:
- always_declare_return_types
- always_put_control_body_on_new_line
- always_put_required_named_parameters_first
- always_require_non_null_named_parameters
- annotate_overrides
- avoid_as
- avoid_bool_literals_in_conditional_expressions
- avoid_catches_without_on_clauses
- avoid_catching_errors
- avoid_classes_with_only_static_members
- avoid_empty_else
# Not compatible with VS Code yet.
# - avoid_field_initializers_in_const_classes
- avoid_function_literals_in_foreach_calls
- avoid_init_to_null
- avoid_null_checks_in_equality_operators
- avoid_positional_boolean_parameters
- avoid_private_typedef_functions
- avoid_relative_lib_imports
# This puts an unnecessary burden on API clients.
# - avoid_renaming_method_parameters
- avoid_return_types_on_setters
- avoid_returning_null
- avoid_returning_this
- avoid_single_cascade_in_expression_statements
- avoid_setters_without_getters
- avoid_slow_async_io
- avoid_types_as_parameter_names
- avoid_types_on_closure_parameters
- avoid_unused_constructor_parameters
- await_only_futures
- camel_case_types
- cancel_subscriptions
- cascade_invocations
- close_sinks
- comment_references
- constant_identifier_names
- control_flow_in_finally
- directives_ordering
- empty_catches
- empty_constructor_bodies
- empty_statements
- hash_and_equals
- implementation_imports
- invariant_booleans
- iterable_contains_unrelated_type
- join_return_with_assignment
- library_names
- library_prefixes
- list_remove_unrelated_type
- literal_only_boolean_expressions
- no_adjacent_strings_in_list
- no_duplicate_case_values
- non_constant_identifier_names
- omit_local_variable_types
- one_member_abstracts
- only_throw_errors
- overridden_fields
- package_api_docs
- package_names
- package_prefixed_library_names
- parameter_assignments
- prefer_adjacent_string_concatenation
- prefer_asserts_in_initializer_lists
- prefer_bool_in_asserts
- prefer_collection_literals
- prefer_conditional_assignment
# Disabled until bug is fixed
# https://github.com/dart-lang/linter/issues/995
# - prefer_const_constructors
- prefer_const_constructors_in_immutables
- prefer_const_declarations
- prefer_const_literals_to_create_immutables
- prefer_constructors_over_static_methods
- prefer_contains
- prefer_equal_for_default_values
# Add this when 'short' is better defined.
# - prefer_expression_function_bodies
- prefer_final_fields
- prefer_final_locals
# Seems to have false positive with await for.
# - prefer_foreach
- prefer_function_declarations_over_variables
- prefer_generic_function_type_aliases
- prefer_initializing_formals
- prefer_interpolation_to_compose_strings
- prefer_is_empty
- prefer_is_not_empty
- prefer_iterable_whereType
- prefer_single_quotes
- prefer_typing_uninitialized_variables
- public_member_api_docs
- recursive_getters
- slash_for_doc_comments
- sort_constructors_first
- sort_unnamed_constructors_first
- super_goes_last
- test_types_in_equals
- throw_in_finally
- type_annotate_public_apis
- type_init_formals
- unawaited_futures
- unnecessary_brace_in_string_interps
- unnecessary_getters_setters
- unnecessary_lambdas
- unnecessary_null_aware_assignments
- unnecessary_null_in_if_null_operators
- unnecessary_overrides
- unnecessary_parenthesis
- unnecessary_statements
- unnecessary_this
- unrelated_type_equality_checks
- use_rethrow_when_possible
- use_setters_to_change_properties
- use_string_buffers
- use_to_and_as_if_applicable
- valid_regexps
# Not compatible with VS Code yet.
# - void_checks
130 changes: 1 addition & 129 deletions example_flutter/analysis_options.yaml
@@ -1,129 +1 @@
# Copyright 2017 The Fuchsia Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
analyzer:
strong-mode: true
language:
enableSuperMixins: true
linter:
# Full list available at http://dart-lang.github.io/linter/lints/options/options.html.
rules:
- always_declare_return_types
- always_put_control_body_on_new_line
- always_put_required_named_parameters_first
- always_require_non_null_named_parameters
- annotate_overrides
- avoid_as
- avoid_bool_literals_in_conditional_expressions
- avoid_catches_without_on_clauses
- avoid_catching_errors
- avoid_classes_with_only_static_members
- avoid_empty_else
# Not compatible with VS Code yet.
# - avoid_field_initializers_in_const_classes
- avoid_function_literals_in_foreach_calls
- avoid_init_to_null
- avoid_null_checks_in_equality_operators
- avoid_positional_boolean_parameters
- avoid_private_typedef_functions
- avoid_relative_lib_imports
# This puts an unnecessary burden on API clients.
# - avoid_renaming_method_parameters
- avoid_return_types_on_setters
- avoid_returning_null
- avoid_returning_this
- avoid_single_cascade_in_expression_statements
- avoid_setters_without_getters
- avoid_slow_async_io
- avoid_types_as_parameter_names
- avoid_types_on_closure_parameters
- avoid_unused_constructor_parameters
- await_only_futures
- camel_case_types
- cancel_subscriptions
- cascade_invocations
- close_sinks
- comment_references
- constant_identifier_names
- control_flow_in_finally
- directives_ordering
- empty_catches
- empty_constructor_bodies
- empty_statements
- hash_and_equals
- implementation_imports
- invariant_booleans
- iterable_contains_unrelated_type
- join_return_with_assignment
- library_names
- library_prefixes
- list_remove_unrelated_type
- literal_only_boolean_expressions
- no_adjacent_strings_in_list
- no_duplicate_case_values
- non_constant_identifier_names
- omit_local_variable_types
- one_member_abstracts
- only_throw_errors
- overridden_fields
- package_api_docs
- package_names
- package_prefixed_library_names
- parameter_assignments
- prefer_adjacent_string_concatenation
- prefer_asserts_in_initializer_lists
- prefer_bool_in_asserts
- prefer_collection_literals
- prefer_conditional_assignment
# Disabled until bug is fixed
# https://github.com/dart-lang/linter/issues/995
# - prefer_const_constructors
- prefer_const_constructors_in_immutables
- prefer_const_declarations
- prefer_const_literals_to_create_immutables
- prefer_constructors_over_static_methods
- prefer_contains
- prefer_equal_for_default_values
# Add this when 'short' is better defined.
# - prefer_expression_function_bodies
- prefer_final_fields
- prefer_final_locals
# Seems to have false positive with await for
# - prefer_foreach
- prefer_function_declarations_over_variables
- prefer_generic_function_type_aliases
- prefer_initializing_formals
- prefer_interpolation_to_compose_strings
- prefer_is_empty
- prefer_is_not_empty
- prefer_iterable_whereType
- prefer_single_quotes
- prefer_typing_uninitialized_variables
# - public_member_api_docs
- recursive_getters
- slash_for_doc_comments
- sort_constructors_first
- sort_unnamed_constructors_first
- super_goes_last
- test_types_in_equals
- throw_in_finally
- type_annotate_public_apis
- type_init_formals
- unawaited_futures
- unnecessary_brace_in_string_interps
- unnecessary_getters_setters
- unnecessary_lambdas
- unnecessary_null_aware_assignments
- unnecessary_null_in_if_null_operators
- unnecessary_overrides
- unnecessary_parenthesis
- unnecessary_statements
- unnecessary_this
- unrelated_type_equality_checks
- use_rethrow_when_possible
- use_setters_to_change_properties
- use_string_buffers
- use_to_and_as_if_applicable
- valid_regexps
# Not compatible with VS Code yet.
# - void_checks
include: ../analysis_options.yaml
60 changes: 56 additions & 4 deletions example_flutter/lib/main.dart
Expand Up @@ -13,10 +13,13 @@
// limitations under the License.
import 'package:flutter/material.dart';
import 'package:color_panel/color_panel.dart';
import 'package:file_chooser/file_chooser.dart' as file_chooser;

void main() => runApp(new MyApp());

/// Top level widget for the example application.
class MyApp extends StatefulWidget {
/// Constructs a new app with the given [key].
const MyApp({Key key}) : super(key: key);

@override
Expand All @@ -43,20 +46,20 @@ class _AppState extends State<MyApp> {
primaryColor: _primaryColor,
accentColor: _primaryColor,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
home: _MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}

class MyHomePage extends StatefulWidget {
const MyHomePage({Key key, this.title}) : super(key: key);
class _MyHomePage extends StatefulWidget {
const _MyHomePage({Key key, this.title}) : super(key: key);
final String title;

@override
_MyHomePageState createState() => new _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
class _MyHomePageState extends State<_MyHomePage> {
int _counter = 0;

void _incrementCounter() {
Expand Down Expand Up @@ -100,6 +103,7 @@ class _MyHomePageState extends State<MyHomePage> {
'$_counter',
style: Theme.of(context).textTheme.display1,
),
FileChooserTestWidget(),
],
),
),
Expand All @@ -111,3 +115,51 @@ class _MyHomePageState extends State<MyHomePage> {
);
}
}

/// A widget containing controls to test the file chooser plugin.
class FileChooserTestWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return ButtonBar(
alignment: MainAxisAlignment.center,
children: <Widget>[
new FlatButton(
child: const Text('SAVE'),
onPressed: () {
file_chooser.showSavePanel((result, paths) {
Scaffold.of(context).showSnackBar(SnackBar(
content: Text(_resultTextForFileChooserOperation(
_FileChooserType.save, result, paths)),
));
}, suggestedFileName: 'save_test.txt');
},
),
new FlatButton(
child: const Text('OPEN'),
onPressed: () {
file_chooser.showOpenPanel((result, paths) {
Scaffold.of(context).showSnackBar(SnackBar(
content: Text(_resultTextForFileChooserOperation(
_FileChooserType.open, result, paths)),
));
}, allowsMultipleSelection: true);
},
),
],
);
}
}

/// Possible file chooser operation types.
enum _FileChooserType { save, open }

/// Returns display text reflecting the result of a file chooser operation.
String _resultTextForFileChooserOperation(
_FileChooserType type, file_chooser.FileChooserResult result,
[List<String> paths]) {
if (result == file_chooser.FileChooserResult.cancel) {
return '${type == _FileChooserType.open ? 'Open' : 'Save'} cancelled';
}
final statusText = type == _FileChooserType.open ? 'Opened' : 'Saved';
return '$statusText: ${paths.join('\n')}';
}
9 changes: 8 additions & 1 deletion example_flutter/pubspec.lock
Expand Up @@ -78,6 +78,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "0.1.1"
file_chooser:
dependency: "direct main"
description:
path: "../plugins/file_chooser"
relative: true
source: path
version: "0.0.0"
flutter:
dependency: "direct main"
description: flutter
Expand Down Expand Up @@ -374,4 +381,4 @@ packages:
source: hosted
version: "2.1.13"
sdks:
dart: ">=2.0.0-dev.52.0 <=2.0.0-dev.54.0.flutter-46ab040e58"
dart: ">=2.0.0-dev.52.0 <=2.0.0-dev.58.0.flutter-f981f09760"
3 changes: 3 additions & 0 deletions example_flutter/pubspec.yaml
Expand Up @@ -9,8 +9,11 @@ dependencies:
# Use with the CupertinoIcons class for iOS style icons.
cupertino_icons: ^0.1.0

# Desktop embedder plugins.
color_panel:
path: ../plugins/color_panel
file_chooser:
path: ../plugins/file_chooser

dev_dependencies:
flutter_test:
Expand Down

0 comments on commit f9075fb

Please sign in to comment.