Skip to content

Commit

Permalink
Display modals on top of main content
Browse files Browse the repository at this point in the history
  • Loading branch information
mtkennerly committed Sep 20, 2024
1 parent 687cf50 commit e238fd4
Show file tree
Hide file tree
Showing 5 changed files with 111 additions and 67 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
* Changed:
* GUI: Updated to the latest version of [Iced](https://github.com/iced-rs/iced).
If the GUI fails to load, Ludusavi will log the error info.
* GUI: Modals now display on top of the app with a transparent background.

## v0.25.0 (2024-08-18)

Expand Down
32 changes: 17 additions & 15 deletions src/gui/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use std::{
time::{Duration, Instant},
};

use iced::{keyboard, padding, widget::scrollable, Alignment, Subscription, Task};
use iced::{keyboard, padding, widget::scrollable, Alignment, Length, Subscription, Task};

use crate::{
cloud::{rclone_monitor, Rclone, Remote},
Expand All @@ -15,7 +15,7 @@ use crate::{
screen,
shortcuts::{RootHistory, Shortcut, TextHistories, TextHistory},
style,
widget::{id, Column, Container, Element, IcedParentExt, Progress, Row},
widget::{id, Column, Container, Element, IcedParentExt, Progress, Row, Stack},
},
lang::TRANSLATOR,
prelude::{app_dir, get_threads_from_env, initialize_rayon, Error, Finality, StrictPath, SyncDirection},
Expand Down Expand Up @@ -2729,16 +2729,6 @@ impl App {
}

pub fn view(&self) -> Element {
if let Some(m) = &self.modal {
return Column::new()
.push(
m.view(&self.config, &self.text_histories)
.class(style::Container::Primary),
)
.push_if(self.progress.visible(), || self.progress.view(&self.operation))
.into();
}

let content = Column::new()
.align_x(Alignment::Center)
.push(
Expand Down Expand Up @@ -2781,9 +2771,21 @@ impl App {
),
})
.push_maybe(self.timed_notification.as_ref().map(|x| x.view()))
.push_maybe(self.manifest_notification.as_ref().map(|x| x.view()))
.push_if(self.progress.visible(), || self.progress.view(&self.operation));
.push_maybe(self.manifest_notification.as_ref().map(|x| x.view()));

let stack = Stack::new()
.push(Container::new(content).class(style::Container::Primary))
.push_maybe(
self.modal
.as_ref()
.map(|modal| modal.view(&self.config, &self.text_histories)),
);

Container::new(content).class(style::Container::Primary).into()
Column::new()
.width(Length::Fill)
.height(Length::Fill)
.push(stack)
.push_if(self.progress.visible(), || self.progress.view(&self.operation))
.into()
}
}
134 changes: 85 additions & 49 deletions src/gui/modal.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
use std::collections::BTreeSet;

use iced::{padding, Alignment, Length};
use iced::{
padding,
widget::{mouse_area, opaque},
Alignment, Length,
};
use itertools::Itertools;

use crate::{
Expand Down Expand Up @@ -467,6 +471,50 @@ impl Modal {
col
}

fn content(&self, config: &Config, histories: &TextHistories) -> Container {
let positive_button = button::primary(
match self.variant() {
ModalVariant::Loading => TRANSLATOR.okay_button(), // dummy
ModalVariant::Info => TRANSLATOR.okay_button(),
ModalVariant::Confirm => TRANSLATOR.continue_button(),
},
self.message(histories),
);

let negative_button = button::negative(TRANSLATOR.cancel_button(), Some(Message::CloseModal));

Container::new(
Column::new()
.width(Length::Fill)
.height(Length::Fill)
.push(
Container::new(ScrollSubject::Modal.into_widget(self.body(config, histories).padding([0, 30])))
.padding(padding::top(30).right(5))
.width(Length::Fill)
.height(Length::Fill),
)
.push(
Container::new(
match self.variant() {
ModalVariant::Loading => Row::new(),
ModalVariant::Info => Row::with_children(self.extra_controls()).push(positive_button),
ModalVariant::Confirm => Row::with_children(self.extra_controls())
.push_if(!matches!(self, Modal::BackupValidation { .. }), || positive_button)
.push(negative_button),
}
.padding([30, 0])
.spacing(20)
.align_y(Alignment::Center),
)
.width(Length::Fill)
.center_x(Length::Fill),
),
)
.class(style::Container::ModalForeground)
.center_x(Length::Fill)
.height(Length::Fill)
}

pub fn add_cloud_change(&mut self, change: CloudChange) {
match self {
Self::ConfirmCloudSync { changes, .. } => {
Expand Down Expand Up @@ -590,61 +638,49 @@ impl Modal {
}
}

pub fn view(&self, config: &Config, histories: &TextHistories) -> Container {
let positive_button = button::primary(
match self.variant() {
ModalVariant::Loading => TRANSLATOR.okay_button(), // dummy
ModalVariant::Info => TRANSLATOR.okay_button(),
ModalVariant::Confirm => TRANSLATOR.continue_button(),
},
self.message(histories),
);

let negative_button = button::negative(TRANSLATOR.cancel_button(), Some(Message::CloseModal));
pub fn view(&self, config: &Config, histories: &TextHistories) -> Element {
let horizontal = || {
Container::new(Space::new(Length::FillPortion(1), Length::Fill)).class(style::Container::ModalBackground)
};

Container::new(
Column::new()
let vertical = || {
Container::new(Space::new(Length::Shrink, Length::Shrink))
.width(Length::Fill)
.align_x(Alignment::Center)
.push(
Container::new(Space::new(Length::Shrink, Length::Shrink))
.width(Length::Fill)
.height(Length::FillPortion(1))
.class(style::Container::ModalBackground),
)
.height(Length::FillPortion(1))
.class(style::Container::ModalBackground)
};

let modal = Container::new(
Row::new()
.push(horizontal())
.push(
Column::new()
.height(Length::FillPortion(self.body_height_portion()))
.align_x(Alignment::Center)
.width(Length::FillPortion(8))
.push(vertical())
.push(
Container::new(
ScrollSubject::Modal.into_widget(self.body(config, histories).padding([0, 30])),
)
.padding(padding::top(30).right(5))
.height(Length::Fill),
Container::new(opaque(self.content(config, histories)))
.class(style::Container::ModalBackground)
.width(Length::Fill)
.height(Length::FillPortion(self.body_height_portion())),
)
.push(
match self.variant() {
ModalVariant::Loading => Row::new(),
ModalVariant::Info => Row::with_children(self.extra_controls()).push(positive_button),
ModalVariant::Confirm => Row::with_children(self.extra_controls())
.push_if(!matches!(self, Modal::BackupValidation { .. }), || positive_button)
.push(negative_button),
}
.padding([30, 0])
.spacing(20)
.height(Length::Shrink)
.align_y(Alignment::Center),
),
.push(vertical()),
)
.push(
Container::new(Space::new(Length::Shrink, Length::Shrink))
.width(Length::Fill)
.height(Length::FillPortion(1))
.class(style::Container::ModalBackground),
),
.push(horizontal()),
)
.height(Length::Fill)
.center_x(Length::Fill)
.width(Length::Fill)
.height(Length::Fill);

opaque({
let mut area = mouse_area(modal);

match self.variant() {
ModalVariant::Loading => {}
ModalVariant::Info | ModalVariant::Confirm => {
area = area.on_press(Message::CloseModal);
}
}

area
})
}
}
10 changes: 7 additions & 3 deletions src/gui/style.rs
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,7 @@ pub enum Container {
#[default]
Wrapper,
Primary,
ModalForeground,
ModalBackground,
GameListEntry,
Badge,
Expand All @@ -296,7 +297,8 @@ impl container::Catalog for Theme {
background: Some(match class {
Container::Wrapper => Color::TRANSPARENT.into(),
Container::GameListEntry => self.field.alpha(0.15).into(),
Container::ModalBackground | Container::Notification | Container::Tooltip => self.field.into(),
Container::ModalBackground => self.field.alpha(0.75).into(),
Container::Notification | Container::Tooltip => self.field.alpha(0.5).into(),
Container::DisabledBackup => self.disabled.into(),
Container::BadgeActivated => self.negative.into(),
_ => self.background.into(),
Expand All @@ -312,11 +314,12 @@ impl container::Catalog for Theme {
ScanChange::Same | ScanChange::Unknown => self.disabled,
},
Container::BadgeActivated => self.negative,
Container::BadgeFaded => self.disabled,
Container::ModalForeground | Container::BadgeFaded => self.disabled,
_ => self.text,
},
width: match class {
Container::GameListEntry
| Container::ModalForeground
| Container::Badge
| Container::BadgeActivated
| Container::BadgeFaded
Expand All @@ -325,7 +328,8 @@ impl container::Catalog for Theme {
_ => 0.0,
},
radius: match class {
Container::GameListEntry
Container::ModalForeground
| Container::GameListEntry
| Container::Badge
| Container::BadgeActivated
| Container::BadgeFaded
Expand Down
1 change: 1 addition & 0 deletions src/gui/widget.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ pub type PickList<'a, T, L, V> = w::PickList<'a, T, L, V, Message, Theme, Render
pub type ProgressBar<'a> = w::ProgressBar<'a, Theme>;
pub type Row<'a> = w::Row<'a, Message, Theme, Renderer>;
pub type Scrollable<'a> = w::Scrollable<'a, Message, Theme, Renderer>;
pub type Stack<'a> = w::Stack<'a, Message, Theme, Renderer>;
pub type Text<'a> = w::Text<'a, Theme, Renderer>;
pub type TextInput<'a> = w::TextInput<'a, Message, Theme, Renderer>;
pub type Tooltip<'a> = w::Tooltip<'a, Message, Theme, Renderer>;
Expand Down

0 comments on commit e238fd4

Please sign in to comment.