From 65f0bda1d95b81685bcb6157e85fa7bc8d6facdf Mon Sep 17 00:00:00 2001 From: sunlian Date: Thu, 17 Oct 2024 14:54:38 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E6=AD=8C=E8=AF=8D=E5=8A=9F?= =?UTF-8?q?=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: sunlian --- .../{ServerConstants.ets => AppConstants.ets} | 77 +++-- .../src/main/ets/manager/HttpManager.ets | 295 +++++++++++------- .../src/main/ets/manager/PlayerManager.ets | 150 +++++++-- .../entry/src/main/ets/model/AudioData.ets | 2 + .../entry/src/main/ets/model/LrcLine.ets | 5 +- .../entry/src/main/ets/model/PlayListData.ets | 5 +- .../UIConstants.ets => model/SettingItem.ets} | 17 +- .../entry/src/main/ets/pages/Index.ets | 109 ++++--- .../entry/src/main/ets/utils/CommonUtils.ets | 59 +++- ...ddToListDialog.ets => AddToListDialog.ets} | 3 +- .../src/main/ets/view/CurrentPlayList.ets | 41 ++- .../src/main/ets/view/ExploreListMore.ets | 183 +++++++++++ .../src/main/ets/view/ExplorePlayList.ets | 57 +++- .../src/main/ets/view/ExploreSongItem.ets | 11 +- .../src/main/ets/view/InputServerHost.ets | 67 ++++ .../view/{loginDialog.ets => LoginDialog.ets} | 0 .../entry/src/main/ets/view/PlayListItem.ets | 10 +- .../entry/src/main/ets/view/PlayerBar.ets | 37 ++- .../entry/src/main/ets/view/PlayerDetail.ets | 212 ++++++------- .../entry/src/main/ets/view/Setting.ets | 72 +---- .../entry/src/main/ets/view/SettingCell.ets | 167 ++++++++++ .../main/ets/view/SingleRowScrollerList.ets | 4 +- .../entry/src/main/ets/view/SongItem.ets | 5 +- .../src/main/ets/view/TriColGridList.ets | 7 +- .../main/ets/view/TriColNestScrollerGrid.ets | 5 +- .../src/main/ets/widget/pages/WidgetCard.ets | 14 +- .../resources/base/media/doc_plaintext.png | Bin 0 -> 320 bytes .../src/main/resources/base/media/more.png | Bin 0 -> 1289 bytes .../main/resources/base/media/order_play.png | Bin 0 -> 354 bytes .../base/media/questionmark_circle.png | Bin 0 -> 1263 bytes .../src/main/resources/base/media/trash.png | Bin 0 -> 1194 bytes .../src/main/resources/base/media/xmark.png | Bin 0 -> 599 bytes 32 files changed, 1140 insertions(+), 474 deletions(-) rename scenario/MusicPlayerOnline/entry/src/main/ets/constants/{ServerConstants.ets => AppConstants.ets} (59%) rename scenario/MusicPlayerOnline/entry/src/main/ets/{constants/UIConstants.ets => model/SettingItem.ets} (66%) rename scenario/MusicPlayerOnline/entry/src/main/ets/view/{addToListDialog.ets => AddToListDialog.ets} (97%) create mode 100644 scenario/MusicPlayerOnline/entry/src/main/ets/view/ExploreListMore.ets create mode 100644 scenario/MusicPlayerOnline/entry/src/main/ets/view/InputServerHost.ets rename scenario/MusicPlayerOnline/entry/src/main/ets/view/{loginDialog.ets => LoginDialog.ets} (100%) create mode 100644 scenario/MusicPlayerOnline/entry/src/main/ets/view/SettingCell.ets create mode 100644 scenario/MusicPlayerOnline/entry/src/main/resources/base/media/doc_plaintext.png create mode 100644 scenario/MusicPlayerOnline/entry/src/main/resources/base/media/more.png create mode 100644 scenario/MusicPlayerOnline/entry/src/main/resources/base/media/order_play.png create mode 100644 scenario/MusicPlayerOnline/entry/src/main/resources/base/media/questionmark_circle.png create mode 100644 scenario/MusicPlayerOnline/entry/src/main/resources/base/media/trash.png create mode 100644 scenario/MusicPlayerOnline/entry/src/main/resources/base/media/xmark.png diff --git a/scenario/MusicPlayerOnline/entry/src/main/ets/constants/ServerConstants.ets b/scenario/MusicPlayerOnline/entry/src/main/ets/constants/AppConstants.ets similarity index 59% rename from scenario/MusicPlayerOnline/entry/src/main/ets/constants/ServerConstants.ets rename to scenario/MusicPlayerOnline/entry/src/main/ets/constants/AppConstants.ets index 4a6968145..d7ae6873c 100644 --- a/scenario/MusicPlayerOnline/entry/src/main/ets/constants/ServerConstants.ets +++ b/scenario/MusicPlayerOnline/entry/src/main/ets/constants/AppConstants.ets @@ -16,57 +16,66 @@ /** * Common constants for Server features. */ -export default class ServerConstants { +export default class AppConstants { /** * server host ,replace with your owen server address */ - static readonly SERVER_HOST = 'http://192.168.13.110:8000/'; + static readonly SERVER_HOST_PROP = 'SERVER_HOST_PROP'; + static readonly SERVER_HOST = 'http://192.168.12.8:8000/'; /** * custom list URL */ - static readonly CUSTOM_LIST_URL = this.SERVER_HOST + 'get_playlists'; + static readonly CUSTOM_LIST_URL = 'get_playlists'; /** * search song */ - static readonly SEARCH_SONG_URL = this.SERVER_HOST + 'search_song/'; + static readonly SEARCH_SONG_URL = 'search_song/'; + /** + * search song + */ + static readonly GET_SONG_LRC_URL = 'get_lrc/'; /** * recommend list URL */ - static readonly RECOMMEND_LIST_URL = this.SERVER_HOST + 'get_recommend_playlists'; + static readonly RECOMMEND_LIST_URL = 'get_recommend_playlists'; /** * recent list URL */ - static readonly RECENT_LIST_URL = this.SERVER_HOST + 'get_recent_playlists'; + static readonly RECENT_LIST_URL = 'get_recent_playlists'; /** * favor list URL */ - static readonly FAVOR_LIST_URL = this.SERVER_HOST + 'get_favor_playlists'; + static readonly FAVOR_LIST_URL = 'get_favor_playlists'; /** * Song Image URL */ - static readonly SONG_IMAGE_URL = this.SERVER_HOST + 'get_song_img/'; + static readonly SONG_IMAGE_URL = 'get_song_img/'; /** * Play songs URL */ - static readonly PLAY_SONG_URL = this.SERVER_HOST + 'play_song1/'; + static readonly PLAY_SONG_URL = 'play_song1/'; /** * record recent */ - static readonly RECORD_RECENT = this.SERVER_HOST + 'record_recent/'; + static readonly RECORD_RECENT_URL = 'record_recent/'; /** * set favourite */ - static readonly SET_FAVOURITE = this.SERVER_HOST + 'set_favourite/'; + static readonly SET_FAVOURITE_URL = 'set_favourite/'; /** * add song to playlist */ - static readonly ADD_TO_PLAYLIST = this.SERVER_HOST + 'add_to_playlist/'; + static readonly ADD_TO_PLAYLIST_URL = 'add_to_playlist/'; + /** + * add song to playlist + */ + static readonly REMOVE_FROM_PLAYLIST_URL = 'remove_from_playlist/'; /** * Login URL */ - static readonly REGISTER_URL = this.SERVER_HOST + 'authentication/signup1/'; - static readonly LOGIN_URL = this.SERVER_HOST + 'authentication/login1/'; - static readonly CSRF_URL = this.SERVER_HOST + 'authentication/get-csrf-token/'; + static readonly REGISTER_URL = 'authentication/signup1/'; + static readonly LOGIN_URL = 'authentication/login1/'; + static readonly CSRF_URL = 'authentication/get-csrf-token/'; /** * PLAYER STATE */ @@ -79,7 +88,6 @@ export default class ServerConstants { static readonly PLAYER_STATE_STOPPED = 'stopped'; static readonly PLAYER_STATE_RELEASED = 'released'; static readonly PLAYER_STATE_UNKNOWN = 'unknown'; - /** * 首页播放状态更新消息 */ @@ -90,6 +98,7 @@ export default class ServerConstants { * 详情页播放状态更新消息 */ static readonly DETAIL_UPDATE_TIME = 'DETAIL_UPDATE_TIME'; + static readonly DETAIL_UPDATE_LRC = 'DETAIL_UPDATE_LRC'; static readonly DETAIL_UPDATE_STATE = 'DETAIL_UPDATE_STATE'; static readonly DETAIL_UPDATE_FAVOR_AND_QUALITY = 'DETAIL_UPDATE_FAVOR_AND_QUALITY'; /** @@ -101,7 +110,6 @@ export default class ServerConstants { */ static readonly PLAYLIST_UPDATE_STATE = 'PLAYLIST_UPDATE_STATE'; static readonly PLAYLIST_UPDATE_CHANGED = 'PLAYLIST_UPDATE_CHANGED'; - //首页列表更新消息 static readonly UPDATE_USER_LIST = 'UPDATE_USER_LIST'; static readonly UPDATE_USER_LIST_RECOMMEND = 'UPDATE_USER_LIST_RECOMMEND'; @@ -109,7 +117,8 @@ export default class ServerConstants { static readonly UPDATE_USER_LIST_RECENT = 'UPDATE_USER_LIST_RECENT'; static readonly UPDATE_USER_LIST_FAVOR = 'UPDATE_USER_LIST_FAVOR'; static readonly UPDATE_USER_LIST_SEARCH = 'UPDATE_USER_LIST_SEARCH'; - + //当前查看歌单更新 + static readonly UPDATE_EXPLORE_LIST = 'UPDATE_EXPLORE_LIST'; //首页登录更新消息 static readonly LOGIN_RESULT = 'LOGIN_RESULT' static readonly LOGIN_RESULT_SUCCESS = 'LOGIN_RESULT_SUCCESS' @@ -119,6 +128,7 @@ export default class ServerConstants { */ static readonly LIST_SONG_COUNT = '首'; static readonly LIST_SONG_NO_PLAYING = '点击或双击歌单'; + static readonly CURRENT_LIST_TITLE = '正在播放' static readonly LIST_SONG_FAVOURITE = '我的收藏'; static readonly LIST_SONG_RECENT = '最近播放'; /** @@ -126,19 +136,42 @@ export default class ServerConstants { */ static readonly LOGIN_BUTTON_IN = '登录'; static readonly LOGIN_BUTTON_OUT = '登出'; + static readonly LOGIN_COOKIE = 'loginCookie'; + static readonly LOGIN_NAME = 'loginName'; static readonly LOGIN_INFO_NO = '未登录'; + static readonly LOGIN_COOKIE_NONE = ''; static readonly LOGIN_INFO_ING = '···'; static readonly LOGIN_INFO_FAILED = '登录失败'; static readonly REGISTER_INFO_FAILED = '注册失败'; static readonly REGISTER_INFO_SUCCESS = '注册成功,自动登录...'; static readonly LOGIN_INFO_DONE = ' 你好!'; - static readonly SET_FAVOURITE_ALREADY = "重复收藏"; - static readonly SET_FAVOURITE_SUCCESS = "收藏成功"; - static readonly CANCEL_FAVOURITE_SUCCESS = "取消收藏成功"; - static readonly CANCEL_FAVOURITE_ALREADY = "重复取消收藏"; + static readonly SET_FAVOURITE_ALREADY = "重复收藏"; + static readonly SET_FAVOURITE_SUCCESS = "收藏成功"; + static readonly CANCEL_FAVOURITE_SUCCESS = "取消收藏成功"; + static readonly CANCEL_FAVOURITE_ALREADY = "重复取消收藏"; static readonly SEARCH_DEFAULT = '未搜索'; static readonly SEARCHING = '搜索:'; static readonly EMPTY_SEARCH_WORD = '不能搜索空字符'; static readonly LOGIN_FAILED = 'login failed!'; static readonly REGISTER_FAILED = 'signup failed!'; + static readonly ADD_TO_CURRENT_LIST_OK = '已加入当前播放列表' + static readonly ADD_TO_CURRENT_LIST_REPEAT = '已在当前播放列表' + static readonly aboutTitle = '帮助'; + static readonly aboutDes = '双击修改服务器地址'; + static readonly detailDefaultSetting = '播放页默认显示歌词'; + static readonly detailDefaultSettingDes = '关闭时默认显示封面'; + static readonly DETAIL_DEFAULT_SETTING = 'detailDefaultSetting'; + static readonly TOGGLE_SETTING_OFF = 'OFF'; + static readonly TOGGLE_SETTING_ON = 'ON'; + static readonly playModeTitle = '记住播放顺序设置'; + static readonly playModeDes = '播放新歌单使用上次的播放顺序'; + static readonly PLAY_MODE_SETTING = 'playModeSetting'; + static readonly PLAY_MODE_RECORD = 'playModeRecord'; + static readonly keepLoginTitle = '保持登录'; + static readonly keepLoginDes = '重启自动登录'; + static readonly KEEP_LOGIN_SETTING = 'keepLoginSetting'; + //点击效果 + static readonly CLICK_EFFECT: ClickEffect = { + level: ClickEffectLevel.MIDDLE, scale: 0.8 + }; } diff --git a/scenario/MusicPlayerOnline/entry/src/main/ets/manager/HttpManager.ets b/scenario/MusicPlayerOnline/entry/src/main/ets/manager/HttpManager.ets index c969d97cc..4cdca87dd 100644 --- a/scenario/MusicPlayerOnline/entry/src/main/ets/manager/HttpManager.ets +++ b/scenario/MusicPlayerOnline/entry/src/main/ets/manager/HttpManager.ets @@ -13,7 +13,7 @@ * limitations under the License. */ import http from '@ohos.net.http' -import ServerConstants from '../constants/ServerConstants'; +import AppConstants from '../constants/AppConstants'; import emitter from '@ohos.events.emitter'; import PlayerManager from './PlayerManager'; import prompt from '@ohos.promptAction'; @@ -56,14 +56,14 @@ export default class HttpManager { return; } try { - this.httpRequest.request(ServerConstants.CSRF_URL, + this.httpRequest.request(AppStorage.get(AppConstants.SERVER_HOST_PROP) + AppConstants.CSRF_URL, (err: Error, data: http.HttpResponse) => { if (!err) { console.info('HttpResponse Result:' + data.result); try { const jsonObject: object = JSON.parse(data.result as string); this.csrfToken = jsonObject['csrf_token']; - this.httpRequest.request(ServerConstants.REGISTER_URL, + this.httpRequest.request(AppStorage.get(AppConstants.SERVER_HOST_PROP) + AppConstants.REGISTER_URL, { method: http.RequestMethod.POST, extraData: 'username=' + userName.trim() + '&password=' + pwd.trim(), @@ -76,40 +76,40 @@ export default class HttpManager { (err: Error, data: http.HttpResponse) => { if (!err) { console.info('HttpResponse Result:' + data.result); - if ((data.result as string).indexOf(ServerConstants.REGISTER_FAILED) !== -1) { + if ((data.result as string).indexOf(AppConstants.REGISTER_FAILED) !== -1) { prompt.showToast({ - message: ServerConstants.REGISTER_INFO_FAILED + data.result + message: AppConstants.REGISTER_INFO_FAILED + data.result }) return; } prompt.showToast({ - message: ServerConstants.REGISTER_INFO_SUCCESS + message: AppConstants.REGISTER_INFO_SUCCESS }) this.login(userName.trim(), pwd.trim()); } else { console.info('HttpResponse error:' + JSON.stringify(err)); prompt.showToast({ - message: ServerConstants.REGISTER_INFO_FAILED + message: AppConstants.REGISTER_INFO_FAILED }) } }); } catch (err) { console.info('HttpRequest error:' + JSON.stringify(err)); prompt.showToast({ - message: ServerConstants.REGISTER_INFO_FAILED + message: AppConstants.REGISTER_INFO_FAILED }) } } else { console.info('HttpResponse error:' + JSON.stringify(err)); prompt.showToast({ - message: ServerConstants.REGISTER_INFO_FAILED + message: AppConstants.REGISTER_INFO_FAILED }) } }); } catch (err) { console.info('HttpRequest error:' + JSON.stringify(err)); prompt.showToast({ - message: ServerConstants.REGISTER_INFO_FAILED + message: AppConstants.REGISTER_INFO_FAILED }) } } @@ -117,14 +117,14 @@ export default class HttpManager { //登录 login(userName: string, pwd: string) { try { - this.httpRequest.request(ServerConstants.CSRF_URL, + this.httpRequest.request(AppStorage.get(AppConstants.SERVER_HOST_PROP) + AppConstants.CSRF_URL, (err: Error, data: http.HttpResponse) => { if (!err) { console.info('HttpResponse Result:' + data.result); try { const jsonObject: object = JSON.parse(data.result as string); this.csrfToken = jsonObject['csrf_token']; - this.httpRequest.request(ServerConstants.LOGIN_URL, + this.httpRequest.request(AppStorage.get(AppConstants.SERVER_HOST_PROP) + AppConstants.LOGIN_URL, { method: http.RequestMethod.POST, extraData: 'username=' + userName + '&password=' + pwd, @@ -137,30 +137,29 @@ export default class HttpManager { (err: Error, data: http.HttpResponse) => { if (!err) { console.info('HttpResponse Result:' + data.result); - console.info('HttpResponse code:' + data.responseCode); - console.info('HttpResponse type:' + JSON.stringify(data.resultType)); - console.info('HttpResponse header:' + JSON.stringify(data.header)); if (200 === data.responseCode) { - console.info('HttpResponse code:' + (data.result as string).indexOf(ServerConstants.LOGIN_FAILED)); - if ((data.result as string).indexOf(ServerConstants.LOGIN_FAILED) !== -1) { + console.info('HttpResponse code:' + + (data.result as string).indexOf(AppConstants.LOGIN_FAILED)); + if ((data.result as string).indexOf(AppConstants.LOGIN_FAILED) !== -1) { this.loginFailed(); return; } - AppStorage.setOrCreate('loginName', userName); let loginCookie: string[] = data.header['set-cookie']; let cookie: string = loginCookie.map(cookie => { const parts = cookie.split('='); return `${parts[0]}=${parts[1]}`; }).join('; ') - AppStorage.setOrCreate('loginCookie', cookie); + + AppStorage.setOrCreate(AppConstants.LOGIN_COOKIE, cookie); + AppStorage.setOrCreate(AppConstants.LOGIN_NAME, userName); let eventData: emitter.EventData = { data: { - "message": ServerConstants.LOGIN_RESULT_SUCCESS, + "message": AppConstants.LOGIN_RESULT_SUCCESS, } }; - emitter.emit(ServerConstants.LOGIN_RESULT, this.emitterOptions, eventData); + emitter.emit(AppConstants.LOGIN_RESULT, this.emitterOptions, eventData); this.getCustomListFromServer(); } } else { @@ -171,8 +170,7 @@ export default class HttpManager { this.loginFailed(); } }); - } - catch (error) { + } catch (error) { console.error("JSON :", error.message); this.loginFailed(); } @@ -193,23 +191,23 @@ export default class HttpManager { loginFailed() { let eventData: emitter.EventData = { data: { - "message": ServerConstants.LOGIN_RESULT_FAILED, + "message": AppConstants.LOGIN_RESULT_FAILED, } }; - emitter.emit(ServerConstants.LOGIN_RESULT, this.emitterOptions, eventData); + emitter.emit(AppConstants.LOGIN_RESULT, this.emitterOptions, eventData); prompt.showToast({ - message: ServerConstants.LOGIN_INFO_FAILED + message: AppConstants.LOGIN_INFO_FAILED }) } //记录最近播放信息,并获取歌曲格式 record_recent() { - let loginCookie: string | undefined = AppStorage.get('loginCookie'); + let loginCookie: string | undefined = AppStorage.get(AppConstants.LOGIN_COOKIE); if (loginCookie === '' || loginCookie === undefined) { return; } try { - this.httpRequest.request(ServerConstants.RECORD_RECENT + this.PlayerManager.getItem().id, + this.httpRequest.request(AppStorage.get(AppConstants.SERVER_HOST_PROP) + AppConstants.RECORD_RECENT_URL + this.PlayerManager.getItem().id, { method: http.RequestMethod.GET, header: { @@ -219,14 +217,10 @@ export default class HttpManager { (err: Error, data: http.HttpResponse) => { if (!err) { console.info('HttpResponse record_recent Result:' + data.result); - console.info('HttpResponse code:' + data.responseCode); - console.info('HttpResponse type:' + JSON.stringify(data.resultType)); - console.info('HttpResponse header:' + JSON.stringify(data.header)); - console.info('HttpResponse cookies:' + data.cookies); try { const jsonObject: object = JSON.parse(data.result as string); this.PlayerManager.setItemQuality(jsonObject['message']); - emitter.emit(ServerConstants.DETAIL_UPDATE_FAVOR_AND_QUALITY, this.emitterOptions); + emitter.emit(AppConstants.DETAIL_UPDATE_FAVOR_AND_QUALITY, this.emitterOptions); } catch (err) { console.info('HttpResponse error:' + JSON.stringify(err)); } @@ -244,14 +238,26 @@ export default class HttpManager { } //设置收藏 - set_favourite() { - let loginCookie: string | undefined = AppStorage.get('loginCookie'); + set_favourite(itemToSet?: AudioData, alwaysSet?: boolean) { + let loginCookie: string | undefined = AppStorage.get(AppConstants.LOGIN_COOKIE); + if (loginCookie === undefined || loginCookie === AppConstants.LOGIN_COOKIE_NONE) { + prompt.showToast({ + message: AppConstants.LOGIN_INFO_NO + }) + return; + } let msg: string = '' try { let item = this.PlayerManager.getItem(); + if (itemToSet !== undefined) { + item = itemToSet; + } let is_favor: string = item.isFavor ? '0' : '1'; - console.info('HttpResponse start:' + ServerConstants.SET_FAVOURITE + item.id + '/' + is_favor); - this.httpRequest.request(ServerConstants.SET_FAVOURITE + item.id + '/' + is_favor, + if (alwaysSet) { + is_favor = '1'; + } + console.info('HttpResponse start:' + AppConstants.SET_FAVOURITE_URL + item.id + '/' + is_favor); + this.httpRequest.request(AppStorage.get(AppConstants.SERVER_HOST_PROP) + AppConstants.SET_FAVOURITE_URL + item.id + '/' + is_favor, { method: http.RequestMethod.GET, header: { @@ -261,19 +267,15 @@ export default class HttpManager { (err: Error, data: http.HttpResponse) => { if (!err) { console.info('HttpResponse Result:' + data.result); - console.info('HttpResponse code:' + data.responseCode); - console.info('HttpResponse type:' + JSON.stringify(data.resultType)); - console.info('HttpResponse header:' + JSON.stringify(data.header)); - console.info('HttpResponse cookies:' + data.cookies); try { const jsonObject: object = JSON.parse(data.result as string); switch (jsonObject["message"]) { - case ServerConstants.SET_FAVOURITE_ALREADY: - case ServerConstants.SET_FAVOURITE_SUCCESS: + case AppConstants.SET_FAVOURITE_ALREADY: + case AppConstants.SET_FAVOURITE_SUCCESS: item.isFavor = true; break; - case ServerConstants.CANCEL_FAVOURITE_SUCCESS: - case ServerConstants.CANCEL_FAVOURITE_ALREADY: + case AppConstants.CANCEL_FAVOURITE_SUCCESS: + case AppConstants.CANCEL_FAVOURITE_ALREADY: item.isFavor = false; break; default: @@ -281,13 +283,12 @@ export default class HttpManager { break; } this.PlayerManager.setItemFavor(item.isFavor); - emitter.emit(ServerConstants.DETAIL_UPDATE_FAVOR_AND_QUALITY, this.emitterOptions); + emitter.emit(AppConstants.DETAIL_UPDATE_FAVOR_AND_QUALITY, this.emitterOptions); prompt.showToast({ message: jsonObject["message"] }) this.getFavorListFromServer(); - } - catch (error) { + } catch (error) { console.error("JSON :", error.message); msg = JSON.stringify(error); } @@ -311,11 +312,68 @@ export default class HttpManager { //歌曲加入歌单 add_to_playlist(song_id: string, playlist_name: string) { - let loginCookie: string | undefined = AppStorage.get('loginCookie'); + let loginCookie: string | undefined = AppStorage.get(AppConstants.LOGIN_COOKIE); + if (loginCookie === undefined || loginCookie === AppConstants.LOGIN_COOKIE_NONE) { + prompt.showToast({ + message: AppConstants.LOGIN_INFO_NO + }) + return; + } + let msg: string = '' + try { + console.info('HttpResponse start:' + AppConstants.ADD_TO_PLAYLIST_URL + song_id + '/' + playlist_name); + this.httpRequest.request(AppStorage.get(AppConstants.SERVER_HOST_PROP) + AppConstants.ADD_TO_PLAYLIST_URL + song_id + '/' + playlist_name, + { + method: http.RequestMethod.GET, + header: { + 'Cookie': loginCookie + } + }, + (err: Error, data: http.HttpResponse) => { + if (!err) { + console.info('HttpResponse Result:' + data.result); + try { + const jsonObject: object = JSON.parse(data.result as string); + console.info('HttpResponse msg:' + jsonObject["message"]); + prompt.showToast({ + message: jsonObject["message"] + }) + this.getCustomListFromServer(); + } catch (error) { + console.error("JSON :", error.message); + msg = JSON.stringify(error); + } + } else { + console.info('HttpResponse error:' + JSON.stringify(err)); + prompt.showToast({ + message: JSON.stringify(err) + }) + } + }); + } catch (err) { + console.info('HttpRequest error:' + JSON.stringify(err)); + msg = JSON.stringify(err); + } + console.info('HttpRequest msg:' + msg); + if (msg !== '') { + prompt.showToast({ + message: msg + }) + } + } + //从歌单删除歌曲 + removeSongFromList(song_id: string, playlist_name: string) { + let loginCookie: string | undefined = AppStorage.get(AppConstants.LOGIN_COOKIE); + if (loginCookie === undefined || loginCookie === AppConstants.LOGIN_COOKIE_NONE) { + prompt.showToast({ + message: AppConstants.LOGIN_INFO_NO + }) + return; + } let msg: string = '' try { - console.info('HttpResponse start:' + ServerConstants.ADD_TO_PLAYLIST + song_id + '/' + playlist_name); - this.httpRequest.request(ServerConstants.ADD_TO_PLAYLIST + song_id + '/' + playlist_name, + console.info('HttpResponse start:' + AppConstants.REMOVE_FROM_PLAYLIST_URL + song_id + '/' + playlist_name); + this.httpRequest.request(AppStorage.get(AppConstants.SERVER_HOST_PROP) + AppConstants.REMOVE_FROM_PLAYLIST_URL + song_id + '/' + playlist_name, { method: http.RequestMethod.GET, header: { @@ -325,10 +383,6 @@ export default class HttpManager { (err: Error, data: http.HttpResponse) => { if (!err) { console.info('HttpResponse Result:' + data.result); - console.info('HttpResponse code:' + data.responseCode); - console.info('HttpResponse type:' + JSON.stringify(data.resultType)); - console.info('HttpResponse header:' + JSON.stringify(data.header)); - console.info('HttpResponse cookies:' + data.cookies); try { const jsonObject: object = JSON.parse(data.result as string); console.info('HttpResponse msg:' + jsonObject["message"]); @@ -362,11 +416,11 @@ export default class HttpManager { //获取推荐歌单 getRecommendListFromServer() { try { - this.httpRequest.request(ServerConstants.RECOMMEND_LIST_URL, + this.httpRequest.request(AppStorage.get(AppConstants.SERVER_HOST_PROP) + AppConstants.RECOMMEND_LIST_URL, { method: http.RequestMethod.GET, header: { - 'Cookie': AppStorage.get('loginCookie') + 'Cookie': AppStorage.get(AppConstants.LOGIN_COOKIE) } }, (err: Error, data: http.HttpResponse) => { @@ -390,28 +444,23 @@ export default class HttpManager { )); }) let item = new PlayListData(key1, $r('app.media.icon'), - aPlayingList.length + ServerConstants.LIST_SONG_COUNT, + aPlayingList.length + AppConstants.LIST_SONG_COUNT, aPlayingList, '') playingLists.push(item); }); let eventData: emitter.EventData = { data: { - "message": ServerConstants.UPDATE_USER_LIST_RECOMMEND, + "message": AppConstants.UPDATE_USER_LIST_RECOMMEND, "item": new PlayListGroupData(key, playingLists), "isStart": isStart, } }; - emitter.emit(ServerConstants.UPDATE_USER_LIST, this.emitterOptions, eventData); + emitter.emit(AppConstants.UPDATE_USER_LIST, this.emitterOptions, eventData); isStart = false; }); - } - catch (error) { + } catch (error) { console.error("JSON :", error.message); } - console.info('HttpResponse code:' + data.responseCode); - console.info('HttpResponse type:' + JSON.stringify(data.resultType)); - console.info('HttpResponse header:' + JSON.stringify(data.header)); - console.info('HttpResponse cookies:' + data.cookies); } else { console.info('HttpResponse error:' + JSON.stringify(err)); prompt.showToast({ @@ -430,11 +479,11 @@ export default class HttpManager { //获取我的收藏 getFavorListFromServer() { try { - this.httpRequest.request(ServerConstants.FAVOR_LIST_URL, + this.httpRequest.request(AppStorage.get(AppConstants.SERVER_HOST_PROP) + AppConstants.FAVOR_LIST_URL, { method: http.RequestMethod.GET, header: { - 'Cookie': AppStorage.get('loginCookie') + 'Cookie': AppStorage.get(AppConstants.LOGIN_COOKIE) } }, (err: Error, data: http.HttpResponse) => { @@ -444,38 +493,33 @@ export default class HttpManager { let aPlayingList: AudioData[] = Array(); const jsonObject: object = JSON.parse(data.result as string); let item: PlayListData | undefined = undefined; - if (jsonObject[ServerConstants.LIST_SONG_FAVOURITE]) { - Object.keys(jsonObject[ServerConstants.LIST_SONG_FAVOURITE]).forEach((key) => { + if (jsonObject[AppConstants.LIST_SONG_FAVOURITE]) { + Object.keys(jsonObject[AppConstants.LIST_SONG_FAVOURITE]).forEach((key) => { aPlayingList.push(new AudioData( - jsonObject[ServerConstants.LIST_SONG_FAVOURITE][key].name, - jsonObject[ServerConstants.LIST_SONG_FAVOURITE][key].singer, - jsonObject[ServerConstants.LIST_SONG_FAVOURITE][key].id, - jsonObject[ServerConstants.LIST_SONG_FAVOURITE][key].album, - jsonObject[ServerConstants.LIST_SONG_FAVOURITE][key].year, - jsonObject[ServerConstants.LIST_SONG_FAVOURITE][key].language + jsonObject[AppConstants.LIST_SONG_FAVOURITE][key].name, + jsonObject[AppConstants.LIST_SONG_FAVOURITE][key].singer, + jsonObject[AppConstants.LIST_SONG_FAVOURITE][key].id, + jsonObject[AppConstants.LIST_SONG_FAVOURITE][key].album, + jsonObject[AppConstants.LIST_SONG_FAVOURITE][key].year, + jsonObject[AppConstants.LIST_SONG_FAVOURITE][key].language ) ); }); - item = new PlayListData(ServerConstants.LIST_SONG_FAVOURITE, $r('app.media.icon'), - aPlayingList.length + ServerConstants.LIST_SONG_COUNT, + item = new PlayListData(AppConstants.LIST_SONG_FAVOURITE, $r('app.media.icon'), + aPlayingList.length + AppConstants.LIST_SONG_COUNT, aPlayingList, '') } this.PlayerManager.setFavourList(aPlayingList); let eventData: emitter.EventData = { data: { - "message": ServerConstants.UPDATE_USER_LIST_FAVOR, + "message": AppConstants.UPDATE_USER_LIST_FAVOR, "item": item, } }; - emitter.emit(ServerConstants.UPDATE_USER_LIST, this.emitterOptions, eventData); - } - catch (error) { + emitter.emit(AppConstants.UPDATE_USER_LIST, this.emitterOptions, eventData); + } catch (error) { console.error("JSON :", error.message); } - console.info('HttpResponse code:' + data.responseCode); - console.info('HttpResponse type:' + JSON.stringify(data.resultType)); - console.info('HttpResponse header:' + JSON.stringify(data.header)); - console.info('HttpResponse cookies:' + data.cookies); } else { console.info('HttpResponse error:' + JSON.stringify(err)); prompt.showToast({ @@ -494,11 +538,11 @@ export default class HttpManager { //获取最近播放 getRecentListFromServer() { try { - this.httpRequest.request(ServerConstants.RECENT_LIST_URL, + this.httpRequest.request(AppStorage.get(AppConstants.SERVER_HOST_PROP) + AppConstants.RECENT_LIST_URL, { method: http.RequestMethod.GET, header: { - 'Cookie': AppStorage.get('loginCookie') + 'Cookie': AppStorage.get(AppConstants.LOGIN_COOKIE) } }, (err: Error, data: http.HttpResponse) => { @@ -521,26 +565,21 @@ export default class HttpManager { }); let item = new PlayListData(key, $r('app.media.icon'), - aPlayingList.length + ServerConstants.LIST_SONG_COUNT, + aPlayingList.length + AppConstants.LIST_SONG_COUNT, aPlayingList, ''); let eventData: emitter.EventData = { data: { - "message": ServerConstants.UPDATE_USER_LIST_RECENT, + "message": AppConstants.UPDATE_USER_LIST_RECENT, "item": item, "isStart": isStart, } }; - emitter.emit(ServerConstants.UPDATE_USER_LIST, this.emitterOptions, eventData); + emitter.emit(AppConstants.UPDATE_USER_LIST, this.emitterOptions, eventData); isStart = false; }); - } - catch (error) { + } catch (error) { console.error("JSON :", error.message); } - console.info('HttpResponse code:' + data.responseCode); - console.info('HttpResponse type:' + JSON.stringify(data.resultType)); - console.info('HttpResponse header:' + JSON.stringify(data.header)); - console.info('HttpResponse cookies:' + data.cookies); } else { console.info('HttpResponse error:' + JSON.stringify(err)); prompt.showToast({ @@ -559,11 +598,11 @@ export default class HttpManager { //获取自定义歌单 getCustomListFromServer() { try { - this.httpRequest.request(ServerConstants.CUSTOM_LIST_URL, + this.httpRequest.request(AppStorage.get(AppConstants.SERVER_HOST_PROP) + AppConstants.CUSTOM_LIST_URL, { method: http.RequestMethod.GET, header: { - 'Cookie': AppStorage.get('loginCookie') + 'Cookie': AppStorage.get(AppConstants.LOGIN_COOKIE) } }, (err: Error, data: http.HttpResponse) => { @@ -595,26 +634,27 @@ export default class HttpManager { console.log(`Playlist: ${playlistName}`); let aPlayingList: AudioData[] = Array(); groupedByPlaylistName[playlistName].forEach((song, index) => { - aPlayingList.push(new AudioData(song.name, song.singer, song.id, song.album, song.year, song.language)); + aPlayingList.push(new AudioData(song.name, song.singer, song.id, song.album, song.year, + song.language)); }); let item = new PlayListData(playlistName, $r('app.media.icon'), - aPlayingList.length + ServerConstants.LIST_SONG_COUNT, + aPlayingList.length + AppConstants.LIST_SONG_COUNT, aPlayingList, '') + item.isCustom = true; let eventData: emitter.EventData = { data: { - "message": ServerConstants.UPDATE_USER_LIST_CUSTOM, + "message": AppConstants.UPDATE_USER_LIST_CUSTOM, "item": item, "isStart": isStart, } }; - emitter.emit(ServerConstants.UPDATE_USER_LIST, this.emitterOptions, eventData); + emitter.emit(AppConstants.UPDATE_USER_LIST, this.emitterOptions, eventData); isStart = false; }); this.getRecentListFromServer(); this.getFavorListFromServer(); - } - catch (error) { + } catch (error) { console.error("JSON :", error.message); } } else { @@ -632,11 +672,11 @@ export default class HttpManager { //搜素歌曲 searchSongsFromServer(search_word: string) { try { - this.httpRequest.request(ServerConstants.SEARCH_SONG_URL + search_word, + this.httpRequest.request(AppStorage.get(AppConstants.SERVER_HOST_PROP) + AppConstants.SEARCH_SONG_URL + search_word, { method: http.RequestMethod.GET, header: { - 'Cookie': AppStorage.get('loginCookie') + 'Cookie': AppStorage.get(AppConstants.LOGIN_COOKIE) } }, (err: Error, data: http.HttpResponse) => { @@ -660,22 +700,51 @@ export default class HttpManager { let item = new PlayListData(jsonObject[key][key2].name, $r('app.media.icon'), '', aPlayingList, '') let eventData: emitter.EventData = { data: { - "message": ServerConstants.UPDATE_USER_LIST_SEARCH, + "message": AppConstants.UPDATE_USER_LIST_SEARCH, "item": item, "isStart": isStart, } }; - emitter.emit(ServerConstants.UPDATE_USER_LIST, this.emitterOptions, eventData); + emitter.emit(AppConstants.UPDATE_USER_LIST, this.emitterOptions, eventData); isStart = false; }); }); } catch (error) { console.error("JSON :", error.message); } - console.info('HttpResponse code:' + data.responseCode); - console.info('HttpResponse type:' + JSON.stringify(data.resultType)); - console.info('HttpResponse header:' + JSON.stringify(data.header)); - console.info('HttpResponse cookies:' + data.cookies); + } else { + console.info('HttpResponse error:' + JSON.stringify(err)); + prompt.showToast({ + message: JSON.stringify(err) + }) + } + }); + } catch (err) { + console.info('HttpRequest error:' + JSON.stringify(err)); + } + } + + //查询歌词 + getLrc(id: string) { + try { + this.httpRequest.request(AppStorage.get(AppConstants.SERVER_HOST_PROP) + AppConstants.GET_SONG_LRC_URL + id, + { + method: http.RequestMethod.GET, + header: { + 'Cookie': AppStorage.get(AppConstants.LOGIN_COOKIE) + } + }, + (err: Error, data: http.HttpResponse) => { + if (!err) { + console.info('HttpResponse getLrc Result:' + data.result); + try { + const jsonObject: object = JSON.parse(data.result as string); + let id: string = jsonObject['id']; + let lrc: string = jsonObject['lrc']; + this.PlayerManager.setLrc(id, lrc); + } catch (error) { + console.error("JSON :", error.message); + } } else { console.info('HttpResponse error:' + JSON.stringify(err)); prompt.showToast({ diff --git a/scenario/MusicPlayerOnline/entry/src/main/ets/manager/PlayerManager.ets b/scenario/MusicPlayerOnline/entry/src/main/ets/manager/PlayerManager.ets index a9e96f8c0..00f14c053 100644 --- a/scenario/MusicPlayerOnline/entry/src/main/ets/manager/PlayerManager.ets +++ b/scenario/MusicPlayerOnline/entry/src/main/ets/manager/PlayerManager.ets @@ -18,7 +18,7 @@ import { BusinessError } from '@ohos.base'; import AudioData from '../model/AudioData'; import Logger from '../utils/Logger'; import emitter from '@ohos.events.emitter'; -import ServerConstants from '../constants/ServerConstants'; +import AppConstants from '../constants/AppConstants'; import { PLAY_MODE } from '../constants/PlayMode'; import backgroundTaskManager from '@ohos.resourceschedule.backgroundTaskManager'; import wantAgent, { WantAgent } from '@ohos.app.ability.wantAgent'; @@ -28,7 +28,8 @@ import PlayListData from '../model/PlayListData'; import Base from '@ohos.base'; import formProvider from '@ohos.app.form.formProvider'; import formBindingData from '@ohos.app.form.formBindingData'; - +import CommonUtils from '../utils/CommonUtils'; +import prompt from '@ohos.promptAction'; export default class PlayerManager { private tag: string = 'PlayerManager'; @@ -42,8 +43,8 @@ export default class PlayerManager { private currentDuration: number = 0; private item: AudioData = new AudioData('未播放', '--', ''); private listPosition: number = 0; - private state: string = ServerConstants.PLAYER_STATE_UNKNOWN; - private listTitle: string = ServerConstants.LIST_SONG_NO_PLAYING; + private state: string = AppConstants.PLAYER_STATE_UNKNOWN; + private listTitle: string = AppConstants.LIST_SONG_NO_PLAYING; private playMode: number = PLAY_MODE.REPEAT; private shuffleIndex: number[] = []; private emitterOptions: emitter.Options = { @@ -54,6 +55,21 @@ export default class PlayerManager { this.startContinuousTask(); } + initialPlayMode() { + if (AppStorage.get(AppConstants.KEEP_LOGIN_SETTING) != AppConstants.TOGGLE_SETTING_ON) { + AppStorage.setOrCreate(AppConstants.LOGIN_COOKIE, AppConstants.LOGIN_COOKIE_NONE); + AppStorage.setOrCreate(AppConstants.LOGIN_NAME, AppConstants.LOGIN_INFO_NO); + } + this.playMode = PLAY_MODE.REPEAT; + if (AppStorage.get(AppConstants.PLAY_MODE_SETTING) == AppConstants.TOGGLE_SETTING_ON) { + let record: number | undefined = AppStorage.get(AppConstants.PLAY_MODE_RECORD); + if (record !== undefined) { + this.playMode = record; + } + } + this.recordPlayMode(); + } + // 注册avplayer回调函数 setAVPlayerCallback(avPlayer: media.AVPlayer) { // seek操作结果回调函数 @@ -75,8 +91,8 @@ export default class PlayerManager { "currentDuration": this.currentDuration } }; - emitter.emit(ServerConstants.MAIN_UPDATE_TIME, this.emitterOptions, eventData); - emitter.emit(ServerConstants.DETAIL_UPDATE_TIME, this.emitterOptions, eventData); + emitter.emit(AppConstants.MAIN_UPDATE_TIME, this.emitterOptions, eventData); + emitter.emit(AppConstants.DETAIL_UPDATE_TIME, this.emitterOptions, eventData); }) avPlayer.on('durationUpdate', (time: number) => { console.info('PlayerManager state durationUpdate:' + time); @@ -92,44 +108,44 @@ export default class PlayerManager { "state": state, } }; - emitter.emit(ServerConstants.MAIN_UPDATE_STATE, this.emitterOptions, eventData); - emitter.emit(ServerConstants.DETAIL_UPDATE_STATE, this.emitterOptions, eventData); - emitter.emit(ServerConstants.PLAYLIST_UPDATE_STATE, this.emitterOptions, eventData); + emitter.emit(AppConstants.MAIN_UPDATE_STATE, this.emitterOptions, eventData); + emitter.emit(AppConstants.DETAIL_UPDATE_STATE, this.emitterOptions, eventData); + emitter.emit(AppConstants.PLAYLIST_UPDATE_STATE, this.emitterOptions, eventData); this.updateCard(); switch (state) { - case ServerConstants.PLAYER_STATE_IDLE: // 成功调用reset接口后触发该状态机上报 + case AppConstants.PLAYER_STATE_IDLE: // 成功调用reset接口后触发该状态机上报 console.info('PlayerManager state idle called.'); //avPlayer.release(); // 调用release接口销毁实例对象 break; - case ServerConstants.PLAYER_STATE_INITIALIZED: // avplayer 设置播放源后触发该状态上报 + case AppConstants.PLAYER_STATE_INITIALIZED: // avplayer 设置播放源后触发该状态上报 console.info('PlayerManager state initialized called.'); avPlayer.prepare(); break; - case ServerConstants.PLAYER_STATE_PREPARED: // prepare调用成功后上报该状态机 + case AppConstants.PLAYER_STATE_PREPARED: // prepare调用成功后上报该状态机 console.info('PlayerManager state prepared called.'); avPlayer.play(); // 调用播放接口开始播放 break; - case ServerConstants.PLAYER_STATE_PLAYING: // play成功调用后触发该状态机上报 + case AppConstants.PLAYER_STATE_PLAYING: // play成功调用后触发该状态机上报 console.info('PlayerManager state playing called.'); this.list[this.listPosition].isPlaying = true; HttpManager.getInstance().record_recent(); break; - case ServerConstants.PLAYER_STATE_PAUSED: // pause成功调用后触发该状态机上报 + case AppConstants.PLAYER_STATE_PAUSED: // pause成功调用后触发该状态机上报 console.info('PlayerManager state paused called.'); break; - case ServerConstants.PLAYER_STATE_COMPLETED: // 播放结束后触发该状态机上报 + case AppConstants.PLAYER_STATE_COMPLETED: // 播放结束后触发该状态机上报 console.info('PlayerManager state completed called.'); //avPlayer.stop(); //调用播放结束接口 this.next(); break; - case ServerConstants.PLAYER_STATE_STOPPED: // stop接口成功调用后触发该状态机上报 + case AppConstants.PLAYER_STATE_STOPPED: // stop接口成功调用后触发该状态机上报 console.info('PlayerManager state stopped called.'); //this.stopContinuousTask(); this.currentTime = 0; Logger.info(this.tag, 'Stop:' + this.item.title); avPlayer.reset(); // 调用reset接口初始化avplayer状态 break; - case ServerConstants.PLAYER_STATE_RELEASED: + case AppConstants.PLAYER_STATE_RELEASED: console.info('PlayerManager state released called.'); break; default: @@ -158,14 +174,14 @@ export default class PlayerManager { } this.list = list; this.listTitle = listTitle; - this.playMode = PLAY_MODE.REPEAT; + this.initialPlayMode(); this.shuffleIndex = []; for (let i = 0; i < list.length; i++) { this.shuffleIndex.push(i); } this.play(item); if (isNotify) { - emitter.emit(ServerConstants.PLAYLIST_UPDATE_CHANGED, this.emitterOptions); + emitter.emit(AppConstants.PLAYLIST_UPDATE_CHANGED, this.emitterOptions); } } @@ -177,7 +193,7 @@ export default class PlayerManager { * 播放 */ resume(): void { - if (this.state === ServerConstants.PLAYER_STATE_PAUSED && this.avPlayer !== undefined) { + if (this.state === AppConstants.PLAYER_STATE_PAUSED && this.avPlayer !== undefined) { this.avPlayer.play(); } else { this.play(this.item); @@ -212,7 +228,8 @@ export default class PlayerManager { } } this.item.isFavor = isFavor; - this.avPlayerLive(ServerConstants.PLAY_SONG_URL + this.item.id); + HttpManager.getInstance().getLrc(this.item.id); + this.avPlayerLive(AppStorage.get(AppConstants.SERVER_HOST_PROP) + AppConstants.PLAY_SONG_URL + this.item.id); } /** @@ -233,6 +250,7 @@ export default class PlayerManager { if (this.list.length > this.listPosition) { this.list[this.listPosition].isPlaying = false; } + this.item = new AudioData('未播放', '--', ''); } } @@ -322,6 +340,7 @@ export default class PlayerManager { this.playMode = PLAY_MODE.REPEAT; break; } + this.recordPlayMode(); this.updatePlayMode(); return this.playMode; } @@ -333,6 +352,7 @@ export default class PlayerManager { setFormId(formId: string) { this.formId = formId; this.updateCard(); + this.updatePlayMode(); } setItemQuality(quality: string) { @@ -346,6 +366,7 @@ export default class PlayerManager { setExploreList(aPlayListData: PlayListData) { this.explorePlaylistItem = aPlayListData; + emitter.emit(AppConstants.UPDATE_EXPLORE_LIST, this.emitterOptions); } getExploreList(): PlayListData { @@ -387,6 +408,89 @@ export default class PlayerManager { this.favourList = list; } + recordPlayMode() { + AppStorage.setOrCreate(AppConstants.PLAY_MODE_RECORD, this.playMode); + } + + setLrc(id: string, lrc: string) { + if (id == this.item.id) { + this.item.lrc = CommonUtils.getLrc(lrc); + emitter.emit(AppConstants.DETAIL_UPDATE_LRC, this.emitterOptions); + } + } + + addSongToCurrentList(item: AudioData) { + if (this.list.indexOf(item) > -1) { + prompt.showToast({ + message: AppConstants.ADD_TO_CURRENT_LIST_REPEAT + }) + return; + } + let insertIndex = this.listPosition + 1; + this.list.splice(insertIndex, 0, item); + let newShuffleIndex: number[] = [...this.shuffleIndex]; + for (let i = 0; i < newShuffleIndex.length; i++) { + //将原来大于等于插入位置的索引+1 + if (newShuffleIndex[i] >= insertIndex) { + newShuffleIndex[i] += 1; + } + } + let newPosition = newShuffleIndex.findIndex(index => index === this.listPosition); + if (newPosition !== -1) { + newShuffleIndex.splice(newPosition + 1, 0, insertIndex); + } else { + console.error("Original index not found in shuffleIndex"); + } + this.shuffleIndex = newShuffleIndex; + //如果原来没有播放列表,则开始播放 + if (this.list.length === 1) { + this.play(item); + this.listTitle = AppConstants.CURRENT_LIST_TITLE; + } + prompt.showToast({ + message: AppConstants.ADD_TO_CURRENT_LIST_OK + }) + } + + removeSongFromCurrentList(item: AudioData) { + if (this.item.id == item.id) { + this.stop(); + } + let index = this.list.indexOf(item); + if (index > -1) { + this.list.splice(index, 1); + let newShuffleIndex: number[] = [...this.shuffleIndex]; + let shuffleIndex = newShuffleIndex.indexOf(index); + if (shuffleIndex > -1) { + //删除的索引 + newShuffleIndex.splice(shuffleIndex, 1); + for (let i = 0; i < newShuffleIndex.length; i++) { + //将原来大于插入位置的索引-1 + if (newShuffleIndex[i] > index) { + newShuffleIndex[i] -= 1; + } + } + } + this.shuffleIndex = newShuffleIndex; + } + let eventData: emitter.EventData = { + data: { + "state": this.state, + } + }; + emitter.emit(AppConstants.MAIN_UPDATE_STATE, this.emitterOptions, eventData); + emitter.emit(AppConstants.DETAIL_UPDATE_STATE, this.emitterOptions, eventData); + emitter.emit(AppConstants.PLAYLIST_UPDATE_STATE, this.emitterOptions, eventData); + } + + removeSongFromCustomList(item: AudioData) { + //http 从服务器请求删除 + const index = this.explorePlaylistItem.list.indexOf(item); + if (index > -1) { + this.explorePlaylistItem.list.splice(index, 1); + } + } + //设置后台任务 startContinuousTask() { let wantAgentInfo: wantAgent.WantAgentInfo = { @@ -456,9 +560,10 @@ export default class PlayerManager { } updateCard() { - let formData: Record = { + let formData: Record = { 'audioItem': this.item, 'isPlaying': this.state, + 'serverHost': AppStorage.get(AppConstants.SERVER_HOST_PROP), }; let formMsg: formBindingData.FormBindingData = formBindingData.createFormBindingData(formData); formProvider.updateForm(this.formId, formMsg).then(() => { @@ -467,6 +572,7 @@ export default class PlayerManager { console.info(`Operation updateForm failed. Cause: ${JSON.stringify(error)}`); }) } + updatePlayMode() { let formData: Record = { 'playMode': this.playMode, diff --git a/scenario/MusicPlayerOnline/entry/src/main/ets/model/AudioData.ets b/scenario/MusicPlayerOnline/entry/src/main/ets/model/AudioData.ets index ea72b1235..96b7283eb 100644 --- a/scenario/MusicPlayerOnline/entry/src/main/ets/model/AudioData.ets +++ b/scenario/MusicPlayerOnline/entry/src/main/ets/model/AudioData.ets @@ -12,6 +12,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +import LrcLine from "./LrcLine"; /** * AudioItem data entity. @@ -23,6 +24,7 @@ export default class AudioData { artist: string = ''; isPlaying: boolean = false; isFavor: boolean = false; + lrc: LrcLine[] = [] quality = '.mp3'; album?: string = ''; year?: string = ''; diff --git a/scenario/MusicPlayerOnline/entry/src/main/ets/model/LrcLine.ets b/scenario/MusicPlayerOnline/entry/src/main/ets/model/LrcLine.ets index af6f3a636..10bbf1711 100644 --- a/scenario/MusicPlayerOnline/entry/src/main/ets/model/LrcLine.ets +++ b/scenario/MusicPlayerOnline/entry/src/main/ets/model/LrcLine.ets @@ -17,11 +17,10 @@ * List item data entity. */ export default class LrcLine { - time: string; + time: number; title: string; - - constructor(time: string, title: string) { + constructor(time: number, title: string) { this.title = title; this.time = time; } diff --git a/scenario/MusicPlayerOnline/entry/src/main/ets/model/PlayListData.ets b/scenario/MusicPlayerOnline/entry/src/main/ets/model/PlayListData.ets index 530d62ebb..046c2f8ba 100644 --- a/scenario/MusicPlayerOnline/entry/src/main/ets/model/PlayListData.ets +++ b/scenario/MusicPlayerOnline/entry/src/main/ets/model/PlayListData.ets @@ -30,8 +30,9 @@ export default class PlayListData { * Other resource of list item. */ others?: string; - subTitle: string - list: AudioData[] = [] + subTitle: string; + list: AudioData[] = []; + isCustom = false; constructor(title: string, img: Resource, subTitle: string, list: AudioData[], others?: string) { this.title = title; diff --git a/scenario/MusicPlayerOnline/entry/src/main/ets/constants/UIConstants.ets b/scenario/MusicPlayerOnline/entry/src/main/ets/model/SettingItem.ets similarity index 66% rename from scenario/MusicPlayerOnline/entry/src/main/ets/constants/UIConstants.ets rename to scenario/MusicPlayerOnline/entry/src/main/ets/model/SettingItem.ets index 0ab04da04..c664ddf7f 100644 --- a/scenario/MusicPlayerOnline/entry/src/main/ets/constants/UIConstants.ets +++ b/scenario/MusicPlayerOnline/entry/src/main/ets/model/SettingItem.ets @@ -13,10 +13,19 @@ * limitations under the License. */ - /** - * Common constants for UI features. + * SettingItem data entity. */ -export default class ServerConstants { - static readonly CLICK_EFFECT:ClickEffect = {level:ClickEffectLevel.MIDDLE, scale: 0.8}; +export default class SettingItem { + title: string; + img: Resource; + subTitle: string; + others?: boolean = false; + + constructor(title: string, img: Resource, subTitle: string, others?: boolean) { + this.title = title; + this.img = img; + this.others = others; + this.subTitle = subTitle; + } } \ No newline at end of file diff --git a/scenario/MusicPlayerOnline/entry/src/main/ets/pages/Index.ets b/scenario/MusicPlayerOnline/entry/src/main/ets/pages/Index.ets index b37ba2cba..2416506df 100644 --- a/scenario/MusicPlayerOnline/entry/src/main/ets/pages/Index.ets +++ b/scenario/MusicPlayerOnline/entry/src/main/ets/pages/Index.ets @@ -15,31 +15,38 @@ import PlayerBar from '../view/PlayerBar'; import CurrentPlayList from '../view/CurrentPlayList'; -import ServerConstants from '../constants/ServerConstants'; -import UIConstants from '../constants/UIConstants'; +import AppConstants from '../constants/AppConstants'; import PlayListData from '../model/PlayListData'; import PlayListGroupData from '../model/PlayListGroupData'; import PlayerDetail from '../view/PlayerDetail'; import emitter from '@ohos.events.emitter'; import prompt from '@ohos.promptAction'; import Setting from '../view/Setting'; -import { LoginCustomDialog } from '../view/loginDialog'; +import { LoginCustomDialog } from '../view/LoginDialog'; import HttpManager from '../manager/HttpManager'; import SingleRowScrollerList from '../view/SingleRowScrollerList'; import TriColGridList from '../view/TriColGridList'; import TriColNestScrollerGrid from '../view/TriColNestScrollerGrid'; import ExplorePlayList from '../view/ExplorePlayList'; +import { PLAY_MODE } from '../constants/PlayMode'; +import PlayerManager from '../manager/PlayerManager'; -PersistentStorage.persistProp('loginCookie', ''); -PersistentStorage.persistProp('loginName', ServerConstants.LOGIN_INFO_NO); +PersistentStorage.persistProp(AppConstants.LOGIN_COOKIE, ''); +PersistentStorage.persistProp(AppConstants.LOGIN_NAME, AppConstants.LOGIN_INFO_NO); +PersistentStorage.persistProp(AppConstants.DETAIL_DEFAULT_SETTING, AppConstants.TOGGLE_SETTING_OFF); +PersistentStorage.persistProp(AppConstants.PLAY_MODE_SETTING, AppConstants.TOGGLE_SETTING_OFF); +PersistentStorage.persistProp(AppConstants.PLAY_MODE_RECORD, PLAY_MODE.REPEAT); +PersistentStorage.persistProp(AppConstants.KEEP_LOGIN_SETTING, AppConstants.TOGGLE_SETTING_ON); +PersistentStorage.persistProp(AppConstants.SERVER_HOST_PROP, AppConstants.SERVER_HOST); @Entry @Component struct Index { + private PlayerManager: PlayerManager = AppStorage.get('PlayerManager') as PlayerManager; @State recommendPlayLists: PlayListGroupData[] = []; @State customPlayLists: PlayListData[] = []; @State searchResultPlayLists: PlayListData[] = []; - @State searchSongTitle: string = ServerConstants.SEARCH_DEFAULT; + @State searchSongTitle: string = AppConstants.SEARCH_DEFAULT; @State isShowPlayerDetail: boolean = false; @State isShowCurrentPlayList: boolean = false; @State isShowPlayList: boolean = false; @@ -48,8 +55,8 @@ struct Index { @State mOffset: number = 0; @State mFriction: number = 48; @State maskOpacity: number = 0.5; - @State loginInfo: string = ServerConstants.LOGIN_INFO_NO; - @State loginButton: string = ServerConstants.LOGIN_BUTTON_IN; + @State loginInfo: string = AppConstants.LOGIN_INFO_NO; + @State loginButton: string = AppConstants.LOGIN_BUTTON_IN; @State colAngle: number = 0; @State isShowSidebar: boolean = false; private rootScroller: Scroller = new Scroller() @@ -62,7 +69,7 @@ struct Index { cancel: () => { if (this.dialogController !== null) { this.dialogController.close() - this.loginButton = ServerConstants.LOGIN_BUTTON_IN; + this.loginButton = AppConstants.LOGIN_BUTTON_IN; } }, confirm: (isRegister: boolean) => { @@ -97,40 +104,41 @@ struct Index { } aboutToAppear(): void { - let loginName: string | undefined = AppStorage.get('loginName'); + let loginName: string | undefined = AppStorage.get(AppConstants.LOGIN_NAME); + this.PlayerManager.initialPlayMode(); HttpManager.getInstance().getRecommendListFromServer(); - if (loginName != ServerConstants.LOGIN_INFO_NO) { - this.loginInfo = loginName + ServerConstants.LOGIN_INFO_DONE; - this.loginButton = ServerConstants.LOGIN_BUTTON_OUT; + if (loginName != AppConstants.LOGIN_INFO_NO) { + this.loginInfo = loginName + AppConstants.LOGIN_INFO_DONE; + this.loginButton = AppConstants.LOGIN_BUTTON_OUT; HttpManager.getInstance().getCustomListFromServer(); } else { this.customPlayLists = []; } - emitter.on(ServerConstants.LOGIN_RESULT, (eventData: emitter.EventData) => { + emitter.on(AppConstants.LOGIN_RESULT, (eventData: emitter.EventData) => { this.updateLogin(eventData); }); - emitter.on(ServerConstants.UPDATE_USER_LIST, (eventData: emitter.EventData) => { + emitter.on(AppConstants.UPDATE_USER_LIST, (eventData: emitter.EventData) => { this.updateLists(eventData); }); - emitter.on(ServerConstants.PLAYLIST_UPDATE_CHANGED, () => { + emitter.on(AppConstants.PLAYLIST_UPDATE_CHANGED, () => { if (!this.isShowPlayerDetail) { this.isShowPlayerDetail = true; } }); - emitter.on(ServerConstants.MAIN_SHOW_PLAYLIST, () => { + emitter.on(AppConstants.MAIN_SHOW_PLAYLIST, () => { this.showExplorePlaylist(); }); } aboutToDisappear(): void { - emitter.off(ServerConstants.UPDATE_USER_LIST); - emitter.off(ServerConstants.LOGIN_RESULT); - emitter.off(ServerConstants.PLAYLIST_UPDATE_CHANGED); - emitter.off(ServerConstants.MAIN_SHOW_PLAYLIST); + emitter.off(AppConstants.UPDATE_USER_LIST); + emitter.off(AppConstants.LOGIN_RESULT); + emitter.off(AppConstants.PLAYLIST_UPDATE_CHANGED); + emitter.off(AppConstants.MAIN_SHOW_PLAYLIST); if (this.dialogController !== null) { this.dialogController.close(); this.dialogController = null; @@ -157,7 +165,7 @@ struct Index { .width(96) .height('100%') .alignSelf(ItemAlign.Start) - .clickEffect(UIConstants.CLICK_EFFECT) + .clickEffect(AppConstants.CLICK_EFFECT) .onClick(() => { animateTo({ duration: 1000 }, () => { this.isShowSidebar = true; @@ -165,7 +173,7 @@ struct Index { }) .id('setting') - if (this.loginInfo === ServerConstants.LOGIN_INFO_NO) { + if (this.loginInfo === AppConstants.LOGIN_INFO_NO) { Text(this.loginInfo) .fontSize(24) .margin({ right: 4, left: 4 }) @@ -191,11 +199,11 @@ struct Index { .fontSize(28) .maxLines(1) .shadow({ radius: 1, color: Color.Gray }) - .clickEffect(UIConstants.CLICK_EFFECT) + .clickEffect(AppConstants.CLICK_EFFECT) .onClick(() => { - if (this.loginButton === ServerConstants.LOGIN_BUTTON_OUT) { + if (this.loginButton === AppConstants.LOGIN_BUTTON_OUT) { this.logout(); - } else if (this.loginButton === ServerConstants.LOGIN_BUTTON_IN) { + } else if (this.loginButton === AppConstants.LOGIN_BUTTON_IN) { if (this.dialogController != null) { this.dialogController.open() } @@ -230,7 +238,7 @@ struct Index { Scroll(this.rootScroller) { Column() { - if (this.searchSongTitle !== ServerConstants.SEARCH_DEFAULT) { + if (this.searchSongTitle !== AppConstants.SEARCH_DEFAULT) { TriColGridList({ title: this.searchSongTitle, playLists: this.searchResultPlayLists }) } @@ -268,7 +276,7 @@ struct Index { .onRefreshing(() => { setTimeout(() => { HttpManager.getInstance().getRecommendListFromServer(); - if (this.loginInfo != ServerConstants.LOGIN_INFO_NO) { + if (this.loginInfo != AppConstants.LOGIN_INFO_NO) { HttpManager.getInstance().getCustomListFromServer(); } else { this.customPlayLists = []; @@ -278,7 +286,7 @@ struct Index { }) if (this.isShowPlayList) { - ExplorePlayList({ isShowPlayList: this.isShowPlayList }) + ExplorePlayList({ isShowPlayList: this.isShowPlayList, customPlayLists: this.customPlayLists, }) .width('100%') .height('90%') .transition(TransitionEffect.OPACITY @@ -374,37 +382,37 @@ struct Index { } logout() { - AppStorage.setOrCreate('loginName', ServerConstants.LOGIN_INFO_NO); - AppStorage.setOrCreate('loginCookie', ''); - this.loginButton = ServerConstants.LOGIN_BUTTON_IN; + AppStorage.setOrCreate(AppConstants.LOGIN_NAME, AppConstants.LOGIN_INFO_NO); + AppStorage.setOrCreate(AppConstants.LOGIN_COOKIE, AppConstants.LOGIN_COOKIE_NONE); + this.loginButton = AppConstants.LOGIN_BUTTON_IN; animateTo({ duration: 2000 }, () => { this.customPlayLists = []; - this.loginInfo = ServerConstants.LOGIN_INFO_NO; + this.loginInfo = AppConstants.LOGIN_INFO_NO; }) HttpManager.getInstance().getRecommendListFromServer(); //TODO request logout from server } login(userName: string, pwd: string) { - this.loginButton = ServerConstants.LOGIN_INFO_ING; + this.loginButton = AppConstants.LOGIN_INFO_ING; HttpManager.getInstance().login(userName, pwd) } register(userName: string, pwd: string, pwd2: string) { - this.loginButton = ServerConstants.LOGIN_INFO_ING; + this.loginButton = AppConstants.LOGIN_INFO_ING; HttpManager.getInstance().register(userName, pwd, pwd2); } searchSongsFromServer(search_word: string) { search_word = search_word.trim(); if (!search_word) { - prompt.showToast({ message: ServerConstants.EMPTY_SEARCH_WORD }); + prompt.showToast({ message: AppConstants.EMPTY_SEARCH_WORD }); return; } animateTo( { duration: 1000 }, () => { - this.searchSongTitle = search_word + ServerConstants.SEARCHING; + this.searchSongTitle = search_word + AppConstants.SEARCHING; this.searchResultPlayLists = []; }) HttpManager.getInstance().searchSongsFromServer(search_word); @@ -413,9 +421,9 @@ struct Index { updateLogin(eventData: emitter.EventData) { if (eventData !== undefined && eventData.data !== undefined) { switch (eventData.data.message) { - case ServerConstants.LOGIN_RESULT_SUCCESS: - this.loginInfo = this.inputUserName + ServerConstants.LOGIN_INFO_DONE; - this.loginButton = ServerConstants.LOGIN_BUTTON_OUT; + case AppConstants.LOGIN_RESULT_SUCCESS: + this.loginInfo = this.inputUserName + AppConstants.LOGIN_INFO_DONE; + this.loginButton = AppConstants.LOGIN_BUTTON_OUT; if (this.dialogController !== null) { this.dialogController.close(); } @@ -424,10 +432,10 @@ struct Index { this.colAngle = 180; this.rootScroller.scrollEdge(Edge.Bottom); }) - },2000) + }, 2000) break; - case ServerConstants.LOGIN_RESULT_FAILED: - this.loginButton = ServerConstants.LOGIN_BUTTON_IN; + case AppConstants.LOGIN_RESULT_FAILED: + this.loginButton = AppConstants.LOGIN_BUTTON_IN; break; default: break; @@ -444,7 +452,7 @@ struct Index { updateLists(eventData: emitter.EventData) { if (eventData !== undefined && eventData.data !== undefined) { switch (eventData.data.message) { - case ServerConstants.UPDATE_USER_LIST_RECOMMEND: + case AppConstants.UPDATE_USER_LIST_RECOMMEND: if (eventData.data.isStart) { animateTo({ duration: 2000 }, () => { this.recommendPlayLists = []; @@ -459,7 +467,7 @@ struct Index { } }) break; - case ServerConstants.UPDATE_USER_LIST_CUSTOM: + case AppConstants.UPDATE_USER_LIST_CUSTOM: if (eventData.data.isStart) { animateTo({ duration: 2000 }, () => { this.customPlayLists = []; @@ -469,10 +477,13 @@ struct Index { if (eventData.data !== undefined && eventData.data.item !== undefined) { console.info('UPDATE_USER_LIST_CUSTOM:' + (eventData.data.item as PlayListData).title); this.customPlayLists.push(eventData.data.item as PlayListData); + if ((eventData.data.item as PlayListData).title === this.PlayerManager.getExploreList().title) { + this.PlayerManager.setExploreList(eventData.data.item as PlayListData); + } } }) break; - case ServerConstants.UPDATE_USER_LIST_RECENT: + case AppConstants.UPDATE_USER_LIST_RECENT: animateTo( { duration: 1000 }, () => { @@ -488,7 +499,7 @@ struct Index { } }) break; - case ServerConstants.UPDATE_USER_LIST_SEARCH: + case AppConstants.UPDATE_USER_LIST_SEARCH: if (eventData.data.isStart) { animateTo({ duration: 2000 }, () => { this.searchResultPlayLists = [] @@ -503,8 +514,8 @@ struct Index { } }) break; - case ServerConstants.UPDATE_USER_LIST_FAVOR: - let existingIndex = this.customPlayLists.findIndex(item => item.title === ServerConstants.LIST_SONG_FAVOURITE); + case AppConstants.UPDATE_USER_LIST_FAVOR: + let existingIndex = this.customPlayLists.findIndex(item => item.title === AppConstants.LIST_SONG_FAVOURITE); animateTo( { duration: 1000 }, () => { diff --git a/scenario/MusicPlayerOnline/entry/src/main/ets/utils/CommonUtils.ets b/scenario/MusicPlayerOnline/entry/src/main/ets/utils/CommonUtils.ets index 694bac6c8..f042ed6db 100644 --- a/scenario/MusicPlayerOnline/entry/src/main/ets/utils/CommonUtils.ets +++ b/scenario/MusicPlayerOnline/entry/src/main/ets/utils/CommonUtils.ets @@ -14,38 +14,68 @@ */ import HashMap from '@ohos.util.HashMap'; // 导入HashMap模块 +import HttpManager from '../manager/HttpManager'; import LrcLine from '../model/LrcLine'; /** * Binds data to components and provides interfaces. */ export class CommonUtils { - private lrcs: HashMap = new HashMap(); - private setLrcs() { - this.lrcs.set('十一种孤独', '[ti:十一种孤独]\n[ar:宿羽阳]\n[al:宿羽阳]\n[by:]\n[offset:0]\n[00:00.46]十一种孤独 - 宿羽阳\n[00:00.78]词:陶小陶\n[00:00.96]曲:宿羽阳\n[00:01.14]编曲:谭侃侃\n[00:01.89]\n[00:30.75]最孤独是读评论区未署名情书\n[00:34.85]\n[00:37.27]像不小心掀开了时光的典故\n[00:41.47]\n[00:44.37]第十是睁开眼就已黄昏迟暮\n[00:48.21]\n[00:51.10]寒星三两落在远远处\n[00:55.48]\n[00:57.95]第九是海蓝时见鲸 林深时见鹿\n[01:01.92]\n[01:04.66]却不见你 在梦醒之处\n[01:08.94]\n[01:11.47]第八是回家的路途绕了几次远路\n[01:16.10]\n[01:18.06]像电台的老情歌循环着音符\n[01:22.34]\n[01:24.84]愿你风尘仆仆 深情不被辜负\n[01:29.32]\n[01:31.41]虽回不到过去 也回不到当初\n[01:36.60]\n[01:38.46]愿你半生漂浮此生能有归宿\n[01:42.99]\n[01:45.20]愿你风雨落幕能有人免你孤苦\n[01:50.38]\n[02:05.91]第七是看一场一群人的演出\n[02:10.02]\n[02:12.61]荧光满眼却看不清楚\n[02:16.74]\n[02:19.44]第六是一个人吃饭 一个人写书\n[02:23.47]\n[02:26.19]一个人拼岁月拼图\n[02:30.43]\n[02:33.03]第五是骑单车过陌生的马路\n[02:37.04]\n[02:39.49]在拥挤的人海中踌躇\n[02:43.57]\n[02:46.52]第四是给空白的纸上画上五线谱\n[02:51.28]\n[02:53.24]每一行都好像是世界的遗嘱\n[02:57.49]\n[02:59.96]愿你风尘仆仆 深情不被辜负\n[03:04.62]\n[03:06.69]虽回不到过去 也回不到当初\n[03:11.60]\n[03:13.38]愿你半生漂浮此生能有归宿\n[03:18.10]\n[03:20.19]愿你风雨落幕能有人免你孤苦\n[03:25.11]\n[03:27.10]愿你风尘仆仆 深情不被辜负\n[03:32.01]\n[03:33.82]虽回不到过去 也回不到当初\n[03:38.70]\n[03:40.52]愿你半生漂浮此生能有归宿\n[03:45.84]\n[03:47.32]愿你风雨落幕能有人免你孤独\n[03:51.97]\n[03:54.58]第三是假装很成熟 假装很忙碌\n[03:58.60]\n[04:01.25]假装擅长一个人独处\n[04:05.28]\n[04:07.94]第二是穿过万家灯火无数\n[04:12.10]\n[04:14.85]却无一人等我在归途\n[04:18.96]\n[04:21.74]第一是收到远方一纸家书\n[04:25.65]\n[04:28.18]说照顾自己 累了别忍着不哭') - } - getLrc(name: string): LrcLine[] { + getLrc(lrc: string): LrcLine[] { let lrcData: LrcLine[] = []; - let lrc = this.lrcs.get(name); - if (lrc !== null && lrc !== undefined) { - let lines = lrc.split('\n'); - // Create an array to store the LRC data + if (lrc !== null && lrc !== undefined && lrc !== '') { + let lines = lrc.replace(/\\n/g, '\n').split('\n'); for (let line of lines) { - // Check if the line is a valid LRC line if (line.includes('[')) { - // Split the line into the time and text components let content = line.split(']'); - // Add the time and text to the LRC data array if (content.length > 1 && content[1].trim() !== '') { - lrcData.push(new LrcLine(content[0], content[1])); + let time: number = this.parseLrcTime(content[0] + ']'); + lrcData.push(new LrcLine(time, content[1])); } } } } - // Return the LRC data array return lrcData; } + + findLrcIndexByTime(lrcList: LrcLine[], currentTime: number, currentIndex: number): number { + if (lrcList == null || lrcList == undefined || lrcList.length < 1) { + return -1; + } + //判断是否已经到最后 + if (currentTime >= lrcList[lrcList.length - 1].time || currentIndex + 1 == lrcList.length) { + return lrcList.length - 1; + } + //从当前index往后查找,减少计算量,在支持seek后,需要先重置currentIndex + for (let i = currentIndex; i < lrcList.length; i++) { + if (currentTime >= lrcList[i].time && currentTime < lrcList[i+1].time) { + if (i > 0 && lrcList[i].time == lrcList[i-1].time) { + //带翻译的双语,时间相同返回原始语言行 + return (i - 1); + } + return i; + } + } + return 0; + } + + parseLrcTime(timeStr: string): number { + // 修改正则表达式以匹配两种格式的毫秒部分 + const parts = timeStr.match(/\[(\d{2}):(\d{2})\.(\d{2})(\d{0,1})?\]/); + if (!parts) { + console.info('time format error.'); + return 0; + } + const minutes = parseInt(parts[1], 10); + const seconds = parseInt(parts[2], 10); + let milliseconds = parseInt(parts[3], 10) * 10; // 将两位数字转换为毫秒 + if (parts[4]) { + milliseconds += parseInt(parts[4], 10); // 如果存在第三个数字,转换为毫秒 + } + return minutes * 60000 + seconds * 1000 + milliseconds; + } + formatTime(time: number): string { let min = Math.floor(time / 60).toString(); let sec = Math.floor((time % 60)).toString() @@ -58,4 +88,5 @@ export class CommonUtils { return min + ':' + sec; } } + export default new CommonUtils(); \ No newline at end of file diff --git a/scenario/MusicPlayerOnline/entry/src/main/ets/view/addToListDialog.ets b/scenario/MusicPlayerOnline/entry/src/main/ets/view/AddToListDialog.ets similarity index 97% rename from scenario/MusicPlayerOnline/entry/src/main/ets/view/addToListDialog.ets rename to scenario/MusicPlayerOnline/entry/src/main/ets/view/AddToListDialog.ets index cbab52709..21f432b6e 100644 --- a/scenario/MusicPlayerOnline/entry/src/main/ets/view/addToListDialog.ets +++ b/scenario/MusicPlayerOnline/entry/src/main/ets/view/AddToListDialog.ets @@ -12,10 +12,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { Font } from '@ohos.arkui.UIContext'; @CustomDialog -export struct addToListDialog { +export struct AddToListDialog { @Link inputListName: string; @State title: string = '将歌曲加入[新建歌单]或[已有歌单]'; @State text: string = "选择已有歌单"; diff --git a/scenario/MusicPlayerOnline/entry/src/main/ets/view/CurrentPlayList.ets b/scenario/MusicPlayerOnline/entry/src/main/ets/view/CurrentPlayList.ets index 44814e140..0dff9143c 100644 --- a/scenario/MusicPlayerOnline/entry/src/main/ets/view/CurrentPlayList.ets +++ b/scenario/MusicPlayerOnline/entry/src/main/ets/view/CurrentPlayList.ets @@ -17,14 +17,13 @@ import AudioData from '../model/AudioData'; import PlayerManager from '../manager/PlayerManager' import SongItem from './SongItem'; import emitter from '@ohos.events.emitter'; -import ServerConstants from '../constants/ServerConstants'; -import UIConstants from '../constants/UIConstants'; +import AppConstants from '../constants/AppConstants'; @Component export default struct CurrentPlayList { private playerManager: PlayerManager = AppStorage.get('PlayerManager') as PlayerManager; @State playingList: AudioData[] = Array(); - @State listTitle: string = ServerConstants.LIST_SONG_NO_PLAYING; + @State listTitle: string = AppConstants.LIST_SONG_NO_PLAYING; private scrollerForList: Scroller = new Scroller(); aboutToAppear() { @@ -33,16 +32,17 @@ export default struct CurrentPlayList { this.playingList = this.playerManager.getCurrentPlayList(); }) setTimeout(() => { - this.scrollerForList.scrollToIndex(this.playingList.indexOf(this.playerManager.getItem()), true, ScrollAlign.CENTER); + this.scrollerForList.scrollToIndex(this.playingList.indexOf(this.playerManager.getItem()), true, + ScrollAlign.CENTER); }, 2000) - emitter.on(ServerConstants.PLAYLIST_UPDATE_STATE, (eventData: emitter.EventData) => { + emitter.on(AppConstants.PLAYLIST_UPDATE_STATE, (eventData: emitter.EventData) => { this.updateState(eventData); }); } aboutToDisappear(): void { - emitter.off(ServerConstants.PLAYLIST_UPDATE_STATE); + emitter.off(AppConstants.PLAYLIST_UPDATE_STATE); } build() { @@ -62,16 +62,29 @@ export default struct CurrentPlayList { List({ scroller: this.scrollerForList }) { ForEach(this.playingList, (item: AudioData) => { ListItem() { - SongItem({ item }) + Row() { + SongItem({ item }) + .width('90%') + .clickEffect(AppConstants.CLICK_EFFECT) + .onClick(() => { + this.playerManager.play(item) + }) + if (!item.isPlaying) { + Image($r('app.media.xmark')) + .height(36) + .width(36) + .padding(8) + .clickEffect(AppConstants.CLICK_EFFECT) + .onClick(() => { + this.playerManager.removeSongFromCurrentList(item); + }) + } + }.margin(8) } .width('100%') .height('84vp') .backgroundColor(item.isPlaying ? '#f0f0f0' : Color.White) .transition({ type: TransitionType.All, opacity: 0 }) - .clickEffect(UIConstants.CLICK_EFFECT) - .onClick(() => { - this.playerManager.play(item) - }) }) } .width('100%') @@ -84,12 +97,14 @@ export default struct CurrentPlayList { } updateState(eventData: emitter.EventData) { - if (eventData !== undefined && eventData.data !== undefined && eventData.data.state === ServerConstants.PLAYER_STATE_PLAYING) { + if (eventData !== undefined && eventData.data !== undefined && + eventData.data.state === AppConstants.PLAYER_STATE_PLAYING) { animateTo({ duration: 2000 }, () => { this.playingList = this.playerManager.getCurrentPlayList(); }) setTimeout(() => { - this.scrollerForList.scrollToIndex(this.playingList.indexOf(this.playerManager.getItem()), true, ScrollAlign.CENTER); + this.scrollerForList.scrollToIndex(this.playingList.indexOf(this.playerManager.getItem()), true, + ScrollAlign.CENTER); }, 2000) } } diff --git a/scenario/MusicPlayerOnline/entry/src/main/ets/view/ExploreListMore.ets b/scenario/MusicPlayerOnline/entry/src/main/ets/view/ExploreListMore.ets new file mode 100644 index 000000000..4e47a0561 --- /dev/null +++ b/scenario/MusicPlayerOnline/entry/src/main/ets/view/ExploreListMore.ets @@ -0,0 +1,183 @@ +/* + * Copyright (c) 2024 Shenzhen Kaihong Digital Industry Development Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import HttpManager from "../manager/HttpManager"; +import PlayerManager from "../manager/PlayerManager"; +import AudioData from "../model/AudioData"; +import PlayListData from "../model/PlayListData"; +import { AddToListDialog } from "./AddToListDialog"; +import prompt from '@ohos.promptAction'; +import AppConstants from "../constants/AppConstants"; + +@Component +struct MoreItem { + private img: ResourceStr = ''; + private title: string = '' + private operate: () => void = () => { + } + + build() { + Row() { + Image(this.img) + .width(28) + .height(28) + .margin(8) + Text(this.title) + .maxLines(1) + .fontSize(20) + .fontWeight(FontWeight.Lighter) + Blank() + Image($r('app.media.chevron_right')) + .width(12) + .height(24) + } + .width('90%') + .margin(8) + .justifyContent(FlexAlign.SpaceBetween) + .onClick(this.operate) + } +} + +@CustomDialog +export struct ExploreListMore { + private clickedItem: AudioData = new AudioData('', '', ''); + private customListTitle: string = ''; + private playerManager: PlayerManager = AppStorage.get('PlayerManager') as PlayerManager; + controller?: CustomDialogController; + @State listOptions: Array = []; + @State inputListName: string = ''; + @Prop customPlayLists: PlayListData[]; + private songIdToAdd: string = ''; + dialogController: CustomDialogController | null = new CustomDialogController({ + builder: AddToListDialog({ + cancel: () => { + if (this.dialogController !== null) { + this.dialogController.close(); + } + }, + confirm: () => { + if (this.inputListName.trim()) { + if (this.songIdToAdd !== '') { + HttpManager.getInstance().add_to_playlist(this.songIdToAdd, this.inputListName); + this.songIdToAdd = ''; + if (this.dialogController !== null) { + this.dialogController.close(); + } + } + } else { + prompt.showToast({ + message: '歌单名不能为空' + }); + } + }, + inputListName: $inputListName, + listOptions: $listOptions, + }), + autoCancel: true, + alignment: DialogAlignment.Bottom, + offset: { dx: 0, dy: -20 }, + gridCount: 4, + customStyle: false, + cornerRadius: 10, + }) + + aboutToDisappear(): void { + if (this.dialogController !== null) { + this.dialogController.close(); + this.dialogController = null; + } + } + + build() { + Column() { + Text(this.clickedItem.title + '-' + this.clickedItem.artist) + .fontSize(20) + .maxLines(1) + .margin({ top: 10, bottom: 10 }) + + List({ space: 10 }) { + ListItem() { + MoreItem({ + img: $r('app.media.order_play'), + title: '下一首播放', operate: () => { + this.playerManager.addSongToCurrentList(this.clickedItem); + if (this.controller != undefined) { + this.controller.close() + } + } + }) + } + + ListItem() { + MoreItem({ + img: $r('app.media.heart'), + title: '加入到我的收藏', operate: () => { + HttpManager.getInstance().set_favourite(this.clickedItem, true); + if (this.controller != undefined) { + this.controller.close() + } + } + }) + } + + ListItem() { + MoreItem({ + img: $r('app.media.folder_badge_plus'), + title: '加入其他到歌单', operate: () => { + if (this.dialogController != null) { + this.listOptions = []; + for (let item of this.customPlayLists) { + if (item.title !== AppConstants.LIST_SONG_FAVOURITE && + item.title !== AppConstants.LIST_SONG_RECENT && + item.title !== this.customListTitle) { + this.listOptions.push({ value: item.title }); + } + } + this.dialogController.open(); + this.songIdToAdd = this.clickedItem.id; + } + } + }) + } + + if (this.customListTitle !== '') { + ListItem() { + MoreItem({ + img: $r('app.media.trash'), + title: '从歌单[' + this.customListTitle + ']删除', operate: () => { + HttpManager.getInstance().removeSongFromList(this.clickedItem.id, this.customListTitle); + if (this.controller != undefined) { + this.controller.close() + } + } + }) + } + } + } + .backgroundColor(Color.White) + .divider({ + strokeWidth: 0.25, + color: Color.Grey, + startMargin: 24, + endMargin: 24 + }) + .borderRadius(16) + .padding({ top: 4, bottom: 4 }) + .alignListItem(ListItemAlign.Center) + } + .width('90%') + .borderRadius(8) + .alignItems(HorizontalAlign.Center) + } +} \ No newline at end of file diff --git a/scenario/MusicPlayerOnline/entry/src/main/ets/view/ExplorePlayList.ets b/scenario/MusicPlayerOnline/entry/src/main/ets/view/ExplorePlayList.ets index 4db54078e..3da8f425a 100644 --- a/scenario/MusicPlayerOnline/entry/src/main/ets/view/ExplorePlayList.ets +++ b/scenario/MusicPlayerOnline/entry/src/main/ets/view/ExplorePlayList.ets @@ -16,24 +16,34 @@ import AudioData from '../model/AudioData'; import PlayerManager from '../manager/PlayerManager' import ExploreSongItem from './ExploreSongItem'; -import UIConstants from '../constants/UIConstants'; +import AppConstants from '../constants/AppConstants'; import PlayListData from '../model/PlayListData'; import prompt from '@ohos.promptAction'; +import { ExploreListMore } from './ExploreListMore'; +import emitter from '@ohos.events.emitter'; @Component export default struct ExplorePlayList { private PlayerManager: PlayerManager = AppStorage.get('PlayerManager') as PlayerManager; @State explorePlaylistItem: PlayListData = new PlayListData('', $r('app.media.icon'), '', [], ''); @Link isShowPlayList: boolean; + @Prop customPlayLists: PlayListData[]; private scrollerForList: Scroller = new Scroller(); + private dialogController: CustomDialogController | null = null; aboutToAppear() { animateTo({ duration: 1000 }, () => { this.explorePlaylistItem = this.PlayerManager.getExploreList(); }) + emitter.on(AppConstants.UPDATE_EXPLORE_LIST, () => { + animateTo({ duration: 1000 }, () => { + this.explorePlaylistItem = this.PlayerManager.getExploreList(); + }) + }); } aboutToDisappear(): void { + emitter.off(AppConstants.UPDATE_EXPLORE_LIST); } build() { @@ -43,7 +53,7 @@ export default struct ExplorePlayList { .width(48) .height(48) .padding(6) - .clickEffect(UIConstants.CLICK_EFFECT) + .clickEffect(AppConstants.CLICK_EFFECT) .onClick(() => { this.isShowPlayList = false; }) @@ -64,13 +74,14 @@ export default struct ExplorePlayList { .width(48) .height(48) .padding(6) - .clickEffect(UIConstants.CLICK_EFFECT) + .clickEffect(AppConstants.CLICK_EFFECT) .onClick(() => { if (this.explorePlaylistItem.list.length > 0) { prompt.showToast({ message: '播放歌单:' + this.explorePlaylistItem.title }) - this.PlayerManager.playList(this.explorePlaylistItem.title, this.explorePlaylistItem.list, this.explorePlaylistItem.list[0]); + this.PlayerManager.playList(this.explorePlaylistItem.title, this.explorePlaylistItem.list, + this.explorePlaylistItem.list[0]); } }) } @@ -83,19 +94,41 @@ export default struct ExplorePlayList { ListItem() { Row() { ExploreSongItem({ item, index }) - } + .width('85%') + .clickEffect(AppConstants.CLICK_EFFECT) + .onClick(() => { + prompt.showToast({ + message: '播放歌曲:' + item.title + }) + this.PlayerManager.playList(this.explorePlaylistItem.title, this.explorePlaylistItem.list, item); + }) + Image($r('app.media.more')) + .height(48) + .width(48) + .padding(8) + .clickEffect(AppConstants.CLICK_EFFECT) + .onClick(() => { + this.dialogController = new CustomDialogController({ + builder: ExploreListMore({ + clickedItem: item, + customListTitle: (this.explorePlaylistItem.isCustom ? this.explorePlaylistItem.title : ''), + customPlayLists: this.customPlayLists, + }), + autoCancel: true, + alignment: DialogAlignment.Bottom, + offset: { dx: 0, dy: -20 }, + gridCount: 4, + customStyle: false, + cornerRadius: 10, + }) + this.dialogController.open(); + }) + }.justifyContent(FlexAlign.SpaceEvenly) } .backgroundColor((index % 2) === 0 ? '#fafafa' : Color.White) .width('100%') .height('84vp') .transition({ type: TransitionType.All, opacity: 0 }) - .clickEffect(UIConstants.CLICK_EFFECT) - .onClick(() => { - prompt.showToast({ - message: '播放歌曲:' + item.title - }) - this.PlayerManager.playList(this.explorePlaylistItem.title, this.explorePlaylistItem.list, item); - }) }) } .width('100%') diff --git a/scenario/MusicPlayerOnline/entry/src/main/ets/view/ExploreSongItem.ets b/scenario/MusicPlayerOnline/entry/src/main/ets/view/ExploreSongItem.ets index ed332789c..92fe16cb7 100644 --- a/scenario/MusicPlayerOnline/entry/src/main/ets/view/ExploreSongItem.ets +++ b/scenario/MusicPlayerOnline/entry/src/main/ets/view/ExploreSongItem.ets @@ -14,7 +14,7 @@ */ import AudioData from '../model/AudioData'; -import ServerConstants from '../constants/ServerConstants'; +import AppConstants from '../constants/AppConstants'; @Component export default struct ExploreSongItem { @@ -39,18 +39,21 @@ export default struct ExploreSongItem { Text(this.item.artist) .fontColor('#a0a0a0') .maxLines(1) - Blank() + .width('50%') + .textOverflow({overflow:TextOverflow.Ellipsis}) Text(this.item.album+'('+this.item.year+')') .fontColor('#a0a0a0') .maxLines(1) + .width('50%') + .textOverflow({overflow:TextOverflow.MARQUEE}) + .textAlign(TextAlign.End) } - .align(Alignment.Start) .width('90%') .justifyContent(FlexAlign.SpaceBetween) } } .justifyContent(FlexAlign.SpaceBetween) - .width('90%') + .width('100%') .alignSelf(ItemAlign.Center) } } diff --git a/scenario/MusicPlayerOnline/entry/src/main/ets/view/InputServerHost.ets b/scenario/MusicPlayerOnline/entry/src/main/ets/view/InputServerHost.ets new file mode 100644 index 000000000..430c305c4 --- /dev/null +++ b/scenario/MusicPlayerOnline/entry/src/main/ets/view/InputServerHost.ets @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2024 Shenzhen Kaihong Digital Industry Development Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@CustomDialog +export struct InputServerHost { + @Link inputListName: string|undefined; + @State title: string = '修改服务器地址:'; + controller?: CustomDialogController; + cancel: () => void = () => { + } + confirm: () => void = () => { + } + + build() { + Column() { + Text(this.title) + .fontSize(20) + .margin({ top: 10, bottom: 10 }) + .fontWeight(FontWeight.Lighter) + Row() { + TextInput({ placeholder: '输入新建歌单名称', text: this.inputListName }) + .height(56) + .fontSize(24) + .width('80%') + .margin(8) + .onChange((value: string) => { + this.inputListName = value + }) + } + + Flex({ justifyContent: FlexAlign.SpaceAround }) { + Button('取消') + .backgroundColor(Color.White) + .fontColor(Color.Black) + .fontWeight(FontWeight.Lighter) + .fontSize(18) + .onClick(() => { + if (this.controller != undefined) { + this.controller.close() + this.cancel() + } + }) + Button('确定') + .backgroundColor(Color.White) + .fontWeight(FontWeight.Lighter) + .fontSize(18) + .fontColor(Color.Red) + .id('login_confirm') + .onClick(() => { + this.confirm() + }) + }.margin({ bottom: 12, top: 12 }) + }.borderRadius(8) + } +} \ No newline at end of file diff --git a/scenario/MusicPlayerOnline/entry/src/main/ets/view/loginDialog.ets b/scenario/MusicPlayerOnline/entry/src/main/ets/view/LoginDialog.ets similarity index 100% rename from scenario/MusicPlayerOnline/entry/src/main/ets/view/loginDialog.ets rename to scenario/MusicPlayerOnline/entry/src/main/ets/view/LoginDialog.ets diff --git a/scenario/MusicPlayerOnline/entry/src/main/ets/view/PlayListItem.ets b/scenario/MusicPlayerOnline/entry/src/main/ets/view/PlayListItem.ets index 5c36ee4be..06e24ced8 100644 --- a/scenario/MusicPlayerOnline/entry/src/main/ets/view/PlayListItem.ets +++ b/scenario/MusicPlayerOnline/entry/src/main/ets/view/PlayListItem.ets @@ -14,11 +14,9 @@ */ import ItemData from '../model/PlayListData'; - -import UIConstants from '../constants/UIConstants'; +import AppConstants from '../constants/AppConstants'; import prompt from '@ohos.promptAction'; import PlayerManager from '../manager/PlayerManager'; -import ServerConstants from '../constants/ServerConstants'; import emitter from '@ohos.events.emitter'; /** @@ -50,7 +48,7 @@ export default struct PlayListItem { .width('100%') } .borderRadius(12) - .backgroundImage(this.item.list.length > 0 ? ServerConstants.SONG_IMAGE_URL + this.item.list[0].id : this.item.img) + .backgroundImage(this.item.list.length > 0 ? AppStorage.get(AppConstants.SERVER_HOST_PROP) + AppConstants.SONG_IMAGE_URL + this.item.list[0].id : this.item.img) .backgroundImageSize(ImageSize.Cover) .shadow({ radius: 1, color: Color.Gray }) .width(120) @@ -66,7 +64,7 @@ export default struct PlayListItem { .margin({ top: 4 }) } .alignItems(HorizontalAlign.Center) - .clickEffect(UIConstants.CLICK_EFFECT) + .clickEffect(AppConstants.CLICK_EFFECT) .gesture( TapGesture({ count: 2 }) .onAction((event: GestureEvent) => { @@ -80,7 +78,7 @@ export default struct PlayListItem { .onAction((event: GestureEvent) => { if (event) { this.PlayerManager.setExploreList(this.item); - emitter.emit(ServerConstants.MAIN_SHOW_PLAYLIST, this.emitterOptions); + emitter.emit(AppConstants.MAIN_SHOW_PLAYLIST, this.emitterOptions); } }) ) diff --git a/scenario/MusicPlayerOnline/entry/src/main/ets/view/PlayerBar.ets b/scenario/MusicPlayerOnline/entry/src/main/ets/view/PlayerBar.ets index ec78a2736..03b1293e4 100644 --- a/scenario/MusicPlayerOnline/entry/src/main/ets/view/PlayerBar.ets +++ b/scenario/MusicPlayerOnline/entry/src/main/ets/view/PlayerBar.ets @@ -19,8 +19,7 @@ import emitter from '@ohos.events.emitter'; import Logger from '../utils/Logger'; import AudioData from '../model/AudioData'; -import ServerConstants from '../constants/ServerConstants'; -import UIConstants from '../constants/UIConstants'; +import AppConstants from '../constants/AppConstants'; import PlayerManager from '../manager/PlayerManager'; @Component @@ -30,7 +29,7 @@ export default struct PlayerBar { @State rotateAngle: number = 0; @State durationTime: number = 100; @State currentTime: number = 0; - @State state: string = ServerConstants.PLAYER_STATE_UNKNOWN; + @State state: string = AppConstants.PLAYER_STATE_UNKNOWN; @Link isShowCurrentPlayList: boolean; @Link isShowPlayerDetail: boolean; private PlayerManager: PlayerManager = AppStorage.get('PlayerManager') as PlayerManager; @@ -38,24 +37,24 @@ export default struct PlayerBar { aboutToAppear() { Logger.info(this.tag, 'aboutToAppear'); - emitter.on(ServerConstants.MAIN_UPDATE_TIME, (eventData: emitter.EventData) => { + emitter.on(AppConstants.MAIN_UPDATE_TIME, (eventData: emitter.EventData) => { this.updateTime(eventData); }); - emitter.on(ServerConstants.MAIN_UPDATE_STATE, (eventData: emitter.EventData) => { + emitter.on(AppConstants.MAIN_UPDATE_STATE, (eventData: emitter.EventData) => { this.updateState(eventData) }); } aboutToDisappear() { - emitter.off(ServerConstants.MAIN_UPDATE_TIME); - emitter.off(ServerConstants.MAIN_UPDATE_STATE); + emitter.off(AppConstants.MAIN_UPDATE_TIME); + emitter.off(AppConstants.MAIN_UPDATE_STATE); Logger.info(this.tag, 'aboutToDisappear'); } build() { Column() { Row() { - Image(this.item.id ? (ServerConstants.SONG_IMAGE_URL + this.item.id) : $r('app.media.startIcon')) + Image(this.item.id ? (AppStorage.get(AppConstants.SERVER_HOST_PROP) + AppConstants.SONG_IMAGE_URL + this.item.id) : $r('app.media.startIcon')) .width(56) .height(56) .margin(4) @@ -70,21 +69,21 @@ export default struct PlayerBar { playMode: PlayMode.Normal }) .id('songImage') - .clickEffect(UIConstants.CLICK_EFFECT) + .clickEffect(AppConstants.CLICK_EFFECT) .onClick(() => { this.isShowPlayerDetail = true; }) - Text(this.item.id ? (this.state === ServerConstants.PLAYER_STATE_PLAYING ? this.spaces + this.item.title + ' - ' + this.item.artist + this.spaces - : this.item.title + ' - ' + this.item.artist) : ServerConstants.LIST_SONG_NO_PLAYING) + Text(this.item.id ? (this.state === AppConstants.PLAYER_STATE_PLAYING ? this.spaces + this.item.title + ' - ' + this.item.artist + this.spaces + : this.item.title + ' - ' + this.item.artist) : AppConstants.LIST_SONG_NO_PLAYING) .fontSize('24fp') .maxLines(1) .textOverflow({ - overflow: (this.state === ServerConstants.PLAYER_STATE_PLAYING) ? TextOverflow.MARQUEE : TextOverflow.None + overflow: (this.state === AppConstants.PLAYER_STATE_PLAYING) ? TextOverflow.MARQUEE : TextOverflow.None }) .width('60%') .textAlign(TextAlign.Center) .id('songName') - .clickEffect(UIConstants.CLICK_EFFECT) + .clickEffect(AppConstants.CLICK_EFFECT) .onClick(() => { this.isShowPlayerDetail = true; }) @@ -100,17 +99,17 @@ export default struct PlayerBar { .id('progressBar') } - if (this.state === ServerConstants.PLAYER_STATE_PLAYING) { + if (this.state === AppConstants.PLAYER_STATE_PLAYING) { Image($r('app.media.pause')) .padding('4vp') - .clickEffect(UIConstants.CLICK_EFFECT) + .clickEffect(AppConstants.CLICK_EFFECT) .onClick(() => { this.PlayerManager.pause(); }) .id('paused') } else { Image($r('app.media.media_center')) - .clickEffect(UIConstants.CLICK_EFFECT) + .clickEffect(AppConstants.CLICK_EFFECT) .onClick(() => { this.PlayerManager.resume(); }) @@ -126,7 +125,7 @@ export default struct PlayerBar { .height(40) .margin({ right: 8, left: 8 }) .shadow({ radius: 1, color: Color.Gray }) - .clickEffect(UIConstants.CLICK_EFFECT) + .clickEffect(AppConstants.CLICK_EFFECT) .onClick(() => { this.isShowCurrentPlayList = true; }) @@ -148,14 +147,14 @@ export default struct PlayerBar { updateState(eventData: emitter.EventData) { if (eventData !== undefined && eventData.data !== undefined) { Logger.info(this.tag, 'state:' + eventData.data.state); - if (this.state !== ServerConstants.PLAYER_STATE_PLAYING && eventData.data.state === ServerConstants.PLAYER_STATE_PLAYING) { + if (this.state !== AppConstants.PLAYER_STATE_PLAYING && eventData.data.state === AppConstants.PLAYER_STATE_PLAYING) { this.item = this.PlayerManager.getItem(); if (this.rotateAngle === 0) { this.rotateAngle = 360; Logger.info(this.tag, 'rotateAngle:360'); } } - if (eventData.data.state !== ServerConstants.PLAYER_STATE_PLAYING) { + if (eventData.data.state !== AppConstants.PLAYER_STATE_PLAYING) { this.rotateAngle = 0; Logger.info(this.tag, 'rotateAngle:0'); } diff --git a/scenario/MusicPlayerOnline/entry/src/main/ets/view/PlayerDetail.ets b/scenario/MusicPlayerOnline/entry/src/main/ets/view/PlayerDetail.ets index 3338b9da6..b19650105 100644 --- a/scenario/MusicPlayerOnline/entry/src/main/ets/view/PlayerDetail.ets +++ b/scenario/MusicPlayerOnline/entry/src/main/ets/view/PlayerDetail.ets @@ -16,16 +16,15 @@ import PlayerManager from '../manager/PlayerManager'; import emitter from '@ohos.events.emitter'; import Logger from '../utils/Logger'; -import LrcLine from '../model/LrcLine'; import CommonUtils from '../utils/CommonUtils'; -import ServerConstants from '../constants/ServerConstants'; -import UIConstants from '../constants/UIConstants'; +import AppConstants from '../constants/AppConstants'; import AudioData from '../model/AudioData'; import { PLAY_MODE } from '../constants/PlayMode'; -import { addToListDialog } from './addToListDialog'; +import { AddToListDialog } from './AddToListDialog'; import PlayListData from '../model/PlayListData'; import prompt from '@ohos.promptAction'; import HttpManager from '../manager/HttpManager'; +import LrcLine from '../model/LrcLine'; /** * Setting tab content @@ -42,8 +41,7 @@ export default struct PlayerDetail { @State rotateAngle: number = 0; @State subCurrentIndex: number = 0; @State lrcIndex: number = 0 - @State lrc: LrcLine[] = []; - @State contentSwitch: boolean = true; + @State albumImageContent: boolean = true; @State playMode: number = this.PlayerManager.getPlayMode(); @State noItem: boolean = false; @Link isShowCurrentPlayList: boolean; @@ -53,11 +51,10 @@ export default struct PlayerDetail { @State listOptions: Array = []; @State inputListName: string = ''; private scroller: Scroller = new Scroller() - private tabsController: TabsController = new TabsController(); private isDialogOpened: boolean = false; private songIdToAdd: string = ''; dialogController: CustomDialogController | null = new CustomDialogController({ - builder: addToListDialog({ + builder: AddToListDialog({ cancel: () => { if (this.dialogController !== null) { this.dialogController.close(); @@ -91,33 +88,9 @@ export default struct PlayerDetail { cornerRadius: 10, }) - @Builder - TabBuilder(title: Resource, index: number, selectedImg: Resource, normalImg: Resource) { - Column() { - Row() { - Text(title) - .fontSize('20fp') - .fontColor(this.subCurrentIndex === index ? '#E02020' : '#6B6B6B') - }.alignItems(VerticalAlign.Top) - - Image(this.subCurrentIndex === index ? selectedImg : normalImg) - .width(25) - } - .height(60) - .margin({ - top: 12, - left: 12, - right: 12 - }) - .clickEffect(UIConstants.CLICK_EFFECT) - .onClick(() => { - this.subCurrentIndex = index; - this.tabsController.changeIndex(this.subCurrentIndex); - }) - } - aboutToAppear() { - if (this.state === ServerConstants.PLAYER_STATE_PLAYING) { + this.albumImageContent = (AppStorage.get(AppConstants.DETAIL_DEFAULT_SETTING) != AppConstants.TOGGLE_SETTING_ON); + if (this.state === AppConstants.PLAYER_STATE_PLAYING) { setTimeout(() => { if (this.rotateAngle === 0) { this.rotateAngle = 360; @@ -126,22 +99,26 @@ export default struct PlayerDetail { }, 100); } - emitter.on(ServerConstants.DETAIL_UPDATE_FAVOR_AND_QUALITY, () => { + emitter.on(AppConstants.DETAIL_UPDATE_FAVOR_AND_QUALITY, () => { this.updateFavor(); }); - emitter.on(ServerConstants.DETAIL_UPDATE_TIME, (eventData: emitter.EventData) => { + emitter.on(AppConstants.DETAIL_UPDATE_TIME, (eventData: emitter.EventData) => { this.updateTime(eventData); }); - emitter.on(ServerConstants.DETAIL_UPDATE_STATE, (eventData: emitter.EventData) => { + emitter.on(AppConstants.DETAIL_UPDATE_STATE, (eventData: emitter.EventData) => { this.updateState(eventData); }); + emitter.on(AppConstants.DETAIL_UPDATE_LRC, () => { + this.updateLrc(); + }); } aboutToDisappear() { Logger.info(this.tag, 'aboutToDisappear'); - emitter.off(ServerConstants.DETAIL_UPDATE_TIME); - emitter.off(ServerConstants.DETAIL_UPDATE_STATE); - emitter.off(ServerConstants.DETAIL_UPDATE_FAVOR_AND_QUALITY); + emitter.off(AppConstants.DETAIL_UPDATE_TIME); + emitter.off(AppConstants.DETAIL_UPDATE_STATE); + emitter.off(AppConstants.DETAIL_UPDATE_FAVOR_AND_QUALITY); + emitter.off(AppConstants.DETAIL_UPDATE_LRC); if (this.dialogController !== null) { this.dialogController.close(); this.isDialogOpened = false; @@ -166,14 +143,14 @@ export default struct PlayerDetail { .width(48) .height(48) .padding(6) - .clickEffect(UIConstants.CLICK_EFFECT) + .clickEffect(AppConstants.CLICK_EFFECT) .onClick(() => { this.isShowPlayerDetail = false; }) .id('detail_dismiss') Column() { - if (this.contentSwitch) { + if (this.albumImageContent) { Text(this.listTitle) .fontSize(20) .maxLines(2) @@ -205,11 +182,11 @@ export default struct PlayerDetail { .width(48) .height(48) .padding(8) - .clickEffect(UIConstants.CLICK_EFFECT) + .clickEffect(AppConstants.CLICK_EFFECT) .onClick(() => { - if (this.loginInfo === ServerConstants.LOGIN_INFO_NO) { + if (this.loginInfo === AppConstants.LOGIN_INFO_NO) { prompt.showToast({ - message: '请先登录!' + message: AppConstants.LOGIN_INFO_NO }) return; } @@ -222,7 +199,8 @@ export default struct PlayerDetail { if (this.dialogController != null) { this.listOptions = []; for (let item of this.customPlayLists) { - if (item.title !== ServerConstants.LIST_SONG_FAVOURITE && item.title !== ServerConstants.LIST_SONG_RECENT) { + if (item.title !== AppConstants.LIST_SONG_FAVOURITE && + item.title !== AppConstants.LIST_SONG_RECENT) { this.listOptions.push({ value: item.title }); } } @@ -238,13 +216,13 @@ export default struct PlayerDetail { Column() { if (!this.noItem) { - if (this.contentSwitch) { + if (this.albumImageContent) { Column() { - Image(this.item.id ? ServerConstants.SONG_IMAGE_URL + this.item.id : $r('app.media.startIcon')) - .width('300vp') - .height('300vp') - .borderRadius('200vp') - .margin('50vp') + Image(this.item.id ? AppStorage.get(AppConstants.SERVER_HOST_PROP) + AppConstants.SONG_IMAGE_URL + this.item.id : $r('app.media.startIcon')) + .width(300) + .height(300) + .borderRadius(150) + .margin(50) .rotate({ angle: this.rotateAngle }) .animation({ duration: 36000, @@ -254,10 +232,10 @@ export default struct PlayerDetail { playMode: PlayMode.Normal }) .id('detail_songImg') - .clickEffect(UIConstants.CLICK_EFFECT) + .clickEffect(AppConstants.CLICK_EFFECT) .shadow({ radius: 1, color: Color.Gray }) .onClick(() => { - this.contentSwitch = false; + this.albumImageContent = false; }) Row() { @@ -284,7 +262,7 @@ export default struct PlayerDetail { } .alignContent(Alignment.Top) .margin({ right: '8vp' }) - .clickEffect(UIConstants.CLICK_EFFECT) + .clickEffect(AppConstants.CLICK_EFFECT) .onClick(() => { HttpManager.getInstance().set_favourite(); }) @@ -297,56 +275,54 @@ export default struct PlayerDetail { .transition(TransitionEffect.OPACITY.animation({ duration: 2000, curve: Curve.Ease }).combine( TransitionEffect.translate({ z: 24 }))) } else { - Column() { - Tabs({ - barPosition: BarPosition.End, - index: 0, - controller: this.tabsController - }) { - TabContent() { - Column() { - List({ space: 10, scroller: this.scroller }) { - ForEach(this.lrc, (item: LrcLine, index: number) => { - ListItem() { - if (index === this.lrcIndex) { - Text(item.title) - .width('100%') - .textAlign(TextAlign.Center) - .fontSize('24fp') - .fontColor(Color.Black) - } else { - Text(item.title) - .width('100%') - .textAlign(TextAlign.Center) - .fontSize('18fp') - .fontColor(Color.Gray) - } - } - }) - } + Stack({ alignContent: Alignment.Center }) { + Image(this.item.id ? AppStorage.get(AppConstants.SERVER_HOST_PROP) + AppConstants.SONG_IMAGE_URL + this.item.id : $r('app.media.startIcon')) + .width('80%') + .height('80%') + .foregroundEffect({ radius: 20 }) + .borderRadius(200) + .opacity(0.4) + Column() { + if (this.item.lrc === null || this.item.lrc === undefined || this.item.lrc.length < 1) { + Text('暂无歌词') .width('100%') - }.height('100%') + .height('100%') + .textAlign(TextAlign.Center) + .fontSize('24fp') + .fontColor(Color.Orange) + } else { + List({ space: 10, scroller: this.scroller }) { + ForEach(this.item.lrc, (item: LrcLine, index: number) => { + ListItem() { + if (index === this.lrcIndex) { + Text(item.title) + .width('100%') + .textAlign(TextAlign.Center) + .fontSize('24fp') + .fontColor(Color.Orange) + } else { + Text(item.title) + .width('100%') + .textAlign(TextAlign.Center) + .fontSize('18fp') + .fontColor(Color.Gray) + } + } + }) + } + .scrollBar(BarState.Off) + .width('100%') } - .tabBar(this.TabBuilder($r('app.string.lyrics'), 0, - $r('app.media.ic_screenshot_line_select'), $r('app.media.ic_screenshot_line'))) } - .width('100%') - .barHeight(60) - .barWidth('70%') - .barMode(BarMode.Scrollable) - .barPosition(BarPosition.Start) - .onChange((index: number) => { - this.subCurrentIndex = index; - }) } .width('100%') .height('100%') .transition(TransitionEffect.OPACITY.animation({ duration: 2000, curve: Curve.Ease }).combine( TransitionEffect.translate({ y: -24 }))) - .clickEffect(UIConstants.CLICK_EFFECT) + .clickEffect(AppConstants.CLICK_EFFECT) .onClick(() => { - this.contentSwitch = true; - if (this.state === ServerConstants.PLAYER_STATE_PLAYING) { + this.albumImageContent = true; + if (this.state === AppConstants.PLAYER_STATE_PLAYING) { this.rotateAngle = 0; animateTo({ duration: 36000 }, () => { this.rotateAngle = 360; @@ -382,10 +358,11 @@ export default struct PlayerDetail { .justifyContent(FlexAlign.SpaceBetween) Row() { - Image(this.playMode === PLAY_MODE.REPEAT ? $r('app.media.repeat') : (this.playMode === PLAY_MODE.REPEAT1 ? $r('app.media.repeat_1') : $r('app.media.shuffle'))) + Image(this.playMode === PLAY_MODE.REPEAT ? $r('app.media.repeat') : + (this.playMode === PLAY_MODE.REPEAT1 ? $r('app.media.repeat_1') : $r('app.media.shuffle'))) .width(42) .height(42) - .clickEffect(UIConstants.CLICK_EFFECT) + .clickEffect(AppConstants.CLICK_EFFECT) .onClick(() => { this.playMode = this.PlayerManager.setPlayMode(); }) @@ -393,16 +370,16 @@ export default struct PlayerDetail { Image($r('app.media.backward_end_fill')) .width(42) .height(42) - .clickEffect(UIConstants.CLICK_EFFECT) + .clickEffect(AppConstants.CLICK_EFFECT) .onClick(() => { this.PlayerManager.previous(); }) .id('detail_previous') - if (this.state === ServerConstants.PLAYER_STATE_PLAYING) { + if (this.state === AppConstants.PLAYER_STATE_PLAYING) { Image($r('app.media.pause')) .width(48) .height(48) - .clickEffect(UIConstants.CLICK_EFFECT) + .clickEffect(AppConstants.CLICK_EFFECT) .onClick(() => { this.PlayerManager.pause(); }) @@ -411,7 +388,7 @@ export default struct PlayerDetail { Image($r('app.media.play_fill')) .width(48) .height(48) - .clickEffect(UIConstants.CLICK_EFFECT) + .clickEffect(AppConstants.CLICK_EFFECT) .onClick(() => { this.PlayerManager.resume(); }) @@ -420,7 +397,7 @@ export default struct PlayerDetail { Image($r('app.media.forward_end_fill')) .width(42) .height(42) - .clickEffect(UIConstants.CLICK_EFFECT) + .clickEffect(AppConstants.CLICK_EFFECT) .onClick(() => { this.PlayerManager.next(); }) @@ -428,7 +405,7 @@ export default struct PlayerDetail { Image($r('app.media.music_note_list')) .width(42) .height(42) - .clickEffect(UIConstants.CLICK_EFFECT) + .clickEffect(AppConstants.CLICK_EFFECT) .onClick(() => { this.isShowCurrentPlayList = true; }) @@ -450,14 +427,21 @@ export default struct PlayerDetail { this.noItem = false; } + updateLrc() { + this.item = this.PlayerManager.getItem(); + } + updateTime(eventData: emitter.EventData) { if (eventData !== undefined && eventData.data !== undefined) { this.currentTime = eventData.data.currentTime; this.durationTime = eventData.data.currentDuration; - let newLrcIndex = Math.floor(this.currentTime * this.lrc.length / this.durationTime); - if (newLrcIndex !== this.lrcIndex) { - this.lrcIndex = newLrcIndex; - this.scroller.scrollToIndex(this.lrcIndex - 5, true) + if (!this.albumImageContent) { + let newLrcIndex = CommonUtils.findLrcIndexByTime(this.item.lrc, this.currentTime, this.lrcIndex) + if (newLrcIndex != this.lrcIndex && newLrcIndex != -1) { + this.lrcIndex = newLrcIndex; + console.info('bestMatchIndex:'+newLrcIndex) + this.scroller.scrollToIndex(this.lrcIndex - 5, true) + } } } } @@ -465,13 +449,17 @@ export default struct PlayerDetail { updateState(eventData: emitter.EventData) { if (eventData !== undefined && eventData.data !== undefined) { Logger.info(this.tag, 'state:' + eventData.data.state); - if (eventData.data.state === ServerConstants.PLAYER_STATE_IDLE) { + if (eventData.data.state === AppConstants.PLAYER_STATE_IDLE) { this.noItem = true; } - if (this.state !== ServerConstants.PLAYER_STATE_PLAYING && eventData.data.state === ServerConstants.PLAYER_STATE_PLAYING) { + if (this.state !== AppConstants.PLAYER_STATE_PLAYING && + eventData.data.state !== AppConstants.PLAYER_STATE_PAUSED) { + this.lrcIndex = 0 + } + if (this.state !== AppConstants.PLAYER_STATE_PLAYING && + eventData.data.state === AppConstants.PLAYER_STATE_PLAYING) { this.item = this.PlayerManager.getItem(); this.noItem = false; - this.lrc = CommonUtils.getLrc(this.item.title); this.listTitle = this.PlayerManager.getListTitle(); this.scroller.scrollToIndex(0, true) setTimeout(() => { @@ -481,7 +469,7 @@ export default struct PlayerDetail { } }, 100); } - if (eventData.data.state !== ServerConstants.PLAYER_STATE_PLAYING) { + if (eventData.data.state !== AppConstants.PLAYER_STATE_PLAYING) { this.rotateAngle = 0; Logger.info(this.tag, 'rotateAngle:0'); } diff --git a/scenario/MusicPlayerOnline/entry/src/main/ets/view/Setting.ets b/scenario/MusicPlayerOnline/entry/src/main/ets/view/Setting.ets index 40d3b9482..172f18013 100644 --- a/scenario/MusicPlayerOnline/entry/src/main/ets/view/Setting.ets +++ b/scenario/MusicPlayerOnline/entry/src/main/ets/view/Setting.ets @@ -12,22 +12,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import UIConstants from '../constants/UIConstants'; +import AppConstants from '../constants/AppConstants'; import PlayerManager from '../manager/PlayerManager'; - -class SettingItem { - title: string; - img: Resource; - subTitle: string; - others?: boolean = false; - - constructor(title: string, img: Resource, subTitle: string, others?: boolean) { - this.title = title; - this.img = img; - this.others = others; - this.subTitle = subTitle; - } -} +import SettingItem from '../model/SettingItem'; +import settingCell from './SettingCell'; /** * Setting tab content @@ -39,49 +27,13 @@ export default struct Setting { @Link loginInfo: string; aboutToAppear(): void { - this.items.push(new SettingItem('保持登录', $r('app.media.key_horizontal'), '重启自动登录', true)); - this.items.push(new SettingItem('关于', $r('app.media.info_circle'), '版本')); - } - - @Builder - settingCell(item: SettingItem) { - Row() { - Image(item.img) - .width(28) - .height(28) - .margin(4) - - Row() { - Text(item.title) - .maxLines(1) - .fontSize(20) - .fontWeight(FontWeight.Lighter) - - Text(item.subTitle) - .fontSize(14) - .fontWeight(FontWeight.Lighter) - .fontColor(Color.Gray) - .margin({ left: 8, right: 8 }) - .maxLines(1) - }.alignItems(VerticalAlign.Bottom) - - Blank() - if (item.others) { - Toggle({ type: ToggleType.Switch, isOn: true }) - .selectedColor(Color.Orange) - } else { - Image($r('app.media.chevron_right')) - .width(12) - .height(24) - } - } - .alignItems(VerticalAlign.Center) - .justifyContent(FlexAlign.SpaceBetween) - .width('100%') - .padding({ - left: 8, - right: 22 - }) + console.log('SettingSetting:'+AppStorage.get(AppConstants.DETAIL_DEFAULT_SETTING)); + this.items.push(new SettingItem(AppConstants.detailDefaultSetting, $r('app.media.doc_plaintext'), AppConstants.detailDefaultSettingDes, + true)); + this.items.push(new SettingItem(AppConstants.playModeTitle, $r('app.media.shuffle'), AppConstants.playModeDes, + true)); + this.items.push(new SettingItem(AppConstants.keepLoginTitle, $r('app.media.key_horizontal'), AppConstants.keepLoginDes, true)); + this.items.push(new SettingItem(AppConstants.aboutTitle, $r('app.media.questionmark_circle'), AppConstants.aboutDes)); } build() { @@ -106,7 +58,7 @@ export default struct Setting { List() { ForEach(this.items, (item: SettingItem) => { ListItem() { - this.settingCell(item) + settingCell({item:item}) } .height(56) }) @@ -141,7 +93,7 @@ export default struct Setting { .backgroundColor(Color.White) .borderRadius(12) .margin({ top: 12, bottom: 12 }) - .clickEffect(UIConstants.CLICK_EFFECT) + .clickEffect(AppConstants.CLICK_EFFECT) .onClick(() => { this.PlayerManager.exitAPP(); }) diff --git a/scenario/MusicPlayerOnline/entry/src/main/ets/view/SettingCell.ets b/scenario/MusicPlayerOnline/entry/src/main/ets/view/SettingCell.ets new file mode 100644 index 000000000..21b63846a --- /dev/null +++ b/scenario/MusicPlayerOnline/entry/src/main/ets/view/SettingCell.ets @@ -0,0 +1,167 @@ +/* + * Copyright (c) 2024 Shenzhen Kaihong Digital Industry Development Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +import AppConstants from '../constants/AppConstants'; +import SettingItem from '../model/SettingItem'; +import { InputServerHost } from './InputServerHost'; +import prompt from '@ohos.promptAction'; + +/** + * settingCell information component. + */ +@Component +export default struct settingCell { + private item = new SettingItem('', $r('app.media.key_horizontal'), '', false); + private toggleState = false; + @State inputListName: string | undefined = ''; + dialogController: CustomDialogController | null = new CustomDialogController({ + builder: InputServerHost({ + cancel: () => { + if (this.dialogController !== null) { + this.dialogController.close(); + } + }, + confirm: () => { + if (this.inputListName !== undefined) { + let regex = /^(https?:\/\/)(\d{1,3}(\.\d{1,3}){3}):(\d+)(\/)$/; + if (regex.test(this.inputListName.trim())) { + AppStorage.setOrCreate(AppConstants.SERVER_HOST_PROP, this.inputListName.trim()) + if (this.dialogController !== null) { + this.dialogController.close(); + } + } else { + prompt.showToast({ + message: '服务器地址格式不符合:http://192.168.12.8:8000/' + }); + } + } + }, + inputListName: $inputListName, + }), + autoCancel: true, + alignment: DialogAlignment.Bottom, + offset: { dx: 0, dy: -20 }, + gridCount: 4, + customStyle: false, + cornerRadius: 10, + }) + + aboutToAppear() { + this.inputListName = AppStorage.get(AppConstants.SERVER_HOST_PROP); + switch (this.item.title) { + case AppConstants.detailDefaultSetting: + this.toggleState = AppStorage.get(AppConstants.DETAIL_DEFAULT_SETTING) == AppConstants.TOGGLE_SETTING_ON; + break; + case AppConstants.playModeTitle: + this.toggleState = AppStorage.get(AppConstants.PLAY_MODE_SETTING) == AppConstants.TOGGLE_SETTING_ON; + break; + case AppConstants.keepLoginTitle: + this.toggleState = AppStorage.get(AppConstants.KEEP_LOGIN_SETTING) == AppConstants.TOGGLE_SETTING_ON; + break; + default: + break; + } + } + + aboutToDisappear(): void { + if (this.dialogController !== null) { + this.dialogController.close(); + this.dialogController = null; + } + } + + build() { + Row() { + Image(this.item.img) + .width(28) + .height(28) + .margin(4) + + Column() { + Text(this.item.title) + .maxLines(1) + .fontSize(20) + .fontWeight(FontWeight.Lighter) + + Text(this.item.subTitle) + .fontSize(14) + .fontWeight(FontWeight.Lighter) + .fontColor(Color.Gray) + .margin({ left: 8, right: 8 }) + .maxLines(1) + } + .alignItems(HorizontalAlign.Start) + + Blank() + if (this.item.others) { + Toggle({ + type: ToggleType.Switch, + isOn: this.toggleState + }) + .selectedColor(Color.Orange) + .onChange((isOn: boolean) => { + switch (this.item.title) { + case AppConstants.detailDefaultSetting: + AppStorage.setOrCreate(AppConstants.DETAIL_DEFAULT_SETTING, + isOn ? AppConstants.TOGGLE_SETTING_ON : AppConstants.TOGGLE_SETTING_OFF); + break; + case AppConstants.playModeTitle: + AppStorage.setOrCreate(AppConstants.PLAY_MODE_SETTING, + isOn ? AppConstants.TOGGLE_SETTING_ON : AppConstants.TOGGLE_SETTING_OFF); + break; + case AppConstants.keepLoginTitle: + AppStorage.setOrCreate(AppConstants.KEEP_LOGIN_SETTING, + isOn ? AppConstants.TOGGLE_SETTING_ON : AppConstants.TOGGLE_SETTING_OFF); + break; + default: + break; + } + + }) + } else { + Image($r('app.media.chevron_right')) + .width(12) + .height(24) + } + } + .alignItems(VerticalAlign.Center) + .justifyContent(FlexAlign.SpaceBetween) + .width('100%') + .padding({ + left: 8, + right: 22 + }) + .clickEffect(AppConstants.CLICK_EFFECT) + .gesture( + TapGesture({ count: 2 }) + .onAction((event: GestureEvent) => { + if (event && this.item.title === AppConstants.aboutTitle) { + if (this.dialogController != null) { + this.dialogController.open(); + } + } + }) + ) + .gesture( + TapGesture({ count: 1 }) + .onAction((event: GestureEvent) => { + if (event) { + + } + }) + ) + } +} \ No newline at end of file diff --git a/scenario/MusicPlayerOnline/entry/src/main/ets/view/SingleRowScrollerList.ets b/scenario/MusicPlayerOnline/entry/src/main/ets/view/SingleRowScrollerList.ets index e13722646..c58831455 100644 --- a/scenario/MusicPlayerOnline/entry/src/main/ets/view/SingleRowScrollerList.ets +++ b/scenario/MusicPlayerOnline/entry/src/main/ets/view/SingleRowScrollerList.ets @@ -18,7 +18,7 @@ * 单行横向滚动组件 */ -import UIConstants from '../constants/UIConstants'; +import AppConstants from '../constants/AppConstants'; import PlayListData from '../model/PlayListData'; import PlayListItem from './PlayListItem'; @@ -48,7 +48,7 @@ export default struct SingleRowScrollerList { .padding(8) .rotate({ angle: this.arrowAngle }) .id('scroll_row') - .clickEffect(UIConstants.CLICK_EFFECT) + .clickEffect(AppConstants.CLICK_EFFECT) .onClick(() => { animateTo({ duration: 1000 }, () => { if (this.arrowAngle === 0) { diff --git a/scenario/MusicPlayerOnline/entry/src/main/ets/view/SongItem.ets b/scenario/MusicPlayerOnline/entry/src/main/ets/view/SongItem.ets index b4fc59a01..30ae75a19 100644 --- a/scenario/MusicPlayerOnline/entry/src/main/ets/view/SongItem.ets +++ b/scenario/MusicPlayerOnline/entry/src/main/ets/view/SongItem.ets @@ -14,7 +14,8 @@ */ import AudioData from '../model/AudioData'; -import ServerConstants from '../constants/ServerConstants'; +import AppConstants from '../constants/AppConstants'; +import PlayerManager from '../manager/PlayerManager'; @Component export default struct SongItem { @@ -23,7 +24,7 @@ export default struct SongItem { build() { Row() { - Image(ServerConstants.SONG_IMAGE_URL + this.item.id) + Image(AppStorage.get(AppConstants.SERVER_HOST_PROP) + AppConstants.SONG_IMAGE_URL + this.item.id) .width(64) .height(64) .borderRadius(4) diff --git a/scenario/MusicPlayerOnline/entry/src/main/ets/view/TriColGridList.ets b/scenario/MusicPlayerOnline/entry/src/main/ets/view/TriColGridList.ets index da3b7ba19..ee0d5b5a9 100644 --- a/scenario/MusicPlayerOnline/entry/src/main/ets/view/TriColGridList.ets +++ b/scenario/MusicPlayerOnline/entry/src/main/ets/view/TriColGridList.ets @@ -12,14 +12,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import ServerConstants from '../constants/ServerConstants'; /** * TriColGridList component. * 三列竖向Grid列表 */ -import UIConstants from '../constants/UIConstants'; +import AppConstants from '../constants/AppConstants'; import PlayListData from '../model/PlayListData'; import PlayListItem from './PlayListItem'; @@ -50,10 +49,10 @@ export default struct TriColGridList { .transition(TransitionEffect.OPACITY.animation({ duration: 2000, curve: Curve.Ease }).combine( TransitionEffect.rotate({ z: 1, angle: 180 }) )) - .clickEffect(UIConstants.CLICK_EFFECT) + .clickEffect(AppConstants.CLICK_EFFECT) .onClick(() => { animateTo({ duration: 1000 }, () => { - this.title = ServerConstants.SEARCH_DEFAULT; + this.title = AppConstants.SEARCH_DEFAULT; this.playLists = []; }) }) diff --git a/scenario/MusicPlayerOnline/entry/src/main/ets/view/TriColNestScrollerGrid.ets b/scenario/MusicPlayerOnline/entry/src/main/ets/view/TriColNestScrollerGrid.ets index 9655b54e4..ede310824 100644 --- a/scenario/MusicPlayerOnline/entry/src/main/ets/view/TriColNestScrollerGrid.ets +++ b/scenario/MusicPlayerOnline/entry/src/main/ets/view/TriColNestScrollerGrid.ets @@ -12,14 +12,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import ServerConstants from '../constants/ServerConstants'; /** * TriColNestScrollerGridList component. * 三列竖向联动滚动Grid列表 */ -import UIConstants from '../constants/UIConstants'; +import AppConstants from '../constants/AppConstants'; import PlayListData from '../model/PlayListData'; import PlayListItem from './PlayListItem'; @@ -50,7 +49,7 @@ export default struct TriColNestScrollerGrid { .padding(8) .id('scroll_col') .rotate({ angle: this.colAngle }) - .clickEffect(UIConstants.CLICK_EFFECT) + .clickEffect(AppConstants.CLICK_EFFECT) .onClick(() => { animateTo({ duration: 1000 }, () => { if (this.colAngle === 0) { diff --git a/scenario/MusicPlayerOnline/entry/src/main/ets/widget/pages/WidgetCard.ets b/scenario/MusicPlayerOnline/entry/src/main/ets/widget/pages/WidgetCard.ets index f0f8ad3ea..868473a24 100644 --- a/scenario/MusicPlayerOnline/entry/src/main/ets/widget/pages/WidgetCard.ets +++ b/scenario/MusicPlayerOnline/entry/src/main/ets/widget/pages/WidgetCard.ets @@ -14,7 +14,7 @@ */ import AudioData from '../../model/AudioData'; -import ServerConstants from '../../constants/ServerConstants'; +import AppConstants from '../../constants/AppConstants'; import { PLAY_MODE } from '../../constants/PlayMode'; let storageUpdateByMsg = new LocalStorage(); @@ -49,10 +49,11 @@ struct WidgetCard { readonly MAX_LINES_VALUE: number = 1; @LocalStorageProp('formId') formId: string = ''; @LocalStorageProp('audioItem') audioItem: AudioData = new AudioData('未播放', '--', '') - @LocalStorageProp('isPlaying') isPlaying: string = ServerConstants.PLAYER_STATE_UNKNOWN; + @LocalStorageProp('serverHost') serverHost: string = ''; + @LocalStorageProp('isPlaying') isPlaying: string = AppConstants.PLAYER_STATE_UNKNOWN; @LocalStorageProp('imgName') imgName: string = ''; - private downloadImgId: string = '' @LocalStorageProp('playMode') playMode: number = PLAY_MODE.REPEAT; + private downloadImgId: string = '' aboutToAppear(): void { postCardAction(this, { @@ -141,7 +142,8 @@ struct WidgetCard { .width(this.FULL_PERCENT) Row() { - Image(this.playMode === PLAY_MODE.REPEAT ? $r('app.media.repeat') : (this.playMode === PLAY_MODE.REPEAT1 ? $r('app.media.repeat_1') : $r('app.media.shuffle'))) + Image(this.playMode === PLAY_MODE.REPEAT ? $r('app.media.repeat') : + (this.playMode === PLAY_MODE.REPEAT1 ? $r('app.media.repeat_1') : $r('app.media.shuffle'))) .width(64) .height(64) .padding(4) @@ -156,7 +158,7 @@ struct WidgetCard { .onClick(() => { this.onPreviousClick() }) - if (this.isPlaying === ServerConstants.PLAYER_STATE_PLAYING) { + if (this.isPlaying === AppConstants.PLAYER_STATE_PLAYING) { Image($r('app.media.pause')) .width(64) .height(64) @@ -173,7 +175,7 @@ struct WidgetCard { postCardAction(this, { action: 'message', params: { - info: ServerConstants.SONG_IMAGE_URL + this.audioItem.id + info: this.serverHost + AppConstants.SONG_IMAGE_URL + this.audioItem.id } }); } diff --git a/scenario/MusicPlayerOnline/entry/src/main/resources/base/media/doc_plaintext.png b/scenario/MusicPlayerOnline/entry/src/main/resources/base/media/doc_plaintext.png new file mode 100644 index 0000000000000000000000000000000000000000..ba03e1b822f4e604025dbfa781522a6ea39856c9 GIT binary patch literal 320 zcmV-G0l)rPx#`bk7VR9Hvt*Re`NK@bJdlUDIJtZb~r#-tH!Yz03<1dAk=X##$SU~6fkHezLC zZ#oy#n{Gte^zJ?HlqfkRBO-x0w#T;L;(mm{!)SKQ(T z-z`aO;S%RK_}zal#>){HVS?k9iBtCn%<$MmAlL??`Yw@;n^T|?*hmG=5UT{yLoW*s zwFjyK|674woR(Yx+$WDuD+PKdP*{BScq;`efvUi&$LJ2RnoygtDzLT!M;POzsjCX@ zPq@Z&)3-eA?+Ax0d=(~2k8fj+A@)+^s@X6mqj2g1QA|umOW4@qw2P|Oitz(vGe{v7 SG3`PC0000Px(!%0LzRA@u(nQ5qgQxwL3e`KC#l36m(Ng;DGXOz&06AG2oo`56P4 zZV!$;;7Cjy%Q8+90a z6L=B0B5nRz#m1`xcLDDK#{yr(nw5bYfj@wK)BZnn*~$S}2zVG+9JmsAEsVC=n-f?M zI2xD(*eU)0d0}I3{O+)MNXxt>0^BdjGy4NSmO$hHoDJ*&>^yWkU6-*4@F4I$aCm0& zs&P0yc5uPqk^xc=_(p!p&CLPuF`Wb4)^+N}_Z@+ofOUZH8sCihLD(Dy{MKQ6>6rg* zfY2ioMjL?nfDeIPfmeD0ST=d?iU1}% zgsuX9Z*zZ7KzhK#PdR`i;_zDlt(l|(i0Rh~y?x3^Z%?%c29Nmp1mKj4!?sN^{eB$G z;9uX{-oU)TN0XdJS4@=Te&9~vyq+L#0Hie*visDx$T zS1-*yD;?;ijvHG)Wt!6i@SZ9BUMS4hwuQ;ty(}~DnxNMEjY{UU>&ur;?^Ee+Z~xND z>b*vUlU(ckA^YYM zmpA2xicU8B5b$ZqVD3<+FZsI#?2vka>Fe%^M57Nkit;z6OIoJ(I%u z^0u{Y0QO1~t-e0AzQZ<%Ypol@!;rKGbZ%dRQL$ay%Advn8aF!jKud_37{(z~`}Ssw z5VB(0Rva}8*#la)f!KEA2mc`p$#yTQO`}^z?zIB;?IM`xZ3s6DmO8x#bRm^Wy`TN0O`KH0ivQ4&9d)@Z8ip*|8 z*YI|ghu*$A+He^jilQgdj~QRZ?+8VP84C?zE4W-t&Coh>08~l#aP0G|v~07K*r=M= zhLdEjN#q6_ua$_I6Px$97#k$RA@u(m$41PKnz7+W}v2J2Po($*@2FZhL#DC5VSPZ6tDn{!9wT|MHDWv zrIQs0IqmrzzyFLxDhB>k1D~G&=-Xfz2m^%)#0nJ#SbRMU6h~OtAPf`+SbW{9feEk# z4icePfHeI13(yJS9Uuuv0Id*S0p`H9wmz*8Ie-!Hl6J3$^DIQ0fo%^1YF_!XN?un; z1M{f~0CiMGg<-%bSasVlppMF@Fbo(4t8V+Z20Z?iNZ$zSrkb3AF>q8nv@4u7TJM3A z2EcA4edj4~ua)nBOYXYY-#{H;1Kir!y#uU(N0&IS0BPn0@RYXBGk`REd=ID+vM!1h zvQAj)9|oj^tk1)Mb;45rFd!vleI5p^6PEhF0kLBgF?UjBzW@LL07*qoM6N<$f-wAw AApigX literal 0 HcmV?d00001 diff --git a/scenario/MusicPlayerOnline/entry/src/main/resources/base/media/questionmark_circle.png b/scenario/MusicPlayerOnline/entry/src/main/resources/base/media/questionmark_circle.png new file mode 100644 index 0000000000000000000000000000000000000000..4046b0ce1176012d6252d9f2e27b84ed7d823ed8 GIT binary patch literal 1263 zcmVPx(sYygZRA@u(nQ5q2RTPGwYbIg{hC?V+f<>T+N)8P~luagxv!&+HAZ7+ZQEBLp z=AuBTNX&UerLs`dGDCs}3M!%?Oe_LLE%HwhQR04Ooy&K>d(O9qbMC!daKrg^_F8+r zd+#;9yNOOdnmW1toCjbhcrkD<&^PDPlv6q1THw#JH=yhZj0C0wvwp~80h@sxz}KljQUS~WCIB}9@0uZ>M;dXh0iOhX0=y4wkJJ(E16_gFfpNf_z}vv# z*hTB+UkOYB9t1uB76bo<>Wn#o;lL{30^l**wa|4!=IJzF0saRT0N;iPg#x$-c**V5 z_kga?=@8`!b9&h|8VWq&{A80)M+kuNz+1pOcDz2FRs7dAoeVqx>}jOX2jFr*&bb;` zUWH{5I-UmZ2juL(7RfaN&;{5B90%q`EL`Q(4M2b34!414@)S1$pgTVXxD)t0!KxlW zZ~J}&{z%lZ*G0WA%_mx^C<1Ud@SG*7*d%kA9legfcF2&|fbSxKC|N4mJq2v5mn{My zhyBKd%x5AOyVXMB7r<`I%({Z3f#-osfmiK|QN0WpVUFEGE)T$shV*s|o1qI`4QvEn zu*{q%_b8xGKJ`(kVwW%#R`tgnulwHp|rmP&KJLIuH0TLi>eQQposS9=RpJOxx9nCAbY(?`p4MR@t7Dtp}i8 zQC)IfjOLmn9vqOR71vcm4TxMr({*~1l^^8-c+nMWeJqN^=wlH`n$VI zPZj}K$1T80muIdh zx7(9R&hTh zKZF4EhSAhSR?$-Hv< zW#A%L@jcYm7DeiR1Nh6ew~yD#%b3DXGT!`L#itVU}!zYzd2(dvNo2%!eQBZeAzMMiaqxs0`sS`;I#`n^4Q z(QKnKepJL-Aye%GAY~ad-Jbkt#*2Cx>JR_|kulWba`X_9LN$h5LD7+VI1xeSWu~Pt z6oBTcG!|#n%^o;nDMudweqVwI2l z;u`iJ1D{z%fDN?Q7d^GM;5&Urm$^bkxPx(WJyFpRA@u(nR&>SRS?F15(*_s7#J%0hoV-9P->x-N~Q?fhD(wnE@|S5`w|x7 zf@o&6AeDQml!hq^;zpVpDk_S&l_F+^{vj^7AwuV|bEEI`J==HRTYTie``4W_XP%jJ z<~%dE3YA={RC51$0N}sQV5u_D3wRM|4%7w?*l!_lB~Q?K185A4GtRyOtOND}zXL6S zcEBTmKrG7(M4kX11y%tUfX{)S$~jpLcn6pa3jd5M1>x_dc^#nyU-DJ`-vAg1v`skU#fDk; zZzu3^$WUwsdfO7IYV&W%HefNZBD7g7fX=`y;F*xYoPIwDOo@3@Vga-QzBS)dwtna2 zXQr8lfn(OM|&Z;My}(iJW40qpifMVIau;C+YARO^_Ef=iwURs(fI z(N6_%8c;di=rJrlblF1_W*DliBQnrqLu^*%vr*mvbTnl6Ymed2fQJB4<}CRD&?Oz_ zvC+o{>e;*jh$e3UKJ^%$2Rv?$k(|g9t-T!}a>IeHfJ%2zQtrS?;JAtKbdS}Uw$#4i z(D~AIV;2K7TKD8h;H{wdiI?~jv+*6%ZH@65*5;xd9UVGf8OKfqf}mcZDlj5%0MpF# z-oUnlF54=TioUClP<7E=n(J|HiJ>j$Je91>(v%~l3M4M{nrCxGZIB(OWT~wOwwOLc z*>s7f8R9}gA}0eW093m*RnQS}$zVe@CVEQXWFyBK1H0aVL)l?!&s@qHc zdJK_E%|Ltx87(wrqaW@xXwnL`;m8h-TyesHYUKv>5s zipW(2fFiF>N#!t0G%ESd9FeE(jI_Lt0?^Gfk$cs4e!fCc#%4+x)xsTs9-5_|DpJf( z%8uryI)YJ>3Sh0B7O2vcLPpzn#>J)X+cOn_YPecTah_6$h@$$1w_}Z`0#K`{KPg0c zOCh4$H_SI7)_5v_NtWkCQQcT4{-LJ|cErBsQOi>S6v|}uLlfo2UrL3CQo(VR*`n`2 z4Rgu1+YLmW^Au5R1xWwgT#GfFngQ7@)Ot1f>W`K3VnqLBss&XO?|UOM_oxT}84{sW z#I$LxV!SsE{3SraP)60QB}qjAByCbkPx%5lKWrRA@u(*m;T+K@i2^Z;s_91W^Q06h&}faNos!7k3>HMNtG%1TW!DJclGy zKs!uN=TbdwVb#Bt74Q9CL|1j@l7U}K1NUzPSab)+4vZaWOyIv6p$+)e7*^@yS(-T= zNQJ)RAs&~ys9b*nr?7cea5(_ULlnG+rgSdpEfJy<9i4eMmE^yRfL{JihmkY*lnJo|_fZ4>mqcp^ zqF5L@i7zuCw&4*KRU5Zc!|}(icQZOAk`1U`#Z5Wm;`Dvy&eEbV;LA z@`DB#^a!O*$nzC5A3#UC%~5aD)b|L*YjicE0rtN+l~jBU)TUWjnA#K)W-%O5G^p^4fF4yj1r;JJjas#hR z#;J6K;#j3vD8p0)Gq+=vK_6@l{%G-c?pbBVsN^i^{ctx&bRla>f5Zzhxt8b%u;`YI l9T+>%n7}wfjR7`4{s(9vbTLMTas&VX002ovPDHLkV1jsB{G$K> literal 0 HcmV?d00001 -- Gitee