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

Commit f9ee25f

Browse files
eugerossettoadpinola
authored andcommitted
Add win32 package and base dialog wrapper class.
Add methods of FileDialogController Add FileDialogController tests. Change the location where the free of the pointer is placed.
1 parent 3d44753 commit f9ee25f

File tree

7 files changed

+444
-0
lines changed

7 files changed

+444
-0
lines changed
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
// Copyright 2013 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
import 'dart:ffi';
6+
7+
import 'package:win32/win32.dart';
8+
9+
import 'ifile_open_dialog_factory.dart';
10+
11+
/// A thin wrapper for IFileDialog to allow for faking and inspection in tests.
12+
///
13+
/// Since this class defines the end of what can be unit tested, it should
14+
/// contain as little logic as possible.
15+
class FileDialogController {
16+
/// Creates a controller managing [IFileDialog](https://pub.dev/documentation/win32/latest/winrt/IFileDialog-class.html).
17+
/// It also receives an IFileOpenDialogFactory to construct [IFileOpenDialog]
18+
/// instances.
19+
FileDialogController(
20+
IFileDialog fileDialog, IFileOpenDialogFactory iFileOpenDialogFactory)
21+
: _fileDialog = fileDialog,
22+
_iFileOpenDialogFactory = iFileOpenDialogFactory;
23+
24+
/// The [IFileDialog] to work with.
25+
final IFileDialog _fileDialog;
26+
27+
/// The [IFileOpenDialogFactory] to work construc [IFileOpenDialog] instances.
28+
final IFileOpenDialogFactory _iFileOpenDialogFactory;
29+
30+
/// Sets the default folder for the dialog to [path]. It also returns the operation result.
31+
int setFolder(Pointer<COMObject> path) {
32+
return _fileDialog.setFolder(path);
33+
}
34+
35+
/// Sets the file [name] that is initially shown in the IFileDialog. It also returns the operation result.
36+
int setFileName(String name) {
37+
return _fileDialog.setFileName(TEXT(name));
38+
}
39+
40+
/// Sets the allowed file type extensions in the IFileOpenDialog. It also returns the operation result.
41+
int setFileTypes(int count, Pointer<COMDLG_FILTERSPEC> filters) {
42+
return _fileDialog.setFileTypes(count, filters);
43+
}
44+
45+
/// Sets the label of the confirmation button. It also returns the operation result. It also returns the operation result.
46+
int setOkButtonLabel(String text) {
47+
return _fileDialog.setOkButtonLabel(TEXT(text));
48+
}
49+
50+
/// Gets the IFileDialog's [options](https://pub.dev/documentation/win32/latest/winrt/FILEOPENDIALOGOPTIONS-class.html),
51+
/// which is a bitfield. It also returns the operation result.
52+
int getOptions(Pointer<Uint32> outOptions) {
53+
return _fileDialog.getOptions(outOptions);
54+
}
55+
56+
/// Sets the [options](https://pub.dev/documentation/win32/latest/winrt/FILEOPENDIALOGOPTIONS-class.html),
57+
/// which is a bitfield, into the IFileDialog. It also returns the operation result.
58+
int setOptions(int options) {
59+
return _fileDialog.setOptions(options);
60+
}
61+
62+
/// Shows an IFileDialog using the given parent. It returns the operation result.
63+
int show(int parent) {
64+
return _fileDialog.show(parent);
65+
}
66+
67+
/// Return results from an IFileDialog. This should be used when selecting
68+
/// single items. It also returns the operation result.
69+
int getResult(Pointer<Pointer<COMObject>> outItem) {
70+
return _fileDialog.getResult(outItem);
71+
}
72+
73+
/// Return results from an IFileOpenDialog. This should be used when selecting
74+
/// single items. This function will fail if the IFileDialog* provided to the
75+
/// constructor was not an IFileOpenDialog instance, returning an E_FAIL
76+
/// error.
77+
int getResults(Pointer<Pointer<COMObject>> outItems) {
78+
IFileOpenDialog? fileOpenDialog;
79+
try {
80+
fileOpenDialog = _iFileOpenDialogFactory.from(_fileDialog);
81+
return fileOpenDialog.getResults(outItems);
82+
} catch (_) {
83+
return E_FAIL;
84+
} finally {
85+
fileOpenDialog?.release();
86+
if (fileOpenDialog != null) {
87+
free(fileOpenDialog.ptr);
88+
}
89+
}
90+
}
91+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// Copyright 2013 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
import 'package:win32/win32.dart';
6+
7+
/// A wrapper of the IFileOpenDialog interface to use its from function.
8+
class IFileOpenDialogFactory {
9+
/// Wraps the IFileOpenDialog from function.
10+
IFileOpenDialog from(IFileDialog fileDialog) {
11+
return IFileOpenDialog.from(fileDialog);
12+
}
13+
}

packages/file_selector/file_selector_windows/pubspec.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,11 @@ flutter:
1818

1919
dependencies:
2020
cross_file: ^0.3.1
21+
ffi: ^2.0.1
2122
file_selector_platform_interface: ^2.2.0
2223
flutter:
2324
sdk: flutter
25+
win32: ^3.0.0
2426

2527
dev_dependencies:
2628
build_runner: 2.1.11
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
// Copyright 2013 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
import 'dart:ffi';
6+
7+
import 'package:ffi/ffi.dart';
8+
import 'package:flutter_test/flutter_test.dart';
9+
import 'package:win32/win32.dart';
10+
11+
// Fake IFileDialog class for testing purposes.
12+
class FakeIFileDialog extends Fake implements IFileDialog {
13+
int _getOptionsCalledTimes = 0;
14+
int _getResultCalledTimes = 0;
15+
int _setOptionsCalledTimes = 0;
16+
int _setFolderCalledTimes = 0;
17+
int _setFileNameCalledTimes = 0;
18+
int _setFileTypesCalledTimes = 0;
19+
int _setOkButtonLabelCalledTimes = 0;
20+
int _showCalledTimes = 0;
21+
22+
@override
23+
int getOptions(Pointer<Uint32> pfos) {
24+
_getOptionsCalledTimes++;
25+
return S_OK;
26+
}
27+
28+
@override
29+
int setOptions(int options) {
30+
_setOptionsCalledTimes++;
31+
return S_OK;
32+
}
33+
34+
@override
35+
int getResult(Pointer<Pointer<COMObject>> ppsi) {
36+
_getResultCalledTimes++;
37+
return S_OK;
38+
}
39+
40+
@override
41+
int setFolder(Pointer<COMObject> psi) {
42+
_setFolderCalledTimes++;
43+
return S_OK;
44+
}
45+
46+
@override
47+
int setFileTypes(int cFileTypes, Pointer<COMDLG_FILTERSPEC> rgFilterSpec) {
48+
_setFileTypesCalledTimes++;
49+
return S_OK;
50+
}
51+
52+
@override
53+
int setFileName(Pointer<Utf16> pszName) {
54+
_setFileNameCalledTimes++;
55+
return S_OK;
56+
}
57+
58+
@override
59+
int setOkButtonLabel(Pointer<Utf16> pszText) {
60+
_setOkButtonLabelCalledTimes++;
61+
return S_OK;
62+
}
63+
64+
@override
65+
int show(int hwndOwner) {
66+
_showCalledTimes++;
67+
return S_OK;
68+
}
69+
70+
void resetCounters() {
71+
_getOptionsCalledTimes = 0;
72+
_getResultCalledTimes = 0;
73+
_setOptionsCalledTimes = 0;
74+
_setFolderCalledTimes = 0;
75+
_setFileTypesCalledTimes = 0;
76+
_setOkButtonLabelCalledTimes = 0;
77+
_showCalledTimes = 0;
78+
_setFileNameCalledTimes = 0;
79+
}
80+
81+
int getOptionsCalledTimes() {
82+
return _getOptionsCalledTimes;
83+
}
84+
85+
int setOptionsCalledTimes() {
86+
return _setOptionsCalledTimes;
87+
}
88+
89+
int getResultCalledTimes() {
90+
return _getResultCalledTimes;
91+
}
92+
93+
int setFolderCalledTimes() {
94+
return _setFolderCalledTimes;
95+
}
96+
97+
int setFileNameCalledTimes() {
98+
return _setFileNameCalledTimes;
99+
}
100+
101+
int setFileTypesCalledTimes() {
102+
return _setFileTypesCalledTimes;
103+
}
104+
105+
int setOkButtonLabelCalledTimes() {
106+
return _setOkButtonLabelCalledTimes;
107+
}
108+
109+
int showCalledTimes() {
110+
return _showCalledTimes;
111+
}
112+
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
// Copyright 2013 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
import 'dart:ffi';
6+
7+
import 'package:flutter_test/flutter_test.dart';
8+
import 'package:win32/win32.dart';
9+
10+
// Fake IFileOpenDialog class for testing purposes.
11+
class FakeIFileOpenDialog extends Fake implements IFileOpenDialog {
12+
int _getResultsCalledTimes = 0;
13+
int _getReleaseCalledTimes = 0;
14+
bool _shouldFail = false;
15+
16+
@override
17+
Pointer<COMObject> get ptr => nullptr;
18+
19+
@override
20+
int release() {
21+
_getReleaseCalledTimes++;
22+
return S_OK;
23+
}
24+
25+
@override
26+
int getResults(Pointer<Pointer<COMObject>> ppsi) {
27+
_getResultsCalledTimes++;
28+
if (_shouldFail) {
29+
throw WindowsException(E_FAIL);
30+
}
31+
32+
return S_OK;
33+
}
34+
35+
void resetCounters() {
36+
_getResultsCalledTimes = 0;
37+
_getReleaseCalledTimes = 0;
38+
}
39+
40+
int getResultsCalledTimes() {
41+
return _getResultsCalledTimes;
42+
}
43+
44+
int getReleaseCalledTimes() {
45+
return _getReleaseCalledTimes;
46+
}
47+
48+
void mockFailure() {
49+
_shouldFail = true;
50+
}
51+
52+
void mockSuccess() {
53+
_shouldFail = false;
54+
}
55+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
// Copyright 2013 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
import 'package:file_selector_windows/src/file_selector_dart/ifile_open_dialog_factory.dart';
6+
import 'package:flutter_test/flutter_test.dart';
7+
import 'package:win32/win32.dart';
8+
9+
import 'fake_ifile_open_dialog.dart';
10+
11+
// Fake FakeIFileOpenDialogFactory class for testing purposes.
12+
class FakeIFileOpenDialogFactory extends Fake
13+
implements IFileOpenDialogFactory {
14+
int _fromCalledTimes = 0;
15+
bool _shouldFail = false;
16+
17+
final FakeIFileOpenDialog fakeIFileOpenDialog = FakeIFileOpenDialog();
18+
19+
@override
20+
IFileOpenDialog from(IFileDialog dialog) {
21+
_fromCalledTimes++;
22+
if (_shouldFail) {
23+
throw WindowsException(E_NOINTERFACE);
24+
}
25+
26+
return fakeIFileOpenDialog;
27+
}
28+
29+
int getFromCalledTimes() {
30+
return _fromCalledTimes;
31+
}
32+
33+
void mockSuccess() {
34+
_shouldFail = false;
35+
}
36+
37+
void mockFailure() {
38+
_shouldFail = true;
39+
}
40+
}

0 commit comments

Comments
 (0)