/ src / app.rs
app.rs
  1  pub mod browser;
  2  mod database;
  3  
  4  use crate::profile::Profile;
  5  use adw::Application;
  6  use anyhow::Result;
  7  use browser::Browser;
  8  use gtk::{
  9      glib::ExitCode,
 10      prelude::{ActionExt, ApplicationExt, ApplicationExtManual, GtkApplicationExt},
 11  };
 12  use sqlite::Transaction;
 13  use std::rc::Rc;
 14  
 15  const APPLICATION_ID: &str = "io.github.yggverse.Yoda";
 16  
 17  pub struct App {
 18      profile: Rc<Profile>,
 19      application: Application,
 20  }
 21  
 22  impl App {
 23      // Constructors
 24  
 25      /// Build new `Self`
 26      pub fn build(profile: Profile) -> Result<Self> {
 27          // Init GTK
 28          let application = Application::builder()
 29              .application_id(APPLICATION_ID)
 30              .build();
 31  
 32          // Init components
 33          let profile = Rc::new(profile);
 34          let browser = Rc::new(Browser::build(&profile));
 35  
 36          // Prevent startup warning @TODO
 37          application.connect_activate(|_| {});
 38  
 39          // Init events
 40          application.connect_startup({
 41              let browser = browser.clone();
 42              let profile = profile.clone();
 43              move |this| {
 44                  // Init readable connection
 45                  match profile.database.pool.get() {
 46                      Ok(connection) => {
 47                          // Create transaction
 48                          match connection.unchecked_transaction() {
 49                              Ok(transaction) => {
 50                                  // Restore previous session from DB
 51                                  match database::select(&transaction) {
 52                                      Ok(records) => {
 53                                          // Restore child components
 54                                          for record in records {
 55                                              if let Err(e) = browser.restore(&transaction, record.id)
 56                                              {
 57                                                  todo!("{e}")
 58                                              }
 59                                          }
 60                                      }
 61                                      Err(e) => todo!("{e}"),
 62                                  }
 63                              }
 64                              Err(e) => todo!("{e}"),
 65                          }
 66                      }
 67                      Err(e) => todo!("{e}"),
 68                  }
 69  
 70                  // Run initial features, show widget
 71                  browser.init(Some(this)).present();
 72              }
 73          });
 74  
 75          application.connect_shutdown({
 76              let browser = browser.clone();
 77              let profile = profile.clone();
 78              move |_| {
 79                  match profile.save() {
 80                      Ok(_) => match profile.database.pool.get() {
 81                          Ok(mut connection) => {
 82                              // Create transaction
 83                              match connection.transaction() {
 84                                  Ok(transaction) => {
 85                                      match database::select(&transaction) {
 86                                          Ok(records) => {
 87                                              // Cleanup previous session records
 88                                              for record in records {
 89                                                  match database::delete(&transaction, record.id) {
 90                                                      Ok(_) => {
 91                                                          // Delegate clean action to childs
 92                                                          if let Err(e) =
 93                                                              browser.clean(&transaction, record.id)
 94                                                          {
 95                                                              todo!("{e}")
 96                                                          }
 97                                                      }
 98                                                      Err(e) => todo!("{e}"),
 99                                                  }
100                                              }
101  
102                                              // Save current session to DB
103                                              match database::insert(&transaction) {
104                                                  Ok(_) => {
105                                                      // Delegate save action to childs
106                                                      if let Err(e) = browser.save(
107                                                          &transaction,
108                                                          database::last_insert_id(&transaction),
109                                                      ) {
110                                                          todo!("{e}")
111                                                      }
112                                                  }
113                                                  Err(e) => todo!("{e}"),
114                                              }
115                                          }
116                                          Err(e) => todo!("{e}"),
117                                      }
118  
119                                      // Confirm changes
120                                      if let Err(e) = transaction.commit() {
121                                          todo!("{e}")
122                                      }
123                                  }
124                                  Err(e) => todo!("{e}"),
125                              }
126                          }
127                          Err(e) => todo!("{e}"),
128                      },
129                      Err(e) => todo!("{e}"),
130                  }
131              }
132          });
133  
134          // Init accels
135          for (detailed_action_name, accels) in &[
136              // Browser actions
137              (
138                  format!(
139                      "{}.{}",
140                      browser.action.id,
141                      browser.action.close.simple_action.name()
142                  ),
143                  ["<Primary>Escape"],
144              ),
145              (
146                  format!(
147                      "{}.{}",
148                      browser.action.id,
149                      browser.action.debug.simple_action.name()
150                  ),
151                  ["<Primary>i"],
152              ),
153              // Tab actions
154              (
155                  format!(
156                      "{}.{}",
157                      browser.window.action.id,
158                      browser.window.action.append.simple_action.name()
159                  ),
160                  ["<Primary>t"],
161              ),
162              (
163                  format!(
164                      "{}.{}",
165                      browser.window.action.id,
166                      browser.window.action.bookmark.simple_action.name()
167                  ),
168                  ["<Primary>b"],
169              ),
170              (
171                  format!(
172                      "{}.{}",
173                      browser.window.action.id,
174                      browser.window.action.find.simple_action.name()
175                  ),
176                  ["<Primary>f"],
177              ),
178              (
179                  format!(
180                      "{}.{}",
181                      browser.window.action.id,
182                      browser.window.action.pin.simple_action.name()
183                  ),
184                  ["<Primary>p"],
185              ),
186              (
187                  format!(
188                      "{}.{}",
189                      browser.window.action.id,
190                      browser.window.action.reload.simple_action.name()
191                  ),
192                  ["<Primary>r"],
193              ),
194              (
195                  format!(
196                      "{}.{}",
197                      browser.window.action.id,
198                      browser.window.action.save_as.simple_action.name()
199                  ),
200                  ["<Primary>s"],
201              ),
202              (
203                  format!(
204                      "{}.{}",
205                      browser.window.action.id,
206                      browser.window.action.open.simple_action.name()
207                  ),
208                  ["<Primary>o"],
209              ),
210              (
211                  format!(
212                      "{}.{}",
213                      browser.window.action.id,
214                      browser.window.action.source.simple_action.name()
215                  ),
216                  ["<Primary>u"],
217              ),
218              (
219                  format!(
220                      "{}.{}",
221                      browser.window.action.id,
222                      browser.window.action.home.simple_action.name()
223                  ),
224                  ["<Primary>h"],
225              ),
226              (
227                  format!(
228                      "{}.{}",
229                      browser.window.action.id,
230                      browser.window.action.history_back.simple_action.name()
231                  ),
232                  ["<Primary>Left"],
233              ),
234              (
235                  format!(
236                      "{}.{}",
237                      browser.window.action.id,
238                      browser.window.action.history_forward.simple_action.name()
239                  ),
240                  ["<Primary>Right"],
241              ),
242              (
243                  format!(
244                      "{}.{}",
245                      browser.window.action.id,
246                      browser.window.action.close.simple_action.name()
247                  ),
248                  ["<Primary>q"],
249              ),
250          ] {
251              application.set_accels_for_action(detailed_action_name, accels);
252          }
253  
254          // Return activated App struct
255          Ok(Self {
256              profile: profile.clone(),
257              application,
258          })
259      }
260  
261      // Actions
262      pub fn run(&self) -> Result<ExitCode> {
263          // Begin database migration @TODO
264          {
265              let mut connection = self.profile.database.pool.get()?;
266              let transaction = connection.transaction()?;
267              migrate(&transaction)?;
268              transaction.commit()?;
269          } // unlock database
270  
271          // Start application
272          Ok(self.application.run())
273      }
274  }
275  
276  // Tools
277  fn migrate(tx: &Transaction) -> Result<()> {
278      // Migrate self components
279      database::init(tx)?;
280  
281      // Delegate migration to childs
282      browser::migrate(tx)?;
283  
284      // Success
285      Ok(())
286  }