1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
use webview_official::Webview;

mod runner;

type InvokeHandler = Box<dyn FnMut(&mut Webview<'_>, &str) -> Result<(), String>>;
type Setup = Box<dyn FnMut(&mut Webview<'_>, String)>;

/// The application runner.
pub struct App {
  /// The JS message handler.
  invoke_handler: Option<InvokeHandler>,
  /// The setup callback, invoked when the webview is ready.
  setup: Option<Setup>,
  /// The HTML of the splashscreen to render.
  splashscreen_html: Option<String>,
}

impl App {
  /// Runs the app until it finishes.
  pub fn run(mut self) {
    runner::run(&mut self).expect("Failed to build webview");
  }

  /// Runs the invoke handler if defined.
  /// Returns whether the message was consumed or not.
  /// The message is considered consumed if the handler exists and returns an Ok Result.
  pub(crate) fn run_invoke_handler(
    &mut self,
    webview: &mut Webview<'_>,
    arg: &str,
  ) -> Result<bool, String> {
    if let Some(ref mut invoke_handler) = self.invoke_handler {
      invoke_handler(webview, arg).map(|_| true)
    } else {
      Ok(false)
    }
  }

  /// Runs the setup callback if defined.
  pub(crate) fn run_setup(&mut self, webview: &mut Webview<'_>, source: String) {
    if let Some(ref mut setup) = self.setup {
      setup(webview, source);
    }
  }

  /// Returns the splashscreen HTML.
  pub fn splashscreen_html(&self) -> Option<&String> {
    self.splashscreen_html.as_ref()
  }
}

/// The App builder.
#[derive(Default)]
pub struct AppBuilder {
  /// The JS message handler.
  invoke_handler: Option<InvokeHandler>,
  /// The setup callback, invoked when the webview is ready.
  setup: Option<Setup>,
  /// The HTML of the splashscreen to render.
  splashscreen_html: Option<String>,
}

impl AppBuilder {
  /// Creates a new App bulder.
  pub fn new() -> Self {
    Self {
      invoke_handler: None,
      setup: None,
      splashscreen_html: None,
    }
  }

  /// Defines the JS message handler callback.
  pub fn invoke_handler<F: FnMut(&mut Webview<'_>, &str) -> Result<(), String> + 'static>(
    mut self,
    invoke_handler: F,
  ) -> Self {
    self.invoke_handler = Some(Box::new(invoke_handler));
    self
  }

  /// Defines the setup callback.
  pub fn setup<F: FnMut(&mut Webview<'_>, String) + 'static>(mut self, setup: F) -> Self {
    self.setup = Some(Box::new(setup));
    self
  }

  /// Defines the splashscreen HTML to render.
  pub fn splashscreen_html(mut self, html: &str) -> Self {
    self.splashscreen_html = Some(html.to_string());
    self
  }

  /// Adds a plugin to the runtime.
  pub fn plugin(self, plugin: impl crate::plugin::Plugin + 'static) -> Self {
    crate::plugin::register(plugin);
    self
  }

  /// Builds the App.
  pub fn build(self) -> App {
    App {
      invoke_handler: self.invoke_handler,
      setup: self.setup,
      splashscreen_html: self.splashscreen_html,
    }
  }
}