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;
}
}
}