Skip to content

Commit a423028

Browse files
committed
UI/UX overhaul: improved Now Playing, queue, and theming
- Add blurred/glassy backgrounds to NowPlaying/HomePage - Redesign mini/expanded player layouts with Material components - Replace helpBtn with queueBtn; prevent multiple queue sheets - Add animated "Love" button with haptic/circular reveal - Song list: improved actions, theming, and favorite feedback - Artist picker bottom sheet for filtering/searching by artist - Lyrics and song info: horizontal image+title, better styling - Theme-aware colors for buttons, text, and backgrounds - Refactor ViewModel naming and remove unused carousel code - Update AndroidManifest and project device settings
1 parent 51f98c9 commit a423028

File tree

15 files changed

+558
-346
lines changed

15 files changed

+558
-346
lines changed

Dimmer/Dimmer.Droid/AndroidManifest.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
android:pathPrefix="/invite" /> -->
2121
</intent-filter>
2222
</activity>
23-
<activity android:name=".Activities.PlaybackBubbleActivity" android:label="Dimmer Bubble" android:allowEmbedded="true" android:resizeableActivity="true" android:documentLaunchMode="always" android:exported="false" android:taskAffinity="" android:launchMode="singleInstance" android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation" />
23+
<activity android:name=".Activities.PlaybackBubbleActivity" android:label="Dimmer Bubble" android:allowEmbedded="true" android:resizeableActivity="true" android:documentLaunchMode="always" android:exported="false" android:taskAffinity="" android:launchMode="singleInstance" android:configChanges="uiMode|screenSize|smallestScreenSize|screenLayout|orientation" />
2424
<service android:name="com.yvanbrunel.dimmer.ExoPlayerService" android:directBootAware="true" android:exported="true" android:foregroundServiceType="mediaPlayback">
2525
<intent-filter>
2626
<action android:name="android.media.browse.MediaBrowserService" />

Dimmer/Dimmer.Droid/Dimmer.Droid.csproj.user

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
<?xml version="1.0" encoding="utf-8"?>
22
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
33
<PropertyGroup>
4-
<SelectedDevice>Nothing A142</SelectedDevice>
5-
<SelectedPlatformGroup>PhysicalDevice</SelectedPlatformGroup>
6-
<ActiveDebugProfile>Nothing A142 (Android 16.0 - API 36)</ActiveDebugProfile>
7-
<DefaultDevice>pixel_7_-_api_36</DefaultDevice>
4+
<SelectedDevice>pixel_7_-_api_35</SelectedDevice>
5+
<SelectedPlatformGroup>Emulator</SelectedPlatformGroup>
6+
<ActiveDebugProfile>Pixel 7 - API 35 (Android 15.0 - API 35)</ActiveDebugProfile>
7+
<DefaultDevice>pixel_7_-_api_35</DefaultDevice>
88
</PropertyGroup>
99
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
1010
<DebuggerFlavor>ProjectDebugger</DebuggerFlavor>

Dimmer/Dimmer.Droid/Utils/Extensions/ViewExtensions.cs

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,32 @@
1-
using Point = Microsoft.Maui.Graphics.Point;
1+
using System.Threading.Tasks;
2+
using AndroidX.Lifecycle;
3+
using Bumptech.Glide;
4+
using Dimmer.Utilities;
5+
using Point = Microsoft.Maui.Graphics.Point;
26
using Rect = Microsoft.Maui.Graphics.Rect;
37

48
namespace Dimmer.Utils.Extensions;
59

610
public static class ViewExts
711
{
12+
public static void SetButtonIconColor(this MaterialButton btn, Color color)
13+
{
14+
btn.IconTint = AppUtil.ToColorStateList(color);
15+
}
16+
public static void SetImageWithGlide(this ImageView ImgView, string imgPath)
17+
{
18+
19+
Glide.With(ImgView.Context).Load(imgPath).Into(ImgView);
20+
}
21+
public static async Task SetImageWithStringPathViaGlideAndFilterEffect(this ImageView ImgView, string imgPath, FilterType desiredFilter)
22+
{
23+
var glassyImg = await ImageFilterUtils.ApplyFilter(imgPath, desiredFilter);
24+
Glide.With(ImgView.Context)
25+
.Load(glassyImg)
26+
.Into(ImgView);
27+
28+
}
29+
830
public static Rect GetAbsoluteBounds(VisualElement view, IWindow window)
931
{
1032
var location = GetAbsoluteLocation(view,window);

Dimmer/Dimmer.Droid/ViewsAndPages/NativeViews/Activity/TransitionActivity.cs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,33 @@ protected override void OnCreate(Bundle? savedInstanceState)
147147

148148
}
149149
private SmoothBottomBar _bottomBar;
150+
151+
public override void OnConfigurationChanged(Configuration newConfig)
152+
{
153+
base.OnConfigurationChanged(newConfig);
154+
RefreshBottomSheet();
155+
}
156+
157+
private void RefreshBottomSheet()
158+
{
159+
SheetBehavior.State = BottomSheetBehavior.StateHidden;
160+
161+
var frag = SupportFragmentManager.FindFragmentByTag("NowPlayingFragment");
162+
if(frag is not null)
163+
{
164+
SupportFragmentManager.BeginTransaction()
165+
.Remove(frag)
166+
.CommitNow();
167+
}
168+
169+
170+
var nowPlayingFrag = new NowPlayingFragment(MyViewModel);
171+
SupportFragmentManager
172+
.BeginTransaction()
173+
.Replace(_sheetContainer.Id, nowPlayingFrag, "NowPlayingFragment")
174+
.CommitNow();
175+
}
176+
150177
private void SetupCsharpUi()
151178
{
152179
// 1. Theme Colors
@@ -849,6 +876,7 @@ private void ShowCrashDialog(Exception ex)
849876
.Show();
850877

851878
}
879+
852880
}
853881
sealed class BackInvokedCallback : Java.Lang.Object, IOnBackInvokedCallback
854882
{

Dimmer/Dimmer.Droid/ViewsAndPages/NativeViews/DimmerLive/SocialFragment.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ public SocialFragment(string transitionName, BaseViewModelAnd viewModel)
3636
ChatVM = MainApplication.ServiceProvider.GetRequiredService<ChatViewModel>();
3737
SocialVM = MainApplication.ServiceProvider.GetRequiredService<SocialViewModel>();
3838
}
39-
public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
39+
public override View OnCreateView(LayoutInflater inflater, ViewGroup? container, Bundle? savedInstanceState)
4040
{
4141
var ctx = Context;
4242
var root = new LinearLayout(ctx)

Dimmer/Dimmer.Droid/ViewsAndPages/NativeViews/DimsSection/PlayEventsAdapter.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ public override RecyclerView.ViewHolder OnCreateViewHolder(ViewGroup parent, int
9191
moreCol.SetGravity(GravityFlags.End | GravityFlags.CenterVertical);
9292

9393
var timeAgoTxt = new TextView(_ctx) { TextSize = 12 };
94-
var moreBtn = UiBuilder.CreateMaterialButton(_ctx, _ctx.Resources.Configuration, sizeDp: 40, iconRes: Resource.Drawable.more1);
94+
var moreBtn = UiBuilder.CreateMaterialButton(_ctx, sizeDp: 40, iconRes: Resource.Drawable.more1);
9595

9696
moreCol.AddView(timeAgoTxt);
9797
moreCol.AddView(moreBtn);

Dimmer/Dimmer.Droid/ViewsAndPages/NativeViews/HomePageFragment.cs

Lines changed: 49 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
using Dimmer.DimmerSearch;
1010
using Dimmer.UiUtils;
1111
using Dimmer.Utils;
12+
using Dimmer.Utils.Extensions;
1213
using Dimmer.ViewsAndPages.NativeViews.DimmerLive;
1314
using Dimmer.ViewsAndPages.NativeViews.Misc;
1415
using Dimmer.ViewsAndPages.ViewUtils;
@@ -75,7 +76,7 @@ public HomePageFragment(BaseViewModelAnd myViewModel)
7576
}
7677
private CancellationTokenSource? _searchCts;
7778
private SongAdapter _adapter;
78-
79+
private ImageView _backgroundImageView;
7980

8081
public override View OnCreateView(LayoutInflater inflater, ViewGroup? container, Bundle? savedInstanceState)
8182
{
@@ -89,6 +90,15 @@ public override View OnCreateView(LayoutInflater inflater, ViewGroup? container,
8990

9091
root.SetBackgroundColor(UiBuilder.IsDark(ctx) ? Color.ParseColor("#0D0E20") : Color.ParseColor("#CAD3DA"));
9192

93+
_backgroundImageView = new ImageView(ctx)
94+
{
95+
LayoutParameters = new FrameLayout.LayoutParams(-1, -1),
96+
97+
};
98+
99+
_backgroundImageView.SetScaleType(ImageView.ScaleType.CenterCrop);
100+
101+
root.AddView(_backgroundImageView);
92102
// 2. Main Content Container (Linear Layout inside Coordinator)
93103
var contentLinear = new LinearLayout(ctx)
94104
{
@@ -129,6 +139,7 @@ public override View OnCreateView(LayoutInflater inflater, ViewGroup? container,
129139
Background = null,
130140
TextSize = 14
131141
};
142+
_searchBar.SetTextColor(!UiBuilder.IsDark(this.View) ? Color.Black : Color.White);
132143
_searchBar.SetPadding(40, 30, 40, 30);
133144

134145
_searchBar.TextChanged += _searchBar_TextChanged;
@@ -143,27 +154,27 @@ public override View OnCreateView(LayoutInflater inflater, ViewGroup? container,
143154
};
144155
searchCard.AddView(_searchBar);
145156
// Help Button
146-
helpBtn = new Google.Android.Material.Button.MaterialButton(ctx, null, Resource.Attribute.materialIconButtonStyle)
157+
QueueBtn = new Google.Android.Material.Button.MaterialButton(ctx, null, Resource.Attribute.materialIconButtonStyle)
147158
{
148159
Icon = AndroidX.Core.Content.ContextCompat.GetDrawable(ctx, Resource.Drawable.playlista),
149160
IconTint = Android.Content.Res.ColorStateList.ValueOf(Android.Graphics.Color.DarkSlateBlue),
150161
LayoutParameters = new LinearLayout.LayoutParams(AppUtil.DpToPx(50), AppUtil.DpToPx(50))
151162
};
152-
helpBtn.Click += async (s, e) =>
163+
QueueBtn.Click += async (s, e) =>
153164
{
154165

155-
var queueSheet = new QueueBottomSheetFragment(MyViewModel);
166+
var queueSheet = new QueueBottomSheetFragment(MyViewModel,QueueBtn);
156167
queueSheet.Show(ParentFragmentManager, "QueueSheet");
157-
168+
QueueBtn.Enabled = false;
158169
await Task.Delay(800);
159170
queueSheet.ScrollToSong();
160171
};
161-
helpBtn.LongClickable = true;
162-
helpBtn.LongClick += (s, e) =>
172+
QueueBtn.LongClickable = true;
173+
QueueBtn.LongClick += (s, e) =>
163174
{
164175
MyViewModel.CopyAllSongsInNowPlayingQueueToMainSearchResult();
165176
Toast.MakeText(ctx, "Copied Queue to Main UI", ToastLength.Short);
166-
helpBtn.PerformHapticFeedback(FeedbackConstants.Confirm);
177+
QueueBtn.PerformHapticFeedback(FeedbackConstants.Confirm);
167178
};
168179

169180
loadingIndic = new LoadingIndicator(ctx);
@@ -173,7 +184,7 @@ public override View OnCreateView(LayoutInflater inflater, ViewGroup? container,
173184
// Add items to Header
174185
headerLayout.AddView(menuBtn);
175186
headerLayout.AddView(searchCard);
176-
headerLayout.AddView(helpBtn);
187+
headerLayout.AddView(QueueBtn);
177188

178189

179190

@@ -186,24 +197,22 @@ public override View OnCreateView(LayoutInflater inflater, ViewGroup? container,
186197
bottomLayout.SetPadding(20, 20, 20, 20);
187198

188199
songsTotal = new TextView(ctx, null, Resource.Attribute.titleTextStyle);
189-
200+
songsTotal.SetTextColor(UiBuilder.IsDark(this.View) ? Color.White : Color.Black);
190201
songsTotal.TextAlignment = TextAlignment.TextStart;
191202

192203

193-
var twoRowLayout = new LinearLayout(ctx)
194-
{
195-
Orientation = Orientation.Vertical
196-
};
197204

198-
twoRowLayout.SetPadding(10, 10, 10, 10);
199-
currentTql = UiBuilder.CreateMarqueeTextView(ctx);
205+
currentTql = new TextView(ctx, null, Resource.Attribute.titleTextStyle);
206+
207+
208+
currentTql.SetTextColor(UiBuilder.IsDark(this.View) ? Color.White : Color.Black);
200209

201-
twoRowLayout.AddView(currentTql);
202210

203211
bottomLayout.AddView(loadingIndic);
204212

205213
bottomLayout.AddView(songsTotal);
206-
bottomLayout.AddView(twoRowLayout);
214+
215+
bottomLayout.AddView(currentTql);
207216

208217

209218

@@ -241,7 +250,9 @@ public override View OnCreateView(LayoutInflater inflater, ViewGroup? container,
241250
// --- 5. Extended FAB ---
242251
fab = new Google.Android.Material.FloatingActionButton.ExtendedFloatingActionButton(ctx);
243252
;
244-
fab.Extended = false;
253+
fab.Extended = true;
254+
255+
fab.SetBackgroundColor(UiBuilder.IsDark(ctx) ? Color.ParseColor("#1a1a1a") : Color.ParseColor("#DEDFF0"));
245256
fab.SetIconResource(Resource.Drawable.musicaba);
246257

247258

@@ -337,13 +348,27 @@ public override void OnResume()
337348

338349
MyViewModel.WhenPropertyChange(nameof(MyViewModel.CurrentPlayingSongView), newVl => MyViewModel.CurrentPlayingSongView)
339350
.ObserveOn(RxSchedulers.UI)
340-
.Subscribe(currSong =>
351+
.Subscribe(async currSong =>
341352
{
342353
var art = currSong.Artist;
343354
var alb= currSong.Album;
344355
var artImgPath = art?.ImagePath;
345356
var albImgPath = alb?.ImagePath;
346-
357+
if (MyViewModel.CurrentPlayingSongView.CoverImagePath is not null)
358+
{
359+
360+
if(UiBuilder.IsDark(this.View))
361+
{
362+
363+
await _backgroundImageView.SetImageWithStringPathViaGlideAndFilterEffect(MyViewModel.CurrentPlayingSongView.CoverImagePath,
364+
Utilities.FilterType.DarkAcrylic);
365+
}
366+
else
367+
{
368+
await _backgroundImageView.SetImageWithStringPathViaGlideAndFilterEffect(MyViewModel.CurrentPlayingSongView.CoverImagePath,
369+
Utilities.FilterType.Glassy);
370+
}
371+
}
347372
//currSong.IsCurrentPlayingHighlight= true;
348373
});
349374

@@ -366,7 +391,7 @@ public override void OnResume()
366391
.Subscribe(pbQueue =>
367392
{
368393
if(pbQueue is not null)
369-
helpBtn.TooltipText = $"{MyViewModel.PlaybackQueue.Count} Songs in Queue";
394+
QueueBtn.TooltipText = $"{MyViewModel.PlaybackQueue.Count} Songs in Queue";
370395
});
371396

372397

@@ -457,37 +482,7 @@ public override void OnViewCreated(View view, Bundle? savedInstanceState)
457482
.DisposeWith(CompositeDisposables);
458483

459484

460-
_morphMenu = new FabMorphMenu(Context, root, fab)
461-
.AddItem("Settings", Resource.Drawable.settings, () =>
462-
{
463-
// Logic copied from your old ShowFabMenu
464-
if (Activity is TransitionActivity act)
465-
act.NavigateTo(new SettingsFragment("sett", MyViewModel), "SettingsFragment");
466-
})
467-
.AddItem("Search (TQL)", Resource.Drawable.searchd, () =>
468-
{
469-
var searchSheet = new TqlSearchBottomSheet(MyViewModel);
470-
searchSheet.Show(ParentFragmentManager, "TqlSearchSheet");
471-
})
472-
.AddItem("Scroll to Playing", Resource.Drawable.eye, () =>
473-
{
474-
475-
var songPos = MyViewModel.SearchResults.IndexOf(MyViewModel.CurrentPlayingSongView);
476-
_songListRecycler?.SmoothScrollToPosition(songPos);
477-
478-
Toast.MakeText(Context, $"Scrolled To Song {MyViewModel.CurrentPlayingSongView.Title}", ToastLength.Short)?.Show();
479-
})
480-
.AddItem("View Queue", Resource.Drawable.playlistminimalistic3, () =>
481-
{
482-
var queueSheet = new QueueBottomSheetFragment(MyViewModel);
483-
queueSheet.Show(ParentFragmentManager, "QueueSheet");
484-
})
485-
.AddItem("Login", Resource.Drawable.user, () =>
486-
{
487-
MyViewModel.NavigateToAnyPageOfGivenType(this, new LoginFragment("IntoLogin", MyViewModel), "loginPageTag");
488-
});
489-
490-
485+
491486
PostponeEnterTransition();
492487
_songListRecycler?.ViewTreeObserver?.AddOnPreDrawListener(new MyPreDrawListener(_songListRecycler, this));
493488

@@ -516,7 +511,7 @@ private void Fab_LongClick(object? sender, View.LongClickEventArgs e)
516511
public LoadingIndicator loadingIndic { get; private set; }
517512
public TextView songsTotal { get; private set; }
518513
public TextView currentTql { get; private set; }
519-
public Button helpBtn { get; private set; }
514+
public Button QueueBtn { get; private set; }
520515

521516
public override void OnDestroyView()
522517
{

0 commit comments

Comments
 (0)