Compare commits
7 Commits
feature/re
...
v1.2.6-bet
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f39ab85624 | ||
|
|
01bd17e8cb | ||
|
|
1075e31623 | ||
|
|
8678e3d881 | ||
|
|
0fc087e832 | ||
|
|
a8d563f66d | ||
|
|
1c659d7d90 |
10
README.md
@@ -7,8 +7,10 @@ This is a [React Native](https://reactnative.dev/)-based audio streaming app for
|
|||||||
## ❗️Now open for beta testing on iOS
|
## ❗️Now open for beta testing on iOS
|
||||||
Please follow this link to enroll for the TestFlight beta release of Jellyfin Audio Player: https://testflight.apple.com/join/cf2AMDpx.
|
Please follow this link to enroll for the TestFlight beta release of Jellyfin Audio Player: https://testflight.apple.com/join/cf2AMDpx.
|
||||||
|
|
||||||
|||||
|
|||
|
||||||
|-|-|-|-|
|
|-|-|-|
|
||||||
|
|||
|
||||||
|
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
* Sorting by recent albums
|
* Sorting by recent albums
|
||||||
@@ -18,14 +20,12 @@ Please follow this link to enroll for the TestFlight beta release of Jellyfin Au
|
|||||||
* AirPlay and Chromecast support
|
* AirPlay and Chromecast support
|
||||||
* Background audio
|
* Background audio
|
||||||
* Native Dark Mode
|
* Native Dark Mode
|
||||||
|
|
||||||
### Features being considered
|
|
||||||
* Downloading music for offline playback
|
* Downloading music for offline playback
|
||||||
* Searching based on track names
|
* Searching based on track names
|
||||||
* Looping and shuffling queue
|
* Looping and shuffling queue
|
||||||
|
|
||||||
## Getting Started
|
## Getting Started
|
||||||
This piece of software is in alpha. I am working on getting this app in ~~TestFlight and~~ Google Play Developer Console, but this is contingent on keys being available. In the meantime, IPAs and APK are intermittenly released on the [Releases page](https://github.com/leinelissen/jellyfin-audio-player/releases). Alternatively, you can build this app from source using the build instructions.
|
This piece of software is in beta. I am working on getting this app in ~~TestFlight and~~ Google Play Developer Console, but this is contingent on keys being available. In the meantime, IPAs and APK are intermittenly released on the [Releases page](https://github.com/leinelissen/jellyfin-audio-player/releases). Alternatively, you can build this app from source using the build instructions.
|
||||||
|
|
||||||
### Using the app
|
### Using the app
|
||||||
You will need to setup your Jellyfin account for the application to be able to pull in all your audio. To do this, go over to the "Settings" tab and click the "Set Jellyfin server"-button. A modal will pop up in which you will enter your Jellyfin server url, after which you enter your credentials in the provided browser view. When the app detects your credentials, they will automatically be remembered for the future.
|
You will need to setup your Jellyfin account for the application to be able to pull in all your audio. To do this, go over to the "Settings" tab and click the "Set Jellyfin server"-button. A modal will pop up in which you will enter your Jellyfin server url, after which you enter your credentials in the provided browser view. When the app detects your credentials, they will automatically be remembered for the future.
|
||||||
|
|||||||
@@ -138,8 +138,8 @@ android {
|
|||||||
applicationId "com.jellyfinaudioplayer"
|
applicationId "com.jellyfinaudioplayer"
|
||||||
minSdkVersion rootProject.ext.minSdkVersion
|
minSdkVersion rootProject.ext.minSdkVersion
|
||||||
targetSdkVersion rootProject.ext.targetSdkVersion
|
targetSdkVersion rootProject.ext.targetSdkVersion
|
||||||
versionCode 8
|
versionCode 9
|
||||||
versionName "1.2.4"
|
versionName "1.2.5"
|
||||||
buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled().toString()
|
buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled().toString()
|
||||||
|
|
||||||
if (isNewArchitectureEnabled()) {
|
if (isNewArchitectureEnabled()) {
|
||||||
@@ -322,4 +322,4 @@ def isNewArchitectureEnabled() {
|
|||||||
// - Invoke gradle with `-newArchEnabled=true`
|
// - Invoke gradle with `-newArchEnabled=true`
|
||||||
// - Set an environment variable `ORG_GRADLE_PROJECT_newArchEnabled=true`
|
// - Set an environment variable `ORG_GRADLE_PROJECT_newArchEnabled=true`
|
||||||
return project.hasProperty("newArchEnabled") && project.newArchEnabled == "true"
|
return project.hasProperty("newArchEnabled") && project.newArchEnabled == "true"
|
||||||
}
|
}
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 222 KiB After Width: | Height: | Size: 2.9 MiB |
BIN
docs/images/album.png
Normal file
|
After Width: | Height: | Size: 1.6 MiB |
BIN
docs/images/downloads.png
Normal file
|
After Width: | Height: | Size: 506 KiB |
|
Before Width: | Height: | Size: 252 KiB After Width: | Height: | Size: 1.4 MiB |
|
Before Width: | Height: | Size: 282 KiB After Width: | Height: | Size: 1.8 MiB |
|
Before Width: | Height: | Size: 145 KiB After Width: | Height: | Size: 261 KiB |
@@ -555,7 +555,7 @@
|
|||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
CLANG_ENABLE_MODULES = YES;
|
CLANG_ENABLE_MODULES = YES;
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 36;
|
CURRENT_PROJECT_VERSION = 37;
|
||||||
DEVELOPMENT_TEAM = 238P3C58WC;
|
DEVELOPMENT_TEAM = 238P3C58WC;
|
||||||
ENABLE_BITCODE = NO;
|
ENABLE_BITCODE = NO;
|
||||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||||
@@ -591,7 +591,7 @@
|
|||||||
CLANG_ENABLE_MODULES = YES;
|
CLANG_ENABLE_MODULES = YES;
|
||||||
CODE_SIGN_IDENTITY = "Apple Development";
|
CODE_SIGN_IDENTITY = "Apple Development";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 36;
|
CURRENT_PROJECT_VERSION = 37;
|
||||||
DEVELOPMENT_TEAM = 238P3C58WC;
|
DEVELOPMENT_TEAM = 238P3C58WC;
|
||||||
INFOPLIST_FILE = JellyfinAudioPlayer/Info.plist;
|
INFOPLIST_FILE = JellyfinAudioPlayer/Info.plist;
|
||||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||||
|
|||||||
@@ -17,11 +17,11 @@
|
|||||||
<key>CFBundlePackageType</key>
|
<key>CFBundlePackageType</key>
|
||||||
<string>APPL</string>
|
<string>APPL</string>
|
||||||
<key>CFBundleShortVersionString</key>
|
<key>CFBundleShortVersionString</key>
|
||||||
<string>1.2.4</string>
|
<string>1.2.5</string>
|
||||||
<key>CFBundleSignature</key>
|
<key>CFBundleSignature</key>
|
||||||
<string>????</string>
|
<string>????</string>
|
||||||
<key>CFBundleVersion</key>
|
<key>CFBundleVersion</key>
|
||||||
<string>36</string>
|
<string>37</string>
|
||||||
<key>LSRequiresIPhoneOS</key>
|
<key>LSRequiresIPhoneOS</key>
|
||||||
<true/>
|
<true/>
|
||||||
<key>NSAppTransportSecurity</key>
|
<key>NSAppTransportSecurity</key>
|
||||||
|
|||||||
@@ -15,10 +15,10 @@
|
|||||||
<key>CFBundlePackageType</key>
|
<key>CFBundlePackageType</key>
|
||||||
<string>BNDL</string>
|
<string>BNDL</string>
|
||||||
<key>CFBundleShortVersionString</key>
|
<key>CFBundleShortVersionString</key>
|
||||||
<string>1.2.4</string>
|
<string>1.2.5</string>
|
||||||
<key>CFBundleSignature</key>
|
<key>CFBundleSignature</key>
|
||||||
<string>????</string>
|
<string>????</string>
|
||||||
<key>CFBundleVersion</key>
|
<key>CFBundleVersion</key>
|
||||||
<string>36</string>
|
<string>37</string>
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
|
|||||||
18
package-lock.json
generated
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "JellyfinAudioPlayer",
|
"name": "JellyfinAudioPlayer",
|
||||||
"version": "1.2.4",
|
"version": "1.2.5",
|
||||||
"lockfileVersion": 2,
|
"lockfileVersion": 2,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "JellyfinAudioPlayer",
|
"name": "JellyfinAudioPlayer",
|
||||||
"version": "1.2.4",
|
"version": "1.2.5",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@react-native-community/async-storage": "^1.12.1",
|
"@react-native-community/async-storage": "^1.12.1",
|
||||||
"@react-native-community/blur": "^3.6.0",
|
"@react-native-community/blur": "^3.6.0",
|
||||||
@@ -45,7 +45,7 @@
|
|||||||
"react-native-shadow-2": "^6.0.5",
|
"react-native-shadow-2": "^6.0.5",
|
||||||
"react-native-svg": "^12.3.0",
|
"react-native-svg": "^12.3.0",
|
||||||
"react-native-svg-transformer": "^1.0.0",
|
"react-native-svg-transformer": "^1.0.0",
|
||||||
"react-native-track-player": "^2.1.3",
|
"react-native-track-player": "^2.2.0-rc3",
|
||||||
"react-native-webview": "^11.18.2",
|
"react-native-webview": "^11.18.2",
|
||||||
"react-redux": "^8.0.1",
|
"react-redux": "^8.0.1",
|
||||||
"redux": "^4.2.0",
|
"redux": "^4.2.0",
|
||||||
@@ -14268,9 +14268,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/react-native-track-player": {
|
"node_modules/react-native-track-player": {
|
||||||
"version": "2.1.3",
|
"version": "2.2.0-rc3",
|
||||||
"resolved": "https://registry.npmjs.org/react-native-track-player/-/react-native-track-player-2.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/react-native-track-player/-/react-native-track-player-2.2.0-rc3.tgz",
|
||||||
"integrity": "sha512-JWKFRu+hr1ECN339RH+c+XDM7HfwvdvS4H1p4cJbhg/9b1CQGPJSrYXEhYkngN0msoxBxAjFyFIhjT2fWDCltA==",
|
"integrity": "sha512-Pvmum3MQ5PE8/yOIIPsk00zZk3EzdocUuVUwuBKSCmdKK/3O9YhnZRC3EuT59XCDm23pZZJZDSR44VeXN6Gamg==",
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"react": ">=16.8.6",
|
"react": ">=16.8.6",
|
||||||
"react-native": ">=0.60.0-rc.2",
|
"react-native": ">=0.60.0-rc.2",
|
||||||
@@ -28569,9 +28569,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"react-native-track-player": {
|
"react-native-track-player": {
|
||||||
"version": "2.1.3",
|
"version": "2.2.0-rc3",
|
||||||
"resolved": "https://registry.npmjs.org/react-native-track-player/-/react-native-track-player-2.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/react-native-track-player/-/react-native-track-player-2.2.0-rc3.tgz",
|
||||||
"integrity": "sha512-JWKFRu+hr1ECN339RH+c+XDM7HfwvdvS4H1p4cJbhg/9b1CQGPJSrYXEhYkngN0msoxBxAjFyFIhjT2fWDCltA==",
|
"integrity": "sha512-Pvmum3MQ5PE8/yOIIPsk00zZk3EzdocUuVUwuBKSCmdKK/3O9YhnZRC3EuT59XCDm23pZZJZDSR44VeXN6Gamg==",
|
||||||
"requires": {}
|
"requires": {}
|
||||||
},
|
},
|
||||||
"react-native-webview": {
|
"react-native-webview": {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "JellyfinAudioPlayer",
|
"name": "JellyfinAudioPlayer",
|
||||||
"version": "1.2.4",
|
"version": "1.2.5",
|
||||||
"main": "src/index.js",
|
"main": "src/index.js",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
@@ -49,7 +49,7 @@
|
|||||||
"react-native-shadow-2": "^6.0.5",
|
"react-native-shadow-2": "^6.0.5",
|
||||||
"react-native-svg": "^12.3.0",
|
"react-native-svg": "^12.3.0",
|
||||||
"react-native-svg-transformer": "^1.0.0",
|
"react-native-svg-transformer": "^1.0.0",
|
||||||
"react-native-track-player": "^2.1.3",
|
"react-native-track-player": "^2.2.0-rc3",
|
||||||
"react-native-webview": "^11.18.2",
|
"react-native-webview": "^11.18.2",
|
||||||
"react-redux": "^8.0.1",
|
"react-redux": "^8.0.1",
|
||||||
"redux": "^4.2.0",
|
"redux": "^4.2.0",
|
||||||
|
|||||||
3
src/assets/icons/xmark.svg
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
<svg width="28" height="28" viewBox="0 0 28 28" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M7.18849 19.0509C6.81935 19.4201 6.80177 20.0792 7.19728 20.466C7.58399 20.8527 8.24317 20.8439 8.61231 20.4747L13.9912 15.087L19.3789 20.4747C19.7568 20.8527 20.4072 20.8527 20.794 20.466C21.1719 20.0704 21.1807 19.4288 20.794 19.0509L15.415 13.6632L20.794 8.28431C21.1807 7.90638 21.1807 7.25599 20.794 6.86927C20.3984 6.49134 19.7568 6.48255 19.3789 6.86048L13.9912 12.2482L8.61231 6.86048C8.24317 6.49134 7.5752 6.47376 7.19728 6.86927C6.81056 7.25599 6.81935 7.91517 7.18849 8.28431L12.5762 13.6632L7.18849 19.0509Z" fill="#1C1C1E"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 651 B |
@@ -2,7 +2,7 @@ import { BlurView, BlurViewProperties } from '@react-native-community/blur';
|
|||||||
import { THEME_COLOR } from 'CONSTANTS';
|
import { THEME_COLOR } from 'CONSTANTS';
|
||||||
import React, { PropsWithChildren } from 'react';
|
import React, { PropsWithChildren } from 'react';
|
||||||
import { useContext } from 'react';
|
import { useContext } from 'react';
|
||||||
import { ColorSchemeName, Platform, StyleSheet, useColorScheme } from 'react-native';
|
import { ColorSchemeName, Platform, StyleSheet, useColorScheme, View } from 'react-native';
|
||||||
|
|
||||||
const majorPlatformVersion = typeof Platform.Version === 'string' ? parseInt(Platform.Version, 10) : Platform.Version;
|
const majorPlatformVersion = typeof Platform.Version === 'string' ? parseInt(Platform.Version, 10) : Platform.Version;
|
||||||
|
|
||||||
@@ -100,12 +100,16 @@ export function DefaultStylesProvider(props: DefaultStylesProviderProps) {
|
|||||||
export function ColoredBlurView(props: PropsWithChildren<BlurViewProperties>) {
|
export function ColoredBlurView(props: PropsWithChildren<BlurViewProperties>) {
|
||||||
const scheme = useColorScheme();
|
const scheme = useColorScheme();
|
||||||
|
|
||||||
return (
|
return Platform.OS === 'ios' ? (
|
||||||
<BlurView
|
<BlurView
|
||||||
{...props}
|
{...props}
|
||||||
blurType={Platform.OS === 'ios' && majorPlatformVersion >= 13
|
blurType={Platform.OS === 'ios' && majorPlatformVersion >= 13
|
||||||
? 'material'
|
? 'material'
|
||||||
: scheme === 'dark' ? 'extraDark' : 'xlight'
|
: scheme === 'dark' ? 'extraDark' : 'xlight'
|
||||||
} />
|
} />
|
||||||
|
) : (
|
||||||
|
<View {...props} style={[ props.style, {
|
||||||
|
backgroundColor: scheme === 'light' ? '#f6f6f6f6' : '#333333f6',
|
||||||
|
} ]} />
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -32,7 +32,8 @@ const Logo = styled.Image`
|
|||||||
height: 150px;
|
height: 150px;
|
||||||
margin: 0 auto 50px auto;
|
margin: 0 auto 50px auto;
|
||||||
border-radius: 12px;
|
border-radius: 12px;
|
||||||
border: 1px solid #e6e6e6;
|
border-width: 1px;
|
||||||
|
border-color: #e6e6e6;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
function Onboarding() {
|
function Onboarding() {
|
||||||
|
|||||||
28
src/screens/modals/Player/components/Backbutton.tsx
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
import React, { useCallback } from 'react';
|
||||||
|
import { useNavigation } from '@react-navigation/native';
|
||||||
|
import XmarkIcon from 'assets/icons/xmark.svg';
|
||||||
|
import { TouchableOpacity } from 'react-native';
|
||||||
|
import styled from 'styled-components/native';
|
||||||
|
|
||||||
|
const Container = styled.View`
|
||||||
|
padding: 6px 12px;
|
||||||
|
`;
|
||||||
|
|
||||||
|
function BackButton() {
|
||||||
|
const navigation = useNavigation();
|
||||||
|
|
||||||
|
const handlePress = useCallback(() => {
|
||||||
|
console.log(navigation.canGoBack());
|
||||||
|
navigation.goBack();
|
||||||
|
}, [navigation]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Container>
|
||||||
|
<TouchableOpacity onPress={handlePress}>
|
||||||
|
<XmarkIcon />
|
||||||
|
</TouchableOpacity>
|
||||||
|
</Container>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default BackButton;
|
||||||
@@ -1,16 +1,14 @@
|
|||||||
|
import { t } from '@localisation';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Text } from 'react-native';
|
|
||||||
import styled from 'styled-components/native';
|
import styled from 'styled-components/native';
|
||||||
|
|
||||||
const Button = styled.View`
|
const Label = styled.Text`
|
||||||
margin: 20px 40px;
|
font-size: 13px;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
function Casting() {
|
function Casting() {
|
||||||
return (
|
return (
|
||||||
<Button>
|
<Label>{t('local-playback')}</Label>
|
||||||
<Text>Local Playback</Text>
|
|
||||||
</Button>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ import ticksToDuration from 'utility/ticksToDuration';
|
|||||||
const ICON_SIZE = 16;
|
const ICON_SIZE = 16;
|
||||||
|
|
||||||
const Container = styled.FlatList<Track>`
|
const Container = styled.FlatList<Track>`
|
||||||
padding: 40px;
|
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const Header = styled.View`
|
const Header = styled.View`
|
||||||
@@ -103,6 +103,7 @@ export default function Queue({ header }: Props) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Container
|
<Container
|
||||||
|
contentContainerStyle={{ padding: 40 }}
|
||||||
data={queue}
|
data={queue}
|
||||||
ListHeaderComponent={
|
ListHeaderComponent={
|
||||||
<>
|
<>
|
||||||
|
|||||||
@@ -6,10 +6,13 @@ import Queue from './components/Queue';
|
|||||||
import ConnectionNotice from './components/ConnectionNotice';
|
import ConnectionNotice from './components/ConnectionNotice';
|
||||||
import { GestureHandlerRootView } from 'react-native-gesture-handler';
|
import { GestureHandlerRootView } from 'react-native-gesture-handler';
|
||||||
import StreamStatus from './components/StreamStatus';
|
import StreamStatus from './components/StreamStatus';
|
||||||
|
import { Platform } from 'react-native';
|
||||||
|
import BackButton from './components/Backbutton';
|
||||||
|
|
||||||
export default function Player() {
|
export default function Player() {
|
||||||
return (
|
return (
|
||||||
<GestureHandlerRootView style={{ flex: 1 }}>
|
<GestureHandlerRootView style={{ flex: 1 }}>
|
||||||
|
{Platform.OS === 'android' && (<BackButton />)}
|
||||||
<Queue header={(
|
<Queue header={(
|
||||||
<>
|
<>
|
||||||
<NowPlaying />
|
<NowPlaying />
|
||||||
|
|||||||