LCOV - code coverage report
Current view: top level - lib/widgets - profileimage.dart (source / functions) Hit Total Coverage
Test: lcov.info Lines: 40 52 76.9 %
Date: 2026-07-15 19:28:30 Functions: 0 0 -

          Line data    Source code
       1             : import 'dart:io';
       2             : import 'dart:math';
       3             : 
       4             : import 'package:cwtch/cwtch_icons_icons.dart';
       5             : import 'package:flutter/material.dart';
       6             : import 'package:cwtch/themes/opaque.dart';
       7             : import 'package:provider/provider.dart';
       8             : 
       9             : import '../settings.dart';
      10             : 
      11             : class ProfileImage extends StatefulWidget {
      12           1 :   ProfileImage({
      13             :     required this.imagePath,
      14             :     required this.diameter,
      15             :     required this.border,
      16             :     this.badgeCount = 0,
      17             :     required this.badgeColor,
      18             :     required this.badgeTextColor,
      19             :     this.maskOut = false,
      20             :     this.tooltip = "",
      21             :     this.disabled = false,
      22             :     this.badgeEdit = false,
      23             :     this.badgeIcon,
      24             :   });
      25             :   final double diameter;
      26             :   final String imagePath;
      27             :   final Color border;
      28             :   final int badgeCount;
      29             :   final Color badgeColor;
      30             :   final Color badgeTextColor;
      31             :   final bool maskOut;
      32             :   final bool disabled;
      33             :   final bool badgeEdit;
      34             :   final String tooltip;
      35             :   final Widget? badgeIcon;
      36             : 
      37           1 :   @override
      38           1 :   _ProfileImageState createState() => _ProfileImageState();
      39             : }
      40             : 
      41             : class _ProfileImageState extends State<ProfileImage> {
      42           1 :   @override
      43             :   Widget build(BuildContext context) {
      44           3 :     var file = new File(widget.imagePath);
      45           1 :     var image = Image.file(
      46             :       file,
      47           4 :       cacheWidth: (4 * widget.diameter.floor()),
      48             :       filterQuality: FilterQuality.medium,
      49             :       fit: BoxFit.cover,
      50             :       alignment: Alignment.center,
      51             :       // We need some theme specific blending here...we might want to consider making this a theme level attribute
      52           2 :       colorBlendMode: !widget.maskOut
      53           4 :           ? Provider.of<Settings>(context).theme.mode == mode_dark
      54             :                 ? BlendMode.softLight
      55             :                 : BlendMode.darken
      56             :           : BlendMode.srcOut,
      57           3 :       color: Provider.of<Settings>(context).theme.portraitBackgroundColor,
      58             :       isAntiAlias: false,
      59           2 :       width: widget.diameter,
      60           2 :       height: widget.diameter,
      61           0 :       errorBuilder: (context, error, stackTrace) {
      62             :         // on android the above will fail for asset images, in which case try to load them the original way
      63           0 :         return Image.asset(
      64           0 :           widget.imagePath,
      65             :           filterQuality: FilterQuality.medium,
      66             :           // We need some theme specific blending here...we might want to consider making this a theme level attribute
      67           0 :           colorBlendMode: !widget.maskOut
      68           0 :               ? Provider.of<Settings>(context).theme.mode == mode_dark
      69             :                     ? BlendMode.softLight
      70             :                     : BlendMode.darken
      71             :               : BlendMode.srcOut,
      72           0 :           color: Provider.of<Settings>(context).theme.portraitBackgroundColor,
      73             :           isAntiAlias: true,
      74           0 :           width: widget.diameter,
      75           0 :           height: widget.diameter,
      76             :         );
      77             :       },
      78             :     );
      79             : 
      80           1 :     return RepaintBoundary(
      81           1 :       child: Stack(
      82           1 :         children: [
      83           1 :           ClipOval(
      84             :             clipBehavior: Clip.antiAlias,
      85           1 :             child: Container(
      86           2 :               width: widget.diameter,
      87           2 :               height: widget.diameter,
      88           2 :               color: widget.border,
      89           2 :               foregroundDecoration: widget.disabled
      90           0 :                   ? BoxDecoration(
      91           0 :                       color: Provider.of<Settings>(context).theme.portraitBackgroundColor, //Colors.grey,
      92             :                       backgroundBlendMode: BlendMode.color, //saturation,
      93             :                     )
      94             :                   : null,
      95           1 :               child: Padding(
      96             :                 padding: const EdgeInsets.all(2.0), //border size
      97           1 :                 child: ClipOval(
      98             :                   clipBehavior: Clip.antiAlias,
      99           3 :                   child: widget.tooltip == "" ? image : Tooltip(message: widget.tooltip, child: image),
     100             :                 ),
     101             :               ),
     102             :             ),
     103             :           ),
     104             :           // badge
     105           1 :           Visibility(
     106           7 :             visible: widget.badgeIcon != null || widget.badgeEdit || widget.badgeCount > 0,
     107           1 :             child: Positioned(
     108             :               bottom: 0.0,
     109             :               right: 0.0,
     110           1 :               child: CircleAvatar(
     111           4 :                 radius: max(10.0, widget.diameter / 6.0),
     112           2 :                 backgroundColor: widget.badgeColor,
     113           2 :                 child: widget.badgeEdit
     114           0 :                     ? Icon(Icons.edit, color: widget.badgeTextColor)
     115           2 :                     : (widget.badgeIcon != null
     116           0 :                           ? widget.badgeIcon
     117          10 :                           : Text(widget.badgeCount > 99 ? "99+" : widget.badgeCount.toString(), style: TextStyle(color: widget.badgeTextColor, fontSize: 8.0))),
     118             :               ),
     119             :             ),
     120             :           ),
     121             :           // disabled center icon
     122           1 :           Visibility(
     123           2 :             visible: widget.disabled,
     124           1 :             child: Container(
     125           2 :               width: widget.diameter,
     126           2 :               height: widget.diameter,
     127           1 :               child: Center(
     128           7 :                 child: Icon(CwtchIcons.negative_heart_24px, size: widget.diameter / 1.5, color: Provider.of<Settings>(context).theme.portraitOfflineBorderColor),
     129             :               ),
     130             :             ),
     131             :           ),
     132             :         ],
     133             :       ),
     134             :     );
     135             :   }
     136             : }

Generated by: LCOV version 1.14