💄 Dynamic app color based on playing track
This commit is contained in:
@@ -1,11 +1,14 @@
|
|||||||
import 'package:audio_service/audio_service.dart';
|
import 'package:audio_service/audio_service.dart';
|
||||||
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:media_kit/media_kit.dart' as media_kit;
|
import 'package:media_kit/media_kit.dart' as media_kit;
|
||||||
import 'package:groovybox/data/db.dart';
|
import 'package:groovybox/data/db.dart';
|
||||||
|
import 'package:groovybox/providers/theme_provider.dart';
|
||||||
|
|
||||||
class AudioHandler extends BaseAudioHandler with QueueHandler, SeekHandler {
|
class AudioHandler extends BaseAudioHandler with QueueHandler, SeekHandler {
|
||||||
final media_kit.Player _player;
|
final media_kit.Player _player;
|
||||||
List<MediaItem> _queue = [];
|
List<MediaItem> _queue = [];
|
||||||
int _queueIndex = 0;
|
int _queueIndex = 0;
|
||||||
|
ProviderContainer? _container;
|
||||||
|
|
||||||
AudioHandler() : _player = media_kit.Player() {
|
AudioHandler() : _player = media_kit.Player() {
|
||||||
// Configure for audio
|
// Configure for audio
|
||||||
@@ -29,12 +32,42 @@ class AudioHandler extends BaseAudioHandler with QueueHandler, SeekHandler {
|
|||||||
final currentIndex = playlist.index;
|
final currentIndex = playlist.index;
|
||||||
if (currentIndex >= 0 && currentIndex < _queue.length) {
|
if (currentIndex >= 0 && currentIndex < _queue.length) {
|
||||||
_queueIndex = currentIndex;
|
_queueIndex = currentIndex;
|
||||||
mediaItem.add(_queue[_queueIndex]);
|
final currentItem = _queue[_queueIndex];
|
||||||
|
mediaItem.add(currentItem);
|
||||||
|
_updateThemeFromCurrentTrack(currentItem);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Method to set the provider container for theme updates
|
||||||
|
void setProviderContainer(ProviderContainer container) {
|
||||||
|
_container = container;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update theme color based on current track's album art
|
||||||
|
void _updateThemeFromCurrentTrack(MediaItem mediaItem) {
|
||||||
|
if (_container == null) return;
|
||||||
|
|
||||||
|
final artUri = mediaItem.artUri;
|
||||||
|
if (artUri != null &&
|
||||||
|
artUri.scheme == 'file' &&
|
||||||
|
artUri.path.isNotEmpty &&
|
||||||
|
!artUri.path.contains('..') && // Prevent directory traversal
|
||||||
|
(artUri.path.endsWith('.jpg') ||
|
||||||
|
artUri.path.endsWith('.jpeg') ||
|
||||||
|
artUri.path.endsWith('.png') ||
|
||||||
|
artUri.path.endsWith('.bmp') ||
|
||||||
|
artUri.path.endsWith('.webp'))) {
|
||||||
|
final seedColorNotifier = _container!.read(seedColorProvider.notifier);
|
||||||
|
seedColorNotifier.updateFromAlbumArt(artUri.path);
|
||||||
|
} else {
|
||||||
|
// Reset to default color if no valid album art
|
||||||
|
final seedColorNotifier = _container!.read(seedColorProvider.notifier);
|
||||||
|
seedColorNotifier.resetToDefault();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
media_kit.Player get player => _player;
|
media_kit.Player get player => _player;
|
||||||
|
|
||||||
// AudioService callbacks
|
// AudioService callbacks
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:groovybox/logic/audio_handler.dart';
|
||||||
|
import 'package:groovybox/providers/audio_provider.dart';
|
||||||
|
import 'package:groovybox/providers/theme_provider.dart';
|
||||||
|
import 'package:groovybox/ui/shell.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:media_kit/media_kit.dart';
|
import 'package:media_kit/media_kit.dart';
|
||||||
import 'package:audio_service/audio_service.dart' as audio_service;
|
import 'package:audio_service/audio_service.dart' as audio_service;
|
||||||
import 'logic/audio_handler.dart';
|
|
||||||
import 'providers/audio_provider.dart';
|
|
||||||
import 'ui/shell.dart';
|
|
||||||
|
|
||||||
late AudioHandler _audioHandler;
|
late AudioHandler _audioHandler;
|
||||||
|
|
||||||
@@ -25,42 +26,33 @@ Future<void> main() async {
|
|||||||
// Set the audio handler for the provider
|
// Set the audio handler for the provider
|
||||||
setAudioHandler(_audioHandler);
|
setAudioHandler(_audioHandler);
|
||||||
|
|
||||||
runApp(const ProviderScope(child: MyApp()));
|
runApp(
|
||||||
|
ProviderScope(
|
||||||
|
child: Builder(
|
||||||
|
builder: (context) {
|
||||||
|
// Get the provider container and set it on the audio handler
|
||||||
|
final container = ProviderScope.containerOf(context);
|
||||||
|
_audioHandler.setProviderContainer(container);
|
||||||
|
return const GroovyApp();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
class MyApp extends StatelessWidget {
|
class GroovyApp extends ConsumerWidget {
|
||||||
const MyApp({super.key});
|
const GroovyApp({super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
|
final themeMode = ref.watch(themeProvider);
|
||||||
|
|
||||||
return MaterialApp(
|
return MaterialApp(
|
||||||
title: 'GroovyBox',
|
title: 'GroovyBox',
|
||||||
debugShowCheckedModeBanner: false,
|
debugShowCheckedModeBanner: false,
|
||||||
theme: ThemeData(
|
theme: ref.watch(lightThemeProvider),
|
||||||
colorScheme: ColorScheme.fromSeed(
|
darkTheme: ref.watch(darkThemeProvider),
|
||||||
seedColor: Colors.deepPurple,
|
themeMode: themeMode,
|
||||||
brightness: Brightness.light,
|
|
||||||
),
|
|
||||||
useMaterial3: true,
|
|
||||||
inputDecorationTheme: InputDecorationTheme(
|
|
||||||
border: OutlineInputBorder(
|
|
||||||
borderRadius: const BorderRadius.all(Radius.circular(12)),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
darkTheme: ThemeData(
|
|
||||||
colorScheme: ColorScheme.fromSeed(
|
|
||||||
seedColor: Colors.deepPurple,
|
|
||||||
brightness: Brightness.dark,
|
|
||||||
),
|
|
||||||
useMaterial3: true,
|
|
||||||
inputDecorationTheme: InputDecorationTheme(
|
|
||||||
border: OutlineInputBorder(
|
|
||||||
borderRadius: const BorderRadius.all(Radius.circular(12)),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
themeMode: ThemeMode.system,
|
|
||||||
home: const Shell(),
|
home: const Shell(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:groovybox/logic/audio_handler.dart';
|
import 'package:groovybox/logic/audio_handler.dart';
|
||||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||||
|
|
||||||
|
|||||||
@@ -48,4 +48,4 @@ final class AudioHandlerProvider
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
String _$audioHandlerHash() => r'd2864a90812b2c615afb327e5a5504558097c945';
|
String _$audioHandlerHash() => r'65fbd92e049fe4f3a0763516f1e68e1614f7630f';
|
||||||
|
|||||||
173
lib/providers/theme_provider.dart
Normal file
173
lib/providers/theme_provider.dart
Normal file
@@ -0,0 +1,173 @@
|
|||||||
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:palette_generator/palette_generator.dart';
|
||||||
|
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||||
|
|
||||||
|
part 'theme_provider.g.dart';
|
||||||
|
|
||||||
|
// Default seed color
|
||||||
|
const Color defaultSeedColor = Colors.deepPurple;
|
||||||
|
|
||||||
|
// State class for theme data
|
||||||
|
class ThemeState {
|
||||||
|
final ThemeMode themeMode;
|
||||||
|
final Color seedColor;
|
||||||
|
|
||||||
|
const ThemeState({required this.themeMode, required this.seedColor});
|
||||||
|
|
||||||
|
ThemeState copyWith({ThemeMode? themeMode, Color? seedColor}) {
|
||||||
|
return ThemeState(
|
||||||
|
themeMode: themeMode ?? this.themeMode,
|
||||||
|
seedColor: seedColor ?? this.seedColor,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Light theme definition with dynamic seed color
|
||||||
|
ThemeData createLightTheme(Color seedColor) => ThemeData(
|
||||||
|
colorScheme: ColorScheme.fromSeed(
|
||||||
|
seedColor: seedColor,
|
||||||
|
brightness: Brightness.light,
|
||||||
|
),
|
||||||
|
useMaterial3: true,
|
||||||
|
inputDecorationTheme: InputDecorationTheme(
|
||||||
|
border: OutlineInputBorder(
|
||||||
|
borderRadius: const BorderRadius.all(Radius.circular(12)),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Dark theme definition with dynamic seed color
|
||||||
|
ThemeData createDarkTheme(Color seedColor) => ThemeData(
|
||||||
|
colorScheme: ColorScheme.fromSeed(
|
||||||
|
seedColor: seedColor,
|
||||||
|
brightness: Brightness.dark,
|
||||||
|
),
|
||||||
|
useMaterial3: true,
|
||||||
|
inputDecorationTheme: InputDecorationTheme(
|
||||||
|
border: OutlineInputBorder(
|
||||||
|
borderRadius: const BorderRadius.all(Radius.circular(12)),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
@Riverpod(keepAlive: true)
|
||||||
|
class ThemeNotifier extends _$ThemeNotifier {
|
||||||
|
@override
|
||||||
|
ThemeMode build() {
|
||||||
|
return ThemeMode.system; // Default to system theme
|
||||||
|
}
|
||||||
|
|
||||||
|
void setThemeMode(ThemeMode themeMode) {
|
||||||
|
state = themeMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
void toggleTheme() {
|
||||||
|
switch (state) {
|
||||||
|
case ThemeMode.light:
|
||||||
|
state = ThemeMode.dark;
|
||||||
|
break;
|
||||||
|
case ThemeMode.dark:
|
||||||
|
state = ThemeMode.light;
|
||||||
|
break;
|
||||||
|
case ThemeMode.system:
|
||||||
|
// If system, default to light
|
||||||
|
state = ThemeMode.light;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void setLightTheme() => state = ThemeMode.light;
|
||||||
|
void setDarkTheme() => state = ThemeMode.dark;
|
||||||
|
void setSystemTheme() => state = ThemeMode.system;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Riverpod(keepAlive: true)
|
||||||
|
class SeedColorNotifier extends _$SeedColorNotifier {
|
||||||
|
@override
|
||||||
|
Color build() {
|
||||||
|
return defaultSeedColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setSeedColor(Color color) {
|
||||||
|
state = color;
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateFromAlbumArt(String? imagePath) async {
|
||||||
|
if (imagePath == null || imagePath.isEmpty) {
|
||||||
|
// Reset to default color if no album art
|
||||||
|
state = defaultSeedColor;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Validate that the file exists before attempting to load it
|
||||||
|
final file = File(imagePath);
|
||||||
|
if (!await file.exists()) {
|
||||||
|
// File doesn't exist, reset to default color
|
||||||
|
state = defaultSeedColor;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Additional validation: check if file is readable and not empty
|
||||||
|
final fileStat = await file.stat();
|
||||||
|
if (fileStat.size == 0) {
|
||||||
|
// Empty file, reset to default color
|
||||||
|
state = defaultSeedColor;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final paletteGenerator = await PaletteGenerator.fromImageProvider(
|
||||||
|
FileImage(file),
|
||||||
|
size: const Size(200, 200),
|
||||||
|
maximumColorCount: 20, // Increase color count for better extraction
|
||||||
|
);
|
||||||
|
|
||||||
|
// Use dominant color with better fallback hierarchy
|
||||||
|
Color? extractedColor;
|
||||||
|
if (paletteGenerator.dominantColor != null) {
|
||||||
|
extractedColor = paletteGenerator.dominantColor!.color;
|
||||||
|
} else if (paletteGenerator.vibrantColor != null) {
|
||||||
|
extractedColor = paletteGenerator.vibrantColor!.color;
|
||||||
|
} else if (paletteGenerator.mutedColor != null) {
|
||||||
|
extractedColor = paletteGenerator.mutedColor!.color;
|
||||||
|
} else if (paletteGenerator.paletteColors.isNotEmpty) {
|
||||||
|
// Fallback to the first available color
|
||||||
|
extractedColor = paletteGenerator.paletteColors.first.color;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure we have a valid color, otherwise use default
|
||||||
|
state = extractedColor ?? defaultSeedColor;
|
||||||
|
} catch (e) {
|
||||||
|
// Log the error for debugging (in a real app, you'd use proper logging)
|
||||||
|
// debugPrint('Failed to extract color from album art: $e');
|
||||||
|
// If color extraction fails, reset to default color
|
||||||
|
state = defaultSeedColor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void resetToDefault() {
|
||||||
|
state = defaultSeedColor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Riverpod(keepAlive: true)
|
||||||
|
ThemeData currentTheme(Ref ref) {
|
||||||
|
final themeMode = ref.watch(themeProvider);
|
||||||
|
final seedColor = ref.watch(seedColorProvider);
|
||||||
|
final brightness = themeMode == ThemeMode.system
|
||||||
|
? WidgetsBinding.instance.platformDispatcher.platformBrightness
|
||||||
|
: (themeMode == ThemeMode.dark ? Brightness.dark : Brightness.light);
|
||||||
|
|
||||||
|
return brightness == Brightness.dark
|
||||||
|
? createDarkTheme(seedColor)
|
||||||
|
: createLightTheme(seedColor);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Legacy providers for backward compatibility
|
||||||
|
@Riverpod(keepAlive: true)
|
||||||
|
ThemeData lightTheme(Ref ref) => createLightTheme(ref.watch(seedColorProvider));
|
||||||
|
|
||||||
|
@Riverpod(keepAlive: true)
|
||||||
|
ThemeData darkTheme(Ref ref) => createDarkTheme(ref.watch(seedColorProvider));
|
||||||
239
lib/providers/theme_provider.g.dart
Normal file
239
lib/providers/theme_provider.g.dart
Normal file
@@ -0,0 +1,239 @@
|
|||||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
|
||||||
|
part of 'theme_provider.dart';
|
||||||
|
|
||||||
|
// **************************************************************************
|
||||||
|
// RiverpodGenerator
|
||||||
|
// **************************************************************************
|
||||||
|
|
||||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
// ignore_for_file: type=lint, type=warning
|
||||||
|
|
||||||
|
@ProviderFor(ThemeNotifier)
|
||||||
|
const themeProvider = ThemeNotifierProvider._();
|
||||||
|
|
||||||
|
final class ThemeNotifierProvider
|
||||||
|
extends $NotifierProvider<ThemeNotifier, ThemeMode> {
|
||||||
|
const ThemeNotifierProvider._()
|
||||||
|
: super(
|
||||||
|
from: null,
|
||||||
|
argument: null,
|
||||||
|
retry: null,
|
||||||
|
name: r'themeProvider',
|
||||||
|
isAutoDispose: false,
|
||||||
|
dependencies: null,
|
||||||
|
$allTransitiveDependencies: null,
|
||||||
|
);
|
||||||
|
|
||||||
|
@override
|
||||||
|
String debugGetCreateSourceHash() => _$themeNotifierHash();
|
||||||
|
|
||||||
|
@$internal
|
||||||
|
@override
|
||||||
|
ThemeNotifier create() => ThemeNotifier();
|
||||||
|
|
||||||
|
/// {@macro riverpod.override_with_value}
|
||||||
|
Override overrideWithValue(ThemeMode value) {
|
||||||
|
return $ProviderOverride(
|
||||||
|
origin: this,
|
||||||
|
providerOverride: $SyncValueProvider<ThemeMode>(value),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String _$themeNotifierHash() => r'5ba92ae22271e01ef165260fc7dc1cce6d1d72e0';
|
||||||
|
|
||||||
|
abstract class _$ThemeNotifier extends $Notifier<ThemeMode> {
|
||||||
|
ThemeMode build();
|
||||||
|
@$mustCallSuper
|
||||||
|
@override
|
||||||
|
void runBuild() {
|
||||||
|
final created = build();
|
||||||
|
final ref = this.ref as $Ref<ThemeMode, ThemeMode>;
|
||||||
|
final element =
|
||||||
|
ref.element
|
||||||
|
as $ClassProviderElement<
|
||||||
|
AnyNotifier<ThemeMode, ThemeMode>,
|
||||||
|
ThemeMode,
|
||||||
|
Object?,
|
||||||
|
Object?
|
||||||
|
>;
|
||||||
|
element.handleValue(ref, created);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ProviderFor(SeedColorNotifier)
|
||||||
|
const seedColorProvider = SeedColorNotifierProvider._();
|
||||||
|
|
||||||
|
final class SeedColorNotifierProvider
|
||||||
|
extends $NotifierProvider<SeedColorNotifier, Color> {
|
||||||
|
const SeedColorNotifierProvider._()
|
||||||
|
: super(
|
||||||
|
from: null,
|
||||||
|
argument: null,
|
||||||
|
retry: null,
|
||||||
|
name: r'seedColorProvider',
|
||||||
|
isAutoDispose: false,
|
||||||
|
dependencies: null,
|
||||||
|
$allTransitiveDependencies: null,
|
||||||
|
);
|
||||||
|
|
||||||
|
@override
|
||||||
|
String debugGetCreateSourceHash() => _$seedColorNotifierHash();
|
||||||
|
|
||||||
|
@$internal
|
||||||
|
@override
|
||||||
|
SeedColorNotifier create() => SeedColorNotifier();
|
||||||
|
|
||||||
|
/// {@macro riverpod.override_with_value}
|
||||||
|
Override overrideWithValue(Color value) {
|
||||||
|
return $ProviderOverride(
|
||||||
|
origin: this,
|
||||||
|
providerOverride: $SyncValueProvider<Color>(value),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String _$seedColorNotifierHash() => r'7c7893af5be42f3771a268159e7a5e2597bebc4e';
|
||||||
|
|
||||||
|
abstract class _$SeedColorNotifier extends $Notifier<Color> {
|
||||||
|
Color build();
|
||||||
|
@$mustCallSuper
|
||||||
|
@override
|
||||||
|
void runBuild() {
|
||||||
|
final created = build();
|
||||||
|
final ref = this.ref as $Ref<Color, Color>;
|
||||||
|
final element =
|
||||||
|
ref.element
|
||||||
|
as $ClassProviderElement<
|
||||||
|
AnyNotifier<Color, Color>,
|
||||||
|
Color,
|
||||||
|
Object?,
|
||||||
|
Object?
|
||||||
|
>;
|
||||||
|
element.handleValue(ref, created);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ProviderFor(currentTheme)
|
||||||
|
const currentThemeProvider = CurrentThemeProvider._();
|
||||||
|
|
||||||
|
final class CurrentThemeProvider
|
||||||
|
extends $FunctionalProvider<ThemeData, ThemeData, ThemeData>
|
||||||
|
with $Provider<ThemeData> {
|
||||||
|
const CurrentThemeProvider._()
|
||||||
|
: super(
|
||||||
|
from: null,
|
||||||
|
argument: null,
|
||||||
|
retry: null,
|
||||||
|
name: r'currentThemeProvider',
|
||||||
|
isAutoDispose: false,
|
||||||
|
dependencies: null,
|
||||||
|
$allTransitiveDependencies: null,
|
||||||
|
);
|
||||||
|
|
||||||
|
@override
|
||||||
|
String debugGetCreateSourceHash() => _$currentThemeHash();
|
||||||
|
|
||||||
|
@$internal
|
||||||
|
@override
|
||||||
|
$ProviderElement<ThemeData> $createElement($ProviderPointer pointer) =>
|
||||||
|
$ProviderElement(pointer);
|
||||||
|
|
||||||
|
@override
|
||||||
|
ThemeData create(Ref ref) {
|
||||||
|
return currentTheme(ref);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// {@macro riverpod.override_with_value}
|
||||||
|
Override overrideWithValue(ThemeData value) {
|
||||||
|
return $ProviderOverride(
|
||||||
|
origin: this,
|
||||||
|
providerOverride: $SyncValueProvider<ThemeData>(value),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String _$currentThemeHash() => r'29c9080ae24ba144ebb6e0aac60b16bebcc8a919';
|
||||||
|
|
||||||
|
@ProviderFor(lightTheme)
|
||||||
|
const lightThemeProvider = LightThemeProvider._();
|
||||||
|
|
||||||
|
final class LightThemeProvider
|
||||||
|
extends $FunctionalProvider<ThemeData, ThemeData, ThemeData>
|
||||||
|
with $Provider<ThemeData> {
|
||||||
|
const LightThemeProvider._()
|
||||||
|
: super(
|
||||||
|
from: null,
|
||||||
|
argument: null,
|
||||||
|
retry: null,
|
||||||
|
name: r'lightThemeProvider',
|
||||||
|
isAutoDispose: false,
|
||||||
|
dependencies: null,
|
||||||
|
$allTransitiveDependencies: null,
|
||||||
|
);
|
||||||
|
|
||||||
|
@override
|
||||||
|
String debugGetCreateSourceHash() => _$lightThemeHash();
|
||||||
|
|
||||||
|
@$internal
|
||||||
|
@override
|
||||||
|
$ProviderElement<ThemeData> $createElement($ProviderPointer pointer) =>
|
||||||
|
$ProviderElement(pointer);
|
||||||
|
|
||||||
|
@override
|
||||||
|
ThemeData create(Ref ref) {
|
||||||
|
return lightTheme(ref);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// {@macro riverpod.override_with_value}
|
||||||
|
Override overrideWithValue(ThemeData value) {
|
||||||
|
return $ProviderOverride(
|
||||||
|
origin: this,
|
||||||
|
providerOverride: $SyncValueProvider<ThemeData>(value),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String _$lightThemeHash() => r'be4e02c30ddc60a134ed2a1f7124caf162894889';
|
||||||
|
|
||||||
|
@ProviderFor(darkTheme)
|
||||||
|
const darkThemeProvider = DarkThemeProvider._();
|
||||||
|
|
||||||
|
final class DarkThemeProvider
|
||||||
|
extends $FunctionalProvider<ThemeData, ThemeData, ThemeData>
|
||||||
|
with $Provider<ThemeData> {
|
||||||
|
const DarkThemeProvider._()
|
||||||
|
: super(
|
||||||
|
from: null,
|
||||||
|
argument: null,
|
||||||
|
retry: null,
|
||||||
|
name: r'darkThemeProvider',
|
||||||
|
isAutoDispose: false,
|
||||||
|
dependencies: null,
|
||||||
|
$allTransitiveDependencies: null,
|
||||||
|
);
|
||||||
|
|
||||||
|
@override
|
||||||
|
String debugGetCreateSourceHash() => _$darkThemeHash();
|
||||||
|
|
||||||
|
@$internal
|
||||||
|
@override
|
||||||
|
$ProviderElement<ThemeData> $createElement($ProviderPointer pointer) =>
|
||||||
|
$ProviderElement(pointer);
|
||||||
|
|
||||||
|
@override
|
||||||
|
ThemeData create(Ref ref) {
|
||||||
|
return darkTheme(ref);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// {@macro riverpod.override_with_value}
|
||||||
|
Override overrideWithValue(ThemeData value) {
|
||||||
|
return $ProviderOverride(
|
||||||
|
origin: this,
|
||||||
|
providerOverride: $SyncValueProvider<ThemeData>(value),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String _$darkThemeHash() => r'edc0e042521cc60d1d1bb026100ac46094825f7c';
|
||||||
@@ -680,6 +680,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.2.0"
|
version: "2.2.0"
|
||||||
|
palette_generator:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: palette_generator
|
||||||
|
sha256: "4420f7ccc3f0a4a906144e73f8b6267cd940b64f57a7262e95cb8cec3a8ae0ed"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.3.3+7"
|
||||||
path:
|
path:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
|||||||
@@ -52,6 +52,7 @@ dependencies:
|
|||||||
super_sliver_list: ^0.4.1
|
super_sliver_list: ^0.4.1
|
||||||
http: ^1.0.0
|
http: ^1.0.0
|
||||||
audio_service: ^0.18.18
|
audio_service: ^0.18.18
|
||||||
|
palette_generator: ^0.3.3+4
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import 'package:groovybox/main.dart';
|
|||||||
void main() {
|
void main() {
|
||||||
testWidgets('Counter increments smoke test', (WidgetTester tester) async {
|
testWidgets('Counter increments smoke test', (WidgetTester tester) async {
|
||||||
// Build our app and trigger a frame.
|
// Build our app and trigger a frame.
|
||||||
await tester.pumpWidget(const MyApp());
|
await tester.pumpWidget(const GroovyApp());
|
||||||
|
|
||||||
// Verify that our counter starts at 0.
|
// Verify that our counter starts at 0.
|
||||||
expect(find.text('0'), findsOneWidget);
|
expect(find.text('0'), findsOneWidget);
|
||||||
|
|||||||
Reference in New Issue
Block a user