|
|
@@ -123,7 +123,8 @@ import {
|
|
|
HdsSceneType,
|
|
|
HdsVisualComponentAttribute,
|
|
|
} from '@kit.UIDesignKit';
|
|
|
-
|
|
|
+import { GlobalAlphabetIndexerModifier } from '../Styels/GlobalStyles'
|
|
|
+import { getFirstLetter } from '../Constants';
|
|
|
|
|
|
const TAG = 'LocalMusic';
|
|
|
|
|
|
@@ -615,6 +616,16 @@ const ITEM_HEIGHT_BIG: number = 78; // 列表项大高度
|
|
|
@Preview
|
|
|
@Component
|
|
|
export struct LocalMusic {
|
|
|
+ // 字母表
|
|
|
+ @State alphaBet: string[] = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K',
|
|
|
+ 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z']
|
|
|
+ @State alphaBetStyle: GlobalAlphabetIndexerModifier = new GlobalAlphabetIndexerModifier()
|
|
|
+ @State selectAlphaBetIndex: number = 0
|
|
|
+ @State isShowAlphaBet: boolean = false
|
|
|
+ @State isScrolling: boolean = false
|
|
|
+ @State isTouchingAlphaBet: boolean = false
|
|
|
+ @State alphabetHeight: number = 0
|
|
|
+ public enableShowAlphabet: boolean = true // 是否显示字母表
|
|
|
@State isShowPrecious: boolean = false //播控条显示上一首按钮
|
|
|
//背景两侧流光控制器
|
|
|
@State sceneBgController: HdsSceneController|undefined = deviceInfo.sdkApiVersion>=20
|
|
|
@@ -2185,6 +2196,8 @@ export struct LocalMusic {
|
|
|
animateTo({ duration: 666 }, () => {
|
|
|
this.opacityItem = 1;
|
|
|
});
|
|
|
+ //添加到字母索引表
|
|
|
+ this.setAlphaBet()
|
|
|
this.setButtonStatus()
|
|
|
}, 200);
|
|
|
|
|
|
@@ -2569,7 +2582,7 @@ export struct LocalMusic {
|
|
|
message:'用系统自带的文件管理器将:\n\n1、音频文件放入' + '\n\n我的设备/Download/'
|
|
|
+ this.appName + '\n\n2、无需繁琐的勾选和分类步骤。\n\n3、每个子文件夹将被组成一个分组。' +
|
|
|
'\n\n4、歌词文件的文件名必须和目标歌曲文件名相同(不包含后缀名)。\n\n5、歌词文件和目标歌曲文件必须同个目录。' +
|
|
|
- '\n\n6、电脑上Download的目录是\nDownload/' + this.packName + '。\n\n7、放好文件后如果没显示点击刷新按钮。\n',
|
|
|
+ '\n\n6、电脑上Download的目录是\nDownload/' + this.packName + '。\n\n7、放好文件后去文件扫描一下。\n',
|
|
|
buttons: [
|
|
|
{
|
|
|
text: '知道了',
|
|
|
@@ -3229,31 +3242,9 @@ export struct LocalMusic {
|
|
|
})
|
|
|
|
|
|
Stack() {
|
|
|
- Row() {
|
|
|
- Blank()
|
|
|
- .layoutWeight(1)
|
|
|
- IndexerView(
|
|
|
- {
|
|
|
- indexArray: DEFAULT_INDEX,
|
|
|
- selectedIndex: this.selectedIndex,
|
|
|
- textSize: 12,
|
|
|
- selectedColor: "#ff419ee5",
|
|
|
- normalColor: "#ffa0a0a0",
|
|
|
- floatSelectedTextColor: "#ffffff",
|
|
|
- floatSelectedViewColor: "#ff419ee5",
|
|
|
- onIndexChanged: (index) => {
|
|
|
- this.listScroller.scrollToIndex(index)
|
|
|
- }
|
|
|
- })
|
|
|
- .width(24)
|
|
|
- .height("50%")
|
|
|
- }.visibility(Visibility.None)
|
|
|
|
|
|
- Column() {
|
|
|
|
|
|
- // if (!this.isShowCoverHeader()) {
|
|
|
- // this.tabTitle()
|
|
|
- // }
|
|
|
+ Column() {
|
|
|
|
|
|
if(this.twoFingerType==4){
|
|
|
this.getWaterView()
|
|
|
@@ -3287,6 +3278,8 @@ export struct LocalMusic {
|
|
|
}
|
|
|
.layoutWeight(1)
|
|
|
.height('100%')
|
|
|
+ // 右侧居中的字母表索引
|
|
|
+ this.indexBuilder()
|
|
|
|
|
|
this.topTitleBar()
|
|
|
}
|
|
|
@@ -3467,6 +3460,158 @@ export struct LocalMusic {
|
|
|
|
|
|
}
|
|
|
|
|
|
+ //字母表索引
|
|
|
+ @Builder
|
|
|
+ indexBuilder(){
|
|
|
+ if(this.enableShowAlphabet){
|
|
|
+ Column({space: 5}){
|
|
|
+ if(this.isShowAlphaBet){
|
|
|
+ AlphabetIndexer({arrayValue: this.alphaBet,selected: this.selectAlphaBetIndex})
|
|
|
+ .attributeModifier(this.alphaBetStyle)
|
|
|
+ .usingPopup(this.isTouchingAlphaBet)
|
|
|
+ .onAreaChange((old_value,new_value)=>{
|
|
|
+ this.alphabetHeight = new_value.height as number
|
|
|
+ })
|
|
|
+ .popupPosition({
|
|
|
+ x: 40,
|
|
|
+ y: this.alphabetHeight / 2
|
|
|
+ })
|
|
|
+ .onSelect((index: number) => {
|
|
|
+ this.onSelectIndexItem(this.alphaBet[index])
|
|
|
+ })
|
|
|
+ .onTouch((event: TouchEvent) =>{
|
|
|
+ this.isShowAlphaBet = true
|
|
|
+ if(event.type === TouchType.Up || event.type === TouchType.Cancel){
|
|
|
+ this.isTouchingAlphaBet = false
|
|
|
+ }else{
|
|
|
+ this.isTouchingAlphaBet = true
|
|
|
+ }
|
|
|
+ })
|
|
|
+ .transition(
|
|
|
+ TransitionEffect.translate({x: 10})
|
|
|
+ .combine(TransitionEffect.opacity(0.1))
|
|
|
+ .animation({
|
|
|
+ duration: 150,
|
|
|
+ curve: Curve.EaseInOut,
|
|
|
+ })
|
|
|
+ )
|
|
|
+ }else{
|
|
|
+ Blank()
|
|
|
+ .layoutWeight(1)
|
|
|
+ }
|
|
|
+
|
|
|
+ // ListLocateButton()
|
|
|
+ // .onClick(() =>{
|
|
|
+ // this.locateSong()
|
|
|
+ // })
|
|
|
+ // .clickEffect({level:ClickEffectLevel.LIGHT,scale: 0.5})
|
|
|
+ // .margin({
|
|
|
+ // bottom: 10
|
|
|
+ // })
|
|
|
+ }
|
|
|
+ .padding({
|
|
|
+ bottom: 0
|
|
|
+ })
|
|
|
+ .position({x:'92%'})
|
|
|
+ .height('100%')
|
|
|
+ .justifyContent(FlexAlign.Center)
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ onSelectIndexItem(letter: string) {
|
|
|
+ let songs = this.videoLocalList
|
|
|
+ let targetIndex = -1;
|
|
|
+ for (let i = 0; i < songs.length; i++) {
|
|
|
+ let song = songs[i]
|
|
|
+ let text = this.isShowFileName?song.fileName:song.name
|
|
|
+ if(this.sortType === 0||this.sortType==1){
|
|
|
+ text = song.artist
|
|
|
+ }else if(this.sortType === 2||this.sortType==3){
|
|
|
+ text = song.album
|
|
|
+ }
|
|
|
+ if(text){
|
|
|
+ let firstPinyin = getFirstLetter(text)
|
|
|
+ if (firstPinyin&&firstPinyin === letter) {
|
|
|
+ targetIndex = i;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+ if (targetIndex !== -1) {
|
|
|
+ this.listScroller.scrollToIndex(targetIndex);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // 找到对应字母表的索引
|
|
|
+ findAlphaBetIndex(song: VideoItem):number{
|
|
|
+ let text = this.isShowFileName?song.fileName:song.name
|
|
|
+ if(this.sortType === 0||this.sortType==1){
|
|
|
+ text = song.artist
|
|
|
+ }else if(this.sortType === 2||this.sortType==3){
|
|
|
+ text = song.album
|
|
|
+ }
|
|
|
+ if(text){
|
|
|
+ let firstLetter = getFirstLetter(text)
|
|
|
+ for(let i=0;i<this.alphaBet.length;i++){
|
|
|
+ if(this.alphaBet[i] === firstLetter){
|
|
|
+ return i
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0
|
|
|
+ }
|
|
|
+
|
|
|
+ async setAlphaBet(){
|
|
|
+ return new Promise<void>((resolve,reject) => {
|
|
|
+ try {
|
|
|
+ let songs = this.videoLocalList
|
|
|
+ if(songs.length > 40000){
|
|
|
+ this.alphaBet = []
|
|
|
+ resolve()
|
|
|
+ return
|
|
|
+ }
|
|
|
+ let alphabetSet = new Set<string>();
|
|
|
+ for (let song of songs) {
|
|
|
+ let text = this.isShowFileName?song.fileName:song.name
|
|
|
+ if(this.sortType === 0||this.sortType==1){
|
|
|
+ text = song.artist
|
|
|
+ }else if(this.sortType === 2||this.sortType==3){
|
|
|
+ text = song.album
|
|
|
+ }
|
|
|
+ if(text){
|
|
|
+ let firstPinyin = getFirstLetter(text)
|
|
|
+ if(!alphabetSet.has(firstPinyin)){
|
|
|
+ alphabetSet.add(firstPinyin)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // const pyStr = song.pyStr
|
|
|
+ // if(pyStr){
|
|
|
+ // if(!alphabetSet.has(pyStr)){
|
|
|
+ // alphabetSet.add(pyStr)
|
|
|
+ // }
|
|
|
+ // }
|
|
|
+
|
|
|
+ }
|
|
|
+ this.alphaBet = Array.from(alphabetSet).sort((a,b)=>{
|
|
|
+ if(this.sortType ===4||this.sortType==0||this.sortType==2||this.sortType==6){
|
|
|
+ return a.localeCompare(b)
|
|
|
+ }else{
|
|
|
+ return b.localeCompare(a)
|
|
|
+ }
|
|
|
+ })
|
|
|
+ if(this.videoLocalList.length > 0){
|
|
|
+ this.listScroller.scrollToIndex(0)
|
|
|
+ this.selectAlphaBetIndex = 0
|
|
|
+ }
|
|
|
+ resolve()
|
|
|
+ }catch (e) {
|
|
|
+ console.error('testTag','排序字母表出错',JSON.stringify(e))
|
|
|
+ resolve()
|
|
|
+ }
|
|
|
+ })
|
|
|
+ }
|
|
|
+
|
|
|
|
|
|
@Builder
|
|
|
topTitleBar(){
|
|
|
@@ -4594,16 +4739,16 @@ export struct LocalMusic {
|
|
|
Blank()
|
|
|
Image($r('app.media.arrow_right'))
|
|
|
.height(25)
|
|
|
- .margin({ right: 10 })
|
|
|
.alignSelf(ItemAlign.Center)
|
|
|
.id(item.filePath)
|
|
|
-
|
|
|
+ .visibility(this.isShowAlphaBet?Visibility.None:Visibility.Visible)
|
|
|
+ .animation({ duration: 300, curve: Curve.Ease })
|
|
|
|
|
|
}
|
|
|
}
|
|
|
.backgroundColor(Color.Transparent)
|
|
|
.height(this.twoFingerType == 3 ? ITEM_HEIGHT_BIG : this.twoFingerType == 2 ? ITEM_HEIGHT : ITEM_HEIGHT_SMALL)
|
|
|
- .width('100%')
|
|
|
+ .width('98%')
|
|
|
.reuseId('dir_item')
|
|
|
.visibility(this.isShowDir(item.name) ? Visibility.Visible : Visibility.None)
|
|
|
.opacity(this.opacityItem) // 绑定透明度
|
|
|
@@ -6161,37 +6306,40 @@ export struct LocalMusic {
|
|
|
}
|
|
|
@Builder
|
|
|
getList(){
|
|
|
- Refresh({ refreshing: $$this.isRefreshing, refreshingContent: this.contentNode }) {
|
|
|
- this.getListView()
|
|
|
- }
|
|
|
- .pullDownRatio(this.ratioL)
|
|
|
- .pullToRefresh(true)
|
|
|
- .refreshOffset(0)
|
|
|
- .onOffsetChange((offset: number) => {
|
|
|
- // 越接近最大距离,下拉跟手系数越小。
|
|
|
- this.ratioL = 1 - Math.pow((offset / this.maxRefreshingHeight), 3);
|
|
|
- })
|
|
|
- .onStateChange((refreshStatus: RefreshStatus) => {
|
|
|
- console.info('onecold Refresh onStatueChange state is ' + refreshStatus);
|
|
|
- })
|
|
|
- .onRefreshing(async () => {
|
|
|
- if(this.modeType==0){
|
|
|
- this.getHistoryList(false)
|
|
|
- this.asyncCurrentPathOnlyFile()
|
|
|
- }else if(this.modeType == 1){
|
|
|
- workerInstance.postMessage({ code: 2, data: this.context,data2:this.packName });
|
|
|
- }else if(this.modeType == 2){
|
|
|
- workerInstance.postMessage({ code: 3, data: this.context });
|
|
|
- }else if(this.modeType == 3){
|
|
|
- workerInstance.postMessage({ code: 4, data: this.context });
|
|
|
- }else if(this.modeType == 4){
|
|
|
- this.doSongListTask()
|
|
|
- }
|
|
|
+ Stack() {
|
|
|
+ Refresh({ refreshing: $$this.isRefreshing, refreshingContent: this.contentNode }) {
|
|
|
+ this.getListView()
|
|
|
+ }
|
|
|
+ .pullDownRatio(this.ratioL)
|
|
|
+ .pullToRefresh(true)
|
|
|
+ .refreshOffset(0)
|
|
|
+ .onOffsetChange((offset: number) => {
|
|
|
+ // 越接近最大距离,下拉跟手系数越小。
|
|
|
+ this.ratioL = 1 - Math.pow((offset / this.maxRefreshingHeight), 3);
|
|
|
+ })
|
|
|
+ .onStateChange((refreshStatus: RefreshStatus) => {
|
|
|
+ console.info('onecold Refresh onStatueChange state is ' + refreshStatus);
|
|
|
+ })
|
|
|
+ .onRefreshing(async () => {
|
|
|
+ if(this.modeType==0){
|
|
|
+ this.getHistoryList(false)
|
|
|
+ this.asyncCurrentPathOnlyFile()
|
|
|
+ }else if(this.modeType == 1){
|
|
|
+ workerInstance.postMessage({ code: 2, data: this.context,data2:this.packName });
|
|
|
+ }else if(this.modeType == 2){
|
|
|
+ workerInstance.postMessage({ code: 3, data: this.context });
|
|
|
+ }else if(this.modeType == 3){
|
|
|
+ workerInstance.postMessage({ code: 4, data: this.context });
|
|
|
+ }else if(this.modeType == 4){
|
|
|
+ this.doSongListTask()
|
|
|
+ }
|
|
|
|
|
|
|
|
|
- console.log('onRefreshing test');
|
|
|
- })
|
|
|
+ console.log('onRefreshing test');
|
|
|
+ })
|
|
|
+
|
|
|
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
|
|
|
@@ -6377,6 +6525,22 @@ export struct LocalMusic {
|
|
|
}, (item: VideoItem) => item.filePath + '_' + this.listRefreshKey)
|
|
|
// }
|
|
|
}
|
|
|
+ .onScrollStart(() => {
|
|
|
+ this.isScrolling = true
|
|
|
+ this.isShowAlphaBet = true
|
|
|
+ })
|
|
|
+ .onScrollIndex((start: number,center:number,end:number) => {
|
|
|
+ this.selectedIndex = start
|
|
|
+ if(start >= 0 && start < this.videoLocalList.length){
|
|
|
+ this.selectAlphaBetIndex = this.findAlphaBetIndex(this.videoLocalList[start])
|
|
|
+ }
|
|
|
+ })
|
|
|
+ .onScrollStop(() => {
|
|
|
+ if(this.isScrolling){
|
|
|
+ this.isScrolling = false
|
|
|
+ }
|
|
|
+ this.isShowAlphaBet = false
|
|
|
+ })
|
|
|
.scrollBar(BarState.Off)
|
|
|
.scale({ x: this.scaleValue, y: this.scaleValue, z: 1 })
|
|
|
.gesture(PinchGesture({ fingers: 2 })
|
|
|
@@ -6396,12 +6560,7 @@ export struct LocalMusic {
|
|
|
.cachedCount(10)
|
|
|
// .reuseId('list_item')
|
|
|
.borderRadius(20)
|
|
|
- // .transition(TransitionEffect.asymmetric(TransitionEffect.scale({ x: 0.9, y: 0.9 }).animation({ duration: 400 }),
|
|
|
- // TransitionEffect.scale({ x: 0, y: 0 })))
|
|
|
.layoutWeight(1)
|
|
|
- .onScrollIndex((start) => {
|
|
|
- this.selectedIndex = start
|
|
|
- })
|
|
|
.visibility(this.isGridMusic ? Visibility.None : Visibility.Visible)
|
|
|
.lanes(
|
|
|
new BreakpointType<number>({
|