Skip to content

Commit f33053f

Browse files
authored
Merge pull request #318 from Scriptbash/windows-db
Store DB in app support directory on Windows
2 parents fcc6436 + e2ebb62 commit f33053f

10 files changed

Lines changed: 117 additions & 55 deletions

File tree

.github/workflows/publish.yml

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,25 @@ jobs:
155155
run: |
156156
choco install innosetup -y
157157
refreshenv
158+
- name: Extract version from pubspec.yaml
159+
shell: pwsh
160+
id: extract_version
161+
run: |
162+
$pubspec = Get-Content pubspec.yaml
163+
foreach ($line in $pubspec) {
164+
if ($line -match '^version:\s*(.+)$') {
165+
$version = $matches[1]
166+
break
167+
}
168+
}
169+
Write-Host "VERSION=$version"
170+
echo "VERSION=$version" >> $env:GITHUB_ENV
171+
- name: Patch ISS with correct version
172+
shell: powershell
173+
run: |
174+
$issPath = ".\windows\wispar_setup.iss"
175+
(Get-Content $issPath) -replace '#define MyAppVersion ".*"', '#define MyAppVersion "${{ env.VERSION }}"' | Set-Content $issPath
176+
Write-Host "Patched ISS file with version ${{ env.VERSION }}"
158177
- name: Create Windows installer
159178
shell: powershell
160179
run: |

lib/main.dart

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,29 @@ import './services/background_service.dart';
1616
import './services/logs_helper.dart';
1717
import 'package:background_fetch/background_fetch.dart';
1818
import 'package:sqflite_common_ffi/sqflite_ffi.dart';
19+
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
20+
import 'package:path_provider/path_provider.dart';
21+
import 'package:wispar/webview_env.dart';
1922
import 'dart:io' show Platform;
2023

2124
void main() async {
2225
WidgetsFlutterBinding.ensureInitialized();
26+
27+
if (Platform.isWindows) {
28+
final availableVersion = await WebViewEnvironment.getAvailableVersion();
29+
if (availableVersion == null) {
30+
return;
31+
}
32+
33+
final appDataDir = await getApplicationSupportDirectory();
34+
35+
webViewEnvironment = await WebViewEnvironment.create(
36+
settings: WebViewEnvironmentSettings(
37+
userDataFolder: '${appDataDir.path}\\WisparWebView',
38+
),
39+
);
40+
}
41+
2342
if (Platform.isLinux || Platform.isWindows) {
2443
sqfliteFfiInit();
2544
databaseFactory = databaseFactoryFfi;

lib/screens/article_website.dart

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@ import 'package:path_provider/path_provider.dart';
1111
import 'dart:io';
1212
import 'package:http/http.dart' as http;
1313
import 'package:wispar/services/logs_helper.dart';
14-
import '../services/database_helper.dart';
14+
import 'package:wispar/webview_env.dart';
15+
import 'package:wispar/services/database_helper.dart';
1516

1617
class ArticleWebsite extends StatefulWidget {
1718
final PublicationCard publicationCard;
@@ -307,6 +308,8 @@ class ArticleWebsiteState extends State<ArticleWebsite> {
307308
isReadyToLoad
308309
? InAppWebView(
309310
key: webViewKey,
311+
webViewEnvironment:
312+
Platform.isWindows ? webViewEnvironment : null,
310313
initialUrlRequest: URLRequest(url: WebUri(pdfUrl)),
311314
initialSettings: settings,
312315
pullToRefreshController: pullToRefreshController,
@@ -979,6 +982,10 @@ class ArticleWebsiteState extends State<ArticleWebsite> {
979982

980983
if (useCustomPath && customPath != null) {
981984
baseDirPath = customPath;
985+
} else if (Platform.isWindows) {
986+
final defaultAppDir =
987+
await getApplicationSupportDirectory();
988+
baseDirPath = defaultAppDir.path;
982989
} else {
983990
final defaultAppDir =
984991
await getApplicationDocumentsDirectory();

lib/screens/database_settings_screen.dart

Lines changed: 34 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -118,8 +118,7 @@ class DatabaseSettingsScreenState extends State<DatabaseSettingsScreen> {
118118
String? targetPath;
119119

120120
if (Platform.isIOS) {
121-
targetPath =
122-
await DatabaseHelper.resolveCustomDatabasePath(pickedFolder);
121+
targetPath = await DatabaseHelper.resolveBookmarkPath(pickedFolder);
123122
if (targetPath == null) {
124123
throw Exception('Failed to resolve custom database bookmark on iOS.');
125124
}
@@ -150,22 +149,21 @@ class DatabaseSettingsScreenState extends State<DatabaseSettingsScreen> {
150149
try {
151150
await _showLoadingDialog(
152151
AppLocalizations.of(context)!.movingDatabase);
153-
final dbHelper = DatabaseHelper();
154152
await dbHelper.closeDatabase();
153+
final oldDbPath = await dbHelper.getDbPath();
154+
final oldBaseDir = Directory(p.dirname(oldDbPath));
155155

156-
final defaultAppDir = await getApplicationDocumentsDirectory();
157-
final oldDBPath = p.join(await getDatabasesPath(), 'wispar.db');
158-
final newDBPath = p.join(targetPath, 'wispar.db');
156+
final newDbPath = p.join(targetPath, 'wispar.db');
159157

160158
// Move database
161-
final oldDBFile = File(oldDBPath);
159+
final oldDBFile = File(oldDbPath);
162160
if (await oldDBFile.exists()) {
163-
await oldDBFile.copy(newDBPath);
161+
await oldDBFile.copy(newDbPath);
164162
await oldDBFile.delete();
165163
}
166164

167165
// Move PDFs
168-
await for (final file in defaultAppDir.list()) {
166+
await for (final file in oldBaseDir.list()) {
169167
if (file is File && file.path.endsWith('.pdf')) {
170168
final newFile = File(p.join(targetPath, p.basename(file.path)));
171169
await file.copy(newFile.path);
@@ -175,7 +173,7 @@ class DatabaseSettingsScreenState extends State<DatabaseSettingsScreen> {
175173

176174
// Move graphical abstracts
177175
final oldGraphicalDir =
178-
Directory(p.join(defaultAppDir.path, 'graphical_abstracts'));
176+
Directory(p.join(oldBaseDir.path, 'graphical_abstracts'));
179177
final newGraphicalDir =
180178
Directory(p.join(targetPath, 'graphical_abstracts'));
181179

@@ -251,14 +249,24 @@ class DatabaseSettingsScreenState extends State<DatabaseSettingsScreen> {
251249
if (customPath == null) {
252250
throw Exception("Custom DB folder not accessible");
253251
}
252+
String defaultDBPath;
253+
Directory defaultBaseDir;
254+
255+
if (Platform.isWindows) {
256+
final appDir = await getApplicationSupportDirectory();
257+
defaultDBPath = p.join(appDir.path, 'wispar.db');
258+
defaultBaseDir = appDir;
259+
} else {
260+
final defaultPath = await getDatabasesPath();
261+
defaultDBPath = p.join(defaultPath, 'wispar.db');
262+
defaultBaseDir = Directory(defaultPath);
263+
}
254264

255-
final defaultDBPath = p.join(await getDatabasesPath(), 'wispar.db');
256-
final appDir = await getApplicationDocumentsDirectory();
257265
final oldDBPath = p.join(customPath, 'wispar.db');
258266
final oldGraphicalDir =
259267
Directory(p.join(customPath, 'graphical_abstracts'));
260268
final newGraphicalDir =
261-
Directory(p.join(appDir.path, 'graphical_abstracts'));
269+
Directory(p.join(defaultBaseDir.path, 'graphical_abstracts'));
262270

263271
// Move DB
264272
final oldDBFile = File(oldDBPath);
@@ -271,7 +279,8 @@ class DatabaseSettingsScreenState extends State<DatabaseSettingsScreen> {
271279
final customDir = Directory(customPath);
272280
await for (final file in customDir.list()) {
273281
if (file is File && file.path.endsWith('.pdf')) {
274-
final newFile = File(p.join(appDir.path, p.basename(file.path)));
282+
final newFile =
283+
File(p.join(defaultBaseDir.path, p.basename(file.path)));
275284
await file.copy(newFile.path);
276285
await file.delete();
277286
}
@@ -372,22 +381,9 @@ class DatabaseSettingsScreenState extends State<DatabaseSettingsScreen> {
372381
final String outputFile =
373382
p.join(outputDirectory, 'wispar_backup_$timestamp.zip');
374383

375-
final customSourcePath = await _getUsableCustomPath();
376-
String sourceBasePath;
377-
String dbDirectoryPath;
378-
379-
if (customSourcePath != null) {
380-
sourceBasePath = customSourcePath;
381-
dbDirectoryPath = customSourcePath;
382-
} else {
383-
// Use default paths
384-
final defaultAppDir = await getApplicationDocumentsDirectory();
385-
sourceBasePath = defaultAppDir.path;
386-
dbDirectoryPath = await getDatabasesPath();
387-
}
388-
389-
String dbPath = p.join(dbDirectoryPath, "wispar.db");
390-
File dbFile = File(dbPath);
384+
final dbPath = await DatabaseHelper().getDbPath();
385+
final dbFile = File(dbPath);
386+
final sourceBasePath = p.dirname(dbPath);
391387

392388
final sourceDir = Directory(sourceBasePath);
393389

@@ -453,20 +449,18 @@ class DatabaseSettingsScreenState extends State<DatabaseSettingsScreen> {
453449
await dbHelper.closeDatabase();
454450
File selectedFile = File(result.files.single.path!);
455451

452+
final dbPath = await dbHelper.getDbPath();
453+
final dbDirectoryPath = p.dirname(dbPath);
454+
456455
final prefs = await SharedPreferences.getInstance();
457456
final useCustomPath = prefs.getBool('useCustomDatabasePath') ?? false;
458457
final customPath = prefs.getString('customDatabasePath');
459-
460-
String dbDestinationPath;
461-
if (useCustomPath && customPath != null) {
462-
dbDestinationPath = customPath;
463-
} else {
464-
dbDestinationPath = await getDatabasesPath();
465-
}
466-
467458
String docsDestinationPath;
468459
if (useCustomPath && customPath != null) {
469460
docsDestinationPath = customPath;
461+
} else if (Platform.isWindows) {
462+
final appDir = await getApplicationSupportDirectory();
463+
docsDestinationPath = appDir.path;
470464
} else {
471465
final appDir = await getApplicationDocumentsDirectory();
472466
docsDestinationPath = appDir.path;
@@ -478,7 +472,7 @@ class DatabaseSettingsScreenState extends State<DatabaseSettingsScreen> {
478472

479473
for (final file in archive) {
480474
final destinationBasePath =
481-
file.name == 'wispar.db' ? dbDestinationPath : docsDestinationPath;
475+
file.name == 'wispar.db' ? dbDirectoryPath : docsDestinationPath;
482476

483477
final filePath = p.join(destinationBasePath, file.name);
484478
final outFile = File(filePath);
@@ -502,7 +496,7 @@ class DatabaseSettingsScreenState extends State<DatabaseSettingsScreen> {
502496
}
503497

504498
logger.info(
505-
'The database was successfully imported to $dbDestinationPath from ${selectedFile.path}');
499+
'The database was successfully imported to $dbDirectoryPath from ${selectedFile.path}');
506500

507501
if (!mounted) return;
508502
ScaffoldMessenger.of(context).showSnackBar(

lib/screens/pdf_reader.dart

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import 'dart:io';
12
import 'package:flutter/material.dart';
23
import '../generated_l10n/app_localizations.dart';
34
import 'package:pdfrx/pdfrx.dart';
@@ -80,6 +81,9 @@ class PdfReaderState extends State<PdfReader> {
8081
String basePath;
8182
if (_useCustomPath && _customPath != null) {
8283
basePath = _customPath!;
84+
} else if (Platform.isWindows) {
85+
final defaultDirectory = await getApplicationSupportDirectory();
86+
basePath = defaultDirectory.path;
8387
} else {
8488
final defaultDirectory = await getApplicationDocumentsDirectory();
8589
basePath = defaultDirectory.path;

lib/services/abstract_scraper.dart

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@ import 'dart:async';
22
import 'dart:io' show Platform;
33
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
44
import 'package:shared_preferences/shared_preferences.dart';
5-
import './string_format_helper.dart';
6-
import './logs_helper.dart';
5+
import 'package:wispar/webview_env.dart';
6+
import 'package:wispar/services/string_format_helper.dart';
7+
import 'package:wispar/services/logs_helper.dart';
78

89
class AbstractScraper {
910
Completer<Map<String, String?>> _completer =
@@ -47,6 +48,7 @@ class AbstractScraper {
4748
initialSettings: InAppWebViewSettings(
4849
userAgent: userAgent,
4950
),
51+
webViewEnvironment: Platform.isWindows ? webViewEnvironment : null,
5052
initialUrlRequest: URLRequest(url: WebUri(url)),
5153
onLoadStop: (controller, loadedUrl) async {
5254
await Future.delayed(const Duration(seconds: 3));

lib/services/database_helper.dart

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import 'package:path_provider/path_provider.dart';
1717
class DatabaseHelper {
1818
static const platform = MethodChannel('app.wispar.wispar/database_access');
1919

20-
static Future<String?> resolveCustomDatabasePath(String? path) async {
20+
static Future<String?> resolveBookmarkPath(String? path) async {
2121
if (path == null) return null;
2222

2323
if (Platform.isIOS) {
@@ -29,7 +29,6 @@ class DatabaseHelper {
2929
return null;
3030
}
3131
} else {
32-
// Android can use the path directly
3332
return path;
3433
}
3534
}
@@ -44,23 +43,26 @@ class DatabaseHelper {
4443
return _database!;
4544
}
4645

47-
Future<Database> initDatabase() async {
46+
Future<String> getDbPath() async {
4847
SharedPreferences prefs = await SharedPreferences.getInstance();
4948
String? customPath = prefs.getString('customDatabasePath');
5049
String? bookmark = prefs.getString('customDatabaseBookmark');
5150

5251
if (Platform.isIOS && bookmark != null) {
53-
final resolvedPath = await DatabaseHelper.platform
54-
.invokeMethod('resolveCustomPath', bookmark);
55-
if (resolvedPath != null) {
56-
customPath = resolvedPath;
57-
} else {
58-
customPath = null;
59-
}
52+
final resolved = await resolveBookmarkPath(bookmark);
53+
if (resolved != null) customPath = resolved;
54+
}
55+
String defaultPath = await getDatabasesPath();
56+
if (Platform.isWindows) {
57+
final dir = await getApplicationSupportDirectory();
58+
defaultPath = dir.path;
6059
}
61-
62-
final defaultPath = await getDatabasesPath();
6360
final databasePath = join(customPath ?? defaultPath, 'wispar.db');
61+
return databasePath;
62+
}
63+
64+
Future<Database> initDatabase() async {
65+
String databasePath = await getDbPath();
6466

6567
return openDatabase(databasePath, version: 9, onOpen: (db) async {
6668
await db.execute('PRAGMA foreign_keys = ON');
@@ -1115,6 +1117,9 @@ class DatabaseHelper {
11151117
String baseDirPath;
11161118
if (useCustomPath && customPath != null) {
11171119
baseDirPath = customPath;
1120+
} else if (Platform.isWindows) {
1121+
final dir = await getApplicationSupportDirectory();
1122+
baseDirPath = dir.path;
11181123
} else {
11191124
final dir = await getApplicationDocumentsDirectory();
11201125
baseDirPath = dir.path;

lib/services/graphical_abstract_manager.dart

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@ class GraphicalAbstractManager {
1717

1818
if (useCustomPath && customPath != null) {
1919
basePath = customPath;
20+
} else if (Platform.isWindows) {
21+
final dir = await getApplicationSupportDirectory();
22+
basePath = dir.path;
2023
} else {
2124
final dir = await getApplicationDocumentsDirectory();
2225
basePath = dir.path;

lib/webview_env.dart

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
2+
3+
/* Global variable to specify where to save the inappwebview cache
4+
on Windows*/
5+
WebViewEnvironment? webViewEnvironment;

lib/widgets/publication_card/publication_card.dart

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import 'dart:io';
12
import 'package:flutter/material.dart';
23
import 'package:flutter/services.dart';
34
import 'package:wispar/generated_l10n/app_localizations.dart';
@@ -401,6 +402,9 @@ class PublicationCardState extends State<PublicationCard>
401402
String basePath;
402403
if (useCustomPath && customPath != null) {
403404
basePath = customPath;
405+
} else if (Platform.isWindows) {
406+
final defaultDirectory = await getApplicationSupportDirectory();
407+
basePath = defaultDirectory.path;
404408
} else {
405409
final defaultDirectory = await getApplicationDocumentsDirectory();
406410
basePath = defaultDirectory.path;

0 commit comments

Comments
 (0)