Skip to content

Commit 17a1c5e

Browse files
committed
merge origin/main into main
2 parents a16ddf3 + 36d2645 commit 17a1c5e

12 files changed

Lines changed: 1236 additions & 293 deletions

File tree

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -127,13 +127,13 @@ A: Make sure storage permissions are granted and your audio files are in support
127127
**Q: Does XMusic collect any personal data?**
128128
A: No. There is no tracking, analytics abuse, or data harvesting.
129129

130-
**Q: Why did playback stop in the background?**
130+
**Q: Why did playback stop in the background?**
131131
A: Your system’s battery optimization or OEM “power saving” probably killed it. Disable optimizations for XMusic.
132132

133133
**Q: Can I request features or report bugs?**
134134
A: Yes. Use GitHub Issues for bugs and feature requests, or join the Telegram community for discussion.
135135

136-
**Q: Why is feature X not available?**
136+
**Q: Why is feature X not available?**
137137
A: If you think this feature will be useful for a lot of people, feel free to suggest it via reaching to our [Telegram Community](https://t.me/xmusiccommunity)
138138

139139
**Q: Is XMusic open source?**

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

Lines changed: 21 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,13 @@
88
import android.media.MediaMetadataRetriever;
99
import android.net.Uri;
1010
import android.os.*;
11-
import android.util.*;
1211
import android.view.*;
1312
import android.view.animation.*;
1413
import android.widget.*;
1514
import androidx.activity.*;
1615
import androidx.activity.OnBackPressedCallback;
1716
import androidx.annotation.*;
1817
import androidx.appcompat.app.AppCompatActivity;
19-
import androidx.core.content.ContextCompat;
2018
import androidx.core.view.*;
2119
import androidx.fragment.app.Fragment;
2220
import androidx.lifecycle.ViewModelProvider;
@@ -34,7 +32,6 @@
3432
import com.google.android.material.search.SearchView;
3533
import com.google.android.material.transition.MaterialFadeThrough;
3634
import com.google.common.util.concurrent.ListenableFuture;
37-
import com.google.common.util.concurrent.MoreExecutors;
3835
import com.xapps.media.xmusic.R;
3936
import com.xapps.media.xmusic.activity.controller.ActivityMediaController;
4037
import com.xapps.media.xmusic.activity.manager.BottomSheetBehaviorManager;
@@ -116,34 +113,34 @@ protected void onSaveInstanceState(@NonNull Bundle outState) {
116113
super.onSaveInstanceState(outState);
117114
}
118115

119-
@Override
116+
@Override
120117
protected void onCreate(Bundle bundle) {
121118
isCreated = true;
122119
EdgeToEdge.enable(this);
123120
if (Build.VERSION.SDK_INT >= 29) getWindow().setNavigationBarContrastEnforced(false);
124121
XUtils.updateTheme();
125122
XUtils.applyDynamicColors(this, DataManager.isOledThemeEnabled());
126123
if (XUtils.isDarkMode(this) && DataManager.isOledThemeEnabled())getTheme().applyStyle(R.style.ThemeOverlay_XMusic_OLED, true);
127-
super.onCreate(bundle);
128-
binding = ActivityMainBinding.inflate(getLayoutInflater());
124+
super.onCreate(bundle);
125+
binding = ActivityMainBinding.inflate(getLayoutInflater());
129126
setContentView(binding.getRoot());
130127
int resourceId = context.getResources().getIdentifier("navigation_bar_height", "dimen", "android");
131128
int resourceId2 = context.getResources().getIdentifier("status_bar_height", "dimen", "android");
132129
if (resourceId > 0 && resourceId2 > 0) {
133130
statusBarHeight = context.getResources().getDimensionPixelSize(resourceId2);
134131
navBarHeight = context.getResources().getDimensionPixelSize(resourceId);
135132
}
136-
loadSongs();
137-
initialize();
133+
loadSongs();
134+
initialize();
138135
}
139136

140-
@Override
137+
@Override
141138
protected void onResume() {
142139
CallbackInterface.setActivityCallback(this);
143140
binding.currentSongTitle.resetMarquee();
144141
binding.currentSongArtist.resetMarquee();
145142
binding.artistBigTitle.resetMarquee();
146-
binding.songBigTitle.resetMarquee();
143+
binding.songBigTitle.resetMarquee();
147144
super.onResume();
148145
isResuming = true;
149146
if (mediaController != null) {
@@ -162,10 +159,10 @@ protected void onResume() {
162159
isResuming = false;
163160
}
164161

165-
@Override
162+
@Override
166163
public void onPause() {
167-
CallbackInterface.clearActivityCallback(this);
168-
super.onPause();
164+
CallbackInterface.clearActivityCallback(this);
165+
super.onPause();
169166
}
170167

171168
@Override
@@ -234,7 +231,7 @@ private void initialize() {
234231
Looper looper = handlerThread.getLooper();
235232
backgroundHandler = new Handler(looper);
236233
MaterialColorUtils.initColors(this);
237-
setupUI();
234+
setupUI();
238235
setupListeners();
239236
setupCallbacks();
240237
bsbManager = new BottomSheetBehaviorManager(this);
@@ -252,12 +249,12 @@ private void setupUI() {
252249
progressDrawable.setTransitionEnabled(true);
253250
progressDrawable.setAnimate(true);
254251
progressDrawable.setTint(MaterialColorUtils.colorPrimary);
255-
binding.songSeekbar.setProgressDrawable(progressDrawable);
252+
binding.songSeekbar.setProgressDrawable(progressDrawable);
256253
bottomSheetColor = MaterialColorUtils.colorSurfaceContainer;
257254
binding.extendableLayout.setPadding(0, 0, 0, navBarHeight);
258255
XUtils.setMargins(binding.coversPager, 0, XUtils.getStatusBarHeight(this)*5, 0, 0);
259256
bsbHeight = binding.expressiveBottomSheet.getPeekHeight();
260-
loadSettings();
257+
loadSettings();
261258
}
262259

263260
public void setSong(int position, boolean ignored) {
@@ -491,17 +488,17 @@ private void restoreStateIfPossible() {
491488
}
492489

493490
private void setupListeners() {
494-
binding.toggleView.setExtraOnClickListener(new View.OnClickListener() {
495-
@Override
496-
public void onClick(View _view) {
491+
binding.toggleView.setExtraOnClickListener(new View.OnClickListener() {
492+
@Override
493+
public void onClick(View _view) {
497494
if (!binding.toggleView.isAnimating()) {
498495
mediaController.pause();
499-
progressDrawable.setAnimate(false);
496+
progressDrawable.setAnimate(false);
500497
} else {
501498
mediaController.play();
502-
progressDrawable.setAnimate(true);
503-
}
504-
}
499+
progressDrawable.setAnimate(true);
500+
}
501+
}
505502
});
506503

507504
binding.miniPlayerBottomSheet.setOnClickListener(v -> {
@@ -1255,7 +1252,7 @@ public void loadLyrics(String path) {
12551252
if (lyrics != null && !lyrics.isEmpty()) {
12561253
LyricsParser.parse(lyrics, result -> {
12571254
binding.xlyricsView.post(() -> {
1258-
binding.xlyricsView.setLyrics(result.lines);
1255+
binding.xlyricsView.setLyrics(result.lines());
12591256
binding.xlyricsView.setListener(MainActivity.this);
12601257

12611258
MaterialFadeThrough mft = new MaterialFadeThrough();
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
package com.xapps.media.xmusic.fragment;
2+
3+
import com.xapps.media.xmusic.activity.RootActivity;
4+
import com.xapps.media.xmusic.common.SettingsItem;
5+
import com.xapps.media.xmusic.data.DataManager;
6+
import com.xapps.media.xmusic.utils.XUtils;
7+
8+
import java.util.ArrayList;
9+
import java.util.List;
10+
11+
public class LyricsCustomizeFragment extends BasePrefsFragment {
12+
private RootActivity activity;
13+
14+
@Override
15+
protected List<SettingsItem> provideItems() {
16+
activity = (RootActivity) getActivity();
17+
List<SettingsItem> settings = new ArrayList<>();
18+
19+
settings.add(new SettingsItem(SettingsItem.TYPE_HEADER, "h1", "Lyrics font", "", null));
20+
settings.add(new SettingsItem(SettingsItem.TYPE_NAV, "font_size", "Font size", "Choose how big lyrics text should be", null));
21+
settings.add(new SettingsItem(SettingsItem.TYPE_SWITCH, "use_system_font", "Use System font", "Whether to use the app's font or the system's for rendering lyrics", null));
22+
settings.add(new SettingsItem(SettingsItem.TYPE_NAV, "font_weight", "Font weight", "Choose the font weight that suits you", null));
23+
settings.add(new SettingsItem(SettingsItem.TYPE_SWITCH, "rounded_font", "Round lyrics letters", "Make the lyrics letters' edges round", null));
24+
settings.add(new SettingsItem(SettingsItem.TYPE_HEADER, "h2", "Lyrics Appearance", "", null));
25+
settings.add(new SettingsItem(SettingsItem.TYPE_SWITCH, "lyrics_gradient_background", "Enable lyrics gradient", "Display a beautiful gradient background behind the lyrics, might impact performance", null));
26+
settings.add(new SettingsItem(SettingsItem.TYPE_SWITCH, "lyrics_blur", "Blur Lyrics", "Apply a blur effect for inactive lyrics lines, might impact performance", null));
27+
settings.add(new SettingsItem(SettingsItem.TYPE_SWITCH, "lyrics_sparkles", "Enable Lyrics Sparkles", "Apply a Sparkling effect to the lyrics while being sung", null));
28+
settings.add(new SettingsItem(SettingsItem.TYPE_HEADER, "h3", "Lyrics Behavior", "", null));
29+
settings.add(new SettingsItem(SettingsItem.TYPE_SWITCH, "lyrics_anticipation", "Enable lyrics anticipation", "Lyrics will always go to next line before it's sung", null));
30+
settings.add(new SettingsItem(SettingsItem.TYPE_SWITCH, "lyrics_elastic_scroll", "Enable Staggered Scrolling", "Make the lyrics lines scroll in a delayed way for better immersion", null));
31+
settings.add(new SettingsItem(SettingsItem.TYPE_SWITCH, "lyrics_elastic_manual_scroll", "Staggered manual scrolling", "Apply the staggered scroll effect to user manual scrolling, might feel weird", null));
32+
33+
return settings;
34+
}
35+
36+
@Override
37+
public String getFragmentTitle() {
38+
return "Customize Lyrics";
39+
}
40+
41+
@Override
42+
protected void onItemSelected(SettingsItem item) {
43+
switch (item.id) {
44+
default -> {
45+
XUtils.showMessage(getActivity(), "Feature to be added soon");
46+
}
47+
}
48+
}
49+
50+
@Override
51+
protected void onSwitchChanged(SettingsItem item, boolean value) {
52+
super.onSwitchChanged(item, value);
53+
switch (item.id) {
54+
case "lyrics_elastic_scroll", "lyrics_elastic_manual_scroll", "lyrics_sparkles" -> {
55+
activity.updateLyrics();
56+
}
57+
default -> {
58+
XUtils.showMessage(getActivity(), "Feature to be added soon");
59+
}
60+
}
61+
}
62+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package com.xapps.media.xmusic.models;
2+
3+
public class LyricItem {
4+
public LyricLine mainLine;
5+
public int mainIndex;
6+
public LyricLine romajiLine;
7+
public int romajiIndex = -1;
8+
public LyricLine linkedBgLine;
9+
public int linkedBgIndex = -1;
10+
11+
public LyricItem(LyricLine main, int idx) {
12+
this.mainLine = main;
13+
this.mainIndex = idx;
14+
}
15+
}

app/src/main/java/com/xapps/media/xmusic/utils/ColorPaletteUtils.java

Lines changed: 11 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
package com.xapps.media.xmusic.utils;
22

3+
import android.annotation.SuppressLint;
34
import android.graphics.Bitmap;
45

56
import com.google.android.material.color.utilities.Hct;
67
import com.google.android.material.color.utilities.QuantizerCelebi;
78
import com.google.android.material.color.utilities.Score;
8-
import com.google.android.material.color.utilities.Scheme;
99

1010
import java.util.HashMap;
1111
import java.util.List;
@@ -52,14 +52,14 @@ public static void generateFromBitmap(Bitmap bitmap, ResultCallback callback) {
5252
0, 0, scaled.getWidth(), scaled.getHeight()
5353
);
5454

55-
Map<Integer, Integer> colorMap =
55+
@SuppressLint("RestrictedApi") Map<Integer, Integer> colorMap =
5656
QuantizerCelebi.quantize(pixels, 16);
5757

58-
List<Integer> ranked =
58+
@SuppressLint("RestrictedApi") List<Integer> ranked =
5959
Score.score(colorMap, 0, 1, false);
6060

6161
int seedColor = ranked.isEmpty() ? 0xFF6750A4 : ranked.get(0);
62-
Hct seed = Hct.fromInt(seedColor);
62+
@SuppressLint("RestrictedApi") Hct seed = Hct.fromInt(seedColor);
6363

6464
Map<String, Integer> newLight =
6565
generateMaterialTones(seed, false);
@@ -95,12 +95,11 @@ public static void generateFromBitmap(Bitmap bitmap, ResultCallback callback) {
9595
}
9696

9797
public static void generateFromColor(int color, ResultCallback callback) {
98-
99-
int hash = color;
100-
if (hash == lastBitmapHash && lightColors != null && darkColors != null) {
98+
99+
if (color == lastBitmapHash && lightColors != null && darkColors != null) {
101100
return;
102101
}
103-
Hct seed = Hct.fromInt(color);
102+
@SuppressLint("RestrictedApi") Hct seed = Hct.fromInt(color);
104103

105104
Map<String, Integer> newLight =
106105
generateMaterialTones(seed, false);
@@ -117,7 +116,7 @@ public static void generateFromColor(int color, ResultCallback callback) {
117116

118117
lightColors = newLight;
119118
darkColors = newDark;
120-
119+
121120
lastBitmapHash = color;
122121

123122
if (callback != null) {
@@ -140,16 +139,13 @@ private static long hashBitmap(Bitmap bitmap) {
140139
}
141140
return hash;
142141
}
143-
144-
public static long getCurrentHash() {
145-
return lastBitmapHash;
146-
}
147142

143+
@SuppressLint("RestrictedApi")
148144
private static Map<String, Integer> generateMaterialTones(Hct hct, boolean isDark) {
149145
Map<String, Integer> tones = new HashMap<>();
150146

151-
double hue = hct.getHue() % 360;
152-
double chroma = hct.getChroma();
147+
@SuppressLint("RestrictedApi") double hue = hct.getHue() % 360;
148+
@SuppressLint("RestrictedApi") double chroma = hct.getChroma();
153149
boolean lowChroma = chroma < 10;
154150

155151
tones.put("primary", Hct.from(hue, lowChroma ? chroma : 40, isDark ? 80 : 30).toInt());
@@ -172,8 +168,4 @@ private static Map<String, Integer> generateMaterialTones(Hct hct, boolean isDar
172168

173169
return tones;
174170
}
175-
176-
public static Scheme generateCustomScheme(int seedColor, boolean isDarkMode) {
177-
return isDarkMode ? Scheme.dark(seedColor) : Scheme.light(seedColor);
178-
}
179171
}

0 commit comments

Comments
 (0)