add ui zoom level setting

This commit is contained in:
pierre
2023-12-21 14:25:15 +01:00
parent 46d68e5448
commit 1ea78e8e97
14 changed files with 102 additions and 4 deletions
+1 -1
View File
@@ -1,5 +1,5 @@
<!doctype html>
<html lang="en" class="text-[14px]">
<html lang="en" class="text-[12px]">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
@@ -78,6 +78,28 @@ pub async fn set_ui_theme(
Ok(())
}
#[instrument(skip(data_state))]
#[tauri::command]
pub async fn set_root_font_size(
data_state: State<'_, SharedAppData>,
size: u32,
) -> Result<(), CmdError> {
debug!("set_root_font_size");
let mut app_data_store = data_state.lock().await;
let mut app_data = app_data_store
.read()
.await
.map_err(|e| CmdError::new(CmdErrorSource::InternalError, e.to_string()))?;
app_data.ui_root_font_size = Some(size);
app_data_store.data = app_data;
app_data_store
.write()
.await
.map_err(|e| CmdError::new(CmdErrorSource::InternalError, e.to_string()))?;
Ok(())
}
#[instrument(skip(data_state))]
#[tauri::command]
pub async fn set_entry_location_selector(
+1
View File
@@ -19,6 +19,7 @@ pub struct AppData {
pub killswitch: Option<bool>,
pub entry_location_selector: Option<bool>,
pub ui_theme: Option<UiTheme>,
pub ui_root_font_size: Option<u32>,
pub vpn_mode: Option<VpnMode>,
pub entry_node: Option<NodeConfig>,
pub exit_node: Option<NodeConfig>,
+1
View File
@@ -109,6 +109,7 @@ async fn main() -> Result<()> {
app_data::set_ui_theme,
app_data::set_entry_location_selector,
app_data::get_node_countries,
app_data::set_root_font_size,
node_location::set_node_location,
node_location::get_default_node_location,
])
+2
View File
@@ -9,3 +9,5 @@ export const AppName = 'NymVPN';
export const ConnectionEvent = 'connection-state';
export const ProgressEvent = 'connection-progress';
export const QuickConnectPrefix = 'Fastest';
// TODO ⚠ keep this value in sync with the one declared in `index.html`
export const DefaultRootFontSize = 12; // in px
+5
View File
@@ -65,6 +65,10 @@ export function mockTauriIPC() {
);
}
if (cmd === 'set_root_font_size') {
return new Promise<void>((resolve) => resolve());
}
if (cmd === 'get_app_data') {
return new Promise<AppDataFromBackend>((resolve) =>
resolve({
@@ -73,6 +77,7 @@ export function mockTauriIPC() {
killswitch: false,
entry_location_selector: false,
ui_theme: 'Dark',
ui_root_font_size: 12,
vpn_mode: 'TwoHop',
entry_node: {
country: {
+3 -1
View File
@@ -90,7 +90,9 @@ function Home() {
</div>
<Button
className={clsx([
'rounded-lg text-lg font-bold py-4 px-6 h-16 focus:outline-none focus:ring-4 focus:ring-black focus:dark:ring-white shadow',
'flex justify-center items-center',
'rounded-lg text-lg font-bold py-4 px-6 h-16',
'focus:outline-none focus:ring-4 focus:ring-black focus:dark:ring-white shadow',
(state === 'Disconnected' || state === 'Connecting') &&
'bg-melon text-white dark:text-baltic-sea',
(state === 'Connected' || state === 'Disconnecting') &&
+1 -1
View File
@@ -46,7 +46,7 @@ export default function HopSelect({
/>
<div className="text-base">{country.name}</div>
</div>
<span className="font-icon scale-150 pointer-events-none">
<span className="font-icon text-2xl pointer-events-none">
arrow_right
</span>
</div>
@@ -4,6 +4,7 @@ import { invoke } from '@tauri-apps/api';
import { Switch } from '@headlessui/react';
import { useMainDispatch, useMainState } from '../../contexts';
import { StateDispatch } from '../../types';
import UiScaler from './UiScaler';
function Settings() {
const state = useMainState();
@@ -55,6 +56,7 @@ function Settings() {
/>
</Switch>
</div>
<UiScaler />
</div>
);
}
@@ -0,0 +1,47 @@
import { ChangeEvent, useEffect, useState } from 'react';
import { invoke } from '@tauri-apps/api';
import { useMainDispatch, useMainState } from '../../contexts';
import { CmdError, StateDispatch } from '../../types';
function UiScaler() {
const [slideValue, setSlideValue] = useState(12);
const dispatch = useMainDispatch() as StateDispatch;
const { rootFontSize } = useMainState();
useEffect(() => {
setSlideValue(rootFontSize);
}, [rootFontSize]);
const handleChange = (e: ChangeEvent<HTMLInputElement>) => {
setSlideValue(parseInt(e.target.value));
dispatch({ type: 'set-root-font-size', size: slideValue });
};
const setNewFontSize = () => {
document.documentElement.style.fontSize = `${slideValue}px`;
dispatch({ type: 'set-root-font-size', size: slideValue });
invoke('set_root_font_size', { size: slideValue }).catch((e: CmdError) => {
console.warn(`backend error: ${e.source} - ${e.message}`);
});
};
return (
<div className="flex flex-row justify-between items-center gap-10">
<p className="text-lg text-baltic-sea dark:text-mercury-pinkish flex-nowrap">
{`Zoom level: ${slideValue}`}
</p>
<input
type="range"
min="8"
max="20"
value={slideValue}
onChange={handleChange}
onMouseUp={setNewFontSize}
onKeyUp={setNewFontSize}
className="range flex flex-1 accent-melon"
/>
</div>
);
}
export default UiScaler;
+8 -1
View File
@@ -26,7 +26,8 @@ export type StateAction =
| { type: 'set-ui-theme'; theme: UiTheme }
| { type: 'set-countries'; countries: Country[] }
| { type: 'set-node-location'; payload: { hop: NodeHop; country: Country } }
| { type: 'set-default-node-location'; country: Country };
| { type: 'set-default-node-location'; country: Country }
| { type: 'set-root-font-size'; size: number };
export const initialState: AppState = {
state: 'Disconnected',
@@ -43,6 +44,7 @@ export const initialState: AppState = {
code: 'FR',
},
countries: [],
rootFontSize: 12,
};
export function reducer(state: AppState, action: StateAction): AppState {
@@ -145,6 +147,11 @@ export function reducer(state: AppState, action: StateAction): AppState {
...state,
defaultNodeLocation: action.country,
};
case 'set-root-font-size':
return {
...state,
rootFontSize: action.size,
};
case 'reset':
return initialState;
}
+7
View File
@@ -7,6 +7,7 @@ import {
ConnectionState,
Country,
} from '../types';
import { DefaultRootFontSize } from '../constants';
import { initialState, reducer } from './main';
import { useTauriEvents } from './useTauriEvents';
@@ -89,10 +90,16 @@ export function MainStateProvider({ children }: Props) {
.then((data) => {
console.log('app data read from disk:');
console.log(data);
if (data.ui_root_font_size) {
document.documentElement.style.fontSize = `${data.ui_root_font_size}px`;
}
const partialState: Partial<typeof initialState> = {
entrySelector: data.entry_location_selector || false,
uiTheme: data.ui_theme || 'Light',
vpnMode: data.vpn_mode || 'TwoHop',
rootFontSize: data.ui_root_font_size || DefaultRootFontSize,
};
if (data.entry_node_location) {
partialState.entryNodeLocation = data.entry_node_location;
+1
View File
@@ -19,6 +19,7 @@ export interface AppDataFromBackend {
killswitch: boolean | null;
entry_location_selector: boolean | null;
ui_theme: UiTheme | null;
ui_root_font_size: number | null;
vpn_mode: VpnMode | null;
entry_node: NodeConfig | null;
exit_node: NodeConfig | null;
+1
View File
@@ -31,6 +31,7 @@ export type AppState = {
exitNodeLocation: Country | null;
defaultNodeLocation: Country;
countries: Country[];
rootFontSize: number;
};
export type ConnectionEventPayload = {