Skip to content

Commit

Permalink
Merge pull request #60 from Enraged-Dun-Cookie-Development-Team/master
Browse files Browse the repository at this point in the history
🔖 release 1.0.3
  • Loading branch information
Goodjooy authored Oct 10, 2023
2 parents 07cf189 + 8eac9c4 commit c69ed7a
Show file tree
Hide file tree
Showing 12 changed files with 263 additions and 24 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "ceobe-canteen-electron",
"version": "1.0.2",
"version": "1.0.3",
"private": true,
"description": "帮小刻找好多好吃的饼",
"author": "CeobeCanteen",
Expand Down
6 changes: 4 additions & 2 deletions src-tauri/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "ceobe-canteen-desktop"
version = "1.0.2"
version = "1.0.3"
description = "小刻食堂的桌面端,恭喜你电脑有多了个和小刻一样喜欢吃东西的浏览器内核 "
authors = ["FrozenString<frozenstringstable@gmail.com>"]
license="AGPL-3"
Expand Down Expand Up @@ -47,13 +47,15 @@ reqwest-retry = "0.2"
serde_repr = "0.1.16"
[target.'cfg(windows)'.dependencies.windows]
version = "0.39"
features = ["Data_Xml_Dom",
features = [
"Win32_Foundation",
"Win32_Security",
"Win32_System_Com",
"Win32_System_Threading",
"Win32_UI_WindowsAndMessaging",
]
[target.'cfg(windows)'.dependencies. winrt-toast]
version = "0.1.1"

[features]
# this feature is used for production builds or when `devPath` points to the filesystem and the built-in dev server is disabled.
Expand Down
4 changes: 4 additions & 0 deletions src-tauri/src/commands/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@ mod quit;
mod request_client;
mod request_refer_image;
mod resource_location;
mod system_notification;
mod update_available;
mod should_silence;

pub use self::auto_launch::{auto_launch_setting, set_auto_launch};
pub use clipboard::copy_image;
Expand All @@ -24,3 +26,5 @@ pub use quit::quit;
pub use request_client::send_request;
pub use request_refer_image::request_refer_image;
pub use resource_location::{get_app_cache_path, get_app_config_path};
pub use system_notification::send_system_notification;
pub use should_silence::should_silence;
39 changes: 39 additions & 0 deletions src-tauri/src/commands/should_silence.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
use tauri::command;

#[command]
pub fn should_silence() -> tauri::Result<bool> {
#[cfg(windows)]
{
use std::mem::size_of;
use windows::Win32::{
Foundation::{RECT},
Graphics::Gdi::{GetMonitorInfoW, MonitorFromWindow, MONITORINFO, MONITOR_DEFAULTTOPRIMARY},
UI::WindowsAndMessaging::{
GetDesktopWindow, GetForegroundWindow, GetShellWindow, GetWindowRect,
},
};

let shell = unsafe { GetShellWindow() };
let desktop = unsafe { GetDesktopWindow() };
let hwnd = unsafe { GetForegroundWindow() };
if hwnd.0 == 0 ||( hwnd == shell || hwnd == desktop ){
Ok(false)
} else {
let mut rect = RECT::default();
unsafe { GetWindowRect(hwnd, &mut rect) };

let mut monitor_info = MONITORINFO {
cbSize: size_of::<MONITORINFO>() as u32,
..Default::default()
};
let monitor = unsafe { MonitorFromWindow(hwnd, MONITOR_DEFAULTTOPRIMARY) };
unsafe { GetMonitorInfoW(monitor, &mut monitor_info) };

let monitor_size = monitor_info.rcMonitor;

Ok(rect.left == monitor_size.left && rect.right == monitor_size.right && rect.top == monitor_size.top && rect.bottom == monitor_size.bottom)
}
}
#[cfg(not(windows))]
Ok(false)
}
130 changes: 130 additions & 0 deletions src-tauri/src/commands/system_notification.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
use serde::{Deserialize, Serialize, Serializer};

use tauri::{command, AppHandle, Window};
use tracing::instrument;

use url::Url;

#[derive(Debug, thiserror::Error)]
pub enum NotifyError {
#[error(transparent)]
TauriApi(#[from] tauri::api::Error),
#[cfg(windows)]
#[error(transparent)]
Tauri(#[from] tauri::Error),
#[cfg(windows)]
#[error(transparent)]
Toast(#[from] winrt_toast::WinToastError),
#[cfg(windows)]
#[error(transparent)]
Request(#[from] reqwest::Error),
#[cfg(windows)]
#[error(transparent)]
RequestMiddle(#[from] reqwest_middleware::Error),
#[cfg(windows)]
#[error(transparent)]
Io(#[from] std::io::Error),
}

impl Serialize for NotifyError {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
self.to_string().serialize(serializer)
}
}

#[derive(Debug, Serialize, Deserialize)]
pub struct NotificationPayload {
title: String,
body: String,
#[serde(default)]
has_sound: bool,
time: String,
image_url: Option<Url>,
}
#[command(async)]
#[instrument(name = "SendToastNotify", skip(app, window), err)]
pub async fn send_system_notification(
window: Window,
app: AppHandle,
payload: NotificationPayload,
) -> Result<(), NotifyError> {
#[cfg(windows)]
{
use crate::{request_client::RequestClient, state::get_cache_dir};
use http::{HeaderValue, Method};
use std::sync::OnceLock;
use tracing::{error, info};
use winrt_toast::{
content::text::TextPlacement, Image, Scenario, Text, Toast, ToastManager,
};

static MANAGER: OnceLock<ToastManager> = OnceLock::new();
let manager = MANAGER
.get_or_init(|| ToastManager::new(app.config().tauri.bundle.identifier.as_str()));

let mut toast = Toast::new();
toast.launch("click:cookie");
toast.text1(payload.title);
toast.text2(Text::new(payload.body));
if let Some(img) = payload.image_url {
let dir = get_cache_dir(app.clone());
let client = RequestClient::get_this(app.clone());
let resp = client
.request(Method::GET, img)
.header("Referer", HeaderValue::from_static("https://weibo.com/"))
.send()
.await?;
let byte = resp.bytes().await?;
let tmp_file = dir.join("notify_img.jpg");
std::fs::write(&tmp_file, byte)?;

toast.image(1, Image::new_local(tmp_file)?);
}

toast.text3(
Text::new(format!("at: {}", payload.time)).with_placement(TextPlacement::Attribution),
);
toast.scenario(Scenario::Reminder);
manager.show_with_callbacks(
&toast,
Some(Box::new(move |launch| {
let re = launch
.map_err(NotifyError::from)
.and_then(|_| window.show().map_err(Into::into));
match re {
Ok(_) => {}
Err(err) => {
error!(Action="Respond To User Select", Error = %err);
}
};
})),
Some(Box::new(|reason| match reason {
Ok(reason) => {
info!(Action="Notify Dismiss",reason= ?reason);
}
Err(err) => {
error!(Action="Notify Dismiss", Error = %err);
}
})),
Some(Box::new(|err| {
error!(Action="Notify Failure", Error = %err);
}) as _),
)?;
}
#[cfg(not(windows))]
{
let mut notify =
tauri::api::notification::Notification::new(&app.config().tauri.bundle.identifier)
.title(payload.title)
.body(payload.body);
if payload.has_sound {
notify = notify.sound(tauri::api::notification::Sound::Default)
}
notify.show()?;
}

Ok(())
}
7 changes: 5 additions & 2 deletions src-tauri/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ use tauri::{generate_context, Builder, Context, Manager, WindowEvent};
use crate::commands::{
auto_launch_setting, back_preview, copy_image, front_logger, get_app_cache_path,
get_app_config_path, get_item, get_monitor_info, hide_notification, is_debug, message_beep,
quit, read_detail, request_refer_image, send_request, set_auto_launch, set_item,
quit, read_detail, request_refer_image, send_request, send_system_notification,
set_auto_launch, set_item,should_silence
};
use crate::setup::logger::init_logger;
use crate::setup::system_tray::new_system_tray;
Expand Down Expand Up @@ -68,7 +69,9 @@ fn main() {
get_app_cache_path,
get_app_config_path,
hide_notification,
is_debug
is_debug,
send_system_notification,
should_silence
]);

let app = builder
Expand Down
2 changes: 1 addition & 1 deletion src-tauri/tauri.conf.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
},
"package": {
"productName": "小刻食堂",
"version": "1.0.2"
"version": "1.0.3"
},
"tauri": {
"systemTray": {
Expand Down
44 changes: 33 additions & 11 deletions src/api/operations/notification.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import {appWindow, getAll, WebviewWindow} from "@tauri-apps/api/window";
import {listen, UnlistenFn, Event} from "@tauri-apps/api/event";
import {Cookie} from "../resourceFetcher/cookieList";
import storage from "./localStorage";
import {invoke} from "@tauri-apps/api";


class NotificationOperate {
async getInfo(callback: (event: string, payload: Cookie) => void,): Promise<UnlistenFn> {
Expand All @@ -24,37 +26,57 @@ class NotificationOperate {
}

async setNotificationMode(modeIdx: number) {
console.log("setting Notify mod",modeIdx)
console.log("setting Notify mod", modeIdx)
await storage.setItem("setting.notify", modeIdx);
}

async getNotificationMode(): Promise<{ idx: number, value: string ,tip:string}> {
async getNotificationMode(): Promise<{ idx: number, value: string, tip: string }> {
const idx = await storage.getItem<number>("setting.notify") ?? NotifyMode.PopUpAndBeep.idx
return allNotifyMode.find((mode)=>mode.idx==idx)!!
const mode = allNotifyMode.find((mode) => mode.idx == idx);
return mode?mode:NotifyMode.None
}

async needNotifyPop():Promise<boolean>{
const mode =await this.getNotificationMode()
async needNotifyPop(): Promise<boolean> {
const mode = await this.getNotificationMode()
return mode.idx == NotifyMode.PopUpOnly.idx || mode.idx == NotifyMode.PopUpAndBeep.idx;
}
async needBeep():Promise<boolean>{
const mode = await this.getNotificationMode()

async needBeep(): Promise<boolean> {
const mode = await this.getNotificationMode()
return mode.idx == NotifyMode.PopUpAndBeep.idx || mode.idx == NotifyMode.BeepOnly.idx;
}
async needSystemNotify():Promise<boolean>{
const mode = await this.getNotificationMode()
return mode.idx == NotifyMode.SystemToast.idx
}

async sendSystemNotify(payload: NotifyPayload) {
await invoke("send_system_notification", {payload: payload})
}
}

export interface NotifyPayload {
title: string,
body: string,
time:string,
has_sound?: boolean,
image_url?: string
}

export const NotifyMode = Object.freeze({
PopUpOnly: {
idx: 0, value: "仅弹窗",tip:"当发现新饼后只会出现右下角弹窗"
idx: 0, value: "仅弹窗", tip: "当发现新饼后只会出现右下角弹窗"
}, BeepOnly: {
idx: 1, value: "仅提示音",tip:"当发现新饼后只会发出提示音"
idx: 1, value: "仅提示音", tip: "当发现新饼后只会发出提示音"
}, PopUpAndBeep: {
idx: 2, value: "弹窗且提示音",tip:"当发现新饼后不但出现右下角弹窗,同时发出提示音"
idx: 2, value: "弹窗且提示音", tip: "当发现新饼后不但出现右下角弹窗,同时发出提示音"
}, SystemToast: {
idx: 4, value: "使用系统消息", tip: "当发现新饼时发出系统弹窗,Windows可以拉起主窗口"
}, None: {
idx: 3, value: "无",tip:"当发现新饼后无任何行为"
},
})
export const allNotifyMode = [NotifyMode.PopUpAndBeep, NotifyMode.BeepOnly, NotifyMode.PopUpOnly, NotifyMode.None]
export const allNotifyMode = [NotifyMode.PopUpAndBeep, NotifyMode.BeepOnly, NotifyMode.PopUpOnly,NotifyMode.SystemToast, NotifyMode.None]
const notification = new NotificationOperate();

export default notification;
18 changes: 16 additions & 2 deletions src/api/operations/operate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@ import notification from "./notification";
class Operate {
async openNotificationWindow(cookie: Cookie) {
console.log(`send Notification`);
if (await invoke("should_silence")){
console.log("Detect FullScreen, cancel notify")
return
}

if (await notification.needNotifyPop()) {

let monitorInfo = await invoke<{
Expand All @@ -28,8 +33,17 @@ class Operate {
console.log(await window.outerPosition());
console.log("send cookie ", cookie)
await window.emit("new_cookie_info", cookie);
}else if (await notification.needBeep()){
await this.messageBeep()
} else if (await notification.needBeep()) {
await this.messageBeep()
} else if (await notification.needSystemNotify()) {
await notification.sendSystemNotify({
body: cookie.default_cookie.text,
has_sound: true,
time:new Date(cookie.timestamp.platform!).toLocaleString(),
image_url: cookie.default_cookie.images ? cookie.default_cookie.images[0].origin_url: undefined ,
title: `小刻在${cookie.datasource}蹲到饼了`

})
}
}

Expand Down
6 changes: 5 additions & 1 deletion src/components/SettingPage.vue
Original file line number Diff line number Diff line change
Expand Up @@ -93,16 +93,20 @@ const isDebug = computed(() => {
// test send notification
const sen_d = () => {
setTimeout(
()=>{
operate.openNotificationWindow({
datasource: 'kkwd',
default_cookie: {
images: [{compress_url: null, origin_url: 'https://i0.hdslb.com/bfs/new_dyn/2956e376fb056cf79cc95bcf585dbbc0161775300.jpg'}],
text: '欸嘿嘿,桃金娘的脚小小的~香香的~.'
text: '欸嘿嘿,桃金娘的脚小小的~香香的~.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'
},
icon: '/assets/icon/anime.png',
source: {data: '123', type: 'nn'},
timestamp: {fetcher: 114514, platform: 114514, platform_precision: 'minute'}
})
},5000)
}
const showDownload = computed(() => props.versionState === VersionStateType.UpdateAvailable)
Expand Down
Loading

0 comments on commit c69ed7a

Please sign in to comment.