Skip to content
This repository was archived by the owner on Feb 22, 2023. It is now read-only.

[file_selector] Migrate file_dialog_controller to Dart. #6518

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import 'dart:ffi';

import 'package:win32/win32.dart';

import 'ifile_open_dialog_factory.dart';

/// A thin wrapper for IFileDialog to allow for faking and inspection in tests.
///
/// Since this class defines the end of what can be unit tested, it should
/// contain as little logic as possible.
class FileDialogController {
/// Creates a controller managing [IFileDialog](https://pub.dev/documentation/win32/latest/winrt/IFileDialog-class.html).
/// It also receives an IFileOpenDialogFactory to construct [IFileOpenDialog]
/// instances.
FileDialogController(
IFileDialog fileDialog, IFileOpenDialogFactory iFileOpenDialogFactory)
: _fileDialog = fileDialog,
_iFileOpenDialogFactory = iFileOpenDialogFactory;

/// The [IFileDialog] to work with.
final IFileDialog _fileDialog;

/// The [IFileOpenDialogFactory] to work construc [IFileOpenDialog] instances.
final IFileOpenDialogFactory _iFileOpenDialogFactory;

/// Sets the default folder for the dialog to [path]. It also returns the operation result.
int setFolder(Pointer<COMObject> path) {
return _fileDialog.setFolder(path);
}

/// Sets the file [name] that is initially shown in the IFileDialog. It also returns the operation result.
int setFileName(String name) {
return _fileDialog.setFileName(TEXT(name));
}

/// Sets the allowed file type extensions in the IFileOpenDialog. It also returns the operation result.
int setFileTypes(int count, Pointer<COMDLG_FILTERSPEC> filters) {
return _fileDialog.setFileTypes(count, filters);
}

/// Sets the label of the confirmation button. It also returns the operation result. It also returns the operation result.
int setOkButtonLabel(String text) {
return _fileDialog.setOkButtonLabel(TEXT(text));
}

/// Gets the IFileDialog's [options](https://pub.dev/documentation/win32/latest/winrt/FILEOPENDIALOGOPTIONS-class.html),
/// which is a bitfield. It also returns the operation result.
int getOptions(Pointer<Uint32> outOptions) {
return _fileDialog.getOptions(outOptions);
}

/// Sets the [options](https://pub.dev/documentation/win32/latest/winrt/FILEOPENDIALOGOPTIONS-class.html),
/// which is a bitfield, into the IFileDialog. It also returns the operation result.
int setOptions(int options) {
return _fileDialog.setOptions(options);
}

/// Shows an IFileDialog using the given parent. It returns the operation result.
int show(int parent) {
return _fileDialog.show(parent);
}

/// Return results from an IFileDialog. This should be used when selecting
/// single items. It also returns the operation result.
int getResult(Pointer<Pointer<COMObject>> outItem) {
return _fileDialog.getResult(outItem);
}

/// Return results from an IFileOpenDialog. This should be used when selecting
/// single items. This function will fail if the IFileDialog* provided to the
/// constructor was not an IFileOpenDialog instance, returning an E_FAIL
/// error.
int getResults(Pointer<Pointer<COMObject>> outItems) {
IFileOpenDialog? fileOpenDialog;
try {
fileOpenDialog = _iFileOpenDialogFactory.from(_fileDialog);
return fileOpenDialog.getResults(outItems);
} catch (_) {
return E_FAIL;
} finally {
fileOpenDialog?.release();
if (fileOpenDialog != null) {
free(fileOpenDialog.ptr);
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import 'package:win32/win32.dart';

/// A wrapper of the IFileOpenDialog interface to use its from function.
class IFileOpenDialogFactory {
/// Wraps the IFileOpenDialog from function.
IFileOpenDialog from(IFileDialog fileDialog) {
return IFileOpenDialog.from(fileDialog);
}
}
2 changes: 2 additions & 0 deletions packages/file_selector/file_selector_windows/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,11 @@ flutter:

dependencies:
cross_file: ^0.3.1
ffi: ^2.0.1
file_selector_platform_interface: ^2.2.0
flutter:
sdk: flutter
win32: ^3.0.0

dev_dependencies:
build_runner: 2.1.11
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import 'dart:ffi';

import 'package:ffi/ffi.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:win32/win32.dart';

// Fake IFileDialog class for testing purposes.
class FakeIFileDialog extends Fake implements IFileDialog {
int _getOptionsCalledTimes = 0;
int _getResultCalledTimes = 0;
int _setOptionsCalledTimes = 0;
int _setFolderCalledTimes = 0;
int _setFileNameCalledTimes = 0;
int _setFileTypesCalledTimes = 0;
int _setOkButtonLabelCalledTimes = 0;
int _showCalledTimes = 0;

@override
int getOptions(Pointer<Uint32> pfos) {
_getOptionsCalledTimes++;
return S_OK;
}

@override
int setOptions(int options) {
_setOptionsCalledTimes++;
return S_OK;
}

@override
int getResult(Pointer<Pointer<COMObject>> ppsi) {
_getResultCalledTimes++;
return S_OK;
}

@override
int setFolder(Pointer<COMObject> psi) {
_setFolderCalledTimes++;
return S_OK;
}

@override
int setFileTypes(int cFileTypes, Pointer<COMDLG_FILTERSPEC> rgFilterSpec) {
_setFileTypesCalledTimes++;
return S_OK;
}

@override
int setFileName(Pointer<Utf16> pszName) {
_setFileNameCalledTimes++;
return S_OK;
}

@override
int setOkButtonLabel(Pointer<Utf16> pszText) {
_setOkButtonLabelCalledTimes++;
return S_OK;
}

@override
int show(int hwndOwner) {
_showCalledTimes++;
return S_OK;
}

void resetCounters() {
_getOptionsCalledTimes = 0;
_getResultCalledTimes = 0;
_setOptionsCalledTimes = 0;
_setFolderCalledTimes = 0;
_setFileTypesCalledTimes = 0;
_setOkButtonLabelCalledTimes = 0;
_showCalledTimes = 0;
_setFileNameCalledTimes = 0;
}

int getOptionsCalledTimes() {
return _getOptionsCalledTimes;
}

int setOptionsCalledTimes() {
return _setOptionsCalledTimes;
}

int getResultCalledTimes() {
return _getResultCalledTimes;
}

int setFolderCalledTimes() {
return _setFolderCalledTimes;
}

int setFileNameCalledTimes() {
return _setFileNameCalledTimes;
}

int setFileTypesCalledTimes() {
return _setFileTypesCalledTimes;
}

int setOkButtonLabelCalledTimes() {
return _setOkButtonLabelCalledTimes;
}

int showCalledTimes() {
return _showCalledTimes;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import 'dart:ffi';

import 'package:flutter_test/flutter_test.dart';
import 'package:win32/win32.dart';

// Fake IFileOpenDialog class for testing purposes.
class FakeIFileOpenDialog extends Fake implements IFileOpenDialog {
int _getResultsCalledTimes = 0;
int _getReleaseCalledTimes = 0;
bool _shouldFail = false;

@override
Pointer<COMObject> get ptr => nullptr;

@override
int release() {
_getReleaseCalledTimes++;
return S_OK;
}

@override
int getResults(Pointer<Pointer<COMObject>> ppsi) {
_getResultsCalledTimes++;
if (_shouldFail) {
throw WindowsException(E_FAIL);
}

return S_OK;
}

void resetCounters() {
_getResultsCalledTimes = 0;
_getReleaseCalledTimes = 0;
}

int getResultsCalledTimes() {
return _getResultsCalledTimes;
}

int getReleaseCalledTimes() {
return _getReleaseCalledTimes;
}

void mockFailure() {
_shouldFail = true;
}

void mockSuccess() {
_shouldFail = false;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import 'package:file_selector_windows/src/file_selector_dart/ifile_open_dialog_factory.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:win32/win32.dart';

import 'fake_ifile_open_dialog.dart';

// Fake FakeIFileOpenDialogFactory class for testing purposes.
class FakeIFileOpenDialogFactory extends Fake
implements IFileOpenDialogFactory {
int _fromCalledTimes = 0;
bool _shouldFail = false;

final FakeIFileOpenDialog fakeIFileOpenDialog = FakeIFileOpenDialog();

@override
IFileOpenDialog from(IFileDialog dialog) {
_fromCalledTimes++;
if (_shouldFail) {
throw WindowsException(E_NOINTERFACE);
}

return fakeIFileOpenDialog;
}

int getFromCalledTimes() {
return _fromCalledTimes;
}

void mockSuccess() {
_shouldFail = false;
}

void mockFailure() {
_shouldFail = true;
}
}
Loading