From a2c2bfe585c40529499de0f1aac91ec5a14dd295 Mon Sep 17 00:00:00 2001 From: LittleSheep Date: Sun, 21 Sep 2025 14:50:30 +0800 Subject: [PATCH] :recycle: Replace the pattle_generator --- ios/Podfile.lock | 16 +++++----- lib/screens/account/profile.dart | 8 ++--- lib/screens/posts/pub_profile.dart | 8 ++--- lib/screens/realm/realm_detail.dart | 8 ++--- lib/screens/settings.dart | 16 +++++----- lib/services/color_extraction.dart | 49 +++++++++++++++++++++++++++++ pubspec.lock | 10 +----- pubspec.yaml | 3 +- 8 files changed, 81 insertions(+), 37 deletions(-) create mode 100644 lib/services/color_extraction.dart diff --git a/ios/Podfile.lock b/ios/Podfile.lock index c4c386c2..987e4302 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -149,9 +149,9 @@ PODS: - flutter_udid (0.0.1): - Flutter - SAMKeychain - - flutter_webrtc (1.1.0): + - flutter_webrtc (1.2.0): - Flutter - - WebRTC-SDK (= 137.7151.03) + - WebRTC-SDK (= 137.7151.04) - gal (1.0.0): - Flutter - FlutterMacOS @@ -219,7 +219,7 @@ PODS: - livekit_client (2.5.0): - Flutter - flutter_webrtc - - WebRTC-SDK (= 137.7151.03) + - WebRTC-SDK (= 137.7151.04) - local_auth_darwin (0.0.1): - Flutter - FlutterMacOS @@ -299,7 +299,7 @@ PODS: - Flutter - wakelock_plus (0.0.1): - Flutter - - WebRTC-SDK (137.7151.03) + - WebRTC-SDK (137.7151.04) DEPENDENCIES: - Alamofire @@ -499,7 +499,7 @@ SPEC CHECKSUMS: flutter_secure_storage: 1ed9476fba7e7a782b22888f956cce43e2c62f13 flutter_timezone: 7c838e17ffd4645d261e87037e5bebf6d38fe544 flutter_udid: f7c3884e6ec2951efe4f9de082257fc77c4d15e9 - flutter_webrtc: b0b2e04411747142962164a1cfa43a1af9a0afac + flutter_webrtc: c3e21fc0dcd9d8eb246ae4d5256fcbeb2f5ecd22 gal: baecd024ebfd13c441269ca7404792a7152fde89 GoogleAdsOnDeviceConversion: 9090c435cde08903e8dd1ba2c77fbec9e46d9afe GoogleAppMeasurement: 09f341dfa8527d1612a09cbfe809a242c0b737af @@ -508,8 +508,8 @@ SPEC CHECKSUMS: image_picker_ios: 7fe1ff8e34c1790d6fff70a32484959f563a928a irondash_engine_context: 8e58ca8e0212ee9d1c7dc6a42121849986c88486 Kingfisher: ff0d31a1f07bdff6a1ebb3ba08b8e6e567b6500c - livekit_client: f810c81bbbc229a84f60b09e66603ac4e93f7599 - local_auth_darwin: d2e8c53ef0c4f43c646462e3415432c4dab3ae19 + livekit_client: a6f5fa86ac28ccd7ded53626a5379961db311ab4 + local_auth_darwin: c3ee6cce0a8d56be34c8ccb66ba31f7f180aaebb media_kit_libs_ios_video: 5a18affdb97d1f5d466dc79988b13eff6c5e2854 media_kit_video: 1746e198cb697d1ffb734b1d05ec429d1fcd1474 nanopb: fad817b59e0457d11a5dfbde799381cd727c1275 @@ -536,7 +536,7 @@ SPEC CHECKSUMS: url_launcher_ios: 694010445543906933d732453a59da0a173ae33d volume_controller: 3657a1f65bedb98fa41ff7dc5793537919f31b12 wakelock_plus: e29112ab3ef0b318e58cfa5c32326458be66b556 - WebRTC-SDK: 69d4e56b0b4b27d788e87bab9b9a1326ed05b1e3 + WebRTC-SDK: 40d4f5ba05cadff14e4db5614aec402a633f007e PODFILE CHECKSUM: c818292390b02fa379036ea099713a332bd7193f diff --git a/lib/screens/account/profile.dart b/lib/screens/account/profile.dart index 7cc61977..d7f06301 100644 --- a/lib/screens/account/profile.dart +++ b/lib/screens/account/profile.dart @@ -32,7 +32,7 @@ import 'package:island/widgets/content/cloud_files.dart'; import 'package:island/widgets/content/markdown.dart'; import 'package:island/widgets/safety/abuse_report_helper.dart'; import 'package:material_symbols_icons/symbols.dart'; -import 'package:palette_generator/palette_generator.dart'; +import 'package:island/services/color_extraction.dart'; import 'package:riverpod_annotation/riverpod_annotation.dart'; import 'package:share_plus/share_plus.dart'; import 'package:styled_widget/styled_widget.dart'; @@ -581,14 +581,14 @@ Future accountAppbarForcegroundColor(Ref ref, String uname) async { try { final account = await ref.watch(accountProvider(uname).future); if (account.profile.background == null) return null; - final palette = await PaletteGenerator.fromImageProvider( + final colors = await ColorExtractionService.getColorsFromImage( CloudImageWidget.provider( fileId: account.profile.background!.id, serverUrl: ref.watch(serverUrlProvider), ), ); - final dominantColor = palette.dominantColor?.color; - if (dominantColor == null) return null; + if (colors.isEmpty) return null; + final dominantColor = colors.first; return dominantColor.computeLuminance() > 0.5 ? Colors.black : Colors.white; } catch (_) { return null; diff --git a/lib/screens/posts/pub_profile.dart b/lib/screens/posts/pub_profile.dart index 567f028f..a005287d 100644 --- a/lib/screens/posts/pub_profile.dart +++ b/lib/screens/posts/pub_profile.dart @@ -21,7 +21,7 @@ import 'package:island/widgets/content/cloud_files.dart'; import 'package:island/widgets/content/markdown.dart'; import 'package:island/widgets/post/post_list.dart'; import 'package:material_symbols_icons/symbols.dart'; -import 'package:palette_generator/palette_generator.dart'; +import 'package:island/services/color_extraction.dart'; import 'package:riverpod_annotation/riverpod_annotation.dart'; import 'package:styled_widget/styled_widget.dart'; @@ -278,14 +278,14 @@ Future publisherAppbarForcegroundColor(Ref ref, String pubName) async { try { final publisher = await ref.watch(publisherProvider(pubName).future); if (publisher.background == null) return null; - final palette = await PaletteGenerator.fromImageProvider( + final colors = await ColorExtractionService.getColorsFromImage( CloudImageWidget.provider( fileId: publisher.background!.id, serverUrl: ref.watch(serverUrlProvider), ), ); - final dominantColor = palette.dominantColor?.color; - if (dominantColor == null) return null; + if (colors.isEmpty) return null; + final dominantColor = colors.first; return dominantColor.computeLuminance() > 0.5 ? Colors.black : Colors.white; } catch (_) { return null; diff --git a/lib/screens/realm/realm_detail.dart b/lib/screens/realm/realm_detail.dart index de57f731..bda9f203 100644 --- a/lib/screens/realm/realm_detail.dart +++ b/lib/screens/realm/realm_detail.dart @@ -8,7 +8,7 @@ import 'package:island/services/responsive.dart'; import 'package:island/widgets/account/account_pfc.dart'; import 'package:island/widgets/account/status.dart'; import 'package:island/widgets/post/post_list.dart'; -import 'package:palette_generator/palette_generator.dart'; +import 'package:island/services/color_extraction.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:gap/gap.dart'; import 'package:go_router/go_router.dart'; @@ -32,14 +32,14 @@ part 'realm_detail.g.dart'; Future realmAppbarForegroundColor(Ref ref, String realmSlug) async { final realm = await ref.watch(realmProvider(realmSlug).future); if (realm?.background == null) return null; - final palette = await PaletteGenerator.fromImageProvider( + final colors = await ColorExtractionService.getColorsFromImage( CloudImageWidget.provider( fileId: realm!.background!.id, serverUrl: ref.watch(serverUrlProvider), ), ); - final dominantColor = palette.dominantColor?.color; - if (dominantColor == null) return null; + if (colors.isEmpty) return null; + final dominantColor = colors.first; return dominantColor.computeLuminance() > 0.5 ? Colors.black : Colors.white; } diff --git a/lib/screens/settings.dart b/lib/screens/settings.dart index f92e50bc..c818d5ac 100644 --- a/lib/screens/settings.dart +++ b/lib/screens/settings.dart @@ -12,11 +12,11 @@ import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:image_picker/image_picker.dart'; import 'package:island/pods/network.dart'; +import 'package:island/services/color_extraction.dart'; import 'package:island/services/responsive.dart'; import 'package:island/widgets/alert.dart'; import 'package:island/widgets/app_scaffold.dart'; import 'package:material_symbols_icons/symbols.dart'; -import 'package:palette_generator/palette_generator.dart'; import 'package:path_provider/path_provider.dart'; import 'package:styled_widget/styled_widget.dart'; import 'package:island/pods/config.dart'; @@ -293,24 +293,26 @@ class SettingsScreen extends HookConsumerWidget { trailing: const Icon(Symbols.chevron_right), onTap: () async { showLoadingModal(context); - final palette = await PaletteGenerator.fromImageProvider( + final colors = await ColorExtractionService.getColorsFromImage( FileImage( File('${docBasepath.value}/$kAppBackgroundImagePath'), ), ); - if (palette.darkVibrantColor == null || - palette.lightVibrantColor == null) { + if (colors.isEmpty) { if (context.mounted) hideLoadingModal(context); showErrorAlert( - 'Unable to calculate the domiant color of the background image.', + 'Unable to calculate the dominant color of the background image.', ); return; } if (!context.mounted) return; + final colorScheme = ColorScheme.fromSeed( + seedColor: colors.first, + ); final color = MediaQuery.of(context).platformBrightness == Brightness.dark - ? palette.darkVibrantColor!.color - : palette.lightVibrantColor!.color; + ? colorScheme.primary + : colorScheme.primary; ref .read(appSettingsNotifierProvider.notifier) .setAppColorScheme(color.value); diff --git a/lib/services/color_extraction.dart b/lib/services/color_extraction.dart new file mode 100644 index 00000000..5afa09a1 --- /dev/null +++ b/lib/services/color_extraction.dart @@ -0,0 +1,49 @@ +import 'package:flutter/widgets.dart'; +import 'package:image/image.dart' as img; +import 'package:material_color_utilities/material_color_utilities.dart' as mcu; + +class ColorExtractionService { + /// Extracts dominant colors from an image provider. + /// Returns a list of colors suitable for UI theming. + static Future> getColorsFromImage(ImageProvider provider) async { + try { + if (provider is FileImage) { + final bytes = await provider.file.readAsBytes(); + final image = img.decodeImage(bytes); + if (image == null) return []; + final Map colorToCount = {}; + for (int y = 0; y < image.height; y++) { + for (int x = 0; x < image.width; x++) { + final pixel = image.getPixel(x, y) as int; + final r = (pixel >> 24) & 0xff; + final g = (pixel >> 16) & 0xff; + final b = (pixel >> 8) & 0xff; + final a = pixel & 0xff; + if (a == 0) continue; + final argb = (a << 24) | (r << 16) | (g << 8) | b; + colorToCount[argb] = (colorToCount[argb] ?? 0) + 1; + } + } + final List filteredResults = mcu.Score.score( + colorToCount, + desired: 1, + filter: true, + ); + final List scoredResults = mcu.Score.score( + colorToCount, + desired: 4, + filter: false, + ); + return { + ...filteredResults, + ...scoredResults, + }.toList().map((argb) => Color(argb)).toList(); + } else { + return []; + } + } catch (e) { + debugPrint('Error getting colors from image: $e'); + return []; + } + } +} diff --git a/pubspec.lock b/pubspec.lock index 60acf6fe..a0e8cc15 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -1270,7 +1270,7 @@ packages: source: hosted version: "4.1.2" image: - dependency: transitive + dependency: "direct main" description: name: image sha256: "4e973fcf4caae1a4be2fa0a13157aa38a8f9cb049db6529aa00b4d71abc4d928" @@ -1717,14 +1717,6 @@ packages: url: "https://pub.dev" source: hosted version: "3.2.1" - palette_generator: - dependency: "direct main" - description: - name: palette_generator - sha256: "4420f7ccc3f0a4a906144e73f8b6267cd940b64f57a7262e95cb8cec3a8ae0ed" - url: "https://pub.dev" - source: hosted - version: "0.3.3+7" pasteboard: dependency: "direct main" description: diff --git a/pubspec.yaml b/pubspec.yaml index dd311f26..60deb900 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -106,10 +106,11 @@ dependencies: livekit_client: ^2.5.1 pasteboard: ^0.4.0 flutter_colorpicker: ^1.1.0 + image: ^4.2.0 record: ^6.1.1 qr_flutter: ^4.1.0 flutter_otp_text_field: ^1.5.1+1 - palette_generator: ^0.3.3+7 + flutter_popup_card: ^0.0.6 timezone: ^0.10.1 flutter_timezone: ^5.0.0