-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathreleaseNotes.tsx
More file actions
127 lines (112 loc) · 3.55 KB
/
Copy pathreleaseNotes.tsx
File metadata and controls
127 lines (112 loc) · 3.55 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
import {
Device,
Markdown,
NavigationStack,
Path,
ScrollView,
Script,
useEffect,
useState,
type MarkdownProps,
type PresentationDetent
} from 'scripting'
type MarkdownReleaseNotesSheetConfig = {
markdownFile?: string
storageKey?: string
title?: string
theme?: MarkdownProps['theme']
detents?: PresentationDetent[]
markAsSeenOnDismiss?: boolean
}
const DEFAULT_CHANGELOG_FILE = 'changelog.md'
function normalizeMarkdownContent(content: string): string {
return content.replace(/\r\n/g, '\n').trim()
}
function hashString(value: string): string {
let hash = 2166136261
for (let index = 0; index < value.length; index += 1) {
hash ^= value.charCodeAt(index)
hash = Math.imul(hash, 16777619)
}
return (hash >>> 0).toString(16)
}
function MarkdownReleaseNotesSheet({
content,
title,
theme,
detents
}: {
content: string
title?: string
theme?: MarkdownProps['theme']
detents?: PresentationDetent[]
}) {
const useGlassPresentation = Number.parseInt(Device.systemVersion, 10) >= 26
return (
<NavigationStack presentationBackground={useGlassPresentation ? "clear" : undefined}>
<ScrollView
background="clear"
scrollContentBackground="hidden"
navigationTitle={title ?? '更新说明'}
navigationBarTitleDisplayMode="inline"
toolbarBackgroundVisibility="hidden"
presentationDragIndicator="visible"
presentationDetents={detents ?? ['medium', 'large']}
presentationBackground={useGlassPresentation ? "clear" : undefined}
padding={{ top: 24, leading: 18, bottom: 18, trailing: 18 }}
>
<Markdown
content={content}
theme={theme ?? 'basic'}
useDefaultHighlighterTheme
scrollable={false}
background="clear"
frame={{ maxWidth: 'infinity', alignment: 'leading' }}
multilineTextAlignment="leading"
/>
</ScrollView>
</NavigationStack>
)
}
export function useMarkdownReleaseNotesSheet(config: MarkdownReleaseNotesSheetConfig = {}) {
const markdownFile = config.markdownFile ?? DEFAULT_CHANGELOG_FILE
const storageKey = config.storageKey ?? `release-notes:${markdownFile}:last-seen-hash`
const markAsSeenOnDismiss = config.markAsSeenOnDismiss ?? true
const [releaseNotesContent, setReleaseNotesContent] = useState('')
const [releaseNotesHash, setReleaseNotesHash] = useState('')
const [showReleaseNotes, setShowReleaseNotes] = useState(false)
useEffect(() => {
async function loadReleaseNotes() {
const filePath = Path.join(Script.directory, markdownFile)
const exists = await FileManager.exists(filePath)
if (!exists) return
const content = normalizeMarkdownContent(await FileManager.readAsString(filePath))
if (!content) return
const contentHash = hashString(content)
const lastSeenHash = Storage.get<string>(storageKey)
if (lastSeenHash === contentHash) return
setReleaseNotesContent(content)
setReleaseNotesHash(contentHash)
setShowReleaseNotes(true)
}
void loadReleaseNotes()
}, [])
function setReleaseNotesPresented(isPresented: boolean) {
if (!isPresented && markAsSeenOnDismiss && releaseNotesHash) {
Storage.set(storageKey, releaseNotesHash)
}
setShowReleaseNotes(isPresented)
}
return {
isPresented: showReleaseNotes,
onChanged: setReleaseNotesPresented,
content: (
<MarkdownReleaseNotesSheet
content={releaseNotesContent}
title={config.title}
theme={config.theme}
detents={config.detents}
/>
)
}
}