~cytrogen/fluent-reader-mobile

ref: 34469ca0231cd9ea216f42aab16cb9e3714bb4e7 fluent-reader-mobile/lib/utils/font_manager.dart -rw-r--r-- 3.4 KiB
34469ca0 — HallowDem feat: enhance custom font upload with WebView rendering, WOFF/WOFF2 support, preview & deletion 4 days ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
import 'dart:io';
import 'package:path_provider/path_provider.dart';

class FontManager {
  static const supportedExtensions = ['.ttf', '.otf', '.woff', '.woff2'];
  static const builtInFonts = ['System', 'OpenSans', 'Roboto', 'SourceSerif'];

  static Future<Directory> getFontsDirectory() async {
    final directory = await getApplicationDocumentsDirectory();
    final fontsDir = Directory('${directory.path}/fonts');
    if (!await fontsDir.exists()) {
      await fontsDir.create(recursive: true);
    }
    return fontsDir;
  }

  static Future<String> installCustomFont(String sourcePath, String fileName) async {
    try {
      final fontsDir = await getFontsDirectory();
      final sourceFile = File(sourcePath);

      // Basic validation: fonts should be > 1KB and < 50MB
      final fileSize = await sourceFile.length();
      if (fileSize < 1024 || fileSize > 50 * 1024 * 1024) {
        throw Exception('Invalid font file size');
      }

      final targetPath = '${fontsDir.path}/$fileName';
      final targetFile = await sourceFile.copy(targetPath);
      return targetFile.path;
    } catch (e) {
      throw Exception('Failed to install custom font: $e');
    }
  }

  static Future<List<String>> getInstalledCustomFonts() async {
    try {
      final fontsDir = await getFontsDirectory();
      final files = await fontsDir.list().toList();
      return files
          .where((file) => file is File &&
                 supportedExtensions.any((ext) => file.path.toLowerCase().endsWith(ext)))
          .map((file) {
            final fileName = file.path.split(Platform.pathSeparator).last;
            return fileName.split('.').first;
          })
          .toList();
    } catch (e) {
      return [];
    }
  }

  /// Get the full file name (with extension) for a given font name
  static Future<String?> getFontFileName(String fontName) async {
    final fontsDir = await getFontsDirectory();
    final files = await fontsDir.list().toList();
    for (final file in files) {
      if (file is File) {
        final fileName = file.path.split(Platform.pathSeparator).last;
        final nameWithoutExt = fileName.split('.').first;
        if (nameWithoutExt == fontName) {
          return fileName;
        }
      }
    }
    return null;
  }

  /// Get the local server URL for a custom font
  static Future<String?> getCustomFontUrl(String fontName) async {
    final fileName = await getFontFileName(fontName);
    if (fileName == null) return null;
    return 'http://127.0.0.1:9000/custom-fonts/${Uri.encodeComponent(fileName)}';
  }

  static Future<void> removeCustomFont(String fontName) async {
    try {
      final fontsDir = await getFontsDirectory();
      final files = await fontsDir.list().toList();
      for (final file in files) {
        if (file is File) {
          final fileName = file.path.split(Platform.pathSeparator).last;
          final nameWithoutExt = fileName.split('.').first;
          if (nameWithoutExt == fontName) {
            await file.delete();
            break;
          }
        }
      }
    } catch (e) {
      throw Exception('Failed to remove custom font: $e');
    }
  }

  static String getFontDisplayName(String fontFamily) {
    switch (fontFamily) {
      case 'System':
        return 'System Font';
      case 'OpenSans':
        return 'Open Sans';
      case 'SourceSerif':
        return 'Source Serif';
      default:
        return fontFamily;
    }
  }
}