SettingPage.ets 121 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165
  1. import TitleBar from '../view/TitleBar'
  2. import { promptAction, router } from '@kit.ArkUI'
  3. import { CommonConstants } from '../common/constants/CommonConstants'
  4. import { EventConstants } from '../common/constants/EventConstants'
  5. import { AppUtil, DeviceUtil, DisplayUtil, FileUtil, LogUtil, MD5, PreferencesUtil, ToastUtil } from '@pura/harmony-utils'
  6. import { CustomContentDialog } from '@kit.ArkUI'
  7. import ConfigurationConstant from '@ohos.app.ability.ConfigurationConstant';
  8. import common from '@ohos.app.ability.common';
  9. import { photoAccessHelper } from '@kit.MediaLibraryKit'
  10. import { fileIo, fileUri } from '@kit.CoreFileKit'
  11. import { BusinessError, emitter } from '@kit.BasicServicesKit'
  12. import { BreakpointTypeEnum } from '../common/util/BreakpointSystem'
  13. import { Utility } from '../common/util/Utility'
  14. import { HSBColorPicker } from '@keke/color-picker'
  15. import { DialogHelper } from '@pura/harmony-dialog'
  16. import { bundleManager } from '@kit.AbilityKit'
  17. import { hilog } from '@kit.PerformanceAnalysisKit'
  18. import { SelectItem } from './SelectItem'
  19. import { FastForwardSecondInterface } from './FastForwardSecondInterface'
  20. import { ButtonFancyModifier, ShadowModifier, SymbolGlyphFancyModifier } from '../common/util/AttributeModifierUtil'
  21. import { CustomizeICON, Icon } from '../view/CustomizeICON'
  22. import { appInfoManager } from '@kit.StoreKit'
  23. import { clearWebDavCacheByAccount, clearWebDavCaches } from '../common/network/RemoteSongCache';
  24. import { RemoteDriveManager } from '../common/util/RemoteDriveManager';
  25. import { LogCollector } from '../common/util/LogCollector';
  26. import { Uploader, UploadConfig } from '../common/network/Uploader';
  27. import { UpTokenUtil } from '../common/util/UpTokenUtil';
  28. import { ServerLogUtil } from '../common/util/ServerLogUtil';
  29. import { audio } from '@kit.AudioKit'
  30. @Preview
  31. // @Entry
  32. @Component
  33. export struct SettingPage {
  34. @State autoHideTitle: boolean = true //滚动自动隐藏标题栏
  35. @State isNoJumpToHome: boolean = false //网盘播放不跳转首页
  36. @State iconCurrentID: string = 'default';//图标的id
  37. @State iconArray: Array<Icon> = []
  38. @State webdavUploadDuplicateAction: string = 'skip' // WebDAV上传重复文件处理方式
  39. @State webdavUploadAutoClear: boolean = false // WebDAV上传完成后自动清理队列
  40. @State webdavUploadAllowMobile: boolean = false // WebDAV是否允许移动网络上传
  41. @State webdavUploadRetryCount: number = 3 // WebDAV上传失败自动重试次数
  42. @StorageProp('isLandscape') isLandscape: boolean = false;
  43. @State isCustomizeICONSheet: boolean = false //自定义背景界面
  44. @StorageProp('topSafeHeight') topSafeHeight: number = 0;
  45. @State isCopyFileToDownLoad: boolean = false
  46. static readonly IS_COPYFILE_TO_DOWNLOAD: string = 'isCopyFileToDownLoad';
  47. static readonly WEBDAV_UPLOAD_DUPLICATE_ACTION: string = 'webdavUploadDuplicateAction';
  48. static readonly WEBDAV_UPLOAD_AUTO_CLEAR: string = 'webdavUploadAutoClear';
  49. static readonly WEBDAV_UPLOAD_ALLOW_MOBILE: string = 'webdavUploadAllowMobile';
  50. static readonly WEBDAV_UPLOAD_RETRY_COUNT: string = 'webdavUploadRetryCount';
  51. @State fastForwardSeconds: string = '10'
  52. @State isShowBackFast: boolean = true//快进快退按钮
  53. @State isClearingCache: boolean = false
  54. @Consume isShowDrawer: boolean;
  55. @Consume offsetX: number;
  56. @Consume mType: number;
  57. static readonly THEME_MODE: string = 'themeMode';
  58. static readonly SORT_TYPE: string = 'musicSortType';
  59. static readonly IS_BGPLAY_OPEN: string = 'isBgPlayOpen';
  60. static readonly IS_AUTO_RATATE: string = 'isAutoRatate';
  61. static readonly iS_MEMORY_PLAY: string = 'isMemoryPlay';
  62. static readonly IS_MIDIACODEC_OPEN: string = 'isMediacodec';
  63. static readonly iS_MUSIC_MEMORY_PLAY: string = 'isMusicMemoryPlay';
  64. static readonly iS_MUSIC_BG_COVER: string = 'isMusicBGCover';
  65. static readonly iS_SAVE_PLAY_MODE: string = 'isSavePlayMode';
  66. static readonly IS_COVER_RECTANGLE: string = 'isCoverRectangle'; //封面圆形或者方形
  67. static readonly IS_SHOW_SIMI: string = 'isShowSimi';
  68. static readonly IS_SHOW_FAV: string = 'isShowFAV';
  69. static readonly IS_SHOW_HISTORY: string = 'isShowHistory';
  70. static readonly IS_CUSTOMIZE_BG: string = 'is_customize_bg';
  71. static readonly IS_GRID_MUSIC: string = 'is_grid_music';
  72. static readonly IS_CUSTOMIZE_BG_PATH: string = 'is_customize_bg_path';
  73. static readonly IS_SCROLL_HIDE: string = 'isAutoScrollHide';
  74. static readonly IS_SAMETIME_PLAY: string = 'isSameTimePlay';
  75. static readonly CUSTOMIZE_BG_BLUR: string = 'customize_bg_blur';
  76. static readonly BG_BRIGHTNESS: string = 'bg_brightness';
  77. static readonly IS_SHOW_ALLBAR: string = 'IS_SHOW_ALLBAR';
  78. static readonly IS_SHOW_TITLTBAR: string = 'IS_SHOW_TITLTBAR';
  79. static readonly IS_SHOW_PLAYPAGE_BACK: string = 'IS_SHOW_PLAYPAGE_BACK';
  80. static readonly IS_SHOW_SLLYRIC: string = 'IS_SHOW_SLLYRIC';
  81. static readonly IS_CIRCLE_BTN: string = 'isCircleBtn';
  82. static readonly IS_COVER_TOP: string = 'IS_COVER_TOP';
  83. static readonly IS_SHOW_HEADER: string = 'IS_SHOW_HEADER';
  84. static readonly IS_COVER_TOP_BIG: string = 'IS_COVER_TOP_BIG';
  85. static readonly LOG_UPLOAD_ENABLED: string = 'logUploadEnabled';
  86. static readonly MEITU_UPLOAD_TOKEN_KEY: string = 'meituUploadToken';
  87. static readonly MEITU_UPLOAD_DOMAIN_KEY: string = 'meituUploadDomain';
  88. static readonly MEITU_AK: string = '7msMIyQ9xOjOwqO9JSPl';
  89. static readonly MEITU_SK: string = 'JU8kLByQ1U1Zgkfni95IC9ttvfv5NLC3qO642R1Z';
  90. static readonly MEITU_BUCKET: string = 'makeup-magic';
  91. static readonly MEITU_DOMAIN: string = 'https://makeup-magic.zone1.meitudata.com';
  92. public static THEME_COLOR_KEY: string = 'THEME_COLOR';
  93. public static TWO_FINGER_TYPE: string = 'twoFingerType';
  94. public static LONG_PRESS_SPEED: string = 'longPressSpeed';
  95. public static IS_PLAYLIST_BG_GRASS: string = 'isPlayListBgGrass';
  96. static readonly IS_SWIPE: string = 'isSwipe'
  97. static readonly IS_AUTO_HIDE_PROGRESS: string = 'IS_AUTO_HIDE_PROGRESS';
  98. public static OPEN_SKIPSONG_ANIMATE: string = 'openSkipSongAnimate';
  99. @State autoParseMusicName: boolean = false
  100. @State idDefaultMediaKu: boolean = false
  101. private fastForwardSecond: FastForwardSecondInterface[] = [
  102. { label: '5秒', value: '5' },
  103. { label: '10秒', value: '10' },
  104. { label: '15秒', value: '15' },
  105. { label: '20秒', value: '20' },
  106. { label: '30秒', value: '30' },
  107. { label: '60秒', value: '60' },
  108. { label: '90秒', value: '90' },
  109. ];
  110. public static THEME_COLOR_LIST: Array<ThemeColorItem> = [
  111. { name: '玫瑰粉', color: '#FF4081', isVip: false },
  112. { name: '经典蓝', color: '#0A59F7', isVip: false },
  113. { name: '活力黄', color: '#FFC107', isVip: true },
  114. { name: '枫叶红', color: '#F44336', isVip: true },
  115. { name: '幻影紫', color: '#9C27B0', isVip: true },
  116. { name: '翡翠绿', color: '#64BB5C', isVip: true },
  117. { name: '竹青蓝', color: '#00BCD4', isVip: true },
  118. { name: '深空灰', color: '#607D8B', isVip: true },
  119. { name: '橙霞橙', color: '#FF9800', isVip: true },
  120. { name: '湖水蓝', color: '#00BFFF', isVip: true },
  121. { name: '柠檬绿', color: '#C6FF00', isVip: true },
  122. { name: '樱花粉', color: '#FF69B4', isVip: true },
  123. { name: '暮夜蓝', color: '#283593', isVip: true },
  124. { name: '薄荷青', color: '#1DE9B6', isVip: true },
  125. { name: '银沙灰', color: '#B0BEC5', isVip: true },
  126. { name: '自定义', color: '#ffecec', isVip: true }
  127. ];
  128. static readonly iS_START_AUTO_PLAY: string = 'isStartAutoPlay';
  129. static readonly iS_MEMORY_LAST_PLAY: string = 'isMemoryLastPlay';
  130. @State showApiDialog: boolean = false
  131. @State tempApiUrl: string = ''
  132. @State lyricApiUrl: string = PreferencesUtil.getStringSync('LRC_API', '')
  133. @State isBgPlayOpen: boolean = true //是否启用后台播放
  134. @State isAutoRatate: boolean = true //是否启用自动横竖屏
  135. @State isMemoryPlay: boolean = true //是否启用记忆播放
  136. @State isMediacodec: boolean = false //是否启用硬件解码
  137. @State isMusicMemoryPlay: boolean = false //是否启用记忆播放
  138. @State isMusicBGCover: boolean = true //播放背景随封面
  139. @State sortType: number = 4 //默认排序方式
  140. @State isStartAutoPlay: boolean = false //启动后自动播放
  141. @State isMemoryLastPlay: boolean = false //是否启用应用退出记忆最后一首的播放进度
  142. @State isShowSimi: boolean = false //是否显示私密音频
  143. @State isShowFAV: boolean = true //是否显示我的收藏
  144. @State isShowHistory: boolean = true //是否显示最近播放
  145. @State isShowPlayPageBack: boolean = false //是否显示播放页返回键
  146. @State isShowPrecious: boolean = false //播控条显示上一首按钮
  147. @State isShowSingleLineLyric: boolean = false //是否显示单行歌词
  148. @State isLogUploadEnabled: boolean = false //日志上传开关
  149. @State isClearingLogs: boolean = false //是否正在清除日志
  150. @State isShowHeader: boolean = true
  151. @State isCustomizeBg: boolean = false //自定义背景界面
  152. @State isCustomizeBgSheet: boolean = false //自定义背景界面
  153. @State isShowTitleBar: boolean = true //是否显示分类导航条
  154. @State isShowAllBar: boolean = true //是否显示播放全部条
  155. @State longPressSpeed: number = 3 //长按默认倍数
  156. @State blurValue: number = 0 //背景模糊
  157. @State bgBrightness: number = 0 //背景亮度
  158. @State isGridMusic: boolean = true //是否网格布局
  159. @State isCircleBtn: boolean = false //是否圆形播放按钮
  160. @State twoFingerType: number = 3 //双指放大瘦小Grid或list的大小
  161. @State isScrollHide: boolean = false //是否滚动隐藏
  162. @State isSameTimePlay: boolean = false //是否和其他app同时播放
  163. @State isCoverRectangle: boolean = false
  164. @State isSavePlayMode: boolean = true
  165. @State volumeSmall: boolean = false
  166. @State isCoverTop: boolean = true
  167. @State isCoverTopBig: boolean = false//顶部大封面部分手机显示会和播放控制页重叠
  168. @State isSwipe: boolean = false //listItem的左滑开关
  169. @State isPlayListBgGrass: boolean = true//是否播放列表玻璃透明效果
  170. @State is_auto_hide_progress: boolean = false
  171. @State openSkipSongAnimate: boolean = true//切歌动画效果
  172. @State isShowFileName: boolean = false//切歌动画效果
  173. @State isLongNameRoLL: boolean = true//长歌名滚动
  174. @State customizeBgPath: string | undefined = '';
  175. context = getContext(this);
  176. @State showCoverApiDialog: boolean = false
  177. @State tempCoverApiUrl: string = ''
  178. @State coverApiUrl: string = PreferencesUtil.getStringSync('COVER_API', '')
  179. @State apiDialogType: 'lyric' | 'cover' = 'lyric'
  180. @State themeMode: number = 0 // 0: 跟随系统, 1: 浅色, 2: 深色
  181. @StorageProp('currentColorMode') @Watch('onColorModeChange') currentMode: number =
  182. ConfigurationConstant.ColorMode.COLOR_MODE_LIGHT;
  183. @StorageLink('isDarkMode') isDarkMode: boolean = false // 是否启用深色模式
  184. /** 当前断点类型(如大屏/小屏) */
  185. @StorageProp('currentBreakpoint') currentBreakpoint: string = BreakpointTypeEnum.MD;
  186. @State verName: string = ''
  187. @StorageProp('themeColor') themeColor: string =
  188. PreferencesUtil.getStringSync('THEME_COLOR', CommonConstants.DEFAULT_THEME_COLOR);
  189. @State showColorPicker: boolean = false
  190. @State customColor: string = PreferencesUtil.getStringSync('THEME_COLOR', CommonConstants.DEFAULT_THEME_COLOR);
  191. @State isThemeSheet: boolean = false // 主题设置弹窗显示状态
  192. @State colorRows: Array<Array<ThemeColorItem>> = chunkArray(SettingPage.THEME_COLOR_LIST, 2);
  193. @State colorGroup: string = "group"
  194. @StorageProp('topRectHeight') topRectHeight: number = 0;
  195. apiDialogController: CustomDialogController = new CustomDialogController({
  196. builder: CustomContentDialog({
  197. primaryTitle: this.apiDialogType === 'lyric' ? '修改歌词API地址' : '修改封面API地址',
  198. contentBuilder: () => {
  199. this.buildApiDialogContent();
  200. },
  201. buttons: [
  202. {
  203. value: '取消',
  204. action: () => {
  205. this.apiDialogController.close();
  206. }
  207. },
  208. {
  209. value: '保存',
  210. action: () => {
  211. if (this.apiDialogType === 'lyric') {
  212. this.lyricApiUrl = this.tempApiUrl.trim()
  213. PreferencesUtil.put('LRC_API', this.lyricApiUrl)
  214. this.getUIContext().getPromptAction().showToast({
  215. message: '保存成功,当前LRC_API:' + this.lyricApiUrl,
  216. duration: 2000,
  217. showMode: promptAction.ToastShowMode.TOP_MOST,
  218. bottom: 85
  219. })
  220. } else {
  221. this.coverApiUrl = this.tempApiUrl.trim()
  222. PreferencesUtil.put('COVER_API', this.coverApiUrl)
  223. this.getUIContext().getPromptAction().showToast({
  224. message: '保存成功,当前COVER_API:' + this.coverApiUrl,
  225. duration: 2000,
  226. showMode: promptAction.ToastShowMode.TOP_MOST,
  227. bottom: 85
  228. })
  229. }
  230. this.apiDialogController.close();
  231. }
  232. }
  233. ]
  234. }),
  235. autoCancel: true,
  236. alignment: DialogAlignment.Center
  237. })
  238. @Builder
  239. buildApiDialogContent() {
  240. Column() {
  241. TextInput({
  242. text: this.tempApiUrl,
  243. placeholder: this.apiDialogType === 'lyric' ? '请输入歌词API地址' : '请输入封面API地址'
  244. })
  245. .onChange((val: string) => {
  246. this.tempApiUrl = val
  247. })
  248. .width('90%')
  249. .height(60)
  250. }
  251. .width('100%')
  252. }
  253. // 组件生命周期
  254. aboutToAppear() {
  255. // this.geIDD()
  256. this.autoHideTitle = PreferencesUtil.getBooleanSync('autoHideTitle', true)
  257. this.isShowPrecious = PreferencesUtil.getBooleanSync('isShowPrecious', false)
  258. this.isBgPlayOpen = PreferencesUtil.getBooleanSync(SettingPage.IS_BGPLAY_OPEN, true)
  259. this.isAutoRatate = PreferencesUtil.getBooleanSync(SettingPage.IS_AUTO_RATATE, true)
  260. this.isMemoryPlay = PreferencesUtil.getBooleanSync(SettingPage.iS_MEMORY_PLAY, true)
  261. this.isMediacodec = PreferencesUtil.getBooleanSync(SettingPage.IS_MIDIACODEC_OPEN, false)
  262. this.isMusicMemoryPlay = PreferencesUtil.getBooleanSync(SettingPage.iS_MUSIC_MEMORY_PLAY, false)
  263. this.isMusicBGCover = PreferencesUtil.getBooleanSync(SettingPage.iS_MUSIC_BG_COVER, true)
  264. this.sortType = PreferencesUtil.getNumberSync(SettingPage.SORT_TYPE, 4)
  265. this.isShowSimi = PreferencesUtil.getBooleanSync(SettingPage.IS_SHOW_SIMI, false)
  266. this.isShowFAV = PreferencesUtil.getBooleanSync(SettingPage.IS_SHOW_FAV, true)
  267. this.isShowHistory = PreferencesUtil.getBooleanSync(SettingPage.IS_SHOW_HISTORY, true)
  268. this.isCustomizeBg = PreferencesUtil.getBooleanSync(SettingPage.IS_CUSTOMIZE_BG, false)
  269. this.customizeBgPath = PreferencesUtil.getStringSync(SettingPage.IS_CUSTOMIZE_BG_PATH, '')
  270. this.isGridMusic = PreferencesUtil.getBooleanSync(SettingPage.IS_GRID_MUSIC, false)
  271. this.isScrollHide = PreferencesUtil.getBooleanSync(SettingPage.IS_SCROLL_HIDE, false)
  272. this.isSameTimePlay = PreferencesUtil.getBooleanSync(SettingPage.IS_SAMETIME_PLAY, false)
  273. this.isSavePlayMode = PreferencesUtil.getBooleanSync(SettingPage.iS_SAVE_PLAY_MODE, true)
  274. this.blurValue = PreferencesUtil.getNumberSync(SettingPage.CUSTOMIZE_BG_BLUR, 0)
  275. this.bgBrightness = PreferencesUtil.getNumberSync(SettingPage.BG_BRIGHTNESS, 0)
  276. this.isStartAutoPlay = PreferencesUtil.getBooleanSync(SettingPage.iS_START_AUTO_PLAY, false)
  277. this.isMemoryLastPlay = PreferencesUtil.getBooleanSync(SettingPage.iS_MEMORY_LAST_PLAY, false)
  278. this.twoFingerType = PreferencesUtil.getNumberSync(SettingPage.TWO_FINGER_TYPE, 2)
  279. this.isCircleBtn = PreferencesUtil.getBooleanSync(SettingPage.IS_CIRCLE_BTN, true)
  280. this.isCoverTop = PreferencesUtil.getBooleanSync(SettingPage.IS_COVER_TOP, true)
  281. this.isShowTitleBar = PreferencesUtil.getBooleanSync(SettingPage.IS_SHOW_TITLTBAR, false)
  282. this.isShowAllBar = PreferencesUtil.getBooleanSync(SettingPage.IS_SHOW_ALLBAR, true)
  283. this.isShowPlayPageBack = PreferencesUtil.getBooleanSync(SettingPage.IS_SHOW_PLAYPAGE_BACK, true)
  284. this.isShowSingleLineLyric = PreferencesUtil.getBooleanSync(SettingPage.IS_SHOW_SLLYRIC, false)
  285. this.isCoverTopBig = PreferencesUtil.getBooleanSync(SettingPage.IS_COVER_TOP_BIG, false)
  286. this.longPressSpeed = PreferencesUtil.getNumberSync(SettingPage.LONG_PRESS_SPEED, 3)
  287. this.isShowHeader = PreferencesUtil.getBooleanSync(SettingPage.IS_SHOW_HEADER, true)
  288. this.isCoverRectangle = PreferencesUtil.getBooleanSync(SettingPage.IS_COVER_RECTANGLE, true)
  289. this.isPlayListBgGrass = PreferencesUtil.getBooleanSync(SettingPage.IS_PLAYLIST_BG_GRASS, true)
  290. this.isSwipe = PreferencesUtil.getBooleanSync(SettingPage.IS_SWIPE, true)
  291. this.is_auto_hide_progress = PreferencesUtil.getBooleanSync(SettingPage.IS_AUTO_HIDE_PROGRESS, false)
  292. this.openSkipSongAnimate = PreferencesUtil.getBooleanSync(SettingPage.OPEN_SKIPSONG_ANIMATE, true)
  293. this.volumeSmall = PreferencesUtil.getBooleanSync('volumeSmall', false)
  294. this.autoParseMusicName = PreferencesUtil.getBooleanSync('autoParseMusicName', true)
  295. this.idDefaultMediaKu = PreferencesUtil.getBooleanSync('idDefaultMediaKu', false)
  296. this.isShowFileName = PreferencesUtil.getBooleanSync('isShowFileName', false)
  297. this.isLongNameRoLL = PreferencesUtil.getBooleanSync('isLongNameRoLL', true)
  298. this.isShowBackFast = PreferencesUtil.getBooleanSync('isShowBackFast', false)
  299. this.fastForwardSeconds = PreferencesUtil.getStringSync('fastForwardSeconds', '10')
  300. this.isCopyFileToDownLoad = PreferencesUtil.getBooleanSync(SettingPage.IS_COPYFILE_TO_DOWNLOAD, false)
  301. this.isNoJumpToHome = PreferencesUtil.getBooleanSync('isNoJumpToHome', true)
  302. this.webdavUploadDuplicateAction = PreferencesUtil.getStringSync(SettingPage.WEBDAV_UPLOAD_DUPLICATE_ACTION, 'skip')
  303. this.webdavUploadAutoClear = PreferencesUtil.getBooleanSync(SettingPage.WEBDAV_UPLOAD_AUTO_CLEAR, false)
  304. this.webdavUploadAllowMobile = PreferencesUtil.getBooleanSync(SettingPage.WEBDAV_UPLOAD_ALLOW_MOBILE, false)
  305. this.webdavUploadRetryCount = PreferencesUtil.getNumberSync(SettingPage.WEBDAV_UPLOAD_RETRY_COUNT, 3)
  306. this.isLogUploadEnabled = PreferencesUtil.getBooleanSync(SettingPage.LOG_UPLOAD_ENABLED, false)
  307. if (this.isLogUploadEnabled) {
  308. this.ensureMeituUploadHandler(true)
  309. } else {
  310. this.registerLogUploadDisabled()
  311. }
  312. // 只用 themeMode 控制主题
  313. this.themeMode = PreferencesUtil.getNumberSync(SettingPage.THEME_MODE, 0)
  314. this.applyThemeMode(this.themeMode)
  315. let themeColor = PreferencesUtil.getStringSync('THEME_COLOR', CommonConstants.DEFAULT_THEME_COLOR);
  316. AppStorage.setOrCreate('themeColor', themeColor);
  317. this.themeColor = themeColor;
  318. this.initIcon()
  319. }
  320. initIcon(){
  321. this.iconCurrentID = PreferencesUtil.getStringSync('iconCurrentID', 'default')
  322. const iconItem:Icon = {
  323. iconUrl: 'default',
  324. iconId: 'default',
  325. enabled: false
  326. }
  327. this.iconArray.push(iconItem)
  328. try {
  329. appInfoManager.queryDynamicIcons()
  330. .then((queryResult: appInfoManager.DynamicIconInfo[]) => {
  331. hilog.info(0, 'TAG', "Succeeded in getting queryResult= " + JSON.stringify(queryResult));
  332. const iconList = JSON.parse(JSON.stringify(queryResult)) as Array<Icon>;
  333. this.iconArray = this.iconArray.concat(iconList)
  334. }).catch((error: BusinessError) => {
  335. hilog.error(0, 'TAG', "queryDynamicIcons failed, code: " + error.code + ", exception message: " + error.message);
  336. });
  337. } catch (error) {
  338. hilog.error(0, 'TAG', "queryDynamicIcons exception code: " + error.code + ", exception message: " + error.message);
  339. }
  340. }
  341. // 监听颜色模式变化
  342. onColorModeChange(): void {
  343. this.isDarkMode = this.currentMode === ConfigurationConstant.ColorMode.COLOR_MODE_DARK;
  344. AppStorage.setOrCreate('isDarkMode', this.isDarkMode);
  345. }
  346. // 组件生命周期
  347. aboutToDisappear() {
  348. // 无需处理apiDialogController
  349. }
  350. applyThemeMode(mode: number) {
  351. let colorMode = ConfigurationConstant.ColorMode.COLOR_MODE_NOT_SET
  352. if (mode === 1) {
  353. colorMode = ConfigurationConstant.ColorMode.COLOR_MODE_LIGHT
  354. } else if (mode === 2) {
  355. colorMode = ConfigurationConstant.ColorMode.COLOR_MODE_DARK
  356. }
  357. AppStorage.setOrCreate('currentColorMode', colorMode)
  358. AppStorage.setOrCreate('isDarkMode', colorMode === ConfigurationConstant.ColorMode.COLOR_MODE_DARK)
  359. PreferencesUtil.putSync(SettingPage.THEME_MODE, mode)
  360. AppStorage.setOrCreate('themeMode', mode)
  361. // 只有强制浅色/深色时才主动设置
  362. const context = getContext(this) as common.UIAbilityContext
  363. context.getApplicationContext().setColorMode(colorMode)
  364. }
  365. private logNetDisk(level: 'info' | 'warn' | 'error', message: string) {
  366. const tag = 'NetDiskSetting';
  367. switch (level) {
  368. case 'info':
  369. void ServerLogUtil.info(tag, message);
  370. break;
  371. case 'warn':
  372. void ServerLogUtil.warn(tag, message);
  373. break;
  374. case 'error':
  375. void ServerLogUtil.error(tag, message);
  376. break;
  377. default:
  378. break;
  379. }
  380. }
  381. private handleClearWebDavCache() {
  382. if (this.isClearingCache) {
  383. return;
  384. }
  385. this.isClearingCache = true;
  386. const manager = RemoteDriveManager.getInstance();
  387. const account = manager?.currentAccount;
  388. const accountId = account?.id;
  389. const clearPromise = accountId !== undefined
  390. ? clearWebDavCacheByAccount(accountId)
  391. : clearWebDavCaches();
  392. const target = accountId !== undefined && account
  393. ? ServerLogUtil.sanitizeAccount(account)
  394. : 'all-accounts';
  395. this.logNetDisk('info', `开始清除网盘缓存: target=${target}`);
  396. clearPromise.then(() => {
  397. ToastUtil.showToast('已清除网盘缓存');
  398. this.logNetDisk('info', `清除网盘缓存成功: target=${target}`);
  399. }).catch((error: Error) => {
  400. hilog.error(0, 'SettingPage', `清除网盘缓存失败: ${error.message}`);
  401. ToastUtil.showToast('清除失败,请稍后重试');
  402. this.logNetDisk('error', `清除网盘缓存失败: target=${target}, err=${error.message}`);
  403. }).finally(() => {
  404. this.isClearingCache = false;
  405. this.logNetDisk('info', `网盘缓存清理结束: target=${target}`);
  406. });
  407. }
  408. private handleClearLogFiles() {
  409. if (this.isClearingLogs) {
  410. return;
  411. }
  412. // 显示确认对话框
  413. AlertDialog.show({
  414. title: '确认清除',
  415. message: '确定要清除所有日志文件吗?此操作不可撤销。',
  416. autoCancel: true,
  417. alignment: DialogAlignment.Bottom,
  418. primaryButton: {
  419. value: '确定清除',
  420. action: () => {
  421. this.clearLogFiles();
  422. }
  423. },
  424. secondaryButton: {
  425. value: '取消',
  426. action: () => {
  427. // 取消操作
  428. }
  429. }
  430. });
  431. }
  432. private deleteDirectoryRecursively(dirPath: string): void {
  433. try {
  434. if (!FileUtil.accessSync(dirPath)) {
  435. return;
  436. }
  437. if (FileUtil.isDirectory(dirPath)) {
  438. const files = FileUtil.listFileSync(dirPath);
  439. files.forEach((file: string) => {
  440. const filePath = `${dirPath}${FileUtil.separator}${file}`;
  441. this.deleteDirectoryRecursively(filePath);
  442. });
  443. FileUtil.rmdirSync(dirPath);
  444. } else {
  445. FileUtil.unlinkSync(dirPath);
  446. }
  447. } catch (error) {
  448. hilog.warn(0, 'SettingPage', `删除目录失败: ${dirPath}, 错误: ${JSON.stringify(error)}`);
  449. }
  450. }
  451. private async clearLogFiles() {
  452. this.isClearingLogs = true;
  453. try {
  454. let clearedCount = 0;
  455. // 清除错误日志
  456. const errorLogPath = FileUtil.getFilesDirPath('ErrorLog', 'errorLog.txt');
  457. if (FileUtil.accessSync(errorLogPath)) {
  458. FileUtil.unlinkSync(errorLogPath);
  459. clearedCount++;
  460. }
  461. // 清除Navidrome日志
  462. const navidromeLogDir = FileUtil.getFilesDirPath('NavidromeLog');
  463. if (FileUtil.accessSync(navidromeLogDir)) {
  464. try {
  465. const files = FileUtil.listFileSync(navidromeLogDir);
  466. files.forEach((file: string) => {
  467. const filePath = `${navidromeLogDir}${FileUtil.separator}${file}`;
  468. if (FileUtil.accessSync(filePath) && !FileUtil.isDirectory(filePath)) {
  469. FileUtil.unlinkSync(filePath);
  470. clearedCount++;
  471. }
  472. });
  473. } catch (error) {
  474. hilog.warn(0, 'SettingPage', `清除Navidrome日志目录时出错: ${JSON.stringify(error)}`);
  475. }
  476. }
  477. // 清除日志上传缓存
  478. const logUploadDir = FileUtil.getCacheDirPath('LogUpload');
  479. if (FileUtil.accessSync(logUploadDir)) {
  480. try {
  481. // 递归删除目录及其内容
  482. this.deleteDirectoryRecursively(logUploadDir);
  483. clearedCount++;
  484. } catch (error) {
  485. hilog.warn(0, 'SettingPage', `清除日志上传缓存时出错: ${JSON.stringify(error)}`);
  486. }
  487. }
  488. // 清除其他可能的日志文件
  489. const logFilePatterns = [
  490. 'app.log',
  491. 'debug.log',
  492. 'info.log',
  493. 'warn.log',
  494. 'crash.log'
  495. ];
  496. logFilePatterns.forEach((fileName: string) => {
  497. try {
  498. const filesDir = AppUtil.getContext().filesDir;
  499. const logFilePath = `${filesDir}${FileUtil.separator}${fileName}`;
  500. if (FileUtil.accessSync(logFilePath)) {
  501. FileUtil.unlinkSync(logFilePath);
  502. clearedCount++;
  503. }
  504. // 检查cache目录
  505. const cacheLogPath = `${AppUtil.getContext().cacheDir}${FileUtil.separator}${fileName}`;
  506. if (FileUtil.accessSync(cacheLogPath)) {
  507. FileUtil.unlinkSync(cacheLogPath);
  508. clearedCount++;
  509. }
  510. } catch (error) {
  511. hilog.warn(0, 'SettingPage', `清除日志文件 ${fileName} 时出错: ${JSON.stringify(error)}`);
  512. }
  513. });
  514. if (clearedCount > 0) {
  515. ToastUtil.showToast(`已清除 ${clearedCount} 个日志文件`);
  516. hilog.info(0, 'SettingPage', `成功清除 ${clearedCount} 个日志文件`);
  517. } else {
  518. ToastUtil.showToast('未找到需要清除的日志文件');
  519. }
  520. } catch (error) {
  521. const errorMessage = error instanceof Error ? error.message : '未知错误';
  522. hilog.error(0, 'SettingPage', `清除日志文件失败: ${errorMessage}`);
  523. ToastUtil.showToast('清除失败,请稍后重试');
  524. } finally {
  525. this.isClearingLogs = false;
  526. }
  527. }
  528. @Builder
  529. pickerBuilder() {
  530. Column({ space: 20 }) {
  531. HSBColorPicker({
  532. color: this.customColor,
  533. radius: 8,
  534. onChange: (value: string) => {
  535. this.customColor = value
  536. }
  537. })
  538. .layoutWeight(1)
  539. .padding(15)
  540. Row({ space: 10 }) {
  541. Button('取消')
  542. .stateEffect(true)
  543. .backgroundColor(this.themeColor)
  544. .onClick(() => {
  545. this.showColorPicker = false
  546. })
  547. Button('确定')
  548. .stateEffect(true)
  549. .backgroundColor(this.themeColor)
  550. .onClick(() => {
  551. this.themeColor = this.customColor
  552. PreferencesUtil.putSync(SettingPage.THEME_COLOR_KEY, this.customColor)
  553. AppStorage.setOrCreate('themeColor', this.customColor)
  554. this.sendChangeEvent()
  555. this.showColorPicker = false
  556. })
  557. }
  558. }
  559. .padding(20)
  560. .width('80%')
  561. .height(300)
  562. }
  563. @Builder
  564. themeSheetBuilder() {
  565. Column() {
  566. // 颜色模式分组卡片
  567. Column() {
  568. Row() {
  569. Row() {
  570. Image($r('app.media.theme'))
  571. .width(20)
  572. .height(20)
  573. .fillColor(this.themeColor)
  574. Text('颜色模式')
  575. .fontSize(15)
  576. .margin({ left: 6 })
  577. .fontWeight(500)
  578. }
  579. .layoutWeight(1)
  580. Blank()
  581. Row() {
  582. ForEach(['自动', '日间', '夜间'], (item: string, idx: number) => {
  583. Column() {
  584. Radio({
  585. value: idx.toString(),
  586. group: this.colorGroup,
  587. })
  588. .checked(this.themeMode === idx)
  589. .radioStyle({
  590. checkedBackgroundColor: this.themeColor
  591. })
  592. .margin({ left: 3, right: 3 })
  593. .onClick(() => {
  594. this.themeMode = idx
  595. this.applyThemeMode(idx)
  596. this.sendChangeEvent()
  597. })
  598. Text(item)
  599. .fontSize(15)
  600. .fontColor($r('app.color.text_color'))
  601. .margin({ top: 6 })
  602. .onClick(() => {
  603. this.themeMode = idx
  604. this.applyThemeMode(idx)
  605. this.sendChangeEvent()
  606. })
  607. }
  608. .alignItems(HorizontalAlign.Center)
  609. .margin({ left: 12, right: 12 })
  610. })
  611. }
  612. .margin({ left: 12, right: 12 })
  613. }
  614. }
  615. .backgroundColor($r('app.color.settings_background_main'))
  616. .borderRadius(18)
  617. .border({ width: 1, color: '#F0F0F0' })
  618. .shadow({
  619. radius: 12,
  620. color: 0x11000000,
  621. offsetX: 0,
  622. offsetY: 2
  623. })
  624. .margin({
  625. left: 0,
  626. right: 0,
  627. bottom: 20
  628. })
  629. .padding({
  630. top: 18,
  631. bottom: 18,
  632. left: 20,
  633. right: 20
  634. })
  635. .width('90%')
  636. // 主题色分组卡片
  637. Column() {
  638. Row() {
  639. SymbolGlyph($r('sys.symbol.paintpalette'))
  640. .fontSize(20)
  641. .fontColor([this.themeColor])
  642. Text('主题色')
  643. .fontSize(15)
  644. .fontWeight(500)
  645. .margin({ left: 8 })
  646. .layoutWeight(1)
  647. }
  648. .margin({ left: 20, top: 12 })
  649. Row() {
  650. Column() {
  651. ForEach(this.colorRows, (row: Array<ThemeColorItem>, rowIdx: number) => {
  652. Row() {
  653. ForEach(row, (item: ThemeColorItem, colIdx: number) => {
  654. Button() {
  655. Row() {
  656. Blank()
  657. .width(22)
  658. .height(22)
  659. .backgroundColor(item.name === '自定义' && this.isCustomThemeColor() ? this.themeColor :
  660. item.color)
  661. .border({ width: 2, color: $r('app.color.text_color') })
  662. .borderRadius(11)
  663. Text(item.name)
  664. .fontSize(15)
  665. .fontColor($r('app.color.text_color'))
  666. .margin({ left: 10 })
  667. // Text(item.isVip?'VIP':"Free")
  668. // .fontSize(10)
  669. // .fontColor(item.isVip?'#FFD700':"#000000") // 金色
  670. // .backgroundColor('#FFF9E3')
  671. // .borderRadius(6)
  672. // .padding({ left: 4, right: 4, top: 1, bottom: 1 })
  673. // .margin({ left: 4 })
  674. }
  675. .alignItems(VerticalAlign.Center)
  676. .justifyContent(FlexAlign.Start)
  677. .layoutWeight(1)
  678. }
  679. .height(40)
  680. .layoutWeight(1)
  681. .backgroundColor(
  682. (item.name === '自定义' && this.isCustomThemeColor()) || this.themeColor === item.color
  683. ? this.themeColor
  684. : $r('app.color.settings_background_main')
  685. )
  686. .borderRadius(20)
  687. .onClick(() => {
  688. if (item.isVip) {
  689. if (!Utility.isNoble()) {
  690. this.showVipDialog();
  691. return;
  692. }
  693. }
  694. if (item.name === '自定义') {
  695. this.showColorPicker = true
  696. } else {
  697. this.themeColor = item.color
  698. PreferencesUtil.putSync(SettingPage.THEME_COLOR_KEY, item.color)
  699. AppStorage.setOrCreate('themeColor', item.color)
  700. this.sendChangeEvent()
  701. }
  702. })
  703. .margin({ right: colIdx === 0 ? '4%' : 20, bottom: 10, left: 20 })
  704. })
  705. }
  706. .justifyContent(FlexAlign.Start)
  707. })
  708. }
  709. .margin({ left: 12, right: 12, top: 12 })
  710. }
  711. }
  712. .width('90%')
  713. .backgroundColor($r('app.color.settings_background_main'))
  714. .borderRadius(18)
  715. .border({ width: 1, color: '#F0F0F0' })
  716. .shadow({
  717. radius: 12,
  718. color: 0x11000000,
  719. offsetX: 0,
  720. offsetY: 2
  721. })
  722. .margin({
  723. left: 0,
  724. right: 0,
  725. bottom: 18
  726. })
  727. .padding({
  728. top: 18,
  729. bottom: 18,
  730. left: 0,
  731. right: 0
  732. })
  733. .bindPopup(this.showColorPicker, {
  734. builder: this.pickerBuilder(),
  735. placement: Placement.Top,
  736. mask: { color: '#33000000' },
  737. enableArrow: false, //是否显示箭头
  738. showInSubWindow: false,
  739. onStateChange: (e) => {
  740. if (!e.isVisible) {
  741. this.showColorPicker = false
  742. }
  743. }
  744. })
  745. // 主题色自定义弹窗
  746. }
  747. .padding({
  748. top: 8,
  749. bottom: 8,
  750. left: 15,
  751. right: 15
  752. })
  753. .width('100%')
  754. .backgroundColor(Color.Transparent)
  755. .borderRadius(24)
  756. }
  757. @Builder
  758. topTitleBar(){
  759. Column() {
  760. Row({ space: 15 }) {
  761. //左侧滑动按钮
  762. Button({ type: ButtonType.Circle, stateEffect: true }) {
  763. SymbolGlyph($r('sys.symbol.chevron_left'))
  764. .attributeModifier(new SymbolGlyphFancyModifier(25, '', ''))
  765. }
  766. .attributeModifier(new ButtonFancyModifier(40, 40))
  767. .clickEffect({ level: ClickEffectLevel.MIDDLE,scale:0.6 })
  768. .animation({ duration: 300, curve: Curve.Ease })
  769. .onClick(() => {
  770. this.getUIContext()?.animateTo({ duration: 555 }, () => {
  771. this.mType =0
  772. })
  773. })
  774. .attributeModifier(new ShadowModifier())
  775. .zIndex(0)
  776. Text($r('app.string.setting'))
  777. .margin({left:3,right:10})
  778. .fontColor($r('app.color.text_color'))
  779. .fontSize(19)
  780. .maxLines(1)
  781. .textOverflow({ overflow: TextOverflow.MARQUEE })//超长滚动
  782. .layoutWeight(1)
  783. .clickEffect({ level: ClickEffectLevel.MIDDLE,scale:0.6 })
  784. }
  785. }
  786. .padding({ top: this.topSafeHeight+10, left: 10, right: 10,bottom:12 })
  787. .width('100%')
  788. }
  789. build() {
  790. Column() {
  791. this.topTitleBar()
  792. // Column() {
  793. // Line().width('100%').height('100%')
  794. // }
  795. // .height(this.topRectHeight)
  796. // .backgroundColor(this.isDarkMode ? $r('app.color.title_bar_bg') : this.themeColor)
  797. // .expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.TOP])
  798. //
  799. // // 自定义标题栏
  800. // Stack() {
  801. // // 居中标题
  802. // Text('通用设置')
  803. // .fontSize(20)
  804. // .fontColor(Color.White)
  805. // .align(Alignment.Center)
  806. // // 左侧返回按钮
  807. // Row() {
  808. // Image($r('app.media.left_back_white'))
  809. // .width(26)
  810. // .height(26)
  811. // .margin({ left: 12, right: 8 })
  812. // .onClick(() => {
  813. // this.getUIContext()?.animateTo({ duration: 555 }, () => {
  814. // // 动画闭包内控制Image组件的出现和消失
  815. // // this.isShowDrawer = !this.isShowDrawer
  816. // // this.offsetX = 0
  817. // this.mType =0
  818. // })
  819. // })
  820. // Blank().flexGrow(1)
  821. // Blank().width(32)
  822. // }
  823. // .height(48)
  824. // .width('100%')
  825. // .alignItems(VerticalAlign.Center)
  826. // }
  827. // .height(48)
  828. // .width('100%')
  829. // .backgroundColor(this.isDarkMode ? $r('app.color.title_bar_bg') : this.themeColor)
  830. Scroll() {
  831. Column() {
  832. // 主题设置分组
  833. Column() {
  834. Row() {
  835. Text('个性化')
  836. .margin({ left: 18, right: 20 })
  837. .fontSize(16)
  838. .fontColor(Color.Gray)
  839. .fontWeight(480)
  840. .layoutWeight(1)
  841. }
  842. .height(48)
  843. Line().width('100%').height(0.3).backgroundColor($r('app.color.index_tab_unselected_font_color'))
  844. // 主题设置弹框入口
  845. Button({ type: ButtonType.Normal, stateEffect: true }) {
  846. Row() {
  847. SymbolGlyph($r('sys.symbol.sun_max'))
  848. .fontSize(20)
  849. .fontColor([this.themeColor])
  850. .alignSelf(ItemAlign.Center)
  851. .margin({ left: 15 })
  852. Text('主题设置')
  853. .margin({ left: 8 })
  854. .fontSize(15)
  855. .fontColor(Color.Gray)
  856. .fontWeight(480)
  857. .layoutWeight(1)
  858. Image($r('app.media.arrow_right'))
  859. .width(22)
  860. .height(22)
  861. .margin({ right: 18 })
  862. }
  863. }
  864. .backgroundColor(Color.Transparent)
  865. .height(55)
  866. .clickEffect({ level: ClickEffectLevel.HEAVY })
  867. .onClick(() => {
  868. this.showColorPicker = false;
  869. this.isThemeSheet = true;
  870. this.customColor = this.themeColor;
  871. })
  872. .bindSheet($$this.isThemeSheet, this.themeSheetBuilder(), {
  873. height: '95%',
  874. dragBar: true,
  875. preferType: this.currentBreakpoint !== BreakpointTypeEnum.SM ? SheetType.CENTER : SheetType.BOTTOM,
  876. showClose: true,
  877. blurStyle: BlurStyle.Thin,
  878. backgroundColor: Color.Transparent,
  879. title: { title: '主题设置' },
  880. shouldDismiss: (SheetDismiss: SheetDismiss) => {
  881. SheetDismiss.dismiss();
  882. this.showColorPicker = false;
  883. }
  884. })
  885. Line().width('100%').height(0.3).backgroundColor($r('app.color.index_tab_unselected_font_color'))
  886. Button({ type: ButtonType.Normal, stateEffect: true }) {
  887. Row() {
  888. SymbolGlyph($r('sys.symbol.paintpalette'))
  889. .fontSize(20)
  890. .fontColor([this.themeColor])
  891. .alignSelf(ItemAlign.Center)
  892. .margin({ left: 15 })
  893. Text('自定义背景')
  894. .margin({ left: 8 })
  895. .fontSize(15)
  896. .fontColor(Color.Gray)
  897. .fontWeight(480)
  898. .layoutWeight(1)
  899. .bindSheet($$this.isCustomizeBgSheet, this.customizeBgSheet(), {
  900. height: '95%',
  901. dragBar: true,
  902. preferType: this.currentBreakpoint !== BreakpointTypeEnum.SM ? SheetType.CENTER : SheetType.BOTTOM,
  903. showClose: true,
  904. blurStyle: BlurStyle.Thin,
  905. backgroundColor: Color.Transparent,
  906. title: { title: '自定义背景' }
  907. })
  908. Blank()
  909. // 右侧箭头
  910. Image($r('app.media.arrow_right'))
  911. .width(22)
  912. .height(22)
  913. .margin({ left: 20, right: 20 })
  914. .align(Alignment.Center)
  915. }
  916. }
  917. .clickEffect({ level: ClickEffectLevel.HEAVY })
  918. .height(55)
  919. .onClick(() => {
  920. if (!Utility.isNoble()) {
  921. this.showVipDialog();
  922. return;
  923. }
  924. this.isCustomizeBgSheet = !this.isCustomizeBgSheet;
  925. })
  926. .backgroundColor(Color.Transparent)
  927. Line().width('100%').height(0.3).backgroundColor($r('app.color.index_tab_unselected_font_color'))
  928. Button({ type: ButtonType.Normal, stateEffect: true }) {
  929. Row() {
  930. SymbolGlyph($r('sys.symbol.satellite_map'))
  931. .fontSize(20)
  932. .fontColor([this.themeColor])
  933. .alignSelf(ItemAlign.Center)
  934. .margin({ left: 15 })
  935. Text('自定义图标')
  936. .margin({ left: 8 })
  937. .fontSize(15)
  938. .fontColor(Color.Gray)
  939. .fontWeight(480)
  940. .layoutWeight(1)
  941. .bindSheet($$this.isCustomizeICONSheet, this.customizeICONSheet(), {
  942. height: this.isLandscape ? '95%' : '85%',
  943. dragBar: true,
  944. preferType: this.currentBreakpoint !== BreakpointTypeEnum.SM ? SheetType.CENTER : SheetType.BOTTOM,
  945. showClose: true,
  946. blurStyle: BlurStyle.Thin,
  947. backgroundColor: Color.Transparent,
  948. title: { title: '自定义图标' }
  949. })
  950. Blank()
  951. // 右侧箭头
  952. Image($r('app.media.arrow_right'))
  953. .width(22)
  954. .height(22)
  955. .margin({ left: 20, right: 20 })
  956. .align(Alignment.Center)
  957. }
  958. }
  959. .clickEffect({level:ClickEffectLevel.HEAVY})
  960. .height(55)
  961. .onClick(() => {
  962. if (!Utility.isNoble()) {
  963. this.showVipDialog();
  964. return;
  965. }
  966. this.isCustomizeICONSheet = !this.isCustomizeICONSheet;
  967. })
  968. .backgroundColor(Color.Transparent)
  969. Line().width('100%').height(0.3).backgroundColor($r('app.color.index_tab_unselected_font_color'))
  970. // 滚动隐藏'
  971. // Row() {
  972. // Text('滚动隐藏')
  973. // .margin({ left: 18 })
  974. // .fontSize(15)
  975. // .fontColor(Color.Gray)
  976. // .fontWeight(480)
  977. // .layoutWeight(1)
  978. // Toggle({ type: ToggleType.Switch, isOn: this.isScrollHide })
  979. // .selectedColor(this.themeColor)
  980. // .switchPointColor(Color.White)
  981. // .clickEffect({level:ClickEffectLevel.LIGHT, scale: 0.5})
  982. // .margin({ right: 18 })
  983. // .onChange((checked: boolean) => {
  984. // this.isScrollHide = checked;
  985. // PreferencesUtil.put(SettingPage.IS_SCROLL_HIDE, this.isScrollHide)
  986. // this.sendChangeEvent()
  987. // })
  988. // .width(50)
  989. // .height(30);
  990. // }
  991. // .height(55)
  992. // .visibility(Visibility.None)
  993. // .clickEffect({ level: ClickEffectLevel.HEAVY })
  994. //
  995. // Line().width('100%').height(0.3).backgroundColor($r('app.color.index_tab_unselected_font_color'))
  996. // .visibility(Visibility.None)
  997. // 网格布局
  998. // 网格布局
  999. Row() {
  1000. SymbolGlyph($r('sys.symbol.more'))
  1001. .fontSize(20)
  1002. .fontColor([this.themeColor])
  1003. .alignSelf(ItemAlign.Center)
  1004. .margin({ left: 15 })
  1005. Text('布局模式')
  1006. .margin({ left: 8 })
  1007. .fontSize(15)
  1008. .fontColor(Color.Gray)
  1009. .fontWeight(480)
  1010. .layoutWeight(1)
  1011. Select([
  1012. { value: CommonConstants.DEFAULT_LAYOUT[0] },
  1013. { value: CommonConstants.DEFAULT_LAYOUT[1] },
  1014. { value: CommonConstants.DEFAULT_LAYOUT[2] }])
  1015. .font({ size: 15, weight: FontWeight.Medium })
  1016. .fontColor(Color.Gray)
  1017. .margin({ right: 18 })
  1018. .selected(this.twoFingerType==4?0:
  1019. this.isGridMusic?2:1)
  1020. .value(CommonConstants.DEFAULT_LAYOUT[this.twoFingerType==4?0:
  1021. this.isGridMusic?2:1])
  1022. .onSelect(async (_index: number, text?: string | undefined) => {
  1023. if(_index == 0){
  1024. PreferencesUtil.put(SettingPage.TWO_FINGER_TYPE,4)
  1025. }else{
  1026. if(this.twoFingerType!=4){
  1027. PreferencesUtil.put(SettingPage.TWO_FINGER_TYPE,this.twoFingerType)
  1028. }else{
  1029. PreferencesUtil.put(SettingPage.TWO_FINGER_TYPE,3)
  1030. }
  1031. if(_index == 1){
  1032. PreferencesUtil.put(SettingPage.IS_GRID_MUSIC,false)
  1033. }else{
  1034. PreferencesUtil.put(SettingPage.IS_GRID_MUSIC,true)
  1035. }
  1036. }
  1037. this.sendChangeEvent()
  1038. })
  1039. }
  1040. .height(55)
  1041. .clickEffect({level:ClickEffectLevel.HEAVY})
  1042. Line().width('100%').height(0.3).backgroundColor($r('app.color.index_tab_unselected_font_color'))
  1043. // 封面方形
  1044. Row() {
  1045. SymbolGlyph($r('sys.symbol.rectangle'))
  1046. .fontSize(20)
  1047. .fontColor([this.themeColor])
  1048. .alignSelf(ItemAlign.Center)
  1049. .margin({ left: 15 })
  1050. Text('封面方形')
  1051. .margin({ left: 8 })
  1052. .fontSize(15)
  1053. .fontColor(Color.Gray)
  1054. .fontWeight(480)
  1055. .layoutWeight(1)
  1056. Toggle({ type: ToggleType.Switch, isOn: this.isCoverRectangle })
  1057. .selectedColor(this.themeColor)
  1058. .switchPointColor(Color.White)
  1059. .margin({ right: 18 })
  1060. .clickEffect({level:ClickEffectLevel.LIGHT, scale: 0.5})
  1061. .onChange((checked: boolean) => {
  1062. this.isCoverRectangle = checked;
  1063. PreferencesUtil.put(SettingPage.IS_COVER_RECTANGLE, this.isCoverRectangle)
  1064. this.sendChangeEvent()
  1065. })
  1066. .width(50)
  1067. .height(30);
  1068. }
  1069. .height(55)
  1070. .clickEffect({ level: ClickEffectLevel.HEAVY })
  1071. Line().width('100%').height(0.3).backgroundColor($r('app.color.index_tab_unselected_font_color'))
  1072. //导入视频复制一份到DownLoad目录
  1073. Row() {
  1074. SymbolGlyph($r('sys.symbol.save'))
  1075. .fontSize(20)
  1076. .fontColor([this.themeColor])
  1077. .alignSelf(ItemAlign.Center)
  1078. .margin({ left: 15 })
  1079. Text('导入音乐复制到DownLoad目录')
  1080. .margin({ left: 8 })
  1081. .fontSize(15)
  1082. .fontColor(Color.Gray)
  1083. .fontWeight(480)
  1084. .layoutWeight(1)
  1085. Toggle({ type: ToggleType.Switch, isOn: this.isCopyFileToDownLoad })
  1086. .selectedColor(this.themeColor)
  1087. .switchPointColor(Color.White)
  1088. .margin({ right: 18 })
  1089. .onChange((checked: boolean) => {
  1090. // if(!this.isCopyFileToDownLoad){
  1091. // ToastUtil.showToast("读取内嵌封面和歌词功能需要开启导入复制开关,不然没有权限读取。")
  1092. // }
  1093. this.isCopyFileToDownLoad = checked;
  1094. PreferencesUtil.put(SettingPage.IS_COPYFILE_TO_DOWNLOAD, this.isCopyFileToDownLoad)
  1095. this.sendChangeEvent()
  1096. })
  1097. .width(50)
  1098. .height(30);
  1099. }
  1100. .height(55)
  1101. .clickEffect({level:ClickEffectLevel.HEAVY})
  1102. Line().width('100%').height(0.3).backgroundColor($r('app.color.index_tab_unselected_font_color'))
  1103. //播放列表透明
  1104. Row() {
  1105. SymbolGlyph($r('sys.symbol.circle_lefthalf_inset_filled'))
  1106. .fontSize(20)
  1107. .fontColor([this.themeColor])
  1108. .alignSelf(ItemAlign.Center)
  1109. .margin({ left: 15 })
  1110. Text('播放列表背景透明')
  1111. .margin({ left: 8 })
  1112. .fontSize(15)
  1113. .fontColor(Color.Gray)
  1114. .fontWeight(480)
  1115. .layoutWeight(1)
  1116. Toggle({ type: ToggleType.Switch, isOn: this.isPlayListBgGrass })
  1117. .selectedColor(this.themeColor)
  1118. .switchPointColor(Color.White)
  1119. .margin({ right: 18 })
  1120. .clickEffect({level:ClickEffectLevel.LIGHT, scale: 0.5})
  1121. .onChange((checked: boolean) => {
  1122. this.isPlayListBgGrass = checked;
  1123. PreferencesUtil.put(SettingPage.IS_PLAYLIST_BG_GRASS, this.isPlayListBgGrass)
  1124. this.sendChangeEvent()
  1125. })
  1126. .width(50)
  1127. .height(30);
  1128. }
  1129. .height(55)
  1130. .clickEffect({ level: ClickEffectLevel.HEAVY })
  1131. Line().width('100%').height(0.3).backgroundColor($r('app.color.index_tab_unselected_font_color'))
  1132. // 网格封面大
  1133. Row() {
  1134. SymbolGlyph($r('sys.symbol.picture'))
  1135. .fontSize(20)
  1136. .fontColor([this.themeColor])
  1137. .alignSelf(ItemAlign.Center)
  1138. .margin({ left: 15 })
  1139. Text('列表封面大小')
  1140. .margin({ left: 8 })
  1141. .fontSize(15)
  1142. .fontColor(Color.Gray)
  1143. .fontWeight(480)
  1144. .layoutWeight(1)
  1145. Select([
  1146. { value: CommonConstants.TWO_FINGER_TYPE[0] },
  1147. { value: CommonConstants.TWO_FINGER_TYPE[1] },
  1148. { value: CommonConstants.TWO_FINGER_TYPE[2] }])
  1149. .font({ size: 15, weight: FontWeight.Medium })
  1150. .fontColor(Color.Gray)
  1151. .margin({ right: 18 })
  1152. .selected(this.twoFingerType - 1)
  1153. .value(CommonConstants.TWO_FINGER_TYPE[this.twoFingerType-1])
  1154. .onSelect(async (_index: number, text?: string | undefined) => {
  1155. _index++;
  1156. this.twoFingerType = _index
  1157. PreferencesUtil.put(SettingPage.TWO_FINGER_TYPE, this.twoFingerType)
  1158. this.sendChangeEvent()
  1159. })
  1160. }
  1161. .height(55)
  1162. .clickEffect({ level: ClickEffectLevel.HEAVY })
  1163. Line().width('100%').height(0.3).backgroundColor($r('app.color.index_tab_unselected_font_color'))
  1164. // 封面顶部
  1165. Row() {
  1166. SymbolGlyph($r('sys.symbol.arrowshape_up'))
  1167. .fontSize(20)
  1168. .fontColor([this.themeColor])
  1169. .alignSelf(ItemAlign.Center)
  1170. .margin({ left: 15 })
  1171. Text('封面顶部')
  1172. .margin({ left: 8 })
  1173. .fontSize(15)
  1174. .fontColor(Color.Gray)
  1175. .fontWeight(480)
  1176. .layoutWeight(1)
  1177. Toggle({ type: ToggleType.Switch, isOn: this.isCoverTop })
  1178. .selectedColor(this.themeColor)
  1179. .switchPointColor(Color.White)
  1180. .margin({ right: 18 })
  1181. .clickEffect({level:ClickEffectLevel.LIGHT, scale: 0.5})
  1182. .onChange((checked: boolean) => {
  1183. this.isCoverTop = checked;
  1184. PreferencesUtil.put(SettingPage.IS_COVER_TOP, this.isCoverTop)
  1185. this.sendChangeEvent()
  1186. })
  1187. .width(50)
  1188. .height(30);
  1189. }
  1190. .height(55)
  1191. .clickEffect({ level: ClickEffectLevel.HEAVY })
  1192. Line().width('100%').height(0.3).backgroundColor($r('app.color.index_tab_unselected_font_color'))
  1193. .opacity(this.isCoverTop ? 1 : 0)
  1194. .visibility(this.isCoverTop ? Visibility.Visible : Visibility.None)
  1195. .animation({
  1196. duration: 500,
  1197. curve: 'ease-in-out' // 可选动画曲线
  1198. })
  1199. // 封面顶部
  1200. Row() {
  1201. SymbolGlyph($r('sys.symbol.shutter_photo'))
  1202. .fontSize(20)
  1203. .fontColor([this.themeColor])
  1204. .alignSelf(ItemAlign.Center)
  1205. .margin({ left: 15 })
  1206. Text('顶部大封面')
  1207. .margin({ left: 8 })
  1208. .fontSize(15)
  1209. .fontColor(Color.Gray)
  1210. .fontWeight(480)
  1211. .layoutWeight(1)
  1212. Toggle({ type: ToggleType.Switch, isOn: this.isCoverTopBig })
  1213. .selectedColor(this.themeColor)
  1214. .switchPointColor(Color.White)
  1215. .margin({ right: 18 })
  1216. .clickEffect({level:ClickEffectLevel.LIGHT, scale: 0.5})
  1217. .onChange((checked: boolean) => {
  1218. this.isCoverTopBig = checked;
  1219. if(this.isCoverTopBig){
  1220. ToastUtil.showToast('启动该开关部分设备封面太大导致和音乐控制重叠!')
  1221. }
  1222. PreferencesUtil.put(SettingPage.IS_COVER_TOP_BIG, this.isCoverTopBig)
  1223. this.sendChangeEvent()
  1224. })
  1225. .width(50)
  1226. .height(30);
  1227. }
  1228. .height(55)
  1229. .clickEffect({ level: ClickEffectLevel.HEAVY })
  1230. .opacity(this.isCoverTop ? 1 : 0)
  1231. .visibility(this.isCoverTop ? Visibility.Visible : Visibility.None)
  1232. .animation({
  1233. duration: 500,
  1234. curve: 'ease-in-out' // 可选动画曲线
  1235. })
  1236. Line().width('100%').height(0.3).backgroundColor($r('app.color.index_tab_unselected_font_color'))
  1237. // 切歌动画效果
  1238. Row() {
  1239. SymbolGlyph($r('sys.symbol.music'))
  1240. .fontSize(20)
  1241. .fontColor([this.themeColor])
  1242. .alignSelf(ItemAlign.Center)
  1243. .margin({ left: 15 })
  1244. Text('切歌动画效果')
  1245. .margin({ left: 8 })
  1246. .fontSize(15)
  1247. .fontColor(Color.Gray)
  1248. .fontWeight(480)
  1249. .layoutWeight(1)
  1250. Toggle({ type: ToggleType.Switch, isOn: this.openSkipSongAnimate })
  1251. .selectedColor(this.themeColor)
  1252. .switchPointColor(Color.White)
  1253. .clickEffect({level:ClickEffectLevel.LIGHT, scale: 0.5})
  1254. .margin({ right: 18 })
  1255. .onChange((checked: boolean) => {
  1256. this.openSkipSongAnimate = checked;
  1257. PreferencesUtil.put(SettingPage.OPEN_SKIPSONG_ANIMATE, this.openSkipSongAnimate)
  1258. this.sendChangeEvent()
  1259. })
  1260. .width(50)
  1261. .height(30);
  1262. }
  1263. .height(55)
  1264. .clickEffect({ level: ClickEffectLevel.HEAVY })
  1265. Line().width('100%').height(0.3).backgroundColor($r('app.color.index_tab_unselected_font_color'))
  1266. // 圆形播放按钮
  1267. Row() {
  1268. SymbolGlyph($r('sys.symbol.circle'))
  1269. .fontSize(20)
  1270. .fontColor([this.themeColor])
  1271. .alignSelf(ItemAlign.Center)
  1272. .margin({ left: 15 })
  1273. Text('圆形播放按钮')
  1274. .margin({ left: 8 })
  1275. .fontSize(15)
  1276. .fontColor(Color.Gray)
  1277. .fontWeight(480)
  1278. .layoutWeight(1)
  1279. Toggle({ type: ToggleType.Switch, isOn: this.isCircleBtn })
  1280. .selectedColor(this.themeColor)
  1281. .switchPointColor(Color.White)
  1282. .clickEffect({level:ClickEffectLevel.LIGHT, scale: 0.5})
  1283. .margin({ right: 18 })
  1284. .onChange((checked: boolean) => {
  1285. this.isCircleBtn = checked;
  1286. PreferencesUtil.put(SettingPage.IS_CIRCLE_BTN, this.isCircleBtn)
  1287. this.sendChangeEvent()
  1288. })
  1289. .width(50)
  1290. .height(30);
  1291. }
  1292. .height(55)
  1293. .clickEffect({ level: ClickEffectLevel.HEAVY })
  1294. Line().width('100%').height(0.3).backgroundColor($r('app.color.index_tab_unselected_font_color'))
  1295. }
  1296. .transition(TransitionEffect.move(TransitionEdge.BOTTOM)
  1297. .animation({ duration: 500, curve: Curve.Ease, delay: 260 }))
  1298. .backgroundColor($r('app.color.settings_background_main'))
  1299. .borderRadius(20)
  1300. .margin({
  1301. left: 0,
  1302. right: 0,
  1303. top: 0,
  1304. bottom: 10
  1305. })
  1306. .padding(0)
  1307. // 网络工具
  1308. // Column() {
  1309. // Row() {
  1310. // Text('网络工具')
  1311. // .margin({ left: 18, right: 20 })
  1312. // .fontSize(16)
  1313. // .fontColor(Color.Gray)
  1314. // .fontWeight(480)
  1315. // .layoutWeight(1)
  1316. // }
  1317. // .height(48)
  1318. //
  1319. // Line().width('100%').height(0.3).backgroundColor($r('app.color.index_tab_unselected_font_color'))
  1320. // Button({ type: ButtonType.Normal, stateEffect: true }) {
  1321. // Row() {
  1322. // Image($r('app.media.cloudDisk'))
  1323. // .width(22)
  1324. // .height(22)
  1325. // .alignSelf(ItemAlign.Center)
  1326. // .margin({ left: 15 })
  1327. // Text('SMB 测试工具')
  1328. // .margin({ left: 8 })
  1329. // .fontSize(15)
  1330. // .fontColor(Color.Gray)
  1331. // .fontWeight(480)
  1332. // .layoutWeight(1)
  1333. // Image($r('app.media.arrow_right'))
  1334. // .width(22)
  1335. // .height(22)
  1336. // .margin({ right: 18 })
  1337. // }
  1338. // }
  1339. // .height(55)
  1340. // .backgroundColor(Color.Transparent)
  1341. // .clickEffect({ level: ClickEffectLevel.HEAVY })
  1342. // .onClick(() => {
  1343. // router.pushUrl({
  1344. // url: 'pages/SmbTestPage'
  1345. // });
  1346. // })
  1347. //
  1348. // Line().width('100%').height(0.3).backgroundColor($r('app.color.index_tab_unselected_font_color'))
  1349. // }
  1350. // .transition(TransitionEffect.move(TransitionEdge.BOTTOM)
  1351. // .animation({ duration: 500, curve: Curve.Ease, delay: 260 }))
  1352. // .backgroundColor($r('app.color.settings_background_main'))
  1353. // .borderRadius(20)
  1354. // .margin({
  1355. // left: 0,
  1356. // right: 0,
  1357. // top: 0,
  1358. // bottom: 10
  1359. // })
  1360. // .padding(0)
  1361. // 音频设置分组
  1362. Column() {
  1363. Row() {
  1364. Text('音频设置')
  1365. .margin({ left: 18, right: 20 })
  1366. .fontSize(16)
  1367. .fontColor(Color.Gray)
  1368. .fontWeight(480)
  1369. .layoutWeight(1)
  1370. }
  1371. .height(48)
  1372. Line().width('100%').height(0.3).backgroundColor($r('app.color.index_tab_unselected_font_color'))
  1373. // 启动时播放
  1374. Row() {
  1375. SymbolGlyph($r('sys.symbol.play_circle'))
  1376. .fontSize(20)
  1377. .fontColor([this.themeColor])
  1378. .alignSelf(ItemAlign.Center)
  1379. .margin({ left: 15 })
  1380. Text('启动时播放')
  1381. .margin({ left: 8 })
  1382. .fontSize(15)
  1383. .fontColor(Color.Gray)
  1384. .fontWeight(480)
  1385. .layoutWeight(1)
  1386. Toggle({ type: ToggleType.Switch, isOn: this.isStartAutoPlay })
  1387. .selectedColor(this.themeColor)
  1388. .switchPointColor(Color.White)
  1389. .clickEffect({level:ClickEffectLevel.LIGHT, scale: 0.5})
  1390. .margin({ right: 18 })
  1391. .onChange((checked: boolean) => {
  1392. this.isStartAutoPlay = checked;
  1393. PreferencesUtil.put(SettingPage.iS_START_AUTO_PLAY, this.isStartAutoPlay)
  1394. })
  1395. .width(50)
  1396. .height(30);
  1397. }
  1398. .height(55)
  1399. .clickEffect({ level: ClickEffectLevel.HEAVY })
  1400. Line().width('100%').height(0.3).backgroundColor($r('app.color.index_tab_unselected_font_color'))
  1401. // 列表是否可左滑
  1402. Row() {
  1403. SymbolGlyph($r('sys.symbol.indentation_left'))
  1404. .fontSize(20)
  1405. .fontColor([this.themeColor])
  1406. .alignSelf(ItemAlign.Center)
  1407. .margin({ left: 15 })
  1408. Text('列表是否可左滑')
  1409. .margin({ left: 8 })
  1410. .fontSize(15)
  1411. .fontColor(Color.Gray)
  1412. .fontWeight(480)
  1413. .layoutWeight(1)
  1414. Toggle({ type: ToggleType.Switch, isOn: this.isSwipe })
  1415. .selectedColor(this.themeColor)
  1416. .switchPointColor(Color.White)
  1417. .margin({ right: 18 })
  1418. .onChange((checked: boolean) => {
  1419. this.isSwipe = checked;
  1420. PreferencesUtil.put(SettingPage.IS_SWIPE, this.isSwipe)
  1421. this.sendChangeEvent()
  1422. })
  1423. .width(50)
  1424. .height(30);
  1425. }
  1426. .height(55)
  1427. .clickEffect({level:ClickEffectLevel.HEAVY})
  1428. Line().width('100%').height(0.3).backgroundColor($r('app.color.index_tab_unselected_font_color'))
  1429. // 记住播放进度
  1430. Row() {
  1431. SymbolGlyph($r('sys.symbol.rectangle_split_3x1'))
  1432. .fontSize(20)
  1433. .fontColor([this.themeColor])
  1434. .alignSelf(ItemAlign.Center)
  1435. .margin({ left: 15 })
  1436. Text('记住最后一首进度')
  1437. .margin({ left: 8 })
  1438. .fontSize(15)
  1439. .fontColor(Color.Gray)
  1440. .fontWeight(480)
  1441. .layoutWeight(1)
  1442. Toggle({ type: ToggleType.Switch, isOn: this.isMemoryLastPlay })
  1443. .selectedColor(this.themeColor)
  1444. .switchPointColor(Color.White)
  1445. .clickEffect({level:ClickEffectLevel.LIGHT, scale: 0.5})
  1446. .margin({ right: 18 })
  1447. .onChange((checked: boolean) => {
  1448. this.isMemoryLastPlay = checked;
  1449. PreferencesUtil.put(SettingPage.iS_MEMORY_LAST_PLAY, this.isMemoryLastPlay)
  1450. this.sendChangeEvent()
  1451. })
  1452. .width(50)
  1453. .height(30);
  1454. }
  1455. .height(55)
  1456. .clickEffect({ level: ClickEffectLevel.HEAVY })
  1457. Line().width('100%').height(0.3).backgroundColor($r('app.color.index_tab_unselected_font_color'))
  1458. // 记忆播放
  1459. Row() {
  1460. SymbolGlyph($r('sys.symbol.route_plan'))
  1461. .fontSize(20)
  1462. .fontColor([this.themeColor])
  1463. .alignSelf(ItemAlign.Center)
  1464. .margin({ left: 15 })
  1465. Text('记忆播放')
  1466. .margin({ left: 8 })
  1467. .fontSize(15)
  1468. .fontColor(Color.Gray)
  1469. .fontWeight(480)
  1470. .layoutWeight(1)
  1471. Toggle({ type: ToggleType.Switch, isOn: this.isMusicMemoryPlay })
  1472. .selectedColor(this.themeColor)
  1473. .switchPointColor(Color.White)
  1474. .clickEffect({level:ClickEffectLevel.LIGHT, scale: 0.5})
  1475. .margin({ right: 18 })
  1476. .onChange((checked: boolean) => {
  1477. this.isMusicMemoryPlay = checked;
  1478. PreferencesUtil.put(SettingPage.iS_MUSIC_MEMORY_PLAY, this.isMusicMemoryPlay)
  1479. this.sendChangeEvent()
  1480. })
  1481. .width(50)
  1482. .height(30);
  1483. }
  1484. .height(55)
  1485. .clickEffect({ level: ClickEffectLevel.HEAVY })
  1486. Line().width('100%').height(0.3).backgroundColor($r('app.color.index_tab_unselected_font_color'))
  1487. //显示快进快退
  1488. Row() {
  1489. SymbolGlyph($r('sys.symbol.hand_point_up_tap'))
  1490. .fontSize(20)
  1491. .fontColor([this.themeColor])
  1492. .alignSelf(ItemAlign.Center)
  1493. .margin({ left: 15 })
  1494. Text('显示快进快退')
  1495. .margin({ left: 8 })
  1496. .fontSize(15)
  1497. .fontColor(Color.Gray)
  1498. .fontWeight(480)
  1499. .layoutWeight(1)
  1500. Toggle({ type: ToggleType.Switch, isOn: this.isShowBackFast })
  1501. .selectedColor(this.themeColor)
  1502. .switchPointColor(Color.White)
  1503. .margin({ right: 18 })
  1504. .onChange((checked: boolean) => {
  1505. this.isShowBackFast = checked;
  1506. PreferencesUtil.put('isShowBackFast', this.isShowBackFast)
  1507. this.sendChangeEvent()
  1508. })
  1509. .width(50)
  1510. .height(30);
  1511. }
  1512. .height(55)
  1513. .clickEffect({ level: ClickEffectLevel.HEAVY })
  1514. Line().width('100%').height(0.3).backgroundColor($r('app.color.index_tab_unselected_font_color'))
  1515. .opacity(this.isShowBackFast ? 1 : 0)
  1516. .visibility(this.isShowBackFast ? Visibility.Visible : Visibility.None)
  1517. .animation({
  1518. duration: 500,
  1519. curve: 'ease-in-out' // 可选动画曲线
  1520. })
  1521. // 快进快退时长
  1522. Row() {
  1523. SymbolGlyph($r('sys.symbol.hand_tap_wave_2'))
  1524. .fontSize(20)
  1525. .fontColor([this.themeColor])
  1526. .alignSelf(ItemAlign.Center)
  1527. .margin({ left: 15 })
  1528. Text('快进快退时长')
  1529. .margin({ left: 8 })
  1530. .fontSize(15)
  1531. .fontColor(Color.Gray)
  1532. .fontWeight(480)
  1533. .layoutWeight(1)
  1534. SelectItem({
  1535. list: this.fastForwardSecond.map(opt => opt.label),
  1536. selected: this.fastForwardSecond.findIndex(opt => opt.value === this.fastForwardSeconds),
  1537. onChange: (index: number) => {
  1538. this.fastForwardSeconds = this.fastForwardSecond[index].value;
  1539. PreferencesUtil.put('fastForwardSeconds', this.fastForwardSeconds)
  1540. this.sendChangeEvent()
  1541. }
  1542. })
  1543. }
  1544. .height(55)
  1545. .opacity(this.isShowBackFast ? 1 : 0)
  1546. .visibility(this.isShowBackFast ? Visibility.Visible : Visibility.None)
  1547. .animation({
  1548. duration: 500,
  1549. curve: 'ease-in-out' // 可选动画曲线
  1550. })
  1551. .clickEffect({ level: ClickEffectLevel.HEAVY })
  1552. Line().width('100%').height(0.3).backgroundColor($r('app.color.index_tab_unselected_font_color'))
  1553. // 长按默认倍数
  1554. Row() {
  1555. SymbolGlyph($r('sys.symbol.timer'))
  1556. .fontSize(20)
  1557. .fontColor([this.themeColor])
  1558. .alignSelf(ItemAlign.Center)
  1559. .margin({ left: 15 })
  1560. Text('长按默认倍数')
  1561. .margin({ left: 8 })
  1562. .fontSize(15)
  1563. .fontColor(Color.Gray)
  1564. .fontWeight(480)
  1565. .layoutWeight(1)
  1566. Select([//倍速
  1567. { value: '0.25x' },
  1568. { value: '0.5x' },
  1569. { value: '0.75x' },
  1570. { value: '1x' },
  1571. { value: '1.25x' },
  1572. { value: '1.5x' },
  1573. { value: '1.75x' },
  1574. { value: '2x' },
  1575. { value: '2.5x' },
  1576. { value: '3x' }])
  1577. .font({ size: 15, weight: FontWeight.Medium })
  1578. .fontColor(Color.Gray)
  1579. .margin({right:18})
  1580. .selected(CommonConstants.video_speed_list.indexOf(this.longPressSpeed))
  1581. .value(Utility.optimizedFormat(this.longPressSpeed))
  1582. .onSelect(async (_index: number, text?: string | undefined) => {
  1583. let speed = parseFloat(text?.replace('x', '') || '1');
  1584. if (!CommonConstants.video_speed_list.includes(speed)) {
  1585. speed = 1;
  1586. }
  1587. this.longPressSpeed = speed
  1588. PreferencesUtil.put(SettingPage.LONG_PRESS_SPEED, this.longPressSpeed)
  1589. this.sendChangeEvent()
  1590. })
  1591. }
  1592. .height(55)
  1593. .clickEffect({level:ClickEffectLevel.HEAVY})
  1594. Line().width('100%').height(0.3).backgroundColor($r('app.color.index_tab_unselected_font_color'))
  1595. // 默认排序模式
  1596. Row() {
  1597. SymbolGlyph($r('sys.symbol.text_and_arrow_down'))
  1598. .fontSize(20)
  1599. .fontColor([this.themeColor])
  1600. .alignSelf(ItemAlign.Center)
  1601. .margin({ left: 15 })
  1602. Text('默认排序模式')
  1603. .margin({ left: 8 })
  1604. .fontSize(15)
  1605. .fontColor(Color.Gray)
  1606. .fontWeight(480)
  1607. .layoutWeight(1)
  1608. Select([
  1609. { value: CommonConstants.SORT_ARRAY[0] },
  1610. { value: CommonConstants.SORT_ARRAY[1] },
  1611. { value: CommonConstants.SORT_ARRAY[2] },
  1612. { value: CommonConstants.SORT_ARRAY[3] },
  1613. { value: CommonConstants.SORT_ARRAY[4] },
  1614. { value: CommonConstants.SORT_ARRAY[5] },
  1615. { value: CommonConstants.SORT_ARRAY[6] },
  1616. { value: CommonConstants.SORT_ARRAY[7] }])
  1617. .font({ size: 15, weight: FontWeight.Medium })
  1618. .fontColor(Color.Gray)
  1619. .margin({ right: 18 })
  1620. .selected(this.sortType)
  1621. .value(CommonConstants.SORT_ARRAY[this.sortType])
  1622. .onSelect(async (_index: number, text?: string | undefined) => {
  1623. this.sortType = _index
  1624. PreferencesUtil.put(SettingPage.SORT_TYPE, this.sortType)
  1625. this.sendChangeEvent()
  1626. })
  1627. }
  1628. .height(55)
  1629. .clickEffect({ level: ClickEffectLevel.HEAVY })
  1630. Line().width('100%').height(0.3).backgroundColor($r('app.color.index_tab_unselected_font_color'))
  1631. // 首页默认切换媒体库
  1632. Row() {
  1633. SymbolGlyph($r('sys.symbol.identify_song'))
  1634. .fontSize(20)
  1635. .fontColor([this.themeColor])
  1636. .alignSelf(ItemAlign.Center)
  1637. .margin({ left: 15 })
  1638. Text('首页默认媒体库')
  1639. .margin({ left: 8 })
  1640. .fontSize(15)
  1641. .fontColor(Color.Gray)
  1642. .fontWeight(480)
  1643. .layoutWeight(1)
  1644. Toggle({ type: ToggleType.Switch, isOn: this.idDefaultMediaKu })
  1645. .selectedColor(this.themeColor)
  1646. .clickEffect({level:ClickEffectLevel.LIGHT, scale: 0.5})
  1647. .switchPointColor(Color.White)
  1648. .margin({ right: 18 })
  1649. .onChange((checked: boolean) => {
  1650. this.idDefaultMediaKu = checked;
  1651. PreferencesUtil.put('idDefaultMediaKu', this.idDefaultMediaKu)
  1652. })
  1653. .width(50)
  1654. .height(30);
  1655. }
  1656. .height(55)
  1657. .clickEffect({ level: ClickEffectLevel.HEAVY })
  1658. Line().width('100%').height(0.3).backgroundColor($r('app.color.index_tab_unselected_font_color'))
  1659. // 列表显示音乐文件名
  1660. Row() {
  1661. SymbolGlyph($r('sys.symbol.text_clipboard'))
  1662. .fontSize(20)
  1663. .fontColor([this.themeColor])
  1664. .alignSelf(ItemAlign.Center)
  1665. .margin({ left: 15 })
  1666. Text('列表显示音乐文件名')
  1667. .margin({ left: 8 })
  1668. .fontSize(15)
  1669. .fontColor(Color.Gray)
  1670. .fontWeight(480)
  1671. .layoutWeight(1)
  1672. Toggle({ type: ToggleType.Switch, isOn: this.isShowFileName })
  1673. .selectedColor(this.themeColor)
  1674. .clickEffect({level:ClickEffectLevel.LIGHT, scale: 0.5})
  1675. .switchPointColor(Color.White)
  1676. .margin({ right: 18 })
  1677. .onChange((checked: boolean) => {
  1678. this.isShowFileName = checked;
  1679. PreferencesUtil.put('isShowFileName', this.isShowFileName)
  1680. this.sendChangeEvent()
  1681. })
  1682. .width(50)
  1683. .height(30);
  1684. }
  1685. .height(55)
  1686. .clickEffect({ level: ClickEffectLevel.HEAVY })
  1687. Line().width('100%').height(0.3).backgroundColor($r('app.color.index_tab_unselected_font_color'))
  1688. // 网盘播放不跳转到首页
  1689. Row() {
  1690. SymbolGlyph($r('sys.symbol.close_sidebar'))
  1691. .fontSize(20)
  1692. .fontColor([this.themeColor])
  1693. .alignSelf(ItemAlign.Center)
  1694. .margin({ left: 15 })
  1695. Text('网盘播放不跳转到首页')
  1696. .margin({ left: 8 })
  1697. .fontSize(15)
  1698. .fontColor(Color.Gray)
  1699. .fontWeight(480)
  1700. .layoutWeight(1)
  1701. Toggle({ type: ToggleType.Switch, isOn: this.isNoJumpToHome })
  1702. .selectedColor(this.themeColor)
  1703. .clickEffect({level:ClickEffectLevel.LIGHT, scale: 0.5})
  1704. .switchPointColor(Color.White)
  1705. .margin({ right: 18 })
  1706. .onChange((checked: boolean) => {
  1707. this.isNoJumpToHome = checked;
  1708. PreferencesUtil.put('isNoJumpToHome', this.isNoJumpToHome)
  1709. })
  1710. .width(50)
  1711. .height(30);
  1712. }
  1713. .height(55)
  1714. .clickEffect({ level: ClickEffectLevel.HEAVY })
  1715. Line().width('100%').height(0.3).backgroundColor($r('app.color.index_tab_unselected_font_color'))
  1716. // 日志上传开关
  1717. Row() {
  1718. SymbolGlyph($r('sys.symbol.cloud'))
  1719. .fontSize(20)
  1720. .fontColor([this.themeColor])
  1721. .alignSelf(ItemAlign.Center)
  1722. .margin({ left: 15 })
  1723. Column({ space: 4 }) {
  1724. Text('开启日志上传')
  1725. .fontSize(15)
  1726. .fontColor(Color.Gray)
  1727. .fontWeight(480)
  1728. Text('开启后,在关于我们页连点Logo 8次将收集并上传日志')
  1729. .fontSize(12)
  1730. .fontColor(Color.Gray)
  1731. }
  1732. .layoutWeight(1)
  1733. .alignItems(HorizontalAlign.Start)
  1734. .margin({ left: 8 })
  1735. Toggle({ type: ToggleType.Switch, isOn: this.isLogUploadEnabled })
  1736. .selectedColor(this.themeColor)
  1737. .clickEffect({level:ClickEffectLevel.LIGHT, scale: 0.5})
  1738. .switchPointColor(Color.White)
  1739. .margin({ right: 18 })
  1740. .onChange((checked: boolean) => {
  1741. this.isLogUploadEnabled = checked;
  1742. PreferencesUtil.put(SettingPage.LOG_UPLOAD_ENABLED, this.isLogUploadEnabled)
  1743. if (checked) {
  1744. const ok = this.ensureMeituUploadHandler(false);
  1745. if (ok) {
  1746. ToastUtil.showToast('已开启日志上传,关于我们页连点Logo 8次将上报')
  1747. }
  1748. } else {
  1749. this.registerLogUploadDisabled();
  1750. ToastUtil.showToast('已关闭日志上传')
  1751. }
  1752. })
  1753. .width(50)
  1754. .height(30);
  1755. }
  1756. .height(70)
  1757. .clickEffect({ level: ClickEffectLevel.HEAVY })
  1758. Line().width('100%').height(0.3).backgroundColor($r('app.color.index_tab_unselected_font_color'))
  1759. // 清除日志文件按钮 - 只在开启日志上传时显示
  1760. if (this.isLogUploadEnabled) {
  1761. Row() {
  1762. SymbolGlyph($r('sys.symbol.trash_fill'))
  1763. .fontSize(20)
  1764. .fontColor([this.themeColor])
  1765. .alignSelf(ItemAlign.Center)
  1766. .margin({ left: 15 })
  1767. Column({ space: 4 }) {
  1768. Text('清除日志文件')
  1769. .fontSize(15)
  1770. .fontColor(Color.Gray)
  1771. .fontWeight(480)
  1772. Text('清除本地保存的所有日志文件')
  1773. .fontSize(12)
  1774. .fontColor(Color.Gray)
  1775. }.layoutWeight(1).margin({ left: 8 })
  1776. .alignItems(HorizontalAlign.Start)
  1777. Text(this.isClearingLogs ? '清除中…' : '立即清除')
  1778. .margin({ right: 18 })
  1779. .fontSize(13)
  1780. .fontColor(this.themeColor)
  1781. }
  1782. .height(55)
  1783. .clickEffect({ level: ClickEffectLevel.HEAVY })
  1784. .onClick(() => {
  1785. this.handleClearLogFiles();
  1786. })
  1787. Line().width('100%').height(0.3).backgroundColor($r('app.color.index_tab_unselected_font_color'))
  1788. }
  1789. Row() {
  1790. SymbolGlyph($r('sys.symbol.trash'))
  1791. .fontSize(20)
  1792. .fontColor([this.themeColor])
  1793. .alignSelf(ItemAlign.Center)
  1794. .margin({ left: 15 })
  1795. Text('清除网盘缓存')
  1796. .margin({ left: 8 })
  1797. .fontSize(15)
  1798. .fontColor(Color.Gray)
  1799. .fontWeight(480)
  1800. .layoutWeight(1)
  1801. Text(this.isClearingCache ? '清理中…' : '立即清理')
  1802. .margin({ right: 18 })
  1803. .fontSize(13)
  1804. .fontColor(this.themeColor)
  1805. }
  1806. .height(55)
  1807. .clickEffect({ level: ClickEffectLevel.HEAVY })
  1808. .onClick(() => {
  1809. this.handleClearWebDavCache();
  1810. })
  1811. Line().width('100%').height(0.3).backgroundColor($r('app.color.index_tab_unselected_font_color'))
  1812. // WebDAV上传默认重复文件处理方式
  1813. Row() {
  1814. SymbolGlyph($r('sys.symbol.doc'))
  1815. .fontSize(20)
  1816. .fontColor([this.themeColor])
  1817. .alignSelf(ItemAlign.Center)
  1818. .margin({ left: 15 })
  1819. Text('上传重复文件处理')
  1820. .margin({ left: 8 })
  1821. .fontSize(15)
  1822. .fontColor(Color.Gray)
  1823. .fontWeight(480)
  1824. .layoutWeight(1)
  1825. Select([
  1826. { value: '跳过' },
  1827. { value: '覆盖' },
  1828. { value: '重命名' }])
  1829. .font({ size: 15, weight: FontWeight.Medium })
  1830. .fontColor(Color.Gray)
  1831. .margin({ right: 18 })
  1832. .selected(this.webdavUploadDuplicateAction === 'skip' ? 0 :
  1833. this.webdavUploadDuplicateAction === 'overwrite' ? 1 : 2)
  1834. .value(this.webdavUploadDuplicateAction === 'skip' ? '跳过' :
  1835. this.webdavUploadDuplicateAction === 'overwrite' ? '覆盖' : '重命名')
  1836. .onSelect((_index: number, text?: string | undefined) => {
  1837. if (_index === 0) {
  1838. this.webdavUploadDuplicateAction = 'skip';
  1839. } else if (_index === 1) {
  1840. this.webdavUploadDuplicateAction = 'overwrite';
  1841. } else {
  1842. this.webdavUploadDuplicateAction = 'rename';
  1843. }
  1844. PreferencesUtil.put(SettingPage.WEBDAV_UPLOAD_DUPLICATE_ACTION, this.webdavUploadDuplicateAction)
  1845. })
  1846. }
  1847. .height(55)
  1848. .clickEffect({ level: ClickEffectLevel.HEAVY })
  1849. Line().width('100%').height(0.3).backgroundColor($r('app.color.index_tab_unselected_font_color'))
  1850. // WebDAV上传完成后自动清理队列
  1851. Row() {
  1852. SymbolGlyph($r('sys.symbol.trash'))
  1853. .fontSize(20)
  1854. .fontColor([this.themeColor])
  1855. .alignSelf(ItemAlign.Center)
  1856. .margin({ left: 15 })
  1857. Text('上传完成自动清理队列')
  1858. .margin({ left: 8 })
  1859. .fontSize(15)
  1860. .fontColor(Color.Gray)
  1861. .fontWeight(480)
  1862. .layoutWeight(1)
  1863. Toggle({ type: ToggleType.Switch, isOn: this.webdavUploadAutoClear })
  1864. .selectedColor(this.themeColor)
  1865. .clickEffect({level:ClickEffectLevel.LIGHT, scale: 0.5})
  1866. .switchPointColor(Color.White)
  1867. .margin({ right: 18 })
  1868. .onChange((checked: boolean) => {
  1869. this.webdavUploadAutoClear = checked;
  1870. PreferencesUtil.put(SettingPage.WEBDAV_UPLOAD_AUTO_CLEAR, this.webdavUploadAutoClear)
  1871. })
  1872. .width(50)
  1873. .height(30);
  1874. }
  1875. .height(55)
  1876. .clickEffect({ level: ClickEffectLevel.HEAVY })
  1877. Line().width('100%').height(0.3).backgroundColor($r('app.color.index_tab_unselected_font_color'))
  1878. // WebDAV是否允许移动网络上传
  1879. Row() {
  1880. SymbolGlyph($r('sys.symbol.wifi'))
  1881. .fontSize(20)
  1882. .fontColor([this.themeColor])
  1883. .alignSelf(ItemAlign.Center)
  1884. .margin({ left: 15 })
  1885. Text('允许移动网络上传')
  1886. .margin({ left: 8 })
  1887. .fontSize(15)
  1888. .fontColor(Color.Gray)
  1889. .fontWeight(480)
  1890. .layoutWeight(1)
  1891. Toggle({ type: ToggleType.Switch, isOn: this.webdavUploadAllowMobile })
  1892. .selectedColor(this.themeColor)
  1893. .clickEffect({level:ClickEffectLevel.LIGHT, scale: 0.5})
  1894. .switchPointColor(Color.White)
  1895. .margin({ right: 18 })
  1896. .onChange((checked: boolean) => {
  1897. this.webdavUploadAllowMobile = checked;
  1898. PreferencesUtil.put(SettingPage.WEBDAV_UPLOAD_ALLOW_MOBILE, this.webdavUploadAllowMobile)
  1899. })
  1900. .width(50)
  1901. .height(30);
  1902. }
  1903. .height(55)
  1904. .clickEffect({ level: ClickEffectLevel.HEAVY })
  1905. Line().width('100%').height(0.3).backgroundColor($r('app.color.index_tab_unselected_font_color'))
  1906. // WebDAV上传失败自动重试次数
  1907. Row() {
  1908. SymbolGlyph($r('sys.symbol.arrow_clockwise'))
  1909. .fontSize(20)
  1910. .fontColor([this.themeColor])
  1911. .alignSelf(ItemAlign.Center)
  1912. .margin({ left: 15 })
  1913. Text('上传失败重试次数')
  1914. .margin({ left: 8 })
  1915. .fontSize(15)
  1916. .fontColor(Color.Gray)
  1917. .fontWeight(480)
  1918. .layoutWeight(1)
  1919. Select([
  1920. { value: '0次' },
  1921. { value: '1次' },
  1922. { value: '2次' },
  1923. { value: '3次' },
  1924. { value: '5次' }])
  1925. .font({ size: 15, weight: FontWeight.Medium })
  1926. .fontColor(Color.Gray)
  1927. .margin({ right: 18 })
  1928. .selected(this.webdavUploadRetryCount === 0 ? 0 :
  1929. this.webdavUploadRetryCount === 1 ? 1 :
  1930. this.webdavUploadRetryCount === 2 ? 2 :
  1931. this.webdavUploadRetryCount === 3 ? 3 : 4)
  1932. .value(this.webdavUploadRetryCount === 0 ? '0次' :
  1933. this.webdavUploadRetryCount === 1 ? '1次' :
  1934. this.webdavUploadRetryCount === 2 ? '2次' :
  1935. this.webdavUploadRetryCount === 3 ? '3次' : '5次')
  1936. .onSelect((_index: number, text?: string | undefined) => {
  1937. if (_index === 0) {
  1938. this.webdavUploadRetryCount = 0;
  1939. } else if (_index === 1) {
  1940. this.webdavUploadRetryCount = 1;
  1941. } else if (_index === 2) {
  1942. this.webdavUploadRetryCount = 2;
  1943. } else if (_index === 3) {
  1944. this.webdavUploadRetryCount = 3;
  1945. } else {
  1946. this.webdavUploadRetryCount = 5;
  1947. }
  1948. PreferencesUtil.put(SettingPage.WEBDAV_UPLOAD_RETRY_COUNT, this.webdavUploadRetryCount)
  1949. })
  1950. }
  1951. .height(55)
  1952. .clickEffect({ level: ClickEffectLevel.HEAVY })
  1953. Line().width('100%').height(0.3).backgroundColor($r('app.color.index_tab_unselected_font_color'))
  1954. // 长歌名滚动
  1955. Row() {
  1956. SymbolGlyph($r('sys.symbol.close_sidebar'))
  1957. .fontSize(20)
  1958. .fontColor([this.themeColor])
  1959. .alignSelf(ItemAlign.Center)
  1960. .margin({ left: 15 })
  1961. Text('长歌名滚动')
  1962. .margin({ left: 8 })
  1963. .fontSize(15)
  1964. .fontColor(Color.Gray)
  1965. .fontWeight(480)
  1966. .layoutWeight(1)
  1967. Toggle({ type: ToggleType.Switch, isOn: this.isLongNameRoLL })
  1968. .selectedColor(this.themeColor)
  1969. .clickEffect({level:ClickEffectLevel.LIGHT, scale: 0.5})
  1970. .switchPointColor(Color.White)
  1971. .margin({ right: 18 })
  1972. .onChange((checked: boolean) => {
  1973. this.isLongNameRoLL = checked;
  1974. PreferencesUtil.put('isLongNameRoLL', this.isLongNameRoLL)
  1975. this.sendChangeEvent()
  1976. })
  1977. .width(50)
  1978. .height(30);
  1979. }
  1980. .height(55)
  1981. .clickEffect({ level: ClickEffectLevel.HEAVY })
  1982. Line().width('100%').height(0.3).backgroundColor($r('app.color.index_tab_unselected_font_color'))
  1983. // 音量优化
  1984. Row() {
  1985. SymbolGlyph($r('sys.symbol.speaker'))
  1986. .fontSize(20)
  1987. .fontColor([this.themeColor])
  1988. .alignSelf(ItemAlign.Center)
  1989. .margin({ left: 15 })
  1990. Text('音量优化')
  1991. .margin({ left: 8 })
  1992. .fontSize(15)
  1993. .fontColor(Color.Gray)
  1994. .fontWeight(480)
  1995. .layoutWeight(1)
  1996. Toggle({ type: ToggleType.Switch, isOn: this.volumeSmall })
  1997. .selectedColor(this.themeColor)
  1998. .clickEffect({level:ClickEffectLevel.LIGHT, scale: 0.5})
  1999. .switchPointColor(Color.White)
  2000. .margin({ right: 18 })
  2001. .onChange((checked: boolean) => {
  2002. this.volumeSmall = checked;
  2003. if(this.volumeSmall){
  2004. ToastUtil.showToast('打开音量优化会比平时音量声音低些')
  2005. }
  2006. PreferencesUtil.put('volumeSmall', this.volumeSmall)
  2007. })
  2008. .width(50)
  2009. .height(30);
  2010. }
  2011. .height(55)
  2012. .clickEffect({ level: ClickEffectLevel.HEAVY })
  2013. Line().width('100%').height(0.3).backgroundColor($r('app.color.index_tab_unselected_font_color'))
  2014. // 智能解析
  2015. Row() {
  2016. SymbolGlyph($r('sys.symbol.t_circle'))
  2017. .fontSize(20)
  2018. .fontColor([this.themeColor])
  2019. .alignSelf(ItemAlign.Center)
  2020. .margin({ left: 15 })
  2021. Text('智能文件名解析歌曲标签')
  2022. .margin({ left: 8 })
  2023. .fontSize(15)
  2024. .fontColor(Color.Gray)
  2025. .fontWeight(480)
  2026. .layoutWeight(1)
  2027. Toggle({ type: ToggleType.Switch, isOn: this.autoParseMusicName })
  2028. .selectedColor(this.themeColor)
  2029. .clickEffect({level:ClickEffectLevel.LIGHT, scale: 0.5})
  2030. .switchPointColor(Color.White)
  2031. .margin({ right: 18 })
  2032. .onChange((checked: boolean) => {
  2033. this.autoParseMusicName = checked;
  2034. PreferencesUtil.put('autoParseMusicName', this.autoParseMusicName)
  2035. })
  2036. .width(50)
  2037. .height(30);
  2038. }
  2039. .height(55)
  2040. .clickEffect({ level: ClickEffectLevel.HEAVY })
  2041. Line().width('100%').height(0.3).backgroundColor($r('app.color.index_tab_unselected_font_color'))
  2042. // 保存播放模式
  2043. Row() {
  2044. SymbolGlyph($r('sys.symbol.clock'))
  2045. .fontSize(20)
  2046. .fontColor([this.themeColor])
  2047. .alignSelf(ItemAlign.Center)
  2048. .margin({ left: 15 })
  2049. Text('保存播放模式')
  2050. .margin({ left: 8 })
  2051. .fontSize(15)
  2052. .fontColor(Color.Gray)
  2053. .fontWeight(480)
  2054. .layoutWeight(1)
  2055. Toggle({ type: ToggleType.Switch, isOn: this.isSavePlayMode })
  2056. .selectedColor(this.themeColor)
  2057. .clickEffect({level:ClickEffectLevel.LIGHT, scale: 0.5})
  2058. .switchPointColor(Color.White)
  2059. .margin({ right: 18 })
  2060. .onChange((checked: boolean) => {
  2061. this.isSavePlayMode = checked;
  2062. PreferencesUtil.put(SettingPage.iS_SAVE_PLAY_MODE, this.isSavePlayMode)
  2063. })
  2064. .width(50)
  2065. .height(30);
  2066. }
  2067. .height(55)
  2068. .clickEffect({ level: ClickEffectLevel.HEAVY })
  2069. Line().width('100%').height(0.3).backgroundColor($r('app.color.index_tab_unselected_font_color'))
  2070. Row() {
  2071. SymbolGlyph($r('sys.symbol.sun_max'))
  2072. .fontSize(20)
  2073. .fontColor([this.themeColor])
  2074. .alignSelf(ItemAlign.Center)
  2075. .margin({ left: 15 })
  2076. Text('与其他应用同时播放')
  2077. .margin({ left: 8 })
  2078. .fontSize(15)
  2079. .fontColor(Color.Gray)
  2080. .fontWeight(480)
  2081. .layoutWeight(1)
  2082. Toggle({ type: ToggleType.Switch, isOn: this.isSameTimePlay })
  2083. .selectedColor(this.themeColor)
  2084. .switchPointColor(Color.White)
  2085. .margin({ right: 18 })
  2086. .clickEffect({level:ClickEffectLevel.LIGHT, scale: 0.5})
  2087. .onChange((checked: boolean) => {
  2088. this.isSameTimePlay = checked;
  2089. PreferencesUtil.put(SettingPage.IS_SAMETIME_PLAY, this.isSameTimePlay)
  2090. this.sendChangeEvent()
  2091. })
  2092. .width(50)
  2093. .height(30);
  2094. }
  2095. .height(55).clickEffect({ level: ClickEffectLevel.HEAVY })
  2096. // .visibility(Visibility.None)
  2097. Line().width('100%').height(0.3).backgroundColor($r('app.color.index_tab_unselected_font_color'))
  2098. // 播放背景随音乐封面
  2099. Row() {
  2100. SymbolGlyph($r('sys.symbol.paperplane'))
  2101. .fontSize(20)
  2102. .fontColor([this.themeColor])
  2103. .alignSelf(ItemAlign.Center)
  2104. .margin({ left: 15 })
  2105. Text('播放背景随音乐封面')
  2106. .margin({ left: 8 })
  2107. .fontSize(15)
  2108. .fontColor(Color.Gray)
  2109. .fontWeight(480)
  2110. .layoutWeight(1)
  2111. Toggle({ type: ToggleType.Switch, isOn: this.isMusicBGCover })
  2112. .selectedColor(this.themeColor)
  2113. .switchPointColor(Color.White)
  2114. .clickEffect({level:ClickEffectLevel.LIGHT, scale: 0.5})
  2115. .margin({ right: 18 })
  2116. .onChange((checked: boolean) => {
  2117. this.isMusicBGCover = checked;
  2118. PreferencesUtil.put(SettingPage.iS_MUSIC_BG_COVER, this.isMusicBGCover)
  2119. })
  2120. .width(50)
  2121. .height(30);
  2122. }
  2123. .height(55)
  2124. .clickEffect({ level: ClickEffectLevel.HEAVY })
  2125. }
  2126. .transition(TransitionEffect.move(TransitionEdge.BOTTOM)
  2127. .animation({ duration: 500, curve: Curve.Ease, delay: 400 }))
  2128. .backgroundColor($r('app.color.settings_background_main'))
  2129. .borderRadius(20)
  2130. .margin({
  2131. left: 0,
  2132. right: 0,
  2133. top: 10,
  2134. bottom: 10
  2135. })
  2136. .padding(0)
  2137. // API设置分组
  2138. this.apiBuilder()
  2139. //设置教程
  2140. this.jcBuilder()
  2141. //显示与隐藏设置
  2142. this.xsBuilder()
  2143. //空白
  2144. Column() {
  2145. Blank()
  2146. .height(88)
  2147. }.height(88)
  2148. }
  2149. .margin({
  2150. left: this.currentBreakpoint !== BreakpointTypeEnum.SM ? 35 : 20,
  2151. right: this.currentBreakpoint !== BreakpointTypeEnum.SM ? 35 : 20,
  2152. top: 20,
  2153. bottom: 20
  2154. })
  2155. .justifyContent(FlexAlign.Start)
  2156. }
  2157. .scrollBar(BarState.Auto)
  2158. .width('100%')
  2159. .margin({ bottom: 10 })
  2160. .backgroundColor($r('app.color.settings_background'))
  2161. }
  2162. .layoutWeight(1)
  2163. .height('100%')
  2164. .expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.BOTTOM])
  2165. }
  2166. @Builder
  2167. xsBuilder() {
  2168. // 显示和隐藏分组
  2169. Column() {
  2170. Row() {
  2171. Text('显示隐藏')
  2172. .margin({ left: 18, right: 20 })
  2173. .fontSize(16)
  2174. .fontColor(Color.Gray)
  2175. .fontWeight(480)
  2176. .layoutWeight(1)
  2177. }
  2178. .onClick(() => {
  2179. ToastUtil.showToast(this.appIdentifier)
  2180. PreferencesUtil.putSync('isShowWX',true)
  2181. })
  2182. .height(48)
  2183. Line().width('100%').height(0.3).backgroundColor($r('app.color.index_tab_unselected_font_color'))
  2184. Row() {
  2185. SymbolGlyph($r('sys.symbol.text_clipboard'))
  2186. .fontSize(20)
  2187. .fontColor([this.themeColor])
  2188. .alignSelf(ItemAlign.Center)
  2189. .margin({ left: 15 })
  2190. Text('滚动隐藏标题栏')
  2191. .margin({ left: 8 })
  2192. .fontSize(15)
  2193. .fontColor(Color.Gray)
  2194. .fontWeight(480)
  2195. .layoutWeight(1)
  2196. Toggle({ type: ToggleType.Switch, isOn: this.autoHideTitle })
  2197. .selectedColor(this.themeColor)
  2198. .clickEffect({level:ClickEffectLevel.LIGHT, scale: 0.5})
  2199. .switchPointColor(Color.White)
  2200. .margin({ right: 18 })
  2201. .onChange((checked: boolean) => {
  2202. this.autoHideTitle = checked;
  2203. PreferencesUtil.put('autoHideTitle', this.autoHideTitle)
  2204. this.sendChangeEvent()
  2205. })
  2206. .width(50)
  2207. .height(30);
  2208. }
  2209. .height(55)
  2210. .clickEffect({ level: ClickEffectLevel.HEAVY })
  2211. Line().width('100%').height(0.3).backgroundColor($r('app.color.index_tab_unselected_font_color'))
  2212. // Row() {
  2213. // SymbolGlyph($r('sys.symbol.label'))
  2214. // .fontSize(20)
  2215. // .fontColor([this.themeColor])
  2216. // .alignSelf(ItemAlign.Center)
  2217. // .margin({ left: 15 })
  2218. // Text('显示播放全部')
  2219. // .margin({ left: 8 })
  2220. // .fontSize(15)
  2221. // .fontColor(Color.Gray)
  2222. // .fontWeight(480)
  2223. // .layoutWeight(1)
  2224. // Toggle({ type: ToggleType.Switch, isOn: this.isShowAllBar })
  2225. // .selectedColor(this.themeColor)
  2226. // .switchPointColor(Color.White)
  2227. // .margin({ right: 18 })
  2228. // .clickEffect({level:ClickEffectLevel.LIGHT, scale: 0.5})
  2229. // .onChange((checked: boolean) => {
  2230. // this.isShowAllBar = checked;
  2231. // PreferencesUtil.put(SettingPage.IS_SHOW_ALLBAR, this.isShowAllBar)
  2232. // this.sendChangeEvent()
  2233. // })
  2234. // .width(50)
  2235. // .height(30);
  2236. // }
  2237. // .height(55)
  2238. // .clickEffect({ level: ClickEffectLevel.HEAVY })
  2239. //
  2240. // Line().width('100%').height(0.3).backgroundColor($r('app.color.index_tab_unselected_font_color'))
  2241. // 显示私密音频
  2242. // Row() {
  2243. // SymbolGlyph($r('sys.symbol.lock'))
  2244. // .fontSize(20)
  2245. // .fontColor([this.themeColor])
  2246. // .alignSelf(ItemAlign.Center)
  2247. // .margin({ left: 15 })
  2248. // Text('显示私密音频')
  2249. // .margin({ left: 8 })
  2250. // .fontSize(15)
  2251. // .fontColor(Color.Gray)
  2252. // .fontWeight(480)
  2253. // .layoutWeight(1)
  2254. // Toggle({ type: ToggleType.Switch, isOn: this.isShowSimi })
  2255. // .selectedColor(this.themeColor)
  2256. // .switchPointColor(Color.White)
  2257. // .margin({ right: 18 })
  2258. // .clickEffect({level:ClickEffectLevel.LIGHT, scale: 0.5})
  2259. // .onChange((checked: boolean) => {
  2260. // this.isShowSimi = checked;
  2261. // PreferencesUtil.put(SettingPage.IS_SHOW_SIMI, this.isShowSimi)
  2262. // this.sendChangeEvent()
  2263. // })
  2264. // .width(50)
  2265. // .height(30);
  2266. // }
  2267. // .height(55)
  2268. // .clickEffect({ level: ClickEffectLevel.HEAVY })
  2269. //
  2270. // Line().width('100%').height(0.3).backgroundColor($r('app.color.index_tab_unselected_font_color'))
  2271. // 播放页单行歌词
  2272. Row() {
  2273. SymbolGlyph($r('sys.symbol.close_sidebar'))
  2274. .fontSize(20)
  2275. .fontColor([this.themeColor])
  2276. .alignSelf(ItemAlign.Center)
  2277. .margin({ left: 15 })
  2278. Text('播放页单行歌词')
  2279. .margin({ left: 8 })
  2280. .fontSize(15)
  2281. .fontColor(Color.Gray)
  2282. .fontWeight(480)
  2283. .layoutWeight(1)
  2284. Toggle({ type: ToggleType.Switch, isOn: this.isShowSingleLineLyric })
  2285. .selectedColor(this.themeColor)
  2286. .switchPointColor(Color.White)
  2287. .margin({ right: 18 })
  2288. .clickEffect({level:ClickEffectLevel.LIGHT, scale: 0.5})
  2289. .onChange((checked: boolean) => {
  2290. this.isShowSingleLineLyric = checked;
  2291. PreferencesUtil.put(SettingPage.IS_SHOW_SLLYRIC, this.isShowSingleLineLyric)
  2292. this.sendChangeEvent()
  2293. })
  2294. .width(50)
  2295. .height(30);
  2296. }
  2297. .height(55)
  2298. .clickEffect({ level: ClickEffectLevel.HEAVY })
  2299. Line().width('100%').height(0.3).backgroundColor($r('app.color.index_tab_unselected_font_color'))
  2300. // 二级菜单新风格
  2301. // Row() {
  2302. // SymbolGlyph($r('sys.symbol.satellite_map'))
  2303. // .fontSize(20)
  2304. // .fontColor([this.themeColor])
  2305. // .alignSelf(ItemAlign.Center)
  2306. // .margin({ left: 15 })
  2307. // Text('二级菜单新风格')
  2308. // .margin({ left: 8 })
  2309. // .fontSize(15)
  2310. // .fontColor(Color.Gray)
  2311. // .fontWeight(480)
  2312. // .layoutWeight(1)
  2313. // Toggle({ type: ToggleType.Switch, isOn: this.isShowHeader })
  2314. // .selectedColor(this.themeColor)
  2315. // .switchPointColor(Color.White)
  2316. // .margin({ right: 18 })
  2317. // .clickEffect({level:ClickEffectLevel.LIGHT, scale: 0.5})
  2318. // .onChange((checked: boolean) => {
  2319. // this.isShowHeader = checked;
  2320. // PreferencesUtil.put(SettingPage.IS_SHOW_HEADER, this.isShowHeader)
  2321. // this.sendChangeEvent()
  2322. // })
  2323. // .width(50)
  2324. // .height(30);
  2325. // }
  2326. // .height(55)
  2327. // .clickEffect({ level: ClickEffectLevel.HEAVY })
  2328. //
  2329. // Line().width('100%').height(0.3).backgroundColor($r('app.color.index_tab_unselected_font_color'))
  2330. //播控条显示上一首按钮
  2331. Row() {
  2332. SymbolGlyph($r('sys.symbol.arrow_left'))
  2333. .fontSize(20)
  2334. .fontColor([this.themeColor])
  2335. .alignSelf(ItemAlign.Center)
  2336. .margin({ left: 15 })
  2337. Text('播控条上一首按钮')
  2338. .margin({ left: 8 })
  2339. .fontSize(15)
  2340. .fontColor(Color.Gray)
  2341. .fontWeight(480)
  2342. .layoutWeight(1)
  2343. Toggle({ type: ToggleType.Switch, isOn: this.isShowPrecious })
  2344. .selectedColor(this.themeColor)
  2345. .switchPointColor(Color.White)
  2346. .margin({ right: 18 })
  2347. .clickEffect({level:ClickEffectLevel.LIGHT, scale: 0.5})
  2348. .onChange((checked: boolean) => {
  2349. this.isShowPrecious = checked;
  2350. PreferencesUtil.put('isShowPrecious', this.isShowPrecious)
  2351. this.sendChangeEvent()
  2352. })
  2353. .width(50)
  2354. .height(30);
  2355. }
  2356. .height(55)
  2357. .clickEffect({ level: ClickEffectLevel.HEAVY })
  2358. Line().width('100%').height(0.3).backgroundColor($r('app.color.index_tab_unselected_font_color'))
  2359. // 播放页返回键
  2360. Row() {
  2361. SymbolGlyph($r('sys.symbol.arrow_left'))
  2362. .fontSize(20)
  2363. .fontColor([this.themeColor])
  2364. .alignSelf(ItemAlign.Center)
  2365. .margin({ left: 15 })
  2366. Text('显示播放页返回键')
  2367. .margin({ left: 8 })
  2368. .fontSize(15)
  2369. .fontColor(Color.Gray)
  2370. .fontWeight(480)
  2371. .layoutWeight(1)
  2372. Toggle({ type: ToggleType.Switch, isOn: this.isShowPlayPageBack })
  2373. .selectedColor(this.themeColor)
  2374. .switchPointColor(Color.White)
  2375. .margin({ right: 18 })
  2376. .clickEffect({level:ClickEffectLevel.LIGHT, scale: 0.5})
  2377. .onChange((checked: boolean) => {
  2378. this.isShowPlayPageBack = checked;
  2379. PreferencesUtil.put(SettingPage.IS_SHOW_PLAYPAGE_BACK, this.isShowPlayPageBack)
  2380. this.sendChangeEvent()
  2381. })
  2382. .width(50)
  2383. .height(30);
  2384. }
  2385. .height(55)
  2386. .clickEffect({ level: ClickEffectLevel.HEAVY })
  2387. Line().width('100%').height(0.3).backgroundColor($r('app.color.index_tab_unselected_font_color'))
  2388. // // 自动隐藏进度条两侧的按钮
  2389. // Row() {
  2390. // SymbolGlyph($r('sys.symbol.sun_max'))
  2391. // .fontSize(20)
  2392. // .fontColor([this.themeColor])
  2393. // .alignSelf(ItemAlign.Center)
  2394. // .margin({ left: 15 })
  2395. // Text('自动隐藏进度条两侧的按钮')
  2396. // .margin({ left: 8 })
  2397. // .fontSize(15)
  2398. // .fontColor(Color.Gray)
  2399. // .fontWeight(480)
  2400. // .layoutWeight(1)
  2401. // Toggle({ type: ToggleType.Switch, isOn: this.is_auto_hide_progress })
  2402. // .selectedColor(this.themeColor)
  2403. // .switchPointColor(Color.White)
  2404. // .margin({ right: 18 })
  2405. // .clickEffect({level:ClickEffectLevel.LIGHT, scale: 0.5})
  2406. // .onChange((checked: boolean) => {
  2407. // this.is_auto_hide_progress = checked;
  2408. // PreferencesUtil.put(SettingPage.IS_AUTO_HIDE_PROGRESS, this.is_auto_hide_progress)
  2409. // this.sendChangeEvent()
  2410. // })
  2411. // .width(50)
  2412. // .height(30);
  2413. // }
  2414. // .height(55)
  2415. // .clickEffect({ level: ClickEffectLevel.HEAVY })
  2416. //
  2417. // Line().width('100%').height(0.3).backgroundColor($r('app.color.index_tab_unselected_font_color'))
  2418. // 显示我的收藏
  2419. Row() {
  2420. SymbolGlyph($r('sys.symbol.heart'))
  2421. .fontSize(20)
  2422. .fontColor([this.themeColor])
  2423. .alignSelf(ItemAlign.Center)
  2424. .margin({ left: 15 })
  2425. Text('显示我的收藏')
  2426. .margin({ left: 8 })
  2427. .fontSize(15)
  2428. .fontColor(Color.Gray)
  2429. .fontWeight(480)
  2430. .layoutWeight(1)
  2431. Toggle({ type: ToggleType.Switch, isOn: this.isShowFAV })
  2432. .selectedColor(this.themeColor)
  2433. .switchPointColor(Color.White)
  2434. .margin({ right: 18 })
  2435. .clickEffect({level:ClickEffectLevel.LIGHT, scale: 0.5})
  2436. .onChange((checked: boolean) => {
  2437. this.isShowFAV = checked;
  2438. PreferencesUtil.put(SettingPage.IS_SHOW_FAV, this.isShowFAV)
  2439. this.sendChangeEvent()
  2440. })
  2441. .width(50)
  2442. .height(30);
  2443. }
  2444. .height(55)
  2445. .clickEffect({ level: ClickEffectLevel.HEAVY })
  2446. Line().width('100%').height(0.3).backgroundColor($r('app.color.index_tab_unselected_font_color'))
  2447. // 显示最近播放
  2448. Row() {
  2449. SymbolGlyph($r('sys.symbol.clock'))
  2450. .fontSize(20)
  2451. .fontColor([this.themeColor])
  2452. .alignSelf(ItemAlign.Center)
  2453. .margin({ left: 15 })
  2454. Text('显示最近播放')
  2455. .margin({ left: 8 })
  2456. .fontSize(15)
  2457. .fontColor(Color.Gray)
  2458. .fontWeight(480)
  2459. .layoutWeight(1)
  2460. Toggle({ type: ToggleType.Switch, isOn: this.isShowHistory })
  2461. .selectedColor(this.themeColor)
  2462. .switchPointColor(Color.White)
  2463. .margin({ right: 18 })
  2464. .clickEffect({level:ClickEffectLevel.LIGHT, scale: 0.5})
  2465. .onChange((checked: boolean) => {
  2466. this.isShowHistory = checked;
  2467. PreferencesUtil.put(SettingPage.IS_SHOW_HISTORY, this.isShowHistory)
  2468. this.sendChangeEvent()
  2469. })
  2470. .width(50)
  2471. .height(30);
  2472. }
  2473. .height(55)
  2474. .clickEffect({ level: ClickEffectLevel.HEAVY })
  2475. }
  2476. .transition(TransitionEffect.move(TransitionEdge.BOTTOM)
  2477. .animation({ duration: 500, curve: Curve.Ease, delay: 600 }))
  2478. .backgroundColor($r('app.color.settings_background_main'))
  2479. .borderRadius(20)
  2480. .margin({
  2481. left: 0,
  2482. right: 0,
  2483. top: 10,
  2484. bottom: 20
  2485. })
  2486. .padding(0)
  2487. }
  2488. @Builder
  2489. jcBuilder() {
  2490. //设置教程
  2491. Button({ type: ButtonType.Capsule, stateEffect: true }) {
  2492. Column() {
  2493. Row() {
  2494. SymbolGlyph($r('sys.symbol.hand_draw'))
  2495. .fontSize(20)
  2496. .fontColor([this.themeColor])
  2497. .alignSelf(ItemAlign.Center)
  2498. .margin({ left: 15 })
  2499. Text('设置教程:')
  2500. .margin({ left: 8 })
  2501. .fontSize(15)
  2502. .fontColor(Color.Gray)
  2503. .fontWeight(480)
  2504. Text('点击进Q群讨论')
  2505. .margin({ right: 10 })
  2506. .fontSize(15)
  2507. .fontColor(Color.Gray)
  2508. .layoutWeight(1)
  2509. Blank()
  2510. // 右侧箭头
  2511. Image($r('app.media.arrow_right'))
  2512. .width(22)
  2513. .height(22)
  2514. .margin({ left: 20, right: 20 })
  2515. .align(Alignment.Center)
  2516. }
  2517. .height(55)
  2518. }
  2519. }
  2520. .clickEffect({ level: ClickEffectLevel.HEAVY })
  2521. .onClick(() => {
  2522. const qqUrl =
  2523. `mqqapi://card/show_pslcard?src_type=internal&version=1&uin=${CommonConstants.QQ_GROUP}&card_type=group&source=external`
  2524. let context = this.getUIContext().getHostContext() as common.UIAbilityContext
  2525. context.openLink(qqUrl, {})
  2526. })
  2527. .backgroundColor($r('app.color.settings_background_main'))
  2528. .borderRadius(15)
  2529. .margin({ top: 0, bottom: 20 })
  2530. .padding(0)
  2531. .transition(TransitionEffect.move(TransitionEdge.BOTTOM)
  2532. .animation({ duration: 500, curve: Curve.Ease, delay: 220 }))
  2533. }
  2534. @Builder
  2535. apiBuilder() {
  2536. // API设置分组
  2537. Column() {
  2538. Row() {
  2539. Text(){
  2540. Span('API设置')
  2541. Span('\n(请注意:使用此功能您需拥有相关著作人的授权,否则可能导致版权法律纠纷,本软件不提供任何API,本软件对此不负任何责任。)')
  2542. .fontColor(this.themeColor).fontSize(14)
  2543. // .fontStyle(FontStyle.Italic)
  2544. }
  2545. .margin({ left: 18, right: 20 })
  2546. .fontSize(16)
  2547. .fontColor(Color.Gray)
  2548. .fontWeight(480)
  2549. .layoutWeight(1)
  2550. }
  2551. .height(82)
  2552. Line().width('100%').height(0.3).backgroundColor($r('app.color.index_tab_unselected_font_color'))
  2553. // 歌词API
  2554. Button({ type: ButtonType.Normal, stateEffect: true }) {
  2555. Row() {
  2556. SymbolGlyph($r('sys.symbol.lightbulb'))
  2557. .fontSize(20)
  2558. .fontColor([this.themeColor])
  2559. .alignSelf(ItemAlign.Center)
  2560. .margin({ left: 15 })
  2561. Text('歌词:')
  2562. .margin({ left: 8, right: 6 })
  2563. .fontSize(15)
  2564. .fontColor(Color.Gray)
  2565. Text(this.lyricApiUrl)
  2566. .margin({ right: 10 })
  2567. .fontSize(15)
  2568. .fontColor(Color.Gray)
  2569. .layoutWeight(1)
  2570. Image(this.isDarkMode ? $r('app.media.rename2') : $r('app.media.rename'))
  2571. .width(20)
  2572. .height(20)
  2573. .margin({ right: 18 })
  2574. }
  2575. }
  2576. .clickEffect({ level: ClickEffectLevel.HEAVY })
  2577. .backgroundColor(Color.Transparent)
  2578. .onClick(() => {
  2579. this.apiDialogType = 'lyric'
  2580. this.tempApiUrl = this.lyricApiUrl
  2581. this.apiDialogController.open()
  2582. })
  2583. .height(55)
  2584. Line().width('100%').height(0.3).backgroundColor($r('app.color.index_tab_unselected_font_color'))
  2585. // 封面API
  2586. Button({ type: ButtonType.Normal, stateEffect: true }) {
  2587. Row() {
  2588. SymbolGlyph($r('sys.symbol.picture'))
  2589. .fontSize(20)
  2590. .fontColor([this.themeColor])
  2591. .alignSelf(ItemAlign.Center)
  2592. .margin({ left: 15 })
  2593. Text('封面:')
  2594. .margin({ left: 8, right: 6 })
  2595. .fontSize(15)
  2596. .fontColor(Color.Gray)
  2597. Text(this.coverApiUrl)
  2598. .margin({ right: 10 })
  2599. .fontSize(15)
  2600. .fontColor(Color.Gray)
  2601. .layoutWeight(1)
  2602. Image(this.isDarkMode ? $r('app.media.rename2') : $r('app.media.rename'))
  2603. .width(20)
  2604. .height(20)
  2605. .margin({ right: 18 })
  2606. }
  2607. }
  2608. .clickEffect({ level: ClickEffectLevel.HEAVY })
  2609. .backgroundColor(Color.Transparent)
  2610. .onClick(() => {
  2611. this.apiDialogType = 'cover'
  2612. this.tempApiUrl = this.coverApiUrl
  2613. this.apiDialogController.open()
  2614. })
  2615. .height(55)
  2616. }
  2617. .transition(TransitionEffect.move(TransitionEdge.BOTTOM)
  2618. .animation({ duration: 500, curve: Curve.Ease, delay: 200 }))
  2619. .backgroundColor($r('app.color.settings_background_main'))
  2620. .borderRadius(20)
  2621. .margin({
  2622. left: 0,
  2623. right: 0,
  2624. top: 10,
  2625. bottom: 20
  2626. })
  2627. .padding(0)
  2628. }
  2629. @Builder
  2630. customizeICONSheet() {
  2631. Scroll() {
  2632. Column() {
  2633. CustomizeICON({
  2634. iconIndex:this.iconCurrentID,
  2635. iconArray:this.iconArray,
  2636. onIconChange:(iconId:string,iconUrl:string)=>{
  2637. this.iconCurrentID = iconId
  2638. PreferencesUtil.put('iconCurrentID', this.iconCurrentID)
  2639. PreferencesUtil.put('iconCurrentUrl', iconUrl)
  2640. this.sendChangeEvent()
  2641. }
  2642. })
  2643. }
  2644. }
  2645. .width('100%')
  2646. .height('100%')
  2647. }
  2648. //发送广播通知更新UI
  2649. sendChangeEvent() {
  2650. const eventData: emitter.EventData = {};
  2651. emitter.emit({ eventId: EventConstants.EVENT_SETTING_UPDATE }, eventData); // 发送广播通知更新doSwipBack
  2652. }
  2653. goSelectImage() {
  2654. let selectUris: Array<string> = [];
  2655. let photoPicker = new photoAccessHelper.PhotoViewPicker();
  2656. let photoSelectOptions = new photoAccessHelper.PhotoSelectOptions();
  2657. photoSelectOptions.MIMEType = photoAccessHelper.PhotoViewMIMETypes.IMAGE_TYPE; // 过滤选择媒体文件类型为IMAGE
  2658. photoSelectOptions.maxSelectNumber = 1; // 选择媒体文件的最大数目
  2659. photoPicker.select(photoSelectOptions).then(async (photoSelectResult: photoAccessHelper.PhotoSelectResult) => {
  2660. //用一个全局变量存储返回的uri
  2661. selectUris = photoSelectResult.photoUris;
  2662. console.info('photoViewPicker.select to file succeed and uris are:' + selectUris);
  2663. //使用fs.openSync接口,通过uri打开这个文件得到fd
  2664. let file = fileIo.openSync(selectUris[0], fileIo.OpenMode.READ_ONLY);
  2665. console.info('file fd: ' + file.fd);
  2666. const timestamp: number = Math.floor(Date.now() / 1000);
  2667. let name = timestamp + "_homebg"
  2668. let imagePath = this.context.filesDir + FileUtil.separator + name
  2669. imagePath = fileUri.getUriFromPath(imagePath)
  2670. let file2 = fileIo.openSync(imagePath, fileIo.OpenMode.READ_WRITE | fileIo.OpenMode.CREATE)
  2671. fileIo.copyFileSync(file.fd, file2.fd)
  2672. fileIo.closeSync(file);
  2673. fileIo.closeSync(file2);
  2674. this.customizeBgPath = imagePath
  2675. PreferencesUtil.put(SettingPage.IS_CUSTOMIZE_BG_PATH, this.customizeBgPath)
  2676. this.sendChangeEvent()
  2677. }).catch((err: BusinessError) => {
  2678. console.error(`Invoke photoViewPicker.select failed, code is ${err.code}, message is ${err.message}`);
  2679. })
  2680. }
  2681. @Builder
  2682. customizeBgSheet() {
  2683. Scroll() {
  2684. Column() {
  2685. this.CustomizeBg()
  2686. }
  2687. }
  2688. .width('100%')
  2689. .height('100%')
  2690. }
  2691. @Builder
  2692. CustomizeBg() {
  2693. Column() {
  2694. Image(this.customizeBgPath)
  2695. .height('42%')
  2696. .alt($r('app.media.add_image2'))
  2697. .objectFit(ImageFit.Contain)
  2698. .borderRadius(15)
  2699. .clip(true)
  2700. .clickEffect({ level: ClickEffectLevel.HEAVY })
  2701. .blur(this.blurValue)
  2702. .clickEffect({level:ClickEffectLevel.LIGHT, scale: 0.6})
  2703. .brightness(this.bgBrightness + 0.8)
  2704. .margin({ left: 30, right: 30, bottom: 20 })
  2705. .onClick(async () => {
  2706. this.goSelectImage()
  2707. })
  2708. Row() {
  2709. Row() {
  2710. Button('选择图片')
  2711. .fontColor(Color.White)
  2712. .fontSize(12)
  2713. .height(48)
  2714. .width(100)
  2715. .clickEffect({ level: ClickEffectLevel.HEAVY })
  2716. .backgroundColor(this.themeColor)
  2717. .stateEffect(true)
  2718. .onClick(async () => {
  2719. this.goSelectImage()
  2720. })
  2721. }
  2722. .height('100%')
  2723. .justifyContent(FlexAlign.Center)
  2724. .layoutWeight(1)
  2725. }
  2726. .width('100%')
  2727. .height(58)
  2728. .margin({ bottom: 20 })
  2729. Column() {
  2730. Row() {
  2731. Text('自定义背景:')
  2732. .margin({ left: 18 })
  2733. .fontSize(15)
  2734. .fontColor($r('app.color.text_color'))
  2735. .fontWeight(480)
  2736. .layoutWeight(1)
  2737. Toggle({ type: ToggleType.Switch, isOn: this.isCustomizeBg })
  2738. .selectedColor(this.themeColor)
  2739. .switchPointColor(Color.White)
  2740. .clickEffect({level:ClickEffectLevel.LIGHT, scale: 0.5})
  2741. .margin({ right: 18 })
  2742. .onChange((checked: boolean) => {
  2743. this.isCustomizeBg = checked;
  2744. PreferencesUtil.put(SettingPage.IS_CUSTOMIZE_BG, this.isCustomizeBg)
  2745. this.sendChangeEvent()
  2746. })
  2747. .width(50)
  2748. .height(30);
  2749. }
  2750. .height(55)
  2751. }
  2752. .backgroundColor($r('app.color.settings_background_main'))
  2753. .borderRadius(15)
  2754. .margin({
  2755. left: 30,
  2756. right: 30,
  2757. top: 0,
  2758. bottom: 20
  2759. })
  2760. .padding(0)
  2761. Column() {
  2762. Row() {
  2763. Text('背景模糊:')
  2764. .margin({ left: 18 })
  2765. .fontSize(15)
  2766. .fontColor($r('app.color.text_color'))
  2767. .fontWeight(480)
  2768. Slider({
  2769. value: this.blurValue,
  2770. min: 0,
  2771. max: 100,
  2772. step: 1,
  2773. style: SliderStyle.OutSet
  2774. })
  2775. .blockColor(this.themeColor)
  2776. .trackColor($r('app.color.speed_text_color'))
  2777. .selectedColor($r('app.color.index_background'))
  2778. .trackThickness(8)
  2779. .onChange((value: number) => {
  2780. this.blurValue = value;
  2781. PreferencesUtil.put(SettingPage.CUSTOMIZE_BG_BLUR, this.blurValue)
  2782. this.sendChangeEvent()
  2783. })
  2784. .layoutWeight(1)
  2785. }
  2786. .height(55)
  2787. }
  2788. .backgroundColor($r('app.color.settings_background_main'))
  2789. .borderRadius(15)
  2790. .margin({
  2791. left: 30,
  2792. right: 30,
  2793. top: 0,
  2794. bottom: 20
  2795. })
  2796. .padding(0)
  2797. Column() {
  2798. Row() {
  2799. Text('背景亮度:')
  2800. .margin({ left: 18 })
  2801. .fontSize(15)
  2802. .fontColor($r('app.color.text_color'))
  2803. .fontWeight(480)
  2804. Slider({
  2805. value: this.bgBrightness,
  2806. min: -0.4,
  2807. max: 0.4,
  2808. step: 0.1,
  2809. style: SliderStyle.OutSet
  2810. })
  2811. .blockColor(this.themeColor)
  2812. .trackColor($r('app.color.speed_text_color'))
  2813. .selectedColor($r('app.color.index_background'))
  2814. .trackThickness(8)
  2815. .onChange((value: number) => {
  2816. this.bgBrightness = value;
  2817. PreferencesUtil.put(SettingPage.BG_BRIGHTNESS, this.bgBrightness)
  2818. this.sendChangeEvent()
  2819. })
  2820. .layoutWeight(1)
  2821. }
  2822. .height(55)
  2823. }
  2824. .backgroundColor($r('app.color.settings_background_main'))
  2825. .borderRadius(15)
  2826. .margin({
  2827. left: 30,
  2828. right: 30,
  2829. top: 0,
  2830. bottom: 20
  2831. })
  2832. .padding(0)
  2833. }
  2834. .margin({ bottom: 30 })
  2835. }
  2836. // 判断当前主题色是否为自定义色
  2837. isCustomThemeColor(): boolean {
  2838. for (let i = 0; i < SettingPage.THEME_COLOR_LIST.length - 1; i++) {
  2839. if (SettingPage.THEME_COLOR_LIST[i].color === this.themeColor) {
  2840. return false;
  2841. }
  2842. }
  2843. return true;
  2844. }
  2845. // 会员功能弹窗
  2846. showVipDialog() {
  2847. DialogHelper.showCustomContentDialog({
  2848. dialogId: 'vip',
  2849. title: "友情提示",
  2850. autoCancel: false,
  2851. backCancel: true,
  2852. contentBuilder: () => {
  2853. this.customVipBuilder("该功能需开通会员,非常感谢您的支持!")
  2854. },
  2855. buttons: [],
  2856. })
  2857. }
  2858. @Builder
  2859. customVipBuilder(content: string) {
  2860. Column() {
  2861. Text(content)
  2862. .fontColor(Color.Gray)
  2863. .fontSize(16)
  2864. .alignSelf(ItemAlign.Start)
  2865. .margin({ bottom: 15 })
  2866. Row() {
  2867. Button('取消')
  2868. .fontColor(Color.White)
  2869. .backgroundColor(this.themeColor)
  2870. .height(50)
  2871. .layoutWeight(1)
  2872. .stateEffect(true)
  2873. .margin({ right: 6 })
  2874. .onClick(() => {
  2875. DialogHelper.closeDialog('vip');
  2876. })
  2877. Button('开通')
  2878. .fontColor(Color.White)
  2879. .layoutWeight(1)
  2880. .height(50)
  2881. .backgroundColor(this.themeColor)
  2882. .stateEffect(true)
  2883. .margin({ left: 6 })
  2884. .onClick(() => {
  2885. this.isThemeSheet = false;
  2886. DialogHelper.closeDialog('vip');
  2887. this.mType = 1//跳转到用户中心
  2888. // router.pushUrl({
  2889. // url: 'pages/UserCenter'
  2890. // }, router.RouterMode.Single);
  2891. })
  2892. }
  2893. }
  2894. .width("100%")
  2895. .padding(10)
  2896. }
  2897. @State appIdentifier:string=''
  2898. geIDD() {
  2899. // 获取应用签名等信息示例代码
  2900. let bundleFlags = bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_APPLICATION |
  2901. bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_SIGNATURE_INFO;
  2902. try {
  2903. bundleManager.getBundleInfoForSelf(bundleFlags).then((data) => {
  2904. hilog.info(0x0000, 'testTag11', 'getBundleInfoForSelf successfully. Data: %{public}s', JSON.stringify(data));
  2905. let inde = JSON.stringify(data)
  2906. this.appIdentifier = inde.substring(inde.indexOf('appIdentifier'),inde.indexOf('"certificate'))
  2907. hilog.info(0x0000, 'testTag11', 'appIdentifier Data: %{public}s', this.appIdentifier);
  2908. }).catch((err: BusinessError) => {
  2909. hilog.error(0x0000, 'testTag11', 'getBundleInfoForSelf failed. Cause: %{public}s', err.message);
  2910. });
  2911. } catch (err) {
  2912. let message = (err as BusinessError).message;
  2913. hilog.error(0x0000, 'testTag33', 'getBundleInfoForSelf failed: %{public}s', message);
  2914. }
  2915. }
  2916. private getMeituConfig(): UploadConfig | null {
  2917. // 尝试清理可能存在的旧token缓存,避免使用过期token
  2918. try {
  2919. PreferencesUtil.put(SettingPage.MEITU_UPLOAD_TOKEN_KEY, '')
  2920. LogUtil.info('SettingPage', '已清理旧的UpToken缓存')
  2921. } catch (error) {
  2922. LogUtil.debug('SettingPage', '清理token缓存失败,继续生成新token')
  2923. }
  2924. // 每次都生成新的UpToken,避免使用过期token
  2925. LogUtil.info('SettingPage', `生成新的UpToken,Bucket: ${SettingPage.MEITU_BUCKET}`)
  2926. const token = UpTokenUtil.generateUpToken(SettingPage.MEITU_AK, SettingPage.MEITU_SK, SettingPage.MEITU_BUCKET, 3600)
  2927. LogUtil.info('SettingPage', `UpToken生成完成,Token前缀: ${token.substring(0, 20)}...`)
  2928. // Domain可以缓存,因为通常不会变化
  2929. let domain = PreferencesUtil.getStringSync(SettingPage.MEITU_UPLOAD_DOMAIN_KEY, SettingPage.MEITU_DOMAIN)
  2930. if (!domain || domain.trim().length === 0) {
  2931. domain = SettingPage.MEITU_DOMAIN
  2932. PreferencesUtil.put(SettingPage.MEITU_UPLOAD_DOMAIN_KEY, domain)
  2933. }
  2934. if (!domain || domain.trim().length === 0) {
  2935. LogUtil.warn('SettingPage', '日志上传未配置域名')
  2936. return null
  2937. }
  2938. LogUtil.info('SettingPage', `上传配置 - Domain: ${domain}, Bucket: ${SettingPage.MEITU_BUCKET}`)
  2939. return {
  2940. uploadToken: token,
  2941. domain: domain,
  2942. keyPrefix: 'logs'
  2943. }
  2944. }
  2945. private ensureMeituUploadHandler(isInit: boolean): boolean {
  2946. const config = this.getMeituConfig()
  2947. if (!config) {
  2948. if (!isInit) {
  2949. ToastUtil.showToast('未配置日志上传token/域名,已关闭开关')
  2950. this.isLogUploadEnabled = false
  2951. PreferencesUtil.put(SettingPage.LOG_UPLOAD_ENABLED, false)
  2952. }
  2953. this.registerLogUploadDisabled()
  2954. return false
  2955. }
  2956. LogCollector.registerUploadHandler(async (filePath: string): Promise<string> => {
  2957. return await Uploader.uploadFile(filePath, config)
  2958. })
  2959. return true
  2960. }
  2961. private registerLogUploadDisabled() {
  2962. LogCollector.registerUploadHandler(async (filePath: string): Promise<void> => {
  2963. LogUtil.info('LogUpload', `日志上传开关关闭,跳过: ${filePath}`)
  2964. return
  2965. })
  2966. }
  2967. }
  2968. // 主题色类型声明
  2969. export interface ThemeColorItem {
  2970. name: string;
  2971. color: string;
  2972. isVip: boolean;
  2973. }
  2974. // 工具函数:将一维数组分成每行2个的二维数组
  2975. function chunkArray<T>(arr: Array<T>, size: number): Array<Array<T>> {
  2976. const result: Array<Array<T>> = [];
  2977. for (let i = 0; i < arr.length; i += size) {
  2978. const row: Array<T> = [];
  2979. for (let j = 0; j < size; j++) {
  2980. if (i + j < arr.length) {
  2981. row.push(arr[i + j]);
  2982. }
  2983. }
  2984. result.push(row);
  2985. }
  2986. return result;
  2987. }