Implement ads in desktop app (#2318)

* Implement ads in desktop app

* Finish ads

* use git dep instead

* attempt to fix linux build (temp)

* bump version + lint

* comment more

* fix build

* try to fix linux build

* Fix crashing on windows

* Fix icons not showing

* Remove useless env vars

* Actual linux build fix

* Run fmt

* Fix scrolling

* fix clippy

* bump version + fix localhost

* rev linux build patch

* update version num

* update csp

* update csp

* update csp

* Switch to mousewheel event
This commit is contained in:
Geometrically
2024-08-28 21:44:08 -07:00
committed by GitHub
parent 4bafae881f
commit acf26940d6
29 changed files with 663 additions and 56 deletions

View File

@@ -1,6 +1,6 @@
[package]
name = "theseus_gui"
version = "0.8.3-1"
version = "0.8.3"
description = "The Modrinth App is a desktop application for managing your Minecraft mods"
license = "GPL-3.0-only"
repository = "https://github.com/modrinth/code/apps/app/"
@@ -57,6 +57,9 @@ cocoa = "0.25.0"
objc = "0.2.7"
rand = "0.8.5"
[target.'cfg(target_os = "linux")'.dependencies]
tauri-plugin-updater = { version = "2.0.0-rc.1", optional = true, features = ["native-tls-vendored", "zip"], default-features = false }
[features]
# by default Tauri runs in production mode
# when `tauri dev` runs it is executed with `cargo run --no-default-features` if `devPath` is an URL

View File

@@ -217,6 +217,18 @@ fn main() {
.default_permission(
DefaultPermissionRule::AllowAllCommands,
),
)
.plugin(
"ads",
InlinedPlugin::new()
.commands(&[
"init_ads_window",
"hide_ads_window",
"scroll_ads_window",
])
.default_permission(
DefaultPermissionRule::AllowAllCommands,
),
),
)
.expect("Failed to run tauri-build");

View File

@@ -0,0 +1,15 @@
{
"identifier": "ads",
"description": "",
"local": false,
"remote": {
"urls": ["https://modrinth.com/*", "http://localhost:3000/*"]
},
"webviews": [
"ads-window"
],
"permissions": [
"shell:allow-open",
"ads:default"
]
}

View File

@@ -35,6 +35,7 @@
"cache:default",
"settings:default",
"tags:default",
"utils:default"
"utils:default",
"ads:default"
]
}

File diff suppressed because one or more lines are too long

View File

@@ -1 +1 @@
{"core":{"identifier":"core","description":"","local":true,"windows":["main"],"permissions":["core:default","core:path:default","core:event:default","core:window:default","core:app:default","core:resources:default","core:menu:default","core:tray:default","core:window:allow-create","core:window:allow-maximize","core:window:allow-toggle-maximize","core:window:allow-unmaximize","core:window:allow-minimize","core:window:allow-unminimize","core:window:allow-show","core:window:allow-hide","core:window:allow-close","core:window:allow-set-decorations","core:window:allow-start-dragging","core:webview:allow-set-webview-zoom"]},"plugins":{"identifier":"plugins","description":"","local":true,"windows":["main"],"permissions":["dialog:allow-open","dialog:allow-confirm","shell:allow-open","os:allow-platform","os:allow-version","os:allow-os-type","os:allow-family","os:allow-arch","os:allow-exe-extension","os:allow-locale","os:allow-hostname","deep-link:default","window-state:default","window-state:allow-restore-state","window-state:allow-save-window-state","auth:default","import:default","jre:default","logs:default","metadata:default","mr-auth:default","profile-create:default","pack:default","process:default","profile:default","cache:default","settings:default","tags:default","utils:default"]}}
{"ads":{"identifier":"ads","description":"","remote":{"urls":["https://modrinth.com/*","http://localhost:3000/*"]},"local":false,"webviews":["ads-window"],"permissions":["shell:allow-open","ads:default"]},"core":{"identifier":"core","description":"","local":true,"windows":["main"],"permissions":["core:default","core:path:default","core:event:default","core:window:default","core:app:default","core:resources:default","core:menu:default","core:tray:default","core:window:allow-create","core:window:allow-maximize","core:window:allow-toggle-maximize","core:window:allow-unmaximize","core:window:allow-minimize","core:window:allow-unminimize","core:window:allow-show","core:window:allow-hide","core:window:allow-close","core:window:allow-set-decorations","core:window:allow-start-dragging","core:webview:allow-set-webview-zoom"]},"plugins":{"identifier":"plugins","description":"","local":true,"windows":["main"],"permissions":["dialog:allow-open","dialog:allow-confirm","shell:allow-open","os:allow-platform","os:allow-version","os:allow-os-type","os:allow-family","os:allow-arch","os:allow-exe-extension","os:allow-locale","os:allow-hostname","deep-link:default","window-state:default","window-state:allow-restore-state","window-state:allow-save-window-state","auth:default","import:default","jre:default","logs:default","metadata:default","mr-auth:default","profile-create:default","pack:default","process:default","profile:default","cache:default","settings:default","tags:default","utils:default","ads:default"]}}

View File

@@ -299,6 +299,55 @@
},
"Identifier": {
"oneOf": [
{
"description": "ads:default -> Default plugin permissions.",
"type": "string",
"enum": [
"ads:default"
]
},
{
"description": "ads:allow-hide-ads-window -> Enables the hide_ads_window command without any pre-configured scope.",
"type": "string",
"enum": [
"ads:allow-hide-ads-window"
]
},
{
"description": "ads:allow-init-ads-window -> Enables the init_ads_window command without any pre-configured scope.",
"type": "string",
"enum": [
"ads:allow-init-ads-window"
]
},
{
"description": "ads:allow-scroll-ads-window -> Enables the scroll_ads_window command without any pre-configured scope.",
"type": "string",
"enum": [
"ads:allow-scroll-ads-window"
]
},
{
"description": "ads:deny-hide-ads-window -> Denies the hide_ads_window command without any pre-configured scope.",
"type": "string",
"enum": [
"ads:deny-hide-ads-window"
]
},
{
"description": "ads:deny-init-ads-window -> Denies the init_ads_window command without any pre-configured scope.",
"type": "string",
"enum": [
"ads:deny-init-ads-window"
]
},
{
"description": "ads:deny-scroll-ads-window -> Denies the scroll_ads_window command without any pre-configured scope.",
"type": "string",
"enum": [
"ads:deny-scroll-ads-window"
]
},
{
"description": "auth:default -> Default plugin permissions.",
"type": "string",

View File

@@ -299,6 +299,55 @@
},
"Identifier": {
"oneOf": [
{
"description": "ads:default -> Default plugin permissions.",
"type": "string",
"enum": [
"ads:default"
]
},
{
"description": "ads:allow-hide-ads-window -> Enables the hide_ads_window command without any pre-configured scope.",
"type": "string",
"enum": [
"ads:allow-hide-ads-window"
]
},
{
"description": "ads:allow-init-ads-window -> Enables the init_ads_window command without any pre-configured scope.",
"type": "string",
"enum": [
"ads:allow-init-ads-window"
]
},
{
"description": "ads:allow-scroll-ads-window -> Enables the scroll_ads_window command without any pre-configured scope.",
"type": "string",
"enum": [
"ads:allow-scroll-ads-window"
]
},
{
"description": "ads:deny-hide-ads-window -> Denies the hide_ads_window command without any pre-configured scope.",
"type": "string",
"enum": [
"ads:deny-hide-ads-window"
]
},
{
"description": "ads:deny-init-ads-window -> Denies the init_ads_window command without any pre-configured scope.",
"type": "string",
"enum": [
"ads:deny-init-ads-window"
]
},
{
"description": "ads:deny-scroll-ads-window -> Denies the scroll_ads_window command without any pre-configured scope.",
"type": "string",
"enum": [
"ads:deny-scroll-ads-window"
]
},
{
"description": "auth:default -> Default plugin permissions.",
"type": "string",

View File

@@ -0,0 +1,17 @@
document.addEventListener('click', function (e) {
let target = e.target
while (target != null) {
if (target.matches('a')) {
e.preventDefault()
if (target.href) {
window.top.postMessage({ modrinthOpenUrl: target.href }, 'https://modrinth.com')
}
break
}
target = target.parentElement
}
})
window.open = (url, target, features) => {
window.top.postMessage({ modrinthOpenUrl: url }, 'https://modrinth.com')
}

82
apps/app/src/api/ads.rs Normal file
View File

@@ -0,0 +1,82 @@
use serde::Serialize;
use tauri::plugin::TauriPlugin;
use tauri::{
Emitter, LogicalPosition, LogicalSize, Manager, Runtime, WebviewUrl,
};
pub fn init<R: Runtime>() -> TauriPlugin<R> {
tauri::plugin::Builder::<R>::new("ads")
.invoke_handler(tauri::generate_handler![
init_ads_window,
hide_ads_window,
scroll_ads_window,
])
.build()
}
const LINK_SCRIPT: &str = include_str!("ads-init.js");
// TODO: make ads work on linux
#[tauri::command]
pub async fn init_ads_window<R: Runtime>(
app: tauri::AppHandle<R>,
x: f32,
y: f32,
width: f32,
height: f32,
) -> crate::api::Result<()> {
#[cfg(not(target_os = "linux"))]
{
if let Some(webview) = app.webviews().get("ads-window") {
let _ = webview.set_position(LogicalPosition::new(x, y));
let _ = webview.set_size(LogicalSize::new(width, height));
} else if let Some(window) = app.get_window("main") {
let _ = window.add_child(
tauri::webview::WebviewBuilder::new(
"ads-window",
WebviewUrl::External(
"https://modrinth.com/wrapper/app-ads".parse().unwrap(),
),
)
.initialization_script(LINK_SCRIPT)
.user_agent("ModrinthApp Ads Webview")
.zoom_hotkeys_enabled(false)
.transparent(true),
LogicalPosition::new(x, y),
LogicalSize::new(width, height),
);
}
}
Ok(())
}
#[tauri::command]
pub async fn hide_ads_window<R: Runtime>(
app: tauri::AppHandle<R>,
) -> crate::api::Result<()> {
#[cfg(not(target_os = "linux"))]
{
if let Some(webview) = app.webviews().get("ads-window") {
let _ = webview.set_position(LogicalPosition::new(-1000, -1000));
}
}
Ok(())
}
#[derive(Serialize, Clone)]
struct ScrollEvent {
scroll: f32,
}
#[tauri::command]
pub async fn scroll_ads_window<R: Runtime>(
app: tauri::AppHandle<R>,
scroll: f32,
) -> crate::api::Result<()> {
let _ = app.emit("ads-scroll", ScrollEvent { scroll });
Ok(())
}

View File

@@ -16,6 +16,7 @@ pub mod settings;
pub mod tags;
pub mod utils;
pub mod ads;
pub mod cache;
pub type Result<T> = std::result::Result<T, TheseusSerializableError>;

View File

@@ -31,6 +31,8 @@ async fn initialize_state(app: tauri::AppHandle) -> api::Result<()> {
let state = State::get().await?;
app.asset_protocol_scope()
.allow_directory(state.directories.caches_dir(), true)?;
app.asset_protocol_scope()
.allow_directory(state.directories.caches_dir().join("icons"), true)?;
Ok(())
}
@@ -39,7 +41,7 @@ async fn initialize_state(app: tauri::AppHandle) -> api::Result<()> {
#[tracing::instrument(skip_all)]
#[tauri::command]
fn show_window(app: tauri::AppHandle) {
let win = app.get_webview_window("main").unwrap();
let win = app.get_window("main").unwrap();
if let Err(e) = win.show() {
MessageDialog::new()
.set_type(MessageType::Error)
@@ -179,6 +181,7 @@ fn main() {
.plugin(api::tags::init())
.plugin(api::utils::init())
.plugin(api::cache::init())
.plugin(api::ads::init())
.invoke_handler(tauri::generate_handler![
initialize_state,
is_dev,

View File

@@ -48,7 +48,7 @@
]
},
"productName": "Modrinth App",
"version": "0.8.3-1",
"version": "0.8.3",
"identifier": "ModrinthApp",
"plugins": {
"deep-link": {
@@ -70,10 +70,10 @@
"resizable": true,
"title": "Modrinth App",
"width": 1280,
"minHeight": 700,
"minHeight": 750,
"minWidth": 1100,
"visible": false,
"zoomHotkeysEnabled": true,
"zoomHotkeysEnabled": false,
"decorations": false
}
],
@@ -86,7 +86,17 @@
],
"enable": true
},
"csp": "default-src 'self'; connect-src ipc: http://ipc.localhost https://modrinth.com https://*.modrinth.com https://*.posthog.com https://*.sentry.io https://*.cloudflare.com https://api.mclo.gs; font-src https://cdn-raw.modrinth.com/fonts/inter/; img-src tauri: https: data: blob: 'unsafe-inline' asset: https://asset.localhost; script-src https://*.cloudflare.com 'self'; frame-src https://*.cloudflare.com https://www.youtube.com https://www.youtube-nocookie.com https://discord.com 'self'; style-src unsafe-inline 'self'"
"csp": {
"default-src": "'self' customprotocol: asset:",
"connect-src": "ipc: http://ipc.localhost https://modrinth.com https://*.modrinth.com https://*.posthog.com https://*.sentry.io https://*.cloudflare.com https://api.mclo.gs https://cmp.inmobi.com",
"font-src": [
"https://cdn-raw.modrinth.com/fonts/inter/"
],
"img-src": "https: 'unsafe-inline' 'self' asset: http://asset.localhost blob: data:",
"style-src": "'unsafe-inline' 'self'",
"script-src": "https://cmp.inmobi.com https://*.cloudflare.com 'self'",
"frame-src": "https://*.cloudflare.com https://www.youtube.com https://www.youtube-nocookie.com https://discord.com 'self'"
}
}
}
}

View File

@@ -12,7 +12,7 @@
"minHeight": 700,
"minWidth": 1100,
"visible": false,
"zoomHotkeysEnabled": true,
"zoomHotkeysEnabled": false,
"decorations": true
}
]