Commit 4a1a7b18 authored by Bilal Elmoussaoui's avatar Bilal Elmoussaoui

use hdy Deck/Carousel to simplify the code

parent ce7b9a4e
......@@ -10,4 +10,7 @@ gdk = "0.13"
gtk = { version = "0.9", features= ["v3_16"] }
gio = "0.9"
log = "0.4"
gettext-rs= { version = "0.4", features = ["gettext-system"] }
gettext-rs = { version = "0.4", features = ["gettext-system"] }
libhandy = { git = "https://gitlab.gnome.org/World/Rust/libhandy-rs.git" }
pretty_env_logger = "0.4"
anyhow = "1.0"
......@@ -14,7 +14,11 @@
"--share=ipc",
"--socket=fallback-x11",
"--socket=wayland",
"--device=dri"
"--device=dri",
"--filesystem=xdg-run/dconf",
"--filesystem=~/.config/dconf:ro",
"--talk-name=ca.desrt.dconf",
"--env=DCONF_USER_CONFIG_DIR=.config/dconf"
],
"build-options" : {
"append-path" : "/usr/lib/sdk/rust-stable/bin",
......@@ -26,7 +30,27 @@
"RUST_BACKTRACE" : "1"
}
},
"modules" : [
"modules" : [{
"name": "libhandy",
"buildsystem": "meson",
"config-opts": [
"-Dintrospection=disabled",
"-Dgtk_doc=false",
"-Dtests=false",
"-Dexamples=false",
"-Dvapi=false",
"-Dglade_catalog=disabled"
],
"cleanup": [
"/include",
"/lib/pkgconfig"
],
"sources": [{
"type": "git",
"url": "https://gitlab.gnome.org/GNOME/libhandy.git",
"branch": "0.83.0"
}]
},
{
"name" : "gnome-tour",
"buildsystem" : "meson",
......
......@@ -58,7 +58,9 @@ impl Application {
"next-page",
clone!(@strong application => move |_, _| {
if let Some(window) = &*application.window.borrow().clone() {
window.next_page();
if window.paginator.borrow_mut().next().is_err() {
window.widget.close();
}
}
}),
);
......@@ -67,7 +69,9 @@ impl Application {
"previous-page",
clone!(@strong application => move |_, _| {
if let Some(window) = &*application.window.borrow().clone() {
window.previous_page();
if window.paginator.borrow_mut().previous().is_err() {
window.stop_tour();
}
}
}),
);
......
......@@ -15,6 +15,7 @@ use application::Application;
use config::{GETTEXT_PACKAGE, LOCALEDIR};
fn main() {
pretty_env_logger::init();
// Prepare i18n
setlocale(LocaleCategory::LcAll, "");
bindtextdomain(GETTEXT_PACKAGE, LOCALEDIR);
......
......@@ -39,7 +39,6 @@ sources = files(
'widgets/pages/image.rs',
'widgets/pages/mod.rs',
'widgets/pages/welcome.rs',
'widgets/headerbar.rs',
'widgets/mod.rs',
'widgets/paginator.rs',
'widgets/window.rs',
......
use gettextrs::gettext;
use gtk::prelude::*;
pub struct HeaderBar {
pub widget: gtk::Stack,
headerbar: gtk::HeaderBar,
title: gtk::Label,
next_btn: gtk::Button,
}
impl HeaderBar {
pub fn new() -> Self {
let widget = gtk::Stack::new();
let headerbar = gtk::HeaderBar::new();
let title = gtk::Label::new(None);
let next_btn = gtk::Button::new();
let headerbar = Self { widget, headerbar, title, next_btn };
headerbar.init();
headerbar
}
pub fn start_tour(&self) {
self.widget.set_visible_child_name("pages");
self.headerbar.set_show_close_button(false);
}
pub fn set_page_nr(&self, page_nr: i32, total_pages: i32) {
if page_nr == total_pages {
self.next_btn.set_label(&gettext("Close"));
} else {
self.next_btn.set_label(&gettext("Next"));
}
}
pub fn set_page_title(&self, title: &str) {
self.title.set_label(title);
}
pub fn end_tour(&self) {
self.widget.set_visible_child_name("welcome");
self.headerbar.set_show_close_button(true);
}
fn init(&self) {
self.headerbar.set_show_close_button(true);
self.headerbar.set_custom_title(Some(&self.title));
self.title.get_style_context().add_class("title");
self.widget.set_hexpand(true);
self.widget.set_transition_type(gtk::StackTransitionType::SlideLeftRight);
self.widget.set_transition_duration(300);
self.widget.get_style_context().add_class("titlebar");
let container = gtk::HeaderBar::new();
container.set_show_close_button(true);
container.set_title(Some(&gettext("Welcome Tour")));
self.widget.add_named(&container, "welcome");
let previous_btn = gtk::Button::new();
previous_btn.add(&gtk::Label::new(Some("Previous")));
previous_btn.set_halign(gtk::Align::Start);
previous_btn.set_action_name(Some("app.previous-page"));
previous_btn.set_hexpand(true);
previous_btn.set_property_width_request(60);
self.next_btn.add(&gtk::Label::new(Some(&gettext("Next"))));
self.next_btn.get_style_context().add_class("suggested-action");
self.next_btn.set_action_name(Some("app.next-page"));
self.next_btn.set_halign(gtk::Align::End);
self.next_btn.set_hexpand(true);
self.next_btn.set_property_width_request(60);
self.headerbar.pack_start(&previous_btn);
self.headerbar.pack_end(&self.next_btn);
self.widget.add_named(&self.headerbar, "pages");
}
}
mod headerbar;
mod pages;
mod paginator;
mod window;
......
use gettextrs::gettext;
use gtk::prelude::*;
use libhandy::prelude::HeaderBarExt;
pub struct WelcomePageWidget {
pub widget: gtk::Box,
......@@ -16,10 +17,14 @@ impl WelcomePageWidget {
}
fn init(&self) {
self.widget.set_valign(gtk::Align::Center);
self.widget.set_halign(gtk::Align::Center);
self.widget.set_margin_top(24);
self.widget.set_margin_bottom(24);
self.widget.set_property_expand(true);
let container = gtk::Box::new(gtk::Orientation::Vertical, 0);
container.set_property_expand(true);
container.set_valign(gtk::Align::Center);
container.set_halign(gtk::Align::Center);
container.set_margin_top(24);
container.set_margin_bottom(24);
let name = glib::get_os_info("NAME").unwrap_or("GNOME".into());
let version = glib::get_os_info("VERSION").unwrap_or("3.36".into());
......@@ -27,17 +32,17 @@ impl WelcomePageWidget {
let logo = gtk::Image::from_icon_name(Some(&icon), gtk::IconSize::Dialog);
logo.set_pixel_size(196);
self.widget.add(&logo);
container.add(&logo);
let title = gtk::Label::new(Some(&gettext(format!("Welcome to {} {}", name, version))));
title.set_margin_top(36);
title.get_style_context().add_class("large-title");
self.widget.add(&title);
container.add(&title);
let text = gtk::Label::new(Some(&gettext("Hi there! If you are new to GNOME, you can take the tour to learn some essential features.")));
text.get_style_context().add_class("body");
text.set_margin_top(12);
self.widget.add(&text);
container.add(&text);
let actions_container = gtk::Box::new(gtk::Orientation::Horizontal, 12);
actions_container.set_halign(gtk::Align::Center);
......@@ -60,6 +65,13 @@ impl WelcomePageWidget {
actions_container.add(&start_tour_btn);
actions_container.set_focus_child(Some(&start_tour_btn));
self.widget.add(&actions_container);
container.add(&actions_container);
let headerbar = libhandy::HeaderBar::new();
headerbar.set_show_close_button(true);
headerbar.set_title(Some(&gettext("Welcome Tour")));
self.widget.add(&headerbar);
self.widget.add(&container);
}
}
use anyhow::Result;
use gettextrs::gettext;
use gtk::prelude::*;
use std::cell::RefCell;
use std::convert::TryInto;
use std::rc::Rc;
use super::pages::Pageable;
use libhandy::prelude::{CarouselExt, HeaderBarExt};
pub struct PaginatorWidget {
pub widget: gtk::Stack,
pages: Vec<Box<dyn Pageable>>,
current_page: RefCell<i32>,
pub widget: gtk::Box,
carousel: libhandy::Carousel,
headerbar: libhandy::HeaderBar,
pages: RefCell<Vec<Box<dyn Pageable>>>,
current_page: RefCell<u32>,
next_btn: gtk::Button,
}
impl PaginatorWidget {
pub fn new() -> Self {
let widget = gtk::Stack::new();
pub fn new() -> Rc<Self> {
let widget = gtk::Box::new(gtk::Orientation::Vertical, 0);
let paginator = Self {
let paginator = Rc::new(Self {
widget,
pages: Vec::new(),
current_page: RefCell::new(1),
};
paginator.init();
carousel: libhandy::Carousel::new(),
headerbar: libhandy::HeaderBar::new(),
next_btn: gtk::Button::new(),
pages: RefCell::new(Vec::new()),
current_page: RefCell::new(0),
});
paginator.init(paginator.clone());
paginator
}
pub fn get_total_pages(&self) -> i32 {
self.pages.len().try_into().unwrap_or(1)
pub fn next(&self) -> Result<()> {
let p = *self.current_page.borrow() + 1;
if p == self.carousel.get_n_pages() {
anyhow::bail!("Already at the latest page");
}
pub fn get_current_page_nr(&self) -> i32 {
*self.current_page.borrow()
self.set_page(p);
Ok(())
}
pub fn get_current_page(&self) -> Option<&Box<dyn Pageable>> {
let current_page_idx: usize = (self.get_current_page_nr() - 1).try_into().unwrap_or(0);
self.pages.get(current_page_idx)
pub fn previous(&self) -> Result<()> {
let p = *self.current_page.borrow();
if p == 0 {
anyhow::bail!("Already at the first page");
}
pub fn next(&self) {
let next_page = *self.current_page.borrow() + 1;
self.go_to(next_page);
self.set_page(p - 1);
Ok(())
}
pub fn previous(&self) {
let previous_page = *self.current_page.borrow() - 1;
self.go_to(previous_page);
pub fn add_page(&self, page: Box<dyn Pageable>) {
let page_nr = self.pages.borrow().len();
self.carousel.insert(&page.get_widget(), page_nr as i32);
self.pages.borrow_mut().push(page);
}
pub fn add_page(&mut self, page: Box<dyn Pageable>) {
let page_nr = self.pages.len() + 1;
let page_name = format!("page-{}", page_nr);
fn init(&self, p: Rc<Self>) {
self.carousel.set_property_expand(true);
self.carousel.set_animation_duration(300);
self.widget.add_named(&page.get_widget(), &page_name);
self.pages.push(page);
}
self.carousel.connect_page_changed(clone!(@weak p => move |carousel, page_nr| {
let pages = &p.pages.borrow();
let page = pages.get(page_nr as usize).unwrap();
p.headerbar.set_title(Some(&page.get_title()));
fn init(&self) {
self.widget.set_transition_type(gtk::StackTransitionType::SlideLeftRight);
self.widget.set_transition_duration(300);
if page_nr == carousel.get_n_pages() - 1 {
p.next_btn.set_label(&gettext("Close"));
} else {
p.next_btn.set_label(&gettext("Next"));
}
p.current_page.replace(page_nr);
}));
let previous_btn = gtk::Button::new();
previous_btn.add(&gtk::Label::new(Some("Previous")));
previous_btn.set_halign(gtk::Align::Start);
previous_btn.set_action_name(Some("app.previous-page"));
previous_btn.set_hexpand(true);
previous_btn.set_property_width_request(60);
fn go_to(&self, page_nr: i32) {
let page_name = format!("page-{}", page_nr);
let total_pages: i32 = self.pages.len().try_into().unwrap_or(0);
self.next_btn.add(&gtk::Label::new(Some(&gettext("Next"))));
self.next_btn.get_style_context().add_class("suggested-action");
self.next_btn.set_action_name(Some("app.next-page"));
self.next_btn.set_halign(gtk::Align::End);
self.next_btn.set_hexpand(true);
self.next_btn.set_property_width_request(60);
self.headerbar.pack_start(&previous_btn);
self.headerbar.pack_end(&self.next_btn);
self.headerbar.set_show_close_button(false);
self.widget.add(&self.headerbar);
self.widget.add(&self.carousel);
}
if page_nr <= total_pages && self.widget.get_child_by_name(&page_name).is_some() {
self.current_page.replace(page_nr);
self.widget.set_visible_child_name(&page_name);
pub fn set_page(&self, page_nr: u32) {
if page_nr < self.carousel.get_n_pages() {
let pages = &self.pages.borrow();
let page = pages.get(page_nr as usize).unwrap();
self.carousel.scroll_to(&page.get_widget());
}
}
}
use gettextrs::gettext;
use gtk::prelude::*;
use std::cell::RefCell;
use std::rc::Rc;
use super::headerbar::HeaderBar;
use super::pages::{ImagePageWidget, WelcomePageWidget};
use super::paginator::PaginatorWidget;
use crate::config::PROFILE;
use libhandy::prelude::DeckExt;
pub struct Window {
pub widget: gtk::ApplicationWindow,
container: gtk::Stack,
headerbar: HeaderBar,
paginator: PaginatorWidget,
pub widget: libhandy::ApplicationWindow,
deck: libhandy::Deck,
pub paginator: RefCell<Rc<PaginatorWidget>>,
welcome_page: WelcomePageWidget,
}
impl Window {
pub fn new(app: &gtk::Application) -> Self {
let widget = gtk::ApplicationWindow::new(app);
let container = gtk::Stack::new();
let headerbar = HeaderBar::new();
let paginator = PaginatorWidget::new();
let widget = libhandy::ApplicationWindow::new();
widget.set_application(Some(app));
let deck = libhandy::Deck::new();
let paginator = RefCell::new(PaginatorWidget::new());
let mut window_widget = Window {
widget,
container,
headerbar,
deck,
welcome_page: WelcomePageWidget::new(),
paginator,
};
......@@ -32,91 +35,55 @@ impl Window {
}
pub fn start_tour(&self) {
if let Some(page) = self.paginator.get_current_page() {
self.headerbar.set_page_title(&page.get_title());
}
self.container.set_visible_child_name("pages");
self.headerbar.start_tour();
}
fn end_tour(&self) {
self.container.set_visible_child_name("welcome");
self.headerbar.end_tour();
}
pub fn next_page(&self) {
let total_pages = self.paginator.get_total_pages();
let current_page = self.paginator.get_current_page_nr();
self.headerbar.set_page_nr(current_page + 1, total_pages);
if current_page == total_pages {
self.widget.close();
} else {
self.paginator.next();
}
if let Some(page) = self.paginator.get_current_page() {
self.headerbar.set_page_title(&page.get_title());
}
self.deck.set_visible_child(&self.paginator.borrow().widget);
self.paginator.borrow_mut().set_page(0);
}
pub fn previous_page(&self) {
let total_pages = self.paginator.get_total_pages();
let current_page = self.paginator.get_current_page_nr();
self.headerbar.set_page_nr(current_page - 1, total_pages);
match current_page {
1 => self.end_tour(),
_ => self.paginator.previous(),
}
if let Some(page) = self.paginator.get_current_page() {
self.headerbar.set_page_title(&page.get_title());
}
pub fn stop_tour(&self) {
self.paginator.borrow_mut().set_page(0);
self.deck.set_visible_child(&self.welcome_page.widget);
}
fn init(&mut self) {
self.widget.set_default_size(920, 640);
self.container.set_transition_type(gtk::StackTransitionType::SlideLeftRight);
self.container.set_transition_duration(300);
self.deck.set_transition_type(libhandy::DeckTransitionType::Slide);
self.deck.set_transition_duration(300);
// Devel Profile
if PROFILE == "Devel" {
self.widget.get_style_context().add_class("devel");
}
self.widget.set_titlebar(Some(&self.headerbar.widget));
let welcome_page = WelcomePageWidget::new();
self.container.add_named(&welcome_page.widget, "welcome");
self.deck.add(&self.welcome_page.widget);
self.paginator.add_page(Box::new(ImagePageWidget::new(
self.paginator.borrow().add_page(Box::new(ImagePageWidget::new(
"/org/gnome/Tour/activities.svg",
gettext("Activities Overview"),
gettext("Open Activities to start apps"),
gettext("You can also view open windows, search and use workspaces."),
)));
self.paginator.add_page(Box::new(ImagePageWidget::new(
self.paginator.borrow_mut().add_page(Box::new(ImagePageWidget::new(
"/org/gnome/Tour/search.svg",
gettext("Search"),
gettext("In the Activities Overview, just start typing to search"),
gettext("Search can be used to launch apps, find settings, do calculations and much more."),
)));
self.paginator.add_page(Box::new(ImagePageWidget::new(
self.paginator.borrow_mut().add_page(Box::new(ImagePageWidget::new(
"/org/gnome/Tour/calendar.svg",
gettext("Date & Time"),
gettext("Click the time to see your now and next"),
gettext("This includes notifications, media controls, calendar events, the weather and world clocks."),
)));
self.paginator.add_page(Box::new(ImagePageWidget::new(
self.paginator.borrow_mut().add_page(Box::new(ImagePageWidget::new(
"/org/gnome/Tour/status-menu.svg",
gettext("System Menu"),
gettext("View system information and settings"),
gettext("Get an overview of the system status and quickly change settings."),
)));
self.paginator.add_page(Box::new(ImagePageWidget::new(
self.paginator.borrow_mut().add_page(Box::new(ImagePageWidget::new(
"/org/gnome/Tour/software.svg",
gettext("Software"),
gettext("Find and install apps"),
......@@ -130,9 +97,9 @@ impl Window {
gettext("The help app contains information, tips and tricks."),
);
last_page.widget.get_style_context().add_class("last-page");
self.paginator.add_page(Box::new(last_page));
self.paginator.borrow_mut().add_page(Box::new(last_page));
self.container.add_named(&self.paginator.widget, "pages");
self.widget.add(&self.container);
self.deck.add(&self.paginator.borrow().widget);
self.widget.add(&self.deck);
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment