add tag color

Signed-off-by: 21pages <pages21@163.com>
This commit is contained in:
21pages 2023-08-13 18:13:06 +08:00
parent ae640dda56
commit a5bba37cae
3 changed files with 139 additions and 18 deletions

View File

@ -1074,6 +1074,30 @@ Color str2color(String str, [alpha = 0xFF]) {
return Color((hash & 0xFF7FFF) | (alpha << 24)); return Color((hash & 0xFF7FFF) | (alpha << 24));
} }
Color str2color2(String str, [alpha = 0xFF]) {
List<Color> colorList = [
Colors.red,
Colors.green,
Colors.blue,
Colors.orange,
Colors.yellow,
Colors.purple,
Colors.grey,
Colors.cyan,
Colors.lime,
Colors.teal,
Colors.pink,
Colors.indigo,
Colors.brown,
];
var hash = 0;
for (var i = 0; i < str.length; i++) {
hash += str.codeUnitAt(i);
}
hash = hash % colorList.length;
return colorList[hash].withAlpha(alpha);
}
const K = 1024; const K = 1024;
const M = K * K; const M = K * K;
const G = M * K; const G = M * K;

View File

@ -449,26 +449,43 @@ class AddressBookTag extends StatelessWidget {
pos = RelativeRect.fromLTRB(x, y, x, y); pos = RelativeRect.fromLTRB(x, y, x, y);
} }
const double radius = 8;
return GestureDetector( return GestureDetector(
onTap: onTap, onTap: onTap,
onTapDown: showActionMenu ? setPosition : null, onTapDown: showActionMenu ? setPosition : null,
onSecondaryTapDown: showActionMenu ? setPosition : null, onSecondaryTapDown: showActionMenu ? setPosition : null,
onSecondaryTap: showActionMenu ? () => _showMenu(context, pos) : null, onSecondaryTap: showActionMenu ? () => _showMenu(context, pos) : null,
onLongPress: showActionMenu ? () => _showMenu(context, pos) : null, onLongPress: showActionMenu ? () => _showMenu(context, pos) : null,
child: Obx( child: Obx(() => Container(
() => Container( decoration: BoxDecoration(
decoration: BoxDecoration( color: tags.contains(name)
color: tags.contains(name) ? str2color2(name, 0xFF)
? Colors.blue : Theme.of(context).colorScheme.background,
: Theme.of(context).colorScheme.background, borderRadius: BorderRadius.circular(4)),
borderRadius: BorderRadius.circular(6)), margin: const EdgeInsets.symmetric(horizontal: 4.0, vertical: 4.0),
margin: const EdgeInsets.symmetric(horizontal: 4.0, vertical: 8.0), padding: const EdgeInsets.symmetric(vertical: 2.0, horizontal: 6.0),
padding: const EdgeInsets.symmetric(vertical: 2.0, horizontal: 8.0), child: IntrinsicWidth(
child: Text(name, child: Row(
style: children: [
TextStyle(color: tags.contains(name) ? Colors.white : null)), Container(
), width: radius,
), height: radius,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: tags.contains(name)
? Colors.white
: str2color2(name)),
).marginOnly(right: radius / 2),
Expanded(
child: Text(name,
style: TextStyle(
overflow: TextOverflow.ellipsis,
color: tags.contains(name) ? Colors.white : null)),
),
],
),
),
)),
); );
} }

View File

@ -14,6 +14,7 @@ import '../../models/peer_model.dart';
import '../../models/platform_model.dart'; import '../../models/platform_model.dart';
import '../../desktop/widgets/material_mod_popup_menu.dart' as mod_menu; import '../../desktop/widgets/material_mod_popup_menu.dart' as mod_menu;
import '../../desktop/widgets/popup_menu.dart'; import '../../desktop/widgets/popup_menu.dart';
import 'dart:math' as math;
typedef PopupMenuEntryBuilder = Future<List<mod_menu.PopupMenuEntry<String>>> typedef PopupMenuEntryBuilder = Future<List<mod_menu.PopupMenuEntry<String>>>
Function(BuildContext); Function(BuildContext);
@ -159,7 +160,7 @@ class _PeerCardState extends State<_PeerCard>
fontSize: 11, fontSize: 11,
color: Theme.of(context).textTheme.titleLarge?.color?.withOpacity(0.6)); color: Theme.of(context).textTheme.titleLarge?.color?.withOpacity(0.6));
final alias = bind.mainGetPeerOptionSync(id: peer.id, key: 'alias'); final alias = bind.mainGetPeerOptionSync(id: peer.id, key: 'alias');
return Obx( final child = Obx(
() => Container( () => Container(
foregroundDecoration: deco.value, foregroundDecoration: deco.value,
child: Row( child: Row(
@ -199,7 +200,7 @@ class _PeerCardState extends State<_PeerCard>
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
style: Theme.of(context).textTheme.titleSmall, style: Theme.of(context).textTheme.titleSmall,
)), )),
]).marginOnly(bottom: 2), ]).marginOnly(bottom: 0, top: 2),
Align( Align(
alignment: Alignment.centerLeft, alignment: Alignment.centerLeft,
child: Text( child: Text(
@ -221,13 +222,29 @@ class _PeerCardState extends State<_PeerCard>
), ),
), ),
); );
final colors = _frontN(peer.tags, 25).map((e) => str2color2(e)).toList();
return Tooltip(
message: peer.tags.isNotEmpty
? '${translate('Tags')}: ${peer.tags.join(', ')}'
: '',
child: Stack(children: [
child,
Positioned(
top: 2,
right: 10,
child: CustomPaint(
painter: TagPainter(radius: 3, colors: colors),
),
)
]),
);
} }
Widget _buildPeerCard( Widget _buildPeerCard(
BuildContext context, Peer peer, Rx<BoxDecoration?> deco) { BuildContext context, Peer peer, Rx<BoxDecoration?> deco) {
final name = final name =
'${peer.username}${peer.username.isNotEmpty && peer.hostname.isNotEmpty ? '@' : ''}${peer.hostname}'; '${peer.username}${peer.username.isNotEmpty && peer.hostname.isNotEmpty ? '@' : ''}${peer.hostname}';
return Card( final child = Card(
color: Colors.transparent, color: Colors.transparent,
elevation: 0, elevation: 0,
margin: EdgeInsets.zero, margin: EdgeInsets.zero,
@ -253,7 +270,7 @@ class _PeerCardState extends State<_PeerCard>
padding: const EdgeInsets.all(6), padding: const EdgeInsets.all(6),
child: child:
getPlatformImage(peer.platform, size: 60), getPlatformImage(peer.platform, size: 60),
), ).marginOnly(top: 4),
Row( Row(
children: [ children: [
Expanded( Expanded(
@ -304,6 +321,31 @@ class _PeerCardState extends State<_PeerCard>
), ),
), ),
); );
final colors = _frontN(peer.tags, 25).map((e) => str2color2(e)).toList();
return Tooltip(
message: peer.tags.isNotEmpty
? '${translate('Tags')}: ${peer.tags.join(', ')}'
: '',
child: Stack(children: [
child,
Positioned(
top: 4,
right: 12,
child: CustomPaint(
painter: TagPainter(radius: 4, colors: colors),
),
)
]),
);
}
List _frontN<T>(List list, int n) {
if (list.length <= n) {
return list;
} else {
return list.sublist(0, n);
}
} }
Widget checkBoxOrActionMoreMobile(Peer peer) { Widget checkBoxOrActionMoreMobile(Peer peer) {
@ -1193,3 +1235,41 @@ Widget build_more(BuildContext context, {bool invert = false}) {
?.color ?.color
?.withOpacity(0.5))))); ?.withOpacity(0.5)))));
} }
class TagPainter extends CustomPainter {
final double radius;
late final List<Color> colors;
TagPainter({required this.radius, required List<Color> colors}) {
this.colors = colors.reversed.toList();
}
@override
void paint(Canvas canvas, Size size) {
double x = 0;
double y = radius;
for (int i = 0; i < colors.length; i++) {
Paint paint = Paint();
paint.color = colors[i];
x -= radius + 1;
if (i == colors.length - 1) {
canvas.drawCircle(Offset(x, y), radius, paint);
} else {
Path path = Path();
path.addArc(Rect.fromCircle(center: Offset(x, y), radius: radius),
math.pi * 4 / 3, math.pi * 4 / 3);
path.addArc(
Rect.fromCircle(center: Offset(x - radius, y), radius: radius),
math.pi * 5 / 3,
math.pi * 2 / 3);
path.fillType = PathFillType.evenOdd;
canvas.drawPath(path, paint);
}
}
}
@override
bool shouldRepaint(covariant CustomPainter oldDelegate) {
return true;
}
}