mirror of
https://github.com/FliegendeWurst/cursive.git
synced 2024-11-23 17:35:00 +00:00
Add AnyCb type alias
This commit is contained in:
parent
8c00b171c0
commit
39babacbf5
15
src/event.rs
15
src/event.rs
@ -17,6 +17,7 @@ use Cursive;
|
||||
use std::ops::Deref;
|
||||
use std::rc::Rc;
|
||||
use vec::Vec2;
|
||||
use std::any::Any;
|
||||
|
||||
/// Callback is a function that can be triggered by an event.
|
||||
/// It has a mutable access to the cursive root.
|
||||
@ -24,6 +25,9 @@ use vec::Vec2;
|
||||
pub struct Callback(Rc<Box<Fn(&mut Cursive)>>);
|
||||
// TODO: remove the Box when Box<T: Sized> -> Rc<T> is possible
|
||||
|
||||
/// A boxed callback that can be run on `&mut Any`.
|
||||
pub type AnyCb<'a> = Box<FnMut(&mut Any) + 'a>;
|
||||
|
||||
impl Callback {
|
||||
/// Wraps the given function into a `Callback` object.
|
||||
pub fn from_fn<F>(f: F) -> Self
|
||||
@ -343,6 +347,17 @@ impl Event {
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a mutable reference to the position of the mouse/
|
||||
///
|
||||
/// Returns `None` if `self` is not a mouse event.
|
||||
pub fn mouse_position_mut(&mut self) -> Option<&mut Vec2> {
|
||||
if let Event::Mouse { ref mut position, .. } = *self {
|
||||
Some(position)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Update `self` with the given offset.
|
||||
///
|
||||
/// If `self` is a mouse event, adds `top_left` to its offset.
|
||||
|
@ -1,6 +1,6 @@
|
||||
use Printer;
|
||||
use direction::Direction;
|
||||
use event::{Event, EventResult};
|
||||
use event::{AnyCb, Event, EventResult};
|
||||
use rect::Rect;
|
||||
use std::any::Any;
|
||||
use vec::Vec2;
|
||||
@ -73,7 +73,7 @@ pub trait View: Any + AnyView {
|
||||
/// If the selector doesn't find a match, the closure will not be run.
|
||||
///
|
||||
/// Default implementation is a no-op.
|
||||
fn call_on_any<'a>(&mut self, _: &Selector, _: Box<FnMut(&mut Any) + 'a>) {
|
||||
fn call_on_any<'a>(&mut self, _: &Selector, _: AnyCb<'a>) {
|
||||
// TODO: FnMut -> FnOnce once it works
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
use Printer;
|
||||
use direction::Direction;
|
||||
use event::{Event, EventResult};
|
||||
use event::{AnyCb, Event, EventResult};
|
||||
use rect::Rect;
|
||||
use std::any::Any;
|
||||
use vec::Vec2;
|
||||
@ -79,7 +79,7 @@ pub trait ViewWrapper: 'static {
|
||||
|
||||
/// Wraps the `find` method.
|
||||
fn wrap_call_on_any<'a>(
|
||||
&mut self, selector: &Selector, callback: Box<FnMut(&mut Any) + 'a>
|
||||
&mut self, selector: &Selector, callback: AnyCb<'a>
|
||||
) {
|
||||
self.with_view_mut(|v| v.call_on_any(selector, callback));
|
||||
}
|
||||
@ -92,8 +92,7 @@ pub trait ViewWrapper: 'static {
|
||||
|
||||
/// Wraps the `needs_relayout` method.
|
||||
fn wrap_needs_relayout(&self) -> bool {
|
||||
self.with_view(|v| v.needs_relayout())
|
||||
.unwrap_or(true)
|
||||
self.with_view(|v| v.needs_relayout()).unwrap_or(true)
|
||||
}
|
||||
|
||||
/// Wraps the `important_area` method.
|
||||
|
@ -1,9 +1,10 @@
|
||||
use Printer;
|
||||
use With;
|
||||
use direction::Direction;
|
||||
use event::{Event, EventResult};
|
||||
use event::{AnyCb, Event, EventResult};
|
||||
use rect::Rect;
|
||||
use vec::Vec2;
|
||||
use view::View;
|
||||
use view::{Selector, View};
|
||||
|
||||
/// A blank view that forwards calls to closures.
|
||||
///
|
||||
@ -17,6 +18,9 @@ pub struct Canvas<T> {
|
||||
layout: Box<FnMut(&mut T, Vec2)>,
|
||||
take_focus: Box<FnMut(&mut T, Direction) -> bool>,
|
||||
needs_relayout: Box<Fn(&T) -> bool>,
|
||||
focus_view: Box<FnMut(&mut T, &Selector) -> Result<(), ()>>,
|
||||
call_on_any: Box<for<'a> FnMut(&mut T, &Selector, AnyCb<'a>)>,
|
||||
important_area: Box<Fn(&T, Vec2) -> Rect>,
|
||||
}
|
||||
|
||||
impl<T: 'static + View> Canvas<T> {
|
||||
@ -31,6 +35,9 @@ impl<T: 'static + View> Canvas<T> {
|
||||
.with_layout(T::layout)
|
||||
.with_take_focus(T::take_focus)
|
||||
.with_needs_relayout(T::needs_relayout)
|
||||
.with_focus_view(T::focus_view)
|
||||
.with_call_on_any(T::call_on_any)
|
||||
.with_important_area(T::important_area)
|
||||
}
|
||||
}
|
||||
|
||||
@ -55,6 +62,11 @@ impl<T> Canvas<T> {
|
||||
layout: Box::new(|_, _| ()),
|
||||
take_focus: Box::new(|_, _| false),
|
||||
needs_relayout: Box::new(|_| true),
|
||||
focus_view: Box::new(|_, _| Err(())),
|
||||
call_on_any: Box::new(|_, _, _| ()),
|
||||
important_area: Box::new(|_, size| {
|
||||
Rect::from_corners((0, 0), size)
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
@ -170,6 +182,60 @@ impl<T> Canvas<T> {
|
||||
{
|
||||
self.with(|s| s.set_needs_relayout(f))
|
||||
}
|
||||
|
||||
/// Sets the closure for `call_on_any()`.
|
||||
pub fn set_call_on_any<F>(&mut self, f: F)
|
||||
where
|
||||
F: 'static + for<'a> FnMut(&mut T, &Selector, AnyCb<'a>),
|
||||
{
|
||||
self.call_on_any = Box::new(f);
|
||||
}
|
||||
|
||||
/// Sets the closure for `call_on_any()`.
|
||||
///
|
||||
/// Chainable variant.
|
||||
pub fn with_call_on_any<F>(self, f: F) -> Self
|
||||
where
|
||||
F: 'static + for<'a> FnMut(&mut T, &Selector, AnyCb<'a>),
|
||||
{
|
||||
self.with(|s| s.set_call_on_any(f))
|
||||
}
|
||||
|
||||
/// Sets the closure for `important_area()`.
|
||||
pub fn set_important_area<F>(&mut self, f: F)
|
||||
where
|
||||
F: 'static + Fn(&T, Vec2) -> Rect,
|
||||
{
|
||||
self.important_area = Box::new(f);
|
||||
}
|
||||
|
||||
/// Sets the closure for `important_area()`.
|
||||
///
|
||||
/// Chainable variant.
|
||||
pub fn with_important_area<F>(self, f: F) -> Self
|
||||
where
|
||||
F: 'static + Fn(&T, Vec2) -> Rect,
|
||||
{
|
||||
self.with(|s| s.set_important_area(f))
|
||||
}
|
||||
|
||||
/// Sets the closure for `focus_view()`.
|
||||
pub fn set_focus_view<F>(&mut self, f: F)
|
||||
where
|
||||
F: 'static + FnMut(&mut T, &Selector) -> Result<(), ()>,
|
||||
{
|
||||
self.focus_view = Box::new(f);
|
||||
}
|
||||
|
||||
/// Sets the closure for `focus_view()`.
|
||||
///
|
||||
/// Chainable variant.
|
||||
pub fn with_focus_view<F>(self, f: F) -> Self
|
||||
where
|
||||
F: 'static + FnMut(&mut T, &Selector) -> Result<(), ()>,
|
||||
{
|
||||
self.with(|s| s.set_focus_view(f))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: 'static> View for Canvas<T> {
|
||||
@ -192,4 +258,20 @@ impl<T: 'static> View for Canvas<T> {
|
||||
fn take_focus(&mut self, source: Direction) -> bool {
|
||||
(self.take_focus)(&mut self.state, source)
|
||||
}
|
||||
|
||||
fn needs_relayout(&self) -> bool {
|
||||
(self.needs_relayout)(&self.state)
|
||||
}
|
||||
|
||||
fn focus_view(&mut self, selector: &Selector) -> Result<(), ()> {
|
||||
(self.focus_view)(&mut self.state, selector)
|
||||
}
|
||||
|
||||
fn important_area(&self, view_size: Vec2) -> Rect {
|
||||
(self.important_area)(&self.state, view_size)
|
||||
}
|
||||
|
||||
fn call_on_any<'a>(&mut self, selector: &Selector, cb: AnyCb<'a>) {
|
||||
(self.call_on_any)(&mut self.state, selector, cb);
|
||||
}
|
||||
}
|
||||
|
@ -3,9 +3,8 @@ use Printer;
|
||||
use With;
|
||||
use align::*;
|
||||
use direction::Direction;
|
||||
use event::*;
|
||||
use event::{AnyCb, Event, EventResult, Key};
|
||||
use rect::Rect;
|
||||
use std::any::Any;
|
||||
use std::cell::Cell;
|
||||
use std::cmp::max;
|
||||
use theme::ColorStyle;
|
||||
@ -249,11 +248,7 @@ impl Dialog {
|
||||
pub fn buttons_mut<'a>(
|
||||
&'a mut self
|
||||
) -> Box<'a + Iterator<Item = &'a mut Button>> {
|
||||
Box::new(
|
||||
self.buttons
|
||||
.iter_mut()
|
||||
.map(|b| &mut b.button.view),
|
||||
)
|
||||
Box::new(self.buttons.iter_mut().map(|b| &mut b.button.view))
|
||||
}
|
||||
|
||||
/// Returns currently focused element
|
||||
@ -566,9 +561,7 @@ impl View for Dialog {
|
||||
}
|
||||
}
|
||||
|
||||
fn call_on_any<'a>(
|
||||
&mut self, selector: &Selector, callback: Box<FnMut(&mut Any) + 'a>
|
||||
) {
|
||||
fn call_on_any<'a>(&mut self, selector: &Selector, callback: AnyCb<'a>) {
|
||||
self.content.call_on_any(selector, callback);
|
||||
}
|
||||
|
||||
|
@ -2,9 +2,8 @@ use Printer;
|
||||
use With;
|
||||
use XY;
|
||||
use direction;
|
||||
use event::{Event, EventResult, Key};
|
||||
use event::{AnyCb, Event, EventResult, Key};
|
||||
use rect::Rect;
|
||||
use std::any::Any;
|
||||
use std::cmp::min;
|
||||
use std::ops::Deref;
|
||||
use vec::Vec2;
|
||||
@ -81,10 +80,8 @@ impl<'a, T: Deref<Target = Child>, I: Iterator<Item = T>> Iterator
|
||||
|
||||
// eprintln!("Available: {}", self.available);
|
||||
|
||||
let length = min(
|
||||
self.available,
|
||||
*child.size.get(self.orientation),
|
||||
);
|
||||
let length =
|
||||
min(self.available, *child.size.get(self.orientation));
|
||||
|
||||
// Allocated width
|
||||
self.available = self.available.saturating_sub(length);
|
||||
@ -175,9 +172,7 @@ impl LinearLayout {
|
||||
|
||||
/// Returns a mutable reference to a child.
|
||||
pub fn get_child_mut(&mut self, i: usize) -> Option<&mut View> {
|
||||
self.children
|
||||
.get_mut(i)
|
||||
.map(|child| &mut *child.view)
|
||||
self.children.get_mut(i).map(|child| &mut *child.view)
|
||||
}
|
||||
|
||||
// If the cache can be used, return the cached size.
|
||||
@ -226,27 +221,21 @@ impl LinearLayout {
|
||||
} else {
|
||||
self.children.len()
|
||||
};
|
||||
Box::new(
|
||||
self.children[..end]
|
||||
.iter_mut()
|
||||
.enumerate()
|
||||
.rev(),
|
||||
)
|
||||
Box::new(self.children[..end].iter_mut().enumerate().rev())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn move_focus(&mut self, source: direction::Direction) -> EventResult {
|
||||
let i = if let Some(i) = source.relative(self.orientation).and_then(
|
||||
|rel| {
|
||||
let i = if let Some(i) =
|
||||
source.relative(self.orientation).and_then(|rel| {
|
||||
// The iterator starts at the focused element.
|
||||
// We don't want that one.
|
||||
self.iter_mut(true, rel)
|
||||
.skip(1)
|
||||
.filter_map(|p| try_focus(p, source))
|
||||
.next()
|
||||
},
|
||||
) {
|
||||
}) {
|
||||
i
|
||||
} else {
|
||||
return EventResult::Ignored;
|
||||
@ -291,9 +280,7 @@ impl LinearLayout {
|
||||
let child_size = item.child.size.get(self.orientation);
|
||||
|
||||
if (item.offset + child_size > position)
|
||||
&& item.child
|
||||
.view
|
||||
.take_focus(direction::Direction::none())
|
||||
&& item.child.view.take_focus(direction::Direction::none())
|
||||
{
|
||||
// eprintln!("It's a match!");
|
||||
self.focus = i;
|
||||
@ -359,9 +346,7 @@ impl View for LinearLayout {
|
||||
// Every item has the same size orthogonal to the layout
|
||||
item.child.size.set_axis_from(o.swap(), &size);
|
||||
|
||||
item.child
|
||||
.view
|
||||
.layout(size.with_axis(o, item.length));
|
||||
item.child.view.layout(size.with_axis(o, item.length));
|
||||
}
|
||||
}
|
||||
|
||||
@ -438,11 +423,7 @@ impl View for LinearLayout {
|
||||
let mut overweight: Vec<(usize, usize)> = ideal_sizes
|
||||
.iter()
|
||||
.map(|v| self.orientation.get(v))
|
||||
.zip(
|
||||
min_sizes
|
||||
.iter()
|
||||
.map(|v| self.orientation.get(v)),
|
||||
)
|
||||
.zip(min_sizes.iter().map(|v| self.orientation.get(v)))
|
||||
.map(|(a, b)| a.saturating_sub(b))
|
||||
.enumerate()
|
||||
.collect();
|
||||
@ -529,9 +510,7 @@ impl View for LinearLayout {
|
||||
);
|
||||
let item = iterator.nth(self.focus).unwrap();
|
||||
let offset = self.orientation.make_vec(item.offset, 0);
|
||||
item.child
|
||||
.view
|
||||
.on_event(event.relativized(offset))
|
||||
item.child.view.on_event(event.relativized(offset))
|
||||
};
|
||||
match result {
|
||||
EventResult::Ignored => match event {
|
||||
@ -574,8 +553,7 @@ impl View for LinearLayout {
|
||||
}
|
||||
|
||||
fn call_on_any<'a>(
|
||||
&mut self, selector: &Selector,
|
||||
mut callback: Box<FnMut(&mut Any) + 'a>,
|
||||
&mut self, selector: &Selector, mut callback: AnyCb<'a>
|
||||
) {
|
||||
for child in &mut self.children {
|
||||
child
|
||||
|
@ -2,9 +2,8 @@ use Cursive;
|
||||
use Printer;
|
||||
use With;
|
||||
use direction;
|
||||
use event::{Callback, Event, EventResult, Key, MouseButton, MouseEvent};
|
||||
use event::{AnyCb, Callback, Event, EventResult, Key, MouseButton, MouseEvent};
|
||||
use rect::Rect;
|
||||
use std::any::Any;
|
||||
use std::rc::Rc;
|
||||
use unicode_width::UnicodeWidthStr;
|
||||
use vec::Vec2;
|
||||
@ -94,10 +93,8 @@ impl ListView {
|
||||
/// Adds a view to the end of the list.
|
||||
pub fn add_child<V: View + 'static>(&mut self, label: &str, mut view: V) {
|
||||
view.take_focus(direction::Direction::none());
|
||||
self.children.push(ListChild::Row(
|
||||
label.to_string(),
|
||||
Box::new(view),
|
||||
));
|
||||
self.children
|
||||
.push(ListChild::Row(label.to_string(), Box::new(view)));
|
||||
}
|
||||
|
||||
/// Removes all children from this view.
|
||||
@ -169,12 +166,7 @@ impl ListView {
|
||||
} else {
|
||||
self.children.len()
|
||||
};
|
||||
Box::new(
|
||||
self.children[..end]
|
||||
.iter_mut()
|
||||
.enumerate()
|
||||
.rev(),
|
||||
)
|
||||
Box::new(self.children[..end].iter_mut().enumerate().rev())
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -313,8 +305,7 @@ impl View for ListView {
|
||||
|
||||
fn layout(&mut self, size: Vec2) {
|
||||
self.last_size = size;
|
||||
self.scrollbase
|
||||
.set_heights(size.y, self.children.len());
|
||||
self.scrollbase.set_heights(size.y, self.children.len());
|
||||
|
||||
// We'll show 2 columns: the labels, and the views.
|
||||
let label_width = self.children
|
||||
@ -325,21 +316,14 @@ impl View for ListView {
|
||||
.unwrap_or(0);
|
||||
|
||||
let spacing = 1;
|
||||
let scrollbar_width = if self.children.len() > size.y {
|
||||
2
|
||||
} else {
|
||||
0
|
||||
};
|
||||
let scrollbar_width = if self.children.len() > size.y { 2 } else { 0 };
|
||||
|
||||
let available = size.x
|
||||
.saturating_sub(label_width + spacing + scrollbar_width);
|
||||
|
||||
debug!("Available: {}", available);
|
||||
|
||||
for child in self.children
|
||||
.iter_mut()
|
||||
.filter_map(ListChild::view)
|
||||
{
|
||||
for child in self.children.iter_mut().filter_map(ListChild::view) {
|
||||
child.layout(Vec2::new(available, 1));
|
||||
}
|
||||
}
|
||||
@ -358,8 +342,7 @@ impl View for ListView {
|
||||
} if position
|
||||
.checked_sub(offset)
|
||||
.map(|position| {
|
||||
self.scrollbase
|
||||
.start_drag(position, self.last_size.x)
|
||||
self.scrollbase.start_drag(position, self.last_size.x)
|
||||
})
|
||||
.unwrap_or(false) =>
|
||||
{
|
||||
@ -394,8 +377,7 @@ impl View for ListView {
|
||||
if let ListChild::Row(_, ref mut view) = self.children[self.focus] {
|
||||
// If self.focus < self.scrollbase.start_line, it means the focus is not
|
||||
// in view. Something's fishy, so don't send the event.
|
||||
if let Some(y) = self.focus
|
||||
.checked_sub(self.scrollbase.start_line)
|
||||
if let Some(y) = self.focus.checked_sub(self.scrollbase.start_line)
|
||||
{
|
||||
let offset = (labels_width + 1, y);
|
||||
let result = view.on_event(event.relativized(offset));
|
||||
@ -419,10 +401,12 @@ impl View for ListView {
|
||||
Event::Key(Key::PageDown) => {
|
||||
self.move_focus(10, direction::Direction::up())
|
||||
}
|
||||
Event::Key(Key::Home) | Event::Ctrl(Key::Home) => self.move_focus(
|
||||
Event::Key(Key::Home) | Event::Ctrl(Key::Home) => {
|
||||
self.move_focus(
|
||||
usize::max_value(),
|
||||
direction::Direction::back(),
|
||||
),
|
||||
)
|
||||
}
|
||||
Event::Key(Key::End) | Event::Ctrl(Key::End) => self.move_focus(
|
||||
usize::max_value(),
|
||||
direction::Direction::front(),
|
||||
@ -472,13 +456,9 @@ impl View for ListView {
|
||||
}
|
||||
|
||||
fn call_on_any<'a>(
|
||||
&mut self, selector: &Selector,
|
||||
mut callback: Box<FnMut(&mut Any) + 'a>,
|
||||
&mut self, selector: &Selector, mut callback: AnyCb<'a>
|
||||
) {
|
||||
for view in self.children
|
||||
.iter_mut()
|
||||
.filter_map(ListChild::view)
|
||||
{
|
||||
for view in self.children.iter_mut().filter_map(ListChild::view) {
|
||||
view.call_on_any(selector, Box::new(|any| callback(any)));
|
||||
}
|
||||
}
|
||||
|
@ -3,14 +3,15 @@ use view::View;
|
||||
use view::ViewWrapper;
|
||||
|
||||
/// Wrapper around a view that remembers its size.
|
||||
pub struct SizedView<T: View> {
|
||||
pub struct SizedView<T> {
|
||||
/// Wrapped view.
|
||||
pub view: T,
|
||||
/// Cached size from the last layout() call.
|
||||
pub size: Vec2,
|
||||
}
|
||||
|
||||
impl<T: View> SizedView<T> {
|
||||
impl<T> SizedView<T> {
|
||||
|
||||
/// Wraps the given view.
|
||||
pub fn new(view: T) -> Self {
|
||||
SizedView {
|
||||
|
@ -1,8 +1,7 @@
|
||||
use Printer;
|
||||
use With;
|
||||
use direction::Direction;
|
||||
use event::{Event, EventResult};
|
||||
use std::any::Any;
|
||||
use event::{AnyCb, Event, EventResult};
|
||||
use std::cell;
|
||||
use std::ops::Deref;
|
||||
use theme::ColorStyle;
|
||||
@ -65,13 +64,9 @@ impl<T: View> ChildWrapper<T> {
|
||||
fn unwrap(self) -> T {
|
||||
match self {
|
||||
// ShadowView::into_inner and Layer::into_inner can never fail.
|
||||
ChildWrapper::Shadow(shadow) => shadow
|
||||
.into_inner()
|
||||
.ok()
|
||||
.unwrap()
|
||||
.into_inner()
|
||||
.ok()
|
||||
.unwrap(),
|
||||
ChildWrapper::Shadow(shadow) => {
|
||||
shadow.into_inner().ok().unwrap().into_inner().ok().unwrap()
|
||||
}
|
||||
ChildWrapper::Plain(layer) => layer.into_inner().ok().unwrap(),
|
||||
}
|
||||
}
|
||||
@ -134,9 +129,7 @@ impl<T: View> View for ChildWrapper<T> {
|
||||
}
|
||||
}
|
||||
|
||||
fn call_on_any<'a>(
|
||||
&mut self, selector: &Selector, callback: Box<FnMut(&mut Any) + 'a>
|
||||
) {
|
||||
fn call_on_any<'a>(&mut self, selector: &Selector, callback: AnyCb<'a>) {
|
||||
match *self {
|
||||
ChildWrapper::Shadow(ref mut v) => {
|
||||
v.call_on_any(selector, callback)
|
||||
@ -216,9 +209,7 @@ impl StackView {
|
||||
/// Returns a reference to the layer at the given position.
|
||||
pub fn get(&self, pos: LayerPosition) -> Option<&View> {
|
||||
let i = self.get_index(pos);
|
||||
self.layers
|
||||
.get(i)
|
||||
.map(|child| child.view.get_inner())
|
||||
self.layers.get(i).map(|child| child.view.get_inner())
|
||||
}
|
||||
|
||||
/// Returns a mutable reference to the layer at the given position.
|
||||
@ -331,10 +322,7 @@ impl StackView {
|
||||
|
||||
/// Returns the size for each layer in this view.
|
||||
pub fn layer_sizes(&self) -> Vec<Vec2> {
|
||||
self.layers
|
||||
.iter()
|
||||
.map(|layer| layer.size)
|
||||
.collect()
|
||||
self.layers.iter().map(|layer| layer.size).collect()
|
||||
}
|
||||
|
||||
fn get_index(&self, pos: LayerPosition) -> usize {
|
||||
@ -535,8 +523,7 @@ impl View for StackView {
|
||||
}
|
||||
|
||||
fn call_on_any<'a>(
|
||||
&mut self, selector: &Selector,
|
||||
mut callback: Box<FnMut(&mut Any) + 'a>,
|
||||
&mut self, selector: &Selector, mut callback: AnyCb<'a>
|
||||
) {
|
||||
for layer in &mut self.layers {
|
||||
layer
|
||||
|
Loading…
Reference in New Issue
Block a user