diff --git a/.github/workflows/build-ios-app.yml b/.github/workflows/build-ios-app.yml
deleted file mode 100644
index 80414a10..00000000
--- a/.github/workflows/build-ios-app.yml
+++ /dev/null
@@ -1,20 +0,0 @@
-name: build-ios-app
-on:
- pull_request:
- push:
- branches:
- - 'main'
-jobs:
- build:
- runs-on: macos-latest
- steps:
- - uses: actions/checkout@v2
- - uses: actions/setup-node@v4
- with:
- node-version: 20
- - run: npm run init
- - run: fastlane match
- - run: fastlane beta
- env:
- MATCH_PASSWORD: ${{ secrets.MATCH_PASSWORD }}
- working-directory: ./ios
\ No newline at end of file
diff --git a/.github/workflows/build-ios.yml b/.github/workflows/build-ios.yml
new file mode 100644
index 00000000..594b2305
--- /dev/null
+++ b/.github/workflows/build-ios.yml
@@ -0,0 +1,28 @@
+name: build-ios
+on:
+ push:
+ branches-ignore:
+ - "main"
+jobs:
+ build-ios:
+ runs-on: macos-latest
+ steps:
+ - uses: actions/checkout@v4
+
+ - uses: actions/setup-node@v4
+ with:
+ node-version: 20
+
+ - name: Echo package.json version to Github ENV
+ run: echo VERISON_NUMBER=$(node -p -e "require('./package.json').version") >> $GITHUB_ENV
+
+ - run: npm run init
+
+ - run: fastlane build
+ working-directory: ./ios
+ env:
+ # FASTLANE_PASSWORD: ${{ secrets.FASTLANE_PASSWORD }}
+ APPSTORE_CONNECT_API_KEY_JSON: ${{ secrets.APPSTORE_CONNECT_API_KEY_JSON }}
+ FASTLANE_APPLE_APPLICATION_SPECIFIC_PASSWORD: ${{ secrets.FASTLANE_APPLE_APPLICATION_SPECIFIC_PASSWORD }}
+ MATCH_PASSWORD: ${{ secrets.MATCH_PASSWORD }}
+ MATCH_REPO_PAT: "anultravioletaurora:${{ secrets.SIGNING_REPO_PAT }}"
\ No newline at end of file
diff --git a/.github/workflows/publish-ios-beta.yml b/.github/workflows/publish-ios-beta.yml
new file mode 100644
index 00000000..3575c4e3
--- /dev/null
+++ b/.github/workflows/publish-ios-beta.yml
@@ -0,0 +1,40 @@
+name: publish-ios-beta
+on:
+ pull_request:
+ push:
+ branches:
+ - 'main'
+jobs:
+ publish-ios-beta:
+ runs-on: macos-latest
+ steps:
+ - uses: actions/checkout@v4
+ with:
+ token: ${{ secrets.SIGNING_REPO_PAT }}
+
+ - uses: actions/setup-node@v4
+ with:
+ node-version: 20
+
+ - name: Echo package.json version to Github ENV
+ run: echo VERISON_NUMBER=$(node -p -e "require('./package.json').version") >> $GITHUB_ENV
+
+ - run: npm run init
+
+ - name: Output App Store Connect API Key JSON to Fastlane
+ run: echo -e '${{ secrets.APPSTORE_CONNECT_API_KEY_JSON }}' > appstore_connect_api_key.json
+ working-directory: ./ios/fastlane
+
+ - run: fastlane beta
+ working-directory: ./ios
+ env:
+ APPSTORE_CONNECT_API_KEY_JSON: ${{ secrets.APPSTORE_CONNECT_API_KEY_JSON }}
+ FASTLANE_APPLE_APPLICATION_SPECIFIC_PASSWORD: ${{ secrets.FASTLANE_APPLE_APPLICATION_SPECIFIC_PASSWORD }}
+ MATCH_PASSWORD: ${{ secrets.MATCH_PASSWORD }}
+ MATCH_REPO_PAT: "anultravioletaurora:${{ secrets.SIGNING_REPO_PAT }}"
+
+ # Commit Fastlane Xcode build number increment
+ - uses: stefanzweifel/git-auto-commit-action@v5
+ with:
+ commit_message: "[skip actions]"
+ file_pattern: "ios/Jellify.xcodeproj/project.pbxproj"
\ No newline at end of file
diff --git a/App.tsx b/App.tsx
index fe4dd2d7..00e76884 100644
--- a/App.tsx
+++ b/App.tsx
@@ -8,6 +8,7 @@ import { useColorScheme } from 'react-native';
import jellifyConfig from './tamagui.config';
import { clientPersister } from './constants/storage';
import { queryClient } from './constants/query-client';
+import { GestureHandlerRootView } from 'react-native-gesture-handler';
export default function App(): React.JSX.Element {
@@ -19,11 +20,13 @@ export default function App(): React.JSX.Element {
persistOptions={{
persister: clientPersister
}}>
-
-
-
-
-
+
+
+
+
+
+
+
);
}
\ No newline at end of file
diff --git a/api/mutations/functions/playlists.ts b/api/mutations/functions/playlists.ts
index af6159a1..24ac1270 100644
--- a/api/mutations/functions/playlists.ts
+++ b/api/mutations/functions/playlists.ts
@@ -1,4 +1,4 @@
-import Client from "@/api/client";
+import Client from "../../../api/client";
import { getPlaylistsApi } from "@jellyfin/sdk/lib/utils/api";
diff --git a/api/queries/functions/downloads.ts b/api/queries/functions/downloads.ts
index 8239b225..d063c0c9 100644
--- a/api/queries/functions/downloads.ts
+++ b/api/queries/functions/downloads.ts
@@ -1,11 +1,26 @@
+import { Dirs, FileSystem } from "react-native-file-access";
import Client from "../../../api/client";
import { getLibraryApi } from "@jellyfin/sdk/lib/utils/api";
export async function downloadTrack(itemId: string) : Promise {
+
+ // Make sure downloads folder exists, create if it doesn't
+ if (!(await FileSystem.exists(`${Dirs.DocumentDir}/downloads`)))
+ await FileSystem.mkdir(`${Dirs.DocumentDir}/downloads`)
+
getLibraryApi(Client.api!)
.getDownload({
itemId
}, {
'responseType': 'blob'
})
+ .then(async (response) => {
+ if (response.status < 300) {
+ await FileSystem.writeFile(getTrackFilePath(itemId), response.data)
+ }
+ })
+}
+
+function getTrackFilePath(itemId: string) {
+ return `${Dirs.DocumentDir}/downloads/${itemId}`
}
\ No newline at end of file
diff --git a/components/Global/components/item-card.tsx b/components/Global/components/item-card.tsx
index e2758796..8f81d915 100644
--- a/components/Global/components/item-card.tsx
+++ b/components/Global/components/item-card.tsx
@@ -18,7 +18,7 @@ export function ItemCard(props: CardProps) {
const dimensions = props.width && typeof(props.width) === "number" ? { width: props.width, height: props.width } : { width: 150, height: 150 };
- const logoDimensions = props.width && typeof(props.width) === "number" ? { width: props.width / 2, height: props.width / 3 }: { width: 100, height: 30 };
+ const logoDimensions = props.width && typeof(props.width) === "number" ? { width: props.width / 2, height: props.width / 6 }: { width: 100, height: 30 };
return (
(false);
- const [progressState, setProgressState] = useState(progress!.position);
+ const [progressState, setProgressState] = useState(progress?.position ?? 0);
const { width } = useSafeAreaFrame();
@@ -45,7 +45,7 @@ export default function PlayerScreen({ navigation }: { navigation: NativeStackNa
useEffect(() => {
if (!seeking)
- setProgressState(Math.round(progress!.position))
+ setProgressState(Math.round(progress?.position ?? 0))
}, [
progress
]);
@@ -147,7 +147,7 @@ export default function PlayerScreen({ navigation }: { navigation: NativeStackNa
{/* playback progress goes here */}
- {progress!.duration}
+ {progress?.duration ?? 0}
diff --git a/components/Player/screens/queue.tsx b/components/Player/screens/queue.tsx
index b41e81a4..9db58b97 100644
--- a/components/Player/screens/queue.tsx
+++ b/components/Player/screens/queue.tsx
@@ -30,6 +30,7 @@ export default function Queue({ navigation }: { navigation: NativeStackNavigatio
(
diff --git a/components/Playlist/component.tsx b/components/Playlist/component.tsx
index e5260ef4..403f8fb2 100644
--- a/components/Playlist/component.tsx
+++ b/components/Playlist/component.tsx
@@ -1,13 +1,16 @@
import { BaseItemDto } from "@jellyfin/sdk/lib/generated-client/models";
import { NativeStackNavigationProp } from "@react-navigation/native-stack";
import { StackParamList } from "../types";
-import { XStack, YStack } from "tamagui";
+import { getTokens, XStack, YStack } from "tamagui";
import { useItemTracks } from "../../api/queries/tracks";
import { RunTimeTicks } from "../Global/helpers/time-codes";
import { H4, H5, Text } from "../Global/helpers/text";
import Track from "../Global/components/track";
-import { FlatList } from "react-native";
import BlurhashedImage from "../Global/components/blurhashed-image";
+import DraggableFlatList from "react-native-draggable-flatlist";
+import { reorderPlaylist } from "../../api/mutations/functions/playlists";
+import { useState } from "react";
+import Icon from "../Global/helpers/icon";
interface PlaylistProps {
playlist: BaseItemDto;
@@ -19,13 +22,33 @@ export default function Playlist({
navigation
}: PlaylistProps): React.JSX.Element {
- const { data: tracks, isLoading } = useItemTracks(playlist.Id!);
+ const [editing, setEditing] = useState(false);
+ const { data: tracks, isLoading, refetch } = useItemTracks(playlist.Id!);
+
+ navigation.setOptions({
+ headerRight: () => {
+ return (
+ setEditing(!editing)}
+ />
+ )
+ }
+ })
return (
- (
+ data={tracks ?? []}
+ dragHitSlop={{ left: -50 }} // https://github.com/computerjazz/react-native-draggable-flatlist/issues/336
+ keyExtractor={({ Id }, index) => {
+ return `${index}-${Id}`
+ }}
+ ListHeaderComponent={(
)}
numColumns={1}
- renderItem={({ item: track, index }) => {
+ onDragEnd={({ data, from, to }) => {
+ reorderPlaylist(playlist.Id!, data[to].Id!, to)
+ refetch();
+ }}
+ renderItem={({ item: track, getIndex, drag }) => {
+
+ const index = getIndex();
return (
)
}}
- ListFooterComponent={() => (
+ ListFooterComponent={(
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ios/Jellify.xcodeproj/xcshareddata/xcschemes/Jellify.xcscheme b/ios/Jellify.xcodeproj/xcshareddata/xcschemes/Jellify.xcscheme
index b2bfedf5..26eed832 100644
--- a/ios/Jellify.xcodeproj/xcshareddata/xcschemes/Jellify.xcscheme
+++ b/ios/Jellify.xcodeproj/xcshareddata/xcschemes/Jellify.xcscheme
@@ -41,7 +41,7 @@
CFBundleSignature
????
CFBundleVersion
- 3
+ 7
ITSAppUsesNonExemptEncryption
LSRequiresIPhoneOS
diff --git a/ios/JellifyTests/Info.plist b/ios/JellifyTests/Info.plist
index ba7f37c6..5566d295 100644
--- a/ios/JellifyTests/Info.plist
+++ b/ios/JellifyTests/Info.plist
@@ -19,6 +19,6 @@
CFBundleSignature
????
CFBundleVersion
- 3
+ 7
diff --git a/ios/fastlane/Fastfile b/ios/fastlane/Fastfile
index 6aee14a5..f8bd1adf 100644
--- a/ios/fastlane/Fastfile
+++ b/ios/fastlane/Fastfile
@@ -17,9 +17,43 @@ default_platform(:ios)
platform :ios do
desc "Push a new beta build to TestFlight"
+
+ lane :build do
+ setup_ci
+ match(
+ type: "appstore",
+ app_identifier: "com.cosmonautical.jellify",
+ readonly: true
+ )
+ build_app(
+ scheme: "Jellify",
+ workspace: "Jellify.xcworkspace"
+ )
+ end
+
lane :beta do
- increment_build_number(xcodeproj: "Jellify.xcodeproj")
- build_app(workspace: "Jellify.xcworkspace", scheme: "Jellify")
- upload_to_testflight
+ setup_ci
+ match(
+ type: "appstore",
+ app_identifier: "com.cosmonautical.jellify",
+ readonly: true
+ )
+
+ increment_version_number(
+ version_number: ENV['VERISON_NUMBER'],
+ xcodeproj: "Jellify.xcodeproj"
+ )
+
+ increment_build_number(
+ xcodeproj: "Jellify.xcodeproj"
+ )
+ build_app(
+ scheme: "Jellify - Release",
+ workspace: "Jellify.xcworkspace",
+ )
+ # http://docs.fastlane.tools/actions/upload_to_testflight/#upload_to_testflight
+ upload_to_testflight(
+ api_key_path: "fastlane/appstore_connect_api_key.json"
+ )
end
end
diff --git a/ios/fastlane/Matchfile b/ios/fastlane/Matchfile
index e852d8ed..6bd20271 100644
--- a/ios/fastlane/Matchfile
+++ b/ios/fastlane/Matchfile
@@ -1,4 +1,4 @@
-git_url("git@github.com:anultravioletaurora/jellify-signing.git")
+git_url("https://github.com/anultravioletaurora/jellify-signing.git")
storage_mode("git")
@@ -11,3 +11,5 @@ username("violet@cosmonautical.cloud") # Your Apple Developer Portal username
# Remove the # in the beginning of the line to enable the other options
# The docs are available on https://docs.fastlane.tools/actions/match
+
+git_basic_authorization(Base64.strict_encode64(ENV["MATCH_REPO_PAT"]))
\ No newline at end of file
diff --git a/package.json b/package.json
index 0e52226c..50d236fc 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "jellify",
- "version": "0.1.5",
+ "version": "0.1.7",
"private": true,
"scripts": {
"init": "npm i && npm run pod:install",