mirror of
https://github.com/an-anime-team/an-anime-game-launcher.git
synced 2024-11-22 04:46:08 +03:00
feat: added voice packages selection to settings
This commit is contained in:
parent
6cc5b26561
commit
f5231fe637
6 changed files with 198 additions and 60 deletions
|
@ -12,6 +12,7 @@ background-downloading-failed = Download des Hintergrundbildes fehlgeschlagen
|
|||
config-update-error = Speichern der Konfiguration fehlgeschlagen
|
||||
wine-prefix-update-failed = Aktualisierung des wine prefix fehlgeschlagen
|
||||
dxvk-install-failed = DXVK konnte nicht installiert werden
|
||||
voice-package-deletion-error = Failed to delete voice package
|
||||
|
||||
game-diff-finding-error = Spiel-Diff nicht gefunden
|
||||
patch-info-fetching-error = Patch-Informationen konnten nicht abgerufen werden
|
||||
|
|
|
@ -12,6 +12,7 @@ background-downloading-failed = Failed to download background picture
|
|||
config-update-error = Failed to save config
|
||||
wine-prefix-update-failed = Failed to update wine prefix
|
||||
dxvk-install-failed = Failed to install DXVK
|
||||
voice-package-deletion-error = Failed to delete voice package
|
||||
|
||||
game-diff-finding-error = Failed to find game diff
|
||||
patch-info-fetching-error = Failed to fetch patch info
|
||||
|
|
|
@ -12,6 +12,7 @@ background-downloading-failed = Не удалось загрузить фоно
|
|||
config-update-error = Ошибка сохранения настроек
|
||||
wine-prefix-update-failed = Ошибка обновления префикса Wine
|
||||
dxvk-install-failed = Ошибка установки DXVK
|
||||
voice-package-deletion-error = Не удалось удалить языковой пакет
|
||||
|
||||
game-diff-finding-error = Не удалось вычислить обновление игры
|
||||
patch-info-fetching-error = Не удалось получить информацию о патче
|
||||
|
|
|
@ -637,6 +637,8 @@ impl SimpleComponent for App {
|
|||
AppMsg::UpdateLauncherState { perform_on_download_needed, show_status_page } => {
|
||||
if show_status_page {
|
||||
sender.input(AppMsg::SetLoadingStatus(Some(Some(tr("loading-launcher-state")))));
|
||||
} else {
|
||||
self.disabled_buttons = true;
|
||||
}
|
||||
|
||||
let updater = clone!(@strong sender => move |state| {
|
||||
|
@ -676,6 +678,8 @@ impl SimpleComponent for App {
|
|||
|
||||
if show_status_page {
|
||||
sender.input(AppMsg::SetLoadingStatus(None));
|
||||
} else {
|
||||
self.disabled_buttons = false;
|
||||
}
|
||||
|
||||
if perform_on_download_needed {
|
||||
|
|
|
@ -1,5 +1,10 @@
|
|||
use relm4::prelude::*;
|
||||
use relm4::component::*;
|
||||
use relm4::factory::{
|
||||
AsyncFactoryVecDeque,
|
||||
AsyncFactoryComponent,
|
||||
AsyncFactorySender
|
||||
};
|
||||
|
||||
use gtk::prelude::*;
|
||||
use adw::prelude::*;
|
||||
|
@ -10,12 +15,92 @@ use anime_launcher_sdk::anime_game_core::prelude::*;
|
|||
use anime_launcher_sdk::components::*;
|
||||
use anime_launcher_sdk::wincompatlib::prelude::*;
|
||||
|
||||
use super::main::PreferencesAppMsg;
|
||||
use crate::ui::components;
|
||||
use crate::ui::components::*;
|
||||
use crate::i18n::*;
|
||||
use crate::*;
|
||||
|
||||
#[derive(Debug)]
|
||||
struct VoicePackageComponent {
|
||||
locale: VoiceLocale,
|
||||
installed: bool,
|
||||
sensitive: bool
|
||||
}
|
||||
|
||||
#[relm4::factory(async)]
|
||||
impl AsyncFactoryComponent for VoicePackageComponent {
|
||||
type Init = (VoiceLocale, bool);
|
||||
type Input = GeneralAppMsg;
|
||||
type Output = GeneralAppMsg;
|
||||
type CommandOutput = ();
|
||||
type ParentInput = GeneralAppMsg;
|
||||
type ParentWidget = adw::ExpanderRow;
|
||||
|
||||
view! {
|
||||
root = adw::ActionRow {
|
||||
set_title: &tr(&self.locale.to_name().to_ascii_lowercase()),
|
||||
|
||||
add_suffix = >k::Button {
|
||||
#[watch]
|
||||
set_visible: self.installed,
|
||||
|
||||
#[watch]
|
||||
set_sensitive: self.sensitive,
|
||||
|
||||
set_icon_name: "user-trash-symbolic",
|
||||
add_css_class: "flat",
|
||||
set_valign: gtk::Align::Center,
|
||||
|
||||
connect_clicked[sender, index] => move |_| {
|
||||
sender.input(GeneralAppMsg::RemoveVoicePackage(index.clone()));
|
||||
}
|
||||
},
|
||||
|
||||
add_suffix = >k::Button {
|
||||
#[watch]
|
||||
set_visible: !self.installed,
|
||||
|
||||
#[watch]
|
||||
set_sensitive: self.sensitive,
|
||||
|
||||
set_icon_name: "document-save-symbolic",
|
||||
add_css_class: "flat",
|
||||
set_valign: gtk::Align::Center,
|
||||
|
||||
connect_clicked[sender, index] => move |_| {
|
||||
sender.input(GeneralAppMsg::AddVoicePackage(index.clone()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn output_to_parent_input(output: Self::Output) -> Option<Self::ParentInput> {
|
||||
Some(output)
|
||||
}
|
||||
|
||||
async fn init_model(
|
||||
init: Self::Init,
|
||||
_index: &DynamicIndex,
|
||||
_sender: AsyncFactorySender<Self>,
|
||||
) -> Self {
|
||||
Self {
|
||||
locale: init.0,
|
||||
installed: init.1,
|
||||
sensitive: true
|
||||
}
|
||||
}
|
||||
|
||||
async fn update(&mut self, msg: Self::Input, sender: AsyncFactorySender<Self>) {
|
||||
self.installed = !self.installed;
|
||||
|
||||
sender.output(msg);
|
||||
}
|
||||
}
|
||||
|
||||
pub struct GeneralApp {
|
||||
voice_packages: AsyncFactoryVecDeque<VoicePackageComponent>,
|
||||
|
||||
wine_components: AsyncController<ComponentsList<GeneralAppMsg>>,
|
||||
dxvk_components: AsyncController<ComponentsList<GeneralAppMsg>>,
|
||||
|
||||
|
@ -46,27 +131,38 @@ pub enum GeneralAppMsg {
|
|||
/// was retrieved from remote repos
|
||||
SetPatch(Option<Patch>),
|
||||
|
||||
// If one ever wich to change it to accept VoiceLocale
|
||||
// I'd recommend to use clone!(@strong self.locale as locale => move |_| { .. })
|
||||
// in the VoicePackage component
|
||||
AddVoicePackage(DynamicIndex),
|
||||
RemoveVoicePackage(DynamicIndex),
|
||||
SetVoicePackageSensitivity(DynamicIndex, bool),
|
||||
|
||||
UpdateLauncherStyle(LauncherStyle),
|
||||
|
||||
WineRecommendedOnly(bool),
|
||||
DxvkRecommendedOnly(bool),
|
||||
|
||||
UpdateDownloadedWine,
|
||||
UpdateDownloadedDxvk,
|
||||
|
||||
SelectWine(usize),
|
||||
SelectDxvk(usize),
|
||||
|
||||
ResetWineSelection(usize),
|
||||
ResetDxvkSelection(usize),
|
||||
|
||||
Toast {
|
||||
title: String,
|
||||
description: Option<String>
|
||||
},
|
||||
|
||||
UpdateLauncherStyle(LauncherStyle),
|
||||
WineRecommendedOnly(bool),
|
||||
DxvkRecommendedOnly(bool),
|
||||
UpdateDownloadedWine,
|
||||
UpdateDownloadedDxvk,
|
||||
SelectWine(usize),
|
||||
SelectDxvk(usize),
|
||||
ResetWineSelection(usize),
|
||||
ResetDxvkSelection(usize)
|
||||
}
|
||||
}
|
||||
|
||||
#[relm4::component(async, pub)]
|
||||
impl SimpleAsyncComponent for GeneralApp {
|
||||
type Init = ();
|
||||
type Input = GeneralAppMsg;
|
||||
type Output = super::main::PreferencesAppMsg;
|
||||
type Output = PreferencesAppMsg;
|
||||
|
||||
view! {
|
||||
adw::PreferencesPage {
|
||||
|
@ -192,48 +288,9 @@ impl SimpleAsyncComponent for GeneralApp {
|
|||
}
|
||||
},
|
||||
|
||||
adw::ExpanderRow {
|
||||
set_title: &tr("game-voiceovers"),
|
||||
|
||||
add_row = &adw::ActionRow {
|
||||
set_title: &tr("english"),
|
||||
|
||||
add_suffix = >k::Button {
|
||||
add_css_class: "flat",
|
||||
set_icon_name: "user-trash-symbolic",
|
||||
set_valign: gtk::Align::Center
|
||||
}
|
||||
},
|
||||
|
||||
add_row = &adw::ActionRow {
|
||||
set_title: &tr("japanese"),
|
||||
|
||||
add_suffix = >k::Button {
|
||||
add_css_class: "flat",
|
||||
set_icon_name: "user-trash-symbolic",
|
||||
set_valign: gtk::Align::Center
|
||||
}
|
||||
},
|
||||
|
||||
add_row = &adw::ActionRow {
|
||||
set_title: &tr("korean"),
|
||||
|
||||
add_suffix = >k::Button {
|
||||
add_css_class: "flat",
|
||||
set_icon_name: "user-trash-symbolic",
|
||||
set_valign: gtk::Align::Center
|
||||
}
|
||||
},
|
||||
|
||||
add_row = &adw::ActionRow {
|
||||
set_title: &tr("chinese"),
|
||||
|
||||
add_suffix = >k::Button {
|
||||
add_css_class: "flat",
|
||||
set_icon_name: "user-trash-symbolic",
|
||||
set_valign: gtk::Align::Center
|
||||
}
|
||||
}
|
||||
#[local_ref]
|
||||
voice_packages -> adw::ExpanderRow {
|
||||
set_title: &tr("game-voiceovers")
|
||||
},
|
||||
|
||||
gtk::Box {
|
||||
|
@ -474,7 +531,9 @@ impl SimpleAsyncComponent for GeneralApp {
|
|||
) -> AsyncComponentParts<Self> {
|
||||
tracing::info!("Initializing general settings");
|
||||
|
||||
let model = Self {
|
||||
let mut model = Self {
|
||||
voice_packages: AsyncFactoryVecDeque::new(adw::ExpanderRow::new(), sender.input_sender()),
|
||||
|
||||
wine_components: ComponentsList::builder()
|
||||
.launch(ComponentsListInit {
|
||||
pattern: ComponentsListPattern {
|
||||
|
@ -514,6 +573,15 @@ impl SimpleAsyncComponent for GeneralApp {
|
|||
selecting_dxvk_version: false
|
||||
};
|
||||
|
||||
for package in VoiceLocale::list() {
|
||||
model.voice_packages.guard().push_back((
|
||||
*package,
|
||||
CONFIG.game.voices.iter().any(|voice| VoiceLocale::from_str(voice) == Some(*package))
|
||||
));
|
||||
}
|
||||
|
||||
let voice_packages = model.voice_packages.widget();
|
||||
|
||||
let widgets = view_output!();
|
||||
|
||||
AsyncComponentParts { model, widgets }
|
||||
|
@ -531,6 +599,56 @@ impl SimpleAsyncComponent for GeneralApp {
|
|||
self.patch = patch;
|
||||
}
|
||||
|
||||
#[allow(unused_must_use)]
|
||||
GeneralAppMsg::AddVoicePackage(index) => {
|
||||
if let Some(package) = self.voice_packages.get(index.current_index()) {
|
||||
if let Ok(mut config) = config::get() {
|
||||
if !config.game.voices.iter().any(|voice| VoiceLocale::from_str(voice) == Some(package.locale)) {
|
||||
config.game.voices.push(package.locale.to_code().to_string());
|
||||
|
||||
config::update(config);
|
||||
|
||||
sender.output(PreferencesAppMsg::UpdateLauncherState);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(unused_must_use)]
|
||||
GeneralAppMsg::RemoveVoicePackage(index) => {
|
||||
if let Some(package) = self.voice_packages.guard().get_mut(index.current_index()) {
|
||||
if let Ok(mut config) = config::get() {
|
||||
package.sensitive = false;
|
||||
|
||||
config.game.voices.retain(|voice| VoiceLocale::from_str(voice) != Some(package.locale));
|
||||
|
||||
config::update(config.clone());
|
||||
|
||||
let package = VoicePackage::with_locale(package.locale).unwrap();
|
||||
|
||||
std::thread::spawn(move || {
|
||||
if let Err(err) = package.delete_in(&config.game.path) {
|
||||
tracing::error!("Failed to delete voice package: {:?}", package.locale());
|
||||
|
||||
sender.input(GeneralAppMsg::Toast {
|
||||
title: tr("voice-package-deletion-error"),
|
||||
description: Some(err.to_string())
|
||||
});
|
||||
}
|
||||
|
||||
sender.input(GeneralAppMsg::SetVoicePackageSensitivity(index, true));
|
||||
sender.output(PreferencesAppMsg::UpdateLauncherState);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GeneralAppMsg::SetVoicePackageSensitivity(index, sensitive) => {
|
||||
if let Some(package) = self.voice_packages.guard().get_mut(index.current_index()) {
|
||||
package.sensitive = sensitive;
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(unused_must_use)]
|
||||
GeneralAppMsg::UpdateLauncherStyle(style) => {
|
||||
if style == LauncherStyle::Classic && !BACKGROUND_FILE.exists() {
|
||||
|
@ -557,11 +675,6 @@ impl SimpleAsyncComponent for GeneralApp {
|
|||
sender.output(Self::Output::SetLauncherStyle(style));
|
||||
}
|
||||
|
||||
#[allow(unused_must_use)]
|
||||
GeneralAppMsg::Toast { title, description } => {
|
||||
sender.output(Self::Output::Toast { title, description });
|
||||
}
|
||||
|
||||
GeneralAppMsg::WineRecommendedOnly(state) => {
|
||||
// todo
|
||||
self.wine_components.sender().send(components::list::AppMsg::ShowRecommendedOnly(state)).unwrap();
|
||||
|
@ -689,6 +802,11 @@ impl SimpleAsyncComponent for GeneralApp {
|
|||
self.selecting_dxvk_version = false;
|
||||
self.selected_dxvk_version = index as u32;
|
||||
}
|
||||
|
||||
#[allow(unused_must_use)]
|
||||
GeneralAppMsg::Toast { title, description } => {
|
||||
sender.output(Self::Output::Toast { title, description });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,6 +34,8 @@ pub enum PreferencesAppMsg {
|
|||
|
||||
SetLauncherStyle(LauncherStyle),
|
||||
|
||||
UpdateLauncherState,
|
||||
|
||||
Toast {
|
||||
title: String,
|
||||
description: Option<String>
|
||||
|
@ -53,6 +55,9 @@ impl SimpleAsyncComponent for PreferencesApp {
|
|||
set_hide_on_close: true,
|
||||
set_modal: true,
|
||||
|
||||
// FIXME: doesn't work for any reason
|
||||
set_search_enabled: false,
|
||||
|
||||
add = model.general.widget(),
|
||||
add = model.enhancements.widget(),
|
||||
add = model.environment.widget(),
|
||||
|
@ -126,6 +131,14 @@ impl SimpleAsyncComponent for PreferencesApp {
|
|||
sender.output(Self::Output::SetLauncherStyle(style));
|
||||
}
|
||||
|
||||
#[allow(unused_must_use)]
|
||||
PreferencesAppMsg::UpdateLauncherState => {
|
||||
sender.output(Self::Output::UpdateLauncherState {
|
||||
perform_on_download_needed: false,
|
||||
show_status_page: false
|
||||
});
|
||||
}
|
||||
|
||||
PreferencesAppMsg::Toast { title, description } => unsafe {
|
||||
let toast = adw::Toast::new(&title);
|
||||
|
||||
|
|
Loading…
Reference in a new issue