refactor: extract AreaDrawer into independent component

This commit is contained in:
Clover You
2026-02-16 11:58:00 +08:00
committed by Dawn
parent b9aaf13ff0
commit 99e1422c70
5 changed files with 189 additions and 64 deletions

View File

@@ -3,27 +3,51 @@
mod desktops;
use crate::common::files_meta::get_files_meta;
use crate::common::init::CustomInit;
#[cfg(desktop)]
use common_cmd::audio;
#[cfg(desktop)]
use common_cmd::default_window_icon;
#[cfg(target_os = "windows")]
use common_cmd::get_windows_scale_info;
#[cfg(desktop)]
use common_cmd::{audio, default_window_icon, screenshot, set_height};
#[cfg(target_os = "macos")]
use common_cmd::{
hide_title_bar_buttons, set_macos_traffic_lights_spacing, set_window_level_above_menubar,
set_window_movable, show_title_bar_buttons,
};
use common_cmd::hide_title_bar_buttons;
#[cfg(desktop)]
use common_cmd::screenshot;
#[cfg(desktop)]
use common_cmd::set_height;
#[cfg(target_os = "macos")]
use common_cmd::set_macos_traffic_lights_spacing;
#[cfg(target_os = "macos")]
use common_cmd::set_window_level_above_menubar;
#[cfg(target_os = "macos")]
use common_cmd::set_window_movable;
#[cfg(target_os = "macos")]
use common_cmd::show_title_bar_buttons;
#[cfg(target_os = "macos")]
use desktops::app_event;
#[cfg(desktop)]
use desktops::window_payload::{get_window_payload, push_window_payload};
use desktops::common_cmd;
#[cfg(desktop)]
use desktops::{common_cmd, directory_scanner, init, tray, video_thumbnail::get_video_thumbnail};
use desktops::directory_scanner;
#[cfg(desktop)]
use directory_scanner::{cancel_directory_scan, get_directory_usage_info_with_progress};
use desktops::init;
#[cfg(desktop)]
use desktops::tray;
#[cfg(desktop)]
use desktops::video_thumbnail::get_video_thumbnail;
#[cfg(desktop)]
use desktops::window_payload::get_window_payload;
#[cfg(desktop)]
use desktops::window_payload::push_window_payload;
#[cfg(desktop)]
use directory_scanner::cancel_directory_scan;
#[cfg(desktop)]
use directory_scanner::get_directory_usage_info_with_progress;
#[cfg(desktop)]
use init::DesktopCustomInit;
use std::sync::Arc;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::atomic::AtomicBool;
use std::sync::atomic::Ordering;
use tauri_plugin_fs::FsExt;
pub mod command;
pub mod common;
@@ -40,22 +64,31 @@ pub mod websocket;
mod webview_helper;
use crate::command::app_state_command::is_app_state_ready;
use crate::command::request_command::{im_request_command, login_command};
use crate::command::room_member_command::{
cursor_page_room_members, get_room_members, page_room, update_my_room_info,
};
use crate::command::setting_command::{get_settings, update_settings};
use crate::command::request_command::im_request_command;
use crate::command::request_command::login_command;
use crate::command::room_member_command::cursor_page_room_members;
use crate::command::room_member_command::get_room_members;
use crate::command::room_member_command::page_room;
use crate::command::room_member_command::update_my_room_info;
use crate::command::setting_command::get_settings;
use crate::command::setting_command::update_settings;
use crate::command::user_command::remove_tokens;
use crate::configuration::{Settings, get_configuration};
use crate::configuration::Settings;
use crate::configuration::get_configuration;
use crate::error::CommonError;
use sea_orm::DatabaseConnection;
use serde::{Deserialize, Serialize};
use serde::Deserialize;
use serde::Serialize;
// 移动端依赖
#[cfg(mobile)]
mod mobiles;
#[cfg(target_os = "ios")]
use mobiles::ios::badge::{request_ios_badge_authorization, set_ios_badge};
use mobiles::ios::badge::request_ios_badge_authorization;
#[cfg(target_os = "ios")]
use mobiles::ios::badge::set_ios_badge;
#[cfg(target_os = "ios")]
use mobiles::ios::trigger_haptic_feedback;
#[cfg(mobile)]
use mobiles::splash;
@@ -76,23 +109,30 @@ pub struct AppData {
pub(crate) static APP_STATE_READY: AtomicBool = AtomicBool::new(false);
use crate::command::chat_history_command::query_chat_history;
use crate::command::contact_command::{hide_contact_command, list_contacts_command};
use crate::command::contact_command::hide_contact_command;
use crate::command::contact_command::list_contacts_command;
use crate::command::database_command::switch_user_database;
use crate::command::file_manager_command::{
debug_message_stats, get_navigation_items, query_files,
};
use crate::command::message_command::{
delete_message, delete_room_messages, page_msg, save_msg, send_msg, sync_messages,
update_message_recall_status,
};
use crate::command::file_manager_command::debug_message_stats;
use crate::command::file_manager_command::get_navigation_items;
use crate::command::file_manager_command::query_files;
use crate::command::message_command::delete_message;
use crate::command::message_command::delete_room_messages;
use crate::command::message_command::page_msg;
use crate::command::message_command::save_msg;
use crate::command::message_command::send_msg;
use crate::command::message_command::sync_messages;
use crate::command::message_command::update_message_recall_status;
use crate::command::message_mark_command::save_message_mark;
use crate::command::oauth_command::OauthServerState;
use crate::command::oauth_command::start_oauth_server;
use tauri::AppHandle;
use tauri::Emitter;
#[cfg(desktop)]
use tauri::Listener;
use tauri::{AppHandle, Emitter, Manager};
use tokio::sync::{Mutex, RwLock};
use tauri::Manager;
use tokio::sync::Mutex;
use tokio::sync::RwLock;
pub fn run() {
#[cfg(desktop)]
@@ -152,7 +192,8 @@ async fn initialize_app_data(
),
CommonError,
> {
use migration::{Migrator, MigratorTrait};
use migration::Migrator;
use migration::MigratorTrait;
use tracing::info;
// 加载配置
@@ -387,22 +428,30 @@ fn get_invoke_handlers() -> impl Fn(tauri::ipc::Invoke<tauri::Wry>) -> bool + Se
{
use crate::command::ai_command::ai_message_cancel_stream;
use crate::command::ai_command::ai_message_send_stream;
use crate::command::markdown_command::{get_readme_html, parse_markdown};
use crate::command::markdown_command::get_readme_html;
use crate::command::markdown_command::parse_markdown;
#[cfg(mobile)]
use crate::command::set_complete;
use crate::command::upload_command::{qiniu_upload_resumable, upload_file_put};
use crate::command::user_command::{
get_user_tokens, save_user_info, update_token, update_user_last_opt_time,
};
use crate::command::upload_command::qiniu_upload_resumable;
use crate::command::upload_command::upload_file_put;
use crate::command::user_command::get_user_tokens;
use crate::command::user_command::save_user_info;
use crate::command::user_command::update_token;
use crate::command::user_command::update_user_last_opt_time;
#[cfg(target_os = "ios")]
use crate::mobiles::keyboard::set_webview_keyboard_adjustment;
#[cfg(mobile)]
use crate::mobiles::splash::hide_splash_screen;
use crate::websocket::commands::{
ws_disconnect, ws_force_reconnect, ws_get_app_background_state, ws_get_health,
ws_get_state, ws_init_connection, ws_is_connected, ws_send_message,
ws_set_app_background_state, ws_update_config,
};
use crate::websocket::commands::ws_disconnect;
use crate::websocket::commands::ws_force_reconnect;
use crate::websocket::commands::ws_get_app_background_state;
use crate::websocket::commands::ws_get_health;
use crate::websocket::commands::ws_get_state;
use crate::websocket::commands::ws_init_connection;
use crate::websocket::commands::ws_is_connected;
use crate::websocket::commands::ws_send_message;
use crate::websocket::commands::ws_set_app_background_state;
use crate::websocket::commands::ws_update_config;
tauri::generate_handler![
// 桌面端特定命令
@@ -495,6 +544,8 @@ fn get_invoke_handlers() -> impl Fn(tauri::ipc::Invoke<tauri::Wry>) -> bool + Se
#[cfg(target_os = "ios")]
set_ios_badge,
#[cfg(target_os = "ios")]
trigger_haptic_feedback,
#[cfg(target_os = "ios")]
request_ios_badge_authorization,
#[cfg(target_os = "ios")]
set_webview_keyboard_adjustment,

View File

@@ -1 +1,16 @@
pub mod badge;
/// 触发IOS选择震动反馈
#[tauri::command]
#[cfg(target_os = "ios")]
pub fn trigger_haptic_feedback(window: tauri::Window) -> Result<(), String> {
use objc2::MainThreadMarker;
use objc2_ui_kit::UISelectionFeedbackGenerator;
if let Some(mtm) = MainThreadMarker::new() {
let generator = UISelectionFeedbackGenerator::new(mtm);
generator.prepare();
generator.selectionChanged();
};
Ok(())
}

View File

@@ -0,0 +1,63 @@
<template>
<NDrawer
v-model:show="showModel"
class="rounded-t-20px! overflow-hidden"
position="bottom"
round
placement="bottom"
default-height="350px">
<VantArea
:area-list="areaList"
@scroll-into="onScrollInto"
@cancel="onCancel"
@change="onChange"
@confirm="onConfirm"
v-model="valueModel">
<template #cancel>
<n-button strong secondary round>
{{ t('components.common.cancel') }}
</n-button>
</template>
<template #confirm>
<n-button strong secondary round type="success">
{{ t('components.common.confirm') }}
</n-button>
</template>
</VantArea>
</NDrawer>
</template>
<script setup lang="ts">
import { invoke } from '@tauri-apps/api/core'
import { areaList as list } from '@vant/area-data'
import { NDrawer } from 'naive-ui'
// The exported props from vant cannot be used with defineProps.
import { AreaList, Area as VantArea } from 'vant'
import { useI18n } from 'vue-i18n'
interface AreaProps {
areaList?: AreaList
}
interface Events {
onChange?: ((...args: any[]) => any) | undefined
'onUpdate:modelValue'?: ((...args: any[]) => any) | undefined
onCancel?: ((...args: any[]) => any) | undefined
onConfirm?: ((...args: any[]) => any) | undefined
}
type Props = AreaProps & Events
const showModel = defineModel<boolean>('show')
const valueModel = defineModel<string>('value')
const { areaList = list } = defineProps<Props>()
const { t } = useI18n()
const onScrollInto = () => {
console.log('into')
invoke('trigger_haptic_feedback')
}
</script>

View File

@@ -1,27 +1,29 @@
<template>
<div
class="h-full flex flex-col box-border"
:class="{
'bg-cover bg-center bg-no-repeat': props.backgroundImage
}"
:style="mergedStyle">
<!-- 顶部安全区域 -->
<div :class="[{ 'safe-area-top': safeAreaTop }, props.topSafeAreaClass]" />
<van-config-provider :theme="settingStore.themes.content === ThemeEnum.DARK ? 'dark' : 'light'" class="h-full">
<div
class="h-full flex flex-col box-border"
:class="{
'bg-cover bg-center bg-no-repeat': props.backgroundImage
}"
:style="mergedStyle">
<!-- 顶部安全区域 -->
<div :class="[{ 'safe-area-top': safeAreaTop }, props.topSafeAreaClass]" />
<!-- 内容区域 -->
<div class="flex-1 min-h-0">
<slot></slot>
<!-- 内容区域 -->
<div class="flex-1 min-h-0">
<slot></slot>
</div>
<!-- 底部安全区域 -->
<div :class="[{ 'safe-area-bottom': safeAreaBottom }, props.bottomSafeAreaClass]" />
</div>
<!-- 底部安全区域 -->
<div :class="[{ 'safe-area-bottom': safeAreaBottom }, props.bottomSafeAreaClass]" />
</div>
</van-config-provider>
</template>
<script setup lang="ts">
import { emitTo } from '@tauri-apps/api/event'
import { WebviewWindow } from '@tauri-apps/api/webviewWindow'
import { MsgEnum, NotificationTypeEnum, TauriCommand } from '@/enums'
import { MsgEnum, NotificationTypeEnum, TauriCommand, ThemeEnum } from '@/enums'
import { useMitt } from '@/hooks/useMitt'
import type { MessageType } from '@/services/types'
import { WsResponseMessageType } from '@/services/wsType'

View File

@@ -169,15 +169,10 @@
:placeholder="t('mobile_edit_profile.placeholder.brithday')"
@click="pickerState.region = true" />
-->
<n-drawer
<area-drawer
v-model:show="pickerState.region"
class="rounded-t-20px! overflow-hidden"
position="bottom"
round
placement="bottom"
default-height="300px">
<van-area :area-list="areaList" @confirm="pickerConfirm.region" @cancel="pickerState.region = false" />
</n-drawer>
@confirm="pickerConfirm.region"
@cancel="pickerState.region = false" />
<!-- 手机号 -->
<!-- <van-field
@@ -215,7 +210,6 @@
</template>
<script setup lang="ts">
import { areaList } from '@vant/area-data'
import { useAvatarUpload } from '@/hooks/useAvatarUpload'
import router from '@/router'
import type { ModifyUserInfoType, UserInfoType } from '@/services/types.ts'