mirror of
https://github.com/ankitects/anki.git
synced 2025-11-09 22:27:12 -05:00
211 lines
6.2 KiB
Rust
211 lines
6.2 KiB
Rust
// Copyright: Ankitects Pty Ltd and contributors
|
|
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|
|
|
use anki_proto::generic;
|
|
use anki_proto::launcher::get_langs_response;
|
|
use anki_proto::launcher::get_mirrors_response;
|
|
use anki_proto::launcher::ChooseVersionRequest;
|
|
use anki_proto::launcher::ChooseVersionResponse;
|
|
use anki_proto::launcher::GetLangsResponse;
|
|
use anki_proto::launcher::GetMirrorsResponse;
|
|
use anki_proto::launcher::GetVersionsResponse;
|
|
use anki_proto::launcher::I18nResourcesRequest;
|
|
use anki_proto::launcher::Mirror;
|
|
use anki_proto::launcher::Options;
|
|
use anki_proto::launcher::ZoomWebviewRequest;
|
|
use anyhow::Context;
|
|
use anyhow::Result;
|
|
use strum::IntoEnumIterator;
|
|
use tauri::AppHandle;
|
|
use tauri::Manager;
|
|
use tauri::Runtime;
|
|
use tauri::WebviewWindow;
|
|
use tauri_plugin_os::locale;
|
|
|
|
use crate::lang::get_tr;
|
|
use crate::lang::setup_i18n;
|
|
use crate::lang::LANGS;
|
|
use crate::lang::LANGS_DEFAULT_REGION;
|
|
use crate::lang::LANGS_WITH_REGIONS;
|
|
use crate::uv;
|
|
|
|
pub async fn i18n_resources<R: Runtime>(
|
|
app: AppHandle<R>,
|
|
_window: WebviewWindow<R>,
|
|
input: I18nResourcesRequest,
|
|
) -> Result<generic::Json> {
|
|
let tr = get_tr(&app)?;
|
|
serde_json::to_vec(&tr.resources_for_js(&input.modules))
|
|
.with_context(|| "failed to serialise i18n resources")
|
|
.map(Into::into)
|
|
}
|
|
|
|
pub async fn get_langs<R: Runtime>(
|
|
_app: AppHandle<R>,
|
|
_window: WebviewWindow<R>,
|
|
) -> Result<GetLangsResponse> {
|
|
let langs = LANGS
|
|
.into_iter()
|
|
.map(|(locale, name)| get_langs_response::Pair {
|
|
name: name.to_string(),
|
|
locale: locale.to_string(),
|
|
})
|
|
.collect();
|
|
|
|
let user_locale = locale()
|
|
.and_then(|l| {
|
|
if LANGS.contains_key(&l) {
|
|
Some(l)
|
|
} else {
|
|
LANGS_DEFAULT_REGION
|
|
.get(l.split('-').next().unwrap())
|
|
.or_else(|| LANGS_DEFAULT_REGION.get("en"))
|
|
.map(ToString::to_string)
|
|
}
|
|
})
|
|
.unwrap();
|
|
|
|
Ok(GetLangsResponse { user_locale, langs })
|
|
}
|
|
|
|
pub async fn set_lang<R: Runtime>(
|
|
app: AppHandle<R>,
|
|
_window: WebviewWindow<R>,
|
|
input: generic::String,
|
|
) -> Result<()> {
|
|
// python's lang_to_disk_lang
|
|
let input = input.val;
|
|
let input = if LANGS_WITH_REGIONS.contains(input.as_str()) {
|
|
input
|
|
} else {
|
|
input.split('-').next().unwrap().to_owned()
|
|
};
|
|
setup_i18n(&app, &[&*input]);
|
|
Ok(())
|
|
}
|
|
|
|
pub async fn get_mirrors<R: Runtime>(
|
|
app: AppHandle<R>,
|
|
_window: WebviewWindow<R>,
|
|
) -> Result<GetMirrorsResponse> {
|
|
let tr = get_tr(&app)?;
|
|
Ok(GetMirrorsResponse {
|
|
mirrors: Mirror::iter()
|
|
.map(|mirror| get_mirrors_response::Pair {
|
|
mirror: mirror.into(),
|
|
name: match mirror {
|
|
Mirror::Disabled => tr.launcher_mirror_no_mirror(),
|
|
Mirror::China => tr.launcher_mirror_china(),
|
|
}
|
|
.into(),
|
|
})
|
|
.collect(),
|
|
})
|
|
}
|
|
|
|
pub async fn get_options<R: Runtime>(
|
|
app: AppHandle<R>,
|
|
_window: WebviewWindow<R>,
|
|
) -> Result<Options> {
|
|
let state = app.state::<uv::State>();
|
|
let allow_betas = state.prerelease_marker.exists();
|
|
let download_caching = !state.no_cache_marker.exists();
|
|
let mirror = if state.mirror_path.exists() {
|
|
Mirror::China
|
|
} else {
|
|
Mirror::Disabled
|
|
}
|
|
.into();
|
|
|
|
Ok(Options {
|
|
allow_betas,
|
|
download_caching,
|
|
mirror,
|
|
})
|
|
}
|
|
|
|
pub async fn get_versions<R: Runtime>(
|
|
app: AppHandle<R>,
|
|
_window: WebviewWindow<R>,
|
|
) -> Result<GetVersionsResponse> {
|
|
let state = (*app.state::<uv::State>()).clone();
|
|
// TODO: why...
|
|
let mut state1 = state.clone();
|
|
|
|
let releases_fut = tauri::async_runtime::spawn_blocking(move || uv::get_releases(&state));
|
|
let check_fut = tauri::async_runtime::spawn_blocking(move || uv::check_versions(&mut state1));
|
|
|
|
let (releases, check) = futures::future::join(releases_fut, check_fut).await;
|
|
// TODO: handle errors properly
|
|
let uv::Releases { latest, all } = releases.unwrap().unwrap();
|
|
let (current, previous) = check.unwrap().unwrap();
|
|
|
|
Ok(GetVersionsResponse {
|
|
latest,
|
|
all,
|
|
current,
|
|
previous,
|
|
})
|
|
}
|
|
|
|
pub async fn choose_version<R: Runtime>(
|
|
app: AppHandle<R>,
|
|
_window: WebviewWindow<R>,
|
|
input: ChooseVersionRequest,
|
|
) -> Result<ChooseVersionResponse> {
|
|
let state = (*app.state::<uv::State>()).clone();
|
|
let version = input.version.clone();
|
|
|
|
tauri::async_runtime::spawn_blocking(move || -> Result<()> {
|
|
if let Some(options) = input.options {
|
|
uv::set_allow_betas(&state, options.allow_betas)?;
|
|
uv::set_cache_enabled(&state, options.download_caching)?;
|
|
uv::set_mirror(&state, options.mirror != Mirror::Disabled as i32)?;
|
|
}
|
|
|
|
if !input.keep_existing || state.pyproject_modified_by_user {
|
|
// install or resync
|
|
let res = uv::handle_version_install_or_update(
|
|
app.clone(),
|
|
&state,
|
|
&input.version,
|
|
input.keep_existing,
|
|
);
|
|
println!("handle_version_install_or_update: {res:?}");
|
|
res?;
|
|
}
|
|
|
|
uv::post_install(&state)?;
|
|
|
|
// TODO: show some sort of notification before closing
|
|
// if let Some(window) = app.get_webview_window("main") {
|
|
// let _ = window.destroy();
|
|
// }
|
|
// // app.exit can't be called from the main thread
|
|
// app.exit(0);
|
|
|
|
Ok(())
|
|
})
|
|
.await??;
|
|
|
|
Ok(ChooseVersionResponse { version })
|
|
}
|
|
|
|
/// NOTE: [zoomHotkeysEnabled](https://v2.tauri.app/reference/config/#zoomhotkeysenabled) exists
|
|
/// but the polyfill it uses on lin doesn't allow regular scrolling
|
|
pub async fn zoom_webview<R: Runtime>(
|
|
_app: AppHandle<R>,
|
|
window: WebviewWindow<R>,
|
|
input: ZoomWebviewRequest,
|
|
) -> Result<()> {
|
|
let factor = input.scale_factor.into();
|
|
// NOTE: not supported on windows
|
|
let _ = window.set_zoom(factor);
|
|
Ok(())
|
|
}
|
|
|
|
pub async fn window_ready<R: Runtime>(_app: AppHandle<R>, window: WebviewWindow<R>) -> Result<()> {
|
|
window
|
|
.show()
|
|
.with_context(|| format!("could not show window: {}", window.label()))
|
|
}
|