mirror of
https://github.com/YGGverse/Yoda.git
synced 2025-01-28 20:14:13 +00:00
create separated wrapper for reload action
This commit is contained in:
parent
baea14de95
commit
b4dee17768
11
src/app.rs
11
src/app.rs
@ -41,8 +41,6 @@ impl App {
|
||||
SimpleAction::new_stateful(&uuid_string_random(), None, &default_state);
|
||||
let action_page_history_forward =
|
||||
SimpleAction::new_stateful(&uuid_string_random(), None, &default_state);
|
||||
let action_page_reload =
|
||||
SimpleAction::new_stateful(&uuid_string_random(), None, &default_state);
|
||||
|
||||
// Init GTK
|
||||
let gobject = Application::builder()
|
||||
@ -57,7 +55,6 @@ impl App {
|
||||
action_page_home.clone(),
|
||||
action_page_history_back.clone(),
|
||||
action_page_history_forward.clone(),
|
||||
action_page_reload.clone(),
|
||||
));
|
||||
|
||||
// Init events
|
||||
@ -209,11 +206,15 @@ impl App {
|
||||
),
|
||||
&["<Primary>p"],
|
||||
),
|
||||
// @TODO
|
||||
(
|
||||
format!("win.{}", action_page_reload.name()),
|
||||
format!(
|
||||
"{}.{}",
|
||||
browser.window().action().id(),
|
||||
browser.window().action().reload().id()
|
||||
),
|
||||
&["<Primary>r"],
|
||||
),
|
||||
// @TODO
|
||||
(
|
||||
format!("win.{}", action_page_history_back.name()),
|
||||
&["<Primary>Left"],
|
||||
|
@ -35,7 +35,6 @@ impl Browser {
|
||||
action_page_home: SimpleAction,
|
||||
action_page_history_back: SimpleAction,
|
||||
action_page_history_forward: SimpleAction,
|
||||
action_page_reload: SimpleAction,
|
||||
) -> Browser {
|
||||
// Init components
|
||||
let action = Rc::new(Action::new());
|
||||
@ -46,7 +45,6 @@ impl Browser {
|
||||
action_page_home.clone(),
|
||||
action_page_history_back.clone(),
|
||||
action_page_history_forward.clone(),
|
||||
action_page_reload.clone(),
|
||||
));
|
||||
|
||||
// Init widget
|
||||
@ -58,7 +56,6 @@ impl Browser {
|
||||
action_page_home.clone(),
|
||||
action_page_history_back.clone(),
|
||||
action_page_history_forward.clone(),
|
||||
action_page_reload.clone(),
|
||||
],
|
||||
));
|
||||
|
||||
@ -151,11 +148,6 @@ impl Browser {
|
||||
}
|
||||
});
|
||||
|
||||
action_page_reload.connect_activate({
|
||||
let window = window.clone();
|
||||
move |this, _| window.tab_page_reload(page_position_from_action_state(this))
|
||||
});
|
||||
|
||||
// Return new activated `Self`
|
||||
Self {
|
||||
action,
|
||||
|
@ -32,7 +32,6 @@ impl Window {
|
||||
action_page_home: SimpleAction,
|
||||
action_page_history_back: SimpleAction,
|
||||
action_page_history_forward: SimpleAction,
|
||||
action_page_reload: SimpleAction,
|
||||
) -> Self {
|
||||
// Init local actions
|
||||
let action = Rc::new(Action::new());
|
||||
@ -46,7 +45,6 @@ impl Window {
|
||||
action_page_home.clone(),
|
||||
action_page_history_back.clone(),
|
||||
action_page_history_forward.clone(),
|
||||
action_page_reload.clone(),
|
||||
);
|
||||
|
||||
let header = Header::new_rc(
|
||||
@ -58,7 +56,6 @@ impl Window {
|
||||
action_page_home,
|
||||
action_page_history_back,
|
||||
action_page_history_forward,
|
||||
action_page_reload,
|
||||
// Widgets
|
||||
tab.gobject(),
|
||||
);
|
||||
@ -76,7 +73,12 @@ impl Window {
|
||||
|
||||
action.pin().connect_activate({
|
||||
let tab = tab.clone();
|
||||
move |page_position| tab.pin(page_position)
|
||||
move |position| tab.pin(position)
|
||||
});
|
||||
|
||||
action.reload().connect_activate({
|
||||
let tab = tab.clone();
|
||||
move |position| tab.page_reload(position)
|
||||
});
|
||||
|
||||
// Init struct
|
||||
@ -101,11 +103,6 @@ impl Window {
|
||||
self.tab.page_history_forward(page_position);
|
||||
}
|
||||
|
||||
/// Reload page at given position or selected page on `None` given
|
||||
pub fn tab_page_reload(&self, position: Option<i32>) {
|
||||
self.tab.page_reload(position);
|
||||
}
|
||||
|
||||
/// Close page at given position or selected page on `None` given
|
||||
pub fn tab_close(&self, page_position: Option<i32>) {
|
||||
self.tab.close(page_position);
|
||||
|
@ -1,8 +1,10 @@
|
||||
mod append;
|
||||
mod pin;
|
||||
mod reload;
|
||||
|
||||
use append::Append;
|
||||
use pin::Pin;
|
||||
use reload::Reload;
|
||||
|
||||
use gtk::{
|
||||
gio::SimpleActionGroup,
|
||||
@ -16,6 +18,7 @@ pub struct Action {
|
||||
// Actions
|
||||
append: Rc<Append>,
|
||||
pin: Rc<Pin>,
|
||||
reload: Rc<Reload>,
|
||||
// Group
|
||||
id: GString,
|
||||
gobject: SimpleActionGroup,
|
||||
@ -29,6 +32,7 @@ impl Action {
|
||||
// Init actions
|
||||
let append = Rc::new(Append::new());
|
||||
let pin = Rc::new(Pin::new());
|
||||
let reload = Rc::new(Reload::new());
|
||||
|
||||
// Generate unique group ID
|
||||
let id = uuid_string_random();
|
||||
@ -39,11 +43,13 @@ impl Action {
|
||||
// Add action to given group
|
||||
gobject.add_action(append.gobject());
|
||||
gobject.add_action(pin.gobject());
|
||||
gobject.add_action(reload.gobject());
|
||||
|
||||
// Done
|
||||
Self {
|
||||
append,
|
||||
pin,
|
||||
reload,
|
||||
id,
|
||||
gobject,
|
||||
}
|
||||
@ -61,6 +67,11 @@ impl Action {
|
||||
&self.pin
|
||||
}
|
||||
|
||||
/// Get reference `Reload` action
|
||||
pub fn reload(&self) -> &Rc<Reload> {
|
||||
&self.reload
|
||||
}
|
||||
|
||||
/// Get auto-generated name for action group
|
||||
/// * useful for manual relationship with GObjects or as the `detailed_name`
|
||||
/// for [Accels](https://docs.gtk.org/gtk4/method.Application.set_accels_for_action.html) or
|
||||
|
@ -57,7 +57,7 @@ impl Pin {
|
||||
let state = self
|
||||
.gobject
|
||||
.state()
|
||||
.expect("Required state value")
|
||||
.expect("State value required")
|
||||
.get::<i32>()
|
||||
.expect("Parameter type does not match `i32`");
|
||||
|
||||
|
85
src/app/browser/window/action/reload.rs
Normal file
85
src/app/browser/window/action/reload.rs
Normal file
@ -0,0 +1,85 @@
|
||||
use gtk::{
|
||||
gio::SimpleAction,
|
||||
glib::{uuid_string_random, GString},
|
||||
prelude::{ActionExt, ToVariant},
|
||||
};
|
||||
|
||||
// Defaults
|
||||
|
||||
/// C-compatible variant type
|
||||
const DEFAULT_STATE: i32 = -1;
|
||||
|
||||
/// [SimpleAction](https://docs.gtk.org/gio/class.SimpleAction.html) wrapper for `Reload` action of `Window` group
|
||||
pub struct Reload {
|
||||
gobject: SimpleAction,
|
||||
}
|
||||
|
||||
impl Reload {
|
||||
// Constructors
|
||||
|
||||
/// Create new `Self`
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
gobject: SimpleAction::new_stateful(
|
||||
&uuid_string_random(),
|
||||
None,
|
||||
&DEFAULT_STATE.to_variant(),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
// Actions
|
||||
|
||||
/// Emit [activate](https://docs.gtk.org/gio/signal.SimpleAction.activate.html) signal
|
||||
pub fn activate(&self) {
|
||||
self.gobject.activate(None);
|
||||
}
|
||||
|
||||
/// Change action [state](https://docs.gtk.org/gio/method.SimpleAction.set_state.html)
|
||||
/// * set `DEFAULT_STATE` on `None`
|
||||
pub fn change_state(&self, state: Option<i32>) {
|
||||
self.gobject.change_state(
|
||||
&match state {
|
||||
Some(value) => value,
|
||||
None => DEFAULT_STATE,
|
||||
}
|
||||
.to_variant(),
|
||||
)
|
||||
}
|
||||
|
||||
// Events
|
||||
|
||||
/// Define callback function for
|
||||
/// [SimpleAction::activate](https://docs.gtk.org/gio/signal.SimpleAction.activate.html) signal
|
||||
pub fn connect_activate(&self, callback: impl Fn(Option<i32>) + 'static) {
|
||||
let state = self.state();
|
||||
self.gobject.connect_activate(move |_, _| callback(state));
|
||||
}
|
||||
|
||||
// Getters
|
||||
|
||||
pub fn state(&self) -> Option<i32> {
|
||||
let state = self
|
||||
.gobject
|
||||
.state()
|
||||
.expect("State value required")
|
||||
.get::<i32>()
|
||||
.expect("Parameter type does not match `i32`");
|
||||
|
||||
if state != DEFAULT_STATE {
|
||||
Some(state)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Get reference to [SimpleAction](https://docs.gtk.org/gio/class.SimpleAction.html) GObject
|
||||
pub fn gobject(&self) -> &SimpleAction {
|
||||
&self.gobject
|
||||
}
|
||||
|
||||
/// Get auto-generated [action name](https://docs.gtk.org/gio/property.SimpleAction.name.html)
|
||||
pub fn id(&self) -> GString {
|
||||
self.gobject.name()
|
||||
}
|
||||
}
|
@ -25,7 +25,6 @@ impl Header {
|
||||
action_page_home: SimpleAction,
|
||||
action_page_history_back: SimpleAction,
|
||||
action_page_history_forward: SimpleAction,
|
||||
action_page_reload: SimpleAction,
|
||||
// Widgets
|
||||
tab_view: &TabView,
|
||||
) -> Rc<Self> {
|
||||
@ -38,7 +37,6 @@ impl Header {
|
||||
action_page_home,
|
||||
action_page_history_back,
|
||||
action_page_history_forward,
|
||||
action_page_reload,
|
||||
tab_view,
|
||||
);
|
||||
|
||||
|
@ -28,7 +28,6 @@ impl Bar {
|
||||
action_page_home: SimpleAction,
|
||||
action_page_history_back: SimpleAction,
|
||||
action_page_history_forward: SimpleAction,
|
||||
action_page_reload: SimpleAction,
|
||||
view: &TabView,
|
||||
) -> Rc<Self> {
|
||||
// Init components
|
||||
@ -42,7 +41,6 @@ impl Bar {
|
||||
action_page_home,
|
||||
action_page_history_back,
|
||||
action_page_history_forward,
|
||||
action_page_reload,
|
||||
);
|
||||
|
||||
// Build result
|
||||
|
@ -24,7 +24,6 @@ impl Menu {
|
||||
action_page_home: SimpleAction,
|
||||
action_page_history_back: SimpleAction,
|
||||
action_page_history_forward: SimpleAction,
|
||||
action_page_reload: SimpleAction,
|
||||
) -> Rc<Self> {
|
||||
// Main
|
||||
let main = gio::Menu::new();
|
||||
@ -37,7 +36,12 @@ impl Menu {
|
||||
window_action.append().id()
|
||||
)));
|
||||
|
||||
main_page.append(Some("Reload"), Some(&detailed_action_name(&action_page_reload)));
|
||||
main_page.append(Some("Reload"), Some(&format!(
|
||||
"{}.{}",
|
||||
window_action.id(),
|
||||
window_action.reload().id()
|
||||
)));
|
||||
|
||||
main_page.append(Some("Pin"), Some(&format!(
|
||||
"{}.{}",
|
||||
window_action.id(),
|
||||
|
@ -30,7 +30,6 @@ pub struct Tab {
|
||||
action_page_home: SimpleAction,
|
||||
action_page_history_back: SimpleAction,
|
||||
action_page_history_forward: SimpleAction,
|
||||
action_page_reload: SimpleAction,
|
||||
// Dynamically allocated reference index
|
||||
index: Rc<RefCell<HashMap<GString, Rc<Item>>>>,
|
||||
action: Rc<Action>,
|
||||
@ -47,7 +46,6 @@ impl Tab {
|
||||
action_page_home: SimpleAction,
|
||||
action_page_history_back: SimpleAction,
|
||||
action_page_history_forward: SimpleAction,
|
||||
action_page_reload: SimpleAction,
|
||||
) -> Rc<Self> {
|
||||
// Init local actions
|
||||
let action = Rc::new(Action::new());
|
||||
@ -63,7 +61,6 @@ impl Tab {
|
||||
action_page_history_back.clone(),
|
||||
action_page_history_forward.clone(),
|
||||
action_page_home.clone(),
|
||||
action_page_reload.clone(),
|
||||
);
|
||||
|
||||
// Init widget
|
||||
@ -82,7 +79,6 @@ impl Tab {
|
||||
let action_page_home = action_page_home.clone();
|
||||
let action_page_history_back = action_page_history_back.clone();
|
||||
let action_page_history_forward = action_page_history_forward.clone();
|
||||
let action_page_reload = action_page_reload.clone();
|
||||
|
||||
move |request| {
|
||||
// Init new tab item
|
||||
@ -96,7 +92,6 @@ impl Tab {
|
||||
action_page_home.clone(),
|
||||
action_page_history_back.clone(),
|
||||
action_page_history_forward.clone(),
|
||||
action_page_reload.clone(),
|
||||
// Options
|
||||
gobject
|
||||
.selected_page()
|
||||
@ -123,7 +118,6 @@ impl Tab {
|
||||
let action_page_history_forward = action_page_history_forward.clone();
|
||||
let action_page_home = action_page_home.clone();
|
||||
let window_action = window_action.clone();
|
||||
let action_page_reload = action_page_reload.clone();
|
||||
move |tab_view, tab_page| {
|
||||
// Update actions
|
||||
let state_v2 = match tab_page {
|
||||
@ -133,6 +127,7 @@ impl Tab {
|
||||
None => None,
|
||||
}; // @TODO
|
||||
window_action.pin().change_state(state_v2);
|
||||
window_action.reload().change_state(state_v2);
|
||||
|
||||
// @TODO old version requires update
|
||||
// Setup state for selected page
|
||||
@ -147,7 +142,6 @@ impl Tab {
|
||||
action_page_history_back.change_state(&state);
|
||||
action_page_history_forward.change_state(&state);
|
||||
action_page_home.change_state(&state);
|
||||
action_page_reload.change_state(&state);
|
||||
}
|
||||
});
|
||||
|
||||
@ -191,7 +185,6 @@ impl Tab {
|
||||
action_page_home,
|
||||
action_page_history_back,
|
||||
action_page_history_forward,
|
||||
action_page_reload,
|
||||
// Init empty HashMap index as no tabs appended yet
|
||||
index,
|
||||
action,
|
||||
@ -212,7 +205,6 @@ impl Tab {
|
||||
self.action_page_home.clone(),
|
||||
self.action_page_history_back.clone(),
|
||||
self.action_page_history_forward.clone(),
|
||||
self.action_page_reload.clone(),
|
||||
// Options
|
||||
position,
|
||||
false,
|
||||
@ -356,7 +348,6 @@ impl Tab {
|
||||
self.action_page_home.clone(),
|
||||
self.action_page_history_back.clone(),
|
||||
self.action_page_history_forward.clone(),
|
||||
self.action_page_reload.clone(),
|
||||
) {
|
||||
Ok(items) => {
|
||||
for item in items {
|
||||
|
@ -38,7 +38,6 @@ impl Item {
|
||||
action_page_home: SimpleAction,
|
||||
action_page_history_back: SimpleAction,
|
||||
action_page_history_forward: SimpleAction,
|
||||
action_page_reload: SimpleAction,
|
||||
// Options
|
||||
position: Option<i32>,
|
||||
is_pinned: bool,
|
||||
@ -52,11 +51,11 @@ impl Item {
|
||||
id.clone(),
|
||||
// Actions
|
||||
browser_action,
|
||||
window_action,
|
||||
tab_action,
|
||||
action_page_home.clone(),
|
||||
action_page_history_back.clone(),
|
||||
action_page_history_forward.clone(),
|
||||
action_page_reload.clone(),
|
||||
);
|
||||
|
||||
let widget = Widget::new_rc(
|
||||
@ -139,7 +138,6 @@ impl Item {
|
||||
action_page_home: SimpleAction,
|
||||
action_page_history_back: SimpleAction,
|
||||
action_page_history_forward: SimpleAction,
|
||||
action_page_reload: SimpleAction,
|
||||
) -> Result<Vec<Rc<Item>>, String> {
|
||||
let mut items = Vec::new();
|
||||
|
||||
@ -156,7 +154,6 @@ impl Item {
|
||||
action_page_home.clone(),
|
||||
action_page_history_back.clone(),
|
||||
action_page_history_forward.clone(),
|
||||
action_page_reload.clone(),
|
||||
// Options
|
||||
None,
|
||||
record.is_pinned,
|
||||
|
@ -13,6 +13,7 @@ use navigation::Navigation;
|
||||
use widget::Widget;
|
||||
|
||||
use crate::app::browser::action::Action as BrowserAction;
|
||||
use crate::app::browser::window::action::Action as WindowAction;
|
||||
use crate::app::browser::window::tab::action::Action as TabAction;
|
||||
use gtk::{
|
||||
gdk_pixbuf::Pixbuf,
|
||||
@ -37,6 +38,7 @@ pub struct Page {
|
||||
cancellable: RefCell<Cancellable>,
|
||||
// Actions
|
||||
browser_action: Rc<BrowserAction>,
|
||||
window_action: Rc<WindowAction>,
|
||||
tab_action: Rc<TabAction>,
|
||||
action_page_load: SimpleAction,
|
||||
// Components
|
||||
@ -56,11 +58,11 @@ impl Page {
|
||||
pub fn new_rc(
|
||||
id: GString,
|
||||
browser_action: Rc<BrowserAction>,
|
||||
window_action: Rc<WindowAction>,
|
||||
tab_action: Rc<TabAction>,
|
||||
action_page_home: SimpleAction,
|
||||
action_page_history_back: SimpleAction,
|
||||
action_page_history_forward: SimpleAction,
|
||||
action_page_reload: SimpleAction,
|
||||
) -> Rc<Self> {
|
||||
// Init local actions
|
||||
let action_page_load = SimpleAction::new(&uuid_string_random(), None);
|
||||
@ -72,10 +74,10 @@ impl Page {
|
||||
|
||||
let navigation = Navigation::new_rc(
|
||||
browser_action.clone(),
|
||||
window_action.clone(),
|
||||
action_page_home.clone(),
|
||||
action_page_history_back.clone(),
|
||||
action_page_history_forward.clone(),
|
||||
action_page_reload.clone(),
|
||||
action_page_open.clone(),
|
||||
);
|
||||
|
||||
@ -97,6 +99,7 @@ impl Page {
|
||||
id,
|
||||
// Actions
|
||||
browser_action,
|
||||
window_action,
|
||||
tab_action,
|
||||
action_page_load: action_page_load.clone(),
|
||||
// Components
|
||||
|
@ -15,6 +15,7 @@ use request::Request;
|
||||
use widget::Widget;
|
||||
|
||||
use crate::app::browser::action::Action as BrowserAction;
|
||||
use crate::app::browser::window::action::Action as WindowAction;
|
||||
use gtk::{gio::SimpleAction, glib::GString, prelude::WidgetExt, Box};
|
||||
use sqlite::Transaction;
|
||||
use std::rc::Rc;
|
||||
@ -31,16 +32,16 @@ pub struct Navigation {
|
||||
impl Navigation {
|
||||
pub fn new_rc(
|
||||
browser_action: Rc<BrowserAction>,
|
||||
window_action: Rc<WindowAction>,
|
||||
action_page_home: SimpleAction,
|
||||
action_page_history_back: SimpleAction,
|
||||
action_page_history_forward: SimpleAction,
|
||||
action_page_reload: SimpleAction,
|
||||
action_page_open: SimpleAction,
|
||||
) -> Rc<Self> {
|
||||
// Init components
|
||||
let home = Home::new_rc(action_page_home);
|
||||
let history = History::new_rc(action_page_history_back, action_page_history_forward);
|
||||
let reload = Reload::new_rc(action_page_reload.clone());
|
||||
let reload = Reload::new_rc(window_action);
|
||||
let request = Request::new_rc(browser_action, action_page_open.clone());
|
||||
let bookmark = Bookmark::new_rc();
|
||||
|
||||
|
@ -2,27 +2,31 @@ mod widget;
|
||||
|
||||
use widget::Widget;
|
||||
|
||||
use gtk::{gio::SimpleAction, Button};
|
||||
use crate::app::browser::window::action::Action as WindowAction;
|
||||
use gtk::Button;
|
||||
use std::rc::Rc;
|
||||
|
||||
pub struct Reload {
|
||||
action_page_reload: SimpleAction,
|
||||
window_action: Rc<WindowAction>,
|
||||
widget: Rc<Widget>,
|
||||
}
|
||||
|
||||
impl Reload {
|
||||
// Construct
|
||||
pub fn new_rc(action_page_reload: SimpleAction) -> Rc<Self> {
|
||||
pub fn new_rc(window_action: Rc<WindowAction>) -> Rc<Self> {
|
||||
Rc::new(Self {
|
||||
action_page_reload: action_page_reload.clone(),
|
||||
widget: Widget::new_rc(action_page_reload),
|
||||
window_action: window_action.clone(),
|
||||
widget: Widget::new_rc(window_action),
|
||||
})
|
||||
}
|
||||
|
||||
// Actions
|
||||
pub fn update(&self, is_enabled: bool) {
|
||||
// Update actions
|
||||
self.action_page_reload.set_enabled(is_enabled);
|
||||
self.window_action
|
||||
.reload()
|
||||
.gobject()
|
||||
.set_enabled(is_enabled);
|
||||
|
||||
// Update child components
|
||||
self.widget.update(is_enabled);
|
||||
|
@ -1,6 +1,6 @@
|
||||
use crate::app::browser::window::action::Action as WindowAction;
|
||||
use gtk::{
|
||||
gio::SimpleAction,
|
||||
prelude::{ActionExt, ButtonExt, WidgetExt},
|
||||
prelude::{ButtonExt, WidgetExt},
|
||||
Button,
|
||||
};
|
||||
use std::rc::Rc;
|
||||
@ -11,7 +11,7 @@ pub struct Widget {
|
||||
|
||||
impl Widget {
|
||||
// Construct
|
||||
pub fn new_rc(action_page_reload: SimpleAction) -> Rc<Self> {
|
||||
pub fn new_rc(window_action: Rc<WindowAction>) -> Rc<Self> {
|
||||
// Init gobject
|
||||
let gobject = Button::builder()
|
||||
.icon_name("view-refresh-symbolic")
|
||||
@ -20,12 +20,7 @@ impl Widget {
|
||||
.build();
|
||||
|
||||
// Init events
|
||||
gobject.connect_clicked({
|
||||
let action_page_reload = action_page_reload.clone();
|
||||
move |_| {
|
||||
action_page_reload.activate(None);
|
||||
}
|
||||
});
|
||||
gobject.connect_clicked(move |_| window_action.reload().activate());
|
||||
|
||||
// Return activated struct
|
||||
Rc::new(Self { gobject })
|
||||
|
@ -21,13 +21,16 @@ impl Menu {
|
||||
action_page_history_back: SimpleAction,
|
||||
action_page_history_forward: SimpleAction,
|
||||
action_page_home: SimpleAction,
|
||||
action_page_reload: SimpleAction,
|
||||
) -> Self {
|
||||
let main = gtk::gio::Menu::new();
|
||||
|
||||
main.append(
|
||||
Some("Reload"),
|
||||
Some(&detailed_action_name(action_page_reload)),
|
||||
Some(&format!(
|
||||
"{}.{}",
|
||||
window_action.id(),
|
||||
window_action.reload().id()
|
||||
)),
|
||||
);
|
||||
|
||||
main.append(
|
||||
|
Loading…
x
Reference in New Issue
Block a user