use super::*;
use day_toolkit_material::jni::Env;
use day_toolkit_material::jni::objects::{JClass, JObject, JString};
use day_toolkit_material::{AHandle, Material, java, string_of};
use day_spec::NodeId;
day_toolkit_material::java_class! {
DayWebView => dev.daybrite.day.piece.webview.DayWebView,
methods {
static fn supportsProfiles() -> jboolean,
static fn supportsDataClearing() -> jboolean,
static fn makeWebView(id: jlong, url: JString, inline_prefix: JString, provider: jlong,
profile: JString) -> android.view.View,
static fn configureTabs(view: android.view.View, foreground: JString, background: JString),
static fn setTransparent(view: android.view.View),
static fn evalJs(view: android.view.View, req: jdouble, script: JString),
static fn webCommand(view: android.view.View, code: jint, url: JString),
static fn release(view: android.view.View),
static fn response(mime: JString, status: jint, header_lines: JString, body: jbyte[])
-> android.webkit.WebResourceResponse,
},
native_methods {
static fn resource {
sig = (provider: jlong, url: JString, method: JString, range: JString)
-> android.webkit.WebResourceResponse,
error_policy = day_toolkit_material::jni::errors::ThrowRuntimeExAndDefault,
},
},
}
pub(crate) fn capability(method: &str) -> day_spec::Support {
let supported = java(|env| match method {
"supportsProfiles" => DayWebView::supportsProfiles(env),
_ => DayWebView::supportsDataClearing(env),
})
.unwrap_or(false);
if supported {
day_spec::Support::Native
} else {
day_spec::Support::Unsupported
}
}
fn make(_backend: &mut Material, p: &WebProps, id: NodeId) -> AHandle {
if p.profile.private {
return AHandle(day_toolkit_material::with_env(|env| {
day_toolkit_material::placeholder_view(env, "web_view")
}));
}
let (url, prefix) = if p.inline_root.is_empty() {
(
p.url.clone(),
p.resources
.as_ref()
.map(ResourceProvider::base_url)
.unwrap_or_default(),
)
} else {
(
format!("file:///android_asset/{}/{}", p.inline_root, p.inline_start),
format!("file:///android_asset/{}/", p.inline_root),
)
};
let provider = p.resources.as_ref().map(ResourceProvider::id).unwrap_or(0) as i64;
let profile = if p.profile == WebProfile::default() {
String::new()
} else {
p.profile.storage_key()
};
let view = day_toolkit_material::realize("web_view", |env| {
let url = JString::from_str(env, &url)?;
let prefix = JString::from_str(env, &prefix)?;
let profile = JString::from_str(env, &profile)?;
DayWebView::makeWebView(env, id.0 as i64, &url, &prefix, provider, &profile)
});
if let Some(labels) = &p.tabs {
java(|env| {
let foreground = JString::from_str(env, &labels.foreground)?;
let background = JString::from_str(env, &labels.background)?;
DayWebView::configureTabs(env, view.0.as_obj(), &foreground, &background)
});
}
if p.transparent {
java(|env| DayWebView::setTransparent(env, view.0.as_obj()));
}
view
}
fn update(_backend: &mut Material, h: &AHandle, patch: &WebPatch) {
if let WebPatch::Eval { req, script } = patch {
java(|env| {
let script = JString::from_str(env, script)?;
DayWebView::evalJs(env, h.0.as_obj(), *req as f64, &script)
});
return;
}
let (code, url) = match patch {
WebPatch::Load(u) => (0, u.as_str()),
WebPatch::Back => (1, ""),
WebPatch::Forward => (2, ""),
WebPatch::Stop => (3, ""),
WebPatch::Reload => (4, ""),
WebPatch::ForceReload => (5, ""),
WebPatch::Eval { .. } => return, };
java(|env| {
let url = JString::from_str(env, url)?;
DayWebView::webCommand(env, h.0.as_obj(), code, &url)
});
}
fn release(_backend: &mut Material, handle: &AHandle) {
java(|env| DayWebView::release(env, handle.0.as_obj()));
}
day_pieces::renderer!(day_toolkit_material::RENDERERS, Material,
kind: KIND, props: WebProps, patch: WebPatch,
make: make, update: update, measure: day_pieces::fill_measure, release: release);
impl DayWebViewNativeInterface for DayWebViewAPI {
type Error = day_toolkit_material::jni::errors::Error;
fn resource<'l>(
env: &mut Env<'l>,
_class: JClass<'l>,
provider: i64,
url: JString<'l>,
method: JString<'l>,
range: JString<'l>,
) -> Result<JObject<'l>, Self::Error> {
let url = string_of(env, &url)?;
let method = string_of(env, &method)?;
let range = string_of(env, &range)?;
let r = super::resources::respond(provider as u64, &url, &method, &range);
let bytes = env.byte_array_from_slice(&r.body)?;
let mime = JString::from_str(env, &r.mime)?;
let headers = JString::from_str(
env,
r.headers
.iter()
.map(|(k, v)| format!("{k}: {v}\n"))
.collect::<String>(),
)?;
DayWebView::response(env, &mime, r.status as i32, &headers, &bytes)
}
}