Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
23 changes: 21 additions & 2 deletions ios/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
reactNativeFactory = factory

window = UIWindow(frame: UIScreen.main.bounds)

let receiverAppID = kGCKDefaultMediaReceiverApplicationID // or "ABCD1234"
let criteria = GCKDiscoveryCriteria(applicationID: receiverAppID)
let options = GCKCastOptions(discoveryCriteria: criteria)
Expand All @@ -38,7 +38,26 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
options.physicalVolumeButtonsWillControlDeviceVolume = true

GCKCastContext.setSharedInstanceWith(options)


// Debug helper: if launched with --clear-ota argument, wipe any stored Nitro OTA bundle
if ProcessInfo.processInfo.arguments.contains("--clear-ota") {
NitroOtaBundleManager.shared.clearStoredData()
print("[AppDelegate] Cleared Nitro OTA stored data (--clear-ota)")
}

// Debug helper: if environment SKIP_NITRO_OTA=1 is set, clear stored OTA data for this run
if ProcessInfo.processInfo.environment["SKIP_NITRO_OTA"] == "1" {
NitroOtaBundleManager.shared.clearStoredData()
print("[AppDelegate] SKIP_NITRO_OTA=1 detected; cleared Nitro OTA stored data for this run")
}

// Log the resolved JS bundle URL so we can tell whether the app will use an OTA bundle or embedded bundle
if let resolvedURL = delegate.bundleURL() {
print("[AppDelegate] Resolved RN bundle URL: \(resolvedURL.absoluteString)")
} else {
print("[AppDelegate] No RN bundle URL resolved (nil)")
}

factory.startReactNative(
withModuleName: "Jellify",
in: window,
Expand Down
66 changes: 27 additions & 39 deletions ios/Jellify.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -94,8 +94,6 @@
/* Begin PBXFileSystemSynchronizedRootGroup section */
CFE47DDB2EA56B0200EB6067 /* icons */ = {
isa = PBXFileSystemSynchronizedRootGroup;
exceptions = (
);
path = icons;
sourceTree = "<group>";
};
Expand Down Expand Up @@ -399,10 +397,14 @@
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Jellify/Pods-Jellify-frameworks-${CONFIGURATION}-input-files.xcfilelist",
);
inputPaths = (
);
name = "[CP] Embed Pods Frameworks";
outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Jellify/Pods-Jellify-frameworks-${CONFIGURATION}-output-files.xcfilelist",
);
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Jellify/Pods-Jellify-frameworks.sh\"\n";
Expand All @@ -416,10 +418,14 @@
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Jellify/Pods-Jellify-resources-${CONFIGURATION}-input-files.xcfilelist",
);
inputPaths = (
);
name = "[CP] Copy Pods Resources";
outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Jellify/Pods-Jellify-resources-${CONFIGURATION}-output-files.xcfilelist",
);
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Jellify/Pods-Jellify-resources.sh\"\n";
Expand Down Expand Up @@ -541,11 +547,9 @@
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Jellify/Jellify.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
CODE_SIGN_STYLE = Manual;
CURRENT_PROJECT_VERSION = 287;
DEVELOPMENT_TEAM = "";
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = WAH9CZ8BPG;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 300;
DEVELOPMENT_TEAM = YMP32T9CQJ;
Comment on lines +550 to +552
Copy link

Copilot AI Mar 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR is described as adding Home customization, but it also changes iOS signing mode/team, bundle identifier, and app versioning. These are high-impact, environment-specific changes that are typically handled separately (and can break CI/release pipelines for other contributors). Please split these into a separate PR or revert them here unless they’re strictly required for the Home customization feature.

Copilot uses AI. Check for mistakes.
ENABLE_BITCODE = NO;
ENABLE_USER_SCRIPT_SANDBOXING = NO;
INFOPLIST_FILE = Jellify/Info.plist;
Expand All @@ -554,18 +558,17 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 1.0.20;
MARKETING_VERSION = 2.0.1;
Copy link

Copilot AI Mar 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR is described as adding Home customization, but it also changes iOS signing mode/team, bundle identifier, and app versioning. These are high-impact, environment-specific changes that are typically handled separately (and can break CI/release pipelines for other contributors). Please split these into a separate PR or revert them here unless they’re strictly required for the Home customization feature.

Copilot uses AI. Check for mistakes.
NEW_SETTING = "";
OTHER_LDFLAGS = (
"$(inherited)",
"-ObjC",
"-lc++",
);
OTHER_SWIFT_FLAGS = "$(inherited) -D EXPO_CONFIGURATION_DEBUG";
PRODUCT_BUNDLE_IDENTIFIER = com.cosmonautical.jellify;
PRODUCT_BUNDLE_IDENTIFIER = com.dimse.jellify;
Copy link

Copilot AI Mar 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR is described as adding Home customization, but it also changes iOS signing mode/team, bundle identifier, and app versioning. These are high-impact, environment-specific changes that are typically handled separately (and can break CI/release pipelines for other contributors). Please split these into a separate PR or revert them here unless they’re strictly required for the Home customization feature.

Copilot uses AI. Check for mistakes.
PRODUCT_NAME = Jellify;
PROVISIONING_PROFILE_SPECIFIER = "";
"PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "match Development com.cosmonautical.jellify";
SWIFT_OBJC_BRIDGING_HEADER = "Jellify-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0;
Expand All @@ -583,30 +586,27 @@
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Jellify/Jellify.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
CODE_SIGN_STYLE = Manual;
CURRENT_PROJECT_VERSION = 287;
DEVELOPMENT_TEAM = WAH9CZ8BPG;
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = WAH9CZ8BPG;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 300;
DEVELOPMENT_TEAM = YMP32T9CQJ;
ENABLE_USER_SCRIPT_SANDBOXING = NO;
INFOPLIST_FILE = Jellify/Info.plist;
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.music";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 1.0.20;
MARKETING_VERSION = 2.0.1;
NEW_SETTING = "";
OTHER_LDFLAGS = (
"$(inherited)",
"-ObjC",
"-lc++",
);
OTHER_SWIFT_FLAGS = "$(inherited) -D EXPO_CONFIGURATION_RELEASE";
PRODUCT_BUNDLE_IDENTIFIER = com.cosmonautical.jellify;
PRODUCT_BUNDLE_IDENTIFIER = com.dimse.jellify;
PRODUCT_NAME = Jellify;
PROVISIONING_PROFILE_SPECIFIER = "";
"PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "match AppStore com.cosmonautical.jellify";
SWIFT_OBJC_BRIDGING_HEADER = "Jellify-Bridging-Header.h";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
Expand Down Expand Up @@ -655,7 +655,7 @@
COPY_PHASE_STRIP = NO;
CXX = "";
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
ENABLE_TESTABILITY = NO;
ENABLE_USER_SCRIPT_SANDBOXING = NO;
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = "";
GCC_C_LANGUAGE_STANDARD = gnu99;
Expand Down Expand Up @@ -707,10 +707,7 @@
"-DFOLLY_CFG_NO_COROUTINES=1",
"-DFOLLY_HAVE_CLOCK_GETTIME=1",
);
OTHER_LDFLAGS = (
"$(inherited)",
" ",
);
OTHER_LDFLAGS = "$(inherited) ";
REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native";
SDKROOT = iphoneos;
STRING_CATALOG_GENERATE_SYMBOLS = YES;
Expand Down Expand Up @@ -798,10 +795,7 @@
"-DFOLLY_CFG_NO_COROUTINES=1",
"-DFOLLY_HAVE_CLOCK_GETTIME=1",
);
OTHER_LDFLAGS = (
"$(inherited)",
" ",
);
OTHER_LDFLAGS = "$(inherited) ";
REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native";
SDKROOT = iphoneos;
STRING_CATALOG_GENERATE_SYMBOLS = YES;
Expand All @@ -821,11 +815,9 @@
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Jellify/Jellify.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
CODE_SIGN_STYLE = Manual;
CURRENT_PROJECT_VERSION = 287;
DEVELOPMENT_TEAM = WAH9CZ8BPG;
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = WAH9CZ8BPG;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 300;
DEVELOPMENT_TEAM = YMP32T9CQJ;
ENABLE_USER_SCRIPT_SANDBOXING = NO;
ENVFILE = .env.devrelease;
INFOPLIST_FILE = Jellify/Info.plist;
Expand All @@ -834,18 +826,17 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 1.0.20;
MARKETING_VERSION = 2.0.1;
NEW_SETTING = "";
OTHER_LDFLAGS = (
"$(inherited)",
"-ObjC",
"-lc++",
);
OTHER_SWIFT_FLAGS = "$(inherited) -D EXPO_CONFIGURATION_RELEASE -D DEV_RELEASE";
PRODUCT_BUNDLE_IDENTIFIER = com.cosmonautical.jellify;
PRODUCT_BUNDLE_IDENTIFIER = com.dimse.jellify;
PRODUCT_NAME = Jellify;
PROVISIONING_PROFILE_SPECIFIER = "";
"PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "match Development com.cosmonautical.jellify";
SWIFT_OBJC_BRIDGING_HEADER = "Jellify-Bridging-Header.h";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
Expand Down Expand Up @@ -931,10 +922,7 @@
"-DFOLLY_CFG_NO_COROUTINES=1",
"-DFOLLY_HAVE_CLOCK_GETTIME=1",
);
OTHER_LDFLAGS = (
"$(inherited)",
" ",
);
OTHER_LDFLAGS = "$(inherited) ";
REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native";
SDKROOT = iphoneos;
STRING_CATALOG_GENERATE_SYMBOLS = YES;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,19 @@
ReferencedContainer = "container:Jellify.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
<CommandLineArguments>
<CommandLineArgument
argument = "--clear-ota"
isEnabled = "YES">
</CommandLineArgument>
</CommandLineArguments>
<EnvironmentVariables>
<EnvironmentVariable
key = "SKIP_NITROOTA=1"
value = ""
Comment on lines +61 to +62
Copy link

Copilot AI Mar 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The environment variable is declared as SKIP_NITROOTA=1 (including =1 in the key), but AppDelegate.swift checks ProcessInfo.processInfo.environment[\"SKIP_NITRO_OTA\"] == \"1\". As-is, the flag will never be detected. Use a key of SKIP_NITRO_OTA and set its value to 1 (or update the Swift code to match).

Suggested change
key = "SKIP_NITROOTA=1"
value = ""
key = "SKIP_NITRO_OTA"
value = "1"

Copilot uses AI. Check for mistakes.
isEnabled = "YES">
</EnvironmentVariable>
</EnvironmentVariables>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
Expand Down
5 changes: 1 addition & 4 deletions ios/Jellify/Jellify.entitlements
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.developer.carplay-audio</key>
<true/>
</dict>
<dict/>
</plist>
2 changes: 1 addition & 1 deletion ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -3650,7 +3650,7 @@ SPEC CHECKSUMS:
Gifu: 9f7e52357d41c0739709019eb80a71ad9aab1b6d
glog: 5683914934d5b6e4240e497e0f4a3b42d1854183
google-cast-sdk: 32f65af50d164e3c475e79ad123db3cc26fbcd37
hermes-engine: 83ac7cadb2a3a158ae6d9e4192417c5232065e99
hermes-engine: eb56216775bd01d2cbb08c73f932fabe6e878ac5
MMKVCore: d078dce7d6586a888b2c2ef5343b6242678e3ee8
NitroFetch: 0a3dbf3c180870ff93176957cf70b47757552698
NitroMmkv: f0a5804b437ecda18aaf0c75649964343438f083
Expand Down
11 changes: 10 additions & 1 deletion src/components/Artists/component.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ export interface ArtistsProps {
showAlphabeticalSelector: boolean
sortDescending?: boolean
artistPageParams?: RefObject<Set<string>>
// When true, short press triggers the default long-press action
// and long press triggers the default short-press action.
invertPressBehavior?: boolean
}

/**
Expand All @@ -38,6 +41,7 @@ export default function Artists({
showAlphabeticalSelector,
sortDescending,
artistPageParams,
invertPressBehavior,
}: ArtistsProps): React.JSX.Element {
const theme = useTheme()

Expand Down Expand Up @@ -77,7 +81,12 @@ export default function Artists({
<FlashListStickyHeader text={artist.toUpperCase()} />
)
) : typeof artist === 'number' ? null : typeof artist === 'object' ? (
<ItemRow circular item={artist} navigation={navigation} />
<ItemRow
circular
item={artist}
navigation={navigation}
invertPressBehavior={invertPressBehavior}
/>
) : null

// Effect for handling the pending alphabet selector letter
Expand Down
8 changes: 6 additions & 2 deletions src/components/Context/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,8 @@ function AddToQueueMenuRow({ tracks }: { tracks: BaseItemDto[] }): React.JSX.Ele
...mutation,
queuingType: QueuingType.PlayingNext,
})
// Close the popup menu immediately after action
navigationRef.dispatch(StackActions.pop())
}}
pressStyle={{ opacity: 0.5 }}
>
Expand All @@ -211,11 +213,13 @@ function AddToQueueMenuRow({ tracks }: { tracks: BaseItemDto[] }): React.JSX.Ele
flex={1}
gap={'$2.5'}
justifyContent='flex-start'
onPress={() => {
addToQueue({
onPress={async () => {
await addToQueue({
...mutation,
queuingType: QueuingType.DirectlyQueued,
})
// Close the popup menu immediately after action
navigationRef.dispatch(StackActions.pop())
}}
pressStyle={{ opacity: 0.5 }}
>
Expand Down
34 changes: 17 additions & 17 deletions src/components/Global/components/Track/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -86,23 +86,8 @@ export default function Track({
// Memoize tracklist for queue loading
const memoizedTracklist = tracklist ?? playQueue?.map((track) => track.item) ?? []

// Memoize handlers to prevent recreation
const handlePress = async () => {
if (onPress) {
await onPress()
} else {
loadNewQueue({
track,
index,
tracklist: memoizedTracklist,
queue,
queuingType: QueuingType.FromSelection,
startPlayback: true,
})
}
}

const handleLongPress = () => {
// Reverse: short press opens context, long press plays track
const handlePress = () => {
if (onLongPress) {
onLongPress()
} else {
Expand All @@ -117,6 +102,21 @@ export default function Track({
}
}

const handleLongPress = async () => {
if (onPress) {
await onPress()
} else {
loadNewQueue({
track,
index,
tracklist: memoizedTracklist,
queue,
queuingType: QueuingType.FromSelection,
startPlayback: true,
})
}
}

const handleIconPress = () => {
navigationRef.navigate('Context', {
item: track,
Expand Down
Loading
Loading