Support Nanga Kathai: one-time in-app gifts in local currency
Three consumable products (nk_support_small/medium/large) via Google Play and App Store billing; a 'give more' option emails support. FAQ, Terms and Privacy updated: v1 is free, creator accounts come in a later update. docs/support-payments.md lists the per-country prices and store setup. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
d994fc733f
commit
d257fc4c65
@ -33,7 +33,8 @@ Your liked songs, recently played list, sound settings and downloaded songs are
|
|||||||
- To run the app: streaming, your profile and your preferences.
|
- To run the app: streaming, your profile and your preferences.
|
||||||
- To review creator applications and song reports.
|
- To review creator applications and song reports.
|
||||||
- To keep the service safe and to fix problems.
|
- 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.
|
- To count song plays, so we can show what is popular and, in future, give artists listening statistics.
|
||||||
|
- If you make a gift to support the app, Google Play or the App Store processes the payment. We receive a confirmation but never your card or bank details.
|
||||||
|
|
||||||
We do not use your information for advertising.
|
We do not use your information for advertising.
|
||||||
|
|
||||||
|
|||||||
@ -29,7 +29,11 @@ Use "Is this your song?" on the song in the app, or write to support@nkbmusic.co
|
|||||||
|
|
||||||
## Creators
|
## 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.
|
In a future update, singers, lyricists and music directors will be able to apply to become verified creators. Verification will be manual and may require identity documents. Creators who upload songs will confirm that they own them or have permission from everyone with rights in them, and will accept separate creator terms. Any way for listeners to support creators with money, and any fee we keep, will be set out in those terms before it begins.
|
||||||
|
|
||||||
|
## Supporting Nanga Kathai
|
||||||
|
|
||||||
|
You can make an optional one-time gift to support the app's development. Gifts are paid through Google Play or the App Store, in your local currency, and their terms and refund rules apply. A gift does not unlock any content or features: every song stays free for everyone.
|
||||||
|
|
||||||
## Acceptable use
|
## Acceptable use
|
||||||
|
|
||||||
|
|||||||
55
docs/support-payments.md
Normal file
55
docs/support-payments.md
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
# Support payments ("Support Nanga Kathai")
|
||||||
|
|
||||||
|
One-time gifts that support the app's development. They unlock nothing; every song stays free.
|
||||||
|
Payments go through Google Play and the App Store, which charge each listener in their own
|
||||||
|
currency and pay us (after their fee, usually 15% for small developers).
|
||||||
|
|
||||||
|
## Products to create
|
||||||
|
|
||||||
|
Create three **consumable** in-app products, with exactly these IDs, in both stores:
|
||||||
|
|
||||||
|
| Product ID | Name in the app |
|
||||||
|
|---------------------|----------------------------|
|
||||||
|
| `nk_support_small` | Supporter |
|
||||||
|
| `nk_support_medium` | Friend of Nanga Kathai |
|
||||||
|
| `nk_support_large` | Champion of Badaga music |
|
||||||
|
|
||||||
|
## Prices
|
||||||
|
|
||||||
|
Set the main countries by hand. Every other country can use the store's automatic conversion from
|
||||||
|
the US price. The App Store only offers fixed price points, so pick the nearest one.
|
||||||
|
|
||||||
|
| Country | Currency | Supporter | Friend | Champion |
|
||||||
|
|----------------|----------|-----------|---------|----------|
|
||||||
|
| India | INR | 300 | 500 | 1,000 |
|
||||||
|
| United States | USD | 10 | 25 | 50 |
|
||||||
|
| Canada | CAD | 10 | 25 | 50 |
|
||||||
|
| UAE | AED | 39 | 99 | 199 |
|
||||||
|
| Saudi Arabia | SAR | 39 | 99 | 199 |
|
||||||
|
| Qatar | QAR | 39 | 99 | 199 |
|
||||||
|
| Kuwait | KWD | 3 | 7.5 | 15 |
|
||||||
|
| Oman | OMR | 3.9 | 9.9 | 19.9 |
|
||||||
|
| Bahrain | BHD | 3.9 | 9.9 | 19.9 |
|
||||||
|
|
||||||
|
Gulf prices are about US$10 / $25 / $50. Bigger gifts and sponsorships go through
|
||||||
|
"Want to give more?" on the Support page, which emails support@nkbmusic.com.
|
||||||
|
|
||||||
|
## Google Play (Play Console)
|
||||||
|
|
||||||
|
1. Set up a payments profile (merchant account): Play Console > Setup > Payments profile.
|
||||||
|
2. Upload a build that includes billing (any build from now on) to the Internal testing track.
|
||||||
|
3. Monetize > Products > In-app products > Create product, once for each ID above. Set the US
|
||||||
|
price, then open "Edit prices" to set India, Canada and the Gulf countries by hand. Activate each one.
|
||||||
|
4. Add your Google account under Setup > License testing, so test purchases are free.
|
||||||
|
|
||||||
|
## App Store (App Store Connect)
|
||||||
|
|
||||||
|
1. Accept the Paid Apps agreement, and add bank and tax details under Agreements, Tax, and Banking.
|
||||||
|
2. In the app, open Monetization > In-App Purchases and press +. Choose Consumable, and use the same
|
||||||
|
IDs. Add a price schedule with a US base price, and set manual prices for India, Canada and the Gulf.
|
||||||
|
3. Add a review screenshot of the Support page. The products go to review with the first app version.
|
||||||
|
|
||||||
|
## In the app
|
||||||
|
|
||||||
|
Settings > Support Nanga Kathai shows the products, with prices exactly as the store returns them.
|
||||||
|
Until the products exist in the store, the page says support is unavailable on this phone.
|
||||||
@ -24,6 +24,7 @@ import '../features/settings/document_screen.dart';
|
|||||||
import '../features/settings/help_screen.dart';
|
import '../features/settings/help_screen.dart';
|
||||||
import '../features/settings/report_screen.dart';
|
import '../features/settings/report_screen.dart';
|
||||||
import '../features/settings/settings_screen.dart';
|
import '../features/settings/settings_screen.dart';
|
||||||
|
import '../features/support/support_screen.dart';
|
||||||
import '../features/welcome/splash_screen.dart';
|
import '../features/welcome/splash_screen.dart';
|
||||||
import '../shared/widgets/app_shell.dart';
|
import '../shared/widgets/app_shell.dart';
|
||||||
|
|
||||||
@ -86,6 +87,7 @@ final routerProvider = Provider<GoRouter>((ref) {
|
|||||||
GoRoute(path: '/about', builder: (_, _) => const AboutScreen()),
|
GoRoute(path: '/about', builder: (_, _) => const AboutScreen()),
|
||||||
GoRoute(path: '/settings', builder: (_, _) => const SettingsScreen()),
|
GoRoute(path: '/settings', builder: (_, _) => const SettingsScreen()),
|
||||||
GoRoute(path: '/help', builder: (_, _) => const HelpScreen()),
|
GoRoute(path: '/help', builder: (_, _) => const HelpScreen()),
|
||||||
|
GoRoute(path: '/support', builder: (_, _) => const SupportScreen()),
|
||||||
GoRoute(
|
GoRoute(
|
||||||
path: '/privacy',
|
path: '/privacy',
|
||||||
builder: (_, _) => const DocumentScreen(title: 'Privacy Policy', asset: 'assets/legal/privacy.md'),
|
builder: (_, _) => const DocumentScreen(title: 'Privacy Policy', asset: 'assets/legal/privacy.md'),
|
||||||
|
|||||||
@ -7,9 +7,9 @@ import 'settings_screen.dart';
|
|||||||
const _faq = [
|
const _faq = [
|
||||||
(
|
(
|
||||||
'Is Nanga Kathai free?',
|
'Is Nanga Kathai free?',
|
||||||
'Yes. The songs in the app today are free to stream with a free account. Guests can hear a 30-second '
|
'Yes. Every song is free to stream with a free account, with no ads. Guests can hear a 30-second '
|
||||||
'preview of each song. In future, new songs from verified creators may be part of a paid plan that '
|
'preview of each song. If you would like to help, you can make a one-time gift from Settings > '
|
||||||
'shares revenue with the artists.',
|
'Support Nanga Kathai.',
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
'How do I listen without internet?',
|
'How do I listen without internet?',
|
||||||
@ -45,7 +45,7 @@ const _faq = [
|
|||||||
),
|
),
|
||||||
(
|
(
|
||||||
'I am a singer or music director. Can I publish my songs here?',
|
'I am a singer or music director. Can I publish my songs here?',
|
||||||
'Yes, that is why we built Nanga Kathai. A creator application in the app is coming soon. Until then, '
|
'Yes, that is why we built Nanga Kathai. Creator accounts are coming in a future update. Until then, '
|
||||||
'write to support@nkbmusic.com and we will get in touch.',
|
'write to support@nkbmusic.com and we will get in touch.',
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
|
|||||||
@ -75,6 +75,9 @@ class SettingsScreen extends ConsumerWidget {
|
|||||||
tile(Icons.sd_storage_outlined, 'Storage used',
|
tile(Icons.sd_storage_outlined, 'Storage used',
|
||||||
subtitle: '${downloads.entries.length} songs · $mb MB',
|
subtitle: '${downloads.entries.length} songs · $mb MB',
|
||||||
onTap: downloads.entries.isEmpty ? null : () => _removeAll(context, ref)),
|
onTap: downloads.entries.isEmpty ? null : () => _removeAll(context, ref)),
|
||||||
|
section('Support us'),
|
||||||
|
tile(Icons.favorite_outline, 'Support Nanga Kathai',
|
||||||
|
subtitle: 'Help keep Badaga music free', onTap: () => context.push('/support')),
|
||||||
section('Help'),
|
section('Help'),
|
||||||
tile(Icons.help_outline, 'Help & FAQ', onTap: () => context.push('/help')),
|
tile(Icons.help_outline, 'Help & FAQ', onTap: () => context.push('/help')),
|
||||||
tile(Icons.flag_outlined, 'Is this your song? Report a song', onTap: () => context.push('/report')),
|
tile(Icons.flag_outlined, 'Is this your song? Report a song', onTap: () => context.push('/report')),
|
||||||
|
|||||||
217
lib/features/support/support_screen.dart
Normal file
217
lib/features/support/support_screen.dart
Normal file
@ -0,0 +1,217 @@
|
|||||||
|
import 'dart:async';
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
|
import 'package:in_app_purchase/in_app_purchase.dart';
|
||||||
|
|
||||||
|
import '../../app/theme.dart';
|
||||||
|
import '../settings/settings_screen.dart';
|
||||||
|
|
||||||
|
/// One-time "Support Nanga Kathai" amounts. Create these as consumable in-app products with the
|
||||||
|
/// same IDs in Play Console and App Store Connect; each store charges in the buyer's own
|
||||||
|
/// currency (₹, CA$, US$, AED, SAR…) and the app shows the price exactly as the store gives it.
|
||||||
|
const supportProductIds = {'nk_support_small', 'nk_support_medium', 'nk_support_large'};
|
||||||
|
|
||||||
|
/// Prices are set per country in the stores, e.g. India ₹300 / ₹500 / ₹1,000,
|
||||||
|
/// US and Canada $10 / $25 / $50 (see docs/support-payments.md).
|
||||||
|
const _labels = {
|
||||||
|
'nk_support_small': ('Supporter', Icons.favorite_outline),
|
||||||
|
'nk_support_medium': ('Friend of Nanga Kathai', Icons.music_note_outlined),
|
||||||
|
'nk_support_large': ('Champion of Badaga music', Icons.favorite_rounded),
|
||||||
|
};
|
||||||
|
|
||||||
|
enum SupportStatus { loading, ready, unavailable, buying, thanks, failed }
|
||||||
|
|
||||||
|
class SupportState {
|
||||||
|
const SupportState(this.status, [this.products = const []]);
|
||||||
|
|
||||||
|
final SupportStatus status;
|
||||||
|
final List<ProductDetails> products;
|
||||||
|
|
||||||
|
SupportState copyWith(SupportStatus status) => SupportState(status, products);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Started at app launch, so a purchase that finishes while the app was closed is still
|
||||||
|
/// completed (Google refunds purchases that are never acknowledged).
|
||||||
|
class SupportPurchases extends Notifier<SupportState> {
|
||||||
|
StreamSubscription<List<PurchaseDetails>>? _sub;
|
||||||
|
|
||||||
|
@override
|
||||||
|
SupportState build() {
|
||||||
|
_sub = InAppPurchase.instance.purchaseStream.listen(_onPurchases, onError: (_) {
|
||||||
|
state = state.copyWith(SupportStatus.failed);
|
||||||
|
});
|
||||||
|
ref.onDispose(() => _sub?.cancel());
|
||||||
|
return const SupportState(SupportStatus.loading);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> loadProducts() async {
|
||||||
|
if (state.products.isNotEmpty) return;
|
||||||
|
state = const SupportState(SupportStatus.loading);
|
||||||
|
try {
|
||||||
|
if (!await InAppPurchase.instance.isAvailable()) {
|
||||||
|
state = const SupportState(SupportStatus.unavailable);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final res = await InAppPurchase.instance.queryProductDetails(supportProductIds);
|
||||||
|
final products = [...res.productDetails]..sort((a, b) => a.rawPrice.compareTo(b.rawPrice));
|
||||||
|
state = SupportState(products.isEmpty ? SupportStatus.unavailable : SupportStatus.ready, products);
|
||||||
|
} catch (_) {
|
||||||
|
state = const SupportState(SupportStatus.unavailable);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> buy(ProductDetails product) async {
|
||||||
|
state = state.copyWith(SupportStatus.buying);
|
||||||
|
try {
|
||||||
|
await InAppPurchase.instance.buyConsumable(purchaseParam: PurchaseParam(productDetails: product));
|
||||||
|
} catch (_) {
|
||||||
|
state = state.copyWith(SupportStatus.failed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void reset() => state = state.copyWith(state.products.isEmpty ? SupportStatus.loading : SupportStatus.ready);
|
||||||
|
|
||||||
|
Future<void> _onPurchases(List<PurchaseDetails> purchases) async {
|
||||||
|
for (final p in purchases) {
|
||||||
|
switch (p.status) {
|
||||||
|
case PurchaseStatus.purchased || PurchaseStatus.restored:
|
||||||
|
state = state.copyWith(SupportStatus.thanks);
|
||||||
|
case PurchaseStatus.error:
|
||||||
|
state = state.copyWith(SupportStatus.failed);
|
||||||
|
case PurchaseStatus.canceled:
|
||||||
|
state = state.copyWith(SupportStatus.ready);
|
||||||
|
case PurchaseStatus.pending:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (p.pendingCompletePurchase) await InAppPurchase.instance.completePurchase(p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
final supportProvider = NotifierProvider<SupportPurchases, SupportState>(SupportPurchases.new);
|
||||||
|
|
||||||
|
class SupportScreen extends ConsumerStatefulWidget {
|
||||||
|
const SupportScreen({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
ConsumerState<SupportScreen> createState() => _SupportScreenState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _SupportScreenState extends ConsumerState<SupportScreen> {
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
Future.microtask(() => ref.read(supportProvider.notifier).loadProducts());
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final text = Theme.of(context).textTheme;
|
||||||
|
final support = ref.watch(supportProvider);
|
||||||
|
final notifier = ref.read(supportProvider.notifier);
|
||||||
|
|
||||||
|
if (support.status == SupportStatus.thanks) {
|
||||||
|
return Scaffold(
|
||||||
|
appBar: AppBar(),
|
||||||
|
body: Padding(
|
||||||
|
padding: const EdgeInsets.all(24),
|
||||||
|
child: Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
|
children: [
|
||||||
|
const Icon(Icons.favorite_rounded, color: NkColors.sun, size: 64),
|
||||||
|
const SizedBox(height: 16),
|
||||||
|
Text('Thank you!', textAlign: TextAlign.center, style: text.headlineMedium),
|
||||||
|
const SizedBox(height: 8),
|
||||||
|
const Text(
|
||||||
|
'Your support keeps Badaga music free for everyone and helps us bring more artists to Nanga Kathai.',
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
style: TextStyle(color: NkColors.muted, height: 1.5),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 24),
|
||||||
|
FilledButton(
|
||||||
|
onPressed: () {
|
||||||
|
notifier.reset();
|
||||||
|
Navigator.of(context).maybePop();
|
||||||
|
},
|
||||||
|
child: const Text('Done'),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Scaffold(
|
||||||
|
appBar: AppBar(title: const Text('Support Nanga Kathai')),
|
||||||
|
body: ListView(
|
||||||
|
padding: const EdgeInsets.fromLTRB(20, 0, 20, 32),
|
||||||
|
children: [
|
||||||
|
Text('Help keep Badaga music free', style: text.headlineSmall),
|
||||||
|
const SizedBox(height: 8),
|
||||||
|
const Text(
|
||||||
|
'Nanga Kathai is free, with no ads. If it brings you joy, a one-time gift helps us pay for the servers, '
|
||||||
|
'restore old recordings and build the tools that will let singers earn from their songs.',
|
||||||
|
style: TextStyle(color: NkColors.muted, height: 1.5),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 20),
|
||||||
|
switch (support.status) {
|
||||||
|
SupportStatus.loading => const Padding(
|
||||||
|
padding: EdgeInsets.all(32),
|
||||||
|
child: Center(child: CircularProgressIndicator()),
|
||||||
|
),
|
||||||
|
SupportStatus.unavailable => const Card(
|
||||||
|
color: NkColors.surface,
|
||||||
|
child: Padding(
|
||||||
|
padding: EdgeInsets.all(16),
|
||||||
|
child: Text(
|
||||||
|
'Support is not available on this phone right now. Please check that you are signed in to '
|
||||||
|
'Google Play or the App Store, and try again later.',
|
||||||
|
style: TextStyle(color: NkColors.muted, height: 1.5),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
_ => Column(
|
||||||
|
children: [
|
||||||
|
for (final p in support.products)
|
||||||
|
Card(
|
||||||
|
color: NkColors.surface,
|
||||||
|
child: ListTile(
|
||||||
|
leading: Icon(_labels[p.id]?.$2 ?? Icons.favorite_outline, color: NkColors.sun),
|
||||||
|
title: Text(_labels[p.id]?.$1 ?? p.title,
|
||||||
|
style: const TextStyle(fontWeight: FontWeight.w700)),
|
||||||
|
trailing: FilledButton(
|
||||||
|
onPressed: support.status == SupportStatus.buying ? null : () => notifier.buy(p),
|
||||||
|
child: Text(p.price),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (support.status == SupportStatus.failed)
|
||||||
|
const Padding(
|
||||||
|
padding: EdgeInsets.only(top: 8),
|
||||||
|
child: Text('The payment did not go through. You have not been charged.',
|
||||||
|
style: TextStyle(color: NkColors.muted)),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
},
|
||||||
|
const SizedBox(height: 8),
|
||||||
|
ListTile(
|
||||||
|
contentPadding: EdgeInsets.zero,
|
||||||
|
leading: const Icon(Icons.volunteer_activism_outlined, color: NkColors.sun),
|
||||||
|
title: const Text('Want to give more, or sponsor an album?'),
|
||||||
|
subtitle: const Text('Write to us at $supportEmail', style: TextStyle(color: NkColors.muted)),
|
||||||
|
onTap: () => contactSupport(subject: 'Supporting Nanga Kathai'),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 8),
|
||||||
|
const Text(
|
||||||
|
'One-time payment through Google Play or the App Store, in your local currency. '
|
||||||
|
'Nothing renews and nothing is unlocked: every song stays free for everyone.',
|
||||||
|
style: TextStyle(color: NkColors.muted, fontSize: 12, height: 1.5),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -12,6 +12,7 @@ import 'audio/player_providers.dart';
|
|||||||
import 'audio/sound_settings.dart';
|
import 'audio/sound_settings.dart';
|
||||||
import 'core/env.dart';
|
import 'core/env.dart';
|
||||||
import 'data/user_library.dart';
|
import 'data/user_library.dart';
|
||||||
|
import 'features/support/support_screen.dart';
|
||||||
import 'offline/download_store.dart';
|
import 'offline/download_store.dart';
|
||||||
|
|
||||||
Future<void> main() async {
|
Future<void> main() async {
|
||||||
@ -53,6 +54,7 @@ class NangaKathaiApp extends ConsumerWidget {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, WidgetRef ref) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
ref.watch(soundSettingsProvider); // apply the saved equalizer and boost at startup
|
ref.watch(soundSettingsProvider); // apply the saved equalizer and boost at startup
|
||||||
|
ref.read(supportProvider); // finish any support payment that completed while the app was closed
|
||||||
final router = ref.watch(routerProvider);
|
final router = ref.watch(routerProvider);
|
||||||
// Guests hear a short preview of each song, then are invited to sign up.
|
// Guests hear a short preview of each song, then are invited to sign up.
|
||||||
ref.listen(positionProvider, (_, next) {
|
ref.listen(positionProvider, (_, next) {
|
||||||
|
|||||||
32
pubspec.lock
32
pubspec.lock
@ -509,6 +509,38 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.2.2"
|
version: "0.2.2"
|
||||||
|
in_app_purchase:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: in_app_purchase
|
||||||
|
sha256: d8317ec2ed6fe33199957d67ee67e08a4fd4871ef93b91d7611d8ee560892afc
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "3.3.1"
|
||||||
|
in_app_purchase_android:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: in_app_purchase_android
|
||||||
|
sha256: b76ab601573f8a848e72d015496257235066ba3479bef6300482239f417e0d72
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.5.5"
|
||||||
|
in_app_purchase_platform_interface:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: in_app_purchase_platform_interface
|
||||||
|
sha256: "0b0076cac8ce4fa7048f01e76af8b123aeb6a7c4e0dea2a5206d6664454f3e36"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.4.1"
|
||||||
|
in_app_purchase_storekit:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: in_app_purchase_storekit
|
||||||
|
sha256: fb2744b928bb0fcbfc95d1833469b3f638a44670aac3e278695930d3727011b6
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.4.16"
|
||||||
intl:
|
intl:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|||||||
@ -51,6 +51,7 @@ dependencies:
|
|||||||
http: ^1.6.0
|
http: ^1.6.0
|
||||||
url_launcher: ^6.3.3
|
url_launcher: ^6.3.3
|
||||||
connectivity_plus: ^7.3.2
|
connectivity_plus: ^7.3.2
|
||||||
|
in_app_purchase: ^3.3.1
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
|
|||||||
@ -22,7 +22,7 @@ strong{color:#FBF7EE} a{color:#F5B335} li{margin:4px 0} .brand{color:#F5B335;fon
|
|||||||
<h2>What stays on your phone</h2>
|
<h2>What stays on your phone</h2>
|
||||||
<p>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.</p>
|
<p>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.</p>
|
||||||
<h2>How we use your information</h2>
|
<h2>How we use your information</h2>
|
||||||
<ul><li>To create and secure your account, including sending sign-in and verification codes by email.</li><li>To run the app: streaming, your profile and your preferences.</li><li>To review creator applications and song reports.</li><li>To keep the service safe and to fix problems.</li><li>In future, to count song plays so that verified artists can share in subscription revenue. We will update this policy before that starts.</li></ul>
|
<ul><li>To create and secure your account, including sending sign-in and verification codes by email.</li><li>To run the app: streaming, your profile and your preferences.</li><li>To review creator applications and song reports.</li><li>To keep the service safe and to fix problems.</li><li>To count song plays, so we can show what is popular and, in future, give artists listening statistics.</li><li>If you make a gift to support the app, Google Play or the App Store processes the payment. We receive a confirmation but never your card or bank details.</li></ul>
|
||||||
<p>We do not use your information for advertising.</p>
|
<p>We do not use your information for advertising.</p>
|
||||||
<h2>Who can see your information</h2>
|
<h2>Who can see your information</h2>
|
||||||
<ul><li><strong>Our team:</strong> only the people who run Nanga Kathai, and only when needed.</li><li><strong>Service providers:</strong> 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.</li><li><strong>The law:</strong> we may disclose information if required by law or to protect the safety of our users.</li></ul>
|
<ul><li><strong>Our team:</strong> only the people who run Nanga Kathai, and only when needed.</li><li><strong>Service providers:</strong> 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.</li><li><strong>The law:</strong> we may disclose information if required by law or to protect the safety of our users.</li></ul>
|
||||||
|
|||||||
@ -20,7 +20,9 @@ strong{color:#FBF7EE} a{color:#F5B335} li{margin:4px 0} .brand{color:#F5B335;fon
|
|||||||
<ul><li><strong>claim a song</strong> so we credit you correctly,</li><li><strong>ask us to correct</strong> its details, or</li><li><strong>ask us to remove it.</strong></li></ul>
|
<ul><li><strong>claim a song</strong> so we credit you correctly,</li><li><strong>ask us to correct</strong> its details, or</li><li><strong>ask us to remove it.</strong></li></ul>
|
||||||
<p>Use "Is this your song?" on the song in the app, or write to <a href="mailto:support@nkbmusic.com.">support@nkbmusic.com.</a> We review every request and act on genuine removal requests promptly.</p>
|
<p>Use "Is this your song?" on the song in the app, or write to <a href="mailto:support@nkbmusic.com.">support@nkbmusic.com.</a> We review every request and act on genuine removal requests promptly.</p>
|
||||||
<h2>Creators</h2>
|
<h2>Creators</h2>
|
||||||
<p>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.</p>
|
<p>In a future update, singers, lyricists and music directors will be able to apply to become verified creators. Verification will be manual and may require identity documents. Creators who upload songs will confirm that they own them or have permission from everyone with rights in them, and will accept separate creator terms. Any way for listeners to support creators with money, and any fee we keep, will be set out in those terms before it begins.</p>
|
||||||
|
<h2>Supporting Nanga Kathai</h2>
|
||||||
|
<p>You can make an optional one-time gift to support the app's development. Gifts are paid through Google Play or the App Store, in your local currency, and their terms and refund rules apply. A gift does not unlock any content or features: every song stays free for everyone.</p>
|
||||||
<h2>Acceptable use</h2>
|
<h2>Acceptable use</h2>
|
||||||
<p>Please do not:</p>
|
<p>Please do not:</p>
|
||||||
<ul><li>break, overload or try to get around the app's security, including its download protection;</li><li>use bots or scripts to play songs, create accounts or inflate play counts;</li><li>impersonate a singer or anyone else, or submit false claims or reports;</li><li>upload or send anything unlawful, hateful or harmful.</li></ul>
|
<ul><li>break, overload or try to get around the app's security, including its download protection;</li><li>use bots or scripts to play songs, create accounts or inflate play counts;</li><li>impersonate a singer or anyone else, or submit false claims or reports;</li><li>upload or send anything unlawful, hateful or harmful.</li></ul>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user