Skip to content

Commit bc7c26d

Browse files
committed
[*] refactor
1 parent 768d671 commit bc7c26d

File tree

16 files changed

+150
-107
lines changed

16 files changed

+150
-107
lines changed

lib/video-editor/src/font.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@ pub fn get_fonts_info() -> Result<Vec<(String, PathBuf)>> {
1717
}
1818
}
1919

20-
fonts.sort_by(|a, b| a.0.cmp(&b.0));
21-
fonts.dedup_by(|a, b| a.0 == b.0);
20+
fonts.sort_by(|a, b| a.1.cmp(&b.1));
21+
fonts.dedup_by(|a, b| a.1 == b.1);
2222

2323
Ok(fonts)
2424
}

todo.md

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,12 @@
11
## 问题
22
- subtitle需要重新设计
33

4-
- font 列表toggle实现逻辑过于复杂
5-
- font 搜索功能实现有问题,列表条目丢失
6-
- 刷新后导入条目丢失
7-
- fly in滤镜应该重构成和transform一样的模式
8-
- chorme-key 路径参数面板无法显示
9-
10-
- moving filter参数面板暂停时会恢复默认值
11-
- color picker弹出时需要设置现有的颜色
4+
- fly in preview显示时机有问题
5+
- fly in filter参数面板暂停时会恢复默认值
126

137
## 待验证
8+
- color picker弹出时需要设置现有的颜色
9+
- font 列表显示有问题,条目变少了。刷新时有275条,但是显示时却只有254条
1410

1511
- 视频轨道分离字幕
1612

wayshot/src/db.rs

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use crate::slint_generatedAppWindow::{
2-
FileType as UIFileType, FontEntry as UIFontEntry, HistoryEntry as UIHistoryEntry,
3-
SettingPlayer as UISettingPlayer, Subtitle as UISubtitle, Transcribe as UITranscribe,
2+
FileType as UIFileType, FontEntry as UIFontEntry, FontSource as UIFontSource,
3+
HistoryEntry as UIHistoryEntry, SettingPlayer as UISettingPlayer, Subtitle as UISubtitle,
4+
Transcribe as UITranscribe,
45
};
56
use pmacro::SlintFromConvert;
67
use serde::{Deserialize, Serialize};
@@ -222,4 +223,14 @@ pub struct FontEntry {
222223
pub family: String,
223224
pub path: String,
224225
pub marked: bool,
226+
pub source: FontSource,
225227
}
228+
229+
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Default)]
230+
pub enum FontSource {
231+
#[default]
232+
System,
233+
Imported,
234+
}
235+
236+
crate::impl_c_like_enum_convert!(UIFontSource, FontSource, System, Imported);

wayshot/src/logic/video_editor/conversion.rs

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ use super::command::with_history_manager;
22
use crate::slint_generatedAppWindow::{
33
AudioChannels as UIAudioChannels, AudioFormat as UIAudioFormat,
44
AudioSampleRate as UIAudioSampleRate, CropDetail as UICropDetail, FilterType as UIFilterType,
5-
Fps as UIFps, MediaType as UIMediaType, Resolution as UIResolution,
6-
SegmentFilter as UISegmentFilter, SubtitleType as UISubtitleType,
5+
FlyInDetail as UIFlyInDetail, Fps as UIFps, MediaType as UIMediaType,
6+
Resolution as UIResolution, SegmentFilter as UISegmentFilter, SubtitleType as UISubtitleType,
77
TransformDetail as UITransformDetail, VideoEditorLayerImage as UIVideoEditorLayerImage,
88
VideoEditorPlaylistItem as UIVideoEditorPlaylistItem,
99
VideoEditorPreviewConfig as UIVideoEditorPreviewConfig,
@@ -39,9 +39,9 @@ use video_editor::{
3939
OutlineWidthFilter, PaddingFilter, PrimaryColorFilter,
4040
},
4141
video::{
42-
BorderFilter, ChromaKeyFilter, CropFilter,
43-
FadeInFilter as VideoFadeInFilter, FadeOutFilter as VideoFadeOutFilter, FlipFilter,
44-
OpacityFilter, SlideFilter, TransformFilter, WipeFilter, ZoomFilter,
42+
BorderFilter, ChromaKeyFilter, CropFilter, FadeInFilter as VideoFadeInFilter,
43+
FadeOutFilter as VideoFadeOutFilter, FlipFilter, FlyInFilter, OpacityFilter,
44+
SlideFilter, TransformFilter, WipeFilter, ZoomFilter,
4545
},
4646
},
4747
media::{MediaItem, media_type::MediaType, playlist::PlaylistItem},
@@ -745,6 +745,28 @@ pub fn layer_frame_to_ui(layer: &LayerFrame) -> Option<UIVideoEditorLayerImage>
745745
})
746746
.unwrap_or_else(|| ZoomFilter::default().into());
747747

748+
let fly_in: UIFlyInDetail = layer
749+
.from_segment
750+
.as_ref()
751+
.and_then(|(_, segment)| {
752+
if is_image_track {
753+
segment
754+
.image_filters
755+
.iter()
756+
.find(|f| f.inner.name() == FlyInFilter::NAME)
757+
.and_then(|f| f.inner.as_any().downcast_ref::<FlyInFilter>())
758+
.map(|t| t.clone().into())
759+
} else {
760+
segment
761+
.video_filters
762+
.iter()
763+
.find(|f| f.inner.name() == FlyInFilter::NAME)
764+
.and_then(|f| f.inner.as_any().downcast_ref::<FlyInFilter>())
765+
.map(|t| t.clone().into())
766+
}
767+
})
768+
.unwrap_or_else(|| FlyInFilter::default().into());
769+
748770
Some(UIVideoEditorLayerImage {
749771
track_index: layer.track_index as i32,
750772
segment_index: layer
@@ -757,6 +779,7 @@ pub fn layer_frame_to_ui(layer: &LayerFrame) -> Option<UIVideoEditorLayerImage>
757779
transform,
758780
crop,
759781
zoom,
782+
fly_in,
760783
})
761784
}
762785

wayshot/src/logic/video_editor/font.rs

Lines changed: 59 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
11
use crate::{
2-
db::{FONT_TABLE as DB_TABLE, FontEntry},
2+
db::{FONT_TABLE as DB_TABLE, FontEntry, FontSource},
33
db_select_all, db_update,
44
logic::{toast, tr::tr, video_editor::playlist::picker_files},
55
logic_cb,
66
slint_generatedAppWindow::{AppWindow, FontEntry as UIFontEntry},
77
};
88
use once_cell::sync::Lazy;
99
use slint::{ComponentHandle, Model, SharedString, VecModel, Weak};
10-
use std::{collections::HashSet, path::PathBuf};
11-
use tokio::sync::RwLock;
10+
use std::{collections::HashSet, path::PathBuf, sync::RwLock};
1211
use video_editor::font::{get_font_family_from_file, get_fonts_info};
1312

1413
db_update!(DB_TABLE, FontEntry);
@@ -39,11 +38,19 @@ pub fn init(ui: &AppWindow) {
3938
fn init_font_dialog(ui: &AppWindow) {
4039
let ui_weak = ui.as_weak();
4140
tokio::spawn(async move {
42-
let db_fonts = db_select_all!(DB_TABLE, FontEntry);
43-
if db_fonts.is_empty() {
44-
refresh_font_entries_impl(ui_weak.clone()).await;
41+
let cached_fonts = {
42+
let cache = FONT_CACHE.read().unwrap();
43+
if cache.is_empty() {
44+
None
45+
} else {
46+
Some(cache.clone())
47+
}
48+
};
49+
50+
if let Some(fonts) = cached_fonts {
51+
sync_fonts_to_ui(ui_weak, fonts).await;
4552
} else {
46-
sync_fonts_to_ui(ui_weak, db_fonts).await;
53+
refresh_font_entries_impl(ui_weak).await;
4754
}
4855
});
4956
}
@@ -56,18 +63,19 @@ fn refresh_font_entries(ui: &AppWindow) {
5663
}
5764

5865
async fn refresh_font_entries_impl(ui_weak: Weak<AppWindow>) {
59-
let marked_fonts: HashSet<String> = {
60-
let db_fonts = db_select_all!(DB_TABLE, FontEntry);
61-
db_fonts
62-
.into_iter()
63-
.filter(|f| f.marked)
64-
.map(|f| f.path)
65-
.collect()
66-
};
66+
let existing_fonts = db_select_all!(DB_TABLE, FontEntry);
6767

68-
if let Err(e) = sqldb::entry::delete_all(DB_TABLE).await {
69-
log::warn!("Failed to clear font table: {}", e);
70-
}
68+
let imported_fonts: Vec<FontEntry> = existing_fonts
69+
.iter()
70+
.filter(|f| f.source == FontSource::Imported)
71+
.cloned()
72+
.collect();
73+
74+
let marked_paths: HashSet<String> = existing_fonts
75+
.iter()
76+
.filter(|f| f.marked)
77+
.map(|f| f.path.clone())
78+
.collect();
7179

7280
let system_fonts = match get_fonts_info() {
7381
Ok(fonts) => fonts,
@@ -77,16 +85,22 @@ async fn refresh_font_entries_impl(ui_weak: Weak<AppWindow>) {
7785
}
7886
};
7987

88+
if let Err(e) = sqldb::entry::delete_all(DB_TABLE).await {
89+
log::warn!("Failed to clear font table: {}", e);
90+
}
91+
8092
let mut font_entries: Vec<FontEntry> = Vec::new();
93+
8194
for (family, path) in system_fonts {
8295
let path_str = path.to_string_lossy().to_string();
83-
let marked = marked_fonts.contains(&path_str);
96+
let marked = marked_paths.contains(&path_str);
8497

8598
let entry = FontEntry {
8699
id: path_str.clone(),
87100
family,
88101
path: path_str,
89102
marked,
103+
source: FontSource::System,
90104
};
91105

92106
let data = serde_json::to_string(&entry).expect("Serialize font entry");
@@ -97,13 +111,22 @@ async fn refresh_font_entries_impl(ui_weak: Weak<AppWindow>) {
97111
font_entries.push(entry);
98112
}
99113

114+
for entry in imported_fonts {
115+
let data = serde_json::to_string(&entry).expect("Serialize font entry");
116+
if let Err(e) = sqldb::entry::insert(DB_TABLE, entry.id.as_str(), &data).await {
117+
log::warn!("Failed to insert imported font {}: {}", entry.family, e);
118+
}
119+
font_entries.push(entry);
120+
}
121+
122+
{
123+
let mut cache = FONT_CACHE.write().unwrap();
124+
*cache = font_entries.clone();
125+
}
100126
sync_fonts_to_ui(ui_weak, font_entries).await;
101127
}
102128

103129
async fn sync_fonts_to_ui(ui_weak: Weak<AppWindow>, mut fonts: Vec<FontEntry>) {
104-
let fonts_for_cache = fonts.clone();
105-
*FONT_CACHE.write().await = fonts_for_cache;
106-
107130
fonts.sort_by(|a, b| b.marked.cmp(&a.marked));
108131
let ui_fonts: Vec<UIFontEntry> = fonts.into_iter().map(|f| f.into()).collect();
109132

@@ -133,9 +156,11 @@ fn import_font_files(ui: &AppWindow) {
133156
}
134157

135158
if !imported_fonts.is_empty() {
136-
let mut cache = FONT_CACHE.write().await;
137-
for font in &imported_fonts {
138-
cache.push(font.clone().into());
159+
{
160+
let mut cache = FONT_CACHE.write().unwrap();
161+
for font in &imported_fonts {
162+
cache.push(font.clone().into());
163+
}
139164
}
140165

141166
_ = ui_weak.upgrade_in_event_loop(move |ui| {
@@ -166,6 +191,7 @@ async fn import_font_to_db(ui_weak: Weak<AppWindow>, file_path: PathBuf) -> Opti
166191
family,
167192
path: path_str,
168193
marked: true,
194+
source: FontSource::Imported,
169195
};
170196

171197
let data = serde_json::to_string(&entry).expect("Serialize font entry");
@@ -190,6 +216,13 @@ fn toggle_font_marked(ui: &AppWindow, index: i32) {
190216
font_info.marked = !font_info.marked;
191217
db_update(ui.as_weak(), font_info.clone().into());
192218

219+
{
220+
let mut cache = FONT_CACHE.write().unwrap();
221+
if let Some(entry) = cache.iter_mut().find(|e| e.id == font_info.id.as_str()) {
222+
entry.marked = font_info.marked;
223+
}
224+
}
225+
193226
let mut fonts: Vec<UIFontEntry> = store_font_entries!(ui).iter().collect();
194227
fonts[idx] = font_info;
195228
fonts.sort_by(|a, b| b.marked.cmp(&a.marked));
@@ -202,7 +235,7 @@ fn search_font_entries(ui: &AppWindow, text: SharedString) {
202235
let text = text.to_string();
203236

204237
tokio::spawn(async move {
205-
let cache = FONT_CACHE.read().await.clone();
238+
let cache = FONT_CACHE.read().unwrap().clone();
206239

207240
let filtered = if text.is_empty() {
208241
cache

wayshot/ui/panel/desktop/font-dialog.slint

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,8 @@ component HeadBar inherits HorizontalLayout {
4444

4545
key-pressed(event) => {
4646
if (event.text == Key.Escape) {
47-
Logic.search-font-entries("");
4847
show-search-bar = false;
48+
Logic.refresh-font-entries();
4949
}
5050
}
5151

@@ -71,6 +71,9 @@ component HeadBar inherits HorizontalLayout {
7171

7272
clicked => {
7373
show-search-bar = !show-search-bar;
74+
if (!show-search-bar) {
75+
Logic.refresh-font-entries();
76+
}
7477
}
7578
}
7679

@@ -114,7 +117,6 @@ component FontItem inherits Rectangle {
114117

115118
clicked => {
116119
Store.selected-font-entry = entry;
117-
VEFilter.selected-font-path = entry.path;
118120
Store.is-show-font-dialog = false;
119121
}
120122
}

wayshot/ui/panel/desktop/video-editor/filter.slint

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -273,12 +273,7 @@ export global VEFilter {
273273
// 用于创建预设滤镜时,临时存储选中的滤镜
274274
in-out property <[PresetFilter]> cache-preset-filters: [];
275275

276-
in-out property <float> preview-locate-layer-move-to-x: 0.6;
277-
in-out property <float> preview-locate-layer-move-to-y: 0.6;
278-
279276
in-out property <int> right-panel-selected-index;
280-
in-out property <string> selected-font-path;
281-
282277
in-out property <FontStyle> font-style;
283278

284279
callback up-filter(index: int);

0 commit comments

Comments
 (0)