Create the asynchronous communication channel between the UI and the core app loop. #126
File diff suppressed because it is too large
Load Diff
|
@ -7,6 +7,7 @@ edition = "2021"
|
|||
|
||||
[dependencies]
|
||||
adw = { version = "0.5", package = "libadwaita", features = [ "v1_2" ] }
|
||||
async-channel = "2.1.1"
|
||||
emseries = { path = "../../emseries" }
|
||||
ft-core = { path = "../core" }
|
||||
gio = { version = "0.18" }
|
||||
|
|
|
@ -17,6 +17,7 @@ You should have received a copy of the GNU General Public License along with Fit
|
|||
mod ui;
|
||||
|
||||
use adw::prelude::*;
|
||||
use async_channel::{Receiver, Sender};
|
||||
use emseries::{EmseriesReadError, Series};
|
||||
use ft_core::TraxRecord;
|
||||
use gio::resources_lookup_data;
|
||||
|
@ -36,11 +37,16 @@ const APP_ID_PROD: &str = "com.luminescent-dreams.fitnesstrax";
|
|||
|
||||
const RESOURCE_BASE_PATH: &str = "/com/luminescent-dreams/fitnesstrax/";
|
||||
|
||||
/// A set of events that can occur at the global application level. These events should represent
|
||||
/// significant state changes that should go through a central dispatcher.
|
||||
enum Events {
|
||||
DatabaseChanged(Series<TraxRecord>),
|
||||
#[derive(Debug)]
|
||||
enum AppInvocation {
|
||||
OpenDatabase(PathBuf),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum AppResponse {
|
||||
DatabaseChanged,
|
||||
}
|
||||
|
||||
// Note that I have not yet figured out the communication channel or how the central dispatcher
|
||||
// should work. There's a dance between the App and the AppWindow that I haven't figured out yet.
|
||||
|
||||
|
@ -222,7 +228,7 @@ impl HistoricalView {
|
|||
/// everything occurs here.
|
||||
#[derive(Clone)]
|
||||
struct AppWindow {
|
||||
app: App,
|
||||
app_tx: Sender<AppInvocation>,
|
||||
window: adw::ApplicationWindow,
|
||||
layout: gtk::Box,
|
||||
current_view: Rc<RefCell<gtk::Widget>>,
|
||||
|
@ -235,7 +241,7 @@ impl AppWindow {
|
|||
/// otherwise we don't use this.
|
||||
///
|
||||
/// app is a core [App] object which encapsulates all of the basic logic.
|
||||
fn new(adw_app: &adw::Application, app: App) -> AppWindow {
|
||||
fn new(adw_app: &adw::Application, app_tx: Sender<AppInvocation>) -> AppWindow {
|
||||
let window = adw::ApplicationWindow::builder()
|
||||
.application(adw_app)
|
||||
.width_request(800)
|
||||
|
@ -275,15 +281,14 @@ impl AppWindow {
|
|||
window.present();
|
||||
|
||||
let s = Self {
|
||||
app: app.clone(),
|
||||
app_tx,
|
||||
window,
|
||||
layout,
|
||||
current_view: Rc::new(RefCell::new(initial_view.upcast())),
|
||||
};
|
||||
|
||||
let initial_view = if app.database.read().unwrap().is_none() {
|
||||
let initial_view = if true {
|
||||
WelcomeView::new({
|
||||
let app = app.clone();
|
||||
let s = s.clone();
|
||||
Box::new(move |path: PathBuf| {
|
||||
// The user has selected a path. Perhaps the path is new, perhaps it already
|
||||
|
@ -295,8 +300,20 @@ impl AppWindow {
|
|||
//
|
||||
// If the file does not exist, create a new one. Again, show the user an error if
|
||||
// some kind of error occurs.
|
||||
app.open_db(&path);
|
||||
s.change_view(HistoricalView::new().upcast());
|
||||
// app.open_db(&path);
|
||||
// s.change_view(HistoricalView::new().upcast());
|
||||
// let s = s.clone();
|
||||
/*
|
||||
glib::spawn_future_local(async move {
|
||||
s.app_tx
|
||||
.send(AppInvocation::OpenDatabase(path))
|
||||
.await
|
||||
.unwrap();
|
||||
});
|
||||
*/
|
||||
s.app_tx
|
||||
.send_blocking(AppInvocation::OpenDatabase(path))
|
||||
.unwrap();
|
||||
})
|
||||
})
|
||||
.upcast()
|
||||
|
@ -342,20 +359,33 @@ fn main() {
|
|||
|
||||
let app = App::new(settings);
|
||||
|
||||
/*
|
||||
let runtime = tokio::runtime::Builder::new_multi_thread()
|
||||
.enable_all()
|
||||
.build()
|
||||
.unwrap();
|
||||
*/
|
||||
|
||||
let adw_app = adw::Application::builder()
|
||||
.application_id(app_id)
|
||||
.resource_base_path(RESOURCE_BASE_PATH)
|
||||
.build();
|
||||
|
||||
let runtime = tokio::runtime::Builder::new_multi_thread()
|
||||
.enable_all()
|
||||
.build()
|
||||
.unwrap();
|
||||
|
||||
adw_app.connect_activate(move |adw_app| {
|
||||
AppWindow::new(adw_app, app.clone());
|
||||
let (gtk_tx, gtk_rx) = async_channel::unbounded::<AppResponse>();
|
||||
let (app_tx, app_rx) = async_channel::unbounded::<AppInvocation>();
|
||||
|
||||
AppWindow::new(adw_app, app_tx.clone());
|
||||
|
||||
glib::spawn_future_local(async move {
|
||||
while let Ok(response) = gtk_rx.recv().await {
|
||||
println!("response received: {:?}", response);
|
||||
}
|
||||
});
|
||||
|
||||
runtime.spawn(async move {
|
||||
while let Ok(invocation) = app_rx.recv().await {
|
||||
println!("Received an invocation: {:?}", invocation);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
let args: Vec<String> = env::args().collect();
|
||||
|
|
Loading…
Reference in New Issue