2026-06-02 23:28:39 +02:00
|
|
|
|
class ThemeProfile {
|
|
|
|
|
|
final String name;
|
|
|
|
|
|
final String slideBackgroundColor;
|
|
|
|
|
|
final String textColor;
|
|
|
|
|
|
final String accentColor;
|
2026-06-09 13:28:23 +02:00
|
|
|
|
final String checklistCheckedColor;
|
|
|
|
|
|
final String checklistUncheckedColor;
|
|
|
|
|
|
final bool checklistStrikeThrough;
|
2026-06-02 23:28:39 +02:00
|
|
|
|
final String tableTextColor;
|
|
|
|
|
|
final String tableHeaderTextColor;
|
|
|
|
|
|
final String titleBackgroundColor;
|
|
|
|
|
|
final String titleTextColor;
|
|
|
|
|
|
final String sectionBackgroundColor;
|
2026-06-08 13:51:29 +02:00
|
|
|
|
|
|
|
|
|
|
/// Colours for code (broncode) slides. Defaults mirror the atom-one-dark
|
|
|
|
|
|
/// editor look. Set e.g. black background + bright green text with
|
|
|
|
|
|
/// [codeHighlightSyntax] off for a classic CRT terminal feel.
|
|
|
|
|
|
final String codeBackgroundColor;
|
|
|
|
|
|
final String codeTextColor;
|
|
|
|
|
|
|
|
|
|
|
|
/// When false, code is shown monochrome in [codeTextColor] (no per-token
|
|
|
|
|
|
/// syntax colours) — required for a believable single-colour CRT screen.
|
|
|
|
|
|
final bool codeHighlightSyntax;
|
|
|
|
|
|
|
2026-06-08 14:28:04 +02:00
|
|
|
|
/// Monospace font family for code slides. `monospace` uses the system default;
|
|
|
|
|
|
/// e.g. `Courier New` for a typewriter look.
|
|
|
|
|
|
final String codeFontFamily;
|
|
|
|
|
|
|
2026-06-02 23:28:39 +02:00
|
|
|
|
final String? logoPath;
|
|
|
|
|
|
final String logoPosition;
|
|
|
|
|
|
final int logoSize;
|
|
|
|
|
|
|
|
|
|
|
|
/// Lettertype van de presentatie — hoort bij de stijl, niet bij de app.
|
|
|
|
|
|
final String fontFamily;
|
|
|
|
|
|
|
|
|
|
|
|
/// Vrije footertekst onderaan elke slide. Ondersteunt tokens: {page},
|
|
|
|
|
|
/// {total}, {date}, {title}. Leeg = geen footertekst.
|
|
|
|
|
|
final String footerText;
|
|
|
|
|
|
|
|
|
|
|
|
/// Toon "pagina / totaal" rechtsonder op elke slide.
|
|
|
|
|
|
final bool footerShowPageNumbers;
|
|
|
|
|
|
|
|
|
|
|
|
/// Horizontale positie van de footer: left, center of right.
|
|
|
|
|
|
final String footerPosition;
|
|
|
|
|
|
|
2026-06-05 00:02:51 +02:00
|
|
|
|
/// Optional markdown slide that is appended when presenting/exporting with
|
|
|
|
|
|
/// this theme profile. It stays out of the editable deck slide list.
|
|
|
|
|
|
final bool closingSlideEnabled;
|
|
|
|
|
|
final String closingSlideMarkdown;
|
|
|
|
|
|
|
2026-06-02 23:28:39 +02:00
|
|
|
|
const ThemeProfile({
|
|
|
|
|
|
this.name = 'Standaard',
|
|
|
|
|
|
this.slideBackgroundColor = '#FFFFFF',
|
|
|
|
|
|
this.textColor = '#222222',
|
|
|
|
|
|
this.accentColor = '#2E7D64',
|
2026-06-09 13:28:23 +02:00
|
|
|
|
this.checklistCheckedColor = '#2E7D64',
|
|
|
|
|
|
this.checklistUncheckedColor = '#CBD5E1',
|
|
|
|
|
|
this.checklistStrikeThrough = true,
|
2026-06-02 23:28:39 +02:00
|
|
|
|
String? tableTextColor,
|
|
|
|
|
|
this.tableHeaderTextColor = '#FFFFFF',
|
|
|
|
|
|
this.titleBackgroundColor = '#1C2B47',
|
|
|
|
|
|
this.titleTextColor = '#FFFFFF',
|
|
|
|
|
|
this.sectionBackgroundColor = '#2E7D64',
|
2026-06-08 13:51:29 +02:00
|
|
|
|
this.codeBackgroundColor = '#282C34',
|
|
|
|
|
|
this.codeTextColor = '#ABB2BF',
|
|
|
|
|
|
this.codeHighlightSyntax = true,
|
2026-06-08 14:28:04 +02:00
|
|
|
|
this.codeFontFamily = 'monospace',
|
2026-06-02 23:28:39 +02:00
|
|
|
|
this.logoPath,
|
|
|
|
|
|
this.logoPosition = 'bottom-right',
|
|
|
|
|
|
this.logoSize = 96,
|
|
|
|
|
|
this.fontFamily = 'Arial',
|
|
|
|
|
|
this.footerText = '',
|
|
|
|
|
|
this.footerShowPageNumbers = false,
|
|
|
|
|
|
this.footerPosition = 'right',
|
2026-06-05 00:02:51 +02:00
|
|
|
|
this.closingSlideEnabled = false,
|
|
|
|
|
|
this.closingSlideMarkdown = '# Bedankt\n\nVragen?',
|
2026-06-02 23:28:39 +02:00
|
|
|
|
}) : tableTextColor = tableTextColor ?? textColor;
|
|
|
|
|
|
|
|
|
|
|
|
static const logoPositions = [
|
|
|
|
|
|
'top-left',
|
|
|
|
|
|
'top-right',
|
|
|
|
|
|
'bottom-left',
|
|
|
|
|
|
'bottom-right',
|
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
|
|
static const footerPositions = ['left', 'center', 'right'];
|
|
|
|
|
|
|
|
|
|
|
|
ThemeProfile copyWith({
|
|
|
|
|
|
String? name,
|
|
|
|
|
|
String? slideBackgroundColor,
|
|
|
|
|
|
String? textColor,
|
|
|
|
|
|
String? accentColor,
|
2026-06-09 13:28:23 +02:00
|
|
|
|
String? checklistCheckedColor,
|
|
|
|
|
|
String? checklistUncheckedColor,
|
|
|
|
|
|
bool? checklistStrikeThrough,
|
2026-06-02 23:28:39 +02:00
|
|
|
|
String? tableTextColor,
|
|
|
|
|
|
String? tableHeaderTextColor,
|
|
|
|
|
|
String? titleBackgroundColor,
|
|
|
|
|
|
String? titleTextColor,
|
|
|
|
|
|
String? sectionBackgroundColor,
|
2026-06-08 13:51:29 +02:00
|
|
|
|
String? codeBackgroundColor,
|
|
|
|
|
|
String? codeTextColor,
|
|
|
|
|
|
bool? codeHighlightSyntax,
|
2026-06-08 14:28:04 +02:00
|
|
|
|
String? codeFontFamily,
|
2026-06-02 23:28:39 +02:00
|
|
|
|
String? logoPath,
|
|
|
|
|
|
String? logoPosition,
|
|
|
|
|
|
int? logoSize,
|
|
|
|
|
|
String? fontFamily,
|
|
|
|
|
|
String? footerText,
|
|
|
|
|
|
bool? footerShowPageNumbers,
|
|
|
|
|
|
String? footerPosition,
|
2026-06-05 00:02:51 +02:00
|
|
|
|
bool? closingSlideEnabled,
|
|
|
|
|
|
String? closingSlideMarkdown,
|
2026-06-02 23:28:39 +02:00
|
|
|
|
bool clearLogo = false,
|
|
|
|
|
|
}) {
|
|
|
|
|
|
return ThemeProfile(
|
|
|
|
|
|
name: name ?? this.name,
|
|
|
|
|
|
slideBackgroundColor: slideBackgroundColor ?? this.slideBackgroundColor,
|
|
|
|
|
|
textColor: textColor ?? this.textColor,
|
|
|
|
|
|
accentColor: accentColor ?? this.accentColor,
|
2026-06-09 13:28:23 +02:00
|
|
|
|
checklistCheckedColor:
|
|
|
|
|
|
checklistCheckedColor ?? this.checklistCheckedColor,
|
|
|
|
|
|
checklistUncheckedColor:
|
|
|
|
|
|
checklistUncheckedColor ?? this.checklistUncheckedColor,
|
|
|
|
|
|
checklistStrikeThrough:
|
|
|
|
|
|
checklistStrikeThrough ?? this.checklistStrikeThrough,
|
2026-06-02 23:28:39 +02:00
|
|
|
|
tableTextColor: tableTextColor ?? this.tableTextColor,
|
|
|
|
|
|
tableHeaderTextColor: tableHeaderTextColor ?? this.tableHeaderTextColor,
|
|
|
|
|
|
titleBackgroundColor: titleBackgroundColor ?? this.titleBackgroundColor,
|
|
|
|
|
|
titleTextColor: titleTextColor ?? this.titleTextColor,
|
|
|
|
|
|
sectionBackgroundColor:
|
|
|
|
|
|
sectionBackgroundColor ?? this.sectionBackgroundColor,
|
2026-06-08 13:51:29 +02:00
|
|
|
|
codeBackgroundColor: codeBackgroundColor ?? this.codeBackgroundColor,
|
|
|
|
|
|
codeTextColor: codeTextColor ?? this.codeTextColor,
|
|
|
|
|
|
codeHighlightSyntax: codeHighlightSyntax ?? this.codeHighlightSyntax,
|
2026-06-08 14:28:04 +02:00
|
|
|
|
codeFontFamily: codeFontFamily ?? this.codeFontFamily,
|
2026-06-02 23:28:39 +02:00
|
|
|
|
logoPath: clearLogo ? null : (logoPath ?? this.logoPath),
|
|
|
|
|
|
logoPosition: logoPosition ?? this.logoPosition,
|
|
|
|
|
|
logoSize: logoSize ?? this.logoSize,
|
|
|
|
|
|
fontFamily: fontFamily ?? this.fontFamily,
|
|
|
|
|
|
footerText: footerText ?? this.footerText,
|
|
|
|
|
|
footerShowPageNumbers:
|
|
|
|
|
|
footerShowPageNumbers ?? this.footerShowPageNumbers,
|
|
|
|
|
|
footerPosition: footerPosition ?? this.footerPosition,
|
2026-06-05 00:02:51 +02:00
|
|
|
|
closingSlideEnabled: closingSlideEnabled ?? this.closingSlideEnabled,
|
|
|
|
|
|
closingSlideMarkdown: closingSlideMarkdown ?? this.closingSlideMarkdown,
|
2026-06-02 23:28:39 +02:00
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Map<String, Object?> toJson() {
|
|
|
|
|
|
return {
|
|
|
|
|
|
'slideBackgroundColor': slideBackgroundColor,
|
|
|
|
|
|
'name': name,
|
|
|
|
|
|
'textColor': textColor,
|
|
|
|
|
|
'accentColor': accentColor,
|
2026-06-09 13:28:23 +02:00
|
|
|
|
'checklistCheckedColor': checklistCheckedColor,
|
|
|
|
|
|
'checklistUncheckedColor': checklistUncheckedColor,
|
|
|
|
|
|
'checklistStrikeThrough': checklistStrikeThrough,
|
2026-06-02 23:28:39 +02:00
|
|
|
|
'tableTextColor': tableTextColor,
|
|
|
|
|
|
'tableHeaderTextColor': tableHeaderTextColor,
|
|
|
|
|
|
'titleBackgroundColor': titleBackgroundColor,
|
|
|
|
|
|
'titleTextColor': titleTextColor,
|
|
|
|
|
|
'sectionBackgroundColor': sectionBackgroundColor,
|
2026-06-08 13:51:29 +02:00
|
|
|
|
'codeBackgroundColor': codeBackgroundColor,
|
|
|
|
|
|
'codeTextColor': codeTextColor,
|
|
|
|
|
|
'codeHighlightSyntax': codeHighlightSyntax,
|
2026-06-08 14:28:04 +02:00
|
|
|
|
'codeFontFamily': codeFontFamily,
|
2026-06-02 23:28:39 +02:00
|
|
|
|
'logoPath': logoPath,
|
|
|
|
|
|
'logoPosition': logoPosition,
|
|
|
|
|
|
'logoSize': logoSize,
|
|
|
|
|
|
'fontFamily': fontFamily,
|
|
|
|
|
|
'footerText': footerText,
|
|
|
|
|
|
'footerShowPageNumbers': footerShowPageNumbers,
|
|
|
|
|
|
'footerPosition': footerPosition,
|
2026-06-05 00:02:51 +02:00
|
|
|
|
'closingSlideEnabled': closingSlideEnabled,
|
|
|
|
|
|
'closingSlideMarkdown': closingSlideMarkdown,
|
2026-06-02 23:28:39 +02:00
|
|
|
|
};
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
factory ThemeProfile.fromJson(Map<String, Object?> json) {
|
|
|
|
|
|
return ThemeProfile(
|
|
|
|
|
|
slideBackgroundColor:
|
|
|
|
|
|
json['slideBackgroundColor'] as String? ?? '#FFFFFF',
|
|
|
|
|
|
name: json['name'] as String? ?? 'Standaard',
|
|
|
|
|
|
textColor: json['textColor'] as String? ?? '#222222',
|
|
|
|
|
|
accentColor: json['accentColor'] as String? ?? '#2E7D64',
|
2026-06-09 13:28:23 +02:00
|
|
|
|
checklistCheckedColor:
|
|
|
|
|
|
json['checklistCheckedColor'] as String? ??
|
|
|
|
|
|
json['accentColor'] as String? ??
|
|
|
|
|
|
'#2E7D64',
|
|
|
|
|
|
checklistUncheckedColor:
|
|
|
|
|
|
json['checklistUncheckedColor'] as String? ?? '#CBD5E1',
|
|
|
|
|
|
checklistStrikeThrough: json['checklistStrikeThrough'] as bool? ?? true,
|
2026-06-02 23:28:39 +02:00
|
|
|
|
tableTextColor:
|
|
|
|
|
|
json['tableTextColor'] as String? ??
|
|
|
|
|
|
json['textColor'] as String? ??
|
|
|
|
|
|
'#222222',
|
|
|
|
|
|
tableHeaderTextColor:
|
|
|
|
|
|
json['tableHeaderTextColor'] as String? ?? '#FFFFFF',
|
|
|
|
|
|
titleBackgroundColor:
|
|
|
|
|
|
json['titleBackgroundColor'] as String? ?? '#1C2B47',
|
|
|
|
|
|
titleTextColor: json['titleTextColor'] as String? ?? '#FFFFFF',
|
|
|
|
|
|
sectionBackgroundColor:
|
|
|
|
|
|
json['sectionBackgroundColor'] as String? ?? '#2E7D64',
|
2026-06-09 13:28:23 +02:00
|
|
|
|
codeBackgroundColor: json['codeBackgroundColor'] as String? ?? '#282C34',
|
2026-06-08 13:51:29 +02:00
|
|
|
|
codeTextColor: json['codeTextColor'] as String? ?? '#ABB2BF',
|
|
|
|
|
|
codeHighlightSyntax: json['codeHighlightSyntax'] as bool? ?? true,
|
2026-06-08 14:28:04 +02:00
|
|
|
|
codeFontFamily: json['codeFontFamily'] as String? ?? 'monospace',
|
2026-06-02 23:28:39 +02:00
|
|
|
|
logoPath: json['logoPath'] as String?,
|
|
|
|
|
|
logoPosition: json['logoPosition'] as String? ?? 'bottom-right',
|
|
|
|
|
|
logoSize: (json['logoSize'] as num?)?.round() ?? 96,
|
|
|
|
|
|
fontFamily: json['fontFamily'] as String? ?? 'Arial',
|
|
|
|
|
|
footerText: json['footerText'] as String? ?? '',
|
|
|
|
|
|
footerShowPageNumbers: json['footerShowPageNumbers'] as bool? ?? false,
|
|
|
|
|
|
footerPosition: json['footerPosition'] as String? ?? 'right',
|
2026-06-05 00:02:51 +02:00
|
|
|
|
closingSlideEnabled: json['closingSlideEnabled'] as bool? ?? false,
|
|
|
|
|
|
closingSlideMarkdown:
|
|
|
|
|
|
json['closingSlideMarkdown'] as String? ?? '# Bedankt\n\nVragen?',
|
2026-06-02 23:28:39 +02:00
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-06-06 20:41:24 +02:00
|
|
|
|
class AppAppearanceProfile {
|
|
|
|
|
|
final String name;
|
|
|
|
|
|
final bool isBuiltIn;
|
|
|
|
|
|
final bool isDark;
|
|
|
|
|
|
final String primaryColor;
|
|
|
|
|
|
final String accentColor;
|
|
|
|
|
|
final String backgroundColor;
|
|
|
|
|
|
final String surfaceColor;
|
|
|
|
|
|
final String textColor;
|
|
|
|
|
|
final String mutedTextColor;
|
|
|
|
|
|
final String panelColor;
|
|
|
|
|
|
final String panelTextColor;
|
|
|
|
|
|
|
|
|
|
|
|
const AppAppearanceProfile({
|
|
|
|
|
|
required this.name,
|
|
|
|
|
|
this.isBuiltIn = false,
|
|
|
|
|
|
this.isDark = false,
|
|
|
|
|
|
required this.primaryColor,
|
|
|
|
|
|
required this.accentColor,
|
|
|
|
|
|
required this.backgroundColor,
|
|
|
|
|
|
required this.surfaceColor,
|
|
|
|
|
|
required this.textColor,
|
|
|
|
|
|
required this.mutedTextColor,
|
|
|
|
|
|
required this.panelColor,
|
|
|
|
|
|
required this.panelTextColor,
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
static const basic = AppAppearanceProfile(
|
|
|
|
|
|
name: 'Basic',
|
|
|
|
|
|
isBuiltIn: true,
|
|
|
|
|
|
primaryColor: '#1C2B47',
|
|
|
|
|
|
accentColor: '#2563EB',
|
|
|
|
|
|
backgroundColor: '#F8F9FA',
|
|
|
|
|
|
surfaceColor: '#FFFFFF',
|
|
|
|
|
|
textColor: '#1E293B',
|
|
|
|
|
|
mutedTextColor: '#64748B',
|
|
|
|
|
|
panelColor: '#1E2028',
|
|
|
|
|
|
panelTextColor: '#E2E8F0',
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
static const europa = AppAppearanceProfile(
|
|
|
|
|
|
name: 'Europa',
|
|
|
|
|
|
isBuiltIn: true,
|
|
|
|
|
|
primaryColor: '#003399',
|
|
|
|
|
|
accentColor: '#FFCC00',
|
|
|
|
|
|
backgroundColor: '#F4F7FC',
|
|
|
|
|
|
surfaceColor: '#FFFFFF',
|
|
|
|
|
|
textColor: '#17233D',
|
|
|
|
|
|
mutedTextColor: '#5D6B85',
|
|
|
|
|
|
panelColor: '#00266F',
|
|
|
|
|
|
panelTextColor: '#FFFFFF',
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
static const dark = AppAppearanceProfile(
|
|
|
|
|
|
name: 'Donker',
|
|
|
|
|
|
isBuiltIn: true,
|
|
|
|
|
|
isDark: true,
|
|
|
|
|
|
primaryColor: '#111827',
|
|
|
|
|
|
accentColor: '#60A5FA',
|
|
|
|
|
|
backgroundColor: '#0F172A',
|
|
|
|
|
|
surfaceColor: '#1E293B',
|
|
|
|
|
|
textColor: '#F1F5F9',
|
|
|
|
|
|
mutedTextColor: '#94A3B8',
|
|
|
|
|
|
panelColor: '#090E1A',
|
|
|
|
|
|
panelTextColor: '#E2E8F0',
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
static const builtIns = [basic, europa, dark];
|
|
|
|
|
|
|
|
|
|
|
|
AppAppearanceProfile copyWith({
|
|
|
|
|
|
String? name,
|
|
|
|
|
|
bool? isBuiltIn,
|
|
|
|
|
|
bool? isDark,
|
|
|
|
|
|
String? primaryColor,
|
|
|
|
|
|
String? accentColor,
|
|
|
|
|
|
String? backgroundColor,
|
|
|
|
|
|
String? surfaceColor,
|
|
|
|
|
|
String? textColor,
|
|
|
|
|
|
String? mutedTextColor,
|
|
|
|
|
|
String? panelColor,
|
|
|
|
|
|
String? panelTextColor,
|
|
|
|
|
|
}) {
|
|
|
|
|
|
return AppAppearanceProfile(
|
|
|
|
|
|
name: name ?? this.name,
|
|
|
|
|
|
isBuiltIn: isBuiltIn ?? this.isBuiltIn,
|
|
|
|
|
|
isDark: isDark ?? this.isDark,
|
|
|
|
|
|
primaryColor: primaryColor ?? this.primaryColor,
|
|
|
|
|
|
accentColor: accentColor ?? this.accentColor,
|
|
|
|
|
|
backgroundColor: backgroundColor ?? this.backgroundColor,
|
|
|
|
|
|
surfaceColor: surfaceColor ?? this.surfaceColor,
|
|
|
|
|
|
textColor: textColor ?? this.textColor,
|
|
|
|
|
|
mutedTextColor: mutedTextColor ?? this.mutedTextColor,
|
|
|
|
|
|
panelColor: panelColor ?? this.panelColor,
|
|
|
|
|
|
panelTextColor: panelTextColor ?? this.panelTextColor,
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Map<String, Object?> toJson() {
|
|
|
|
|
|
return {
|
|
|
|
|
|
'name': name,
|
|
|
|
|
|
'isBuiltIn': isBuiltIn,
|
|
|
|
|
|
'isDark': isDark,
|
|
|
|
|
|
'primaryColor': primaryColor,
|
|
|
|
|
|
'accentColor': accentColor,
|
|
|
|
|
|
'backgroundColor': backgroundColor,
|
|
|
|
|
|
'surfaceColor': surfaceColor,
|
|
|
|
|
|
'textColor': textColor,
|
|
|
|
|
|
'mutedTextColor': mutedTextColor,
|
|
|
|
|
|
'panelColor': panelColor,
|
|
|
|
|
|
'panelTextColor': panelTextColor,
|
|
|
|
|
|
};
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
factory AppAppearanceProfile.fromJson(Map<String, Object?> json) {
|
|
|
|
|
|
return AppAppearanceProfile(
|
|
|
|
|
|
name: json['name'] as String? ?? 'Eigen thema',
|
|
|
|
|
|
isBuiltIn: json['isBuiltIn'] as bool? ?? false,
|
|
|
|
|
|
isDark: json['isDark'] as bool? ?? false,
|
|
|
|
|
|
primaryColor: json['primaryColor'] as String? ?? basic.primaryColor,
|
|
|
|
|
|
accentColor: json['accentColor'] as String? ?? basic.accentColor,
|
|
|
|
|
|
backgroundColor:
|
|
|
|
|
|
json['backgroundColor'] as String? ?? basic.backgroundColor,
|
|
|
|
|
|
surfaceColor: json['surfaceColor'] as String? ?? basic.surfaceColor,
|
|
|
|
|
|
textColor: json['textColor'] as String? ?? basic.textColor,
|
|
|
|
|
|
mutedTextColor: json['mutedTextColor'] as String? ?? basic.mutedTextColor,
|
|
|
|
|
|
panelColor: json['panelColor'] as String? ?? basic.panelColor,
|
|
|
|
|
|
panelTextColor: json['panelTextColor'] as String? ?? basic.panelTextColor,
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-06-02 23:28:39 +02:00
|
|
|
|
class AppSettings {
|
2026-06-04 02:30:03 +02:00
|
|
|
|
final String languageCode;
|
2026-06-02 23:28:39 +02:00
|
|
|
|
final String? homeDirectory;
|
2026-06-03 15:03:27 +02:00
|
|
|
|
|
|
|
|
|
|
/// Folder where all exports (PDF/PPTX) are written. When null, exports land
|
|
|
|
|
|
/// next to the source deck (legacy behaviour).
|
|
|
|
|
|
final String? exportDirectory;
|
2026-06-02 23:28:39 +02:00
|
|
|
|
final List<ThemeProfile> themeProfiles;
|
|
|
|
|
|
final String selectedThemeProfileName;
|
2026-06-06 20:41:24 +02:00
|
|
|
|
final List<AppAppearanceProfile> appAppearanceProfiles;
|
|
|
|
|
|
final String selectedAppAppearanceProfileName;
|
2026-06-02 23:28:39 +02:00
|
|
|
|
final List<String> recentFiles;
|
|
|
|
|
|
|
2026-06-12 00:26:29 +02:00
|
|
|
|
/// Optioneel vrijgaveplafond voor de classificatie-gate, opgeslagen als
|
|
|
|
|
|
/// TLP-sleutel (zie `TlpLevelX.key`). `null` = geen plafond, alles mag worden
|
|
|
|
|
|
/// geëxporteerd (standaard). Classificeren blijft optioneel; dit plafond
|
|
|
|
|
|
/// blokkeert alleen decks die er bovenuit zijn geclassificeerd.
|
|
|
|
|
|
final String? maxReleaseExportTlpKey;
|
|
|
|
|
|
|
Add image-library dedupe and untagged filter, UI text scaling, table paste
Image library:
- "Clean up duplicates" finds byte-identical images by md5, keeps one
file per group (preferring the most-used, then the oldest), merges
the tags/descriptions and captions of the copies, repoints slides in
open decks and in .md presentations on disk, and deletes the copies
after a confirmation that lists every group.
- A header toggle filters to images without tags/description, so it is
easy to see which ones still need attention.
- The delete warning now also lists presentations on disk that still
reference the image (marked "not open"), next to the open decks.
Editor and accessibility (already in tree):
- Interface text scaling up to 200%, keyboard-operable panel divider,
keyboard-first add-slide dialog, and screen-reader improvements.
- Paste a spreadsheet/CSV/markdown selection into a table cell to fill
the whole grid.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-11 13:36:44 +02:00
|
|
|
|
/// Scale factor for all interface text (1.0–2.0), on top of the system
|
|
|
|
|
|
/// text scaling. The slide canvas itself is never scaled: slides are a
|
|
|
|
|
|
/// fixed 16:9 design surface. WCAG 1.4.4 asks for text resizing up to 200%.
|
|
|
|
|
|
final double uiTextScale;
|
|
|
|
|
|
|
2026-06-02 23:28:39 +02:00
|
|
|
|
const AppSettings({
|
2026-06-04 02:30:03 +02:00
|
|
|
|
this.languageCode = 'nl',
|
2026-06-02 23:28:39 +02:00
|
|
|
|
this.homeDirectory,
|
2026-06-03 15:03:27 +02:00
|
|
|
|
this.exportDirectory,
|
2026-06-02 23:28:39 +02:00
|
|
|
|
this.themeProfiles = const [ThemeProfile()],
|
|
|
|
|
|
this.selectedThemeProfileName = 'Standaard',
|
2026-06-06 20:41:24 +02:00
|
|
|
|
this.appAppearanceProfiles = AppAppearanceProfile.builtIns,
|
|
|
|
|
|
this.selectedAppAppearanceProfileName = 'Basic',
|
2026-06-02 23:28:39 +02:00
|
|
|
|
this.recentFiles = const [],
|
2026-06-12 00:26:29 +02:00
|
|
|
|
this.maxReleaseExportTlpKey,
|
Add image-library dedupe and untagged filter, UI text scaling, table paste
Image library:
- "Clean up duplicates" finds byte-identical images by md5, keeps one
file per group (preferring the most-used, then the oldest), merges
the tags/descriptions and captions of the copies, repoints slides in
open decks and in .md presentations on disk, and deletes the copies
after a confirmation that lists every group.
- A header toggle filters to images without tags/description, so it is
easy to see which ones still need attention.
- The delete warning now also lists presentations on disk that still
reference the image (marked "not open"), next to the open decks.
Editor and accessibility (already in tree):
- Interface text scaling up to 200%, keyboard-operable panel divider,
keyboard-first add-slide dialog, and screen-reader improvements.
- Paste a spreadsheet/CSV/markdown selection into a table cell to fill
the whole grid.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-11 13:36:44 +02:00
|
|
|
|
this.uiTextScale = 1.0,
|
2026-06-02 23:28:39 +02:00
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
ThemeProfile get themeProfile {
|
|
|
|
|
|
return themeProfiles.firstWhere(
|
|
|
|
|
|
(p) => p.name == selectedThemeProfileName,
|
|
|
|
|
|
orElse: () => themeProfiles.first,
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-06-06 20:41:24 +02:00
|
|
|
|
AppAppearanceProfile get appAppearanceProfile {
|
|
|
|
|
|
return appAppearanceProfiles.firstWhere(
|
|
|
|
|
|
(p) => p.name == selectedAppAppearanceProfileName,
|
|
|
|
|
|
orElse: () => appAppearanceProfiles.first,
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-06-02 23:28:39 +02:00
|
|
|
|
static const availableFonts = [
|
|
|
|
|
|
'Arial',
|
|
|
|
|
|
'EB Garamond',
|
|
|
|
|
|
'Helvetica Neue',
|
|
|
|
|
|
'Verdana',
|
|
|
|
|
|
'Trebuchet MS',
|
|
|
|
|
|
'Georgia',
|
|
|
|
|
|
'Times New Roman',
|
|
|
|
|
|
'Gill Sans MT',
|
|
|
|
|
|
'Calibri',
|
|
|
|
|
|
'Segoe UI',
|
|
|
|
|
|
'Courier New',
|
|
|
|
|
|
];
|
|
|
|
|
|
|
2026-06-08 14:28:04 +02:00
|
|
|
|
/// Monospace families offered for code slides. `monospace` is the system
|
|
|
|
|
|
/// default; the rest are common typewriter/coding faces.
|
|
|
|
|
|
static const codeFonts = [
|
|
|
|
|
|
'monospace',
|
|
|
|
|
|
'Courier New',
|
|
|
|
|
|
'Menlo',
|
|
|
|
|
|
'Consolas',
|
|
|
|
|
|
'Roboto Mono',
|
|
|
|
|
|
'Cascadia Code',
|
|
|
|
|
|
];
|
|
|
|
|
|
|
2026-06-02 23:28:39 +02:00
|
|
|
|
AppSettings copyWith({
|
2026-06-04 02:30:03 +02:00
|
|
|
|
String? languageCode,
|
2026-06-02 23:28:39 +02:00
|
|
|
|
String? homeDirectory,
|
2026-06-03 15:03:27 +02:00
|
|
|
|
String? exportDirectory,
|
2026-06-02 23:28:39 +02:00
|
|
|
|
ThemeProfile? themeProfile,
|
|
|
|
|
|
List<ThemeProfile>? themeProfiles,
|
|
|
|
|
|
String? selectedThemeProfileName,
|
2026-06-06 20:41:24 +02:00
|
|
|
|
List<AppAppearanceProfile>? appAppearanceProfiles,
|
|
|
|
|
|
String? selectedAppAppearanceProfileName,
|
2026-06-02 23:28:39 +02:00
|
|
|
|
List<String>? recentFiles,
|
2026-06-12 00:26:29 +02:00
|
|
|
|
String? maxReleaseExportTlpKey,
|
Add image-library dedupe and untagged filter, UI text scaling, table paste
Image library:
- "Clean up duplicates" finds byte-identical images by md5, keeps one
file per group (preferring the most-used, then the oldest), merges
the tags/descriptions and captions of the copies, repoints slides in
open decks and in .md presentations on disk, and deletes the copies
after a confirmation that lists every group.
- A header toggle filters to images without tags/description, so it is
easy to see which ones still need attention.
- The delete warning now also lists presentations on disk that still
reference the image (marked "not open"), next to the open decks.
Editor and accessibility (already in tree):
- Interface text scaling up to 200%, keyboard-operable panel divider,
keyboard-first add-slide dialog, and screen-reader improvements.
- Paste a spreadsheet/CSV/markdown selection into a table cell to fill
the whole grid.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-11 13:36:44 +02:00
|
|
|
|
double? uiTextScale,
|
2026-06-02 23:28:39 +02:00
|
|
|
|
bool clearHomeDirectory = false,
|
2026-06-03 15:03:27 +02:00
|
|
|
|
bool clearExportDirectory = false,
|
2026-06-12 00:26:29 +02:00
|
|
|
|
bool clearMaxReleaseExportTlp = false,
|
2026-06-02 23:28:39 +02:00
|
|
|
|
}) {
|
|
|
|
|
|
final nextProfiles = themeProfiles ?? this.themeProfiles;
|
|
|
|
|
|
return AppSettings(
|
2026-06-04 02:30:03 +02:00
|
|
|
|
languageCode: languageCode ?? this.languageCode,
|
2026-06-02 23:28:39 +02:00
|
|
|
|
homeDirectory: clearHomeDirectory
|
|
|
|
|
|
? null
|
|
|
|
|
|
: (homeDirectory ?? this.homeDirectory),
|
2026-06-03 15:03:27 +02:00
|
|
|
|
exportDirectory: clearExportDirectory
|
|
|
|
|
|
? null
|
|
|
|
|
|
: (exportDirectory ?? this.exportDirectory),
|
2026-06-02 23:28:39 +02:00
|
|
|
|
themeProfiles: themeProfile == null
|
|
|
|
|
|
? nextProfiles
|
|
|
|
|
|
: [
|
|
|
|
|
|
for (final profile in nextProfiles)
|
|
|
|
|
|
if (profile.name == themeProfile.name)
|
|
|
|
|
|
themeProfile
|
|
|
|
|
|
else
|
|
|
|
|
|
profile,
|
|
|
|
|
|
if (!nextProfiles.any((p) => p.name == themeProfile.name))
|
|
|
|
|
|
themeProfile,
|
|
|
|
|
|
],
|
|
|
|
|
|
selectedThemeProfileName:
|
|
|
|
|
|
selectedThemeProfileName ??
|
|
|
|
|
|
themeProfile?.name ??
|
|
|
|
|
|
this.selectedThemeProfileName,
|
2026-06-06 20:41:24 +02:00
|
|
|
|
appAppearanceProfiles:
|
|
|
|
|
|
appAppearanceProfiles ?? this.appAppearanceProfiles,
|
|
|
|
|
|
selectedAppAppearanceProfileName:
|
|
|
|
|
|
selectedAppAppearanceProfileName ??
|
|
|
|
|
|
this.selectedAppAppearanceProfileName,
|
2026-06-02 23:28:39 +02:00
|
|
|
|
recentFiles: recentFiles ?? this.recentFiles,
|
2026-06-12 00:26:29 +02:00
|
|
|
|
maxReleaseExportTlpKey: clearMaxReleaseExportTlp
|
|
|
|
|
|
? null
|
|
|
|
|
|
: (maxReleaseExportTlpKey ?? this.maxReleaseExportTlpKey),
|
Add image-library dedupe and untagged filter, UI text scaling, table paste
Image library:
- "Clean up duplicates" finds byte-identical images by md5, keeps one
file per group (preferring the most-used, then the oldest), merges
the tags/descriptions and captions of the copies, repoints slides in
open decks and in .md presentations on disk, and deletes the copies
after a confirmation that lists every group.
- A header toggle filters to images without tags/description, so it is
easy to see which ones still need attention.
- The delete warning now also lists presentations on disk that still
reference the image (marked "not open"), next to the open decks.
Editor and accessibility (already in tree):
- Interface text scaling up to 200%, keyboard-operable panel divider,
keyboard-first add-slide dialog, and screen-reader improvements.
- Paste a spreadsheet/CSV/markdown selection into a table cell to fill
the whole grid.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-11 13:36:44 +02:00
|
|
|
|
uiTextScale: uiTextScale ?? this.uiTextScale,
|
2026-06-02 23:28:39 +02:00
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|