mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
fix: windows integration test (#2917)
* fix:windows integration test * fix: load asset * fix: windows test * fix: test * test: refactor the folder test --------- Co-authored-by: vedon <vedon.fu@gmail.com> Co-authored-by: Lucas.Xu <lucas.xu@appflowy.io>
This commit is contained in:
parent
2c513be305
commit
f0d5f51703
2
.github/workflows/integration_test.yml
vendored
2
.github/workflows/integration_test.yml
vendored
@ -33,7 +33,7 @@ jobs:
|
|||||||
if: github.event.pull_request.draft != true
|
if: github.event.pull_request.draft != true
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
os: [ubuntu-latest]
|
os: [ubuntu-latest, windows-latest]
|
||||||
|
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
|
|
||||||
|
@ -10,21 +10,6 @@ void main() {
|
|||||||
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
|
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
|
||||||
|
|
||||||
group('database', () {
|
group('database', () {
|
||||||
const location = 'appflowy';
|
|
||||||
|
|
||||||
setUp(() async {
|
|
||||||
await TestFolder.cleanTestLocation(location);
|
|
||||||
await TestFolder.setTestLocation(location);
|
|
||||||
});
|
|
||||||
|
|
||||||
tearDown(() async {
|
|
||||||
await TestFolder.cleanTestLocation(location);
|
|
||||||
});
|
|
||||||
|
|
||||||
tearDownAll(() async {
|
|
||||||
await TestFolder.cleanTestLocation(null);
|
|
||||||
});
|
|
||||||
|
|
||||||
testWidgets('update calendar layout', (tester) async {
|
testWidgets('update calendar layout', (tester) async {
|
||||||
await tester.initializeAppFlowy();
|
await tester.initializeAppFlowy();
|
||||||
await tester.tapGoButton();
|
await tester.tapGoButton();
|
||||||
|
@ -11,21 +11,6 @@ void main() {
|
|||||||
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
|
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
|
||||||
|
|
||||||
group('grid cell', () {
|
group('grid cell', () {
|
||||||
const location = 'appflowy';
|
|
||||||
|
|
||||||
setUp(() async {
|
|
||||||
await TestFolder.cleanTestLocation(location);
|
|
||||||
await TestFolder.setTestLocation(location);
|
|
||||||
});
|
|
||||||
|
|
||||||
tearDown(() async {
|
|
||||||
await TestFolder.cleanTestLocation(location);
|
|
||||||
});
|
|
||||||
|
|
||||||
tearDownAll(() async {
|
|
||||||
await TestFolder.cleanTestLocation(null);
|
|
||||||
});
|
|
||||||
|
|
||||||
testWidgets('edit text cell', (tester) async {
|
testWidgets('edit text cell', (tester) async {
|
||||||
await tester.initializeAppFlowy();
|
await tester.initializeAppFlowy();
|
||||||
await tester.tapGoButton();
|
await tester.tapGoButton();
|
||||||
|
@ -10,21 +10,6 @@ void main() {
|
|||||||
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
|
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
|
||||||
|
|
||||||
group('grid page', () {
|
group('grid page', () {
|
||||||
const location = 'appflowy';
|
|
||||||
|
|
||||||
setUp(() async {
|
|
||||||
await TestFolder.cleanTestLocation(location);
|
|
||||||
await TestFolder.setTestLocation(location);
|
|
||||||
});
|
|
||||||
|
|
||||||
tearDown(() async {
|
|
||||||
await TestFolder.cleanTestLocation(location);
|
|
||||||
});
|
|
||||||
|
|
||||||
tearDownAll(() async {
|
|
||||||
await TestFolder.cleanTestLocation(null);
|
|
||||||
});
|
|
||||||
|
|
||||||
testWidgets('rename existing field', (tester) async {
|
testWidgets('rename existing field', (tester) async {
|
||||||
await tester.initializeAppFlowy();
|
await tester.initializeAppFlowy();
|
||||||
await tester.tapGoButton();
|
await tester.tapGoButton();
|
||||||
|
@ -5,27 +5,11 @@ import 'package:flutter_test/flutter_test.dart';
|
|||||||
import 'package:integration_test/integration_test.dart';
|
import 'package:integration_test/integration_test.dart';
|
||||||
|
|
||||||
import 'util/database_test_op.dart';
|
import 'util/database_test_op.dart';
|
||||||
import 'util/util.dart';
|
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
|
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
|
||||||
|
|
||||||
group('grid', () {
|
group('grid', () {
|
||||||
const location = 'import_files';
|
|
||||||
|
|
||||||
setUp(() async {
|
|
||||||
await TestFolder.cleanTestLocation(location);
|
|
||||||
await TestFolder.setTestLocation(location);
|
|
||||||
});
|
|
||||||
|
|
||||||
tearDown(() async {
|
|
||||||
await TestFolder.cleanTestLocation(location);
|
|
||||||
});
|
|
||||||
|
|
||||||
tearDownAll(() async {
|
|
||||||
await TestFolder.cleanTestLocation(null);
|
|
||||||
});
|
|
||||||
|
|
||||||
testWidgets('add text filter', (tester) async {
|
testWidgets('add text filter', (tester) async {
|
||||||
await tester.openV020database();
|
await tester.openV020database();
|
||||||
|
|
||||||
|
@ -14,21 +14,6 @@ void main() {
|
|||||||
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
|
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
|
||||||
|
|
||||||
group('grid', () {
|
group('grid', () {
|
||||||
const location = 'appflowy';
|
|
||||||
|
|
||||||
setUp(() async {
|
|
||||||
await TestFolder.cleanTestLocation(location);
|
|
||||||
await TestFolder.setTestLocation(location);
|
|
||||||
});
|
|
||||||
|
|
||||||
tearDown(() async {
|
|
||||||
await TestFolder.cleanTestLocation(location);
|
|
||||||
});
|
|
||||||
|
|
||||||
tearDownAll(() async {
|
|
||||||
await TestFolder.cleanTestLocation(null);
|
|
||||||
});
|
|
||||||
|
|
||||||
testWidgets('row details page opens', (tester) async {
|
testWidgets('row details page opens', (tester) async {
|
||||||
await tester.initializeAppFlowy();
|
await tester.initializeAppFlowy();
|
||||||
await tester.tapGoButton();
|
await tester.tapGoButton();
|
||||||
|
@ -8,21 +8,6 @@ void main() {
|
|||||||
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
|
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
|
||||||
|
|
||||||
group('grid', () {
|
group('grid', () {
|
||||||
const location = 'appflowy';
|
|
||||||
|
|
||||||
setUp(() async {
|
|
||||||
await TestFolder.cleanTestLocation(location);
|
|
||||||
await TestFolder.setTestLocation(location);
|
|
||||||
});
|
|
||||||
|
|
||||||
tearDown(() async {
|
|
||||||
await TestFolder.cleanTestLocation(location);
|
|
||||||
});
|
|
||||||
|
|
||||||
tearDownAll(() async {
|
|
||||||
await TestFolder.cleanTestLocation(null);
|
|
||||||
});
|
|
||||||
|
|
||||||
testWidgets('create row of the grid', (tester) async {
|
testWidgets('create row of the grid', (tester) async {
|
||||||
await tester.initializeAppFlowy();
|
await tester.initializeAppFlowy();
|
||||||
await tester.tapGoButton();
|
await tester.tapGoButton();
|
||||||
|
@ -9,21 +9,6 @@ void main() {
|
|||||||
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
|
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
|
||||||
|
|
||||||
group('grid', () {
|
group('grid', () {
|
||||||
const location = 'appflowy';
|
|
||||||
|
|
||||||
setUp(() async {
|
|
||||||
await TestFolder.cleanTestLocation(location);
|
|
||||||
await TestFolder.setTestLocation(location);
|
|
||||||
});
|
|
||||||
|
|
||||||
tearDown(() async {
|
|
||||||
await TestFolder.cleanTestLocation(location);
|
|
||||||
});
|
|
||||||
|
|
||||||
tearDownAll(() async {
|
|
||||||
await TestFolder.cleanTestLocation(null);
|
|
||||||
});
|
|
||||||
|
|
||||||
testWidgets('update layout', (tester) async {
|
testWidgets('update layout', (tester) async {
|
||||||
await tester.initializeAppFlowy();
|
await tester.initializeAppFlowy();
|
||||||
await tester.tapGoButton();
|
await tester.tapGoButton();
|
||||||
|
@ -1,66 +1,15 @@
|
|||||||
import 'dart:io';
|
|
||||||
|
|
||||||
import 'package:appflowy_backend/protobuf/flowy-database2/field_entities.pbenum.dart';
|
import 'package:appflowy_backend/protobuf/flowy-database2/field_entities.pbenum.dart';
|
||||||
import 'package:flutter/services.dart';
|
|
||||||
import 'package:flutter_test/flutter_test.dart';
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
import 'package:integration_test/integration_test.dart';
|
import 'package:integration_test/integration_test.dart';
|
||||||
|
|
||||||
import 'util/database_test_op.dart';
|
import 'util/database_test_op.dart';
|
||||||
import 'util/mock/mock_file_picker.dart';
|
|
||||||
import 'util/util.dart';
|
|
||||||
import 'package:path/path.dart' as p;
|
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
|
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
|
||||||
|
|
||||||
group('database', () {
|
group('database', () {
|
||||||
const location = 'import_files';
|
|
||||||
setUp(() async {
|
|
||||||
await TestFolder.cleanTestLocation(location);
|
|
||||||
await TestFolder.setTestLocation(location);
|
|
||||||
});
|
|
||||||
|
|
||||||
tearDown(() async {
|
|
||||||
await TestFolder.cleanTestLocation(location);
|
|
||||||
});
|
|
||||||
|
|
||||||
tearDownAll(() async {
|
|
||||||
await TestFolder.cleanTestLocation(null);
|
|
||||||
});
|
|
||||||
|
|
||||||
testWidgets('import v0.2.0 database data', (tester) async {
|
testWidgets('import v0.2.0 database data', (tester) async {
|
||||||
await tester.initializeAppFlowy();
|
await tester.openV020database();
|
||||||
await tester.tapGoButton();
|
|
||||||
|
|
||||||
// expect to see a readme page
|
|
||||||
tester.expectToSeePageName(readme);
|
|
||||||
|
|
||||||
await tester.tapAddButton();
|
|
||||||
await tester.tapImportButton();
|
|
||||||
|
|
||||||
final testFileNames = ['v020.afdb'];
|
|
||||||
final fileLocation = await tester.currentFileLocation();
|
|
||||||
for (final fileName in testFileNames) {
|
|
||||||
final str = await rootBundle.loadString(
|
|
||||||
p.join(
|
|
||||||
'assets/test/workspaces/database',
|
|
||||||
fileName,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
File(p.join(fileLocation, fileName)).writeAsStringSync(str);
|
|
||||||
}
|
|
||||||
// mock get files
|
|
||||||
await mockPickFilePaths(testFileNames, name: location);
|
|
||||||
await tester.tapDatabaseRawDataButton();
|
|
||||||
await tester.openPage('v020');
|
|
||||||
|
|
||||||
// check the import content
|
|
||||||
// await tester.assertCellContent(
|
|
||||||
// rowIndex: 7,
|
|
||||||
// fieldType: FieldType.RichText,
|
|
||||||
// // fieldName: 'Name',
|
|
||||||
// content: '',
|
|
||||||
// );
|
|
||||||
|
|
||||||
// check the text cell
|
// check the text cell
|
||||||
final textCells = <String>['A', 'B', 'C', 'D', 'E', '', '', '', '', ''];
|
final textCells = <String>['A', 'B', 'C', 'D', 'E', '', '', '', '', ''];
|
||||||
|
@ -3,27 +3,11 @@ import 'package:flutter_test/flutter_test.dart';
|
|||||||
import 'package:integration_test/integration_test.dart';
|
import 'package:integration_test/integration_test.dart';
|
||||||
|
|
||||||
import 'util/database_test_op.dart';
|
import 'util/database_test_op.dart';
|
||||||
import 'util/util.dart';
|
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
|
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
|
||||||
|
|
||||||
group('grid', () {
|
group('grid', () {
|
||||||
const location = 'import_files';
|
|
||||||
|
|
||||||
setUp(() async {
|
|
||||||
await TestFolder.cleanTestLocation(location);
|
|
||||||
await TestFolder.setTestLocation(location);
|
|
||||||
});
|
|
||||||
|
|
||||||
tearDown(() async {
|
|
||||||
await TestFolder.cleanTestLocation(location);
|
|
||||||
});
|
|
||||||
|
|
||||||
tearDownAll(() async {
|
|
||||||
await TestFolder.cleanTestLocation(null);
|
|
||||||
});
|
|
||||||
|
|
||||||
testWidgets('add text sort', (tester) async {
|
testWidgets('add text sort', (tester) async {
|
||||||
await tester.openV020database();
|
await tester.openV020database();
|
||||||
// create a filter
|
// create a filter
|
||||||
|
@ -11,21 +11,6 @@ void main() {
|
|||||||
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
|
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
|
||||||
|
|
||||||
group('database', () {
|
group('database', () {
|
||||||
const location = 'appflowy';
|
|
||||||
|
|
||||||
setUp(() async {
|
|
||||||
await TestFolder.cleanTestLocation(location);
|
|
||||||
await TestFolder.setTestLocation(location);
|
|
||||||
});
|
|
||||||
|
|
||||||
tearDown(() async {
|
|
||||||
await TestFolder.cleanTestLocation(location);
|
|
||||||
});
|
|
||||||
|
|
||||||
tearDownAll(() async {
|
|
||||||
await TestFolder.cleanTestLocation(null);
|
|
||||||
});
|
|
||||||
|
|
||||||
testWidgets('create linked view', (tester) async {
|
testWidgets('create linked view', (tester) async {
|
||||||
await tester.initializeAppFlowy();
|
await tester.initializeAppFlowy();
|
||||||
await tester.tapGoButton();
|
await tester.tapGoButton();
|
||||||
|
@ -9,21 +9,6 @@ void main() {
|
|||||||
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
|
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
|
||||||
|
|
||||||
group('cover image', () {
|
group('cover image', () {
|
||||||
const location = 'cover_image';
|
|
||||||
|
|
||||||
setUp(() async {
|
|
||||||
await TestFolder.cleanTestLocation(location);
|
|
||||||
await TestFolder.setTestLocation(location);
|
|
||||||
});
|
|
||||||
|
|
||||||
tearDown(() async {
|
|
||||||
await TestFolder.cleanTestLocation(location);
|
|
||||||
});
|
|
||||||
|
|
||||||
tearDownAll(() async {
|
|
||||||
await TestFolder.cleanTestLocation(null);
|
|
||||||
});
|
|
||||||
|
|
||||||
testWidgets('document cover tests', (tester) async {
|
testWidgets('document cover tests', (tester) async {
|
||||||
await tester.initializeAppFlowy();
|
await tester.initializeAppFlowy();
|
||||||
await tester.tapGoButton();
|
await tester.tapGoButton();
|
||||||
|
@ -10,21 +10,6 @@ void main() {
|
|||||||
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
|
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
|
||||||
|
|
||||||
group('document', () {
|
group('document', () {
|
||||||
const location = 'appflowy';
|
|
||||||
|
|
||||||
setUp(() async {
|
|
||||||
await TestFolder.cleanTestLocation(location);
|
|
||||||
await TestFolder.setTestLocation(location);
|
|
||||||
});
|
|
||||||
|
|
||||||
tearDown(() async {
|
|
||||||
await TestFolder.cleanTestLocation(location);
|
|
||||||
});
|
|
||||||
|
|
||||||
tearDownAll(() async {
|
|
||||||
await TestFolder.cleanTestLocation(null);
|
|
||||||
});
|
|
||||||
|
|
||||||
testWidgets('create a new document when launching app in first time',
|
testWidgets('create a new document when launching app in first time',
|
||||||
(tester) async {
|
(tester) async {
|
||||||
await tester.initializeAppFlowy();
|
await tester.initializeAppFlowy();
|
||||||
|
@ -14,17 +14,6 @@ void main() {
|
|||||||
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
|
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
|
||||||
|
|
||||||
group('database view in document', () {
|
group('database view in document', () {
|
||||||
const location = 'database_view';
|
|
||||||
|
|
||||||
setUp(() async {
|
|
||||||
await TestFolder.cleanTestLocation(location);
|
|
||||||
await TestFolder.setTestLocation(location);
|
|
||||||
});
|
|
||||||
|
|
||||||
tearDown(() async {
|
|
||||||
await TestFolder.cleanTestLocation(null);
|
|
||||||
});
|
|
||||||
|
|
||||||
testWidgets('insert a referenced grid', (tester) async {
|
testWidgets('insert a referenced grid', (tester) async {
|
||||||
await tester.initializeAppFlowy();
|
await tester.initializeAppFlowy();
|
||||||
await tester.tapGoButton();
|
await tester.tapGoButton();
|
||||||
|
@ -11,17 +11,6 @@ void main() {
|
|||||||
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
|
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
|
||||||
|
|
||||||
group('inline page view in document', () {
|
group('inline page view in document', () {
|
||||||
const location = 'inline_page';
|
|
||||||
|
|
||||||
setUp(() async {
|
|
||||||
await TestFolder.cleanTestLocation(location);
|
|
||||||
await TestFolder.setTestLocation(location);
|
|
||||||
});
|
|
||||||
|
|
||||||
tearDown(() async {
|
|
||||||
await TestFolder.cleanTestLocation(null);
|
|
||||||
});
|
|
||||||
|
|
||||||
testWidgets('insert a inline page - grid', (tester) async {
|
testWidgets('insert a inline page - grid', (tester) async {
|
||||||
await tester.initializeAppFlowy();
|
await tester.initializeAppFlowy();
|
||||||
await tester.tapGoButton();
|
await tester.tapGoButton();
|
||||||
|
@ -13,17 +13,6 @@ void main() {
|
|||||||
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
|
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
|
||||||
|
|
||||||
group('edit document', () {
|
group('edit document', () {
|
||||||
const location = 'appflowy';
|
|
||||||
|
|
||||||
setUp(() async {
|
|
||||||
await TestFolder.cleanTestLocation(location);
|
|
||||||
await TestFolder.setTestLocation(location);
|
|
||||||
});
|
|
||||||
|
|
||||||
tearDown(() async {
|
|
||||||
await TestFolder.cleanTestLocation(null);
|
|
||||||
});
|
|
||||||
|
|
||||||
testWidgets('redo & undo', (tester) async {
|
testWidgets('redo & undo', (tester) async {
|
||||||
await tester.initializeAppFlowy();
|
await tester.initializeAppFlowy();
|
||||||
await tester.tapGoButton();
|
await tester.tapGoButton();
|
||||||
|
@ -12,23 +12,8 @@ void main() {
|
|||||||
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
|
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
|
||||||
|
|
||||||
group('import files', () {
|
group('import files', () {
|
||||||
const location = 'import_files';
|
|
||||||
|
|
||||||
setUp(() async {
|
|
||||||
await TestFolder.cleanTestLocation(location);
|
|
||||||
await TestFolder.setTestLocation(location);
|
|
||||||
});
|
|
||||||
|
|
||||||
tearDown(() async {
|
|
||||||
await TestFolder.cleanTestLocation(location);
|
|
||||||
});
|
|
||||||
|
|
||||||
tearDownAll(() async {
|
|
||||||
await TestFolder.cleanTestLocation(null);
|
|
||||||
});
|
|
||||||
|
|
||||||
testWidgets('import multiple markdown files', (tester) async {
|
testWidgets('import multiple markdown files', (tester) async {
|
||||||
await tester.initializeAppFlowy();
|
final context = await tester.initializeAppFlowy();
|
||||||
await tester.tapGoButton();
|
await tester.tapGoButton();
|
||||||
|
|
||||||
// expect to see a readme page
|
// expect to see a readme page
|
||||||
@ -38,18 +23,21 @@ void main() {
|
|||||||
await tester.tapImportButton();
|
await tester.tapImportButton();
|
||||||
|
|
||||||
final testFileNames = ['test1.md', 'test2.md'];
|
final testFileNames = ['test1.md', 'test2.md'];
|
||||||
final fileLocation = await tester.currentFileLocation();
|
final paths = <String>[];
|
||||||
for (final fileName in testFileNames) {
|
for (final fileName in testFileNames) {
|
||||||
final str = await rootBundle.loadString(
|
final str = await rootBundle.loadString(
|
||||||
p.join(
|
'assets/test/workspaces/markdowns/$fileName',
|
||||||
'assets/test/workspaces/markdowns',
|
|
||||||
fileName,
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
File(p.join(fileLocation, fileName)).writeAsStringSync(str);
|
final path = p.join(context.applicationDataDirectory, fileName);
|
||||||
|
paths.add(path);
|
||||||
|
File(path).writeAsStringSync(str);
|
||||||
}
|
}
|
||||||
// mock get files
|
// mock get files
|
||||||
await mockPickFilePaths(testFileNames, name: location);
|
await mockPickFilePaths(
|
||||||
|
paths: testFileNames
|
||||||
|
.map((e) => p.join(context.applicationDataDirectory, e))
|
||||||
|
.toList(),
|
||||||
|
);
|
||||||
|
|
||||||
await tester.tapTextAndMarkdownButton();
|
await tester.tapTextAndMarkdownButton();
|
||||||
|
|
||||||
|
@ -8,16 +8,6 @@ void main() {
|
|||||||
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
|
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
|
||||||
|
|
||||||
group('document', () {
|
group('document', () {
|
||||||
const location = 'appflowy';
|
|
||||||
|
|
||||||
setUpAll(() async {
|
|
||||||
await TestFolder.setTestLocation(location);
|
|
||||||
});
|
|
||||||
|
|
||||||
tearDownAll(() async {
|
|
||||||
await TestFolder.cleanTestLocation(null);
|
|
||||||
});
|
|
||||||
|
|
||||||
testWidgets(
|
testWidgets(
|
||||||
'change the language successfully when launching the app for the first time',
|
'change the language successfully when launching the app for the first time',
|
||||||
(tester) async {
|
(tester) async {
|
||||||
|
@ -12,17 +12,6 @@ void main() {
|
|||||||
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
|
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
|
||||||
|
|
||||||
group('outline block test', () {
|
group('outline block test', () {
|
||||||
const location = 'outline_test';
|
|
||||||
|
|
||||||
setUp(() async {
|
|
||||||
await TestFolder.cleanTestLocation(location);
|
|
||||||
await TestFolder.setTestLocation(location);
|
|
||||||
});
|
|
||||||
|
|
||||||
tearDown(() async {
|
|
||||||
await TestFolder.cleanTestLocation(null);
|
|
||||||
});
|
|
||||||
|
|
||||||
testWidgets('insert an outline block', (tester) async {
|
testWidgets('insert an outline block', (tester) async {
|
||||||
await tester.initializeAppFlowy();
|
await tester.initializeAppFlowy();
|
||||||
await tester.tapGoButton();
|
await tester.tapGoButton();
|
||||||
|
@ -3,7 +3,7 @@ import 'dart:io';
|
|||||||
import 'package:appflowy/plugins/document/presentation/share/share_button.dart';
|
import 'package:appflowy/plugins/document/presentation/share/share_button.dart';
|
||||||
import 'package:flutter_test/flutter_test.dart';
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
import 'package:integration_test/integration_test.dart';
|
import 'package:integration_test/integration_test.dart';
|
||||||
|
import 'package:path/path.dart' as p;
|
||||||
import 'util/mock/mock_file_picker.dart';
|
import 'util/mock/mock_file_picker.dart';
|
||||||
import 'util/util.dart';
|
import 'util/util.dart';
|
||||||
|
|
||||||
@ -11,30 +11,17 @@ void main() {
|
|||||||
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
|
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
|
||||||
|
|
||||||
group('share markdown in document page', () {
|
group('share markdown in document page', () {
|
||||||
const location = 'markdown';
|
|
||||||
|
|
||||||
setUp(() async {
|
|
||||||
await TestFolder.cleanTestLocation(location);
|
|
||||||
await TestFolder.setTestLocation(location);
|
|
||||||
});
|
|
||||||
|
|
||||||
tearDown(() async {
|
|
||||||
await TestFolder.cleanTestLocation(location);
|
|
||||||
});
|
|
||||||
|
|
||||||
tearDownAll(() async {
|
|
||||||
await TestFolder.cleanTestLocation(null);
|
|
||||||
});
|
|
||||||
|
|
||||||
testWidgets('click the share button in document page', (tester) async {
|
testWidgets('click the share button in document page', (tester) async {
|
||||||
await tester.initializeAppFlowy();
|
final context = await tester.initializeAppFlowy();
|
||||||
await tester.tapGoButton();
|
await tester.tapGoButton();
|
||||||
|
|
||||||
// expect to see a readme page
|
// expect to see a readme page
|
||||||
tester.expectToSeePageName(readme);
|
tester.expectToSeePageName(readme);
|
||||||
|
|
||||||
// mock the file picker
|
// mock the file picker
|
||||||
final path = await mockSaveFilePath(location, 'test.md');
|
final path = await mockSaveFilePath(
|
||||||
|
p.join(context.applicationDataDirectory, 'test.md'),
|
||||||
|
);
|
||||||
// click the share button and select markdown
|
// click the share button and select markdown
|
||||||
await tester.tapShareButton();
|
await tester.tapShareButton();
|
||||||
await tester.tapMarkdownButton();
|
await tester.tapMarkdownButton();
|
||||||
@ -52,7 +39,7 @@ void main() {
|
|||||||
testWidgets(
|
testWidgets(
|
||||||
'share the markdown after renaming the document name',
|
'share the markdown after renaming the document name',
|
||||||
(tester) async {
|
(tester) async {
|
||||||
await tester.initializeAppFlowy();
|
final context = await tester.initializeAppFlowy();
|
||||||
await tester.tapGoButton();
|
await tester.tapGoButton();
|
||||||
|
|
||||||
// expect to see a readme page
|
// expect to see a readme page
|
||||||
@ -65,8 +52,12 @@ void main() {
|
|||||||
final shareButton = find.byType(ShareActionList);
|
final shareButton = find.byType(ShareActionList);
|
||||||
final shareButtonState =
|
final shareButtonState =
|
||||||
tester.state(shareButton) as ShareActionListState;
|
tester.state(shareButton) as ShareActionListState;
|
||||||
final path =
|
final path = await mockSaveFilePath(
|
||||||
await mockSaveFilePath(location, '${shareButtonState.name}.md');
|
p.join(
|
||||||
|
context.applicationDataDirectory,
|
||||||
|
'${shareButtonState.name}.md',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
// click the share button and select markdown
|
// click the share button and select markdown
|
||||||
await tester.tapShareButton();
|
await tester.tapShareButton();
|
||||||
|
@ -1,48 +1,36 @@
|
|||||||
|
import 'package:appflowy/startup/startup.dart';
|
||||||
|
import 'package:appflowy/startup/tasks/prelude.dart';
|
||||||
import 'package:appflowy/workspace/application/settings/prelude.dart';
|
import 'package:appflowy/workspace/application/settings/prelude.dart';
|
||||||
import 'package:appflowy/workspace/application/settings/settings_location_cubit.dart';
|
|
||||||
import 'package:flowy_infra/uuid.dart';
|
|
||||||
import 'package:flutter_test/flutter_test.dart';
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
import 'package:integration_test/integration_test.dart';
|
import 'package:integration_test/integration_test.dart';
|
||||||
|
import 'package:path/path.dart' as p;
|
||||||
import 'util/mock/mock_file_picker.dart';
|
import 'util/mock/mock_file_picker.dart';
|
||||||
import 'util/util.dart';
|
import 'util/util.dart';
|
||||||
import 'package:path/path.dart' as p;
|
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
|
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
|
||||||
|
|
||||||
group('customize the folder path', () {
|
group('customize the folder path', () {
|
||||||
const location = 'appflowy';
|
|
||||||
|
|
||||||
setUp(() async {
|
|
||||||
await TestFolder.cleanTestLocation(location);
|
|
||||||
await TestFolder.setTestLocation(location);
|
|
||||||
});
|
|
||||||
|
|
||||||
tearDown(() async {
|
|
||||||
await TestFolder.cleanTestLocation(location);
|
|
||||||
});
|
|
||||||
|
|
||||||
tearDownAll(() async {
|
|
||||||
await TestFolder.cleanTestLocation(null);
|
|
||||||
});
|
|
||||||
|
|
||||||
testWidgets('switch to B from A, then switch to A again', (tester) async {
|
testWidgets('switch to B from A, then switch to A again', (tester) async {
|
||||||
final userA = uuid();
|
const userA = 'UserA';
|
||||||
final userB = uuid();
|
const userB = 'UserB';
|
||||||
|
|
||||||
await TestFolder.cleanTestLocation(userA);
|
final initialPath = p.join(userA, appFlowyDataFolder);
|
||||||
await TestFolder.cleanTestLocation(userB);
|
final context = await tester.initializeAppFlowy(
|
||||||
await TestFolder.setTestLocation(p.join(userA, appFlowyDataFolder));
|
pathExtension: initialPath,
|
||||||
|
);
|
||||||
await tester.initializeAppFlowy();
|
// remove the last extension
|
||||||
|
final rootPath = context.applicationDataDirectory.replaceFirst(
|
||||||
|
initialPath,
|
||||||
|
'',
|
||||||
|
);
|
||||||
|
|
||||||
await tester.tapGoButton();
|
await tester.tapGoButton();
|
||||||
tester.expectToSeeHomePage();
|
tester.expectToSeeHomePage();
|
||||||
|
|
||||||
// switch to user B
|
// switch to user B
|
||||||
{
|
{
|
||||||
// set user name to userA
|
// set user name for userA
|
||||||
await tester.openSettings();
|
await tester.openSettings();
|
||||||
await tester.openSettingsPage(SettingsPage.user);
|
await tester.openSettingsPage(SettingsPage.user);
|
||||||
await tester.enterUserName(userA);
|
await tester.enterUserName(userA);
|
||||||
@ -51,12 +39,14 @@ void main() {
|
|||||||
await tester.pumpAndSettle();
|
await tester.pumpAndSettle();
|
||||||
|
|
||||||
// mock the file_picker result
|
// mock the file_picker result
|
||||||
await mockGetDirectoryPath(userB);
|
await mockGetDirectoryPath(
|
||||||
|
p.join(rootPath, userB),
|
||||||
|
);
|
||||||
await tester.tapCustomLocationButton();
|
await tester.tapCustomLocationButton();
|
||||||
await tester.pumpAndSettle();
|
await tester.pumpAndSettle();
|
||||||
tester.expectToSeeHomePage();
|
tester.expectToSeeHomePage();
|
||||||
|
|
||||||
// set user name to userB
|
// set user name for userB
|
||||||
await tester.openSettings();
|
await tester.openSettings();
|
||||||
await tester.openSettingsPage(SettingsPage.user);
|
await tester.openSettingsPage(SettingsPage.user);
|
||||||
await tester.enterUserName(userB);
|
await tester.enterUserName(userB);
|
||||||
@ -68,7 +58,9 @@ void main() {
|
|||||||
await tester.pumpAndSettle();
|
await tester.pumpAndSettle();
|
||||||
|
|
||||||
// mock the file_picker result
|
// mock the file_picker result
|
||||||
await mockGetDirectoryPath(userA);
|
await mockGetDirectoryPath(
|
||||||
|
p.join(rootPath, userA),
|
||||||
|
);
|
||||||
await tester.tapCustomLocationButton();
|
await tester.tapCustomLocationButton();
|
||||||
|
|
||||||
await tester.pumpAndSettle();
|
await tester.pumpAndSettle();
|
||||||
@ -83,16 +75,15 @@ void main() {
|
|||||||
await tester.pumpAndSettle();
|
await tester.pumpAndSettle();
|
||||||
|
|
||||||
// mock the file_picker result
|
// mock the file_picker result
|
||||||
await mockGetDirectoryPath(userB);
|
await mockGetDirectoryPath(
|
||||||
|
p.join(rootPath, userB),
|
||||||
|
);
|
||||||
await tester.tapCustomLocationButton();
|
await tester.tapCustomLocationButton();
|
||||||
|
|
||||||
await tester.pumpAndSettle();
|
await tester.pumpAndSettle();
|
||||||
tester.expectToSeeHomePage();
|
tester.expectToSeeHomePage();
|
||||||
tester.expectToSeeUserName(userB);
|
tester.expectToSeeUserName(userB);
|
||||||
}
|
}
|
||||||
|
|
||||||
await TestFolder.cleanTestLocation(userA);
|
|
||||||
await TestFolder.cleanTestLocation(userB);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('reset to default location', (tester) async {
|
testWidgets('reset to default location', (tester) async {
|
||||||
@ -109,8 +100,8 @@ void main() {
|
|||||||
await tester.restoreLocation();
|
await tester.restoreLocation();
|
||||||
|
|
||||||
expect(
|
expect(
|
||||||
await TestFolder.defaultDevelopmentLocation(),
|
await appFlowyApplicationDataDirectory().then((value) => value.path),
|
||||||
await TestFolder.currentLocation(),
|
await getIt<ApplicationDataStorage>().getPath(),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -1,81 +1,77 @@
|
|||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:appflowy/core/config/kv_keys.dart';
|
|
||||||
import 'package:appflowy/startup/entry_point.dart';
|
import 'package:appflowy/startup/entry_point.dart';
|
||||||
import 'package:appflowy/startup/startup.dart';
|
import 'package:appflowy/startup/startup.dart';
|
||||||
import 'package:appflowy/startup/tasks/prelude.dart';
|
import 'package:appflowy/workspace/application/settings/prelude.dart';
|
||||||
|
import 'package:flowy_infra/uuid.dart';
|
||||||
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
|
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
|
||||||
import 'package:flutter/gestures.dart';
|
import 'package:flutter/gestures.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'package:flutter_test/flutter_test.dart';
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
import 'package:path_provider/path_provider.dart';
|
import 'package:path_provider/path_provider.dart';
|
||||||
import 'package:shared_preferences/shared_preferences.dart';
|
|
||||||
|
|
||||||
class TestFolder {
|
class FlowyTestContext {
|
||||||
/// Location / Path
|
FlowyTestContext({
|
||||||
|
required this.applicationDataDirectory,
|
||||||
|
});
|
||||||
|
|
||||||
/// Set a given AppFlowy data storage location under test environment.
|
final String applicationDataDirectory;
|
||||||
///
|
|
||||||
/// To pass null means clear the location.
|
|
||||||
///
|
|
||||||
/// The file_picker is a system component and can't be tapped, so using logic instead of tapping.
|
|
||||||
///
|
|
||||||
static Future<void> setTestLocation(String? name) async {
|
|
||||||
final location = await testLocation(name);
|
|
||||||
SharedPreferences.setMockInitialValues({
|
|
||||||
KVKeys.pathLocation: location.path,
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Clean the location.
|
|
||||||
static Future<void> cleanTestLocation(String? name) async {
|
|
||||||
final dir = await testLocation(name);
|
|
||||||
await dir.delete(recursive: true);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get current using location.
|
|
||||||
static Future<String> currentLocation() async {
|
|
||||||
final prefs = await SharedPreferences.getInstance();
|
|
||||||
return prefs.getString(KVKeys.pathLocation)!;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get default location under development environment.
|
|
||||||
static Future<String> defaultDevelopmentLocation() async {
|
|
||||||
final dir = await appFlowyApplicationDataDirectory();
|
|
||||||
return dir.path;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get default location under test environment.
|
|
||||||
static Future<Directory> testLocation(String? name) async {
|
|
||||||
final dir = await getApplicationDocumentsDirectory();
|
|
||||||
var path = '${dir.path}/flowy_test';
|
|
||||||
if (name != null) {
|
|
||||||
path += '/$name';
|
|
||||||
}
|
|
||||||
return Directory(path).create(recursive: true);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extension AppFlowyTestBase on WidgetTester {
|
extension AppFlowyTestBase on WidgetTester {
|
||||||
Future<void> initializeAppFlowy() async {
|
Future<FlowyTestContext> initializeAppFlowy({
|
||||||
|
// use to append after the application data directory
|
||||||
|
String? pathExtension,
|
||||||
|
}) async {
|
||||||
|
mockHotKeyManagerHandlers();
|
||||||
|
final directory = await mockApplicationDataStorage(
|
||||||
|
pathExtension: pathExtension,
|
||||||
|
);
|
||||||
|
|
||||||
|
WidgetsFlutterBinding.ensureInitialized();
|
||||||
|
await FlowyRunner.run(
|
||||||
|
FlowyApp(),
|
||||||
|
IntegrationMode.integrationTest,
|
||||||
|
);
|
||||||
|
|
||||||
|
await wait(3000);
|
||||||
|
await pumpAndSettle(const Duration(seconds: 2));
|
||||||
|
return FlowyTestContext(
|
||||||
|
applicationDataDirectory: directory,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void mockHotKeyManagerHandlers() {
|
||||||
TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger
|
TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger
|
||||||
.setMockMethodCallHandler(const MethodChannel('hotkey_manager'),
|
.setMockMethodCallHandler(const MethodChannel('hotkey_manager'),
|
||||||
(MethodCall methodCall) async {
|
(MethodCall methodCall) async {
|
||||||
if (methodCall.method == 'unregisterAll') {
|
if (methodCall.method == 'unregisterAll') {
|
||||||
// do nothing
|
// do nothing
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
WidgetsFlutterBinding.ensureInitialized();
|
Future<String> mockApplicationDataStorage({
|
||||||
await FlowyRunner.run(FlowyApp(), IntegrationMode.integrationTest);
|
// use to append after the application data directory
|
||||||
|
String? pathExtension,
|
||||||
|
}) async {
|
||||||
|
final dir = await getTemporaryDirectory();
|
||||||
|
|
||||||
await wait(3000);
|
// Use a random uuid to avoid conflict.
|
||||||
await pumpAndSettle(const Duration(seconds: 2));
|
String path = '${dir.path}/appflowy_integration_test/${uuid()}';
|
||||||
|
if (pathExtension != null && pathExtension.isNotEmpty) {
|
||||||
|
path = '$path/$pathExtension';
|
||||||
|
}
|
||||||
|
final directory = Directory(path);
|
||||||
|
if (!directory.existsSync()) {
|
||||||
|
await directory.create(recursive: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
MockApplicationDataStorage.initialPath = directory.path;
|
||||||
|
|
||||||
|
return directory.path;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> tapButton(
|
Future<void> tapButton(
|
||||||
|
@ -17,11 +17,6 @@ import 'package:flutter_test/flutter_test.dart';
|
|||||||
import 'util.dart';
|
import 'util.dart';
|
||||||
|
|
||||||
extension CommonOperations on WidgetTester {
|
extension CommonOperations on WidgetTester {
|
||||||
/// Get current file location of AppFlowy.
|
|
||||||
Future<String> currentFileLocation() async {
|
|
||||||
return TestFolder.currentLocation();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Tap the GetStart button on the launch page.
|
/// Tap the GetStart button on the launch page.
|
||||||
Future<void> tapGoButton() async {
|
Future<void> tapGoButton() async {
|
||||||
final goButton = find.byType(GoButton);
|
final goButton = find.byType(GoButton);
|
||||||
|
@ -73,7 +73,7 @@ import 'mock/mock_file_picker.dart';
|
|||||||
|
|
||||||
extension AppFlowyDatabaseTest on WidgetTester {
|
extension AppFlowyDatabaseTest on WidgetTester {
|
||||||
Future<void> openV020database() async {
|
Future<void> openV020database() async {
|
||||||
await initializeAppFlowy();
|
final context = await initializeAppFlowy();
|
||||||
await tapGoButton();
|
await tapGoButton();
|
||||||
|
|
||||||
// expect to see a readme page
|
// expect to see a readme page
|
||||||
@ -83,18 +83,25 @@ extension AppFlowyDatabaseTest on WidgetTester {
|
|||||||
await tapImportButton();
|
await tapImportButton();
|
||||||
|
|
||||||
final testFileNames = ['v020.afdb'];
|
final testFileNames = ['v020.afdb'];
|
||||||
final fileLocation = await currentFileLocation();
|
final paths = <String>[];
|
||||||
for (final fileName in testFileNames) {
|
for (final fileName in testFileNames) {
|
||||||
final str = await rootBundle.loadString(
|
// Don't use the p.join to build the path that used in loadString. It
|
||||||
p.join(
|
// is not working on windows.
|
||||||
'assets/test/workspaces/database',
|
final str = await rootBundle
|
||||||
fileName,
|
.loadString("assets/test/workspaces/database/$fileName");
|
||||||
),
|
|
||||||
|
// Write the content to the file.
|
||||||
|
final path = p.join(
|
||||||
|
context.applicationDataDirectory,
|
||||||
|
fileName,
|
||||||
);
|
);
|
||||||
File(p.join(fileLocation, fileName)).writeAsStringSync(str);
|
paths.add(path);
|
||||||
|
File(path).writeAsStringSync(str);
|
||||||
}
|
}
|
||||||
// mock get files
|
// mock get files
|
||||||
await mockPickFilePaths(testFileNames, name: 'import_files');
|
await mockPickFilePaths(
|
||||||
|
paths: paths,
|
||||||
|
);
|
||||||
await tapDatabaseRawDataButton();
|
await tapDatabaseRawDataButton();
|
||||||
await openPage('v020');
|
await openPage('v020');
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,6 @@
|
|||||||
import 'dart:io';
|
|
||||||
|
|
||||||
import 'package:appflowy/startup/startup.dart';
|
import 'package:appflowy/startup/startup.dart';
|
||||||
import 'package:appflowy/util/file_picker/file_picker_service.dart';
|
import 'package:appflowy/util/file_picker/file_picker_service.dart';
|
||||||
import 'package:file_picker/file_picker.dart' as fp;
|
import 'package:file_picker/file_picker.dart' as fp;
|
||||||
import 'package:path/path.dart' as p;
|
|
||||||
import '../util.dart';
|
|
||||||
|
|
||||||
class MockFilePicker implements FilePickerService {
|
class MockFilePicker implements FilePickerService {
|
||||||
MockFilePicker({
|
MockFilePicker({
|
||||||
@ -56,20 +52,21 @@ class MockFilePicker implements FilePickerService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> mockGetDirectoryPath(String? name) async {
|
Future<void> mockGetDirectoryPath(
|
||||||
final dir = await TestFolder.testLocation(name);
|
String path,
|
||||||
|
) async {
|
||||||
getIt.unregister<FilePickerService>();
|
getIt.unregister<FilePickerService>();
|
||||||
getIt.registerFactory<FilePickerService>(
|
getIt.registerFactory<FilePickerService>(
|
||||||
() => MockFilePicker(
|
() => MockFilePicker(
|
||||||
mockPath: dir.path,
|
mockPath: path,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<String> mockSaveFilePath(String? name, String fileName) async {
|
Future<String> mockSaveFilePath(
|
||||||
final dir = await TestFolder.testLocation(name);
|
String path,
|
||||||
final path = p.join(dir.path, fileName);
|
) async {
|
||||||
getIt.unregister<FilePickerService>();
|
getIt.unregister<FilePickerService>();
|
||||||
getIt.registerFactory<FilePickerService>(
|
getIt.registerFactory<FilePickerService>(
|
||||||
() => MockFilePicker(
|
() => MockFilePicker(
|
||||||
@ -79,18 +76,16 @@ Future<String> mockSaveFilePath(String? name, String fileName) async {
|
|||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<List<String>> mockPickFilePaths(
|
Future<List<String>> mockPickFilePaths({
|
||||||
List<String> fileNames, {
|
required List<String> paths,
|
||||||
String? name,
|
|
||||||
String? customPath,
|
|
||||||
}) async {
|
}) async {
|
||||||
late final Directory dir;
|
// late final Directory dir;
|
||||||
if (customPath != null) {
|
// if (customPath != null) {
|
||||||
dir = Directory(customPath);
|
// dir = Directory(customPath);
|
||||||
} else {
|
// } else {
|
||||||
dir = await TestFolder.testLocation(name);
|
// dir = await TestFolder.testLocation(applicationDataPath, name);
|
||||||
}
|
// }
|
||||||
final paths = fileNames.map((e) => p.join(dir.path, e)).toList();
|
// final paths = fileNames.map((e) => p.join(dir.path, e)).toList();
|
||||||
getIt.unregister<FilePickerService>();
|
getIt.unregister<FilePickerService>();
|
||||||
getIt.registerFactory<FilePickerService>(
|
getIt.registerFactory<FilePickerService>(
|
||||||
() => MockFilePicker(
|
() => MockFilePicker(
|
||||||
|
@ -2,7 +2,7 @@ import 'dart:io';
|
|||||||
import 'package:appflowy/generated/locale_keys.g.dart';
|
import 'package:appflowy/generated/locale_keys.g.dart';
|
||||||
import 'package:appflowy/startup/startup.dart';
|
import 'package:appflowy/startup/startup.dart';
|
||||||
import 'package:appflowy/util/file_picker/file_picker_service.dart';
|
import 'package:appflowy/util/file_picker/file_picker_service.dart';
|
||||||
import 'package:appflowy/workspace/application/settings/settings_location_cubit.dart';
|
import 'package:appflowy/workspace/application/settings/prelude.dart';
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
import 'package:file_picker/file_picker.dart' as fp;
|
import 'package:file_picker/file_picker.dart' as fp;
|
||||||
|
|
||||||
|
@ -6,6 +6,7 @@ import 'package:appflowy/plugins/database_view/application/field/field_service.d
|
|||||||
import 'package:appflowy/plugins/database_view/application/setting/property_bloc.dart';
|
import 'package:appflowy/plugins/database_view/application/setting/property_bloc.dart';
|
||||||
import 'package:appflowy/plugins/database_view/grid/application/grid_header_bloc.dart';
|
import 'package:appflowy/plugins/database_view/grid/application/grid_header_bloc.dart';
|
||||||
import 'package:appflowy/plugins/document/presentation/editor_plugins/openai/service/openai_client.dart';
|
import 'package:appflowy/plugins/document/presentation/editor_plugins/openai/service/openai_client.dart';
|
||||||
|
import 'package:appflowy/startup/startup.dart';
|
||||||
import 'package:appflowy/user/application/auth/auth_service.dart';
|
import 'package:appflowy/user/application/auth/auth_service.dart';
|
||||||
import 'package:appflowy/user/application/auth/supabase_auth_service.dart';
|
import 'package:appflowy/user/application/auth/supabase_auth_service.dart';
|
||||||
import 'package:appflowy/user/application/user_listener.dart';
|
import 'package:appflowy/user/application/user_listener.dart';
|
||||||
@ -13,7 +14,6 @@ import 'package:appflowy/user/application/user_service.dart';
|
|||||||
import 'package:appflowy/util/file_picker/file_picker_impl.dart';
|
import 'package:appflowy/util/file_picker/file_picker_impl.dart';
|
||||||
import 'package:appflowy/util/file_picker/file_picker_service.dart';
|
import 'package:appflowy/util/file_picker/file_picker_service.dart';
|
||||||
import 'package:appflowy/plugins/document/application/prelude.dart';
|
import 'package:appflowy/plugins/document/application/prelude.dart';
|
||||||
import 'package:appflowy/workspace/application/settings/settings_location_cubit.dart';
|
|
||||||
import 'package:appflowy/workspace/application/user/prelude.dart';
|
import 'package:appflowy/workspace/application/user/prelude.dart';
|
||||||
import 'package:appflowy/workspace/application/workspace/prelude.dart';
|
import 'package:appflowy/workspace/application/workspace/prelude.dart';
|
||||||
import 'package:appflowy/workspace/application/edit_panel/edit_panel_bloc.dart';
|
import 'package:appflowy/workspace/application/edit_panel/edit_panel_bloc.dart';
|
||||||
@ -32,26 +32,35 @@ import 'package:get_it/get_it.dart';
|
|||||||
import 'package:http/http.dart' as http;
|
import 'package:http/http.dart' as http;
|
||||||
|
|
||||||
class DependencyResolver {
|
class DependencyResolver {
|
||||||
static Future<void> resolve(GetIt getIt) async {
|
static Future<void> resolve(
|
||||||
|
GetIt getIt,
|
||||||
|
IntegrationMode mode,
|
||||||
|
) async {
|
||||||
_resolveUserDeps(getIt);
|
_resolveUserDeps(getIt);
|
||||||
|
|
||||||
_resolveHomeDeps(getIt);
|
_resolveHomeDeps(getIt);
|
||||||
|
|
||||||
_resolveFolderDeps(getIt);
|
_resolveFolderDeps(getIt);
|
||||||
|
|
||||||
_resolveDocDeps(getIt);
|
_resolveDocDeps(getIt);
|
||||||
|
|
||||||
_resolveGridDeps(getIt);
|
_resolveGridDeps(getIt);
|
||||||
|
_resolveCommonService(getIt, mode);
|
||||||
_resolveCommonService(getIt);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void _resolveCommonService(GetIt getIt) async {
|
void _resolveCommonService(
|
||||||
|
GetIt getIt,
|
||||||
|
IntegrationMode mode,
|
||||||
|
) async {
|
||||||
// getIt.registerFactory<KeyValueStorage>(() => RustKeyValue());
|
// getIt.registerFactory<KeyValueStorage>(() => RustKeyValue());
|
||||||
getIt.registerFactory<KeyValueStorage>(() => DartKeyValue());
|
getIt.registerFactory<KeyValueStorage>(() => DartKeyValue());
|
||||||
getIt.registerFactory<FilePickerService>(() => FilePicker());
|
getIt.registerFactory<FilePickerService>(() => FilePicker());
|
||||||
getIt.registerFactory<ApplicationDataStorage>(() => ApplicationDataStorage());
|
if (mode.isTest) {
|
||||||
|
getIt.registerFactory<ApplicationDataStorage>(
|
||||||
|
() => MockApplicationDataStorage(),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
getIt.registerFactory<ApplicationDataStorage>(
|
||||||
|
() => ApplicationDataStorage(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
getIt.registerFactoryAsync<OpenAIRepository>(
|
getIt.registerFactoryAsync<OpenAIRepository>(
|
||||||
() async {
|
() async {
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:appflowy/env/env.dart';
|
import 'package:appflowy/env/env.dart';
|
||||||
import 'package:appflowy/workspace/application/settings/settings_location_cubit.dart';
|
import 'package:appflowy/workspace/application/settings/prelude.dart';
|
||||||
import 'package:appflowy_backend/appflowy_backend.dart';
|
import 'package:appflowy_backend/appflowy_backend.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
@ -18,8 +18,14 @@ abstract class EntryPoint {
|
|||||||
Widget create(LaunchConfiguration config);
|
Widget create(LaunchConfiguration config);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class FlowyRunnerContext {
|
||||||
|
final Directory applicationDataDirectory;
|
||||||
|
|
||||||
|
FlowyRunnerContext({required this.applicationDataDirectory});
|
||||||
|
}
|
||||||
|
|
||||||
class FlowyRunner {
|
class FlowyRunner {
|
||||||
static Future<void> run(
|
static Future<FlowyRunnerContext> run(
|
||||||
EntryPoint f,
|
EntryPoint f,
|
||||||
IntegrationMode mode, {
|
IntegrationMode mode, {
|
||||||
LaunchConfiguration config = const LaunchConfiguration(
|
LaunchConfiguration config = const LaunchConfiguration(
|
||||||
@ -32,11 +38,10 @@ class FlowyRunner {
|
|||||||
// Specify the env
|
// Specify the env
|
||||||
initGetIt(getIt, mode, f, config);
|
initGetIt(getIt, mode, f, config);
|
||||||
|
|
||||||
final directory = await getIt<ApplicationDataStorage>()
|
final applicationDataDirectory =
|
||||||
.getPath()
|
await getIt<ApplicationDataStorage>().getPath().then(
|
||||||
.then((value) => Directory(value));
|
(value) => Directory(value),
|
||||||
|
);
|
||||||
// final directory = await appFlowyDocumentDirectory();
|
|
||||||
|
|
||||||
// add task
|
// add task
|
||||||
final launcher = getIt<AppLauncher>();
|
final launcher = getIt<AppLauncher>();
|
||||||
@ -49,13 +54,13 @@ class FlowyRunner {
|
|||||||
// init the app window
|
// init the app window
|
||||||
const InitAppWindowTask(),
|
const InitAppWindowTask(),
|
||||||
// Init Rust SDK
|
// Init Rust SDK
|
||||||
InitRustSDKTask(directory: directory),
|
InitRustSDKTask(directory: applicationDataDirectory),
|
||||||
// Load Plugins, like document, grid ...
|
// Load Plugins, like document, grid ...
|
||||||
const PluginLoadTask(),
|
const PluginLoadTask(),
|
||||||
|
|
||||||
// init the app widget
|
// init the app widget
|
||||||
// ignore in test mode
|
// ignore in test mode
|
||||||
if (!mode.isTest()) ...[
|
if (!mode.isUnitTest) ...[
|
||||||
const HotKeyTask(),
|
const HotKeyTask(),
|
||||||
InitSupabaseTask(
|
InitSupabaseTask(
|
||||||
url: Env.supabaseUrl,
|
url: Env.supabaseUrl,
|
||||||
@ -70,6 +75,10 @@ class FlowyRunner {
|
|||||||
],
|
],
|
||||||
);
|
);
|
||||||
await launcher.launch(); // execute the tasks
|
await launcher.launch(); // execute the tasks
|
||||||
|
|
||||||
|
return FlowyRunnerContext(
|
||||||
|
applicationDataDirectory: applicationDataDirectory,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -94,7 +103,7 @@ Future<void> initGetIt(
|
|||||||
);
|
);
|
||||||
getIt.registerSingleton<PluginSandbox>(PluginSandbox());
|
getIt.registerSingleton<PluginSandbox>(PluginSandbox());
|
||||||
|
|
||||||
await DependencyResolver.resolve(getIt);
|
await DependencyResolver.resolve(getIt, env);
|
||||||
}
|
}
|
||||||
|
|
||||||
class LaunchContext {
|
class LaunchContext {
|
||||||
@ -145,23 +154,24 @@ class AppLauncher {
|
|||||||
enum IntegrationMode {
|
enum IntegrationMode {
|
||||||
develop,
|
develop,
|
||||||
release,
|
release,
|
||||||
test,
|
unitTest,
|
||||||
integrationTest,
|
integrationTest;
|
||||||
}
|
|
||||||
|
|
||||||
extension IntegrationEnvExt on IntegrationMode {
|
// test mode
|
||||||
bool isTest() {
|
bool get isTest => isUnitTest || isIntegrationTest;
|
||||||
return this == IntegrationMode.test;
|
bool get isUnitTest => this == IntegrationMode.unitTest;
|
||||||
}
|
bool get isIntegrationTest => this == IntegrationMode.integrationTest;
|
||||||
|
|
||||||
bool isIntegrationTest() {
|
// release mode
|
||||||
return this == IntegrationMode.integrationTest;
|
bool get isRelease => this == IntegrationMode.release;
|
||||||
}
|
|
||||||
|
// develop mode
|
||||||
|
bool get isDevelop => this == IntegrationMode.develop;
|
||||||
}
|
}
|
||||||
|
|
||||||
IntegrationMode integrationEnv() {
|
IntegrationMode integrationEnv() {
|
||||||
if (Platform.environment.containsKey('FLUTTER_TEST')) {
|
if (Platform.environment.containsKey('FLUTTER_TEST')) {
|
||||||
return IntegrationMode.test;
|
return IntegrationMode.unitTest;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (kReleaseMode) {
|
if (kReleaseMode) {
|
||||||
|
@ -8,5 +8,6 @@ class InitLocalizationTask extends LaunchTask {
|
|||||||
@override
|
@override
|
||||||
Future<void> initialize(LaunchContext context) async {
|
Future<void> initialize(LaunchContext context) async {
|
||||||
await EasyLocalization.ensureInitialized();
|
await EasyLocalization.ensureInitialized();
|
||||||
|
EasyLocalization.logger.enableBuildModes = [];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -38,7 +38,7 @@ AppFlowyEnv getAppFlowyEnv() {
|
|||||||
final collabTableConfig =
|
final collabTableConfig =
|
||||||
CollabTableConfig(enable: true, table_name: Env.supabaseCollabTable);
|
CollabTableConfig(enable: true, table_name: Env.supabaseCollabTable);
|
||||||
|
|
||||||
final supbaseDBConfig = SupabaseDBConfig(
|
final supabaseDBConfig = SupabaseDBConfig(
|
||||||
url: Env.supabaseUrl,
|
url: Env.supabaseUrl,
|
||||||
key: Env.supabaseKey,
|
key: Env.supabaseKey,
|
||||||
jwt_secret: Env.supabaseJwtSecret,
|
jwt_secret: Env.supabaseJwtSecret,
|
||||||
@ -47,7 +47,7 @@ AppFlowyEnv getAppFlowyEnv() {
|
|||||||
|
|
||||||
return AppFlowyEnv(
|
return AppFlowyEnv(
|
||||||
supabase_config: supabaseConfig,
|
supabase_config: supabaseConfig,
|
||||||
supabase_db_config: supbaseDBConfig,
|
supabase_db_config: supabaseDBConfig,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -62,7 +62,7 @@ Future<Directory> appFlowyApplicationDataDirectory() async {
|
|||||||
case IntegrationMode.release:
|
case IntegrationMode.release:
|
||||||
final Directory documentsDir = await getApplicationSupportDirectory();
|
final Directory documentsDir = await getApplicationSupportDirectory();
|
||||||
return Directory(path.join(documentsDir.path, 'data')).create();
|
return Directory(path.join(documentsDir.path, 'data')).create();
|
||||||
case IntegrationMode.test:
|
case IntegrationMode.unitTest:
|
||||||
case IntegrationMode.integrationTest:
|
case IntegrationMode.integrationTest:
|
||||||
return Directory(path.join(Directory.current.path, '.sandbox'));
|
return Directory(path.join(Directory.current.path, '.sandbox'));
|
||||||
}
|
}
|
||||||
|
@ -27,7 +27,7 @@ class InitAppWindowTask extends LaunchTask with WindowListener {
|
|||||||
windowManager.addListener(this);
|
windowManager.addListener(this);
|
||||||
|
|
||||||
Size windowSize = await WindowSizeManager().getSize();
|
Size windowSize = await WindowSizeManager().getSize();
|
||||||
if (context.env.isIntegrationTest()) {
|
if (context.env.isIntegrationTest) {
|
||||||
windowSize = const Size(1600, 1200);
|
windowSize = const Size(1600, 1200);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:appflowy/util/file_picker/file_picker_service.dart';
|
import 'package:appflowy/util/file_picker/file_picker_service.dart';
|
||||||
|
import 'package:appflowy/workspace/application/settings/prelude.dart';
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
import 'package:flowy_infra/image.dart';
|
import 'package:flowy_infra/image.dart';
|
||||||
import 'package:flowy_infra/size.dart';
|
import 'package:flowy_infra/size.dart';
|
||||||
@ -12,7 +13,6 @@ import 'package:google_fonts/google_fonts.dart';
|
|||||||
|
|
||||||
import '../../../generated/locale_keys.g.dart';
|
import '../../../generated/locale_keys.g.dart';
|
||||||
import '../../../startup/startup.dart';
|
import '../../../startup/startup.dart';
|
||||||
import '../../../workspace/application/settings/settings_location_cubit.dart';
|
|
||||||
import '../../../workspace/presentation/home/toast.dart';
|
import '../../../workspace/presentation/home/toast.dart';
|
||||||
|
|
||||||
enum _FolderPage {
|
enum _FolderPage {
|
||||||
|
@ -53,7 +53,7 @@ class AppearanceSettingsCubit extends Cubit<AppearanceSettingsState> {
|
|||||||
/// changed. Fallback to [en] locale if [newLocale] is not supported.
|
/// changed. Fallback to [en] locale if [newLocale] is not supported.
|
||||||
void setLocale(BuildContext context, Locale newLocale) {
|
void setLocale(BuildContext context, Locale newLocale) {
|
||||||
if (!context.supportedLocales.contains(newLocale)) {
|
if (!context.supportedLocales.contains(newLocale)) {
|
||||||
Log.warn("Unsupported locale: $newLocale, Fallback to locale: en");
|
// Log.warn("Unsupported locale: $newLocale, Fallback to locale: en");
|
||||||
newLocale = const Locale('en');
|
newLocale = const Locale('en');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,105 @@
|
|||||||
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:appflowy/core/config/kv.dart';
|
||||||
|
import 'package:appflowy/core/config/kv_keys.dart';
|
||||||
|
import 'package:appflowy/startup/startup.dart';
|
||||||
|
import 'package:appflowy_backend/log.dart';
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
|
import 'package:path/path.dart' as p;
|
||||||
|
|
||||||
|
import '../../../startup/tasks/prelude.dart';
|
||||||
|
|
||||||
|
const appFlowyDataFolder = "AppFlowyDataDoNotRename";
|
||||||
|
|
||||||
|
class ApplicationDataStorage {
|
||||||
|
ApplicationDataStorage();
|
||||||
|
String? _cachePath;
|
||||||
|
|
||||||
|
/// Set the custom path to store the data.
|
||||||
|
/// If the path is not exists, the path will be created.
|
||||||
|
/// If the path is invalid, the path will be set to the default path.
|
||||||
|
Future<void> setCustomPath(String path) async {
|
||||||
|
if (kIsWeb || Platform.isAndroid || Platform.isIOS) {
|
||||||
|
Log.info('LocalFileStorage is not supported on this platform.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Platform.isMacOS) {
|
||||||
|
// remove the prefix `/Volumes/*`
|
||||||
|
path = path.replaceFirst(RegExp(r'^/Volumes/[^/]+'), '');
|
||||||
|
} else if (Platform.isWindows) {
|
||||||
|
path = path.replaceAll('/', '\\');
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the path is not ends with `AppFlowyData`, we will append the
|
||||||
|
// `AppFlowyData` to the path. If the path is ends with `AppFlowyData`,
|
||||||
|
// which means the path is the custom path.
|
||||||
|
if (p.basename(path) != appFlowyDataFolder) {
|
||||||
|
path = p.join(path, appFlowyDataFolder);
|
||||||
|
}
|
||||||
|
|
||||||
|
// create the directory if not exists.
|
||||||
|
final directory = Directory(path);
|
||||||
|
if (!directory.existsSync()) {
|
||||||
|
await directory.create(recursive: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
setPath(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> setPath(String path) async {
|
||||||
|
if (kIsWeb || Platform.isAndroid || Platform.isIOS) {
|
||||||
|
Log.info('LocalFileStorage is not supported on this platform.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await getIt<KeyValueStorage>().set(KVKeys.pathLocation, path);
|
||||||
|
// clear the cache path, and not set the cache path to the new path because the set path may be invalid
|
||||||
|
_cachePath = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<String> getPath() async {
|
||||||
|
if (_cachePath != null) {
|
||||||
|
return _cachePath!;
|
||||||
|
}
|
||||||
|
|
||||||
|
final response = await getIt<KeyValueStorage>().get(KVKeys.pathLocation);
|
||||||
|
String path = await response.fold(
|
||||||
|
(error) async {
|
||||||
|
// return the default path if the path is not set
|
||||||
|
final directory = await appFlowyApplicationDataDirectory();
|
||||||
|
return directory.path;
|
||||||
|
},
|
||||||
|
(path) => path,
|
||||||
|
);
|
||||||
|
_cachePath = path;
|
||||||
|
|
||||||
|
// if the path is not exists means the path is invalid, so we should clear the kv store
|
||||||
|
if (!Directory(path).existsSync()) {
|
||||||
|
await getIt<KeyValueStorage>().clear();
|
||||||
|
final directory = await appFlowyApplicationDataDirectory();
|
||||||
|
path = directory.path;
|
||||||
|
}
|
||||||
|
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class MockApplicationDataStorage extends ApplicationDataStorage {
|
||||||
|
MockApplicationDataStorage();
|
||||||
|
|
||||||
|
// this value will be clear after setup
|
||||||
|
// only for the initial step
|
||||||
|
@visibleForTesting
|
||||||
|
static String? initialPath;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<String> getPath() async {
|
||||||
|
final path = initialPath;
|
||||||
|
if (path != null) {
|
||||||
|
initialPath = null;
|
||||||
|
return Future.value(path);
|
||||||
|
}
|
||||||
|
return super.getPath();
|
||||||
|
}
|
||||||
|
}
|
@ -1 +1,2 @@
|
|||||||
export 'settings_dialog_bloc.dart';
|
export 'settings_dialog_bloc.dart';
|
||||||
|
export 'application_data_storage.dart';
|
||||||
|
@ -1,13 +1,8 @@
|
|||||||
import 'dart:io';
|
|
||||||
|
|
||||||
import 'package:appflowy/core/config/kv.dart';
|
|
||||||
import 'package:appflowy/core/config/kv_keys.dart';
|
|
||||||
import 'package:appflowy/startup/startup.dart';
|
import 'package:appflowy/startup/startup.dart';
|
||||||
import 'package:appflowy_backend/log.dart';
|
import 'package:appflowy/workspace/application/settings/application_data_storage.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||||
import 'package:path/path.dart' as p;
|
|
||||||
|
|
||||||
import '../../../startup/tasks/prelude.dart';
|
import '../../../startup/tasks/prelude.dart';
|
||||||
|
|
||||||
@ -27,7 +22,7 @@ class SettingsLocationCubit extends Cubit<SettingsLocationState> {
|
|||||||
|
|
||||||
Future<void> resetDataStoragePathToApplicationDefault() async {
|
Future<void> resetDataStoragePathToApplicationDefault() async {
|
||||||
final directory = await appFlowyApplicationDataDirectory();
|
final directory = await appFlowyApplicationDataDirectory();
|
||||||
await getIt<ApplicationDataStorage>()._setPath(directory.path);
|
await getIt<ApplicationDataStorage>().setPath(directory.path);
|
||||||
emit(SettingsLocationState.didReceivedPath(directory.path));
|
emit(SettingsLocationState.didReceivedPath(directory.path));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -41,79 +36,3 @@ class SettingsLocationCubit extends Cubit<SettingsLocationState> {
|
|||||||
emit(SettingsLocationState.didReceivedPath(path));
|
emit(SettingsLocationState.didReceivedPath(path));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const appFlowyDataFolder = "AppFlowyDataDoNotRename";
|
|
||||||
|
|
||||||
class ApplicationDataStorage {
|
|
||||||
ApplicationDataStorage();
|
|
||||||
String? _cachePath;
|
|
||||||
|
|
||||||
/// Set the custom path to store the data.
|
|
||||||
/// If the path is not exists, the path will be created.
|
|
||||||
/// If the path is invalid, the path will be set to the default path.
|
|
||||||
Future<void> setCustomPath(String path) async {
|
|
||||||
if (kIsWeb || Platform.isAndroid || Platform.isIOS) {
|
|
||||||
Log.info('LocalFileStorage is not supported on this platform.');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Platform.isMacOS) {
|
|
||||||
// remove the prefix `/Volumes/*`
|
|
||||||
path = path.replaceFirst(RegExp(r'^/Volumes/[^/]+'), '');
|
|
||||||
} else if (Platform.isWindows) {
|
|
||||||
path = path.replaceAll('/', '\\');
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the path is not ends with `AppFlowyData`, we will append the
|
|
||||||
// `AppFlowyData` to the path. If the path is ends with `AppFlowyData`,
|
|
||||||
// which means the path is the custom path.
|
|
||||||
if (p.basename(path) != appFlowyDataFolder) {
|
|
||||||
path = p.join(path, appFlowyDataFolder);
|
|
||||||
}
|
|
||||||
|
|
||||||
// create the directory if not exists.
|
|
||||||
final directory = Directory(path);
|
|
||||||
if (!directory.existsSync()) {
|
|
||||||
await directory.create(recursive: true);
|
|
||||||
}
|
|
||||||
|
|
||||||
_setPath(path);
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> _setPath(String path) async {
|
|
||||||
if (kIsWeb || Platform.isAndroid || Platform.isIOS) {
|
|
||||||
Log.info('LocalFileStorage is not supported on this platform.');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
await getIt<KeyValueStorage>().set(KVKeys.pathLocation, path);
|
|
||||||
// clear the cache path, and not set the cache path to the new path because the set path may be invalid
|
|
||||||
_cachePath = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<String> getPath() async {
|
|
||||||
if (_cachePath != null) {
|
|
||||||
return _cachePath!;
|
|
||||||
}
|
|
||||||
|
|
||||||
final response = await getIt<KeyValueStorage>().get(KVKeys.pathLocation);
|
|
||||||
String path = await response.fold(
|
|
||||||
(error) async {
|
|
||||||
// return the default path if the path is not set
|
|
||||||
final directory = await appFlowyApplicationDataDirectory();
|
|
||||||
return directory.path;
|
|
||||||
},
|
|
||||||
(path) => path,
|
|
||||||
);
|
|
||||||
_cachePath = path;
|
|
||||||
|
|
||||||
// if the path is not exists means the path is invalid, so we should clear the kv store
|
|
||||||
if (!Directory(path).existsSync()) {
|
|
||||||
await getIt<KeyValueStorage>().clear();
|
|
||||||
final directory = await appFlowyApplicationDataDirectory();
|
|
||||||
path = directory.path;
|
|
||||||
}
|
|
||||||
|
|
||||||
return path;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -36,7 +36,7 @@ class AppFlowyUnitTest {
|
|||||||
|
|
||||||
await FlowyRunner.run(
|
await FlowyRunner.run(
|
||||||
FlowyTestApp(),
|
FlowyTestApp(),
|
||||||
IntegrationMode.test,
|
IntegrationMode.unitTest,
|
||||||
);
|
);
|
||||||
|
|
||||||
final test = AppFlowyUnitTest();
|
final test = AppFlowyUnitTest();
|
||||||
|
Loading…
Reference in New Issue
Block a user