feat: load system fonts list at runtime on desktop, closes #287 #237 (#290)

This commit is contained in:
Huang Xin
2025-02-03 00:41:30 +01:00
committed by GitHub
parent dc6cbd2029
commit 93eacf91a0
7 changed files with 137 additions and 12 deletions
+1 -1
View File
@@ -22,7 +22,7 @@ jobs:
- name: Install system dependencies
run: |
sudo apt-get update
sudo apt-get install -y libglib2.0-dev libgtk-3-dev libwebkit2gtk-4.1-dev libappindicator3-dev librsvg2-dev libsoup-3.0-dev
sudo apt-get install -y pkg-config libfontconfig-dev libglib2.0-dev libgtk-3-dev libwebkit2gtk-4.1-dev libappindicator3-dev librsvg2-dev libsoup-3.0-dev
- name: Format
working-directory: apps/readest-app/src-tauri
run: cargo fmt --check
+1 -1
View File
@@ -121,7 +121,7 @@ jobs:
if: matrix.config.os == 'ubuntu-22.04'
run: |
sudo apt-get update
sudo apt-get install -y libgtk-3-dev libwebkit2gtk-4.1-dev libappindicator3-dev librsvg2-dev patchelf
sudo apt-get install -y pkg-config libfontconfig-dev libgtk-3-dev libwebkit2gtk-4.1-dev libappindicator3-dev librsvg2-dev patchelf
- uses: tauri-apps/tauri-action@v0
env:
Generated
+69
View File
@@ -7,6 +7,7 @@ name = "Readest"
version = "0.2.1"
dependencies = [
"cocoa 0.25.0",
"font-enumeration",
"futures-util",
"log",
"objc",
@@ -1030,6 +1031,18 @@ dependencies = [
"libc",
]
[[package]]
name = "core-text"
version = "20.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c9d2790b5c08465d49f8dc05c8bcae9fea467855947db39b0f8145c091aaced5"
dependencies = [
"core-foundation 0.9.4",
"core-graphics 0.23.2",
"foreign-types",
"libc",
]
[[package]]
name = "cpufeatures"
version = "0.2.17"
@@ -1388,6 +1401,20 @@ version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813"
[[package]]
name = "dwrote"
version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "70182709525a3632b2ba96b6569225467b18ecb4a77f46d255f713a6bebf05fd"
dependencies = [
"lazy_static",
"libc",
"serde",
"serde_derive",
"winapi",
"wio",
]
[[package]]
name = "dyn-clone"
version = "1.0.18"
@@ -1575,6 +1602,28 @@ version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
[[package]]
name = "font-enumeration"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "378034ff1da05aa11a0a3882bfa929cda6d0273c30008240aea04cd3936e0902"
dependencies = [
"core-text",
"dwrote",
"fontconfig",
"log",
"thiserror 1.0.69",
]
[[package]]
name = "fontconfig"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b60f7d9b14055dddd3b3ab0e511ecfdf49f02e7e31b09f9111de3e424ea7bb4b"
dependencies = [
"yeslogic-fontconfig-sys",
]
[[package]]
name = "foreign-types"
version = "0.5.0"
@@ -6907,6 +6956,15 @@ dependencies = [
"windows-sys 0.48.0",
]
[[package]]
name = "wio"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5d129932f4644ac2396cb456385cbf9e63b5b30c6e8dc4820bdca4eb082037a5"
dependencies = [
"winapi",
]
[[package]]
name = "wit-bindgen-rt"
version = "0.33.0"
@@ -7023,6 +7081,17 @@ dependencies = [
"windows-sys 0.59.0",
]
[[package]]
name = "yeslogic-fontconfig-sys"
version = "6.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "503a066b4c037c440169d995b869046827dbc71263f6e8f3be6d77d4f3229dbd"
dependencies = [
"dlib",
"once_cell",
"pkg-config",
]
[[package]]
name = "yoke"
version = "0.7.5"
+1
View File
@@ -57,3 +57,4 @@ tauri-plugin-cli = "2"
tauri-plugin-single-instance = "2.2.0"
tauri-plugin-updater = "2"
tauri-plugin-window-state = "2.2.0"
font-enumeration = "0.9.0"
+14 -1
View File
@@ -72,6 +72,17 @@ async fn start_server(window: Window) -> Result<u16, String> {
.map_err(|err| err.to_string())
}
#[cfg(desktop)]
#[command]
async fn list_fonts() -> Result<Vec<String>, String> {
let font_collection = font_enumeration::Collection::new().unwrap();
let mut fonts = Vec::new();
for font in font_collection.all() {
fonts.push(font.font_name.clone());
}
Ok(fonts)
}
#[derive(Clone, serde::Serialize)]
struct Payload {
args: Vec<String>,
@@ -86,7 +97,9 @@ pub fn run() {
.invoke_handler(tauri::generate_handler![
start_server,
download_file,
upload_file
upload_file,
#[cfg(desktop)]
list_fonts
])
.plugin(tauri_plugin_shell::init())
.plugin(tauri_plugin_opener::init())
@@ -19,6 +19,7 @@ import { useTranslation } from '@/hooks/useTranslation';
import { useTheme } from '@/hooks/useTheme';
import { getStyles } from '@/utils/style';
import { getOSPlatform } from '@/utils/misc';
import { FONT_ENUM_SUPPORTED_OS_PLATFORMS, getSysFontsList } from '@/utils/font';
interface FontFaceProps {
className?: string;
@@ -67,26 +68,27 @@ const FontPanel: React.FC<{ bookKey: string }> = ({ bookKey }) => {
const { themeCode } = useTheme();
const osPlatform = getOSPlatform();
let moreFonts: string[] = [];
let defaultSysFonts: string[] = [];
switch (osPlatform) {
case 'macos':
moreFonts = MACOS_FONTS;
defaultSysFonts = MACOS_FONTS;
break;
case 'windows':
moreFonts = WINDOWS_FONTS;
defaultSysFonts = WINDOWS_FONTS;
break;
case 'linux':
moreFonts = LINUX_FONTS;
defaultSysFonts = LINUX_FONTS;
break;
case 'ios':
moreFonts = IOS_FONTS;
defaultSysFonts = IOS_FONTS;
break;
case 'android':
moreFonts = ANDROID_FONTS;
defaultSysFonts = ANDROID_FONTS;
break;
default:
break;
}
const [sysFonts, setSysFonts] = useState<string[]>(defaultSysFonts);
const [defaultFontSize, setDefaultFontSize] = useState(viewSettings.defaultFontSize!);
const [minFontSize, setMinFontSize] = useState(viewSettings.minimumFontSize!);
const [overrideFont, setOverrideFont] = useState(viewSettings.overrideFont!);
@@ -95,6 +97,15 @@ const FontPanel: React.FC<{ bookKey: string }> = ({ bookKey }) => {
const [sansSerifFont, setSansSerifFont] = useState(viewSettings.sansSerifFont!);
const [monospaceFont, setMonospaceFont] = useState(viewSettings.monospaceFont!);
useEffect(() => {
if (FONT_ENUM_SUPPORTED_OS_PLATFORMS.includes(osPlatform)) {
getSysFontsList().then((fonts) => {
setSysFonts(fonts);
});
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
useEffect(() => {
viewSettings.defaultFont = defaultFont;
setViewSettings(bookKey, viewSettings);
@@ -247,7 +258,7 @@ const FontPanel: React.FC<{ bookKey: string }> = ({ bookKey }) => {
family='serif'
label={_('Serif Font')}
options={SERIF_FONTS}
moreOptions={moreFonts}
moreOptions={sysFonts}
selected={serifFont}
onSelect={setSerifFont}
/>
@@ -255,7 +266,7 @@ const FontPanel: React.FC<{ bookKey: string }> = ({ bookKey }) => {
family='sans-serif'
label={_('Sans-Serif Font')}
options={SANS_SERIF_FONTS}
moreOptions={moreFonts}
moreOptions={sysFonts}
selected={sansSerifFont}
onSelect={setSansSerifFont}
/>
@@ -264,7 +275,7 @@ const FontPanel: React.FC<{ bookKey: string }> = ({ bookKey }) => {
family='monospace'
label={_('Monospace Font')}
options={MONOSPACE_FONTS}
moreOptions={moreFonts}
moreOptions={sysFonts}
selected={monospaceFont}
onSelect={setMonospaceFont}
/>
+31
View File
@@ -0,0 +1,31 @@
import { invoke } from '@tauri-apps/api/core';
import { getOSPlatform } from './misc';
let cachedSysFonts: string[] | null = null;
export const FONT_ENUM_SUPPORTED_OS_PLATFORMS = ['macos', 'windows', 'linux'];
const isSymbolicFontName = (font: string) =>
/emoji|icons|symbol|dingbats|ornaments|webdings|wingdings/i.test(font);
export const getSysFontsList = async (): Promise<string[]> => {
if (cachedSysFonts) {
return cachedSysFonts;
}
try {
const osPlatform = getOSPlatform();
if (FONT_ENUM_SUPPORTED_OS_PLATFORMS.includes(osPlatform)) {
const fonts = await invoke<string[]>('list_fonts');
cachedSysFonts = fonts.filter((font) => !isSymbolicFontName(font)).sort();
console.log('Fetched font list:', cachedSysFonts);
return cachedSysFonts;
} else {
console.warn(`Unsupported platform: ${osPlatform}`);
return [];
}
} catch (error) {
console.error('Error fetching font list:', error);
return [];
}
};