diff --git a/src/components/AppRoot.tsx b/src/components/AppRoot.tsx
index e205487..a457092 100644
--- a/src/components/AppRoot.tsx
+++ b/src/components/AppRoot.tsx
@@ -1,5 +1,5 @@
import { useEffect } from 'react';
-import { MdSettings, MdHome } from 'react-icons/md';
+import { MdSettings, MdHome, MdQuestionAnswer } from 'react-icons/md';
import { ChakraProvider, Tabs, TabList, TabPanels, Tab, TabPanel, Icon, chakra } from '@chakra-ui/react';
import { MainTab } from '~/tabs/MainTab';
@@ -10,6 +10,7 @@ import { theme } from '~/theme';
import { persistSettings } from '~/features/settings/persistSettings';
import { setupStore } from '~/store';
import { Footer } from '~/components/Footer';
+import { FaqTab } from '~/tabs/FaqTab';
// Private to this file only.
const store = setupStore();
@@ -30,6 +31,10 @@ export function AppRoot() {
设置
+
+
+ 问答
+
@@ -39,6 +44,9 @@ export function AppRoot() {
+
+
+
diff --git a/src/components/HelpText/Header3.tsx b/src/components/HelpText/Header3.tsx
new file mode 100644
index 0000000..67e1caf
--- /dev/null
+++ b/src/components/HelpText/Header3.tsx
@@ -0,0 +1,26 @@
+import { Heading } from '@chakra-ui/react';
+import React from 'react';
+
+export interface Header3Props {
+ children: React.ReactNode;
+ id?: string;
+ className?: string;
+}
+
+export function Header3({ children, className, id }: Header3Props) {
+ return (
+
+ {children}
+
+ );
+}
diff --git a/src/components/HelpText/Header4.tsx b/src/components/HelpText/Header4.tsx
new file mode 100644
index 0000000..f2b8deb
--- /dev/null
+++ b/src/components/HelpText/Header4.tsx
@@ -0,0 +1,16 @@
+import { Heading } from '@chakra-ui/react';
+import React from 'react';
+
+export interface Header4Props {
+ children: React.ReactNode;
+ id?: string;
+ className?: string;
+}
+
+export function Header4({ children, className, id }: Header4Props) {
+ return (
+
+ {children}
+
+ );
+}
diff --git a/src/components/HelpText/HiWord.tsx b/src/components/HelpText/HiWord.tsx
new file mode 100644
index 0000000..54bee0f
--- /dev/null
+++ b/src/components/HelpText/HiWord.tsx
@@ -0,0 +1,9 @@
+import { Mark } from '@chakra-ui/react';
+
+export function HiWord({ children }: { children: React.ReactNode }) {
+ return (
+
+ {children}
+
+ );
+}
diff --git a/src/components/HelpText/VQuote.tsx b/src/components/HelpText/VQuote.tsx
new file mode 100644
index 0000000..274637c
--- /dev/null
+++ b/src/components/HelpText/VQuote.tsx
@@ -0,0 +1,13 @@
+import { chakra, css } from '@chakra-ui/react';
+
+const cssUnselectable = css({ pointerEvents: 'none', userSelect: 'none' });
+
+export function VQuote({ children }: { children: React.ReactNode }) {
+ return (
+ <>
+ 「
+ {children}
+ 」
+ >
+ );
+}
diff --git a/src/components/ProjectIssue.tsx b/src/components/ProjectIssue.tsx
new file mode 100644
index 0000000..e56055a
--- /dev/null
+++ b/src/components/ProjectIssue.tsx
@@ -0,0 +1,17 @@
+export interface ProjectIssueProps {
+ id: number | string;
+ title?: string;
+}
+
+export function ProjectIssue({ id, title }: ProjectIssueProps) {
+ return (
+
+ {`#${id}`}
+ {title && ` - ${title}`}
+
+ );
+}
diff --git a/src/faq/KuwoFAQ.tsx b/src/faq/KuwoFAQ.tsx
new file mode 100644
index 0000000..c955de1
--- /dev/null
+++ b/src/faq/KuwoFAQ.tsx
@@ -0,0 +1,50 @@
+import { Alert, AlertIcon, Container, List, ListItem, Text, VStack, chakra } from '@chakra-ui/react';
+import { Header4 } from '~/components/HelpText/Header4';
+import { VQuote } from '~/components/HelpText/VQuote';
+import { SegmentTryOfficialPlayer } from './SegmentTryOfficialPlayer';
+import { HiWord } from '~/components/HelpText/HiWord';
+import { KWMv2AllInstructions } from '~/features/settings/panels/KWMv2/KWMv2AllInstructions';
+import { SegmentKeyImportInstructions } from './SegmentKeyImportInstructions';
+
+export function KuwoFAQ() {
+ return (
+ <>
+ 解锁失败
+
+
+
+
+
+
+ 2、检查您的平台
+
+
+ 日前,仅手机客户端下载的
+
+ 至臻全景声
+
+ 及
+
+ 至臻母带
+
+ {'音质的音乐文件采用新版加密。'}
+
+ 其他音质目前不需要提取密钥。
+ PC平台暂未推出使用新版加密的音质。
+
+
+
+
+
+ Android 用户提取密钥需要 root 权限,或注入文件提供器。
+ 请注意:项目组不提倡使用第三方修改版应用亦不会提供,使用前请自行评估风险。
+
+
+
+
+ } />
+
+
+ >
+ );
+}
diff --git a/src/faq/OtherFAQ.tsx b/src/faq/OtherFAQ.tsx
new file mode 100644
index 0000000..f044698
--- /dev/null
+++ b/src/faq/OtherFAQ.tsx
@@ -0,0 +1,28 @@
+import { ExternalLinkIcon } from '@chakra-ui/icons';
+import { Link, Text } from '@chakra-ui/react';
+import { Header4 } from '~/components/HelpText/Header4';
+import { ProjectIssue } from '~/components/ProjectIssue';
+
+export function OtherFAQ() {
+ return (
+ <>
+ 解密后没有封面等信息
+ 该项目进行解密处理。如果加密前的资源没有内嵌元信息或封面,解密的文件也没有。
+ 请使用第三方工具进行编辑或管理元信息。
+ 如何批量下载
+
+ 暂时没有实现,不过你可以在 以及{' '}
+ 追踪该问题。
+
+ 有更多问题?
+
+ {'欢迎进入 '}
+
+ Telegram “音乐解锁-交流” 交流群
+
+
+ {' 一起探讨。'}
+
+ >
+ );
+}
diff --git a/src/faq/QQMusicFAQ.tsx b/src/faq/QQMusicFAQ.tsx
new file mode 100644
index 0000000..33d3bc8
--- /dev/null
+++ b/src/faq/QQMusicFAQ.tsx
@@ -0,0 +1,40 @@
+import { Alert, AlertIcon, Container, List, ListItem, Text, chakra } from '@chakra-ui/react';
+import { Header4 } from '~/components/HelpText/Header4';
+import { SegmentTryOfficialPlayer } from './SegmentTryOfficialPlayer';
+import { QMCv2AllInstructions } from '~/features/settings/panels/QMCv2/QMCv2AllInstructions';
+import { SegmentKeyImportInstructions } from './SegmentKeyImportInstructions';
+
+export function QQMusicFAQ() {
+ return (
+ <>
+ 解锁失败
+
+
+
+
+
+
+ 2、检查您的平台
+
+ 日前,仅Windows客户端下载的歌曲无需密钥,其余平台的官方正式版本均需要提取密钥。
+
+
+
+
+ iOS用户提取歌曲困难,建议换用电脑操作;Android用户提取密钥需要root,也建议用电脑操作。
+
+
+
+
+
+
+ 重复下载同一首的歌曲不重复扣下载配额,但是同一首歌的两个版本会重复扣下载配额,请仔细分辨。
+
+
+
+ } />
+
+
+ >
+ );
+}
diff --git a/src/faq/SegmentAddKeyDropdown.tsx b/src/faq/SegmentAddKeyDropdown.tsx
new file mode 100644
index 0000000..c529e82
--- /dev/null
+++ b/src/faq/SegmentAddKeyDropdown.tsx
@@ -0,0 +1,25 @@
+import { Flex, IconButton } from '@chakra-ui/react';
+import { MdExpandMore } from 'react-icons/md';
+import { HiWord } from '~/components/HelpText/HiWord';
+import { VQuote } from '~/components/HelpText/VQuote';
+
+export function SegmentAddKeyDropdown() {
+ return (
+
+ 按下添加一条密钥按钮
+ 右侧的
+ }
+ ml="2"
+ borderTopLeftRadius={0}
+ borderBottomLeftRadius={0}
+ isDisabled
+ css={{ ':disabled': { opacity: 1 } }}
+ aria-label="示例按钮"
+ />
+
+ );
+}
diff --git a/src/faq/SegmentKeyImportInstructions.tsx b/src/faq/SegmentKeyImportInstructions.tsx
new file mode 100644
index 0000000..8d35f47
--- /dev/null
+++ b/src/faq/SegmentKeyImportInstructions.tsx
@@ -0,0 +1,44 @@
+import { Flex, Icon, ListItem, OrderedList, Tabs, Text } from '@chakra-ui/react';
+import { SegmentTopNavSettings } from './SegmentTopNavSettings';
+import { VQuote } from '~/components/HelpText/VQuote';
+import { SegmentAddKeyDropdown } from './SegmentAddKeyDropdown';
+import React from 'react';
+import { MdFileUpload } from 'react-icons/md';
+
+export interface SegmentKeyImportInstructionsProps {
+ clientInstructions: React.ReactNode;
+ tab: string;
+}
+
+export function SegmentKeyImportInstructions({ clientInstructions, tab }: SegmentKeyImportInstructionsProps) {
+ return (
+ <>
+ 导入密钥可以参考下面的步骤:
+
+
+
+
+
+ 设定区域选择{tab}
+
+
+
+
+
+
+ {'选择 '}
+
+ 从文件导入密钥…
+
+
+
+
+ 选择你的客户端平台来查看密钥提取说明:
+
+ {clientInstructions}
+
+
+
+ >
+ );
+}
diff --git a/src/faq/SegmentTopNavSettings.tsx b/src/faq/SegmentTopNavSettings.tsx
new file mode 100644
index 0000000..918ab6e
--- /dev/null
+++ b/src/faq/SegmentTopNavSettings.tsx
@@ -0,0 +1,9 @@
+import { VQuote } from '~/components/HelpText/VQuote';
+
+export function SegmentTopNavSettings() {
+ return (
+ <>
+ 点击顶部的设置
+ >
+ );
+}
diff --git a/src/faq/SegmentTryOfficialPlayer.tsx b/src/faq/SegmentTryOfficialPlayer.tsx
new file mode 100644
index 0000000..3142621
--- /dev/null
+++ b/src/faq/SegmentTryOfficialPlayer.tsx
@@ -0,0 +1,12 @@
+import { Text, chakra } from '@chakra-ui/react';
+
+export function SegmentTryOfficialPlayer() {
+ return (
+ <>
+
+ 1、请检查您的文件
+
+ 尝试用下载音乐的设备播放一次看看,如果官方客户端都无法播放,那解锁肯定会失败哦。
+ >
+ );
+}
diff --git a/src/features/settings/panels/KWMv2/KWMv2AllInstructions.tsx b/src/features/settings/panels/KWMv2/KWMv2AllInstructions.tsx
new file mode 100644
index 0000000..144e604
--- /dev/null
+++ b/src/features/settings/panels/KWMv2/KWMv2AllInstructions.tsx
@@ -0,0 +1,25 @@
+import { Tab, TabList, TabPanel, TabPanels } from '@chakra-ui/react';
+import { AndroidADBPullInstruction } from '~/components/AndroidADBPullInstruction/AndroidADBPullInstruction';
+import { InstructionsPC } from './InstructionsPC';
+
+export function KWMv2AllInstructions() {
+ return (
+ <>
+
+ 安卓
+ Windows
+
+
+
+
+
+
+
+
+
+ >
+ );
+}
diff --git a/src/features/settings/panels/PanelKWMv2Key.tsx b/src/features/settings/panels/PanelKWMv2Key.tsx
index ba6d4e7..ca97311 100644
--- a/src/features/settings/panels/PanelKWMv2Key.tsx
+++ b/src/features/settings/panels/PanelKWMv2Key.tsx
@@ -14,10 +14,6 @@ import {
MenuDivider,
MenuItem,
MenuList,
- Tab,
- TabList,
- TabPanel,
- TabPanels,
Text,
useToast,
} from '@chakra-ui/react';
@@ -32,8 +28,7 @@ import { kwm2AddKey, kwm2ClearKeys, kwm2ImportKeys } from '../settingsSlice';
import { selectStagingKWMv2Keys } from '../settingsSelector';
import { KWMv2EKeyItem } from './KWMv2/KWMv2EKeyItem';
import type { StagingKWMv2Key } from '../keyFormats';
-import { InstructionsPC } from './KWMv2/InstructionsPC';
-import { AndroidADBPullInstruction } from '~/components/AndroidADBPullInstruction/AndroidADBPullInstruction';
+import { KWMv2AllInstructions } from './KWMv2/KWMv2AllInstructions';
export function PanelKWMv2Key() {
const toast = useToast();
@@ -120,21 +115,7 @@ export function PanelKWMv2Key() {
onClose={() => setShowImportModal(false)}
onImport={handleSecretImport}
>
-
- 安卓
- Windows
-
-
-
-
-
-
-
-
-
+
);
diff --git a/src/features/settings/panels/PanelQMCv2Key.tsx b/src/features/settings/panels/PanelQMCv2Key.tsx
index c309b2c..802eac7 100644
--- a/src/features/settings/panels/PanelQMCv2Key.tsx
+++ b/src/features/settings/panels/PanelQMCv2Key.tsx
@@ -14,10 +14,6 @@ import {
MenuDivider,
MenuItem,
MenuList,
- Tab,
- TabList,
- TabPanel,
- TabPanels,
Text,
Tooltip,
useToast,
@@ -34,10 +30,7 @@ import { StagingQMCv2Key } from '../keyFormats';
import { DatabaseKeyExtractor } from '~/util/DatabaseKeyExtractor';
import { MMKVParser } from '~/util/MMKVParser';
import { getFileName } from '~/util/pathHelper';
-import { InstructionsIOS } from './QMCv2/InstructionsIOS';
-import { InstructionsMac } from './QMCv2/InstructionsMac';
-import { InstructionsPC } from './QMCv2/InstructionsPC';
-import { AndroidADBPullInstruction } from '~/components/AndroidADBPullInstruction/AndroidADBPullInstruction';
+import { QMCv2AllInstructions } from './QMCv2/QMCv2AllInstructions';
export function PanelQMCv2Key() {
const toast = useToast();
@@ -171,26 +164,7 @@ export function PanelQMCv2Key() {
onClose={() => setShowImportModal(false)}
onImport={handleSecretImport}
>
-
- 安卓
- iOS
- Mac
- Windows
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
);
diff --git a/src/features/settings/panels/QMCv2/QMCv2AllInstructions.tsx b/src/features/settings/panels/QMCv2/QMCv2AllInstructions.tsx
new file mode 100644
index 0000000..3cfd9f5
--- /dev/null
+++ b/src/features/settings/panels/QMCv2/QMCv2AllInstructions.tsx
@@ -0,0 +1,32 @@
+import { Tab, TabList, TabPanel, TabPanels } from '@chakra-ui/react';
+import { AndroidADBPullInstruction } from '~/components/AndroidADBPullInstruction/AndroidADBPullInstruction';
+import { InstructionsIOS } from './InstructionsIOS';
+import { InstructionsMac } from './InstructionsMac';
+import { InstructionsPC } from './InstructionsPC';
+
+export function QMCv2AllInstructions() {
+ return (
+ <>
+
+ 安卓
+ iOS
+ Mac
+ Windows
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ >
+ );
+}
diff --git a/src/tabs/FaqTab.tsx b/src/tabs/FaqTab.tsx
new file mode 100644
index 0000000..2ac9c3a
--- /dev/null
+++ b/src/tabs/FaqTab.tsx
@@ -0,0 +1,21 @@
+import { Center, Container, Heading } from '@chakra-ui/react';
+import { Header3 } from '~/components/HelpText/Header3';
+import { KuwoFAQ } from '~/faq/KuwoFAQ';
+import { OtherFAQ } from '~/faq/OtherFAQ';
+import { QQMusicFAQ } from '~/faq/QQMusicFAQ';
+
+export function FaqTab() {
+ return (
+
+
+ 常见问题解答
+
+ QQ 音乐
+
+ 酷我音乐
+
+ 其它问题
+
+
+ );
+}