feat(ui): Lucide migration unit 1 — dependency + heart (#60)
Design system mandates Lucide, not Material. Foundation before the mechanical Icons.* sweep: - pubspec: add flutter_lucide ^1.11.0 - shared/widgets/lucide_heart.dart: LucideHeart renders the verified lucide-icons/lucide heart path as outline (stroke) or filled, via flutter_svg, tinted by color — Lucide ships no filled heart, so the liked state fills the same Lucide silhouette (user-chosen approach) - like_button: use LucideHeart instead of Icons.favorite/_border - notification drawables re-derived from the verbatim Lucide heart path (border = stroke, filled = fill); separators spaced for Android pathData Unit 2 (mechanical Icons.* -> LucideIcons.* sweep) follows once this is CI-green. pubspec.lock regenerated by CI. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -4,7 +4,8 @@
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24"
|
||||
android:tint="#FFFFFFFF">
|
||||
<!-- Lucide "heart" (filled) — same path verbatim from lucide-icons/lucide -->
|
||||
<path
|
||||
android:fillColor="#FFFFFFFF"
|
||||
android:pathData="M12,21.35l-1.45,-1.32C5.4,15.36 2,12.28 2,8.5 2,5.42 4.42,3 7.5,3c1.74,0 3.41,0.81 4.5,2.09C13.09,3.81 14.76,3 16.5,3 19.58,3 22,5.42 22,8.5c0,3.78 -3.4,6.86 -8.55,11.54L12,21.35z"/>
|
||||
android:pathData="M2 9.5a5.5 5.5 0 0 1 9.591 -3.676 .56 .56 0 0 0 .818 0A5.49 5.49 0 0 1 22 9.5c0 2.29 -1.5 4 -3 5.5l-5.492 5.313a2 2 0 0 1 -3 .019L5 15c-1.5 -1.5 -3 -3.2 -3 -5.5"/>
|
||||
</vector>
|
||||
|
||||
@@ -4,7 +4,12 @@
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24"
|
||||
android:tint="#FFFFFFFF">
|
||||
<!-- Lucide "heart" (outline) — path verbatim from lucide-icons/lucide -->
|
||||
<path
|
||||
android:fillColor="#FFFFFFFF"
|
||||
android:pathData="M16.5,3c-1.74,0 -3.41,0.81 -4.5,2.09C10.91,3.81 9.24,3 7.5,3 4.42,3 2,5.42 2,8.5c0,3.78 3.4,6.86 8.55,11.54L12,21.35l1.45,-1.32C18.6,15.36 22,12.28 22,8.5 22,5.42 19.58,3 16.5,3zM12.1,18.55l-0.1,0.1 -0.1,-0.1C7.14,14.24 4,11.39 4,8.5 4,6.5 5.5,5 7.5,5c1.54,0 3.04,0.99 3.57,2.36h1.87C13.46,5.99 14.96,5 16.5,5c2,0 3.5,1.5 3.5,3.5 0,2.89 -3.14,5.74 -7.9,10.05z"/>
|
||||
android:strokeColor="#FFFFFFFF"
|
||||
android:strokeWidth="2"
|
||||
android:strokeLineCap="round"
|
||||
android:strokeLineJoin="round"
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M2 9.5a5.5 5.5 0 0 1 9.591 -3.676 .56 .56 0 0 0 .818 0A5.49 5.49 0 0 1 22 9.5c0 2.29 -1.5 4 -3 5.5l-5.492 5.313a2 2 0 0 1 -3 .019L5 15c-1.5 -1.5 -3 -3.2 -3 -5.5"/>
|
||||
</vector>
|
||||
|
||||
@@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
|
||||
import '../api/endpoints/likes.dart';
|
||||
import '../shared/widgets/lucide_heart.dart';
|
||||
import '../theme/theme_extension.dart';
|
||||
import 'likes_provider.dart';
|
||||
|
||||
@@ -25,8 +26,8 @@ class LikeButton extends ConsumerWidget {
|
||||
orElse: () => false,
|
||||
);
|
||||
return IconButton(
|
||||
icon: Icon(
|
||||
liked ? Icons.favorite : Icons.favorite_border,
|
||||
icon: LucideHeart(
|
||||
filled: liked,
|
||||
color: liked ? fs.accent : fs.ash,
|
||||
size: size,
|
||||
),
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
|
||||
/// The Lucide "heart" silhouette rendered as either an outline (stroke)
|
||||
/// or a solid fill. Lucide ships only an outline heart, so the liked
|
||||
/// state fills the same authoritative Lucide path (verified verbatim
|
||||
/// from lucide-icons/lucide) — keeping both states visually Lucide
|
||||
/// rather than introducing a Material filled heart. Used by LikeButton
|
||||
/// (and, re-derived to a VectorDrawable, by the media notification).
|
||||
class LucideHeart extends StatelessWidget {
|
||||
const LucideHeart({
|
||||
required this.filled,
|
||||
required this.color,
|
||||
this.size = 22,
|
||||
super.key,
|
||||
});
|
||||
|
||||
final bool filled;
|
||||
final Color color;
|
||||
final double size;
|
||||
|
||||
static const _path =
|
||||
'M2 9.5a5.5 5.5 0 0 1 9.591-3.676.56.56 0 0 0 .818 0A5.49 5.49 0 0 1 '
|
||||
'22 9.5c0 2.29-1.5 4-3 5.5l-5.492 5.313a2 2 0 0 1-3 .019L5 15c-1.5-1.5'
|
||||
'-3-3.2-3-5.5';
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final svg = filled
|
||||
? '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">'
|
||||
'<path d="$_path" fill="currentColor"/></svg>'
|
||||
: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">'
|
||||
'<path d="$_path" fill="none" stroke="currentColor" '
|
||||
'stroke-width="2" stroke-linecap="round" '
|
||||
'stroke-linejoin="round"/></svg>';
|
||||
return SvgPicture.string(
|
||||
svg,
|
||||
width: size,
|
||||
height: size,
|
||||
colorFilter: ColorFilter.mode(color, BlendMode.srcIn),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -22,6 +22,9 @@ dependencies:
|
||||
flutter_secure_storage: ^10.1.0
|
||||
go_router: ^17.2.3
|
||||
flutter_svg: ^2.0.16
|
||||
# Lucide icon set (design system mandates Lucide, not Material).
|
||||
# Icons exposed as LucideIcons.<snake_case> IconData usable in Icon().
|
||||
flutter_lucide: ^1.11.0
|
||||
google_fonts: ^8.1.0
|
||||
# 10.x conflicts with flutter_secure_storage 10.x on win32. Hold at 8.3.1
|
||||
# until either lib bumps win32 to 6.x.
|
||||
|
||||
Reference in New Issue
Block a user