Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
fdc929d
feat: init flo watch companion app
faultables Feb 17, 2026
bcb16c8
feat: init watch app related ui
faultables Feb 17, 2026
c875ce7
chore: add watchkitapp bundle
faultables Feb 17, 2026
d68c495
chore: update pbxproj
faultables Feb 17, 2026
030a4cd
hotfix: scale factor in stat cards
f-longobardi Feb 17, 2026
d72a521
build(release): bump version to 2.1 (207)
faultables Feb 19, 2026
293f816
fix: resolve crashes on iPhone 13 mini and smaller screens
faultables Feb 21, 2026
6adccb2
fix: remove redundant bottom padding from miniplayer
faultables Feb 21, 2026
9e4da54
add support for navidrome artis radio
docmeth02 Feb 21, 2026
6fc81ef
fix: improve artist radio reliability and error handling
faultables Feb 21, 2026
fc8f267
fix: artist radio UX polish and miniplayer gap
faultables Feb 21, 2026
904d7a6
docs(l10n): add another words
faultables Feb 21, 2026
f3d9787
build(release): bump version to 2.1 (209)
faultables Feb 21, 2026
09a1004
feat: prepare IAP
faultables Feb 23, 2026
3913518
feat: add alternative app icon
faultables Feb 23, 2026
cecb6b2
docs(l10n): add another words
faultables Feb 23, 2026
44f1ffc
feat: added top songs for artist + refactor artist detail to use view…
f-longobardi Feb 22, 2026
fa8f561
feat: add another alternative app icon
faultables Feb 24, 2026
3e8f670
feat: add some adjustment
faultables Feb 24, 2026
6bf2d0a
build(release): bump version to 2.1 (210)
faultables Feb 24, 2026
b78059b
feat: bring back to bottom padding
faultables Feb 25, 2026
cfdfad8
build(release): bump version to 2.1 (211)
faultables Feb 25, 2026
bb3f9de
initial support for apple carplay
docmeth02 Feb 22, 2026
0e1099d
use MPNowPlayingInfoCenter to acurately mirror ios playback into carp…
docmeth02 Feb 22, 2026
0906d44
Add artist radio and artist top songs to carplay
docmeth02 Feb 26, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion fastlane/Appfile
Original file line number Diff line number Diff line change
@@ -1 +1 @@
app_identifier("com.penerbangwalet.flo")
app_identifier("com.penerbangwalet.flo,com.penerbangwalet.flo.watchkitapp")
82 changes: 78 additions & 4 deletions flo.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,19 @@
objects = {

/* Begin PBXBuildFile section */
2F9D6FC45D72E9812C06DEE1 /* WatchLibraryResponder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 13D2299BFD0380D9B04BBFF5 /* WatchLibraryResponder.swift */; };
4BFDB7E71EDDA3BC9DB60860 /* ArtistDetailViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5D68C4A77696683D132DD518 /* ArtistDetailViewModel.swift */; };
520EF9C46F4E2CC1BC306993 /* WatchConnectivityManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3D2F567171E8CE853FC5F151 /* WatchConnectivityManager.swift */; };
55CFFAB52342C01E366F87B0 /* CarPlayCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2645E70081EEE2C0396E04D8 /* CarPlayCoordinator.swift */; };
5E64C3D71B02BE8FEDF5FF3C /* CarPlaySceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 566B2E217C6248B16912297F /* CarPlaySceneDelegate.swift */; };
6BDAFB58A4C77A82BCCFD0F4 /* CarPlay.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CE85DCBEE7ADB56E8BFD6338 /* CarPlay.framework */; };
7C09E28C1BFFDB5D5F124EC9 /* CarPlayNowPlayingManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEF17030A154EB98122A089 /* CarPlayNowPlayingManager.swift */; };
B02A003F2F36662C0024E8EC /* UIScreen+.swift in Sources */ = {isa = PBXBuildFile; fileRef = B02A003E2F3666240024E8EC /* UIScreen+.swift */; };
B0BAAAA62F31F0A0002A5FBB /* RadiosView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B0BAAAA52F31F0A0002A5FBB /* RadiosView.swift */; };
B0BAAAA92F3213AF002A5FBB /* RadiosViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = B0BAAAA82F3213AB002A5FBB /* RadiosViewModel.swift */; };
B0BAAAAB2F3214F7002A5FBB /* Radio.swift in Sources */ = {isa = PBXBuildFile; fileRef = B0BAAAAA2F3214F7002A5FBB /* Radio.swift */; };
B0BAAAAD2F3216A0002A5FBB /* RadioService.swift in Sources */ = {isa = PBXBuildFile; fileRef = B0BAAAAC2F321697002A5FBB /* RadioService.swift */; };
C3C4F155C7432144F2925F57 /* ArtistRadio.swift in Sources */ = {isa = PBXBuildFile; fileRef = B0387072F26D2718279566F4 /* ArtistRadio.swift */; };
C401D09A2C5AED9F009F91C7 /* LocalFileManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = C401D0992C5AED9F009F91C7 /* LocalFileManager.swift */; };
C4051DFF2CD25BBA0039D062 /* ArtistsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4051DFE2CD25BBA0039D062 /* ArtistsView.swift */; };
C4100A692CE78B25001BC9BE /* PlaylistView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4100A682CE78B21001BC9BE /* PlaylistView.swift */; };
Expand Down Expand Up @@ -81,10 +89,23 @@
C4F870D02CEFD25900312F8A /* StatCardView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4F870CF2CEFD24D00312F8A /* StatCardView.swift */; };
C4FE524B2C14E1F70053763A /* UserDefaultsManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4FE524A2C14E1F70053763A /* UserDefaultsManager.swift */; };
C4FE524D2C14E71B0053763A /* KeychainManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4FE524C2C14E71B0053763A /* KeychainManager.swift */; };
FA138533DE126212552B3A51 /* CarPlayImageLoader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 80C89AD8466BDBA43F95F5DC /* CarPlayImageLoader.swift */; };
FB380D022BD218AA1CE914B3 /* InAppPurchaseManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 92A728780B0275FE854EC627 /* InAppPurchaseManager.swift */; };
FD0E6B93BA00F1E355588795 /* PlaybackCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = E8A0D339760884271C69E36B /* PlaybackCoordinator.swift */; };
/* End PBXBuildFile section */

/* Begin PBXFileReference section */
0EEF17030A154EB98122A089 /* CarPlayNowPlayingManager.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = CarPlayNowPlayingManager.swift; sourceTree = "<group>"; };
13D2299BFD0380D9B04BBFF5 /* WatchLibraryResponder.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = WatchLibraryResponder.swift; sourceTree = "<group>"; };
2645E70081EEE2C0396E04D8 /* CarPlayCoordinator.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = CarPlayCoordinator.swift; sourceTree = "<group>"; };
3D2F567171E8CE853FC5F151 /* WatchConnectivityManager.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = WatchConnectivityManager.swift; sourceTree = "<group>"; };
566B2E217C6248B16912297F /* CarPlaySceneDelegate.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = CarPlaySceneDelegate.swift; sourceTree = "<group>"; };
5D68C4A77696683D132DD518 /* ArtistDetailViewModel.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ArtistDetailViewModel.swift; sourceTree = "<group>"; };
7E2C854C4AFDB5F757411C4C /* flo.entitlements */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.entitlements; path = flo.entitlements; sourceTree = "<group>"; };
80C89AD8466BDBA43F95F5DC /* CarPlayImageLoader.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = CarPlayImageLoader.swift; sourceTree = "<group>"; };
92A728780B0275FE854EC627 /* InAppPurchaseManager.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = InAppPurchaseManager.swift; sourceTree = "<group>"; };
B02A003E2F3666240024E8EC /* UIScreen+.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIScreen+.swift"; sourceTree = "<group>"; };
B0387072F26D2718279566F4 /* ArtistRadio.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ArtistRadio.swift; sourceTree = "<group>"; };
B0BAAAA52F31F0A0002A5FBB /* RadiosView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RadiosView.swift; sourceTree = "<group>"; };
B0BAAAA82F3213AB002A5FBB /* RadiosViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RadiosViewModel.swift; sourceTree = "<group>"; };
B0BAAAAA2F3214F7002A5FBB /* Radio.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Radio.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -155,6 +176,8 @@
C4F870CF2CEFD24D00312F8A /* StatCardView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatCardView.swift; sourceTree = "<group>"; };
C4FE524A2C14E1F70053763A /* UserDefaultsManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserDefaultsManager.swift; sourceTree = "<group>"; };
C4FE524C2C14E71B0053763A /* KeychainManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeychainManager.swift; sourceTree = "<group>"; };
CE85DCBEE7ADB56E8BFD6338 /* CarPlay.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = CarPlay.framework; sourceTree = SDKROOT; };
E8A0D339760884271C69E36B /* PlaybackCoordinator.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = PlaybackCoordinator.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */

/* Begin PBXFrameworksBuildPhase section */
Expand All @@ -168,12 +191,44 @@
C45F0E312CE5582C00F75C7A /* Nuke in Frameworks */,
C45F0E2C2CE4CCEA00F75C7A /* Pulse in Frameworks */,
C415F5512C11912800E3E1D2 /* KeychainAccess in Frameworks */,
6BDAFB58A4C77A82BCCFD0F4 /* CarPlay.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */

/* Begin PBXGroup section */
09524ACAFDF0F9A349F1CCA8 /* Artists */ = {
isa = PBXGroup;
children = (
C4824D242CE9086E003EAB52 /* ArtistDetailView.swift */,
C4051DFE2CD25BBA0039D062 /* ArtistsView.swift */,
5D68C4A77696683D132DD518 /* ArtistDetailViewModel.swift */,
);
name = Artists;
path = Artists;
sourceTree = "<group>";
};
3187E4E95236423EE8702B86 /* CarPlay */ = {
isa = PBXGroup;
children = (
566B2E217C6248B16912297F /* CarPlaySceneDelegate.swift */,
2645E70081EEE2C0396E04D8 /* CarPlayCoordinator.swift */,
0EEF17030A154EB98122A089 /* CarPlayNowPlayingManager.swift */,
80C89AD8466BDBA43F95F5DC /* CarPlayImageLoader.swift */,
);
name = CarPlay;
path = CarPlay;
sourceTree = "<group>";
};
6BEE21E914C1B4C06D14C578 /* Frameworks */ = {
isa = PBXGroup;
children = (
CE85DCBEE7ADB56E8BFD6338 /* CarPlay.framework */,
);
name = Frameworks;
sourceTree = "<group>";
};
B0BAAAA72F32139D002A5FBB /* Radios */ = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -210,6 +265,7 @@
C4EAA4852C297E35007EB2E0 /* NowPlaying.swift */,
C456D8F52F2FBD61002AAB8B /* LRCLIB.swift */,
C456D8FB2F2FF397002AAB8B /* LyricsLine.swift */,
B0387072F26D2718279566F4 /* ArtistRadio.swift */,
);
path = Models;
sourceTree = "<group>";
Expand Down Expand Up @@ -263,6 +319,10 @@
C4D7F84E2C7F2C5D00165EFD /* PlaybackService.swift */,
B0BAAAAC2F321697002A5FBB /* RadioService.swift */,
C456D8F72F2FBD64002AAB8B /* LRCLIBService.swift */,
92A728780B0275FE854EC627 /* InAppPurchaseManager.swift */,
E8A0D339760884271C69E36B /* PlaybackCoordinator.swift */,
3D2F567171E8CE853FC5F151 /* WatchConnectivityManager.swift */,
13D2299BFD0380D9B04BBFF5 /* WatchLibraryResponder.swift */,
);
path = Services;
sourceTree = "<group>";
Expand All @@ -284,6 +344,7 @@
C49134542C15C47F00CCF2EB /* README.md */,
C4E8D95A2B763BA900C2353E /* flo */,
C4E8D9592B763BA900C2353E /* Products */,
6BEE21E914C1B4C06D14C578 /* Frameworks */,
);
sourceTree = "<group>";
};
Expand Down Expand Up @@ -318,15 +379,16 @@
C42E7E172CE7EF4D00505B4E /* PlaylistDetailView.swift */,
C4F870CF2CEFD24D00312F8A /* StatCardView.swift */,
C47876012C2BF15900184A33 /* AlbumsView.swift */,
C4051DFE2CD25BBA0039D062 /* ArtistsView.swift */,
C47876032C2BFFF900184A33 /* SongView.swift */,
C4100A682CE78B21001BC9BE /* PlaylistView.swift */,
C4824D242CE9086E003EAB52 /* ArtistDetailView.swift */,
C467AD502D3264AE00644E68 /* FloooViewModel.swift */,
C429DB312D33C704009F2684 /* DownloadButtonView.swift */,
C429DB2F2D33AE81009F2684 /* DownloadQueueView.swift */,
C4DFFA202D32E769003B9C4E /* DownloadViewModel.swift */,
C456D8FD2F300D37002AAB8B /* LyricsView.swift */,
3187E4E95236423EE8702B86 /* CarPlay */,
7E2C854C4AFDB5F757411C4C /* flo.entitlements */,
09524ACAFDF0F9A349F1CCA8 /* Artists */,
);
path = flo;
sourceTree = "<group>";
Expand Down Expand Up @@ -490,6 +552,16 @@
C4875E042C149F9A00D9BAEB /* APIManager.swift in Sources */,
C4A4BF312C14433D00363290 /* HomeView.swift in Sources */,
C4A4BF392C14445000363290 /* PreferencesView.swift in Sources */,
5E64C3D71B02BE8FEDF5FF3C /* CarPlaySceneDelegate.swift in Sources */,
55CFFAB52342C01E366F87B0 /* CarPlayCoordinator.swift in Sources */,
7C09E28C1BFFDB5D5F124EC9 /* CarPlayNowPlayingManager.swift in Sources */,
FA138533DE126212552B3A51 /* CarPlayImageLoader.swift in Sources */,
4BFDB7E71EDDA3BC9DB60860 /* ArtistDetailViewModel.swift in Sources */,
C3C4F155C7432144F2925F57 /* ArtistRadio.swift in Sources */,
FB380D022BD218AA1CE914B3 /* InAppPurchaseManager.swift in Sources */,
FD0E6B93BA00F1E355588795 /* PlaybackCoordinator.swift in Sources */,
520EF9C46F4E2CC1BC306993 /* WatchConnectivityManager.swift in Sources */,
2F9D6FC45D72E9812C06DEE1 /* WatchLibraryResponder.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down Expand Up @@ -624,6 +696,7 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CODE_SIGN_ENTITLEMENTS = flo/flo.entitlements;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
CODE_SIGN_STYLE = Manual;
CURRENT_PROJECT_VERSION = 205;
Expand All @@ -634,7 +707,7 @@
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = flo/Info.plist;
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.music";
INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;
INFOPLIST_KEY_UIApplicationSceneManifest_Generation = NO;
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
INFOPLIST_KEY_UILaunchScreen_Generation = YES;
INFOPLIST_KEY_UIStatusBarStyle = "";
Expand Down Expand Up @@ -664,6 +737,7 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CODE_SIGN_ENTITLEMENTS = flo/flo.entitlements;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
CODE_SIGN_STYLE = Manual;
CURRENT_PROJECT_VERSION = 205;
Expand All @@ -674,7 +748,7 @@
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = flo/Info.plist;
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.music";
INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;
INFOPLIST_KEY_UIApplicationSceneManifest_Generation = NO;
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
INFOPLIST_KEY_UILaunchScreen_Generation = YES;
INFOPLIST_KEY_UIStatusBarStyle = "";
Expand Down
8 changes: 7 additions & 1 deletion flo/App.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,24 @@ import SwiftUI

@main
struct FloApp: App {
@StateObject private var inAppPurchaseManager = InAppPurchaseManager()

init() {
do {
try AVAudioSession.sharedInstance().setCategory(AVAudioSession.Category.playback)
try AVAudioSession.sharedInstance().setActive(true)
} catch {
print(error)
}

#if os(iOS)
WatchConnectivityManager.shared.start()
#endif
}

var body: some Scene {
WindowGroup {
ContentView()
.environmentObject(inAppPurchaseManager)
}
}
}
73 changes: 0 additions & 73 deletions flo/ArtistDetailView.swift

This file was deleted.

Loading