Skip to content

Commit 701bb7c

Browse files
authored
fix: library scan empty, status bar overlap, cpal unable to open audio, and more.
Fix issue #3 - [Android] Storage permissions handler - [Android] URI path resolution - [Android] Folder manager access on mobile - [Android] Library scan empty - [Android] Status bar overlap - [Android] window_manager crash on Android - [Android] Spectrum negative padding - [Android] Using ndk context to open audio output for cpal - [Android] Overflow on grid item
2 parents 10eb1db + 09ab4fe commit 701bb7c

31 files changed

Lines changed: 765 additions & 159 deletions

.github/contributing.md

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
# Contributing to Aqloss
2+
3+
Thanks for wanting to contribute. Here's what you need to know.
4+
5+
## Project structure
6+
7+
```
8+
lib/ → Flutter frontend (Dart)
9+
rust/src/ → Audio backend (Rust)
10+
audio_engine.rs → playback core
11+
discord_rpc.rs → Discord rich presence
12+
api.rs → bridge between Rust and Flutter
13+
```
14+
15+
## Getting started
16+
17+
1. Make sure you have Flutter and Rust installed
18+
2. Fork the repo and clone your fork
19+
3. Run `flutter pub get` in the root
20+
4. Run `cargo build` inside `rust/`
21+
5. Start the app with `flutter run`
22+
23+
## Before submitting a PR
24+
25+
- Keep changes focused — one fix or feature per PR
26+
- If you're fixing a bug, mention the issue number (`Fixes #123`)
27+
- Test on your platform at minimum; note if you can't test others
28+
- For Rust changes, make sure there are no new `unwrap()`/`expect()` on hot paths — use `?` or `global_opt()` instead
29+
- For Flutter changes, test both desktop and mobile behavior if relevant (they can differ, e.g. context menus)
30+
- Short commit messages are fine, just be descriptive enough
31+
32+
## Code style
33+
34+
- Rust: `cargo fmt` before committing
35+
- Dart: `dart format .` before committing
36+
- Comments are welcome but keep them brief — `// ...` style, not paragraph essays
37+
38+
## What to work on
39+
40+
Check issues labeled `good first issue` or `help wanted`. If you want to work on something, leave a comment first so we don't duplicate effort.
41+
42+
## Reporting bugs
43+
44+
Use the bug report template. Logs are really helpful — especially backend logs and `RUST_BACKTRACE=1` output for panics.
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
---
2+
name: Bug Report
3+
about: Something is broken or not working as expected
4+
labels: bug, needs reproduction
5+
---
6+
7+
## What happened
8+
9+
<!-- Describe the bug clearly. What did you expect vs what actually happened? -->
10+
11+
## Steps to reproduce
12+
13+
1.
14+
2.
15+
3.
16+
17+
## Logs
18+
19+
<!-- Paste relevant backend/frontend logs here. Run with RUST_BACKTRACE=1 if there's a panic. -->
20+
21+
```
22+
(paste logs here)
23+
```
24+
25+
## Environment
26+
27+
- **OS:** <!-- e.g. Arch Linux, Windows 11, macOS 14 -->
28+
- **Aqloss version:** <!-- e.g. v0.3.1 or commit hash -->
29+
- **Audio backend:** <!-- e.g. ALSA, WASAPI, CoreAudio -->
30+
- **File format (if audio-related):** <!-- e.g. FLAC 96kHz/24bit -->
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
---
2+
name: Feature Request
3+
about: Suggest a new feature or improvement
4+
labels: feature
5+
---
6+
7+
## What do you want?
8+
9+
<!-- Describe the feature clearly. What problem does it solve? -->
10+
11+
## Why is this useful?
12+
13+
<!-- Who benefits from this and in what scenario? -->
14+
15+
## Any ideas on implementation?
16+
17+
<!-- Optional. If you have thoughts on how this could work, share them. -->

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,10 @@ A music player built around a Rust audio engine, with optional WASAPI Exclusive
77
[![Release](https://img.shields.io/github/v/release/nokarin-dev/aqloss?style=for-the-badge&color=4F8EF7)](https://github.com/nokarin-dev/aqloss/releases/latest)
88
[![License: GPL v3](https://img.shields.io/badge/License-GPLv3-blue.svg?style=for-the-badge)](LICENSE)
99
[![Flutter](https://img.shields.io/badge/Flutter-3.41-02569B?style=for-the-badge&logo=flutter)](https://flutter.dev)
10-
[![Platform](https://img.shields.io/badge/platform-Windows%20%7C%20Linux-02569B?style=for-the-badge)](#download)
10+
[![Platform](https://img.shields.io/badge/platform-Windows%20%7C%20Linux%20%7C%20Android-02569B?style=for-the-badge)](#download)
1111

1212
[![Total Downloads](https://img.shields.io/github/downloads/nokarin-dev/aqloss/total?style=for-the-badge&logoColor=%3D&color=3471eb)](https://github.com/nokarin-dev/aqloss/releases)
13+
[![Flathub Downloads](https://img.shields.io/flathub/downloads/xyz.nokarin.aqloss?style=for-the-badge&label=flathub%40installs&color=0451b8)](https://github.com/nokarin-dev/aqloss/releases/latest)
1314
[![Latest Downloads](https://img.shields.io/github/downloads/nokarin-dev/aqloss/latest/total?style=for-the-badge&color=3d47d4)](https://github.com/nokarin-dev/aqloss/releases/latest)
1415
[![Test Status](https://img.shields.io/github/actions/workflow/status/nokarin-dev/aqloss/build-test.yml?style=for-the-badge&label=test%20build&color=22316e)](https://github.com/nokarin-dev/aqloss/actions/workflows/build-test.yml)
1516

android/app/src/main/AndroidManifest.xml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
2+
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="32" />
3+
<uses-permission android:name="android.permission.READ_MEDIA_AUDIO" />
4+
25
<application
36
android:label="aqloss"
47
android:name="${applicationName}"
Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,20 @@
11
package xyz.nokarin.aqloss
22

33
import io.flutter.embedding.android.FlutterActivity
4+
import io.flutter.embedding.engine.FlutterEngine
45

5-
class MainActivity : FlutterActivity()
6+
class MainActivity : FlutterActivity() {
7+
8+
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
9+
super.configureFlutterEngine(flutterEngine)
10+
initAudioContext(applicationContext)
11+
}
12+
13+
private external fun initAudioContext(context: Any)
14+
15+
companion object {
16+
init {
17+
System.loadLibrary("aqloss_rust_core")
18+
}
19+
}
20+
}

android/app/src/profile/AndroidManifest.xml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,6 @@
44
to allow setting breakpoints, to provide hot reload, etc.
55
-->
66
<uses-permission android:name="android.permission.INTERNET"/>
7+
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="32" />
8+
<uses-permission android:name="android.permission.READ_MEDIA_AUDIO" />
79
</manifest>

changes.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,25 @@ This project loosely follows Keep a Changelog and uses Semantic Versioning.
88

99
## [Unreleased]
1010

11+
### Added
12+
13+
- find button discord RPC now links to YouTube Music search
14+
- [Android] Storage permissions handler
15+
- [Android] URI path resolution
16+
- [Android] Folder manager access on mobile
17+
1118
### Fixed
1219

1320
- Call backend only on drag end to prevent seek throttle
1421
- All button now should has pointer now
1522
- Discord button label overflow
1623
- Added helpers to prevent backend crash
24+
- [Android] Library scan empty
25+
- [Android] Status bar overlap
26+
- [Android] window_manager crash on Android
27+
- [Android] Spectrum negative padding
28+
- [Android] Using ndk context to open audio output for cpal
29+
- [Android] Overflow on grid item
1730

1831
---
1932

lib/app.dart

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import 'dart:io';
12
import 'package:flutter/material.dart' hide ThemeMode;
23
import 'package:flutter/material.dart' as theme;
34
import 'package:flutter_riverpod/flutter_riverpod.dart';
@@ -6,6 +7,9 @@ import 'package:aqloss/widgets/settings_watcher.dart';
67
import 'package:window_manager/window_manager.dart';
78
import 'screens/home_screen.dart';
89

10+
bool get _isDesktop =>
11+
Platform.isWindows || Platform.isLinux || Platform.isMacOS;
12+
913
class AqlossApp extends ConsumerStatefulWidget {
1014
const AqlossApp({super.key});
1115

@@ -19,19 +23,24 @@ class _AqlossAppState extends ConsumerState<AqlossApp> with WindowListener {
1923
@override
2024
void initState() {
2125
super.initState();
22-
windowManager.addListener(this);
23-
_checkMaximize();
26+
if (_isDesktop) {
27+
windowManager.addListener(this);
28+
_checkMaximize();
29+
}
2430
}
2531

2632
@override
2733
void dispose() {
28-
windowManager.removeListener(this);
34+
if (_isDesktop) windowManager.removeListener(this);
2935
super.dispose();
3036
}
3137

3238
Future<void> _checkMaximize() async {
33-
final fs = await windowManager.isMaximized();
34-
if (mounted) setState(() => _isMaximize = fs);
39+
if (!_isDesktop) return;
40+
try {
41+
final fs = await windowManager.isMaximized();
42+
if (mounted) setState(() => _isMaximize = fs);
43+
} catch (_) {}
3544
}
3645

3746
@override
@@ -57,12 +66,10 @@ class _AqlossAppState extends ConsumerState<AqlossApp> with WindowListener {
5766
theme: _buildLightTheme(),
5867
darkTheme: _buildDarkTheme(),
5968
builder: (context, child) {
60-
return ClipRRect(
61-
borderRadius: _isMaximize
62-
? BorderRadius.zero
63-
: BorderRadius.circular(12.0),
64-
child: child,
65-
);
69+
final radius = _isDesktop && !_isMaximize
70+
? BorderRadius.circular(12.0)
71+
: BorderRadius.zero;
72+
return ClipRRect(borderRadius: radius, child: child);
6673
},
6774
home: const SettingsWatcher(child: HomeScreen()),
6875
);

lib/main.dart

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -39,15 +39,22 @@ void main() async {
3939
runApp(const ProviderScope(child: AqlossApp()));
4040

4141
WidgetsBinding.instance.addPostFrameCallback((_) async {
42-
final (deviceId, exclusive, volume) = await _loadStartupPrefs();
43-
final prefs = await SharedPreferences.getInstance();
44-
final settings = await _loadSettingsState(prefs);
45-
await AudioService.init(
46-
deviceId: deviceId,
47-
exclusive: exclusive,
48-
volume: volume,
49-
settings: settings,
50-
);
42+
if (Platform.isAndroid) {
43+
await Future.delayed(const Duration(milliseconds: 800));
44+
}
45+
try {
46+
final (deviceId, exclusive, volume) = await _loadStartupPrefs();
47+
final prefs = await SharedPreferences.getInstance();
48+
final settings = await _loadSettingsState(prefs);
49+
await AudioService.init(
50+
deviceId: deviceId,
51+
exclusive: exclusive,
52+
volume: volume,
53+
settings: settings,
54+
);
55+
} catch (e, st) {
56+
print('[aqloss] main init error: $e\n$st');
57+
}
5158
});
5259
}
5360

0 commit comments

Comments
 (0)