-
Notifications
You must be signed in to change notification settings - Fork 56
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
refactor(app): media view and note open logic
- Loading branch information
Showing
11 changed files
with
247 additions
and
195 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,166 @@ | ||
/* eslint-disable deprecation/deprecation */ | ||
import type { | ||
PaneType, | ||
App, | ||
SplitDirection, | ||
WorkspaceLeaf, | ||
TFile, | ||
MarkdownView, | ||
Editor, | ||
} from "obsidian"; | ||
import type { MediaEmbedViewState } from "@/media-view/iframe-view"; | ||
import type { MediaUrlViewState } from "@/media-view/url-view"; | ||
import type { MediaWebpageViewState } from "@/media-view/webpage-view"; | ||
import type MxPlugin from "@/mx-main"; | ||
import type { MediaInfo } from "../manager"; | ||
import { isFileMediaInfo } from "../manager/file-info"; | ||
import type { UrlMediaInfo } from "../manager/url-info"; | ||
import { filterFileLeaf, filterUrlLeaf, sortByMtime } from "./utils"; | ||
|
||
interface NewNoteInfo { | ||
title: string; | ||
fm: (newNotePath: string) => Record<string, any>; | ||
sourcePath?: string; | ||
} | ||
|
||
export class LeafOpener { | ||
app: App; | ||
constructor(public plugin: MxPlugin) { | ||
this.app = plugin.app; | ||
} | ||
|
||
async openMedia( | ||
mediaInfo: MediaInfo, | ||
newLeaf?: "split", | ||
direction?: SplitDirection, | ||
): Promise<void>; | ||
async openMedia( | ||
mediaInfo: MediaInfo, | ||
newLeaf?: PaneType | boolean, | ||
): Promise<void>; | ||
async openMedia( | ||
mediaInfo: MediaInfo, | ||
newLeaf?: PaneType | boolean, | ||
direction?: SplitDirection, | ||
): Promise<void> { | ||
const { workspace } = this.app; | ||
if (!newLeaf && this.#openInExistingPlayer(mediaInfo)) { | ||
return; | ||
} | ||
const leaf = workspace.getLeaf(newLeaf as any, direction); | ||
if (isFileMediaInfo(mediaInfo)) { | ||
await leaf.openFile(mediaInfo.file, { | ||
eState: { subpath: mediaInfo.hash }, | ||
}); | ||
} else { | ||
await openInLeaf(mediaInfo, leaf); | ||
} | ||
} | ||
|
||
#getLeavesOfMedia(info: MediaInfo) { | ||
const { workspace } = this.app; | ||
|
||
return workspace.getLeavesOfType(info.viewType).filter((leaf) => { | ||
if (isFileMediaInfo(info)) { | ||
return filterFileLeaf(leaf, info); | ||
} else { | ||
return filterUrlLeaf(leaf, info); | ||
} | ||
}); | ||
} | ||
|
||
#openInExistingPlayer(info: MediaInfo): boolean { | ||
const opened = this.#getLeavesOfMedia(info); | ||
if (opened.length > 0) { | ||
updateHash(info.hash, opened[0]); | ||
return true; | ||
} | ||
return false; | ||
} | ||
|
||
async openNote( | ||
mediaInfo: MediaInfo, | ||
newNoteInfo: NewNoteInfo, | ||
newLeaf?: "split", | ||
direction?: SplitDirection, | ||
): Promise<{ file: TFile; editor: Editor }>; | ||
async openNote( | ||
mediaInfo: MediaInfo, | ||
newNoteInfo: NewNoteInfo, | ||
newLeaf?: PaneType | boolean, | ||
): Promise<{ file: TFile; editor: Editor }>; | ||
async openNote( | ||
mediaInfo: MediaInfo, | ||
newNoteInfo: NewNoteInfo, | ||
newLeaf?: PaneType | boolean, | ||
direction?: SplitDirection, | ||
): Promise<{ file: TFile; editor: Editor }> { | ||
const notes = this.plugin.mediaNote.findNotes(mediaInfo); | ||
if (!newLeaf) { | ||
const opened = this.#getOpenedNote(notes); | ||
if (opened) return opened; | ||
} | ||
|
||
let targetNote: TFile; | ||
if (notes.length === 0) { | ||
const filename = `Media Note - ${newNoteInfo.title}.md`; | ||
targetNote = await this.#createNewNote( | ||
filename, | ||
newNoteInfo.fm, | ||
newNoteInfo.sourcePath ?? "", | ||
); | ||
} else { | ||
targetNote = notes.sort(sortByMtime).at(0)!; | ||
} | ||
|
||
const leaf = this.app.workspace.getLeaf(newLeaf as any, direction); | ||
await leaf.openFile(targetNote); | ||
return { | ||
file: targetNote, | ||
editor: (leaf.view as MarkdownView).editor, | ||
}; | ||
} | ||
|
||
#getOpenedNote(notes: TFile[]): { file: TFile; editor: Editor } | null { | ||
const { workspace } = this.app; | ||
const opened = workspace.getLeavesOfType("markdown").filter((leaf) => { | ||
const filePath = (leaf.view as MarkdownView).file?.path; | ||
return !!filePath && notes.some((note) => note.path === filePath); | ||
}) as (WorkspaceLeaf & { view: MarkdownView & { file: TFile } })[]; | ||
if (opened.length === 0) return null; | ||
const view = ( | ||
opened.find((leaf) => leaf === workspace.activeLeaf) ?? | ||
opened.sort((a, b) => sortByMtime(a.view.file, b.view.file)).at(0)! | ||
).view; | ||
return { file: view.file, editor: view.editor }; | ||
} | ||
async #createNewNote( | ||
filename: string, | ||
fm: (sourcePath: string) => Record<string, any>, | ||
sourcePath = "", | ||
) { | ||
const { fileManager, vault } = this.app; | ||
const folder = fileManager.getNewFileParent(sourcePath, filename); | ||
const newNote = await vault.create(`${folder.path}/${filename}`, ""); | ||
await fileManager.processFrontMatter(newNote, (fn) => { | ||
Object.assign(fn, fm(newNote.path)); | ||
}); | ||
return newNote; | ||
} | ||
} | ||
|
||
function updateHash(hash: string, leaf: WorkspaceLeaf) { | ||
leaf.setEphemeralState({ subpath: hash }); | ||
} | ||
async function openInLeaf(info: UrlMediaInfo, leaf: WorkspaceLeaf) { | ||
const state: MediaEmbedViewState | MediaWebpageViewState | MediaUrlViewState = | ||
{ source: info.original }; | ||
await leaf.setViewState( | ||
{ | ||
type: info.viewType, | ||
state, | ||
active: true, | ||
}, | ||
{ subpath: info.hash }, | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
import type { TFile, WorkspaceLeaf } from "obsidian"; | ||
import { AudioFileView, VideoFileView } from "@/media-view/file-view"; | ||
import { MediaEmbedView } from "@/media-view/iframe-view"; | ||
import { VideoUrlView, AudioUrlView } from "@/media-view/url-view"; | ||
import { MediaWebpageView } from "@/media-view/webpage-view"; | ||
import { type FileMediaInfo } from "../manager/file-info"; | ||
import type { UrlMediaInfo } from "../manager/url-info"; | ||
|
||
export function filterFileLeaf( | ||
leaf: WorkspaceLeaf, | ||
info: FileMediaInfo, | ||
): boolean { | ||
if ( | ||
!(leaf.view instanceof VideoFileView || leaf.view instanceof AudioFileView) | ||
) { | ||
return false; | ||
} | ||
const { file: filePath } = leaf.view.getState() as { file: string }; | ||
return filePath === info.file.path; | ||
} | ||
|
||
export function filterUrlLeaf( | ||
leaf: WorkspaceLeaf, | ||
info: UrlMediaInfo, | ||
): boolean { | ||
if ( | ||
!( | ||
leaf.view instanceof MediaEmbedView || | ||
leaf.view instanceof MediaWebpageView || | ||
leaf.view instanceof VideoUrlView || | ||
leaf.view instanceof AudioUrlView | ||
) | ||
) { | ||
return false; | ||
} | ||
const { source } = leaf.view.getState(); | ||
return !!source && info.isSameSource(source); | ||
} | ||
|
||
export function sortByMtime(a: TFile, b: TFile) { | ||
const aDate = a.stat.mtime; | ||
const bDate = b.stat.mtime; | ||
if (!aDate || !bDate) return 0; | ||
return bDate - aDate; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,44 +1,16 @@ | ||
import type { WorkspaceLeaf } from "obsidian"; | ||
import type { MediaEmbedViewState } from "@/media-view/iframe-view"; | ||
import type { MediaWebpageViewState } from "@/media-view/webpage-view"; | ||
import type MxPlugin from "@/mx-main"; | ||
import type { UrlMediaInfo } from "../manager/url-info"; | ||
import { parseUrl } from "../manager/url-info"; | ||
import { openInOpenedPlayer } from "./opened"; | ||
|
||
export async function onExternalLinkClick( | ||
this: MxPlugin, | ||
url: string, | ||
newLeaf: boolean, | ||
fallback: () => void, | ||
) { | ||
// eslint-disable-next-line @typescript-eslint/no-this-alias | ||
const { workspace } = this.app; | ||
|
||
const urlInfo = parseUrl(url); | ||
if (!urlInfo) { | ||
fallback(); | ||
return; | ||
} | ||
if (!newLeaf && openInOpenedPlayer(urlInfo, workspace)) return; | ||
|
||
const leaf = newLeaf | ||
? workspace.getLeaf("split", "vertical") | ||
: workspace.getLeaf(false); | ||
|
||
await openInLeaf(urlInfo, leaf); | ||
} | ||
|
||
export async function openInLeaf(info: UrlMediaInfo, leaf: WorkspaceLeaf) { | ||
const state: MediaEmbedViewState | MediaWebpageViewState = { | ||
source: info.original, | ||
}; | ||
await leaf.setViewState( | ||
{ | ||
type: info.viewType, | ||
state, | ||
active: true, | ||
}, | ||
{ subpath: info.hash }, | ||
); | ||
await this.leafOpener.openMedia(urlInfo, newLeaf); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
Oops, something went wrong.