Update the build environment and some architectural elements of the Kifu app #210
|
@ -39,12 +39,19 @@ where
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// LocalObserver creates a task on the current thread which watches the specified observer for notifications and calls the handler function with each one.
|
||||||
|
///
|
||||||
|
/// The LocalObserver starts a task which listens for notifications during the constructor. When the observer goes out of scope, it will make a point of aborting the task. This combination means that anything which uses the observer can create it, hold on to a reference of it, and then drop it when done, and not have to do anything else with the observer object.
|
||||||
struct LocalObserver<T> {
|
struct LocalObserver<T> {
|
||||||
join_handle: glib::JoinHandle<()>,
|
join_handle: glib::JoinHandle<()>,
|
||||||
handler: Rc<dyn Fn(T)>,
|
handler: Rc<dyn Fn(T)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: 'static> LocalObserver<T> {
|
impl<T: 'static> LocalObserver<T> {
|
||||||
|
/// Construct a new LocalObserver and start it running.
|
||||||
|
///
|
||||||
|
/// observable -- any object which emits events
|
||||||
|
/// handler -- a function which can process events
|
||||||
fn new(observable: &dyn Observable<T>, handler: impl Fn(T) + 'static) -> Self {
|
fn new(observable: &dyn Observable<T>, handler: impl Fn(T) + 'static) -> Self {
|
||||||
let listener = observable.subscribe();
|
let listener = observable.subscribe();
|
||||||
let handler = Rc::new(handler);
|
let handler = Rc::new(handler);
|
||||||
|
@ -54,8 +61,9 @@ impl<T: 'static> LocalObserver<T> {
|
||||||
loop {
|
loop {
|
||||||
match listener.recv().await {
|
match listener.recv().await {
|
||||||
Ok(msg) => handler(msg),
|
Ok(msg) => handler(msg),
|
||||||
Err(err) => {
|
Err(_) => {
|
||||||
unimplemented!("Should display an error message in the UI: {}", err)
|
// recv only fails if the channel has been closed and no other notifications are pending. This will break out of the loop and terminate the observer.
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
yield_now().await;
|
yield_now().await;
|
||||||
|
@ -71,6 +79,7 @@ impl<T: 'static> LocalObserver<T> {
|
||||||
|
|
||||||
impl<T> Drop for LocalObserver<T> {
|
impl<T> Drop for LocalObserver<T> {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
|
// Abort the task when the observer goes out of scope.
|
||||||
self.join_handle.abort();
|
self.join_handle.abort();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,7 @@ You should have received a copy of the GNU General Public License along with Kif
|
||||||
use crate::LocalObserver;
|
use crate::LocalObserver;
|
||||||
use kifu_core::{Core, CoreNotification};
|
use kifu_core::{Core, CoreNotification};
|
||||||
|
|
||||||
/// DatabaseViewModel controls the view that the user sees when starting the application if the application has been configured and if there are no games in progress. It provides a window into the database, showing a list of recently recorded games (whether from this app or from a main database). It also provides the UI for starting a new game. This will render an empty database view if the user hasn't configured a database yet.
|
/// Home controls the view that the user sees when starting the application if there are no games in progress. It provides a window into the database, showing a list of recently recorded games. It also provides the UI for starting a new game. This will render an empty database view if the user hasn't configured a database yet.
|
||||||
pub struct HomeViewModel {
|
pub struct HomeViewModel {
|
||||||
core: Core,
|
core: Core,
|
||||||
notification_observer: LocalObserver<CoreNotification>,
|
notification_observer: LocalObserver<CoreNotification>,
|
||||||
|
|
Loading…
Reference in New Issue