Skip to content

Commit 7260bec

Browse files
committed
Release version 1.3
1 parent 8536410 commit 7260bec

14 files changed

Lines changed: 414 additions & 136 deletions

File tree

.idea/misc.xml

Lines changed: 0 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

app/src/main/AndroidManifest.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK" />
1111
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
1212
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="28"/>
13-
13+
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>
1414

1515
<application
1616
android:name=".SpatialFlowApplication"

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

Lines changed: 41 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,23 @@
11
package com.codetrio.spatialflow;
22

3+
import android.Manifest;
4+
import android.content.pm.PackageManager;
35
import android.content.res.ColorStateList;
46
import android.content.res.Configuration;
57
import android.os.Build;
68
import android.os.Bundle;
7-
import android.util.Log;
89
import android.view.ViewGroup;
910
import android.view.Window;
10-
import android.widget.Toast;
1111

1212
import androidx.annotation.NonNull;
1313
import androidx.appcompat.app.AppCompatActivity;
14+
import androidx.core.app.ActivityCompat;
1415
import androidx.core.content.ContextCompat;
1516
import androidx.core.graphics.Insets;
1617
import androidx.core.view.ViewCompat;
1718
import androidx.core.view.WindowCompat;
1819
import androidx.core.view.WindowInsetsCompat;
1920
import androidx.core.view.WindowInsetsControllerCompat;
20-
import androidx.recyclerview.widget.RecyclerView;
2121
import androidx.navigation.NavController;
2222
import androidx.navigation.NavDestination;
2323
import androidx.navigation.NavOptions;
@@ -30,41 +30,40 @@
3030
public class MainActivity extends AppCompatActivity {
3131

3232
private static final String TAG = "MainActivity";
33+
private static final int AUDIO_PERMISSION_REQUEST = 100;
34+
3335
private BottomNavigationView navView;
3436
private NavController navController;
3537
private int previousDestination = R.id.navigation_player; // default
3638

3739
@Override
3840
protected void onCreate(Bundle savedInstanceState) {
39-
// ⭐ ENABLE DYNAMIC COLORS FIRST - This is the key!
41+
// Enable dynamic colors
4042
DynamicColors.applyToActivityIfAvailable(this);
4143

4244
super.onCreate(savedInstanceState);
4345

4446
setupSystemBars();
4547
setContentView(R.layout.activity_main);
4648

49+
// Check audio/media permissions for MediaStore song list
50+
checkAudioPermission();
51+
4752
navView = findViewById(R.id.nav_view);
4853
navController = Navigation.findNavController(this, R.id.nav_host_fragment_activity_main);
4954

50-
// apply insets so navView doesn't overlap app content and top area is safe
5155
applyWindowInsetsBehavior();
52-
53-
// color the bottom nav icons/text according to theme - NOW USING DYNAMIC COLORS
5456
setupBottomNavColors(navView);
5557

56-
// wire up Navigation component
5758
NavigationUI.setupWithNavController(navView, navController);
5859

59-
// override selection to provide custom backstack behavior + animated transitions
6060
navView.setOnItemSelectedListener(item -> {
6161
int destId = item.getItemId();
6262
NavDestination current = navController.getCurrentDestination();
6363
if (current != null && current.getId() == destId) return true;
6464

6565
NavOptions navOptions = getNavOptions(previousDestination, destId);
6666

67-
// Pop to start destination, then navigate so each tab behaves like top-level
6867
navController.popBackStack(navController.getGraph().getStartDestinationId(), false);
6968
navController.navigate(destId, null, navOptions);
7069

@@ -76,89 +75,90 @@ protected void onCreate(Bundle savedInstanceState) {
7675
// optional: scroll to top or refresh
7776
});
7877

79-
// ensure initial selected item
8078
if (savedInstanceState == null) {
8179
navController.navigate(R.id.navigation_player);
8280
navView.setSelectedItemId(R.id.navigation_player);
8381
}
82+
}
8483

85-
// (Optional) start background service if your app requires it (uncomment if needed)
86-
// startYourService();
84+
private void checkAudioPermission() {
85+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
86+
if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_MEDIA_AUDIO)
87+
!= PackageManager.PERMISSION_GRANTED) {
88+
ActivityCompat.requestPermissions(
89+
this,
90+
new String[]{Manifest.permission.READ_MEDIA_AUDIO},
91+
AUDIO_PERMISSION_REQUEST
92+
);
93+
}
94+
} else {
95+
if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE)
96+
!= PackageManager.PERMISSION_GRANTED) {
97+
ActivityCompat.requestPermissions(
98+
this,
99+
new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},
100+
AUDIO_PERMISSION_REQUEST
101+
);
102+
}
103+
}
87104
}
88105

89106
private void applyWindowInsetsBehavior() {
90107
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.container), (v, insets) -> {
91108
Insets sys = insets.getInsets(WindowInsetsCompat.Type.systemBars());
92-
93-
// add top padding if you want content below status bar (optional)
94109
v.setPadding(v.getPaddingLeft(), sys.top, v.getPaddingRight(), v.getPaddingBottom());
95110
return insets;
96111
});
97112

98-
// apply bottom navigation margin equal to nav bar inset so it sits above system nav
99113
ViewCompat.setOnApplyWindowInsetsListener(navView, (v, insets) -> {
100114
Insets sys = insets.getInsets(WindowInsetsCompat.Type.systemBars());
101115

102116
ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) v.getLayoutParams();
103117
params.bottomMargin = sys.bottom;
104118
v.setLayoutParams(params);
105-
106-
// ensure bottom nav is above content visually
107119
v.bringToFront();
108120
return insets;
109121
});
110122

111-
// ALSO pad inner NavHostFragment's RecyclerView if it exists (not always necessary, but safe)
112-
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.nav_host_fragment_activity_main), (v, insets) -> {
113-
Insets sys = insets.getInsets(WindowInsetsCompat.Type.systemBars());
114-
// find inner recycler view if needed later (fragments may host it)
115-
return insets;
116-
});
123+
ViewCompat.setOnApplyWindowInsetsListener(
124+
findViewById(R.id.nav_host_fragment_activity_main),
125+
(v, insets) -> insets
126+
);
117127

118-
// trigger insets dispatch
119128
findViewById(R.id.container).requestApplyInsets();
120129
}
121130

122131
private void setupBottomNavColors(BottomNavigationView navView) {
123-
// ⭐ USE THEME ATTRIBUTES INSTEAD OF HARDCODED COLORS
124-
// This allows dynamic colors to work properly
125-
126-
// Get colors from the current theme (which has dynamic colors applied)
127132
android.util.TypedValue typedValue = new android.util.TypedValue();
128133
android.content.res.Resources.Theme theme = getTheme();
129134

130-
// Get active color (selected state) - use onSecondaryContainer for better contrast
131135
theme.resolveAttribute(com.google.android.material.R.attr.colorOnSecondaryContainer, typedValue, true);
132136
int activeColor = typedValue.data;
133137

134-
// Get inactive color (unselected state)
135138
theme.resolveAttribute(com.google.android.material.R.attr.colorOnSurfaceVariant, typedValue, true);
136139
int inactiveColor = typedValue.data;
137140

138-
// Get background color
139141
theme.resolveAttribute(com.google.android.material.R.attr.colorSurfaceContainer, typedValue, true);
140142
int backgroundColor = typedValue.data;
141143

142-
// ---- Create ColorStateList for icons ----
143144
ColorStateList iconColorStateList = new ColorStateList(
144145
new int[][]{
145-
new int[]{android.R.attr.state_checked}, // selected
146-
new int[]{-android.R.attr.state_checked} // unselected
146+
new int[]{android.R.attr.state_checked},
147+
new int[]{-android.R.attr.state_checked}
147148
},
148149
new int[]{
149150
activeColor,
150151
inactiveColor
151152
}
152153
);
153154

154-
// ---- Create ColorStateList for text (uses onSurface for better visibility) ----
155155
theme.resolveAttribute(com.google.android.material.R.attr.colorOnSurface, typedValue, true);
156156
int activeTextColor = typedValue.data;
157157

158158
ColorStateList textColorStateList = new ColorStateList(
159159
new int[][]{
160-
new int[]{android.R.attr.state_checked}, // selected
161-
new int[]{-android.R.attr.state_checked} // unselected
160+
new int[]{android.R.attr.state_checked},
161+
new int[]{-android.R.attr.state_checked}
162162
},
163163
new int[]{
164164
activeTextColor,
@@ -168,11 +168,7 @@ private void setupBottomNavColors(BottomNavigationView navView) {
168168

169169
navView.setItemIconTintList(iconColorStateList);
170170
navView.setItemTextColor(textColorStateList);
171-
172-
// ---- BACKGROUND COLOR (uses Material3 dynamic color) ----
173171
navView.setBackgroundColor(backgroundColor);
174-
175-
// ---- Material3 icon size ----
176172
navView.setItemIconSize((int) (28 * getResources().getDisplayMetrics().density));
177173
}
178174

@@ -184,9 +180,9 @@ private void setupSystemBars() {
184180

185181
WindowCompat.setDecorFitsSystemWindows(window, false);
186182

187-
WindowInsetsControllerCompat insetsController = WindowCompat.getInsetsController(window, window.getDecorView());
183+
WindowInsetsControllerCompat insetsController =
184+
WindowCompat.getInsetsController(window, window.getDecorView());
188185

189-
// make status/nav bar transparent so app draws behind them (we handle padding)
190186
window.setStatusBarColor(android.graphics.Color.TRANSPARENT);
191187
window.setNavigationBarColor(android.graphics.Color.TRANSPARENT);
192188

@@ -228,4 +224,4 @@ private int getDestinationIndex(int id) {
228224
public boolean onSupportNavigateUp() {
229225
return navController.navigateUp() || super.onSupportNavigateUp();
230226
}
231-
}
227+
}

app/src/main/java/com/codetrio/spatialflow/service/AudioPlaybackService.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -864,4 +864,3 @@ public void onDestroy() {
864864
}
865865
}
866866

867-

0 commit comments

Comments
 (0)