Adds app whitelabling feature from kmountainflower site dumps
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'generated/theme_colors.dart';
|
||||
|
||||
class AppThemeColors {
|
||||
const AppThemeColors({
|
||||
required this.primarySeed,
|
||||
@@ -33,37 +35,8 @@ class AppThemeColors {
|
||||
}
|
||||
|
||||
class AppThemeBusinessObject {
|
||||
static const AppThemeColors lightColors = AppThemeColors(
|
||||
primarySeed: Color(0xFFE36A18),
|
||||
secondarySeed: Color(0xFF1663C7),
|
||||
scaffoldGradientStart: Color(0xFFFFF3E3),
|
||||
scaffoldGradientEnd: Color(0xFFE6F2FF),
|
||||
shellSurface: Color(0xF7FFFFFF),
|
||||
shellBorder: Color(0x1A1A4D86),
|
||||
accent: Color(0xFF0F5DB6),
|
||||
webViewBorder: Color(0x261A4D86),
|
||||
webViewBackground: Color(0xFFFFFFFF),
|
||||
controlsGradientStart: Color(0xFFFFB465),
|
||||
controlsGradientEnd: Color(0xFF69ADFF),
|
||||
controlsShadow: Color(0x24114B7A),
|
||||
statusText: Color(0xFF13243D),
|
||||
);
|
||||
|
||||
static const AppThemeColors darkColors = AppThemeColors(
|
||||
primarySeed: Color(0xFFFF9D59),
|
||||
secondarySeed: Color(0xFF76B8FF),
|
||||
scaffoldGradientStart: Color(0xFF0F1C30),
|
||||
scaffoldGradientEnd: Color(0xFF31190C),
|
||||
shellSurface: Color(0xD9162438),
|
||||
shellBorder: Color(0x3366AAFF),
|
||||
accent: Color(0xFFFFBC7E),
|
||||
webViewBorder: Color(0x3378B7FF),
|
||||
webViewBackground: Color(0xFF0C1420),
|
||||
controlsGradientStart: Color(0xFF275792),
|
||||
controlsGradientEnd: Color(0xFF9A4F1F),
|
||||
controlsShadow: Color(0x44000000),
|
||||
statusText: Color(0xFFF4F7FF),
|
||||
);
|
||||
static const AppThemeColors lightColors = GeneratedThemeColors.lightColors;
|
||||
static const AppThemeColors darkColors = GeneratedThemeColors.darkColors;
|
||||
|
||||
static bool isDarkMode(BuildContext context) {
|
||||
return MediaQuery.platformBrightnessOf(context) == Brightness.dark;
|
||||
|
||||
@@ -6,6 +6,7 @@ import 'package:audio_session/audio_session.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:just_audio/just_audio.dart';
|
||||
|
||||
import 'generated/app_config.dart';
|
||||
import 'live_info_business_object.dart';
|
||||
|
||||
class KryzAudioHandler extends BaseAudioHandler with SeekHandler {
|
||||
@@ -16,16 +17,16 @@ class KryzAudioHandler extends BaseAudioHandler with SeekHandler {
|
||||
);
|
||||
}
|
||||
|
||||
static const String streamUrl = 'https://kryz.out.airtime.pro/kryz_a';
|
||||
static const String streamUrl = AppConfig.streamUrl;
|
||||
static const String mediaId = 'kryz-live-stream';
|
||||
static const String _liveInfoEndpoint = 'http://kryz.airtime.pro/api/live-info';
|
||||
static const String _liveInfoEndpoint = AppConfig.metadataUrl ?? '';
|
||||
static const Duration _liveInfoTimeout = Duration(seconds: 8);
|
||||
static const Duration _metadataRefreshInterval = Duration(seconds: 20);
|
||||
|
||||
static const MediaItem _defaultMediaItem = MediaItem(
|
||||
id: mediaId,
|
||||
title: 'KRYZ Live Stream',
|
||||
artist: 'KRYZ Radio',
|
||||
title: AppConfig.defaultTitle,
|
||||
artist: AppConfig.defaultArtist,
|
||||
album: 'Live',
|
||||
extras: <String, dynamic>{
|
||||
'isLive': true,
|
||||
@@ -52,7 +53,7 @@ class KryzAudioHandler extends BaseAudioHandler with SeekHandler {
|
||||
MediaItem(
|
||||
id: mediaId,
|
||||
title: current.displayTitle,
|
||||
artist: subtitle.isEmpty ? 'KRYZ Radio' : subtitle,
|
||||
artist: subtitle.isEmpty ? AppConfig.defaultArtist : subtitle,
|
||||
album: 'Live',
|
||||
extras: <String, dynamic>{
|
||||
'isLive': true,
|
||||
|
||||
@@ -4,17 +4,31 @@ import 'dart:convert';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
|
||||
import 'generated/app_config.dart';
|
||||
|
||||
class LiveInfoBusinessObject extends ChangeNotifier {
|
||||
LiveInfoBusinessObject({
|
||||
this.endpoint = const String.fromEnvironment(
|
||||
'KRYZ_LIVE_INFO_URL',
|
||||
defaultValue: 'http://kryz.airtime.pro/api/live-info',
|
||||
),
|
||||
String? endpoint,
|
||||
int refreshIntervalSeconds = 20,
|
||||
this.requestTimeout = const Duration(seconds: 8),
|
||||
}) : _refreshIntervalSeconds = refreshIntervalSeconds;
|
||||
}) : _endpointOverride = endpoint,
|
||||
_refreshIntervalSeconds = refreshIntervalSeconds;
|
||||
|
||||
final String endpoint;
|
||||
/// Explicit endpoint passed at construction, if any.
|
||||
final String? _endpointOverride;
|
||||
|
||||
/// The effective polling endpoint: construction override > env var > AppConfig.
|
||||
String get endpoint {
|
||||
final override = _endpointOverride;
|
||||
if (override != null && override.isNotEmpty) {
|
||||
return override;
|
||||
}
|
||||
const envUrl = String.fromEnvironment('KRYZ_LIVE_INFO_URL', defaultValue: '');
|
||||
if (envUrl.isNotEmpty) {
|
||||
return envUrl;
|
||||
}
|
||||
return AppConfig.metadataUrl ?? '';
|
||||
}
|
||||
final Duration requestTimeout;
|
||||
|
||||
Timer? _pollTimer;
|
||||
@@ -34,6 +48,10 @@ class LiveInfoBusinessObject extends ChangeNotifier {
|
||||
List<RecentPlayedItem> get recentPlayed => List.unmodifiable(_recentPlayed);
|
||||
|
||||
Future<void> start() async {
|
||||
// Skip polling if no endpoint is configured
|
||||
if (endpoint.isEmpty && (AppConfig.metadataUrl ?? '').isEmpty) {
|
||||
return;
|
||||
}
|
||||
await refresh();
|
||||
_restartTimer();
|
||||
}
|
||||
|
||||
+3
-2
@@ -4,6 +4,7 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:timezone/data/latest.dart' as tz;
|
||||
import 'generated/app_config.dart';
|
||||
import 'app_theme_business_object.dart';
|
||||
import 'casting_business_object.dart';
|
||||
import 'live_info_business_object.dart';
|
||||
@@ -53,7 +54,7 @@ class _MyAppState extends State<MyApp> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return MaterialApp(
|
||||
title: 'KRYZ Go!',
|
||||
title: AppConfig.appName,
|
||||
theme: AppThemeBusinessObject.lightTheme(),
|
||||
darkTheme: AppThemeBusinessObject.darkTheme(),
|
||||
themeMode: ThemeMode.system,
|
||||
@@ -394,7 +395,7 @@ class _MainPageState extends State<MainPage> with WidgetsBindingObserver {
|
||||
const SizedBox(width: 14),
|
||||
Expanded(
|
||||
child: Text(
|
||||
'KRYZ Go!',
|
||||
AppConfig.appName,
|
||||
textAlign: TextAlign.center,
|
||||
style: theme.textTheme.headlineMedium?.copyWith(
|
||||
fontWeight: FontWeight.w900,
|
||||
|
||||
@@ -3,6 +3,7 @@ import 'dart:async';
|
||||
import 'package:audio_service/audio_service.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
|
||||
import 'generated/app_config.dart';
|
||||
import 'kryz_audio_handler.dart';
|
||||
import 'live_info_business_object.dart';
|
||||
|
||||
@@ -38,7 +39,7 @@ class StreamingAudioBusinessObject extends ChangeNotifier {
|
||||
builder: () => KryzAudioHandler(),
|
||||
config: const AudioServiceConfig(
|
||||
androidNotificationChannelId: 'com.kryzgoflutter.audio.channel',
|
||||
androidNotificationChannelName: 'KRYZ Audio Playback',
|
||||
androidNotificationChannelName: '${AppConfig.appName} Audio Playback',
|
||||
androidNotificationOngoing: true,
|
||||
androidStopForegroundOnPause: true,
|
||||
),
|
||||
@@ -60,8 +61,8 @@ class StreamingAudioBusinessObject extends ChangeNotifier {
|
||||
StreamingPlaybackStatus _playbackStatus = StreamingPlaybackStatus.stopped;
|
||||
bool _isDisposed = false;
|
||||
bool _isAttached = false;
|
||||
String _currentTitle = 'KRYZ Live Stream';
|
||||
String _currentSubtitle = 'KRYZ Radio';
|
||||
String _currentTitle = AppConfig.defaultTitle;
|
||||
String _currentSubtitle = AppConfig.defaultArtist;
|
||||
|
||||
StreamingPlaybackStatus get playbackStatus => _playbackStatus;
|
||||
bool get isPlaying => _playbackStatus == StreamingPlaybackStatus.playing;
|
||||
@@ -145,9 +146,9 @@ class StreamingAudioBusinessObject extends ChangeNotifier {
|
||||
return;
|
||||
}
|
||||
|
||||
final title = item.title.trim().isEmpty ? 'KRYZ Live Stream' : item.title;
|
||||
final title = item.title.trim().isEmpty ? AppConfig.defaultTitle : item.title;
|
||||
final subtitle =
|
||||
(item.artist ?? '').trim().isEmpty ? 'KRYZ Radio' : item.artist!.trim();
|
||||
(item.artist ?? '').trim().isEmpty ? AppConfig.defaultArtist : item.artist!.trim();
|
||||
|
||||
if (title == _currentTitle && subtitle == _currentSubtitle) {
|
||||
return;
|
||||
|
||||
Reference in New Issue
Block a user