Skip to content

Commit 063299e

Browse files
committed
• Player UI design improved
• Now player will try to fix content correctly in split screen mode
1 parent b901984 commit 063299e

19 files changed

Lines changed: 1322 additions & 892 deletions

README.md

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11

2-
# 🎵 XMusic
2+
# XMusic
33

44
##### A Material 3 Expressive Music player for Android built with pure Java
55

@@ -10,7 +10,7 @@
1010

1111
---
1212

13-
## Features (Detailed)
13+
## Features (Detailed)
1414
---
1515
### Core Playback
1616

@@ -66,7 +66,7 @@
6666
- [ ] Finish settings screen
6767
- [ ] Add more features to the now Playing UI
6868
- [ ] Add a contextual menu for songs
69-
- [ ] Make a functional search fragment
69+
- [x] Make a functional search fragment
7070
- [ ] Idk
7171
---
7272

@@ -78,23 +78,23 @@
7878

7979
---
8080

81-
## ⬇️ Download the app
81+
## Download the app
8282
- You can get Latest XMusic build via [GitHub Actions](https://github.com/Yamenher/XMusic/actions) or via the [dedicated topic](https://t.me/XMusicCommunity/4) in our telegram community.
8383

8484
---
8585

86-
## 📱 Minimum Requirements
86+
## Minimum Requirements
8787

8888
- Android 8.0 (API 26) or higher
8989
- Local audio files stored on device
9090
- A brain (for reporting bugs)
9191
---
9292

93-
## ⚠️ Important Notice
93+
## Important Notice
9494
- The app is still WIP (Work In Progress) and is far away from a stable release, that's why you might notice a lot of bugs, missing features, and some instability problems, but **Don't worry,** everything will worked on in the near future.
9595
---
9696

97-
## 🐛 Report bugs
97+
## Report bugs
9898
If you run into bugs, crashes, or weird behavior that clearly wasn’t supposed to happen (looking at you, OEMs) :
9999

100100
- **GitHub Issues**
@@ -110,7 +110,7 @@ Note : “App broken” is not a bug report.
110110

111111
---
112112

113-
## Q&A
113+
## Q & A
114114

115115
**Q: Is XMusic free?**
116116
A: Yes. Completely free. No ads, no subscriptions, no hidden nonsense.
@@ -140,20 +140,20 @@ A: If you think this feature will be useful for a lot of people, feel free to su
140140
A: You can tell.
141141

142142
---
143-
## 🤝 Credits & Special Thanks
143+
## Credits & Special Thanks
144144
* [Nick](https://github.com/nift4) For the precious advices and help he provided for me when I needed help.
145145
* **Oto music, PixelPlayer and Gramophone Devs** - For the UI inspiration and feedback.
146146
* **All Testers, Especially [MACİT ELCİBİN](https://t.me/Macitelc)** for testing new builds, trying out buggy features, and reporting every single bug and helping me *break* the app to improve it :P
147147
* **All Contributors** - For helping make XMusic better for everyone.
148148

149149
---
150150

151-
## 📜 License
151+
## License
152152
Distributed under the **GNU General Public License v3.0**. See [LICENSE](https://github.com/Yamenher/XMusic/blob/main/LICENSE) for more information.
153153

154154
---
155155

156-
## ✉️ Contact
156+
## Contact
157157

158158
For inquiries or support, reach out at:
159159
hermassiyamen@gmail.com

app/src/main/java/com/xapps/media/xmusic/activity/RootActivity.java

Lines changed: 30 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,52 +1,58 @@
11
package com.xapps.media.xmusic.activity;
22

3+
import android.content.res.Configuration;
34
import android.os.*;
5+
6+
import androidx.annotation.NonNull;
47
import androidx.appcompat.app.AppCompatActivity;
58
import androidx.media3.session.MediaController;
69
import androidx.media3.session.SessionToken;
10+
711
import com.xapps.media.xmusic.activity.manager.LogicManager;
812
import com.xapps.media.xmusic.activity.manager.UIManager;
913
import com.xapps.media.xmusic.callback.ActivityCallback;
1014
import com.xapps.media.xmusic.callback.CallbackInterface;
1115
import com.xapps.media.xmusic.databinding.ActivityRootBinding;
1216
import com.xapps.media.xmusic.models.Song;
1317
import com.xapps.media.xmusic.utils.MaterialColorUtils;
18+
1419
import java.util.ArrayList;
1520

1621
public class RootActivity extends BaseActivity implements ActivityCallback {
1722
private ActivityRootBinding binding;
1823
private UIManager uiManager;
1924
private LogicManager logicManager;
2025
private MediaController mediaController;
21-
26+
2227
@Override
2328
protected void onCreate(Bundle savedInstanceState) {
2429
super.onCreate(savedInstanceState);
2530
binding = ActivityRootBinding.inflate(getLayoutInflater());
2631
setContentView(binding.getRoot());
2732
init();
2833
}
29-
30-
@Override
34+
35+
@Override
3136
public void onStart() {
3237
super.onStart();
3338
CallbackInterface.setActivityCallback(this);
34-
logicManager.initController(this, controller -> {
35-
mediaController = controller;
36-
//progressDrawable.setAnimate(controller.isPlaying());
37-
//setupControllerListener();
38-
},
39-
e -> showInfoDialog("Error", 0, e.toString(), "OK", binding.Coordinator),
40-
this::restoreStateIfPossible
41-
);
39+
logicManager.initController(
40+
this,
41+
controller -> {
42+
mediaController = controller;
43+
// progressDrawable.setAnimate(controller.isPlaying());
44+
// setupControllerListener();
45+
},
46+
e -> showInfoDialog("Error", 0, e.toString(), "OK", binding.Coordinator),
47+
this::restoreStateIfPossible);
4248
}
43-
49+
4450
@Override
4551
public void onDestroy() {
4652
super.onDestroy();
4753
CallbackInterface.clearActivityCallback(this);
4854
mediaController.release();
49-
mediaController = null;
55+
mediaController = null;
5056
}
5157

5258
private void init() {
@@ -64,7 +70,7 @@ public void setSong(int position) {
6470
logicManager.playSong(position);
6571
uiManager.hideComponents(false, uiManager.bnvHidden, uiManager.tabsHidden);
6672
}
67-
73+
6874
@Override
6975
public void onPlaybackStateChanged(boolean isPlaying) {
7076
logicManager.updateVumeters(isPlaying);
@@ -78,24 +84,22 @@ public void updateSongsQueue(ArrayList<Song> songs) {
7884
if (CallbackInterface.service() != null) CallbackInterface.service().updateSongs();
7985
}
8086

81-
public void restoreStateIfPossible() {
82-
83-
}
87+
public void restoreStateIfPossible() {}
88+
89+
public void loadSettings() {}
8490

85-
public void loadSettings() {
86-
87-
}
88-
8991
@Override
9092
public void onColorsChanged() {
9193
runOnUiThread(() -> uiManager.updateColors());
9294
}
9395

94-
@Override
95-
public void onSongChanged() {
96-
runOnUiThread(() -> {
97-
uiManager.updateContent(false);
98-
});
96+
@Override
97+
public void onSongChanged(int position) {
98+
runOnUiThread(
99+
() -> {
100+
uiManager.updateContent(position, false);
101+
});
102+
if (CallbackInterface.mlFrag() != null) CallbackInterface.mlFrag().updateActiveItem(position);
99103
}
100104

101105
@Override

app/src/main/java/com/xapps/media/xmusic/activity/controller/ActivityMediaController.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ public void onMediaItemTransition(@Nullable MediaItem mediaItem, int reason) {
111111

112112
@Override
113113
public void onPositionDiscontinuity(Player.PositionInfo positionInfo, Player.PositionInfo positionInfo2, int i) {
114-
//activity.updateProgress(controller.getCurrentPosition());
114+
activity.onProgressChanged(controller.getCurrentPosition());
115115
}
116116

117117
@Override

app/src/main/java/com/xapps/media/xmusic/activity/manager/LogicManager.java

Lines changed: 59 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
package com.xapps.media.xmusic.activity.manager;
22

3+
import android.os.*;
34
import android.content.ComponentName;
5+
import android.widget.*;
6+
import android.view.*;
47

58
import androidx.fragment.app.FragmentActivity;
69
import androidx.media3.common.MediaItem;
@@ -28,9 +31,8 @@ public class LogicManager {
2831
private MediaController mediaController;
2932
private SessionToken sessionToken;
3033
private ActivityMediaController controller;
31-
32-
private boolean test1 = false;
33-
private boolean test2 = true;
34+
35+
private boolean isUserSeeking;
3436

3537
public LogicManager(RootActivity activity, UIManager uiManager) {
3638
this.activity = activity;
@@ -44,47 +46,60 @@ public void initLogic() {
4446
}
4547

4648
private void setupListeners() {
47-
binding.bottomButton.setOnClickListener(
48-
v -> {
49-
if (test1) {
50-
if (test2) {
51-
uiManager.setLayoutState(UIManager.LAYOUT_STATE_EXPOSE_TABS_BNV);
52-
} else {
53-
uiManager.setLayoutState(UIManager.LAYOUT_STATE_FULL);
54-
}
55-
test1 = false;
56-
binding.bottomButton.setText("Show Player");
57-
} else {
58-
if (test2) {
59-
uiManager.setLayoutState(UIManager.LAYOUT_STATE_EXPOSE_FULL);
60-
} else {
61-
uiManager.setLayoutState(UIManager.LAYOUT_STATE_EXPOSE_PLAYER_ONLY);
62-
}
63-
test1 = true;
64-
binding.bottomButton.setText("Hide Player");
49+
binding.collapsedPlayer.cover.addOnLayoutChangeListener(
50+
(v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> {
51+
if (left != oldLeft
52+
|| top != oldTop
53+
|| right != oldRight
54+
|| bottom != oldBottom) {
55+
56+
binding.collapsedPlayer.cover.captureCollapsedBounds();
6557
}
6658
});
6759

68-
binding.topButton.setOnClickListener(
69-
v -> {
70-
if (test2) {
71-
if (test1) {
72-
uiManager.setLayoutState(UIManager.LAYOUT_STATE_EXPOSE_PLAYER_ONLY);
73-
} else {
74-
uiManager.setLayoutState(UIManager.LAYOUT_STATE_FULL);
75-
}
76-
test2 = false;
77-
binding.topButton.setText("Expand Card");
78-
} else {
79-
if (test1) {
80-
uiManager.setLayoutState(UIManager.LAYOUT_STATE_EXPOSE_FULL);
81-
} else {
82-
uiManager.setLayoutState(UIManager.LAYOUT_STATE_EXPOSE_TABS_BNV);
83-
}
84-
test2 = true;
85-
binding.topButton.setText("Collapse Card");
60+
binding.maximumSizeView.addOnLayoutChangeListener(
61+
(v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> {
62+
if (left != oldLeft
63+
|| top != oldTop
64+
|| right != oldRight
65+
|| bottom != oldBottom) {
66+
67+
int size = binding.maximumSizeView.getMaximumSize();
68+
69+
View v2 = binding.maximumSizeView;
70+
int leftNow = v2.getLeft();
71+
int topNow = v2.getTop();
72+
int x = leftNow + (v2.getWidth() - size) / 2;
73+
74+
binding.collapsedPlayer.cover.setExpandedBounds(x, topNow, x + size, topNow + size);
75+
76+
binding.collapsedPlayer.cover.setExpansionProgress(Math.max(0f, binding.miniPlayer.getSlideOffset()));
8677
}
8778
});
79+
80+
binding.expandedPlayer.songSeekbar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
81+
@Override
82+
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
83+
binding.expandedPlayer.currentDurationText.setText(XUtils.millisecondsToDuration(seekBar.getProgress()));
84+
}
85+
86+
@Override
87+
public void onStartTrackingTouch(SeekBar seekBar) {
88+
isUserSeeking = true;
89+
}
90+
91+
@Override
92+
public void onStopTrackingTouch(SeekBar seekBar) {
93+
new Handler(Looper.getMainLooper()).postDelayed(() -> {
94+
isUserSeeking = false;
95+
}, 100);
96+
mediaController.seekTo(seekBar.getProgress());
97+
}
98+
});
99+
100+
// ----- THIS PREVENTS SEEKBAR FROM STEALING FOCUS IN PLAYER SHEET
101+
102+
binding.expandedPlayer.songSeekbar.setOnClickListener(v -> {});
88103
}
89104

90105
private void setupCallbacks() {
@@ -108,7 +123,9 @@ public void onStateChanged(int state) {
108123
@Override
109124
public void onSlide(float offset) {
110125
binding.layoutScrim.setAlpha(Math.max(0f, offset) * 0.7f);
126+
uiManager.updateTopProgress(Math.max(0f, offset));
111127
updateImageSize(offset);
128+
binding.collapsedPlayer.cover.setExpansionProgress(Math.max(0f, offset));
112129
}
113130
});
114131
}
@@ -152,6 +169,7 @@ public void playSong(int position) {
152169
mediaController.seekTo(position, 0);
153170
mediaController.play();
154171
}
172+
CallbackInterface.service().regenColors(position);
155173
binding.expandedPlayer.toggleView.forcePlayState();
156174
}
157175

@@ -183,7 +201,7 @@ public void updateVumeters(boolean isPlaying) {
183201
private void updateImageSize(float offset) {
184202
float clampedOffset = Math.max(0f, offset);
185203
// binding.collapsedPlayer.motionRoot.setAlpha(Math.max(0f, 1f - clampedOffset));
186-
binding.collapsedPlayer.motionRoot.setProgress(clampedOffset);
204+
// binding.collapsedPlayer.motionRoot.setProgress(clampedOffset);
187205
}
188206

189207
public void handleProgress(long progress) {
@@ -193,7 +211,6 @@ public void handleProgress(long progress) {
193211

194212
public void updateProgress(long position) {
195213
binding.collapsedPlayer.musicProgress.setProgressCompat((int) position, true);
196-
binding.expandedPlayer.songSeekbar.setProgress((int) position, false);
197-
binding.expandedPlayer.currentDurationText.setText(XUtils.millisecondsToDuration(position));
214+
if (!isUserSeeking) binding.expandedPlayer.songSeekbar.setProgress((int) position, false);
198215
}
199216
}

0 commit comments

Comments
 (0)