Merge #1740: Smart screen size
b1e06ee10638895e2bcf7ac41bd5933048e2ca34 global_settings: do not create file if not existing & empty (pythcoiner) a0b74709f33d7eb84c2c9692d2d079096891c283 settings: add a tests for GlobalSettings (pythcoiner) c53ace8b0bb2e006221ae2faf013fe7ab0b1e16d gui: store the window size in global settings only on shutdown (pythcoiner) 13652e3c33f1844440831761d01faa7bfc499d0e settings: add a lock to read/write global settings (pythcoiner) b696f50f8c9b4938e9a43e0bcb6b77db82c5b002 gui: apply previous screen size before launch (pythcoiner) 2dc838f85c0de563ee19d28332f7c60f4a9c094c gui: be smart with window size at launch (pythcoiner) 089992b9475d4d9b2868399afeb1ceadf7ee37f5 settings: add window_config to GlobalSettings (pythcoiner) cb8a421571bebb2fe0ac206175682167b7b1b64c settings: rename global::Settings => global::GlobalSettings (pythcoiner) bf666539bfed7a75a0dfc2d34ac377b1b094278b gui: implement State::datadir_path() (pythcoiner) Pull request description: closes #1546 following last requirements: > Currently the consensus has been on the following solution: resize the window according to a logic similar to https://github.com/wizardsardine/liana/pull/1695 at the first launch and then remember the last size for following launches of the application. Summary of the feature introduced in this PR: - The first time Liana launch, the window is maximized in order to "guess" the maximum usable size on the monitor, and then we apply [this logic](https://github.com/wizardsardine/liana/issues/1546#issuecomment-2750974470) for deciding the default size. - The default size is recorded in `global_settings.json` (so this aplly to ALL wallets) - On nexts Liana launch, the window is resized to the value contained in `global_settings.json` I added something not clearly defined: if the user resize its screen, we reapply the last screen size at startup. ACKs for top commit: edouardparis: ACK b1e06ee10638895e2bcf7ac41bd5933048e2ca34 Tree-SHA512: 1ffb0ef852846d5599a747d619a19a2ee2b47ecbb26172de95ffbf6ad2d0c65851b3236070081e81b2503914e6916abc3ed59899131a8a475f6d07662a951d0e
This commit is contained in:
commit
a90d894af9
11
Cargo.lock
generated
11
Cargo.lock
generated
@ -1827,6 +1827,16 @@ dependencies = [
|
||||
"percent-encoding",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fs2"
|
||||
version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9564fc758e15025b46aa6643b1b77d047d1a56a1aea6e01002ac0c7026876213"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures"
|
||||
version = "0.3.31"
|
||||
@ -3072,6 +3082,7 @@ dependencies = [
|
||||
"dirs 3.0.2",
|
||||
"email_address",
|
||||
"flate2",
|
||||
"fs2",
|
||||
"hex",
|
||||
"iced",
|
||||
"iced_aw",
|
||||
|
||||
@ -54,6 +54,7 @@ bitcoin_hashes = "0.12"
|
||||
reqwest = { version = "0.11", default-features=false, features = ["json", "rustls-tls", "stream"] }
|
||||
rust-ini = "0.19.0"
|
||||
rfd = "0.15.1"
|
||||
fs2 = "0.4.3"
|
||||
|
||||
# Used for opening URLs in browser
|
||||
open = "5.3"
|
||||
|
||||
@ -441,6 +441,10 @@ impl App {
|
||||
content
|
||||
}
|
||||
}
|
||||
|
||||
pub fn datadir_path(&self) -> &LianaDirectory {
|
||||
&self.cache.datadir_path
|
||||
}
|
||||
}
|
||||
|
||||
fn new_recovery_panel(wallet: Arc<Wallet>, cache: &Cache) -> CreateSpendPanel {
|
||||
|
||||
@ -380,18 +380,141 @@ impl std::fmt::Display for SettingsError {
|
||||
pub mod global {
|
||||
use crate::dir::LianaDirectory;
|
||||
use async_hwi::bitbox::{ConfigError, NoiseConfig, NoiseConfigData};
|
||||
use fs2::FileExt;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::io::{Read, Write};
|
||||
use std::fs::OpenOptions;
|
||||
use std::io::{Read, Seek, SeekFrom, Write};
|
||||
use std::path::PathBuf;
|
||||
|
||||
pub const DEFAULT_FILE_NAME: &str = "global_settings.json";
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize)]
|
||||
pub struct Settings {
|
||||
pub bitbox: Option<BitboxSettings>,
|
||||
#[derive(Debug, Deserialize, Serialize, Clone, PartialEq)]
|
||||
pub struct WindowConfig {
|
||||
pub width: f32,
|
||||
pub height: f32,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize)]
|
||||
#[derive(Debug, Deserialize, Serialize, Default)]
|
||||
pub struct GlobalSettings {
|
||||
pub bitbox: Option<BitboxSettings>,
|
||||
pub window_config: Option<WindowConfig>,
|
||||
}
|
||||
|
||||
impl GlobalSettings {
|
||||
pub fn path(global_datadir: &LianaDirectory) -> PathBuf {
|
||||
global_datadir.path().join(DEFAULT_FILE_NAME)
|
||||
}
|
||||
|
||||
pub fn load_window_config(path: &PathBuf) -> Option<WindowConfig> {
|
||||
let mut ret = None;
|
||||
if let Err(e) = Self::update(path, |s| ret = s.window_config.clone(), false) {
|
||||
tracing::error!("Failed to load window config: {e}");
|
||||
}
|
||||
ret
|
||||
}
|
||||
|
||||
pub fn update_window_config(
|
||||
path: &PathBuf,
|
||||
window_config: &WindowConfig,
|
||||
) -> Result<(), String> {
|
||||
Self::update(
|
||||
path,
|
||||
|s| s.window_config = Some(window_config.clone()),
|
||||
true,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn load_bitbox_settings(path: &PathBuf) -> Result<Option<BitboxSettings>, String> {
|
||||
let mut ret = None;
|
||||
Self::update(path, |s| ret = s.bitbox.clone(), false)?;
|
||||
Ok(ret)
|
||||
}
|
||||
|
||||
pub fn update_bitbox_settings(
|
||||
path: &PathBuf,
|
||||
bitbox: &BitboxSettings,
|
||||
) -> Result<(), String> {
|
||||
Self::update(path, |s| s.bitbox = Some(bitbox.clone()), true)
|
||||
}
|
||||
|
||||
pub fn update<F>(path: &PathBuf, mut update: F, mut write: bool) -> Result<(), String>
|
||||
where
|
||||
F: FnMut(&mut GlobalSettings),
|
||||
{
|
||||
log::info!("GLobalSettings::update() write: {write}");
|
||||
let exists = path.is_file();
|
||||
|
||||
let (mut global_settings, file) = if exists {
|
||||
let mut file = OpenOptions::new()
|
||||
.read(true)
|
||||
.write(true)
|
||||
.create(true)
|
||||
.truncate(false)
|
||||
.open(path)
|
||||
.map_err(|e| format!("Opening file: {e}"))?;
|
||||
|
||||
file.lock_exclusive()
|
||||
.map_err(|e| format!("Locking file: {e}"))?;
|
||||
|
||||
let mut content = String::new();
|
||||
file.read_to_string(&mut content)
|
||||
.map_err(|e| format!("Reading file: {e}"))?;
|
||||
|
||||
if !write {
|
||||
file.unlock().map_err(|e| format!("Unlocking file: {e}"))?;
|
||||
}
|
||||
|
||||
(
|
||||
serde_json::from_str::<GlobalSettings>(&content).map_err(|e| e.to_string())?,
|
||||
Some(file),
|
||||
)
|
||||
} else {
|
||||
(GlobalSettings::default(), None)
|
||||
};
|
||||
|
||||
update(&mut global_settings);
|
||||
|
||||
if !exists
|
||||
&& global_settings.bitbox.is_none()
|
||||
&& global_settings.window_config.is_none()
|
||||
{
|
||||
write = false;
|
||||
}
|
||||
|
||||
if write {
|
||||
let mut file = if let Some(file) = file {
|
||||
file
|
||||
} else {
|
||||
let file = OpenOptions::new()
|
||||
.read(true)
|
||||
.write(true)
|
||||
.create(true)
|
||||
.truncate(false)
|
||||
.open(path)
|
||||
.map_err(|e| format!("Opening file: {e}"))?;
|
||||
|
||||
file.lock_exclusive()
|
||||
.map_err(|e| format!("Locking file: {e}"))?;
|
||||
file
|
||||
};
|
||||
let content = serde_json::to_vec_pretty(&global_settings)
|
||||
.map_err(|e| format!("Failed to serialize GlobalSettings: {e}"))?;
|
||||
|
||||
file.seek(SeekFrom::Start(0))
|
||||
.map_err(|e| format!("Failed to seek file: {e}"))?;
|
||||
|
||||
file.write_all(&content)
|
||||
.map_err(|e| format!("Failed to write file: {e}"))?;
|
||||
file.set_len(content.len() as u64)
|
||||
.map_err(|e| format!("Failed to truncate file: {e}"))?;
|
||||
file.unlock().map_err(|e| format!("Unlocking file: {e}"))?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize, Clone)]
|
||||
pub struct BitboxSettings {
|
||||
pub noise_config: NoiseConfigData,
|
||||
}
|
||||
@ -407,68 +530,209 @@ pub mod global {
|
||||
/// in the provided directory.
|
||||
pub fn new(global_datadir: &LianaDirectory) -> PersistedBitboxNoiseConfig {
|
||||
PersistedBitboxNoiseConfig {
|
||||
file_path: global_datadir.path().join(DEFAULT_FILE_NAME),
|
||||
file_path: GlobalSettings::path(global_datadir),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl NoiseConfig for PersistedBitboxNoiseConfig {
|
||||
fn read_config(&self) -> Result<NoiseConfigData, async_hwi::bitbox::api::ConfigError> {
|
||||
if !self.file_path.exists() {
|
||||
return Ok(NoiseConfigData::default());
|
||||
}
|
||||
|
||||
let mut file =
|
||||
std::fs::File::open(&self.file_path).map_err(|e| ConfigError(e.to_string()))?;
|
||||
|
||||
let mut contents = String::new();
|
||||
file.read_to_string(&mut contents)
|
||||
.map_err(|e| ConfigError(e.to_string()))?;
|
||||
|
||||
let settings = serde_json::from_str::<Settings>(&contents)
|
||||
.map_err(|e| ConfigError(e.to_string()))?;
|
||||
|
||||
Ok(settings
|
||||
.bitbox
|
||||
fn read_config(&self) -> Result<NoiseConfigData, ConfigError> {
|
||||
let res = GlobalSettings::load_bitbox_settings(&self.file_path)
|
||||
.map_err(ConfigError)?
|
||||
.map(|s| s.noise_config)
|
||||
.unwrap_or_else(NoiseConfigData::default))
|
||||
.unwrap_or_else(NoiseConfigData::default);
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
fn store_config(&self, conf: &NoiseConfigData) -> Result<(), ConfigError> {
|
||||
let data = if self.file_path.exists() {
|
||||
let mut file =
|
||||
std::fs::File::open(&self.file_path).map_err(|e| ConfigError(e.to_string()))?;
|
||||
|
||||
let mut contents = String::new();
|
||||
file.read_to_string(&mut contents)
|
||||
.map_err(|e| ConfigError(e.to_string()))?;
|
||||
|
||||
let mut settings = serde_json::from_str::<Settings>(&contents)
|
||||
.map_err(|e| ConfigError(e.to_string()))?;
|
||||
|
||||
settings.bitbox = Some(BitboxSettings {
|
||||
noise_config: conf.clone(),
|
||||
});
|
||||
|
||||
serde_json::to_string_pretty(&settings).map_err(|e| ConfigError(e.to_string()))?
|
||||
} else {
|
||||
serde_json::to_string_pretty(&Settings {
|
||||
bitbox: Some(BitboxSettings {
|
||||
noise_config: conf.clone(),
|
||||
}),
|
||||
})
|
||||
.map_err(|e| ConfigError(e.to_string()))?
|
||||
};
|
||||
|
||||
let mut file = std::fs::OpenOptions::new()
|
||||
.write(true)
|
||||
.create(true)
|
||||
.truncate(true)
|
||||
.open(&self.file_path)
|
||||
.map_err(|e| ConfigError(e.to_string()))?;
|
||||
|
||||
file.write_all(data.as_bytes())
|
||||
.map_err(|e| ConfigError(e.to_string()))
|
||||
GlobalSettings::update(
|
||||
&self.file_path,
|
||||
|s| {
|
||||
if let Some(bitbox) = s.bitbox.as_mut() {
|
||||
bitbox.noise_config = conf.clone();
|
||||
} else {
|
||||
s.bitbox = Some(BitboxSettings {
|
||||
noise_config: conf.clone(),
|
||||
});
|
||||
}
|
||||
},
|
||||
true,
|
||||
)
|
||||
.map_err(ConfigError)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::global::{GlobalSettings, WindowConfig};
|
||||
use std::env;
|
||||
|
||||
const RAW_GLOBAL_SETTINGS: &str = r#"{
|
||||
"bitbox": {
|
||||
"noise_config": {
|
||||
"app_static_privkey": [
|
||||
84,
|
||||
118,
|
||||
69,
|
||||
7,
|
||||
5,
|
||||
246,
|
||||
50,
|
||||
252,
|
||||
79,
|
||||
62,
|
||||
233,
|
||||
118,
|
||||
54,
|
||||
46,
|
||||
247,
|
||||
143,
|
||||
255,
|
||||
152,
|
||||
11,
|
||||
96,
|
||||
7,
|
||||
213,
|
||||
209,
|
||||
42,
|
||||
219,
|
||||
58,
|
||||
237,
|
||||
22,
|
||||
53,
|
||||
221,
|
||||
227,
|
||||
228
|
||||
],
|
||||
"device_static_pubkeys": [
|
||||
[
|
||||
252,
|
||||
78,
|
||||
254,
|
||||
112,
|
||||
62,
|
||||
72,
|
||||
220,
|
||||
22,
|
||||
23,
|
||||
147,
|
||||
205,
|
||||
166,
|
||||
248,
|
||||
39,
|
||||
97,
|
||||
46,
|
||||
32,
|
||||
255,
|
||||
132,
|
||||
125,
|
||||
97,
|
||||
142,
|
||||
31,
|
||||
146,
|
||||
44,
|
||||
186,
|
||||
231,
|
||||
1,
|
||||
12,
|
||||
190,
|
||||
105,
|
||||
11
|
||||
]
|
||||
]
|
||||
}
|
||||
},
|
||||
"window_config": {
|
||||
"width": 1248.0,
|
||||
"height": 688.0
|
||||
}
|
||||
}"#;
|
||||
|
||||
#[test]
|
||||
fn test_parse_global_config() {
|
||||
let _ = serde_json::from_str::<GlobalSettings>(RAW_GLOBAL_SETTINGS).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_update_global_config() {
|
||||
let path = env::current_dir()
|
||||
.unwrap()
|
||||
.join("test_assets")
|
||||
.join("global_settings.json");
|
||||
assert!(path.exists());
|
||||
|
||||
// read global config file
|
||||
GlobalSettings::update(
|
||||
&path,
|
||||
|s| {
|
||||
assert_eq!(
|
||||
*s.window_config.as_ref().unwrap(),
|
||||
WindowConfig {
|
||||
width: 1248.0,
|
||||
height: 688.0
|
||||
}
|
||||
);
|
||||
assert!(s.bitbox.is_some());
|
||||
// this must not be written to the file as write == false
|
||||
s.window_config.as_mut().unwrap().height = 0.0;
|
||||
},
|
||||
false,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
// re-read the global config file
|
||||
GlobalSettings::update(
|
||||
&path,
|
||||
|s| {
|
||||
// change have not been written
|
||||
assert_eq!(
|
||||
*s.window_config.as_ref().unwrap(),
|
||||
WindowConfig {
|
||||
width: 1248.0,
|
||||
height: 688.0
|
||||
}
|
||||
);
|
||||
},
|
||||
true,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
// edit the global config file
|
||||
GlobalSettings::update(
|
||||
&path,
|
||||
|s| {
|
||||
assert_eq!(
|
||||
*s.window_config.as_ref().unwrap(),
|
||||
WindowConfig {
|
||||
width: 1248.0,
|
||||
height: 688.0
|
||||
}
|
||||
);
|
||||
assert!(s.bitbox.is_some());
|
||||
// this must be written to the file as write == true
|
||||
s.window_config.as_mut().unwrap().height = 0.0;
|
||||
},
|
||||
true,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
// re-read the global config file
|
||||
GlobalSettings::update(
|
||||
&path,
|
||||
|s| {
|
||||
// change have been written
|
||||
assert_eq!(
|
||||
*s.window_config.as_ref().unwrap(),
|
||||
WindowConfig {
|
||||
width: 1248.0,
|
||||
height: 0.0
|
||||
}
|
||||
);
|
||||
s.window_config.as_mut().unwrap().height = 688.0;
|
||||
},
|
||||
true,
|
||||
)
|
||||
.unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,8 +2,9 @@ use iced::{
|
||||
event::{self, Event},
|
||||
keyboard,
|
||||
widget::{focus_next, focus_previous, pane_grid},
|
||||
Length, Subscription, Task,
|
||||
Length, Size, Subscription, Task,
|
||||
};
|
||||
use iced_runtime::window;
|
||||
use tracing::{error, info};
|
||||
use tracing_subscriber::filter::LevelFilter;
|
||||
extern crate serde;
|
||||
@ -15,12 +16,23 @@ use liana_ui::widget::{Column, Container, Element};
|
||||
pub mod pane;
|
||||
pub mod tab;
|
||||
|
||||
use crate::{dir::LianaDirectory, launcher, logger::setup_logger, VERSION};
|
||||
use crate::{
|
||||
app::settings::global::{GlobalSettings, WindowConfig},
|
||||
dir::LianaDirectory,
|
||||
launcher,
|
||||
logger::setup_logger,
|
||||
VERSION,
|
||||
};
|
||||
|
||||
use iced::window::Id;
|
||||
|
||||
pub struct GUI {
|
||||
panes: pane_grid::State<pane::Pane>,
|
||||
focus: Option<pane_grid::Pane>,
|
||||
config: Config,
|
||||
window_id: Option<Id>,
|
||||
window_init: Option<bool>,
|
||||
window_config: Option<WindowConfig>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
@ -39,6 +51,8 @@ pub enum Message {
|
||||
Clicked(pane_grid::Pane),
|
||||
Dragged(pane_grid::DragEvent),
|
||||
Resized(pane_grid::ResizeEvent),
|
||||
Window(Option<Id>),
|
||||
WindowSize(Size),
|
||||
}
|
||||
|
||||
impl From<Result<(), iced::font::Error>> for Message {
|
||||
@ -65,15 +79,24 @@ impl GUI {
|
||||
if let Err(e) = setup_logger(log_level, config.liana_directory.clone()) {
|
||||
tracing::warn!("Error while setting error: {}", e);
|
||||
}
|
||||
let mut cmds = vec![Task::perform(ctrl_c(), |_| Message::CtrlC)];
|
||||
let mut cmds = vec![
|
||||
window::get_oldest().map(Message::Window),
|
||||
Task::perform(ctrl_c(), |_| Message::CtrlC),
|
||||
];
|
||||
let (pane, cmd) = pane::Pane::new(&config);
|
||||
let (panes, focused_pane) = pane_grid::State::new(pane);
|
||||
cmds.push(cmd.map(move |msg| Message::Pane(focused_pane, msg)));
|
||||
let window_config =
|
||||
GlobalSettings::load_window_config(&GlobalSettings::path(&config.liana_directory));
|
||||
let window_init = window_config.is_some().then_some(true);
|
||||
(
|
||||
Self {
|
||||
panes,
|
||||
focus: Some(focused_pane),
|
||||
config,
|
||||
window_id: None,
|
||||
window_init,
|
||||
window_config,
|
||||
},
|
||||
Task::batch(cmds),
|
||||
)
|
||||
@ -81,11 +104,81 @@ impl GUI {
|
||||
|
||||
pub fn update(&mut self, message: Message) -> Task<Message> {
|
||||
match message {
|
||||
// we get this message only once at startup
|
||||
Message::Window(id) => {
|
||||
self.window_id = id;
|
||||
// Common case: if there is an already saved screen size we reuse it
|
||||
if let (Some(id), Some(WindowConfig { width, height })) = (id, &self.window_config)
|
||||
{
|
||||
window::resize(
|
||||
id,
|
||||
Size {
|
||||
width: *width,
|
||||
height: *height,
|
||||
},
|
||||
)
|
||||
// Initial startup: we maximize the screen in order to know the max usable screen area
|
||||
} else if let Some(id) = &self.window_id {
|
||||
window::maximize(*id, true)
|
||||
} else {
|
||||
Task::none()
|
||||
}
|
||||
}
|
||||
Message::WindowSize(monitor_size) => {
|
||||
let cloned_cfg = self.window_config.clone();
|
||||
match (cloned_cfg, &self.window_init, &self.window_id) {
|
||||
// no previous screen size recorded && window maximized
|
||||
(None, Some(false), Some(id)) => {
|
||||
self.window_init = Some(true);
|
||||
let mut batch = vec![window::maximize(*id, false)];
|
||||
let new_size = if monitor_size.height >= 1200.0 {
|
||||
let size = Size {
|
||||
width: 1200.0,
|
||||
height: 950.0,
|
||||
};
|
||||
batch.push(window::resize(*id, size));
|
||||
size
|
||||
} else {
|
||||
batch.push(window::resize(*id, iced::window::Settings::default().size));
|
||||
iced::window::Settings::default().size
|
||||
};
|
||||
self.window_config = Some(WindowConfig {
|
||||
width: new_size.width,
|
||||
height: new_size.height,
|
||||
});
|
||||
Task::batch(batch)
|
||||
}
|
||||
// we already have a record of the last window size and we update it
|
||||
(Some(WindowConfig { width, height }), _, _) => {
|
||||
if width != monitor_size.width || height != monitor_size.height {
|
||||
if let Some(cfg) = &mut self.window_config {
|
||||
cfg.width = monitor_size.width;
|
||||
cfg.height = monitor_size.height;
|
||||
}
|
||||
}
|
||||
Task::none()
|
||||
}
|
||||
// we ignore the first notification about initial window size it will always be
|
||||
// the default one
|
||||
_ => {
|
||||
if self.window_init.is_none() {
|
||||
self.window_init = Some(false);
|
||||
}
|
||||
Task::none()
|
||||
}
|
||||
}
|
||||
}
|
||||
Message::CtrlC
|
||||
| Message::Event(iced::Event::Window(iced::window::Event::CloseRequested)) => {
|
||||
for (_, pane) in self.panes.iter_mut() {
|
||||
pane.stop();
|
||||
}
|
||||
if let Some(window_config) = &self.window_config {
|
||||
let path = GlobalSettings::path(&self.config.liana_directory);
|
||||
if let Err(e) = GlobalSettings::update_window_config(&path, window_config) {
|
||||
tracing::error!("Failed to update the window config: {e}");
|
||||
}
|
||||
}
|
||||
iced::window::get_latest().and_then(iced::window::close)
|
||||
}
|
||||
Message::KeyPressed(Key::Tab(shift)) => {
|
||||
@ -250,6 +343,9 @@ impl GUI {
|
||||
iced::Event::Window(iced::window::Event::CloseRequested),
|
||||
event::Status::Ignored,
|
||||
) => Some(Message::Event(event)),
|
||||
(iced::Event::Window(iced::window::Event::Resized(size)), _) => {
|
||||
Some(Message::WindowSize(*size))
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
})];
|
||||
|
||||
@ -47,7 +47,7 @@ pub enum State {
|
||||
pub struct Launcher {
|
||||
state: State,
|
||||
network: Network,
|
||||
datadir_path: LianaDirectory,
|
||||
pub datadir_path: LianaDirectory,
|
||||
error: Option<String>,
|
||||
delete_wallet_modal: Option<DeleteWalletModal>,
|
||||
}
|
||||
|
||||
@ -14,6 +14,7 @@ use liana::miniscript::bitcoin;
|
||||
use liana_ui::{component::text, font, image, theme};
|
||||
|
||||
use liana_gui::{
|
||||
app::settings::global::{GlobalSettings, WindowConfig},
|
||||
dir::LianaDirectory,
|
||||
gui::{Config, GUI},
|
||||
node::bitcoind::delete_all_bitcoind_locks_for_process,
|
||||
@ -106,8 +107,18 @@ fn main() -> Result<(), Box<dyn Error>> {
|
||||
fonts: font::load(),
|
||||
};
|
||||
|
||||
let global_config_path = GlobalSettings::path(&config.liana_directory);
|
||||
let initial_size = if let Some(WindowConfig { width, height }) =
|
||||
GlobalSettings::load_window_config(&global_config_path)
|
||||
{
|
||||
Size { width, height }
|
||||
} else {
|
||||
iced::window::Settings::default().size
|
||||
};
|
||||
|
||||
#[allow(unused_mut)]
|
||||
let mut window_settings = iced::window::Settings {
|
||||
size: initial_size,
|
||||
icon: Some(image::liana_app_icon()),
|
||||
position: iced::window::Position::Default,
|
||||
min_size: Some(Size {
|
||||
|
||||
80
liana-gui/test_assets/global_settings.json
Normal file
80
liana-gui/test_assets/global_settings.json
Normal file
@ -0,0 +1,80 @@
|
||||
{
|
||||
"bitbox": {
|
||||
"noise_config": {
|
||||
"app_static_privkey": [
|
||||
84,
|
||||
118,
|
||||
69,
|
||||
7,
|
||||
5,
|
||||
246,
|
||||
50,
|
||||
252,
|
||||
79,
|
||||
62,
|
||||
233,
|
||||
118,
|
||||
54,
|
||||
46,
|
||||
247,
|
||||
143,
|
||||
255,
|
||||
152,
|
||||
11,
|
||||
96,
|
||||
7,
|
||||
213,
|
||||
209,
|
||||
42,
|
||||
219,
|
||||
58,
|
||||
237,
|
||||
22,
|
||||
53,
|
||||
221,
|
||||
227,
|
||||
228
|
||||
],
|
||||
"device_static_pubkeys": [
|
||||
[
|
||||
252,
|
||||
78,
|
||||
254,
|
||||
112,
|
||||
62,
|
||||
72,
|
||||
220,
|
||||
22,
|
||||
23,
|
||||
147,
|
||||
205,
|
||||
166,
|
||||
248,
|
||||
39,
|
||||
97,
|
||||
46,
|
||||
32,
|
||||
255,
|
||||
132,
|
||||
125,
|
||||
97,
|
||||
142,
|
||||
31,
|
||||
146,
|
||||
44,
|
||||
186,
|
||||
231,
|
||||
1,
|
||||
12,
|
||||
190,
|
||||
105,
|
||||
11
|
||||
]
|
||||
]
|
||||
}
|
||||
},
|
||||
"window_config": {
|
||||
"width": 1248.0,
|
||||
"height": 688.0
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user