fontastic 1.1.0 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/claude-code-review.yml +0 -6
- package/.github/workflows/release-please.yml +25 -0
- package/.github/workflows/release.yml +5 -109
- package/.release-please-manifest.json +3 -0
- package/CHANGELOG.md +39 -0
- package/README.md +6 -0
- package/app/Application.js +4 -4
- package/app/Application.ts +13 -13
- package/app/config/database.js +1 -1
- package/app/config/database.ts +1 -1
- package/app/config/mimes.js +23 -23
- package/app/config/mimes.ts +35 -29
- package/app/core/ConfigManager.js +27 -0
- package/app/core/ConfigManager.ts +28 -0
- package/app/core/FontFinder.js +66 -15
- package/app/core/FontFinder.ts +81 -22
- package/app/core/FontManager.js +20 -18
- package/app/core/FontManager.ts +21 -19
- package/app/core/FontObject.js +44 -24
- package/app/core/FontObject.ts +47 -27
- package/app/core/MessageHandler.js +70 -19
- package/app/core/MessageHandler.ts +82 -21
- package/app/core/SystemManager.js +5 -1
- package/app/core/SystemManager.ts +5 -1
- package/app/database/entity/Collection.schema.js +20 -18
- package/app/database/entity/Collection.schema.ts +22 -21
- package/app/database/repository/Collection.repository.js +17 -18
- package/app/database/repository/Collection.repository.ts +27 -18
- package/app/database/repository/Store.repository.js +13 -18
- package/app/database/repository/Store.repository.ts +13 -21
- package/app/enums/ChannelType.js +18 -0
- package/app/enums/ChannelType.ts +24 -0
- package/app/main.js +98 -10
- package/app/main.ts +126 -19
- package/app/package.json +1 -1
- package/app/types/NativeThemeState.js +3 -0
- package/app/types/NativeThemeState.ts +4 -0
- package/app/types/ScanProgress.js +3 -0
- package/app/types/ScanProgress.ts +6 -0
- package/app/types/SystemPreferencesState.js +3 -0
- package/app/types/SystemPreferencesState.ts +4 -0
- package/app/types/index.js +3 -0
- package/app/types/index.ts +3 -0
- package/package.json +2 -2
- package/release-please-config.json +20 -0
- package/scripts/patch-electron-plist.js +41 -0
- package/src/app/core/services/database/database.service.ts +6 -0
- package/src/app/core/services/message/message.service.ts +33 -1
- package/src/app/core/services/presentation/presentation.service.ts +100 -1
- package/src/app/layout/footer/footer.component.html +13 -2
- package/src/app/layout/footer/footer.component.ts +18 -2
- package/src/app/layout/header/header.component.html +0 -10
- package/src/app/layout/header/header.component.ts +4 -23
- package/src/app/layout/navigation/navigation.component.html +66 -16
- package/src/app/layout/navigation/navigation.component.ts +65 -12
- package/src/app/settings/ai-keys/ai-keys.component.ts +13 -18
- package/src/app/settings/danger-zone/danger-zone.component.html +8 -0
- package/src/app/settings/danger-zone/danger-zone.component.ts +12 -0
- package/src/app/settings/news-api/news-api.component.ts +6 -8
- package/src/app/settings/theme/theme.component.html +15 -2
- package/src/app/settings/theme/theme.component.ts +4 -0
- package/src/app/shared/components/datagrid/datagrid.component.html +8 -17
- package/src/app/shared/components/datagrid/datagrid.component.ts +6 -10
- package/src/app/shared/components/glyphs/glyphs.component.html +5 -15
- package/src/app/shared/components/glyphs/glyphs.component.ts +3 -0
- package/src/app/shared/components/preview/preview.component.html +1 -1
- package/src/app/shared/components/preview/preview.component.ts +3 -8
- package/src/app/shared/components/prompt-dialog/prompt-dialog.component.html +2 -2
- package/src/app/shared/components/prompt-dialog/prompt-dialog.component.ts +2 -1
- package/src/app/shared/components/rule-builder/rule-builder.component.html +18 -6
- package/src/app/shared/components/rule-builder/rule-builder.component.ts +34 -2
- package/src/app/shared/components/search/search.component.html +9 -36
- package/src/app/shared/components/search/search.component.ts +2 -1
- package/src/app/shared/components/waterfall/waterfall.component.html +1 -3
- package/src/app/shared/components/waterfall/waterfall.component.ts +2 -1
- package/src/app/shared/directives/disabled-opacity/disabled-opacity.directive.ts +18 -0
- package/src/app/shared/directives/hover-highlight/hover-highlight.directive.ts +38 -0
- package/src/app/shared/directives/index.ts +5 -0
- package/src/app/shared/directives/modal-backdrop/modal-backdrop.directive.ts +18 -0
- package/src/app/shared/directives/scroll-reset/scroll-reset.directive.ts +15 -0
- package/src/app/shared/directives/stop-propagation/stop-propagation.directive.ts +12 -0
- package/src/assets/icons/favicon.256x256.png +0 -0
- package/src/assets/icons/favicon.512x512.png +0 -0
- package/src/assets/icons/favicon.icns +0 -0
- package/src/assets/icons/favicon.ico +0 -0
- package/src/assets/icons/favicon.png +0 -0
- package/src/favicon.ico +0 -0
|
@@ -72,13 +72,11 @@ export const CollectionRepository = {
|
|
|
72
72
|
},
|
|
73
73
|
|
|
74
74
|
async updateCollectionCounts(items: any[]) {
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
.update(Collection)
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
.execute();
|
|
81
|
-
});
|
|
75
|
+
await Promise.all(
|
|
76
|
+
items.map((item) =>
|
|
77
|
+
this.createQueryBuilder().update(Collection).set({ count: item.total }).where('id = :id', { id: item.collection_id }).execute(),
|
|
78
|
+
),
|
|
79
|
+
);
|
|
82
80
|
},
|
|
83
81
|
|
|
84
82
|
updateCollection(collectionId: number, data: any) {
|
|
@@ -112,10 +110,13 @@ export const CollectionRepository = {
|
|
|
112
110
|
},
|
|
113
111
|
|
|
114
112
|
async createParent(title: string) {
|
|
115
|
-
const data = await this.createQueryBuilder()
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
.
|
|
113
|
+
const data = await this.createQueryBuilder().select('MAX(collection.right_id)', 'right_id').getRawOne();
|
|
114
|
+
|
|
115
|
+
await this.createQueryBuilder()
|
|
116
|
+
.update(Collection)
|
|
117
|
+
.set({ orderby: () => 'orderby + 1' })
|
|
118
|
+
.where({ parent_id: 0 })
|
|
119
|
+
.execute();
|
|
119
120
|
|
|
120
121
|
return await this.createQueryBuilder()
|
|
121
122
|
.insert()
|
|
@@ -125,7 +126,7 @@ export const CollectionRepository = {
|
|
|
125
126
|
parent_id: 0,
|
|
126
127
|
left_id: data.right_id + 1,
|
|
127
128
|
right_id: data.right_id + 2,
|
|
128
|
-
orderby:
|
|
129
|
+
orderby: 0,
|
|
129
130
|
})
|
|
130
131
|
.execute();
|
|
131
132
|
},
|
|
@@ -133,18 +134,24 @@ export const CollectionRepository = {
|
|
|
133
134
|
async createChild(parentId: number, title: string) {
|
|
134
135
|
const row = await this.findOne({ where: { id: parentId } });
|
|
135
136
|
|
|
136
|
-
this.createQueryBuilder()
|
|
137
|
+
await this.createQueryBuilder()
|
|
137
138
|
.update(Collection)
|
|
138
139
|
.set({ left_id: () => 'left_id + 2', right_id: () => 'right_id + 2' })
|
|
139
140
|
.where({ left_id: MoreThan(row.right_id) })
|
|
140
141
|
.execute();
|
|
141
142
|
|
|
142
|
-
this.createQueryBuilder()
|
|
143
|
+
await this.createQueryBuilder()
|
|
143
144
|
.update(Collection)
|
|
144
145
|
.set({ right_id: () => 'right_id + 2' })
|
|
145
146
|
.where({ left_id: LessThanOrEqual(row.left_id), right_id: MoreThanOrEqual(row.left_id) })
|
|
146
147
|
.execute();
|
|
147
148
|
|
|
149
|
+
await this.createQueryBuilder()
|
|
150
|
+
.update(Collection)
|
|
151
|
+
.set({ orderby: () => 'orderby + 1' })
|
|
152
|
+
.where({ parent_id: parentId })
|
|
153
|
+
.execute();
|
|
154
|
+
|
|
148
155
|
return await this.createQueryBuilder()
|
|
149
156
|
.insert()
|
|
150
157
|
.into(Collection)
|
|
@@ -153,7 +160,7 @@ export const CollectionRepository = {
|
|
|
153
160
|
parent_id: parentId,
|
|
154
161
|
left_id: row.right_id,
|
|
155
162
|
right_id: row.right_id + 1,
|
|
156
|
-
orderby:
|
|
163
|
+
orderby: 0,
|
|
157
164
|
})
|
|
158
165
|
.execute();
|
|
159
166
|
},
|
|
@@ -264,9 +271,11 @@ export const CollectionRepository = {
|
|
|
264
271
|
.orderBy('collection.left_id', 'ASC')
|
|
265
272
|
.getMany();
|
|
266
273
|
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
274
|
+
await Promise.all(
|
|
275
|
+
newSiblings.map((sibling: Collection, i: number) =>
|
|
276
|
+
this.createQueryBuilder().update(Collection).set({ orderby: i }).where('id = :id', { id: sibling.id }).execute(),
|
|
277
|
+
),
|
|
278
|
+
);
|
|
270
279
|
},
|
|
271
280
|
|
|
272
281
|
async createSystemCollection() {
|
|
@@ -131,9 +131,8 @@ exports.StoreRepository = {
|
|
|
131
131
|
}
|
|
132
132
|
});
|
|
133
133
|
}
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
}
|
|
134
|
+
const MAX_SEARCH_LIMIT = 5000;
|
|
135
|
+
db.limit(Math.min(options.take || 500, MAX_SEARCH_LIMIT));
|
|
137
136
|
if (options.skip) {
|
|
138
137
|
db.offset(options.skip);
|
|
139
138
|
}
|
|
@@ -298,13 +297,7 @@ exports.StoreRepository = {
|
|
|
298
297
|
if (item.version && item.version !== '') {
|
|
299
298
|
data.version = item.version;
|
|
300
299
|
}
|
|
301
|
-
|
|
302
|
-
return yield this.createQueryBuilder()
|
|
303
|
-
.insert()
|
|
304
|
-
.into(entity_1.Store)
|
|
305
|
-
.values(data)
|
|
306
|
-
.execute()
|
|
307
|
-
.catch((err) => console.log('insert-error', err));
|
|
300
|
+
return yield this.createQueryBuilder().insert().into(entity_1.Store).values(data).execute();
|
|
308
301
|
});
|
|
309
302
|
},
|
|
310
303
|
evaluateSmartRules(rules_1, matchType_1) {
|
|
@@ -416,15 +409,17 @@ exports.StoreRepository = {
|
|
|
416
409
|
},
|
|
417
410
|
fetchSystemStats() {
|
|
418
411
|
return __awaiter(this, void 0, void 0, function* () {
|
|
419
|
-
const
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
412
|
+
const stats = yield this.createQueryBuilder()
|
|
413
|
+
.select('COUNT(*)', 'rowCount')
|
|
414
|
+
.addSelect('SUM(CASE WHEN store.favorite = 1 THEN 1 ELSE 0 END)', 'favoriteCount')
|
|
415
|
+
.addSelect('SUM(CASE WHEN store.system = 1 THEN 1 ELSE 0 END)', 'systemCount')
|
|
416
|
+
.addSelect('SUM(CASE WHEN store.temporary = 1 THEN 1 ELSE 0 END)', 'temporaryCount')
|
|
417
|
+
.getRawOne();
|
|
423
418
|
return {
|
|
424
|
-
rowCount: rowCount
|
|
425
|
-
favoriteCount: favoriteCount
|
|
426
|
-
systemCount: systemCount
|
|
427
|
-
temporaryCount: temporaryCount
|
|
419
|
+
rowCount: Number(stats.rowCount) || 0,
|
|
420
|
+
favoriteCount: Number(stats.favoriteCount) || 0,
|
|
421
|
+
systemCount: Number(stats.systemCount) || 0,
|
|
422
|
+
temporaryCount: Number(stats.temporaryCount) || 0,
|
|
428
423
|
};
|
|
429
424
|
});
|
|
430
425
|
},
|
|
@@ -135,9 +135,8 @@ export const StoreRepository = {
|
|
|
135
135
|
});
|
|
136
136
|
}
|
|
137
137
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
}
|
|
138
|
+
const MAX_SEARCH_LIMIT = 5000;
|
|
139
|
+
db.limit(Math.min(options.take || 500, MAX_SEARCH_LIMIT));
|
|
141
140
|
|
|
142
141
|
if (options.skip) {
|
|
143
142
|
db.offset(options.skip);
|
|
@@ -322,13 +321,7 @@ export const StoreRepository = {
|
|
|
322
321
|
data.version = item.version;
|
|
323
322
|
}
|
|
324
323
|
|
|
325
|
-
|
|
326
|
-
return await this.createQueryBuilder()
|
|
327
|
-
.insert()
|
|
328
|
-
.into(Store)
|
|
329
|
-
.values(data)
|
|
330
|
-
.execute()
|
|
331
|
-
.catch((err: any) => console.log('insert-error', err));
|
|
324
|
+
return await this.createQueryBuilder().insert().into(Store).values(data).execute();
|
|
332
325
|
},
|
|
333
326
|
|
|
334
327
|
async evaluateSmartRules(rules: SmartCollectionRule[], matchType: string, options: any = {}) {
|
|
@@ -437,19 +430,18 @@ export const StoreRepository = {
|
|
|
437
430
|
},
|
|
438
431
|
|
|
439
432
|
async fetchSystemStats() {
|
|
440
|
-
const
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
const temporaryCount = await this.createQueryBuilder().select('COUNT(*)', 'total').where('store.temporary = 1').getRawOne();
|
|
433
|
+
const stats = await this.createQueryBuilder()
|
|
434
|
+
.select('COUNT(*)', 'rowCount')
|
|
435
|
+
.addSelect('SUM(CASE WHEN store.favorite = 1 THEN 1 ELSE 0 END)', 'favoriteCount')
|
|
436
|
+
.addSelect('SUM(CASE WHEN store.system = 1 THEN 1 ELSE 0 END)', 'systemCount')
|
|
437
|
+
.addSelect('SUM(CASE WHEN store.temporary = 1 THEN 1 ELSE 0 END)', 'temporaryCount')
|
|
438
|
+
.getRawOne();
|
|
447
439
|
|
|
448
440
|
return {
|
|
449
|
-
rowCount: rowCount
|
|
450
|
-
favoriteCount: favoriteCount
|
|
451
|
-
systemCount: systemCount
|
|
452
|
-
temporaryCount: temporaryCount
|
|
441
|
+
rowCount: Number(stats.rowCount) || 0,
|
|
442
|
+
favoriteCount: Number(stats.favoriteCount) || 0,
|
|
443
|
+
systemCount: Number(stats.systemCount) || 0,
|
|
444
|
+
temporaryCount: Number(stats.temporaryCount) || 0,
|
|
453
445
|
};
|
|
454
446
|
},
|
|
455
447
|
};
|
package/app/enums/ChannelType.js
CHANGED
|
@@ -63,6 +63,24 @@ var ChannelType;
|
|
|
63
63
|
ChannelType["IPC_SMART_COLLECTION_UPDATE"] = "IPC_SMART_COLLECTION_UPDATE";
|
|
64
64
|
ChannelType["IPC_SMART_COLLECTION_DELETE"] = "IPC_SMART_COLLECTION_DELETE";
|
|
65
65
|
ChannelType["IPC_SMART_COLLECTION_EVALUATE"] = "IPC_SMART_COLLECTION_EVALUATE";
|
|
66
|
+
ChannelType["IPC_SMART_COLLECTION_PREVIEW"] = "IPC_SMART_COLLECTION_PREVIEW";
|
|
66
67
|
ChannelType["IPC_TOGGLE_PANEL"] = "IPC_TOGGLE_PANEL";
|
|
68
|
+
// Native Theme
|
|
69
|
+
ChannelType["IPC_GET_NATIVE_THEME"] = "IPC_GET_NATIVE_THEME";
|
|
70
|
+
ChannelType["IPC_NATIVE_THEME_CHANGED"] = "IPC_NATIVE_THEME_CHANGED";
|
|
71
|
+
// Safe Storage
|
|
72
|
+
ChannelType["IPC_SAFE_STORE"] = "IPC_SAFE_STORE";
|
|
73
|
+
ChannelType["IPC_SAFE_RETRIEVE"] = "IPC_SAFE_RETRIEVE";
|
|
74
|
+
// Session
|
|
75
|
+
ChannelType["IPC_CLEAR_CACHE"] = "IPC_CLEAR_CACHE";
|
|
76
|
+
// Power Monitor
|
|
77
|
+
ChannelType["IPC_POWER_SUSPEND"] = "IPC_POWER_SUSPEND";
|
|
78
|
+
ChannelType["IPC_POWER_RESUME"] = "IPC_POWER_RESUME";
|
|
79
|
+
ChannelType["IPC_POWER_SHUTDOWN"] = "IPC_POWER_SHUTDOWN";
|
|
80
|
+
ChannelType["IPC_POWER_LOCK_SCREEN"] = "IPC_POWER_LOCK_SCREEN";
|
|
81
|
+
// System Preferences
|
|
82
|
+
ChannelType["IPC_GET_SYSTEM_PREFERENCES"] = "IPC_GET_SYSTEM_PREFERENCES";
|
|
83
|
+
// Scan Progress (MessageChannelMain)
|
|
84
|
+
ChannelType["IPC_SCAN_PROGRESS_PORT"] = "IPC_SCAN_PROGRESS_PORT";
|
|
67
85
|
})(ChannelType || (exports.ChannelType = ChannelType = {}));
|
|
68
86
|
//# sourceMappingURL=ChannelType.js.map
|
package/app/enums/ChannelType.ts
CHANGED
|
@@ -68,6 +68,30 @@ export enum ChannelType {
|
|
|
68
68
|
IPC_SMART_COLLECTION_UPDATE = 'IPC_SMART_COLLECTION_UPDATE',
|
|
69
69
|
IPC_SMART_COLLECTION_DELETE = 'IPC_SMART_COLLECTION_DELETE',
|
|
70
70
|
IPC_SMART_COLLECTION_EVALUATE = 'IPC_SMART_COLLECTION_EVALUATE',
|
|
71
|
+
IPC_SMART_COLLECTION_PREVIEW = 'IPC_SMART_COLLECTION_PREVIEW',
|
|
71
72
|
|
|
72
73
|
IPC_TOGGLE_PANEL = 'IPC_TOGGLE_PANEL',
|
|
74
|
+
|
|
75
|
+
// Native Theme
|
|
76
|
+
IPC_GET_NATIVE_THEME = 'IPC_GET_NATIVE_THEME',
|
|
77
|
+
IPC_NATIVE_THEME_CHANGED = 'IPC_NATIVE_THEME_CHANGED',
|
|
78
|
+
|
|
79
|
+
// Safe Storage
|
|
80
|
+
IPC_SAFE_STORE = 'IPC_SAFE_STORE',
|
|
81
|
+
IPC_SAFE_RETRIEVE = 'IPC_SAFE_RETRIEVE',
|
|
82
|
+
|
|
83
|
+
// Session
|
|
84
|
+
IPC_CLEAR_CACHE = 'IPC_CLEAR_CACHE',
|
|
85
|
+
|
|
86
|
+
// Power Monitor
|
|
87
|
+
IPC_POWER_SUSPEND = 'IPC_POWER_SUSPEND',
|
|
88
|
+
IPC_POWER_RESUME = 'IPC_POWER_RESUME',
|
|
89
|
+
IPC_POWER_SHUTDOWN = 'IPC_POWER_SHUTDOWN',
|
|
90
|
+
IPC_POWER_LOCK_SCREEN = 'IPC_POWER_LOCK_SCREEN',
|
|
91
|
+
|
|
92
|
+
// System Preferences
|
|
93
|
+
IPC_GET_SYSTEM_PREFERENCES = 'IPC_GET_SYSTEM_PREFERENCES',
|
|
94
|
+
|
|
95
|
+
// Scan Progress (MessageChannelMain)
|
|
96
|
+
IPC_SCAN_PROGRESS_PORT = 'IPC_SCAN_PROGRESS_PORT',
|
|
73
97
|
}
|
package/app/main.js
CHANGED
|
@@ -1,14 +1,59 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
2
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
12
|
const electron_1 = require("electron");
|
|
4
13
|
const path = require("path");
|
|
5
14
|
const fs = require("fs");
|
|
6
15
|
const node_machine_id_1 = require("node-machine-id");
|
|
7
16
|
const Application_1 = require("./Application");
|
|
17
|
+
const ChannelType_1 = require("./enums/ChannelType");
|
|
18
|
+
electron_1.app.name = 'Fontastic';
|
|
19
|
+
const iconPath = path.join(__dirname, '..', 'src', 'assets', 'icons', 'favicon.512x512.png');
|
|
20
|
+
electron_1.app.setAboutPanelOptions({
|
|
21
|
+
applicationName: 'Fontastic',
|
|
22
|
+
applicationVersion: electron_1.app.getVersion(),
|
|
23
|
+
iconPath,
|
|
24
|
+
});
|
|
8
25
|
let win = null;
|
|
9
26
|
let resolveAppReady;
|
|
10
|
-
const appReadyPromise = new Promise(resolve => {
|
|
11
|
-
|
|
27
|
+
const appReadyPromise = new Promise((resolve) => {
|
|
28
|
+
resolveAppReady = resolve;
|
|
29
|
+
});
|
|
30
|
+
const args = process.argv.slice(1), serve = args.some((val) => val === '--serve');
|
|
31
|
+
// --- Native Theme ---
|
|
32
|
+
function getNativeThemeState() {
|
|
33
|
+
return {
|
|
34
|
+
shouldUseDarkColors: electron_1.nativeTheme.shouldUseDarkColors,
|
|
35
|
+
themeSource: electron_1.nativeTheme.themeSource,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
electron_1.ipcMain.handle(ChannelType_1.ChannelType.IPC_GET_NATIVE_THEME, () => getNativeThemeState());
|
|
39
|
+
electron_1.nativeTheme.on('updated', () => {
|
|
40
|
+
if (win && !win.isDestroyed()) {
|
|
41
|
+
win.webContents.send(ChannelType_1.ChannelType.IPC_NATIVE_THEME_CHANGED, getNativeThemeState());
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
// --- System Preferences ---
|
|
45
|
+
function getSystemPreferencesState() {
|
|
46
|
+
var _a, _b;
|
|
47
|
+
let reduceMotion = false;
|
|
48
|
+
if (process.platform === 'darwin') {
|
|
49
|
+
reduceMotion = electron_1.systemPreferences.getAnimationSettings().prefersReducedMotion;
|
|
50
|
+
}
|
|
51
|
+
return {
|
|
52
|
+
accentColor: (_b = (_a = electron_1.systemPreferences.getAccentColor) === null || _a === void 0 ? void 0 : _a.call(electron_1.systemPreferences)) !== null && _b !== void 0 ? _b : '',
|
|
53
|
+
reduceMotion,
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
electron_1.ipcMain.handle(ChannelType_1.ChannelType.IPC_GET_SYSTEM_PREFERENCES, () => getSystemPreferencesState());
|
|
12
57
|
function createWindow() {
|
|
13
58
|
const size = electron_1.screen.getPrimaryDisplay().workAreaSize;
|
|
14
59
|
// Create the browser window.
|
|
@@ -21,15 +66,15 @@ function createWindow() {
|
|
|
21
66
|
nodeIntegration: true,
|
|
22
67
|
allowRunningInsecureContent: serve,
|
|
23
68
|
contextIsolation: false,
|
|
24
|
-
webSecurity: !serve
|
|
69
|
+
webSecurity: !serve,
|
|
25
70
|
},
|
|
26
71
|
});
|
|
27
72
|
(0, node_machine_id_1.machineId)(true).then((machineId) => new Application_1.default(machineId, !serve, win).initialize().then(() => resolveAppReady()));
|
|
28
73
|
if (serve) {
|
|
29
|
-
Promise.resolve().then(() => require('electron-debug')).then(debug => {
|
|
74
|
+
Promise.resolve().then(() => require('electron-debug')).then((debug) => {
|
|
30
75
|
debug.default({ isEnabled: true, showDevTools: true });
|
|
31
76
|
});
|
|
32
|
-
Promise.resolve().then(() => require('electron-reloader')).then(reloader => {
|
|
77
|
+
Promise.resolve().then(() => require('electron-reloader')).then((reloader) => {
|
|
33
78
|
const reloaderFn = reloader.default || reloader;
|
|
34
79
|
// watchRenderer: false — Angular dev server handles HMR for the renderer.
|
|
35
80
|
// Without this, reloader triggers spurious reloads on macOS (issue #840).
|
|
@@ -58,10 +103,12 @@ function createWindow() {
|
|
|
58
103
|
return win;
|
|
59
104
|
}
|
|
60
105
|
try {
|
|
61
|
-
electron_1.protocol.registerSchemesAsPrivileged([
|
|
106
|
+
electron_1.protocol.registerSchemesAsPrivileged([
|
|
107
|
+
{
|
|
62
108
|
scheme: 'font',
|
|
63
|
-
privileges: { bypassCSP: true, supportFetchAPI: true }
|
|
64
|
-
}
|
|
109
|
+
privileges: { bypassCSP: true, supportFetchAPI: true },
|
|
110
|
+
},
|
|
111
|
+
]);
|
|
65
112
|
electron_1.ipcMain.handle('app:get-version', () => electron_1.app.getVersion());
|
|
66
113
|
electron_1.ipcMain.handle('app:ready', () => appReadyPromise);
|
|
67
114
|
// This method will be called when Electron has finished
|
|
@@ -69,9 +116,50 @@ try {
|
|
|
69
116
|
// Some APIs can only be used after this event occurs.
|
|
70
117
|
// Added 400 ms to fix the black background issue while using transparent window. More detais at https://github.com/electron/electron/issues/15947
|
|
71
118
|
electron_1.app.on('ready', () => {
|
|
72
|
-
electron_1.protocol.handle('font', (request) => {
|
|
119
|
+
electron_1.protocol.handle('font', (request) => __awaiter(void 0, void 0, void 0, function* () {
|
|
73
120
|
const filePath = decodeURIComponent(request.url.replace('font://', ''));
|
|
74
|
-
|
|
121
|
+
try {
|
|
122
|
+
return yield electron_1.net.fetch(`file://${filePath}`);
|
|
123
|
+
}
|
|
124
|
+
catch (_a) {
|
|
125
|
+
return new Response('Not found', { status: 404 });
|
|
126
|
+
}
|
|
127
|
+
}));
|
|
128
|
+
// --- Session: deny unnecessary permissions ---
|
|
129
|
+
electron_1.session.defaultSession.setPermissionRequestHandler((_webContents, permission, callback) => {
|
|
130
|
+
const allowed = ['clipboard-read', 'clipboard-sanitized-write'];
|
|
131
|
+
callback(allowed.includes(permission));
|
|
132
|
+
});
|
|
133
|
+
// --- Session: set CSP in production ---
|
|
134
|
+
if (!serve) {
|
|
135
|
+
electron_1.session.defaultSession.webRequest.onHeadersReceived((details, callback) => {
|
|
136
|
+
callback({
|
|
137
|
+
responseHeaders: Object.assign(Object.assign({}, details.responseHeaders), { 'Content-Security-Policy': [
|
|
138
|
+
"default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; font-src 'self' font:; img-src 'self' data: https:;",
|
|
139
|
+
] }),
|
|
140
|
+
});
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
// --- Power Monitor ---
|
|
144
|
+
electron_1.powerMonitor.on('suspend', () => {
|
|
145
|
+
if (win && !win.isDestroyed()) {
|
|
146
|
+
win.webContents.send(ChannelType_1.ChannelType.IPC_POWER_SUSPEND);
|
|
147
|
+
}
|
|
148
|
+
});
|
|
149
|
+
electron_1.powerMonitor.on('resume', () => {
|
|
150
|
+
if (win && !win.isDestroyed()) {
|
|
151
|
+
win.webContents.send(ChannelType_1.ChannelType.IPC_POWER_RESUME);
|
|
152
|
+
}
|
|
153
|
+
});
|
|
154
|
+
electron_1.powerMonitor.on('shutdown', () => {
|
|
155
|
+
if (win && !win.isDestroyed()) {
|
|
156
|
+
win.webContents.send(ChannelType_1.ChannelType.IPC_POWER_SHUTDOWN);
|
|
157
|
+
}
|
|
158
|
+
});
|
|
159
|
+
electron_1.powerMonitor.on('lock-screen', () => {
|
|
160
|
+
if (win && !win.isDestroyed()) {
|
|
161
|
+
win.webContents.send(ChannelType_1.ChannelType.IPC_POWER_LOCK_SCREEN);
|
|
162
|
+
}
|
|
75
163
|
});
|
|
76
164
|
setTimeout(createWindow, 400);
|
|
77
165
|
});
|
package/app/main.ts
CHANGED
|
@@ -1,18 +1,76 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
app,
|
|
3
|
+
BrowserWindow,
|
|
4
|
+
ipcMain,
|
|
5
|
+
nativeImage,
|
|
6
|
+
nativeTheme,
|
|
7
|
+
net,
|
|
8
|
+
powerMonitor,
|
|
9
|
+
protocol,
|
|
10
|
+
screen,
|
|
11
|
+
session,
|
|
12
|
+
systemPreferences,
|
|
13
|
+
} from 'electron';
|
|
2
14
|
import * as path from 'path';
|
|
3
15
|
import * as fs from 'fs';
|
|
4
16
|
import { machineId } from 'node-machine-id';
|
|
5
17
|
import Application from './Application';
|
|
18
|
+
import { ChannelType } from './enums/ChannelType';
|
|
19
|
+
import type { NativeThemeState, SystemPreferencesState } from './types';
|
|
20
|
+
|
|
21
|
+
app.name = 'Fontastic';
|
|
22
|
+
|
|
23
|
+
const iconPath = path.join(__dirname, '..', 'src', 'assets', 'icons', 'favicon.512x512.png');
|
|
24
|
+
|
|
25
|
+
app.setAboutPanelOptions({
|
|
26
|
+
applicationName: 'Fontastic',
|
|
27
|
+
applicationVersion: app.getVersion(),
|
|
28
|
+
iconPath,
|
|
29
|
+
});
|
|
6
30
|
|
|
7
31
|
let win: BrowserWindow | null = null;
|
|
8
32
|
let resolveAppReady: () => void;
|
|
9
|
-
const appReadyPromise = new Promise<void>(resolve => {
|
|
33
|
+
const appReadyPromise = new Promise<void>((resolve) => {
|
|
34
|
+
resolveAppReady = resolve;
|
|
35
|
+
});
|
|
10
36
|
|
|
11
37
|
const args = process.argv.slice(1),
|
|
12
|
-
serve = args.some(val => val === '--serve');
|
|
38
|
+
serve = args.some((val) => val === '--serve');
|
|
13
39
|
|
|
14
|
-
|
|
40
|
+
// --- Native Theme ---
|
|
41
|
+
|
|
42
|
+
function getNativeThemeState(): NativeThemeState {
|
|
43
|
+
return {
|
|
44
|
+
shouldUseDarkColors: nativeTheme.shouldUseDarkColors,
|
|
45
|
+
themeSource: nativeTheme.themeSource,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
ipcMain.handle(ChannelType.IPC_GET_NATIVE_THEME, () => getNativeThemeState());
|
|
50
|
+
|
|
51
|
+
nativeTheme.on('updated', () => {
|
|
52
|
+
if (win && !win.isDestroyed()) {
|
|
53
|
+
win.webContents.send(ChannelType.IPC_NATIVE_THEME_CHANGED, getNativeThemeState());
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
// --- System Preferences ---
|
|
58
|
+
|
|
59
|
+
function getSystemPreferencesState(): SystemPreferencesState {
|
|
60
|
+
let reduceMotion = false;
|
|
61
|
+
if (process.platform === 'darwin') {
|
|
62
|
+
reduceMotion = systemPreferences.getAnimationSettings().prefersReducedMotion;
|
|
63
|
+
}
|
|
15
64
|
|
|
65
|
+
return {
|
|
66
|
+
accentColor: systemPreferences.getAccentColor?.() ?? '',
|
|
67
|
+
reduceMotion,
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
ipcMain.handle(ChannelType.IPC_GET_SYSTEM_PREFERENCES, () => getSystemPreferencesState());
|
|
72
|
+
|
|
73
|
+
function createWindow(): BrowserWindow {
|
|
16
74
|
const size = screen.getPrimaryDisplay().workAreaSize;
|
|
17
75
|
|
|
18
76
|
// Create the browser window.
|
|
@@ -25,20 +83,18 @@ function createWindow(): BrowserWindow {
|
|
|
25
83
|
nodeIntegration: true,
|
|
26
84
|
allowRunningInsecureContent: serve,
|
|
27
85
|
contextIsolation: false,
|
|
28
|
-
webSecurity: !serve
|
|
86
|
+
webSecurity: !serve,
|
|
29
87
|
},
|
|
30
88
|
});
|
|
31
89
|
|
|
32
|
-
machineId(true).then((machineId: string) =>
|
|
33
|
-
new Application(machineId, !serve, win!).initialize().then(() => resolveAppReady())
|
|
34
|
-
);
|
|
90
|
+
machineId(true).then((machineId: string) => new Application(machineId, !serve, win!).initialize().then(() => resolveAppReady()));
|
|
35
91
|
|
|
36
92
|
if (serve) {
|
|
37
|
-
import('electron-debug').then(debug => {
|
|
38
|
-
debug.default({isEnabled: true, showDevTools: true});
|
|
93
|
+
import('electron-debug').then((debug) => {
|
|
94
|
+
debug.default({ isEnabled: true, showDevTools: true });
|
|
39
95
|
});
|
|
40
96
|
|
|
41
|
-
import('electron-reloader').then(reloader => {
|
|
97
|
+
import('electron-reloader').then((reloader) => {
|
|
42
98
|
const reloaderFn = (reloader as any).default || reloader;
|
|
43
99
|
// watchRenderer: false — Angular dev server handles HMR for the renderer.
|
|
44
100
|
// Without this, reloader triggers spurious reloads on macOS (issue #840).
|
|
@@ -50,7 +106,7 @@ function createWindow(): BrowserWindow {
|
|
|
50
106
|
let pathIndex = './browser/index.html';
|
|
51
107
|
|
|
52
108
|
if (fs.existsSync(path.join(__dirname, '../dist/browser/index.html'))) {
|
|
53
|
-
|
|
109
|
+
// Path when running electron in local folder
|
|
54
110
|
pathIndex = '../dist/browser/index.html';
|
|
55
111
|
}
|
|
56
112
|
|
|
@@ -71,10 +127,12 @@ function createWindow(): BrowserWindow {
|
|
|
71
127
|
}
|
|
72
128
|
|
|
73
129
|
try {
|
|
74
|
-
protocol.registerSchemesAsPrivileged([
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
130
|
+
protocol.registerSchemesAsPrivileged([
|
|
131
|
+
{
|
|
132
|
+
scheme: 'font',
|
|
133
|
+
privileges: { bypassCSP: true, supportFetchAPI: true },
|
|
134
|
+
},
|
|
135
|
+
]);
|
|
78
136
|
|
|
79
137
|
ipcMain.handle('app:get-version', () => app.getVersion());
|
|
80
138
|
ipcMain.handle('app:ready', () => appReadyPromise);
|
|
@@ -84,10 +142,60 @@ try {
|
|
|
84
142
|
// Some APIs can only be used after this event occurs.
|
|
85
143
|
// Added 400 ms to fix the black background issue while using transparent window. More detais at https://github.com/electron/electron/issues/15947
|
|
86
144
|
app.on('ready', () => {
|
|
87
|
-
protocol.handle('font', (request) => {
|
|
145
|
+
protocol.handle('font', async (request) => {
|
|
88
146
|
const filePath = decodeURIComponent(request.url.replace('font://', ''));
|
|
89
|
-
|
|
147
|
+
try {
|
|
148
|
+
return await net.fetch(`file://${filePath}`);
|
|
149
|
+
} catch {
|
|
150
|
+
return new Response('Not found', { status: 404 });
|
|
151
|
+
}
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
// --- Session: deny unnecessary permissions ---
|
|
155
|
+
session.defaultSession.setPermissionRequestHandler((_webContents, permission, callback) => {
|
|
156
|
+
const allowed = ['clipboard-read', 'clipboard-sanitized-write'];
|
|
157
|
+
callback(allowed.includes(permission));
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
// --- Session: set CSP in production ---
|
|
161
|
+
if (!serve) {
|
|
162
|
+
session.defaultSession.webRequest.onHeadersReceived((details, callback) => {
|
|
163
|
+
callback({
|
|
164
|
+
responseHeaders: {
|
|
165
|
+
...details.responseHeaders,
|
|
166
|
+
'Content-Security-Policy': [
|
|
167
|
+
"default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; font-src 'self' font:; img-src 'self' data: https:;",
|
|
168
|
+
],
|
|
169
|
+
},
|
|
170
|
+
});
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// --- Power Monitor ---
|
|
175
|
+
powerMonitor.on('suspend', () => {
|
|
176
|
+
if (win && !win.isDestroyed()) {
|
|
177
|
+
win.webContents.send(ChannelType.IPC_POWER_SUSPEND);
|
|
178
|
+
}
|
|
90
179
|
});
|
|
180
|
+
|
|
181
|
+
powerMonitor.on('resume', () => {
|
|
182
|
+
if (win && !win.isDestroyed()) {
|
|
183
|
+
win.webContents.send(ChannelType.IPC_POWER_RESUME);
|
|
184
|
+
}
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
powerMonitor.on('shutdown', () => {
|
|
188
|
+
if (win && !win.isDestroyed()) {
|
|
189
|
+
win.webContents.send(ChannelType.IPC_POWER_SHUTDOWN);
|
|
190
|
+
}
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
powerMonitor.on('lock-screen', () => {
|
|
194
|
+
if (win && !win.isDestroyed()) {
|
|
195
|
+
win.webContents.send(ChannelType.IPC_POWER_LOCK_SCREEN);
|
|
196
|
+
}
|
|
197
|
+
});
|
|
198
|
+
|
|
91
199
|
setTimeout(createWindow, 400);
|
|
92
200
|
});
|
|
93
201
|
|
|
@@ -107,7 +215,6 @@ try {
|
|
|
107
215
|
createWindow();
|
|
108
216
|
}
|
|
109
217
|
});
|
|
110
|
-
|
|
111
218
|
} catch (e) {
|
|
112
219
|
// Catch Error
|
|
113
220
|
// throw e;
|
package/app/package.json
CHANGED
package/app/types/index.js
CHANGED
|
@@ -24,4 +24,7 @@ __exportStar(require("./SystemStats"), exports);
|
|
|
24
24
|
__exportStar(require("./SystemConfig"), exports);
|
|
25
25
|
__exportStar(require("./ImportOptions"), exports);
|
|
26
26
|
__exportStar(require("./SmartCollection"), exports);
|
|
27
|
+
__exportStar(require("./NativeThemeState"), exports);
|
|
28
|
+
__exportStar(require("./SystemPreferencesState"), exports);
|
|
29
|
+
__exportStar(require("./ScanProgress"), exports);
|
|
27
30
|
//# sourceMappingURL=index.js.map
|