Update the build environment and some architectural elements of the Kifu app #210

Merged
savanni merged 13 commits from kifu/flake into main 2024-02-28 04:42:58 +00:00
2 changed files with 12 additions and 3 deletions
Showing only changes of commit a0478f8b62 - Show all commits

View File

@ -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();
} }
} }

View File

@ -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>,