diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml
index 676d363..b779ee5 100644
--- a/android/app/src/main/AndroidManifest.xml
+++ b/android/app/src/main/AndroidManifest.xml
@@ -60,5 +60,10 @@
+
+
+
+
+
diff --git a/android/app/src/main/kotlin/com/metatroncubesolutions/nanga_kathai/MainActivity.kt b/android/app/src/main/kotlin/com/metatroncubesolutions/nanga_kathai/MainActivity.kt
index 267d37a..67a7cd0 100644
--- a/android/app/src/main/kotlin/com/metatroncubesolutions/nanga_kathai/MainActivity.kt
+++ b/android/app/src/main/kotlin/com/metatroncubesolutions/nanga_kathai/MainActivity.kt
@@ -1,5 +1,43 @@
package com.metatroncubesolutions.nanga_kathai
+import android.content.Intent
+import android.media.MediaRouter2
+import android.os.Build
+import android.provider.Settings
import com.ryanheise.audioservice.AudioServiceActivity
+import io.flutter.embedding.engine.FlutterEngine
+import io.flutter.plugin.common.MethodChannel
-class MainActivity : AudioServiceActivity()
+class MainActivity : AudioServiceActivity() {
+ override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
+ super.configureFlutterEngine(flutterEngine)
+ MethodChannel(flutterEngine.dartExecutor.binaryMessenger, "nk/output").setMethodCallHandler { call, result ->
+ when (call.method) {
+ "showOutputSwitcher" -> result.success(showOutputSwitcher())
+ else -> result.notImplemented()
+ }
+ }
+ }
+
+ /** Opens the phone's own "play on" picker (speaker, Bluetooth, cast). */
+ private fun showOutputSwitcher(): Boolean {
+ if (Build.VERSION.SDK_INT >= 34 && MediaRouter2.getInstance(this).showSystemOutputSwitcher()) return true
+ if (Build.VERSION.SDK_INT >= 31) {
+ try {
+ sendBroadcast(
+ Intent("com.android.systemui.action.LAUNCH_MEDIA_OUTPUT_DIALOG")
+ .setPackage("com.android.systemui")
+ .putExtra("package_name", packageName)
+ )
+ return true
+ } catch (_: Exception) {
+ }
+ }
+ return try {
+ startActivity(Intent(Settings.ACTION_BLUETOOTH_SETTINGS).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK))
+ true
+ } catch (_: Exception) {
+ false
+ }
+ }
+}
diff --git a/assets/legal/privacy.md b/assets/legal/privacy.md
new file mode 100644
index 0000000..043e792
--- /dev/null
+++ b/assets/legal/privacy.md
@@ -0,0 +1,79 @@
+# Privacy Policy
+
+Last updated: 1 November 2026
+
+Nanga Kathai ("we", "us") is a music app for Badaga songs, made by Metatroncube Software Solutions. This policy explains what we collect, why, and the choices you have. We wrote it to be read, not skimmed.
+
+## The short version
+
+- We collect only what we need to run the app: your email, the name you give us, and optional profile details.
+- We do not sell your data, show ads, or share your details with advertisers.
+- Your likes, recently played songs and downloads stay on your phone.
+- You can delete your account, and everything linked to it, from the app at any time.
+
+## What we collect
+
+**Account details.** When you sign up we store your email address, the name you enter and a securely hashed password. We never see or store your password in readable form.
+
+**Optional profile details.** If you choose to add them: a profile photo, your village or hatti, and your phone number. Your phone number is visible only to the Nanga Kathai team, never to other listeners.
+
+**Creator applications.** If you apply to become a verified creator, we also collect the details you submit, such as your stage name, Instagram ID, WhatsApp number, links to your work and an identity document. These are used only to verify you, are visible only to our admin team, and are stored privately.
+
+**Reports and messages.** If you report a song, claim a song or contact us, we keep what you send so we can respond.
+
+**Technical information.** Our servers keep standard logs (such as IP address, device type and time of request) for security and to fix problems. Logs are kept for a limited time.
+
+## What stays on your phone
+
+Your liked songs, recently played list, sound settings and downloaded songs are stored on your device. Downloaded songs are encrypted and can only be played inside Nanga Kathai. Removing the app removes them.
+
+## How we use your information
+
+- To create and secure your account, including sending sign-in and verification codes by email.
+- To run the app: streaming, your profile and your preferences.
+- To review creator applications and song reports.
+- To keep the service safe and to fix problems.
+- In future, to count song plays so that verified artists can share in subscription revenue. We will update this policy before that starts.
+
+We do not use your information for advertising.
+
+## Who can see your information
+
+- **Our team:** only the people who run Nanga Kathai, and only when needed.
+- **Service providers:** our app runs on servers we operate, and email is sent through our own mail server. If we ever use an outside provider for hosting, email or payments, they may only use your data to provide that service to us.
+- **The law:** we may disclose information if required by law or to protect the safety of our users.
+
+Other listeners never see your email or phone number.
+
+## How long we keep it
+
+We keep your account details for as long as your account exists. When you delete your account, your profile, likes, playlists and history on our servers are removed. Backups are overwritten within about 14 days. Reports you sent may be kept, without your account, where we need a record of a rights or removal request.
+
+## Your choices and rights
+
+- **See and edit** your profile in the app (Library > your profile).
+- **Delete your account** from your profile page. This cannot be undone.
+- **Ask us** for a copy of your data, a correction, or anything else about your privacy by writing to support@nkbmusic.com.
+
+These rights apply wherever you live, including your rights under India's Digital Personal Data Protection Act, 2023.
+
+## Children
+
+Nanga Kathai is meant for listeners of all ages, but accounts are intended for people aged 18 and over. Younger listeners should use the app with the consent and supervision of a parent or guardian.
+
+## Security
+
+We use encrypted connections (HTTPS) for everything the app sends, store passwords only in hashed form, restrict data access with database rules, and keep creator documents in private storage. No system is perfectly secure, so please use a password you do not use elsewhere.
+
+## Changes to this policy
+
+If we make important changes, we will tell you in the app before they take effect. The date at the top shows the latest version.
+
+## Contact and grievances
+
+Questions, requests or complaints about privacy:
+
+**Email:** support@nkbmusic.com
+**Grievance contact:** Metatroncube Software Solutions, via support@nkbmusic.com
+
+We aim to reply within 7 days.
diff --git a/assets/legal/terms.md b/assets/legal/terms.md
new file mode 100644
index 0000000..e846939
--- /dev/null
+++ b/assets/legal/terms.md
@@ -0,0 +1,65 @@
+# Terms of Use
+
+Last updated: 1 November 2026
+
+Welcome to Nanga Kathai, a home for Badaga music, provided by Metatroncube Software Solutions ("we", "us"). By using the app you agree to these terms. Please read them; they are short.
+
+## Using Nanga Kathai
+
+- Nanga Kathai is for your personal, non-commercial listening.
+- Guests can preview songs. A free account lets you listen in full, keep likes and download songs.
+- You are responsible for your account. Keep your password private and tell us at support@nkbmusic.com if you think someone else has used it.
+- Accounts are intended for people aged 18 and over. Younger listeners should use the app with a parent or guardian.
+
+## Songs and rights
+
+- The songs in Nanga Kathai belong to their singers, lyricists, composers and other rights holders. Using the app does not give you any ownership of them.
+- You may not copy, record, re-upload, sell, broadcast or publicly perform songs from the app, or remove them from the app by any means.
+- **Downloads** are for offline listening inside Nanga Kathai only. They are encrypted, cannot be played elsewhere, and may stop working if a song is removed or your account is deleted.
+
+## Our older recordings
+
+Our first songs come from a family collection gathered over many years, and not every artist has been identified yet. We respect the people behind these songs. If you are an artist, rights holder or family member, you can, at any time:
+
+- **claim a song** so we credit you correctly,
+- **ask us to correct** its details, or
+- **ask us to remove it.**
+
+Use "Is this your song?" on the song in the app, or write to support@nkbmusic.com. We review every request and act on genuine removal requests promptly.
+
+## Creators
+
+Singers, lyricists and music directors can apply to become verified creators. Verification is manual and may require identity documents. Creators who upload songs confirm that they own them or have permission from everyone with rights in them, and accept the separate terms shown when they apply. Plans to share subscription revenue with verified creators will be described in those terms before they begin.
+
+## Acceptable use
+
+Please do not:
+
+- break, overload or try to get around the app's security, including its download protection;
+- use bots or scripts to play songs, create accounts or inflate play counts;
+- impersonate a singer or anyone else, or submit false claims or reports;
+- upload or send anything unlawful, hateful or harmful.
+
+We may suspend or close accounts that break these terms.
+
+## Changes and availability
+
+We are a small team building something for our community. Features may change, and songs may be added or removed, sometimes at an artist's request. We try to keep the app running smoothly but cannot promise it will always be available or error-free.
+
+## Liability
+
+Nanga Kathai is provided "as is". To the extent the law allows, we are not liable for indirect or consequential losses arising from your use of the app. Nothing in these terms limits rights you have under consumer protection law.
+
+## Ending your account
+
+You can delete your account at any time from your profile page. We may close an account that breaks these terms, and will tell you why where we can.
+
+## Changes to these terms
+
+If we make important changes, we will tell you in the app before they take effect. Continuing to use Nanga Kathai afterwards means you accept the new terms.
+
+## Law and contact
+
+These terms are governed by the laws of India.
+
+Questions: **support@nkbmusic.com**
diff --git a/lib/app/router.dart b/lib/app/router.dart
index 26d76bf..c7b9bb6 100644
--- a/lib/app/router.dart
+++ b/lib/app/router.dart
@@ -20,6 +20,10 @@ import '../features/player/now_playing_screen.dart';
import '../features/about/about_screen.dart';
import '../features/album/album_screen.dart';
import '../features/search/search_screen.dart';
+import '../features/settings/document_screen.dart';
+import '../features/settings/help_screen.dart';
+import '../features/settings/report_screen.dart';
+import '../features/settings/settings_screen.dart';
import '../features/welcome/splash_screen.dart';
import '../shared/widgets/app_shell.dart';
@@ -80,6 +84,20 @@ final routerProvider = Provider((ref) {
),
GoRoute(path: '/profile', builder: (_, _) => const ProfileScreen()),
GoRoute(path: '/about', builder: (_, _) => const AboutScreen()),
+ GoRoute(path: '/settings', builder: (_, _) => const SettingsScreen()),
+ GoRoute(path: '/help', builder: (_, _) => const HelpScreen()),
+ GoRoute(
+ path: '/privacy',
+ builder: (_, _) => const DocumentScreen(title: 'Privacy Policy', asset: 'assets/legal/privacy.md'),
+ ),
+ GoRoute(
+ path: '/terms',
+ builder: (_, _) => const DocumentScreen(title: 'Terms of Use', asset: 'assets/legal/terms.md'),
+ ),
+ GoRoute(
+ path: '/report',
+ builder: (_, state) => ReportScreen(trackId: state.uri.queryParameters['track']),
+ ),
StatefulShellRoute.indexedStack(
builder: (_, _, shell) => AppShell(shell: shell),
branches: [
diff --git a/lib/audio/output_device.dart b/lib/audio/output_device.dart
new file mode 100644
index 0000000..854a73c
--- /dev/null
+++ b/lib/audio/output_device.dart
@@ -0,0 +1,82 @@
+import 'package:audio_session/audio_session.dart';
+import 'package:flutter/foundation.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter/services.dart';
+import 'package:flutter_riverpod/flutter_riverpod.dart';
+
+import '../app/theme.dart';
+
+/// Where music plays right now, as the phone reports it.
+class OutputDevice {
+ const OutputDevice(this.label, this.icon);
+
+ final String label;
+ final IconData icon;
+
+ static const speaker = OutputDevice('Phone speaker', Icons.speaker_phone_rounded);
+
+ /// Android sends media to the most recently connected external device, so
+ /// pick Bluetooth, then wired/USB/car, then the built-in speaker.
+ static OutputDevice from(Set devices) {
+ final outputs = devices.where((d) => d.isOutput).toList();
+ int rank(AudioDevice d) {
+ final t = d.type.name.toLowerCase();
+ if (t.contains('bluetooth') && t != 'bluetoothsco') return 0;
+ if (t.contains('car') || t.contains('wired') || t.contains('usb') || t.contains('line')) return 1;
+ if (t.contains('hdmi') || t.contains('airplay') || t.contains('dock')) return 2;
+ if (t == 'builtinspeaker') return 3;
+ return 9;
+ }
+
+ outputs.sort((a, b) => rank(a).compareTo(rank(b)));
+ if (outputs.isEmpty || rank(outputs.first) >= 3) return speaker;
+ final d = outputs.first;
+ final t = d.type.name.toLowerCase();
+ final name = d.name.trim().isEmpty ? null : d.name.trim();
+ if (t.contains('bluetooth')) return OutputDevice(name ?? 'Bluetooth', Icons.bluetooth_audio_rounded);
+ if (t.contains('car')) return OutputDevice(name ?? 'Car audio', Icons.directions_car_rounded);
+ if (t.contains('wired') || t.contains('line')) return const OutputDevice('Headphones', Icons.headphones_rounded);
+ if (t.contains('usb')) return OutputDevice(name ?? 'USB audio', Icons.usb_rounded);
+ return OutputDevice(name ?? 'External speaker', Icons.speaker_rounded);
+ }
+}
+
+final outputDeviceProvider = StreamProvider((ref) async* {
+ final session = await AudioSession.instance;
+ yield OutputDevice.from(await session.getDevices(includeInputs: false));
+ yield* session.devicesStream.map(OutputDevice.from);
+});
+
+const _channel = MethodChannel('nk/output');
+
+/// Shows where music is playing; tap to choose another speaker or Bluetooth device.
+class OutputDeviceButton extends ConsumerWidget {
+ const OutputDeviceButton({super.key});
+
+ @override
+ Widget build(BuildContext context, WidgetRef ref) {
+ final device = ref.watch(outputDeviceProvider).value ?? OutputDevice.speaker;
+ final external = device != OutputDevice.speaker;
+ final color = external ? NkColors.teaLeaf : NkColors.mutedOnPhoto;
+ return TextButton.icon(
+ onPressed: () => _choose(context),
+ style: TextButton.styleFrom(foregroundColor: color, visualDensity: VisualDensity.compact),
+ icon: Icon(device.icon, size: 20),
+ label: Text(device.label, maxLines: 1, overflow: TextOverflow.ellipsis),
+ );
+ }
+
+ Future _choose(BuildContext context) async {
+ if (!kIsWeb && defaultTargetPlatform == TargetPlatform.android) {
+ try {
+ if (await _channel.invokeMethod('showOutputSwitcher') == true) return;
+ } on PlatformException {
+ // Fall through to the hint below.
+ }
+ }
+ if (!context.mounted) return;
+ ScaffoldMessenger.of(context).showSnackBar(const SnackBar(
+ content: Text('Choose a speaker or Bluetooth device from Control Center (swipe down from the top right).'),
+ ));
+ }
+}
diff --git a/lib/audio/player_providers.dart b/lib/audio/player_providers.dart
index af7282c..6f5c127 100644
--- a/lib/audio/player_providers.dart
+++ b/lib/audio/player_providers.dart
@@ -1,8 +1,10 @@
import 'package:audio_service/audio_service.dart';
+import 'package:connectivity_plus/connectivity_plus.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import '../core/models.dart';
import '../data/catalog_repository.dart';
+import '../features/settings/settings_screen.dart';
import '../offline/download_store.dart';
import 'nk_audio_handler.dart';
@@ -72,12 +74,20 @@ class PlayerController {
], index: index);
}
- void download(Iterable