Skip to content

Commit 8001f90

Browse files
committed
Release version 1.6
1 parent 552d0b5 commit 8001f90

44 files changed

Lines changed: 3584 additions & 1095 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/release.yml

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -55,22 +55,24 @@ jobs:
5555
body: |
5656
## SpatialFlow ${{ github.ref_name }}
5757
58-
### What's New
59-
- Updated app logo
60-
- Replaced Toast notifications with Snackbar in player
61-
- Added landscape mode support
62-
- Added copyright information in Settings page
58+
### What's New in v1.6
59+
- 8D Auto-Reset on Song Change
60+
- Full Light Mode Support (Player, Effects, Mesh Gradient)
61+
- Fixed Landscape Mode (Player & Effects)
62+
- Dark Mode Toggle Syncs with System Theme
63+
- Optimized 8D Processing (Faster FFmpeg, No Bass Interference)
64+
- Better Bottom Spacing in Effects & Settings
65+
- Enhanced Mini Player Styling
66+
- Improved Mesh Gradient Animations
6367
6468
### Installation
6569
1. Download `app-release.apk`
6670
2. Install on your Android device
6771
3. Or use in-app "Check for updates" to auto-update
6872
69-
⚠️ **Note for v1.0.0 users**: You must uninstall the old version first before installing v1.1. Future updates will install seamlessly.
70-
7173
### Technical Details
7274
- Min SDK: 24 (Android 7.0+)
7375
- Target SDK: 35 (Android 15)
74-
- Version Code: 3
76+
- Version Code: 6
7577
env:
7678
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

.idea/render.experimental.xml

Lines changed: 0 additions & 6 deletions
This file was deleted.

.vscode/settings.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"java.configuration.updateBuildConfiguration": "disabled"
3+
}

app/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ android {
1717
minSdk 24
1818
targetSdk 35
1919
versionCode 6
20-
versionName "1.5"
20+
versionName "1.6"
2121
}
2222

2323
signingConfigs {

app/src/main/AndroidManifest.xml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,7 @@
2727
<activity
2828
android:name=".MainActivity"
2929
android:exported="true"
30-
android:supportsPictureInPicture="true"
3130
android:resizeableActivity="true"
32-
android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation"
3331
android:label="@string/app_name"
3432
android:theme="@style/Theme.SpatialFlow">
3533
<intent-filter>

app/src/main/java/com/codetrio/spatialflow/MainActivity.java

Lines changed: 65 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
import android.animation.AnimatorSet;
77
import android.animation.ObjectAnimator;
88
import android.app.ActivityManager;
9-
import android.app.PictureInPictureParams;
109
import android.content.ComponentName;
1110
import android.content.Context;
1211
import android.content.Intent;
@@ -19,7 +18,6 @@
1918
import android.os.Bundle;
2019
import android.os.IBinder;
2120
import android.util.Log;
22-
import android.util.Rational;
2321
import android.view.MenuItem;
2422
import android.view.View;
2523
import android.view.Window;
@@ -106,7 +104,7 @@ protected void onCreate(Bundle savedInstanceState) {
106104

107105
NavigationUI.setupWithNavController(navView, navController);
108106

109-
// Open PlayerFragment when tapped from PiP
107+
// Open PlayerFragment when tapped from notification
110108
if (getIntent() != null && getIntent().getBooleanExtra(EXTRA_OPEN_PLAYER, false)) {
111109
navController.navigate(R.id.navigation_player);
112110
navView.setSelectedItemId(R.id.navigation_player);
@@ -116,8 +114,10 @@ protected void onCreate(Bundle savedInstanceState) {
116114
int destId = item.getItemId();
117115
NavDestination current = navController.getCurrentDestination();
118116

119-
if (current != null && current.getId() == destId) return true;
120-
if (isNavigating) return false;
117+
if (current != null && current.getId() == destId)
118+
return true;
119+
if (isNavigating)
120+
return false;
121121

122122
bounceBottomNavIcon(item);
123123

@@ -293,7 +293,8 @@ private void startAudioService() {
293293

294294
private void ensureServiceRunning() {
295295
ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
296-
if (manager == null) return;
296+
if (manager == null)
297+
return;
297298

298299
for (ActivityManager.RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
299300
if (AudioPlaybackService.class.getName().equals(service.service.getClassName())) {
@@ -305,22 +306,20 @@ private void ensureServiceRunning() {
305306

306307
private void checkAudioPermission() {
307308
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
308-
if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_MEDIA_AUDIO)
309-
!= PackageManager.PERMISSION_GRANTED) {
309+
if (ContextCompat.checkSelfPermission(this,
310+
Manifest.permission.READ_MEDIA_AUDIO) != PackageManager.PERMISSION_GRANTED) {
310311
ActivityCompat.requestPermissions(
311312
this,
312-
new String[]{Manifest.permission.READ_MEDIA_AUDIO},
313-
AUDIO_PERMISSION_REQUEST
314-
);
313+
new String[] { Manifest.permission.READ_MEDIA_AUDIO },
314+
AUDIO_PERMISSION_REQUEST);
315315
}
316316
} else {
317-
if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE)
318-
!= PackageManager.PERMISSION_GRANTED) {
317+
if (ContextCompat.checkSelfPermission(this,
318+
Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
319319
ActivityCompat.requestPermissions(
320320
this,
321-
new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},
322-
AUDIO_PERMISSION_REQUEST
323-
);
321+
new String[] { Manifest.permission.READ_EXTERNAL_STORAGE },
322+
AUDIO_PERMISSION_REQUEST);
324323
}
325324
}
326325
}
@@ -331,7 +330,7 @@ private void applyWindowInsetsBehavior() {
331330

332331
ViewCompat.setOnApplyWindowInsetsListener(container, (v, windowInsets) -> {
333332
Insets insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars());
334-
v.setPadding(0, insets.top, 0, 0);
333+
v.setPadding(0, 0, 0, 0); // Remove top padding
335334
return windowInsets;
336335
});
337336

@@ -341,8 +340,7 @@ private void applyWindowInsetsBehavior() {
341340
v.getPaddingLeft(),
342341
v.getPaddingTop(),
343342
v.getPaddingRight(),
344-
insets.bottom
345-
);
343+
insets.bottom);
346344
return WindowInsetsCompat.CONSUMED;
347345
});
348346

@@ -367,29 +365,27 @@ private void setupBottomNavColors(BottomNavigationView navView) {
367365
int backgroundColor = typedValue.data;
368366

369367
ColorStateList iconColorStateList = new ColorStateList(
370-
new int[][]{
371-
new int[]{android.R.attr.state_checked},
372-
new int[]{-android.R.attr.state_checked}
368+
new int[][] {
369+
new int[] { android.R.attr.state_checked },
370+
new int[] { -android.R.attr.state_checked }
373371
},
374-
new int[]{
372+
new int[] {
375373
activeColor,
376374
inactiveColor
377-
}
378-
);
375+
});
379376

380377
theme.resolveAttribute(com.google.android.material.R.attr.colorOnSurface, typedValue, true);
381378
int activeTextColor = typedValue.data;
382379

383380
ColorStateList textColorStateList = new ColorStateList(
384-
new int[][]{
385-
new int[]{android.R.attr.state_checked},
386-
new int[]{-android.R.attr.state_checked}
381+
new int[][] {
382+
new int[] { android.R.attr.state_checked },
383+
new int[] { -android.R.attr.state_checked }
387384
},
388-
new int[]{
385+
new int[] {
389386
activeTextColor,
390387
inactiveColor
391-
}
392-
);
388+
});
393389

394390
navView.setItemIconTintList(iconColorStateList);
395391
navView.setItemTextColor(textColorStateList);
@@ -420,9 +416,12 @@ private void setupSystemBars() {
420416
}
421417

422418
private int getDestinationIndex(int id) {
423-
if (id == R.id.navigation_player) return 0;
424-
if (id == R.id.navigation_effects) return 1;
425-
if (id == R.id.navigation_settings) return 2;
419+
if (id == R.id.navigation_player)
420+
return 0;
421+
if (id == R.id.navigation_effects)
422+
return 1;
423+
if (id == R.id.navigation_settings)
424+
return 2;
426425
return 0;
427426
}
428427

@@ -431,37 +430,18 @@ public boolean onSupportNavigateUp() {
431430
return navController.navigateUp() || super.onSupportNavigateUp();
432431
}
433432

434-
public void enterPipModeIfPossible() {
435-
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
436-
Rational aspectRatio = new Rational(1, 1);
437-
PictureInPictureParams params = new PictureInPictureParams.Builder()
438-
.setAspectRatio(aspectRatio)
439-
.build();
440-
enterPictureInPictureMode(params);
441-
}
442-
}
443-
444-
@Override
445-
public void onPictureInPictureModeChanged(boolean isInPictureInPictureMode) {
446-
super.onPictureInPictureModeChanged(isInPictureInPictureMode);
433+
// PIP mode methods removed as per user request
447434

448-
if (navView != null) {
449-
navView.setVisibility(isInPictureInPictureMode ? View.GONE : View.VISIBLE);
450-
}
435+
// isPlayerFragmentVisible kept for potential future use
436+
private boolean isPlayerFragmentVisible() {
437+
NavDestination currentDestination = navController.getCurrentDestination();
438+
return currentDestination != null && currentDestination.getId() == R.id.navigation_player;
451439
}
452440

453441
@Override
454442
protected void onUserLeaveHint() {
455443
super.onUserLeaveHint();
456-
457-
if (isPlayerFragmentVisible() && audioService != null && audioService.isPlaying()) {
458-
enterPipModeIfPossible();
459-
}
460-
}
461-
462-
private boolean isPlayerFragmentVisible() {
463-
NavDestination currentDestination = navController.getCurrentDestination();
464-
return currentDestination != null && currentDestination.getId() == R.id.navigation_player;
444+
// PIP mode removed
465445
}
466446

467447
@Override
@@ -495,4 +475,30 @@ public AudioPlaybackService getAudioService() {
495475
public boolean isAudioServiceBound() {
496476
return isServiceBound;
497477
}
478+
479+
public void setBottomNavVisibility(boolean visible) {
480+
if (navView == null)
481+
return;
482+
navView.clearAnimation();
483+
if (visible)
484+
navView.setVisibility(View.VISIBLE);
485+
float targetY = visible ? 0 : navView.getHeight() + 100;
486+
navView.animate()
487+
.translationY(targetY)
488+
.setDuration(300)
489+
.setInterpolator(visible ? new android.view.animation.DecelerateInterpolator()
490+
: new android.view.animation.AccelerateInterpolator())
491+
.start();
492+
}
493+
494+
public void setBottomNavTranslation(float translationY) {
495+
if (navView == null)
496+
return;
497+
navView.setTranslationY(translationY);
498+
if (translationY >= navView.getHeight()) {
499+
navView.setVisibility(View.GONE);
500+
} else {
501+
navView.setVisibility(View.VISIBLE);
502+
}
503+
}
498504
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
package com.codetrio.spatialflow.model;
2+
3+
import android.net.Uri;
4+
5+
/**
6+
* Data class representing a song in the library.
7+
* Used for the song list in PlayerFragment.
8+
*/
9+
public class SongItem {
10+
public final long id;
11+
public final String title;
12+
public final String artist;
13+
public final long albumId;
14+
public final String path;
15+
public final long dateAdded;
16+
public final Uri contentUri;
17+
18+
public SongItem(long id, String title, String artist, long albumId, String path, long dateAdded) {
19+
this.id = id;
20+
this.title = title != null ? title : "Unknown Title";
21+
this.artist = artist != null ? artist : "Unknown Artist";
22+
this.albumId = albumId;
23+
this.path = path;
24+
this.dateAdded = dateAdded;
25+
this.contentUri = Uri.parse("content://media/external/audio/media/" + id);
26+
}
27+
28+
/**
29+
* Get album art URI for this song.
30+
*/
31+
public Uri getAlbumArtUri() {
32+
if (albumId <= 0)
33+
return null;
34+
return Uri.parse("content://media/external/audio/albumart/" + albumId);
35+
}
36+
37+
/**
38+
* Compare titles for A-Z sorting (case insensitive).
39+
*/
40+
public int compareByTitle(SongItem other) {
41+
return this.title.compareToIgnoreCase(other.title);
42+
}
43+
44+
@Override
45+
public boolean equals(Object o) {
46+
if (this == o)
47+
return true;
48+
if (o == null || getClass() != o.getClass())
49+
return false;
50+
SongItem songItem = (SongItem) o;
51+
return id == songItem.id;
52+
}
53+
54+
@Override
55+
public int hashCode() {
56+
return Long.hashCode(id);
57+
}
58+
}

0 commit comments

Comments
 (0)