diff --git a/CHANGELOG.md b/CHANGELOG.md index 21eb4ab..7d3acef 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - **Create playlist from Library** — new `+` button in the Library header opens a modal to create an empty playlist directly from the app. - **Auto-download** — optional setting (disabled by default) that automatically downloads each played track to the device for offline playback. Enabling shows a confirmation warning about storage and server bandwidth usage. - **Add ext- tracks to playlist** — Deezer tracks can now be added to playlists via the add-to-playlist sheet; OctoFiesta import is triggered automatically and Navidrome is polled until the native ID is available. +- **iOS app icon** — all required sizes now bundled (20×20 → 1024×1024) for iPhone and iPad; `Contents.json` updated with explicit filenames for every slot. ### Fixed - **deezerFetch timeout** — all Deezer API calls now use an 8 s `AbortController` timeout, preventing Magic Shuffle and Autoplay from hanging silently on slow CDN responses. diff --git a/ios/Musonic/Images.xcassets/AppIcon.appiconset/Contents.json b/ios/Musonic/Images.xcassets/AppIcon.appiconset/Contents.json index 359c1d6..92a5988 100644 --- a/ios/Musonic/Images.xcassets/AppIcon.appiconset/Contents.json +++ b/ios/Musonic/Images.xcassets/AppIcon.appiconset/Contents.json @@ -1,53 +1,116 @@ -{ - "images" : [ - { - "idiom" : "iphone", - "scale" : "2x", - "size" : "20x20" - }, - { - "idiom" : "iphone", - "scale" : "3x", - "size" : "20x20" - }, - { - "idiom" : "iphone", - "scale" : "2x", - "size" : "29x29" - }, - { - "idiom" : "iphone", - "scale" : "3x", - "size" : "29x29" - }, - { - "idiom" : "iphone", - "scale" : "2x", - "size" : "40x40" - }, - { - "idiom" : "iphone", - "scale" : "3x", - "size" : "40x40" - }, - { - "idiom" : "iphone", - "scale" : "2x", - "size" : "60x60" - }, - { - "idiom" : "iphone", - "scale" : "3x", - "size" : "60x60" - }, - { - "idiom" : "ios-marketing", - "scale" : "1x", - "size" : "1024x1024" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} +{ + "images": [ + { + "filename": "Icon-40.png", + "idiom": "iphone", + "scale": "2x", + "size": "20x20" + }, + { + "filename": "Icon-60.png", + "idiom": "iphone", + "scale": "3x", + "size": "20x20" + }, + { + "filename": "Icon-58.png", + "idiom": "iphone", + "scale": "2x", + "size": "29x29" + }, + { + "filename": "Icon-87.png", + "idiom": "iphone", + "scale": "3x", + "size": "29x29" + }, + { + "filename": "Icon-80.png", + "idiom": "iphone", + "scale": "2x", + "size": "40x40" + }, + { + "filename": "Icon-120.png", + "idiom": "iphone", + "scale": "3x", + "size": "40x40" + }, + { + "filename": "Icon-120.png", + "idiom": "iphone", + "scale": "2x", + "size": "60x60" + }, + { + "filename": "Icon-180.png", + "idiom": "iphone", + "scale": "3x", + "size": "60x60" + }, + { + "filename": "Icon-20.png", + "idiom": "ipad", + "scale": "1x", + "size": "20x20" + }, + { + "filename": "Icon-40.png", + "idiom": "ipad", + "scale": "2x", + "size": "20x20" + }, + { + "filename": "Icon-29.png", + "idiom": "ipad", + "scale": "1x", + "size": "29x29" + }, + { + "filename": "Icon-58.png", + "idiom": "ipad", + "scale": "2x", + "size": "29x29" + }, + { + "filename": "Icon-40.png", + "idiom": "ipad", + "scale": "1x", + "size": "40x40" + }, + { + "filename": "Icon-80.png", + "idiom": "ipad", + "scale": "2x", + "size": "40x40" + }, + { + "filename": "Icon-76.png", + "idiom": "ipad", + "scale": "1x", + "size": "76x76" + }, + { + "filename": "Icon-152.png", + "idiom": "ipad", + "scale": "2x", + "size": "76x76" + }, + { + "filename": "Icon-167.png", + "idiom": "ipad", + "scale": "2x", + "size": "83.5x83.5" + }, + { + "filename": "Icon-1024.png", + "idiom": "ios-marketing", + "scale": "1x", + "size": "1024x1024" + } + ], + "info": { + "author": "xcode", + "version": 1 + } +} \ No newline at end of file diff --git a/ios/Musonic/Images.xcassets/AppIcon.appiconset/Icon-1024.png b/ios/Musonic/Images.xcassets/AppIcon.appiconset/Icon-1024.png new file mode 100644 index 0000000..42e22f4 Binary files /dev/null and b/ios/Musonic/Images.xcassets/AppIcon.appiconset/Icon-1024.png differ diff --git a/ios/Musonic/Images.xcassets/AppIcon.appiconset/Icon-120.png b/ios/Musonic/Images.xcassets/AppIcon.appiconset/Icon-120.png new file mode 100644 index 0000000..360c482 Binary files /dev/null and b/ios/Musonic/Images.xcassets/AppIcon.appiconset/Icon-120.png differ diff --git a/ios/Musonic/Images.xcassets/AppIcon.appiconset/Icon-152.png b/ios/Musonic/Images.xcassets/AppIcon.appiconset/Icon-152.png new file mode 100644 index 0000000..e4236f7 Binary files /dev/null and b/ios/Musonic/Images.xcassets/AppIcon.appiconset/Icon-152.png differ diff --git a/ios/Musonic/Images.xcassets/AppIcon.appiconset/Icon-167.png b/ios/Musonic/Images.xcassets/AppIcon.appiconset/Icon-167.png new file mode 100644 index 0000000..38368b6 Binary files /dev/null and b/ios/Musonic/Images.xcassets/AppIcon.appiconset/Icon-167.png differ diff --git a/ios/Musonic/Images.xcassets/AppIcon.appiconset/Icon-180.png b/ios/Musonic/Images.xcassets/AppIcon.appiconset/Icon-180.png new file mode 100644 index 0000000..031186a Binary files /dev/null and b/ios/Musonic/Images.xcassets/AppIcon.appiconset/Icon-180.png differ diff --git a/ios/Musonic/Images.xcassets/AppIcon.appiconset/Icon-20.png b/ios/Musonic/Images.xcassets/AppIcon.appiconset/Icon-20.png new file mode 100644 index 0000000..861ea94 Binary files /dev/null and b/ios/Musonic/Images.xcassets/AppIcon.appiconset/Icon-20.png differ diff --git a/ios/Musonic/Images.xcassets/AppIcon.appiconset/Icon-29.png b/ios/Musonic/Images.xcassets/AppIcon.appiconset/Icon-29.png new file mode 100644 index 0000000..2ea2e5e Binary files /dev/null and b/ios/Musonic/Images.xcassets/AppIcon.appiconset/Icon-29.png differ diff --git a/ios/Musonic/Images.xcassets/AppIcon.appiconset/Icon-40.png b/ios/Musonic/Images.xcassets/AppIcon.appiconset/Icon-40.png new file mode 100644 index 0000000..8a93eda Binary files /dev/null and b/ios/Musonic/Images.xcassets/AppIcon.appiconset/Icon-40.png differ diff --git a/ios/Musonic/Images.xcassets/AppIcon.appiconset/Icon-58.png b/ios/Musonic/Images.xcassets/AppIcon.appiconset/Icon-58.png new file mode 100644 index 0000000..ec0942d Binary files /dev/null and b/ios/Musonic/Images.xcassets/AppIcon.appiconset/Icon-58.png differ diff --git a/ios/Musonic/Images.xcassets/AppIcon.appiconset/Icon-60.png b/ios/Musonic/Images.xcassets/AppIcon.appiconset/Icon-60.png new file mode 100644 index 0000000..709d9e2 Binary files /dev/null and b/ios/Musonic/Images.xcassets/AppIcon.appiconset/Icon-60.png differ diff --git a/ios/Musonic/Images.xcassets/AppIcon.appiconset/Icon-76.png b/ios/Musonic/Images.xcassets/AppIcon.appiconset/Icon-76.png new file mode 100644 index 0000000..7766c81 Binary files /dev/null and b/ios/Musonic/Images.xcassets/AppIcon.appiconset/Icon-76.png differ diff --git a/ios/Musonic/Images.xcassets/AppIcon.appiconset/Icon-80.png b/ios/Musonic/Images.xcassets/AppIcon.appiconset/Icon-80.png new file mode 100644 index 0000000..4b34143 Binary files /dev/null and b/ios/Musonic/Images.xcassets/AppIcon.appiconset/Icon-80.png differ diff --git a/ios/Musonic/Images.xcassets/AppIcon.appiconset/Icon-87.png b/ios/Musonic/Images.xcassets/AppIcon.appiconset/Icon-87.png new file mode 100644 index 0000000..5ebfd9c Binary files /dev/null and b/ios/Musonic/Images.xcassets/AppIcon.appiconset/Icon-87.png differ diff --git a/ios/Musonic/Info.plist b/ios/Musonic/Info.plist index 818f665..467cd65 100644 --- a/ios/Musonic/Info.plist +++ b/ios/Musonic/Info.plist @@ -24,6 +24,32 @@ ???? CFBundleVersion $(CURRENT_PROJECT_VERSION) + CFBundleIconName + AppIcon + CFBundleIcons + + CFBundlePrimaryIcon + + CFBundleIconName + AppIcon + CFBundleIconFiles + + AppIcon60x60 + + + + CFBundleIcons~ipad + + CFBundlePrimaryIcon + + CFBundleIconName + AppIcon + CFBundleIconFiles + + AppIcon76x76 + + + LSRequiresIPhoneOS NSAppTransportSecurity diff --git a/package-lock.json b/package-lock.json index 47ae57c..dd30152 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "Musonic", - "version": "1.0.0", + "version": "1.0.2", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "Musonic", - "version": "1.0.0", + "version": "1.0.2", "hasInstallScript": true, "dependencies": { "@d11/react-native-fast-image": "^8.13.0", diff --git a/src/screens/PlaylistDetail/index.tsx b/src/screens/PlaylistDetail/index.tsx index 0d28046..db919b9 100644 --- a/src/screens/PlaylistDetail/index.tsx +++ b/src/screens/PlaylistDetail/index.tsx @@ -379,6 +379,7 @@ type HeaderProps = { coverArtId?: string; localCoverUri?: string | null; playlistName: string; + owner: string; songCount: number; totalDuration: number; isShuffled: boolean; @@ -405,6 +406,7 @@ function PlaylistHeader({ coverArtId, localCoverUri, playlistName, + owner, songCount, totalDuration, isShuffled: _isShuffled, @@ -695,6 +697,7 @@ export default function PlaylistDetailScreen() { const {playlistId, autoEdit} = route.params; const [playlistName, setPlaylistName] = useState(''); + const [owner, setOwner] = useState(''); const [description, setDescription] = useState(''); const [songs, setSongs] = useState([]); const [coverArtId, setCoverArtId] = useState(); @@ -728,6 +731,10 @@ export default function PlaylistDetailScreen() { const setShuffleMode = usePlayerStore(s => s.setShuffleMode); const togglePlay = usePlayerStore(s => s.togglePlay); const isOfflineMode = useSettingsStore(s => s.isOfflineMode); + const activeServerUsername = useSettingsStore(s => { + const id = s.activeServerId; + return s.servers.find(srv => srv.id === id)?.username ?? ''; + }); const downloads = useDownloadStore(s => s.downloads); const t = useT(); @@ -771,6 +778,7 @@ export default function PlaylistDetailScreen() { const offlineSongs = usePlaylistCacheStore.getState().getOfflineSongs(playlistId); const {isDownloaded} = useDownloadStore.getState(); setPlaylistName(cachedPl?.name ?? ''); + setOwner(cachedPl?.owner ?? activeServerUsername); setCoverArtId(cachedPl?.coverArt); setSongs(offlineSongs.filter(s => isDownloaded(String(s.id)))); setLoading(false); @@ -779,6 +787,7 @@ export default function PlaylistDetailScreen() { getPlaylist(playlistId) .then(({playlist, songs: s}) => { setPlaylistName(playlist.name); + setOwner(playlist.owner ?? activeServerUsername); setDescription(playlist.comment ?? ''); setCoverArtId(playlist.coverArt); setSongs(s); @@ -1102,6 +1111,7 @@ export default function PlaylistDetailScreen() { coverArtId={coverArtId} localCoverUri={localCoverUri} playlistName={playlistName} + owner={owner} songCount={songs.length} totalDuration={totalDuration} isShuffled={isShuffled} @@ -1166,7 +1176,7 @@ export default function PlaylistDetailScreen() { ), // eslint-disable-next-line react-hooks/exhaustive-deps [ - topBarH, coverArtId, localCoverUri, playlistName, songs, totalDuration, + topBarH, coverArtId, localCoverUri, playlistName, owner, songs, totalDuration, isShuffled, shuffleMode, isThisPlaylistActive, isGlobalPlaying, loadingPlaylist, query, handlePlay, handleStartEdit, handleOpenInfo, isOfflineMode, downloads, ],