SettingPage.ets 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374
  1. import TitleBar from '../view/TitleBar'
  2. import { promptAction, router } from '@kit.ArkUI'
  3. import { CommonConstants } from '../common/constants/CommonConstants'
  4. import { AppUtil, PreferencesUtil } from '@pura/harmony-utils'
  5. import { CustomContentDialog } from '@kit.ArkUI'
  6. import ConfigurationConstant from '@ohos.app.ability.ConfigurationConstant';
  7. import common from '@ohos.app.ability.common';
  8. @Preview
  9. @Entry
  10. @Component
  11. export struct SettingPage {
  12. @State showApiDialog: boolean = false
  13. @State tempApiUrl: string = ''
  14. @State lyricApiUrl: string = PreferencesUtil.getStringSync('LRC_API', '')
  15. @State isBgPlayOpen: boolean = true //是否启用后台播放
  16. @State isAutoRatate: boolean = true //是否启用自动横竖屏
  17. @State isMemoryPlay: boolean = true //是否启用记忆播放
  18. @State isMediacodec: boolean = false //是否启用硬件解码
  19. @State isMusicMemoryPlay: boolean = false //是否启用记忆播放
  20. @State isMusicBGCover: boolean = true //播放背景随封面
  21. @State sortType: number = 4 //默认排序方式
  22. @State showCoverApiDialog: boolean = false
  23. @State tempCoverApiUrl: string = ''
  24. @State coverApiUrl: string = PreferencesUtil.getStringSync('COVER_API', '')
  25. @State apiDialogType: 'lyric' | 'cover' = 'lyric'
  26. static readonly SORT_TYPE: string = 'musicSortType';
  27. @StorageProp('currentColorMode') @Watch('onColorModeChange') currentMode: number = ConfigurationConstant.ColorMode.COLOR_MODE_LIGHT;
  28. @StorageLink('isDarkMode') isDarkMode: boolean = false // 是否启用深色模式
  29. static readonly IS_BGPLAY_OPEN: string = 'isBgPlayOpen';
  30. static readonly IS_AUTO_RATATE: string = 'isAutoRatate';
  31. static readonly iS_MEMORY_PLAY: string = 'isMemoryPlay';
  32. static readonly IS_MIDIACODEC_OPEN: string = 'isMediacodec';
  33. static readonly iS_MUSIC_MEMORY_PLAY: string = 'isMusicMemoryPlay';
  34. static readonly iS_MUSIC_BG_COVER: string = 'isMusicBGCover';
  35. static readonly iS_SAVE_PLAY_MODE: string = 'isSavePlayMode';
  36. static readonly IS_COVER_RECTANGLE: string = 'isCoverRectangle'; //封面圆形或者方形
  37. static readonly IS_DARK_MODE: string = 'isDarkMode'; // 深色模式设置
  38. @State titleBarModel: TitleBar.Model = new TitleBar.Model()
  39. .setTitleTextStyle(FontStyle.Normal)
  40. .setTitleBarStyle(TitleBar.BarStyle.TRANSPARENT)
  41. .setLeftIcon($r('app.media.left_back_white'))
  42. .setTitleName('通用设置')
  43. .setTitleFontColor(Color.White)
  44. .setTitleBarBackground($r('app.color.tab_item_bg'))
  45. .setLeftTitleBackground($r('app.color.tab_item_bg'))
  46. .setTitleBarBottomLineColor($r('app.color.tab_item_bg'))
  47. .setOnLeftClickListener(() => {
  48. router.back()
  49. })
  50. .setTitleBarMinHeight(44)
  51. .setTitleBarNormalPadding(0)
  52. @State verName: string = ''
  53. apiDialogController: CustomDialogController = new CustomDialogController({
  54. builder: CustomContentDialog({
  55. primaryTitle: this.apiDialogType === 'lyric' ? '修改歌词API地址' : '修改封面API地址',
  56. contentBuilder: () => {
  57. this.buildApiDialogContent();
  58. },
  59. buttons: [
  60. {
  61. value: '取消',
  62. action: () => {
  63. this.apiDialogController.close();
  64. }
  65. },
  66. {
  67. value: '保存',
  68. action: () => {
  69. if (this.apiDialogType === 'lyric') {
  70. this.lyricApiUrl = this.tempApiUrl
  71. PreferencesUtil.put('LRC_API', this.lyricApiUrl)
  72. this.getUIContext().getPromptAction().showToast({
  73. message: '保存成功,当前LRC_API:' + this.lyricApiUrl,
  74. duration: 2000,
  75. showMode: promptAction.ToastShowMode.TOP_MOST,
  76. bottom: 85
  77. })
  78. } else {
  79. this.coverApiUrl = this.tempApiUrl
  80. PreferencesUtil.put('COVER_API', this.coverApiUrl)
  81. this.getUIContext().getPromptAction().showToast({
  82. message: '保存成功,当前COVER_API:' + this.coverApiUrl,
  83. duration: 2000,
  84. showMode: promptAction.ToastShowMode.TOP_MOST,
  85. bottom: 85
  86. })
  87. }
  88. this.apiDialogController.close();
  89. }
  90. }
  91. ]
  92. }),
  93. autoCancel: true,
  94. alignment: DialogAlignment.Center
  95. })
  96. @Builder
  97. buildApiDialogContent() {
  98. Column() {
  99. TextInput({ text: this.tempApiUrl, placeholder: this.apiDialogType === 'lyric' ? '请输入歌词API地址' : '请输入封面API地址' })
  100. .onChange((val: string) => {
  101. this.tempApiUrl = val
  102. })
  103. .width('90%')
  104. .height(60)
  105. }
  106. .width('100%')
  107. }
  108. // 组件生命周期
  109. aboutToAppear() {
  110. this.isBgPlayOpen = PreferencesUtil.getBooleanSync(SettingPage.IS_BGPLAY_OPEN, true)
  111. this.isAutoRatate = PreferencesUtil.getBooleanSync(SettingPage.IS_AUTO_RATATE, true)
  112. this.isMemoryPlay = PreferencesUtil.getBooleanSync(SettingPage.iS_MEMORY_PLAY, true)
  113. this.isMediacodec = PreferencesUtil.getBooleanSync(SettingPage.IS_MIDIACODEC_OPEN, false)
  114. this.isMusicMemoryPlay = PreferencesUtil.getBooleanSync(SettingPage.iS_MUSIC_MEMORY_PLAY, false)
  115. this.isMusicBGCover = PreferencesUtil.getBooleanSync(SettingPage.iS_MUSIC_BG_COVER, true)
  116. // 从持久化存储中读取深色模式设置
  117. const savedDarkMode = PreferencesUtil.getBooleanSync(SettingPage.IS_DARK_MODE, false);
  118. this.isDarkMode = savedDarkMode;
  119. this.currentMode = savedDarkMode ? ConfigurationConstant.ColorMode.COLOR_MODE_DARK : ConfigurationConstant.ColorMode.COLOR_MODE_LIGHT;
  120. AppStorage.setOrCreate('currentColorMode', this.currentMode);
  121. AppStorage.setOrCreate('isDarkMode', this.isDarkMode);
  122. }
  123. // 监听颜色模式变化
  124. onColorModeChange(): void {
  125. this.isDarkMode = this.currentMode === ConfigurationConstant.ColorMode.COLOR_MODE_DARK;
  126. AppStorage.setOrCreate('isDarkMode', this.isDarkMode);
  127. // 保存深色模式设置到持久化存储
  128. PreferencesUtil.putSync(SettingPage.IS_DARK_MODE, this.isDarkMode);
  129. }
  130. // 切换深色模式
  131. async toggleDarkMode(checked: boolean) {
  132. try {
  133. const newMode = checked ? ConfigurationConstant.ColorMode.COLOR_MODE_DARK : ConfigurationConstant.ColorMode.COLOR_MODE_LIGHT;
  134. // 更新 AppStorage 中的颜色模式
  135. AppStorage.setOrCreate('currentColorMode', newMode);
  136. AppStorage.setOrCreate('isDarkMode', checked);
  137. // 保存深色模式设置到持久化存储
  138. PreferencesUtil.putSync(SettingPage.IS_DARK_MODE, checked);
  139. // 通知系统更新颜色模式
  140. const context = getContext(this) as common.UIAbilityContext;
  141. context.getApplicationContext().setColorMode(newMode);
  142. // 显示提示
  143. this.getUIContext().getPromptAction().showToast({
  144. message: checked ? '已切换到深色模式' : '已切换到浅色模式',
  145. duration: 2000,
  146. showMode: promptAction.ToastShowMode.TOP_MOST,
  147. bottom: 85
  148. });
  149. } catch (err) {
  150. console.error('Failed to update color mode:', err);
  151. }
  152. }
  153. // 组件生命周期
  154. aboutToDisappear() {
  155. // 无需处理apiDialogController
  156. }
  157. build() {
  158. Column() {
  159. TitleBar({ model: $titleBarModel })
  160. Scroll() {
  161. Column() {
  162. // 主题设置分组
  163. Column() {
  164. Row() {
  165. Text('主题设置')
  166. .margin({ left: 18, right: 20 })
  167. .fontSize(16)
  168. .fontColor(Color.Gray)
  169. .fontWeight(480)
  170. .layoutWeight(1)
  171. }
  172. .height(48)
  173. Line().width('100%').height(0.3).backgroundColor($r('app.color.index_tab_unselected_font_color'))
  174. // 深色模式
  175. Row() {
  176. Text('深色模式')
  177. .margin({ left: 18 })
  178. .fontSize(15)
  179. .fontColor(Color.Gray)
  180. .fontWeight(480)
  181. .layoutWeight(1)
  182. Toggle({ type: ToggleType.Switch, isOn: this.isDarkMode })
  183. .selectedColor($r('app.color.tab_item_bg'))
  184. .switchPointColor(Color.White)
  185. .margin({ right: 18 })
  186. .onChange((checked: boolean) => {
  187. this.toggleDarkMode(checked);
  188. })
  189. .width(50)
  190. .height(30);
  191. }
  192. .height(55)
  193. }
  194. .backgroundColor($r('app.color.settings_background_main'))
  195. .borderRadius(20)
  196. .margin({ left: 0, right: 0, top: 0, bottom: 10 })
  197. .padding(0)
  198. // 音频设置分组
  199. Column() {
  200. Row() {
  201. Text('音频设置')
  202. .margin({ left: 18, right: 20 })
  203. .fontSize(16)
  204. .fontColor(Color.Gray)
  205. .fontWeight(480)
  206. .layoutWeight(1)
  207. }
  208. .height(48)
  209. Line().width('100%').height(0.3).backgroundColor($r('app.color.index_tab_unselected_font_color'))
  210. // 记忆播放
  211. Row() {
  212. Text('记忆播放')
  213. .margin({ left: 18 })
  214. .fontSize(15)
  215. .fontColor(Color.Gray)
  216. .fontWeight(480)
  217. .layoutWeight(1)
  218. Toggle({ type: ToggleType.Switch, isOn: this.isMusicMemoryPlay })
  219. .selectedColor($r('app.color.tab_item_bg'))
  220. .switchPointColor(Color.White)
  221. .margin({ right: 18 })
  222. .onChange((checked: boolean) => {
  223. this.isMusicMemoryPlay = checked;
  224. PreferencesUtil.put(SettingPage.iS_MUSIC_MEMORY_PLAY, this.isMusicMemoryPlay)
  225. })
  226. .width(50)
  227. .height(30);
  228. }
  229. .height(55)
  230. Line().width('100%').height(0.3).backgroundColor($r('app.color.index_tab_unselected_font_color'))
  231. // 默认排序模式
  232. Row() {
  233. Text('默认排序模式')
  234. .margin({ left: 18 })
  235. .fontSize(15)
  236. .fontColor(Color.Gray)
  237. .fontWeight(480)
  238. .layoutWeight(1)
  239. Select([
  240. { value: CommonConstants.SORT_ARRAY[0] },
  241. { value: CommonConstants.SORT_ARRAY[1] },
  242. { value: CommonConstants.SORT_ARRAY[2] },
  243. { value: CommonConstants.SORT_ARRAY[3] },
  244. { value: CommonConstants.SORT_ARRAY[4] },
  245. { value: CommonConstants.SORT_ARRAY[5] },
  246. { value: CommonConstants.SORT_ARRAY[6] },
  247. { value: CommonConstants.SORT_ARRAY[7] }])
  248. .font({ size: 15, weight: FontWeight.Medium })
  249. .fontColor(Color.Gray)
  250. .margin({ right: 18 })
  251. .selected(this.sortType)
  252. .value(CommonConstants.SORT_ARRAY[this.sortType])
  253. .onSelect(async (_index: number, text?: string | undefined) => {
  254. this.sortType = _index
  255. PreferencesUtil.put(SettingPage.SORT_TYPE, this.sortType)
  256. })
  257. }
  258. .height(55)
  259. Line().width('100%').height(0.3).backgroundColor($r('app.color.index_tab_unselected_font_color'))
  260. // 播放背景随音乐封面
  261. Row() {
  262. Text('播放背景随音乐封面')
  263. .margin({ left: 18 })
  264. .fontSize(15)
  265. .fontColor(Color.Gray)
  266. .fontWeight(480)
  267. .layoutWeight(1)
  268. Toggle({ type: ToggleType.Switch, isOn: this.isMusicBGCover })
  269. .selectedColor($r('app.color.tab_item_bg'))
  270. .switchPointColor(Color.White)
  271. .margin({ right: 18 })
  272. .onChange((checked: boolean) => {
  273. this.isMusicBGCover = checked;
  274. PreferencesUtil.put(SettingPage.iS_MUSIC_BG_COVER, this.isMusicBGCover)
  275. })
  276. .width(50)
  277. .height(30);
  278. }
  279. .height(55)
  280. }
  281. .backgroundColor($r('app.color.settings_background_main'))
  282. .borderRadius(20)
  283. .margin({ left: 0, right: 0, top: 0, bottom: 10 })
  284. .padding(0)
  285. // API设置分组
  286. Column() {
  287. Row() {
  288. Text('API设置')
  289. .margin({ left: 18, right: 20 })
  290. .fontSize(16)
  291. .fontColor(Color.Gray)
  292. .fontWeight(480)
  293. .layoutWeight(1)
  294. }
  295. .height(48)
  296. Line().width('100%').height(0.3).backgroundColor($r('app.color.index_tab_unselected_font_color'))
  297. // 歌词API
  298. Row() {
  299. Text('歌词:')
  300. .margin({ left: 38, right: 6 })
  301. .fontSize(15)
  302. .fontColor(Color.Gray)
  303. Text(this.lyricApiUrl)
  304. .margin({ right: 10 })
  305. .fontSize(15)
  306. .fontColor(Color.Gray)
  307. .layoutWeight(1)
  308. Image($r('app.media.edit'))
  309. .width(28)
  310. .height(28)
  311. .margin({ right: 18 })
  312. .onClick(() => {
  313. this.apiDialogType = 'lyric'
  314. this.tempApiUrl = this.lyricApiUrl
  315. this.apiDialogController.open()
  316. })
  317. }
  318. .height(55)
  319. // 封面API
  320. Row() {
  321. Text('封面:')
  322. .margin({ left: 38, right: 6 })
  323. .fontSize(15)
  324. .fontColor(Color.Gray)
  325. Text(this.coverApiUrl)
  326. .margin({ right: 10 })
  327. .fontSize(15)
  328. .fontColor(Color.Gray)
  329. .layoutWeight(1)
  330. Image($r('app.media.edit'))
  331. .width(28)
  332. .height(28)
  333. .margin({ right: 18 })
  334. .onClick(() => {
  335. this.apiDialogType = 'cover'
  336. this.tempApiUrl = this.coverApiUrl
  337. this.apiDialogController.open()
  338. })
  339. }
  340. .height(55)
  341. }
  342. .backgroundColor($r('app.color.settings_background_main'))
  343. .borderRadius(20)
  344. .margin({ left: 0, right: 0, top: 0, bottom: 10 })
  345. .padding(0)
  346. }
  347. .margin({ left: 25, right: 25, top: 2, bottom: 30 })
  348. .justifyContent(FlexAlign.Start)
  349. }
  350. .scrollBar(BarState.Auto)
  351. .height('100%')
  352. .width('100%')
  353. .margin({bottom:18})
  354. }
  355. .backgroundColor($r('app.color.settings_background'))
  356. .height('100%')
  357. .expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.BOTTOM])
  358. }
  359. }