SettingPage.ets 14 KB

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