Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,26 @@
# v1.7.0+18

## Material 3 Refresh + Artist Profiles + Search Reliability

### NEW FEATURES

- **Material 3 UI Refresh:** Migrated major screens/components to Material 3 with responsive spacing and layout behavior.
- **Dynamic Theme Colors:** Removed legacy glass mode and added seed-color based app theming.
- **Artist Profile Screen:** Added artist profile page with artist art, bio (more/less), monthly audience, Top Songs, Albums, and Singles & EPs.
- **Multi-Artist Picker:** Tapping artist name in full player now supports multi-artist tracks using a tap-only picker sheet.
- **Search Albums Section:** Search now shows a dedicated Albums section under song results with open-to-playlist flow.

### BUG FIXES / IMPROVEMENTS

- **Navigation + Mini-player:** Stabilized right-side quick switcher layout and floating mini-player spacing across screen sizes.
- **Album Filtering:** Limited search album results to album-only intent and reduced EP/Episode/podcast noise.
- **YouTube Search Resilience:** Added strategy fallback and persisted cache refresh behavior for more stable results under API/network variance.

### UPCOMING (work in progress)

- Better artist identity matching for edge-case names/collaborations
- Further recommendation relevance tuning and queue quality improvements

# v1.6.0+17

## Lyrics + Distribution Flavors + Android Widgets
Expand Down
7 changes: 6 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,13 +77,18 @@ Hongeet is a music player that supports **offline local audio playback** and **o
<tr>
<td><img src="assets/screenshots/01.jpg" width="220" /></td>
<td><img src="assets/screenshots/02.jpg" width="220" /></td>
<td><img src="assets/screenshots/11.png" width="220" /></td>
<td><img src="assets/screenshots/03.jpg" width="220" /></td>
</tr>
<tr>
<td><img src="assets/screenshots/04.jpg" width="220" /></td>
<td><img src="assets/screenshots/05.jpg" width="220" /></td>
<td><img src="assets/screenshots/06.jpg" width="220" /></td>
</tr>
<tr>
<td><img src="assets/screenshots/07.jpg" width="220" /></td>
<td><img src="assets/screenshots/08.jpg" width="220" /></td>
<td><img src="assets/screenshots/09.jpg" width="220" /></td>
</tr>
</table>
</div>

Expand Down
3 changes: 2 additions & 1 deletion SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ Security fixes are provided only for the latest stable release line.

| Version | Supported |
| --------- | --------- |
| 1.6.x | ✅ |
| 1.7.x | ✅ |
| 1.6.x | ❌ |
| 1.5.x | ❌ |
| 1.4.x | ❌ |
| 1.3.x | ❌ |
Expand Down
Binary file modified assets/screenshots/01.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified assets/screenshots/02.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified assets/screenshots/03.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified assets/screenshots/04.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified assets/screenshots/05.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified assets/screenshots/06.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified assets/screenshots/07.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified assets/screenshots/08.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified assets/screenshots/09.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed assets/screenshots/10.jpg
Binary file not shown.
Binary file removed assets/screenshots/11.png
Binary file not shown.
7 changes: 7 additions & 0 deletions fastlane/metadata/android/en-US/changelogs/18.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
v1.7.0+18
- Material 3 UI refresh with improved spacing and responsive layouts
- Dynamic seed-color theming; removed legacy glass mode
- Added artist profile with bio, audience, top songs, albums, singles
- Search now includes Albums section
- Improved navigation and mini-player spacing
- Improved YouTube search reliability
Binary file modified fastlane/metadata/android/en-US/images/phoneScreenshots/01.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified fastlane/metadata/android/en-US/images/phoneScreenshots/02.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified fastlane/metadata/android/en-US/images/phoneScreenshots/03.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified fastlane/metadata/android/en-US/images/phoneScreenshots/04.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified fastlane/metadata/android/en-US/images/phoneScreenshots/06.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified fastlane/metadata/android/en-US/images/phoneScreenshots/07.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified fastlane/metadata/android/en-US/images/phoneScreenshots/08.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified fastlane/metadata/android/en-US/images/phoneScreenshots/09.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file not shown.
6 changes: 3 additions & 3 deletions ghweb/version.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"latest": "v1.6.0+17",
"min_supported": "v1.5.1+16",
"latest": "v1.7.0+18",
"min_supported": "v1.6.0+17",
"apk_url": "https://sourceforge.net/projects/hongeet/files/latest/download",
"notes": "Added lyrics support (synced and unsynced). Added distribution flavors: GitHub/SF keeps first-start update checks while Izzy disables them for policy compliance. Added 2x2 and 4x2 Android music widgets with controls, artwork, and progress. Fixed 3-button navigation bottom-bar sizing/mini-player overlap."
"notes": "Material 3 UI refresh with improved spacing and responsive layouts. Dynamic seed-color theming; removed legacy glass mode. Added artist profile with bio, audience, top songs, albums, singles. Search now includes Albums section. Improved navigation and mini-player spacing. Improved YouTube search reliability."
}
263 changes: 190 additions & 73 deletions lib/core/theme/app_theme.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,82 +2,211 @@ import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
import '../utils/data_saver_settings.dart';

enum ProgressBarStyle { defaultStyle, snake, glass }
enum ProgressBarStyle { defaultStyle, snake }

enum UiPerformanceMode { auto, smooth, full }

class AppTheme {
static ThemeData glassTheme = ThemeData(
brightness: Brightness.dark,
scaffoldBackgroundColor: Colors.transparent,
primaryColor: const Color(0xFF1DB954),
textTheme: ThemeData.dark().textTheme.apply(fontFamily: 'Inter'),
appBarTheme: const AppBarTheme(
backgroundColor: Colors.transparent,
elevation: 0,
),
bottomNavigationBarTheme: const BottomNavigationBarThemeData(
backgroundColor: Color(0xFF111111),
selectedItemColor: Color(0xFF1DB954),
unselectedItemColor: Colors.grey,
showUnselectedLabels: true,
type: BottomNavigationBarType.fixed,
),
);

static ThemeData simpleDarkTheme = ThemeData(
brightness: Brightness.dark,
scaffoldBackgroundColor: const Color(0xFF0D0D0D),
primaryColor: const Color(0xFF1DB954),
textTheme: ThemeData.dark().textTheme.apply(fontFamily: 'Inter'),
appBarTheme: const AppBarTheme(
backgroundColor: Colors.transparent,
elevation: 0,
),
bottomNavigationBarTheme: const BottomNavigationBarThemeData(
backgroundColor: Color(0xFF111111),
selectedItemColor: Color(0xFF1DB954),
unselectedItemColor: Colors.grey,
showUnselectedLabels: true,
type: BottomNavigationBarType.fixed,
),
);
static const Color defaultSeedColor = Color(0xFF28C76F);

static ThemeData buildTheme({required Color seedColor}) {
final scheme = ColorScheme.fromSeed(
seedColor: seedColor,
brightness: Brightness.dark,
);

final textTheme = Typography.material2021(
platform: TargetPlatform.android,
).white.apply(fontFamily: 'Inter');

final base = ThemeData(
useMaterial3: true,
brightness: Brightness.dark,
colorScheme: scheme,
fontFamily: 'Inter',
textTheme: textTheme,
scaffoldBackgroundColor: scheme.surface,
appBarTheme: AppBarTheme(
elevation: 0,
centerTitle: false,
scrolledUnderElevation: 0,
backgroundColor: scheme.surface,
foregroundColor: scheme.onSurface,
surfaceTintColor: Colors.transparent,
),
cardTheme: CardThemeData(
elevation: 0,
margin: EdgeInsets.zero,
color: scheme.surfaceContainerHigh,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)),
),
navigationBarTheme: NavigationBarThemeData(
backgroundColor: scheme.surfaceContainer,
surfaceTintColor: Colors.transparent,
elevation: 0,
indicatorColor: scheme.secondaryContainer,
labelTextStyle: WidgetStateProperty.resolveWith((states) {
final isSelected = states.contains(WidgetState.selected);
return textTheme.labelMedium?.copyWith(
fontWeight: isSelected ? FontWeight.w700 : FontWeight.w500,
color: isSelected ? scheme.onSecondaryContainer : scheme.onSurface,
);
}),
),
navigationRailTheme: NavigationRailThemeData(
backgroundColor: scheme.surfaceContainerLow,
selectedIconTheme: IconThemeData(color: scheme.onSecondaryContainer),
unselectedIconTheme: IconThemeData(
color: scheme.onSurface.withValues(alpha: 0.7),
),
selectedLabelTextStyle: textTheme.labelMedium?.copyWith(
fontWeight: FontWeight.w700,
),
unselectedLabelTextStyle: textTheme.labelMedium,
indicatorColor: scheme.secondaryContainer,
),
inputDecorationTheme: InputDecorationTheme(
filled: true,
fillColor: scheme.surfaceContainerLow,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(16),
borderSide: BorderSide(
color: scheme.outlineVariant.withValues(alpha: 0.45),
),
),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(16),
borderSide: BorderSide(
color: scheme.outlineVariant.withValues(alpha: 0.45),
),
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(16),
borderSide: BorderSide(color: scheme.primary, width: 1.3),
),
hintStyle: textTheme.bodyMedium?.copyWith(
color: scheme.onSurfaceVariant.withValues(alpha: 0.86),
),
),
searchBarTheme: SearchBarThemeData(
elevation: const WidgetStatePropertyAll(0),
backgroundColor: WidgetStatePropertyAll(scheme.surfaceContainerLow),
side: WidgetStatePropertyAll(
BorderSide(color: scheme.outlineVariant.withValues(alpha: 0.45)),
),
shape: WidgetStatePropertyAll(
RoundedRectangleBorder(borderRadius: BorderRadius.circular(18)),
),
hintStyle: WidgetStatePropertyAll(
textTheme.bodyMedium?.copyWith(
color: scheme.onSurfaceVariant.withValues(alpha: 0.86),
),
),
),
listTileTheme: ListTileThemeData(
iconColor: scheme.primary,
titleTextStyle: textTheme.titleSmall?.copyWith(
fontWeight: FontWeight.w600,
color: scheme.onSurface,
),
subtitleTextStyle: textTheme.bodySmall?.copyWith(
color: scheme.onSurfaceVariant,
),
),
snackBarTheme: SnackBarThemeData(
backgroundColor: scheme.inverseSurface,
contentTextStyle: textTheme.bodyMedium?.copyWith(
color: scheme.onInverseSurface,
),
behavior: SnackBarBehavior.floating,
),
bottomSheetTheme: BottomSheetThemeData(
showDragHandle: true,
elevation: 0,
surfaceTintColor: Colors.transparent,
modalBackgroundColor: scheme.surfaceContainerHigh,
backgroundColor: scheme.surfaceContainerHigh,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(top: Radius.circular(24)),
),
),
dividerTheme: DividerThemeData(
color: scheme.outlineVariant.withValues(alpha: 0.4),
),
filledButtonTheme: FilledButtonThemeData(
style: FilledButton.styleFrom(
minimumSize: const Size(0, 44),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(14),
),
),
),
outlinedButtonTheme: OutlinedButtonThemeData(
style: OutlinedButton.styleFrom(
minimumSize: const Size(0, 44),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(14),
),
side: BorderSide(color: scheme.outlineVariant),
),
),
switchTheme: SwitchThemeData(
thumbColor: WidgetStateProperty.resolveWith((states) {
if (states.contains(WidgetState.selected)) {
return scheme.onPrimary;
}
return scheme.outline;
}),
trackColor: WidgetStateProperty.resolveWith((states) {
if (states.contains(WidgetState.selected)) {
return scheme.primary;
}
return scheme.surfaceContainerHighest;
}),
),
);

return base;
}
}

class ThemeProvider with ChangeNotifier {
static const _useGlassThemeKey = 'use_glass_theme';
static const _seedColorKey = 'theme_seed_color';
static const _legacyUseGlassThemeKey = 'use_glass_theme';
static const _progressBarStyleKey = 'progress_bar_style';
static const _uiPerformanceModeKey = 'ui_performance_mode';
static const _dataSaverKey = DataSaverSettings.prefKey;

bool _useGlassTheme = false;
bool get useGlassTheme => _useGlassTheme;
// Kept only for backwards compatibility with older UI branches
bool get useGlassTheme => false;

Color _seedColor = AppTheme.defaultSeedColor;
Color get seedColor => _seedColor;

ProgressBarStyle _progressBarStyle = ProgressBarStyle.defaultStyle;
ProgressBarStyle get progressBarStyle => _progressBarStyle;
ProgressBarStyle get effectiveProgressBarStyle {
if (!_useGlassTheme && _progressBarStyle == ProgressBarStyle.glass) {
return ProgressBarStyle.defaultStyle;
}
return _progressBarStyle;
}
ProgressBarStyle get effectiveProgressBarStyle => _progressBarStyle;

UiPerformanceMode _uiPerformanceMode = UiPerformanceMode.auto;
UiPerformanceMode get uiPerformanceMode => _uiPerformanceMode;

bool _dataSaverEnabled = false;
bool get dataSaverEnabled => _dataSaverEnabled;

ThemeData get currentTheme =>
_useGlassTheme ? AppTheme.glassTheme : AppTheme.simpleDarkTheme;
ThemeData get currentTheme => AppTheme.buildTheme(seedColor: _seedColor);

ThemeProvider() {
_loadTheme();
}

Future<void> _loadTheme() async {
final prefs = await SharedPreferences.getInstance();
_useGlassTheme = prefs.getBool(_useGlassThemeKey) ?? false;
await prefs.remove(_legacyUseGlassThemeKey);
final storedSeed = prefs.getInt(_seedColorKey);
_seedColor = storedSeed == null
? AppTheme.defaultSeedColor
: Color(storedSeed);

final progressRaw =
prefs.getString(_progressBarStyleKey) ??
ProgressBarStyle.defaultStyle.name;
Expand All @@ -93,38 +222,31 @@ class ThemeProvider with ChangeNotifier {
);
_dataSaverEnabled = prefs.getBool(_dataSaverKey) ?? false;
DataSaverSettings.setInMemory(_dataSaverEnabled);
notifyListeners();
}

if (!_useGlassTheme && _progressBarStyle == ProgressBarStyle.glass) {
_progressBarStyle = ProgressBarStyle.defaultStyle;
await prefs.setString(_progressBarStyleKey, _progressBarStyle.name);
}
Future<void> setSeedColor(Color color) async {
if (_seedColor.toARGB32() == color.toARGB32()) return;
_seedColor = color;
final prefs = await SharedPreferences.getInstance();
await prefs.setInt(_seedColorKey, color.toARGB32());
notifyListeners();
}

@Deprecated('Glass theme has been removed')
Future<void> setUseGlassTheme(bool enabled) async {
if (_useGlassTheme == enabled) return;
_useGlassTheme = enabled;
final prefs = await SharedPreferences.getInstance();
await prefs.setBool(_useGlassThemeKey, _useGlassTheme);

if (!_useGlassTheme && _progressBarStyle == ProgressBarStyle.glass) {
_progressBarStyle = ProgressBarStyle.defaultStyle;
await prefs.setString(_progressBarStyleKey, _progressBarStyle.name);
}
notifyListeners();
await prefs.remove(_legacyUseGlassThemeKey);
}

@Deprecated('Glass theme has been removed')
Future<void> toggleTheme() async {
await setUseGlassTheme(!_useGlassTheme);
await setUseGlassTheme(false);
}

Future<void> setProgressBarStyle(ProgressBarStyle style) async {
final next = (!_useGlassTheme && style == ProgressBarStyle.glass)
? ProgressBarStyle.defaultStyle
: style;
if (_progressBarStyle == next) return;

_progressBarStyle = next;
if (_progressBarStyle == style) return;
_progressBarStyle = style;
final prefs = await SharedPreferences.getInstance();
await prefs.setString(_progressBarStyleKey, _progressBarStyle.name);
notifyListeners();
Expand Down Expand Up @@ -159,11 +281,6 @@ class ThemeProvider with ChangeNotifier {
}

UiPerformanceMode resolvedUiPerformanceMode(BuildContext context) {
if (_useGlassTheme) {
// Glass mode always renders at full visual strength.
return UiPerformanceMode.full;
}

if (_uiPerformanceMode != UiPerformanceMode.auto) {
return _uiPerformanceMode;
}
Expand Down
Loading