Compare commits
13 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3053e2b5c9 | ||
|
|
7f1585a6ad | ||
|
|
704edfbaaf | ||
|
|
5622c007f2 | ||
|
|
3719a71e0f | ||
|
|
44fb9a022d | ||
|
|
45cc51192a | ||
|
|
d981690ba6 | ||
|
|
161a621d71 | ||
|
|
7da1afa643 | ||
|
|
77e89fc9e2 | ||
|
|
36e97cb621 | ||
|
|
c539376cc4 |
15
README.md
@@ -5,19 +5,23 @@ Subtracks is an Android open source music streaming app for [Subsonic-API-compat
|
|||||||
|
|
||||||
# Screenshots
|
# Screenshots
|
||||||
<p float="left">
|
<p float="left">
|
||||||
<img src="assets/screenshots/01_home.png" alt="home" width="200"/>
|
<img src="metadata/en-US/images/phoneScreenshots/01_home.png" alt="home" width="200"/>
|
||||||
<img src="assets/screenshots/02_now-playing.png" alt="now playing" width="200"/>
|
<img src="metadata/en-US/images/phoneScreenshots/02_now-playing.png" alt="now playing" width="200"/>
|
||||||
<img src="assets/screenshots/03_library-albums.png" alt="library albums" width="200"/>
|
<img src="metadata/en-US/images/phoneScreenshots/03_library-albums.png" alt="library albums" width="200"/>
|
||||||
<img src="assets/screenshots/04_album.png" alt="album view" width="200"/>
|
<img src="metadata/en-US/images/phoneScreenshots/04_album.png" alt="album view" width="200"/>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
# Download
|
# Download
|
||||||
<p float="left">
|
<p float="left">
|
||||||
<a href="https://github.com/austinried/subtracks/releases/latest" disabled><img src="assets/github-badge.png" width="250"/></a>
|
<a href="https://play.google.com/store/apps/details?id=com.subtracks"><img src="assets/google-play-badge.png" width="250"/></a>
|
||||||
|
<a href="https://github.com/austinried/subtracks/releases/latest"><img src="assets/github-badge.png" width="250"/></a>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
> :warning: Note: each download source above is signed with a different key, so you cannot switch between them without first uninstalling and then re-installing the app.
|
||||||
|
|
||||||
# Features
|
# Features
|
||||||
- Album and artist art display by default (full-res in detail/now playing views)
|
- Album and artist art display by default (full-res in detail/now playing views)
|
||||||
|
- Gapless playback
|
||||||
- Mulitple server support
|
- Mulitple server support
|
||||||
- Filterable/sortable album and artist library views
|
- Filterable/sortable album and artist library views
|
||||||
- Search artists, albums, and songs
|
- Search artists, albums, and songs
|
||||||
@@ -36,3 +40,4 @@ Subtracks is an Android open source music streaming app for [Subsonic-API-compat
|
|||||||
- Queue management (add/remove/sort)
|
- Queue management (add/remove/sort)
|
||||||
- Multi-select actions
|
- Multi-select actions
|
||||||
- Performance & animation improvements
|
- Performance & animation improvements
|
||||||
|
- More shuffle play modes
|
||||||
|
|||||||
@@ -134,8 +134,8 @@ android {
|
|||||||
applicationId "com.subtracks"
|
applicationId "com.subtracks"
|
||||||
minSdkVersion rootProject.ext.minSdkVersion
|
minSdkVersion rootProject.ext.minSdkVersion
|
||||||
targetSdkVersion rootProject.ext.targetSdkVersion
|
targetSdkVersion rootProject.ext.targetSdkVersion
|
||||||
versionCode 1
|
versionCode 3
|
||||||
versionName '0.1.0'
|
versionName '1.0.1'
|
||||||
}
|
}
|
||||||
splits {
|
splits {
|
||||||
abi {
|
abi {
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.subtracks">
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.subtracks" xmlns:tools="http://schemas.android.com/tools">
|
||||||
<uses-permission android:name="android.permission.INTERNET"/>
|
<uses-permission android:name="android.permission.INTERNET"/>
|
||||||
|
<uses-permission tools:node="remove" android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
|
||||||
|
<uses-permission tools:node="remove" android:name="android.permission.READ_EXTERNAL_STORAGE"/>
|
||||||
<application android:name=".MainApplication" android:label="@string/app_name" android:icon="@mipmap/ic_launcher" android:roundIcon="@mipmap/ic_launcher_round" android:allowBackup="false" android:theme="@style/AppTheme" android:usesCleartextTraffic="true">
|
<application android:name=".MainApplication" android:label="@string/app_name" android:icon="@mipmap/ic_launcher" android:roundIcon="@mipmap/ic_launcher_round" android:allowBackup="false" android:theme="@style/AppTheme" android:usesCleartextTraffic="true">
|
||||||
<activity android:name=".MainActivity" android:label="@string/app_name" android:configChanges="keyboard|keyboardHidden|orientation|screenSize|uiMode" android:launchMode="singleTask" android:windowSoftInputMode="adjustPan">
|
<activity android:name=".MainActivity" android:label="@string/app_name" android:configChanges="keyboard|keyboardHidden|orientation|screenSize|uiMode" android:launchMode="singleTask" android:windowSoftInputMode="adjustPan">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
|
|||||||
@@ -156,13 +156,13 @@ const infoStyles = StyleSheet.create({
|
|||||||
justifyContent: 'center',
|
justifyContent: 'center',
|
||||||
},
|
},
|
||||||
title: {
|
title: {
|
||||||
height: 28,
|
minHeight: 30,
|
||||||
fontFamily: font.bold,
|
fontFamily: font.bold,
|
||||||
fontSize: 22,
|
fontSize: 22,
|
||||||
color: colors.text.primary,
|
color: colors.text.primary,
|
||||||
},
|
},
|
||||||
artist: {
|
artist: {
|
||||||
height: 20,
|
minHeight: 21,
|
||||||
fontFamily: font.regular,
|
fontFamily: font.regular,
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
color: colors.text.secondary,
|
color: colors.text.secondary,
|
||||||
@@ -363,7 +363,7 @@ const controlsStyles = StyleSheet.create({
|
|||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
justifyContent: 'space-between',
|
justifyContent: 'space-between',
|
||||||
paddingTop: 10,
|
paddingTop: 10,
|
||||||
paddingBottom: 54,
|
paddingBottom: 40,
|
||||||
},
|
},
|
||||||
play: {
|
play: {
|
||||||
marginHorizontal: 30,
|
marginHorizontal: 30,
|
||||||
@@ -419,7 +419,6 @@ const NowPlayingView: React.FC<NowPlayingProps> = ({ navigation }) => {
|
|||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
container: {
|
container: {
|
||||||
flex: 1,
|
flex: 1,
|
||||||
// paddingTop: StatusBar.currentHeight,
|
|
||||||
},
|
},
|
||||||
content: {
|
content: {
|
||||||
flex: 1,
|
flex: 1,
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import React, { useCallback, useState } from 'react'
|
|||||||
import { KeyboardTypeOptions, Linking, Modal, Pressable, StatusBar, StyleSheet, Text, View } from 'react-native'
|
import { KeyboardTypeOptions, Linking, Modal, Pressable, StatusBar, StyleSheet, Text, View } from 'react-native'
|
||||||
import { ScrollView } from 'react-native-gesture-handler'
|
import { ScrollView } from 'react-native-gesture-handler'
|
||||||
import Icon from 'react-native-vector-icons/MaterialCommunityIcons'
|
import Icon from 'react-native-vector-icons/MaterialCommunityIcons'
|
||||||
|
import { version } from '../../package.json'
|
||||||
|
|
||||||
const ServerItem = React.memo<{
|
const ServerItem = React.memo<{
|
||||||
server: Server
|
server: Server
|
||||||
@@ -286,6 +287,9 @@ const SettingsContent = React.memo(() => {
|
|||||||
buttonStyle="hollow"
|
buttonStyle="hollow"
|
||||||
/>
|
/>
|
||||||
<Header style={styles.header}>About</Header>
|
<Header style={styles.header}>About</Header>
|
||||||
|
<Text style={styles.text}>
|
||||||
|
<Text style={styles.bold}>Subtracks</Text> version {version}
|
||||||
|
</Text>
|
||||||
<Button
|
<Button
|
||||||
disabled={clearing}
|
disabled={clearing}
|
||||||
style={styles.button}
|
style={styles.button}
|
||||||
@@ -396,6 +400,14 @@ const styles = StyleSheet.create({
|
|||||||
modalTextSubmit: {
|
modalTextSubmit: {
|
||||||
marginLeft: 15,
|
marginLeft: 15,
|
||||||
},
|
},
|
||||||
|
text: {
|
||||||
|
color: 'white',
|
||||||
|
fontFamily: font.regular,
|
||||||
|
fontSize: 16,
|
||||||
|
},
|
||||||
|
bold: {
|
||||||
|
fontFamily: font.bold,
|
||||||
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
export default Settings
|
export default Settings
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 149 KiB |
1
metadata/en-US/changelogs/1.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
Initial release
|
||||||
1
metadata/en-US/changelogs/2.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
Initial 1.0.0 release
|
||||||
4
metadata/en-US/changelogs/3.txt
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
## Changes
|
||||||
|
|
||||||
|
- Remove unused permissions (read/write external storage)
|
||||||
|
- Fix text cutting off on Now Playing screen
|
||||||
12
metadata/en-US/full_description.txt
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
Subtracks is an Android open source music streaming app for Subsonic-API-compatible servers (Subsonic, Navidrome, Airsonic, and more). It's designed to give you clean and convenient access to your music in the style of modern media players.
|
||||||
|
|
||||||
|
Features
|
||||||
|
- Album and artist art display by default (full-res in detail/now playing views)
|
||||||
|
- Gapless playback
|
||||||
|
- Mulitple server support
|
||||||
|
- Filterable/sortable album and artist library views
|
||||||
|
- Search artists, albums, and songs
|
||||||
|
- Scrobble support
|
||||||
|
- Max bitrate and buffer size settings
|
||||||
|
- Loop and shuffle playback options
|
||||||
|
- Long-press for context menu shortcuts
|
||||||
BIN
metadata/en-US/images/featureGraphic.png
Normal file
|
After Width: | Height: | Size: 22 KiB |
BIN
metadata/en-US/images/icon.png
Normal file
|
After Width: | Height: | Size: 8.3 KiB |
|
Before Width: | Height: | Size: 1.4 MiB After Width: | Height: | Size: 1.4 MiB |
|
Before Width: | Height: | Size: 649 KiB After Width: | Height: | Size: 649 KiB |
|
Before Width: | Height: | Size: 1.8 MiB After Width: | Height: | Size: 1.8 MiB |
|
Before Width: | Height: | Size: 905 KiB After Width: | Height: | Size: 905 KiB |
|
Before Width: | Height: | Size: 1.4 MiB After Width: | Height: | Size: 1.4 MiB |
|
Before Width: | Height: | Size: 437 KiB After Width: | Height: | Size: 437 KiB |
|
Before Width: | Height: | Size: 444 KiB After Width: | Height: | Size: 444 KiB |
1
metadata/en-US/short_description.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
A music streaming app for Subsonic-API-compatible servers
|
||||||
1
metadata/en-US/title.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
Subtracks
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "subtracks",
|
"name": "subtracks",
|
||||||
"version": "0.1.0",
|
"version": "1.0.1",
|
||||||
"private": true,
|
"private": true,
|
||||||
"license": "GPL-3.0-only",
|
"license": "GPL-3.0-only",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
@@ -26,6 +26,7 @@
|
|||||||
"@react-navigation/bottom-tabs": "^5.11.11",
|
"@react-navigation/bottom-tabs": "^5.11.11",
|
||||||
"@react-navigation/material-top-tabs": "^5.3.15",
|
"@react-navigation/material-top-tabs": "^5.3.15",
|
||||||
"@react-navigation/native": "^5.9.4",
|
"@react-navigation/native": "^5.9.4",
|
||||||
|
"@xmldom/xmldom": "^0.7.2",
|
||||||
"immer": "^9.0.5",
|
"immer": "^9.0.5",
|
||||||
"lodash.debounce": "^4.0.8",
|
"lodash.debounce": "^4.0.8",
|
||||||
"md5": "^2.3.0",
|
"md5": "^2.3.0",
|
||||||
@@ -45,7 +46,6 @@
|
|||||||
"react-native-vector-icons": "^8.1.0",
|
"react-native-vector-icons": "^8.1.0",
|
||||||
"react-native-webview": "^11.13.0",
|
"react-native-webview": "^11.13.0",
|
||||||
"uuid": "^8.3.2",
|
"uuid": "^8.3.2",
|
||||||
"xmldom": "^0.5.0",
|
|
||||||
"zustand": "^3.5.7"
|
"zustand": "^3.5.7"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
@@ -59,7 +59,7 @@
|
|||||||
"@types/react-native-vector-icons": "^6.4.7",
|
"@types/react-native-vector-icons": "^6.4.7",
|
||||||
"@types/react-test-renderer": "^16.9.2",
|
"@types/react-test-renderer": "^16.9.2",
|
||||||
"@types/uuid": "^8.3.0",
|
"@types/uuid": "^8.3.0",
|
||||||
"@types/xmldom": "^0.1.30",
|
"@types/xmldom": "^0.1.31",
|
||||||
"babel-jest": "^26.6.3",
|
"babel-jest": "^26.6.3",
|
||||||
"babel-plugin-module-resolver": "^4.1.0",
|
"babel-plugin-module-resolver": "^4.1.0",
|
||||||
"eslint": "^7.14.0",
|
"eslint": "^7.14.0",
|
||||||
|
|||||||
@@ -46,7 +46,7 @@
|
|||||||
"allowSyntheticDefaultImports": true /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */,
|
"allowSyntheticDefaultImports": true /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */,
|
||||||
"esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */,
|
"esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */,
|
||||||
// "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */
|
// "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */
|
||||||
"skipLibCheck": false /* Skip type checking of declaration files. */
|
"skipLibCheck": false /* Skip type checking of declaration files. */,
|
||||||
|
|
||||||
/* Source Map Options */
|
/* Source Map Options */
|
||||||
// "sourceRoot": "./", /* Specify the location where debugger should locate TypeScript files instead of source locations. */
|
// "sourceRoot": "./", /* Specify the location where debugger should locate TypeScript files instead of source locations. */
|
||||||
@@ -57,6 +57,7 @@
|
|||||||
/* Experimental Options */
|
/* Experimental Options */
|
||||||
// "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */
|
// "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */
|
||||||
// "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */
|
// "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */
|
||||||
|
"resolveJsonModule": true
|
||||||
},
|
},
|
||||||
"exclude": ["node_modules", "babel.config.js", "metro.config.js", "jest.config.js"]
|
"exclude": ["node_modules", "babel.config.js", "metro.config.js", "jest.config.js"]
|
||||||
}
|
}
|
||||||
|
|||||||
13
yarn.lock
@@ -1388,10 +1388,10 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-8.3.0.tgz#215c231dff736d5ba92410e6d602050cce7e273f"
|
resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-8.3.0.tgz#215c231dff736d5ba92410e6d602050cce7e273f"
|
||||||
integrity sha512-eQ9qFW/fhfGJF8WKHGEHZEyVWfZxrT+6CLIJGBcZPfxUh/+BnEj+UCGYMlr9qZuX/2AltsvwrGqp0LhEW8D0zQ==
|
integrity sha512-eQ9qFW/fhfGJF8WKHGEHZEyVWfZxrT+6CLIJGBcZPfxUh/+BnEj+UCGYMlr9qZuX/2AltsvwrGqp0LhEW8D0zQ==
|
||||||
|
|
||||||
"@types/xmldom@^0.1.30":
|
"@types/xmldom@^0.1.31":
|
||||||
version "0.1.30"
|
version "0.1.31"
|
||||||
resolved "https://registry.yarnpkg.com/@types/xmldom/-/xmldom-0.1.30.tgz#d36d9a7d64af4693d3b18d5dc02ce432a95be12e"
|
resolved "https://registry.yarnpkg.com/@types/xmldom/-/xmldom-0.1.31.tgz#519b647cfc66debf82cdf50e49763c8fdee553d6"
|
||||||
integrity sha512-edqgAFXMEtVvaBZ3YnhamvmrHjoYpuxETmnb0lbTZmf/dXpAsO9ZKotUO4K2rn2SIZBDFCMOuA7fOe0H6dRZcA==
|
integrity sha512-bVy7s0nvaR5D1mT1a8ZkByHWNOGb6Vn4yi5TWhEdmyKlAG+08SA7Md6+jH+tYmMLueAwNeWvHHpeKrr6S4c4BA==
|
||||||
|
|
||||||
"@types/yargs-parser@*":
|
"@types/yargs-parser@*":
|
||||||
version "20.2.0"
|
version "20.2.0"
|
||||||
@@ -1465,6 +1465,11 @@
|
|||||||
dependencies:
|
dependencies:
|
||||||
eslint-visitor-keys "^1.1.0"
|
eslint-visitor-keys "^1.1.0"
|
||||||
|
|
||||||
|
"@xmldom/xmldom@^0.7.2":
|
||||||
|
version "0.7.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/@xmldom/xmldom/-/xmldom-0.7.2.tgz#d920079e66806b2626b5311955f6a7c4bed1cba8"
|
||||||
|
integrity sha512-t/Zqo0ewes3iq6zGqEqJNUWI27Acr3jkmSUNp6E3nl0Z2XbtqAG5XYqPNLdYonILmhcxANsIidh69tHzjXtuRg==
|
||||||
|
|
||||||
abab@^2.0.3, abab@^2.0.5:
|
abab@^2.0.3, abab@^2.0.5:
|
||||||
version "2.0.5"
|
version "2.0.5"
|
||||||
resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.5.tgz#c0b678fb32d60fc1219c784d6a826fe385aeb79a"
|
resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.5.tgz#c0b678fb32d60fc1219c784d6a826fe385aeb79a"
|
||||||
|
|||||||