mirror of
https://github.com/modrinth/code.git
synced 2026-08-25 09:04:55 +00:00
feat: implement custom notification and popup components (#6768)
* feat: implement custom popup * feat: add privacy setting * style fixes * more style fixes * feat: implement notification panel changes and better popup in website * feat: update popup button * fix: remove unnecessary modal props * fixes * pnpm prepr * remove devtools opening * update query to find buttons * update copy * update copy * fix: manage permissions depends on showAds booleans instead of managemetn availability
This commit is contained in:
@@ -6,6 +6,14 @@ document.addEventListener(
|
||||
window.top.postMessage({ modrinthAdClick: true }, MODRINTH_ORIGIN)
|
||||
|
||||
let target = e.target
|
||||
if (target?.closest?.('.qc-cmp2-close-icon')) {
|
||||
if (modrinthAdsConsentReprompt) {
|
||||
setTimeout(finishAdsConsentReprompt)
|
||||
} else if (document.documentElement.classList.contains('modrinth-ads-consent-preferences')) {
|
||||
setTimeout(() => void restoreAdsConsentNotification())
|
||||
}
|
||||
}
|
||||
|
||||
while (target != null) {
|
||||
if (target.matches('a')) {
|
||||
e.preventDefault()
|
||||
@@ -27,6 +35,25 @@ window.open = (url, target, features) => {
|
||||
let modrinthAdsConsentOverlayShown = false
|
||||
let modrinthTcfListenerInstalled = false
|
||||
let modrinthTcfListenerAttempts = 0
|
||||
let modrinthAdsConsentReprompt = false
|
||||
let modrinthAdsConsentRepromptManaging = false
|
||||
let modrinthAdsConsentActionRequestId = 0
|
||||
const modrinthAdsConsentActionResolvers = new Map()
|
||||
|
||||
function installAdsRailStyle() {
|
||||
if (document.getElementById('modrinth-ads-rail-style')) {
|
||||
return
|
||||
}
|
||||
const style = document.createElement('style')
|
||||
style.id = 'modrinth-ads-rail-style'
|
||||
style.textContent = `
|
||||
html.modrinth-ads-consent-preferences #modrinth-rail-1 {
|
||||
visibility: hidden !important;
|
||||
pointer-events: none !important;
|
||||
}
|
||||
`
|
||||
document.documentElement.appendChild(style)
|
||||
}
|
||||
|
||||
function installAdsConsentOverlayStyle() {
|
||||
if (document.getElementById('modrinth-ads-consent-overlay-style')) {
|
||||
@@ -35,10 +62,16 @@ function installAdsConsentOverlayStyle() {
|
||||
const style = document.createElement('style')
|
||||
style.id = 'modrinth-ads-consent-overlay-style'
|
||||
style.textContent = `
|
||||
html.modrinth-ads-consent-overlay #modrinth-rail-1 {
|
||||
html.modrinth-ads-consent-overlay:not(.modrinth-ads-consent-preferences) #modrinth-rail-1 {
|
||||
visibility: hidden !important;
|
||||
}
|
||||
|
||||
html.modrinth-ads-consent-overlay:not(.modrinth-ads-consent-preferences) #qc-cmp2-container,
|
||||
html.modrinth-ads-consent-overlay:not(.modrinth-ads-consent-preferences) #qc-cmp2-main {
|
||||
visibility: hidden !important;
|
||||
pointer-events: none !important;
|
||||
}
|
||||
|
||||
.qc-cmp2-close-icon {
|
||||
background: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24'%3E%3Cpath d='M.5.5l23 23m0-23l-23 23' fill='none' stroke='%23b0bac5' stroke-width='3' stroke-linecap='round' stroke-linejoin='round' stroke-miterlimit='10'/%3E%3Cpath fill='none' d='M0 0h24v24H0z'/%3E%3C/svg%3E") 0% 0% / 66% auto no-repeat !important;
|
||||
}
|
||||
@@ -63,12 +96,243 @@ function invokeAdsConsentOverlayCommand(shown) {
|
||||
invoke(`plugin:ads|${command}`, args).catch(() => {})
|
||||
}
|
||||
|
||||
function revealAdsConsentPreferences() {
|
||||
document.documentElement.classList.add('modrinth-ads-consent-preferences')
|
||||
document.getElementById('modrinth-ads-consent-overlay-style')?.remove()
|
||||
}
|
||||
|
||||
function concealAdsConsentPreferences() {
|
||||
document.documentElement.classList.remove('modrinth-ads-consent-preferences')
|
||||
installAdsConsentOverlayStyle()
|
||||
}
|
||||
|
||||
async function expandAdsConsentWebview() {
|
||||
const invoke = getTauriInvoke()
|
||||
if (typeof invoke !== 'function') {
|
||||
throw new Error('Tauri invoke is unavailable in the ads webview')
|
||||
}
|
||||
|
||||
await invoke('plugin:ads|show_ads_consent_preferences')
|
||||
}
|
||||
|
||||
function sendAdsConsentCommandToChildFrames(command) {
|
||||
document.querySelectorAll('iframe').forEach((frame) => {
|
||||
frame.contentWindow?.postMessage({ modrinthAdsConsentCommand: command }, '*')
|
||||
})
|
||||
}
|
||||
|
||||
function isDirectChildFrame(source) {
|
||||
return Array.from(document.querySelectorAll('iframe')).some(
|
||||
(frame) => frame.contentWindow === source,
|
||||
)
|
||||
}
|
||||
|
||||
function findAdsConsentButton(action) {
|
||||
const container = document.querySelector('#qc-cmp2-container, #qc-cmp2-main')
|
||||
if (!container) return null
|
||||
const summaryButtons = Array.from(container.querySelectorAll('.qc-cmp2-summary-buttons button'))
|
||||
|
||||
if (action === 'accept') {
|
||||
const explicitAcceptButton = container.querySelector('#accept-btn')
|
||||
if (explicitAcceptButton) return explicitAcceptButton
|
||||
if (summaryButtons.length >= 3) return summaryButtons[2]
|
||||
|
||||
return container.querySelector('.qc-cmp2-summary-buttons button[mode="primary"]')
|
||||
}
|
||||
|
||||
if (action === 'reject') {
|
||||
const explicitRejectButton = container.querySelector('#disagree-btn')
|
||||
if (explicitRejectButton) return explicitRejectButton
|
||||
if (summaryButtons.length >= 3) return summaryButtons[1]
|
||||
|
||||
const secondaryButtons = container.querySelectorAll(
|
||||
'.qc-cmp2-summary-buttons button[mode="secondary"]',
|
||||
)
|
||||
if (secondaryButtons.length > 1) return secondaryButtons[1]
|
||||
|
||||
return summaryButtons.find(
|
||||
(button) => button.textContent?.trim().toLowerCase() === 'reject all',
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
container.querySelector(
|
||||
'#more-options-btn, .qc-cmp2-summary-buttons > button[mode="secondary"]:first-of-type',
|
||||
) ?? summaryButtons[0]
|
||||
)
|
||||
}
|
||||
|
||||
function clickAdsConsentButtonWhenReady(action, timeoutMs, onButtonFound) {
|
||||
const deadline = Date.now() + timeoutMs
|
||||
|
||||
return new Promise((resolve) => {
|
||||
function tryClick() {
|
||||
const button = findAdsConsentButton(action)
|
||||
if (button) {
|
||||
// CMP navigation can replace this document during the click, so acknowledge it first.
|
||||
onButtonFound?.()
|
||||
resolve(true)
|
||||
button.click()
|
||||
} else if (Date.now() >= deadline) {
|
||||
resolve(false)
|
||||
} else {
|
||||
setTimeout(tryClick, 50)
|
||||
}
|
||||
}
|
||||
|
||||
tryClick()
|
||||
})
|
||||
}
|
||||
|
||||
function performAdsConsentActionAcrossFrames(action, timeoutMs) {
|
||||
const requestId = `${Date.now()}-${++modrinthAdsConsentActionRequestId}`
|
||||
|
||||
return new Promise((resolve) => {
|
||||
let settled = false
|
||||
const settle = (clicked) => {
|
||||
if (settled) return
|
||||
settled = true
|
||||
clearTimeout(timeout)
|
||||
modrinthAdsConsentActionResolvers.delete(requestId)
|
||||
resolve(clicked)
|
||||
}
|
||||
|
||||
const timeout = setTimeout(() => settle(false), timeoutMs)
|
||||
modrinthAdsConsentActionResolvers.set(requestId, () => settle(true))
|
||||
sendAdsConsentCommandToChildFrames({ type: 'perform', action, requestId, timeoutMs })
|
||||
clickAdsConsentButtonWhenReady(action, timeoutMs, () => settle(true)).then((clicked) => {
|
||||
if (!clicked) settle(false)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
function waitForAdsConsentLayout() {
|
||||
return new Promise((resolve) => setTimeout(resolve, 100))
|
||||
}
|
||||
|
||||
async function restoreAdsConsentNotification() {
|
||||
concealAdsConsentPreferences()
|
||||
sendAdsConsentCommandToChildFrames({ type: 'conceal' })
|
||||
|
||||
const invoke = getTauriInvoke()
|
||||
if (typeof invoke === 'function') {
|
||||
await invoke('plugin:ads|hide_ads_consent_preferences')
|
||||
}
|
||||
}
|
||||
|
||||
function finishAdsConsentReprompt() {
|
||||
modrinthAdsConsentReprompt = false
|
||||
modrinthAdsConsentRepromptManaging = false
|
||||
modrinthAdsConsentOverlayShown = false
|
||||
document.documentElement.classList.remove('modrinth-ads-consent-overlay')
|
||||
concealAdsConsentPreferences()
|
||||
sendAdsConsentCommandToChildFrames({ type: 'conceal' })
|
||||
invokeAdsConsentOverlayCommand(false)
|
||||
}
|
||||
|
||||
async function openAdsConsentPreferences() {
|
||||
revealAdsConsentPreferences()
|
||||
sendAdsConsentCommandToChildFrames({ type: 'reveal' })
|
||||
await expandAdsConsentWebview()
|
||||
await waitForAdsConsentLayout()
|
||||
|
||||
window.dispatchEvent(new Event('resize'))
|
||||
sendAdsConsentCommandToChildFrames({ type: 'resize' })
|
||||
|
||||
const clicked = await performAdsConsentActionAcrossFrames('manage', 2500)
|
||||
if (!clicked) {
|
||||
await restoreAdsConsentNotification()
|
||||
}
|
||||
}
|
||||
|
||||
async function performAdsConsentAction(action) {
|
||||
if (!['accept', 'reject', 'manage'].includes(action)) return
|
||||
|
||||
if (action === 'manage') {
|
||||
try {
|
||||
await openAdsConsentPreferences()
|
||||
} catch {
|
||||
await restoreAdsConsentNotification()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
await performAdsConsentActionAcrossFrames(action, 1000)
|
||||
}
|
||||
|
||||
window.modrinthAdsConsentAction = (action) => {
|
||||
void performAdsConsentAction(action)
|
||||
}
|
||||
|
||||
window.modrinthAdsReopenConsentPreferences = async () => {
|
||||
modrinthAdsConsentReprompt = true
|
||||
modrinthAdsConsentRepromptManaging = false
|
||||
revealAdsConsentPreferences()
|
||||
sendAdsConsentCommandToChildFrames({ type: 'reveal' })
|
||||
|
||||
try {
|
||||
await expandAdsConsentWebview()
|
||||
await waitForAdsConsentLayout()
|
||||
window.dispatchEvent(new Event('resize'))
|
||||
sendAdsConsentCommandToChildFrames({ type: 'resize' })
|
||||
|
||||
if (typeof window.__tcfapi === 'function') {
|
||||
window.__tcfapi('displayConsentUi', 2, () => {})
|
||||
} else {
|
||||
finishAdsConsentReprompt()
|
||||
}
|
||||
} catch {
|
||||
finishAdsConsentReprompt()
|
||||
}
|
||||
}
|
||||
|
||||
window.addEventListener('message', (event) => {
|
||||
const resultRequestId = event.data?.modrinthAdsConsentResult
|
||||
if (typeof resultRequestId === 'string' && isDirectChildFrame(event.source)) {
|
||||
if (window.top === window) {
|
||||
modrinthAdsConsentActionResolvers.get(resultRequestId)?.()
|
||||
} else {
|
||||
window.parent.postMessage({ modrinthAdsConsentResult: resultRequestId }, '*')
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if (window.top === window || event.source !== window.parent) return
|
||||
|
||||
const command = event.data?.modrinthAdsConsentCommand
|
||||
if (!command || typeof command !== 'object') return
|
||||
|
||||
if (command.type === 'reveal') {
|
||||
revealAdsConsentPreferences()
|
||||
sendAdsConsentCommandToChildFrames(command)
|
||||
} else if (command.type === 'conceal') {
|
||||
concealAdsConsentPreferences()
|
||||
sendAdsConsentCommandToChildFrames(command)
|
||||
} else if (command.type === 'resize') {
|
||||
window.dispatchEvent(new Event('resize'))
|
||||
sendAdsConsentCommandToChildFrames(command)
|
||||
} else if (
|
||||
command.type === 'perform' &&
|
||||
typeof command.action === 'string' &&
|
||||
typeof command.requestId === 'string' &&
|
||||
typeof command.timeoutMs === 'number'
|
||||
) {
|
||||
sendAdsConsentCommandToChildFrames(command)
|
||||
clickAdsConsentButtonWhenReady(command.action, command.timeoutMs, () => {
|
||||
window.parent.postMessage({ modrinthAdsConsentResult: command.requestId }, '*')
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
function setAdsConsentOverlay(shown) {
|
||||
if (modrinthAdsConsentOverlayShown === shown) return
|
||||
|
||||
modrinthAdsConsentOverlayShown = shown
|
||||
installAdsConsentOverlayStyle()
|
||||
document.documentElement.classList.toggle('modrinth-ads-consent-overlay', shown)
|
||||
if (!shown) {
|
||||
document.documentElement.classList.remove('modrinth-ads-consent-preferences')
|
||||
}
|
||||
|
||||
if (window.top === window) {
|
||||
invokeAdsConsentOverlayCommand(shown)
|
||||
@@ -92,8 +356,23 @@ function handleTcfConsentEvent(tcData, success) {
|
||||
if (!success || !tcData) return
|
||||
|
||||
if (tcData.eventStatus === 'cmpuishown') {
|
||||
if (modrinthAdsConsentReprompt) {
|
||||
if (!modrinthAdsConsentRepromptManaging) {
|
||||
modrinthAdsConsentRepromptManaging = true
|
||||
window.dispatchEvent(new Event('resize'))
|
||||
sendAdsConsentCommandToChildFrames({ type: 'resize' })
|
||||
void performAdsConsentActionAcrossFrames('manage', 2500)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
setAdsConsentOverlay(true)
|
||||
} else if (tcData.eventStatus === 'useractioncomplete' || tcData.eventStatus === 'tcloaded') {
|
||||
} else if (tcData.eventStatus === 'useractioncomplete') {
|
||||
if (modrinthAdsConsentReprompt) {
|
||||
finishAdsConsentReprompt()
|
||||
return
|
||||
}
|
||||
|
||||
setAdsConsentOverlay(false)
|
||||
}
|
||||
}
|
||||
@@ -190,6 +469,7 @@ function muteVideos() {
|
||||
}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
installAdsRailStyle()
|
||||
installAdsConsentOverlayStyle()
|
||||
muteVideos()
|
||||
muteAudioContext()
|
||||
|
||||
+170
-4
@@ -3,7 +3,7 @@ use std::sync::Arc;
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::time::{Duration, Instant};
|
||||
use tauri::plugin::TauriPlugin;
|
||||
use tauri::{Manager, PhysicalPosition, PhysicalSize, Runtime};
|
||||
use tauri::{Emitter, Manager, PhysicalPosition, PhysicalSize, Rect, Runtime};
|
||||
use tauri_plugin_opener::OpenerExt;
|
||||
use theseus::settings;
|
||||
use tokio::sync::RwLock;
|
||||
@@ -11,6 +11,7 @@ use tokio::sync::RwLock;
|
||||
pub struct AdsState {
|
||||
pub shown: bool,
|
||||
pub modal_shown: bool,
|
||||
pub consent_required: bool,
|
||||
pub consent_overlay_shown: bool,
|
||||
pub occluded: bool,
|
||||
pub last_click: Option<Instant>,
|
||||
@@ -18,6 +19,7 @@ pub struct AdsState {
|
||||
}
|
||||
|
||||
const AD_LINK: &str = "https://modrinth.com/wrapper/app-ads-cookie";
|
||||
const ADS_CONSENT_REQUIRED_EVENT: &str = "ads-consent-required";
|
||||
const APP_TITLE_BAR_HEIGHT: f32 = 48.0;
|
||||
#[cfg(any(windows, target_os = "macos"))]
|
||||
pub(super) const OCCLUDED_AREA_THRESHOLD: f64 = 0.5;
|
||||
@@ -275,6 +277,7 @@ pub fn init<R: Runtime>() -> TauriPlugin<R> {
|
||||
app.manage(RwLock::new(AdsState {
|
||||
shown: true,
|
||||
modal_shown: false,
|
||||
consent_required: false,
|
||||
consent_overlay_shown: false,
|
||||
occluded: false,
|
||||
last_click: None,
|
||||
@@ -293,6 +296,7 @@ pub fn init<R: Runtime>() -> TauriPlugin<R> {
|
||||
.map(|state| {
|
||||
state.shown
|
||||
&& !state.modal_shown
|
||||
&& !state.consent_required
|
||||
&& !state.consent_overlay_shown
|
||||
&& !state.occluded
|
||||
})
|
||||
@@ -358,7 +362,12 @@ pub fn init<R: Runtime>() -> TauriPlugin<R> {
|
||||
hide_ads_window,
|
||||
show_ads_window,
|
||||
show_ads_consent_overlay,
|
||||
show_ads_consent_preferences,
|
||||
open_ads_consent_preferences,
|
||||
hide_ads_consent_preferences,
|
||||
hide_ads_consent_overlay,
|
||||
get_ads_consent_required,
|
||||
perform_ads_consent_action,
|
||||
record_ads_click,
|
||||
open_link,
|
||||
get_ads_personalization,
|
||||
@@ -635,6 +644,10 @@ pub async fn init_ads_window<R: Runtime>(
|
||||
// });
|
||||
}
|
||||
|
||||
if state.shown && state.consent_required {
|
||||
app.emit_to("main", ADS_CONSENT_REQUIRED_EVENT, true).ok();
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -648,6 +661,8 @@ pub async fn show_ads_window<R: Runtime>(
|
||||
app: tauri::AppHandle<R>,
|
||||
dpr: f32,
|
||||
) -> crate::api::Result<()> {
|
||||
let mut consent_required = false;
|
||||
|
||||
if let Some(webview) = app.webviews().get("ads-window") {
|
||||
let state = app.state::<RwLock<AdsState>>();
|
||||
let mut state = state.write().await;
|
||||
@@ -667,6 +682,12 @@ pub async fn show_ads_window<R: Runtime>(
|
||||
webview.show().ok();
|
||||
set_webview_visible_for_window(&app, webview, true);
|
||||
}
|
||||
|
||||
consent_required = state.shown && state.consent_required;
|
||||
}
|
||||
|
||||
if consent_required {
|
||||
app.emit_to("main", ADS_CONSENT_REQUIRED_EVENT, true).ok();
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@@ -677,11 +698,13 @@ pub async fn hide_ads_window<R: Runtime>(
|
||||
app: tauri::AppHandle<R>,
|
||||
reset: Option<bool>,
|
||||
) -> crate::api::Result<()> {
|
||||
let reset = reset.unwrap_or(false);
|
||||
|
||||
if let Some(webview) = app.webviews().get("ads-window") {
|
||||
let state = app.state::<RwLock<AdsState>>();
|
||||
let mut state = state.write().await;
|
||||
|
||||
if reset.unwrap_or(false) {
|
||||
if reset {
|
||||
state.shown = false;
|
||||
state.consent_overlay_shown = false;
|
||||
} else {
|
||||
@@ -706,6 +729,10 @@ pub async fn hide_ads_window<R: Runtime>(
|
||||
webview.hide().ok();
|
||||
}
|
||||
|
||||
if reset {
|
||||
app.emit_to("main", ADS_CONSENT_REQUIRED_EVENT, false).ok();
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -722,11 +749,45 @@ pub async fn show_ads_consent_overlay<R: Runtime>(
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
state.consent_required = true;
|
||||
state.consent_overlay_shown = false;
|
||||
|
||||
if !state.modal_shown {
|
||||
let dpr = get_device_pixel_ratio(&app, None);
|
||||
let (position, size) = get_webview_position(&app, dpr)?;
|
||||
webview.set_size(size).ok();
|
||||
webview.set_position(position).ok();
|
||||
webview.show().ok();
|
||||
set_webview_visible_for_window(&app, webview, true);
|
||||
}
|
||||
}
|
||||
|
||||
app.emit_to("main", ADS_CONSENT_REQUIRED_EVENT, true).ok();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn show_ads_consent_preferences<R: Runtime>(
|
||||
app: tauri::AppHandle<R>,
|
||||
) -> crate::api::Result<()> {
|
||||
if let Some(webview) = app.webviews().get("ads-window") {
|
||||
let state = app.state::<RwLock<AdsState>>();
|
||||
let mut state = state.write().await;
|
||||
|
||||
if !state.consent_required {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
state.consent_overlay_shown = true;
|
||||
|
||||
let (position, size) = get_overlay_webview_position(&app)?;
|
||||
webview.set_size(size).ok();
|
||||
webview.set_position(position).ok();
|
||||
webview
|
||||
.set_bounds(Rect {
|
||||
position: position.into(),
|
||||
size: size.into(),
|
||||
})
|
||||
.ok();
|
||||
webview.show().ok();
|
||||
set_webview_visible_for_window(&app, webview, true);
|
||||
}
|
||||
@@ -734,6 +795,62 @@ pub async fn show_ads_consent_overlay<R: Runtime>(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn open_ads_consent_preferences<R: Runtime>(
|
||||
app: tauri::AppHandle<R>,
|
||||
) -> crate::api::Result<()> {
|
||||
let Some(webview) = app.webviews().get("ads-window").cloned() else {
|
||||
return Ok(());
|
||||
};
|
||||
|
||||
{
|
||||
let state = app.state::<RwLock<AdsState>>();
|
||||
let mut state = state.write().await;
|
||||
state.consent_required = true;
|
||||
state.consent_overlay_shown = false;
|
||||
}
|
||||
|
||||
webview.eval("window.modrinthAdsReopenConsentPreferences?.()")?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Restores the ad inventory bounds without resolving the pending consent request.
|
||||
#[tauri::command]
|
||||
pub async fn hide_ads_consent_preferences<R: Runtime>(
|
||||
app: tauri::AppHandle<R>,
|
||||
) -> crate::api::Result<()> {
|
||||
if let Some(webview) = app.webviews().get("ads-window") {
|
||||
let state = app.state::<RwLock<AdsState>>();
|
||||
let mut state = state.write().await;
|
||||
|
||||
state.consent_overlay_shown = false;
|
||||
|
||||
if state.shown && !state.modal_shown {
|
||||
let dpr = get_device_pixel_ratio(&app, None);
|
||||
let (position, size) = get_webview_position(&app, dpr)?;
|
||||
|
||||
webview
|
||||
.set_bounds(Rect {
|
||||
position: position.into(),
|
||||
size: size.into(),
|
||||
})
|
||||
.ok();
|
||||
webview.show().ok();
|
||||
set_webview_visible_for_window(&app, webview, true);
|
||||
} else {
|
||||
webview
|
||||
.set_position(PhysicalPosition::new(-1000, -1000))
|
||||
.ok();
|
||||
webview.hide().ok();
|
||||
}
|
||||
}
|
||||
|
||||
app.emit_to("main", ADS_CONSENT_REQUIRED_EVENT, true).ok();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn hide_ads_consent_overlay<R: Runtime>(
|
||||
app: tauri::AppHandle<R>,
|
||||
@@ -742,7 +859,9 @@ pub async fn hide_ads_consent_overlay<R: Runtime>(
|
||||
if let Some(webview) = app.webviews().get("ads-window") {
|
||||
let state = app.state::<RwLock<AdsState>>();
|
||||
let mut state = state.write().await;
|
||||
let should_reload_ads = state.consent_required;
|
||||
|
||||
state.consent_required = false;
|
||||
state.consent_overlay_shown = false;
|
||||
|
||||
if state.shown && !state.modal_shown {
|
||||
@@ -759,6 +878,53 @@ pub async fn hide_ads_consent_overlay<R: Runtime>(
|
||||
.ok();
|
||||
webview.hide().ok();
|
||||
}
|
||||
|
||||
drop(state);
|
||||
|
||||
if should_reload_ads {
|
||||
webview.navigate(AD_LINK.parse().unwrap()).ok();
|
||||
}
|
||||
}
|
||||
|
||||
app.emit_to("main", ADS_CONSENT_REQUIRED_EVENT, false).ok();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn get_ads_consent_required<R: Runtime>(
|
||||
app: tauri::AppHandle<R>,
|
||||
) -> crate::api::Result<bool> {
|
||||
let state = app.state::<RwLock<AdsState>>();
|
||||
let state = state.read().await;
|
||||
|
||||
Ok(state.shown && state.consent_required)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn perform_ads_consent_action<R: Runtime>(
|
||||
app: tauri::AppHandle<R>,
|
||||
action: String,
|
||||
) -> crate::api::Result<()> {
|
||||
let script = match action.as_str() {
|
||||
"accept" => "window.modrinthAdsConsentAction?.('accept')",
|
||||
"reject" => "window.modrinthAdsConsentAction?.('reject')",
|
||||
"manage" => "window.modrinthAdsConsentAction?.('manage')",
|
||||
_ => return Ok(()),
|
||||
};
|
||||
|
||||
let state = app.state::<RwLock<AdsState>>();
|
||||
let should_perform = {
|
||||
let state = state.read().await;
|
||||
state.shown && state.consent_required
|
||||
};
|
||||
|
||||
if !should_perform {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
if let Some(webview) = app.webviews().get("ads-window") {
|
||||
webview.eval(script)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
||||
Reference in New Issue
Block a user