diff --git a/lib/screens/account.dart b/lib/screens/account.dart index 7cf67326..4086b04d 100644 --- a/lib/screens/account.dart +++ b/lib/screens/account.dart @@ -16,6 +16,7 @@ import 'package:island/widgets/account/leveling_progress.dart'; import 'package:island/widgets/alert.dart'; import 'package:island/widgets/app_scaffold.dart'; import 'package:island/widgets/content/cloud_files.dart'; +import 'package:island/widgets/content/profile_decoration.dart'; import 'package:island/widgets/debug_sheet.dart'; import 'package:material_symbols_icons/symbols.dart'; import 'package:styled_widget/styled_widget.dart'; @@ -98,6 +99,10 @@ class AccountScreen extends HookConsumerWidget { child: ProfilePictureWidget( file: user.value?.profile.picture, radius: 32, + decoration: ProfileDecoration( + text: '#OpenToWork', + color: Colors.green, + ), ), onTap: () { context.pushNamed( @@ -331,23 +336,21 @@ class AccountScreen extends HookConsumerWidget { if (availableWidth > totalMin) { return Row( spacing: 8, - children: - children - .map((child) => Expanded(child: child)) - .toList(), + children: children + .map((child) => Expanded(child: child)) + .toList(), ).padding(horizontal: 12).height(48); } else { return SingleChildScrollView( scrollDirection: Axis.horizontal, child: Row( spacing: 8, - children: - children - .map( - (child) => - SizedBox(width: minWidth, child: child), - ) - .toList(), + children: children + .map( + (child) => + SizedBox(width: minWidth, child: child), + ) + .toList(), ).padding(horizontal: 12), ).height(48); } @@ -495,97 +498,96 @@ class _UnauthorizedAccountScreen extends StatelessWidget { Widget build(BuildContext context) { return AppScaffold( appBar: AppBar(title: const Text('account').tr()), - body: - ConstrainedBox( - constraints: const BoxConstraints(maxWidth: 360), - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, + body: ConstrainedBox( + constraints: const BoxConstraints(maxWidth: 360), + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Padding( + padding: const EdgeInsets.symmetric(horizontal: 24), + child: Card( + child: InkWell( + borderRadius: const BorderRadius.all(Radius.circular(8)), + onTap: () { + context.pushNamed('createAccount'); + }, + child: Padding( + padding: const EdgeInsets.all(16), + child: Column( + children: [ + Icon(Symbols.person_add, size: 48), + const SizedBox(height: 8), + Text('createAccount').tr().bold(), + Text('createAccountDescription').tr(), + ], + ), + ), + ), + ), + ), + const Gap(8), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 24), + child: Card( + child: InkWell( + borderRadius: const BorderRadius.all(Radius.circular(8)), + onTap: () { + context.pushNamed('login'); + }, + child: Padding( + padding: const EdgeInsets.all(16), + child: Column( + children: [ + Icon(Symbols.login, size: 48), + const SizedBox(height: 8), + Text('login').tr().bold(), + Text('loginDescription').tr(), + ], + ), + ), + ), + ), + ), + const Gap(8), + Row( mainAxisAlignment: MainAxisAlignment.center, - children: [ - Padding( - padding: const EdgeInsets.symmetric(horizontal: 24), - child: Card( - child: InkWell( - borderRadius: const BorderRadius.all(Radius.circular(8)), - onTap: () { - context.pushNamed('createAccount'); - }, - child: Padding( - padding: const EdgeInsets.all(16), - child: Column( - children: [ - Icon(Symbols.person_add, size: 48), - const SizedBox(height: 8), - Text('createAccount').tr().bold(), - Text('createAccountDescription').tr(), - ], - ), - ), - ), - ), + children: [ + IconButton( + onPressed: () { + context.pushNamed('about'); + }, + iconSize: 18, + color: Theme.of(context).colorScheme.secondary, + icon: const Icon(Icons.info, fill: 1), + tooltip: 'about'.tr(), ), - const Gap(8), - Padding( - padding: const EdgeInsets.symmetric(horizontal: 24), - child: Card( - child: InkWell( - borderRadius: const BorderRadius.all(Radius.circular(8)), - onTap: () { - context.pushNamed('login'); - }, - child: Padding( - padding: const EdgeInsets.all(16), - child: Column( - children: [ - Icon(Symbols.login, size: 48), - const SizedBox(height: 8), - Text('login').tr().bold(), - Text('loginDescription').tr(), - ], - ), - ), - ), - ), + IconButton( + icon: const Icon(Icons.bug_report, fill: 1), + onPressed: () { + showModalBottomSheet( + context: context, + builder: (context) => DebugSheet(), + ); + }, + iconSize: 18, + color: Theme.of(context).colorScheme.secondary, + tooltip: 'debugOptions'.tr(), ), - const Gap(8), - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - IconButton( - onPressed: () { - context.pushNamed('about'); - }, - iconSize: 18, - color: Theme.of(context).colorScheme.secondary, - icon: const Icon(Icons.info, fill: 1), - tooltip: 'about'.tr(), - ), - IconButton( - icon: const Icon(Icons.bug_report, fill: 1), - onPressed: () { - showModalBottomSheet( - context: context, - builder: (context) => DebugSheet(), - ); - }, - iconSize: 18, - color: Theme.of(context).colorScheme.secondary, - tooltip: 'debugOptions'.tr(), - ), - IconButton( - onPressed: () { - context.pushNamed('settings'); - }, - icon: const Icon(Icons.settings, fill: 1), - iconSize: 18, - color: Theme.of(context).colorScheme.secondary, - tooltip: 'appSettings'.tr(), - ), - ], + IconButton( + onPressed: () { + context.pushNamed('settings'); + }, + icon: const Icon(Icons.settings, fill: 1), + iconSize: 18, + color: Theme.of(context).colorScheme.secondary, + tooltip: 'appSettings'.tr(), ), ], ), - ).center(), + ], + ), + ).center(), ); } } diff --git a/lib/widgets/content/cloud_files.dart b/lib/widgets/content/cloud_files.dart index bd9c2d0e..e49839ac 100644 --- a/lib/widgets/content/cloud_files.dart +++ b/lib/widgets/content/cloud_files.dart @@ -9,8 +9,11 @@ import 'package:island/models/file.dart'; import 'package:island/pods/config.dart'; import 'package:island/services/time.dart'; import 'package:island/utils/format.dart'; +import 'package:island/widgets/content/profile_decoration.dart'; import 'package:material_symbols_icons/symbols.dart'; import 'package:styled_widget/styled_widget.dart'; +import 'dart:math' as math; +import 'dart:ui' as ui; import 'package:island/widgets/data_saving_gate.dart'; import 'file_viewer_contents.dart'; @@ -258,17 +261,15 @@ class CloudFileWidget extends HookConsumerWidget { var content = switch (item.mimeType?.split('/').firstOrNull) { 'image' => AspectRatio( aspectRatio: ratio, - child: - (useInternalGate && dataSaving && !unlocked.value) - ? dataPlaceHolder(Symbols.image) - : cloudImage(), + child: (useInternalGate && dataSaving && !unlocked.value) + ? dataPlaceHolder(Symbols.image) + : cloudImage(), ), 'video' => AspectRatio( aspectRatio: ratio, - child: - (useInternalGate && dataSaving && !unlocked.value) - ? dataPlaceHolder(Symbols.play_arrow) - : cloudVideo(), + child: (useInternalGate && dataSaving && !unlocked.value) + ? dataPlaceHolder(Symbols.play_arrow) + : cloudVideo(), ), 'audio' => AudioFileContent(item: item, uri: uri), _ => Builder( @@ -383,10 +384,9 @@ class CloudVideoWidget extends HookConsumerWidget { final serverUrl = ref.watch(serverUrlProvider); final uri = '$serverUrl/drive/files/${item.id}'; - var ratio = - item.fileMeta?['ratio'] is num - ? item.fileMeta!['ratio'].toDouble() - : 1.0; + var ratio = item.fileMeta?['ratio'] is num + ? item.fileMeta!['ratio'].toDouble() + : 1.0; if (ratio == 0) ratio = 1.0; if (open.value) { @@ -533,10 +533,9 @@ class CloudImageWidget extends ConsumerWidget { return AspectRatio( aspectRatio: aspectRatio, - child: - file != null - ? CloudFileWidget(item: file!, fit: fit) - : UniversalImage(uri: uri, blurHash: blurHash, fit: fit), + child: file != null + ? CloudFileWidget(item: file!, fit: fit) + : UniversalImage(uri: uri, blurHash: blurHash, fit: fit), ); } @@ -545,10 +544,9 @@ class CloudImageWidget extends ConsumerWidget { required String serverUrl, bool original = false, }) { - final uri = - original - ? '$serverUrl/drive/files/$fileId?original=true' - : '$serverUrl/drive/files/$fileId'; + final uri = original + ? '$serverUrl/drive/files/$fileId?original=true' + : '$serverUrl/drive/files/$fileId'; return CachedNetworkImageProvider(uri); } } @@ -560,6 +558,7 @@ class ProfilePictureWidget extends ConsumerWidget { final double? borderRadius; final IconData? fallbackIcon; final Color? fallbackColor; + final ProfileDecoration? decoration; const ProfilePictureWidget({ super.key, this.fileId, @@ -568,6 +567,7 @@ class ProfilePictureWidget extends ConsumerWidget { this.borderRadius, this.fallbackIcon, this.fallbackColor, + this.decoration, }); @override @@ -575,36 +575,49 @@ class ProfilePictureWidget extends ConsumerWidget { final serverUrl = ref.watch(serverUrlProvider); final String? id = file?.id ?? fileId; - final fallback = - Icon( - fallbackIcon ?? Symbols.account_circle, - size: radius, - color: - fallbackColor ?? Theme.of(context).colorScheme.onPrimaryContainer, - ).center(); + final fallback = Icon( + fallbackIcon ?? Symbols.account_circle, + size: radius, + color: fallbackColor ?? Theme.of(context).colorScheme.onPrimaryContainer, + ).center(); + + final image = id == null + ? fallback + : DataSavingGate( + bypass: true, + placeholder: fallback, + content: () => UniversalImage( + uri: '$serverUrl/drive/files/$id', + fit: BoxFit.cover, + ), + ); + + Widget content = Container( + width: radius * 2, + height: radius * 2, + color: Theme.of(context).colorScheme.primaryContainer, + child: decoration != null + ? Stack( + fit: StackFit.expand, + children: [ + image, + CustomPaint( + painter: _ProfileDecorationPainter( + text: decoration!.text, + color: decoration!.color, + textColor: decoration!.textColor ?? Colors.white, + ), + ), + ], + ) + : image, + ); return ClipRRect( - borderRadius: - borderRadius == null - ? BorderRadius.all(Radius.circular(radius)) - : BorderRadius.all(Radius.circular(borderRadius!)), - child: Container( - width: radius * 2, - height: radius * 2, - color: Theme.of(context).colorScheme.primaryContainer, - child: - id == null - ? fallback - : DataSavingGate( - bypass: true, - placeholder: fallback, - content: - () => UniversalImage( - uri: '$serverUrl/drive/files/$id', - fit: BoxFit.cover, - ), - ), - ), + borderRadius: borderRadius == null + ? BorderRadius.all(Radius.circular(radius)) + : BorderRadius.all(Radius.circular(borderRadius!)), + child: content, ); } } @@ -716,32 +729,29 @@ class SplitAvatarWidget extends ConsumerWidget { ), ), Expanded( - child: - filesId.length > 4 - ? Container( - color: - Theme.of( + child: filesId.length > 4 + ? Container( + color: Theme.of( + context, + ).colorScheme.primaryContainer, + child: Center( + child: Text( + '+${filesId.length - 3}', + style: TextStyle( + fontSize: radius * 0.4, + color: Theme.of( context, - ).colorScheme.primaryContainer, - child: Center( - child: Text( - '+${filesId.length - 3}', - style: TextStyle( - fontSize: radius * 0.4, - color: - Theme.of( - context, - ).colorScheme.onPrimaryContainer, - ), + ).colorScheme.onPrimaryContainer, ), ), - ) - : _buildQuadrant( - context, - filesId[3], - ref, - radius, ), + ) + : _buildQuadrant( + context, + filesId[3], + ref, + radius, + ), ), ], ), @@ -765,14 +775,12 @@ class SplitAvatarWidget extends ConsumerWidget { width: radius, height: radius, color: Theme.of(context).colorScheme.primaryContainer, - child: - Icon( - fallbackIcon, - size: radius * 0.6, - color: - fallbackColor ?? - Theme.of(context).colorScheme.onPrimaryContainer, - ).center(), + child: Icon( + fallbackIcon, + size: radius * 0.6, + color: + fallbackColor ?? Theme.of(context).colorScheme.onPrimaryContainer, + ).center(), ); } @@ -786,3 +794,106 @@ class SplitAvatarWidget extends ConsumerWidget { ); } } + +class _ProfileDecorationPainter extends CustomPainter { + final String text; + final Color color; + final Color textColor; + + _ProfileDecorationPainter({ + required this.text, + required this.color, + required this.textColor, + }); + + @override + void paint(Canvas canvas, Size size) { + if (text.isEmpty) return; + + final radius = size.width / 2; + final center = Offset(size.width / 2, size.height / 2); + + final strokeWidth = radius * 0.4; // Increased thickness + final centerAngle = 3 * math.pi / 4; + final sweepAngle = math.pi / 1; + final startAngle = centerAngle - (sweepAngle / 2); + + final arcRadius = radius - (strokeWidth / 2); + final rect = Rect.fromCircle(center: center, radius: arcRadius); + + final paint = Paint() + ..style = PaintingStyle.stroke + ..strokeWidth = strokeWidth + ..shader = SweepGradient( + startAngle: startAngle, + endAngle: startAngle + sweepAngle, + colors: [color.withOpacity(0), color, color, color.withOpacity(0)], + stops: const [0.0, 0.25, 0.75, 1.0], + ).createShader(rect); + + canvas.drawArc(rect, startAngle, sweepAngle, false, paint); + + _drawTextOnArc(canvas, center, arcRadius, text, centerAngle); + } + + void _drawTextOnArc( + Canvas canvas, + Offset center, + double radius, + String text, + double centerAngle, + ) { + final textStyle = TextStyle( + color: textColor, + fontSize: radius * 0.28, + fontWeight: FontWeight.bold, + ); + + double totalAngle = 0; + List charAngles = []; + + // Calculate total angle occupied by text + for (int i = 0; i < text.length; i++) { + final char = text[i]; + final span = TextSpan(text: char, style: textStyle); + final tp = TextPainter(text: span, textDirection: ui.TextDirection.ltr); + tp.layout(); + final charWidth = tp.width; + final angle = charWidth / radius; + charAngles.add(angle); + totalAngle += angle; + } + + // Start from "Left" of the center (High angle) + // We want to traverse from centerAngle + total/2 to centerAngle - total/2 + double currentAngle = centerAngle + (totalAngle / 2); + + for (int i = 0; i < text.length; i++) { + final char = text[i]; + final span = TextSpan(text: char, style: textStyle); + final tp = TextPainter(text: span, textDirection: ui.TextDirection.ltr); + tp.layout(); + + final charAngle = charAngles[i]; + final midCharAngle = currentAngle - charAngle / 2; + + final x = center.dx + radius * math.cos(midCharAngle); + final y = center.dy + radius * math.sin(midCharAngle); + + canvas.save(); + canvas.translate(x, y); + canvas.rotate(midCharAngle - math.pi / 2); + + tp.paint(canvas, Offset(-tp.width / 2, -tp.height / 2)); + + canvas.restore(); + + currentAngle -= charAngle; + } + } + + @override + bool shouldRepaint(covariant CustomPainter oldDelegate) { + return true; + } +} diff --git a/lib/widgets/content/profile_decoration.dart b/lib/widgets/content/profile_decoration.dart new file mode 100644 index 00000000..2f16f50a --- /dev/null +++ b/lib/widgets/content/profile_decoration.dart @@ -0,0 +1,13 @@ +import 'package:flutter/material.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; + +part 'profile_decoration.freezed.dart'; + +@freezed +sealed class ProfileDecoration with _$ProfileDecoration { + const factory ProfileDecoration({ + required String text, + required Color color, + Color? textColor, + }) = _ProfileDecoration; +} diff --git a/lib/widgets/content/profile_decoration.freezed.dart b/lib/widgets/content/profile_decoration.freezed.dart new file mode 100644 index 00000000..8f1b29c0 --- /dev/null +++ b/lib/widgets/content/profile_decoration.freezed.dart @@ -0,0 +1,277 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND +// coverage:ignore-file +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of 'profile_decoration.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +// dart format off +T _$identity(T value) => value; +/// @nodoc +mixin _$ProfileDecoration { + + String get text; Color get color; Color? get textColor; +/// Create a copy of ProfileDecoration +/// with the given fields replaced by the non-null parameter values. +@JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +$ProfileDecorationCopyWith get copyWith => _$ProfileDecorationCopyWithImpl(this as ProfileDecoration, _$identity); + + + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is ProfileDecoration&&(identical(other.text, text) || other.text == text)&&(identical(other.color, color) || other.color == color)&&(identical(other.textColor, textColor) || other.textColor == textColor)); +} + + +@override +int get hashCode => Object.hash(runtimeType,text,color,textColor); + +@override +String toString() { + return 'ProfileDecoration(text: $text, color: $color, textColor: $textColor)'; +} + + +} + +/// @nodoc +abstract mixin class $ProfileDecorationCopyWith<$Res> { + factory $ProfileDecorationCopyWith(ProfileDecoration value, $Res Function(ProfileDecoration) _then) = _$ProfileDecorationCopyWithImpl; +@useResult +$Res call({ + String text, Color color, Color? textColor +}); + + + + +} +/// @nodoc +class _$ProfileDecorationCopyWithImpl<$Res> + implements $ProfileDecorationCopyWith<$Res> { + _$ProfileDecorationCopyWithImpl(this._self, this._then); + + final ProfileDecoration _self; + final $Res Function(ProfileDecoration) _then; + +/// Create a copy of ProfileDecoration +/// with the given fields replaced by the non-null parameter values. +@pragma('vm:prefer-inline') @override $Res call({Object? text = null,Object? color = null,Object? textColor = freezed,}) { + return _then(_self.copyWith( +text: null == text ? _self.text : text // ignore: cast_nullable_to_non_nullable +as String,color: null == color ? _self.color : color // ignore: cast_nullable_to_non_nullable +as Color,textColor: freezed == textColor ? _self.textColor : textColor // ignore: cast_nullable_to_non_nullable +as Color?, + )); +} + +} + + +/// Adds pattern-matching-related methods to [ProfileDecoration]. +extension ProfileDecorationPatterns on ProfileDecoration { +/// A variant of `map` that fallback to returning `orElse`. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case _: +/// return orElse(); +/// } +/// ``` + +@optionalTypeArgs TResult maybeMap(TResult Function( _ProfileDecoration value)? $default,{required TResult orElse(),}){ +final _that = this; +switch (_that) { +case _ProfileDecoration() when $default != null: +return $default(_that);case _: + return orElse(); + +} +} +/// A `switch`-like method, using callbacks. +/// +/// Callbacks receives the raw object, upcasted. +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case final Subclass2 value: +/// return ...; +/// } +/// ``` + +@optionalTypeArgs TResult map(TResult Function( _ProfileDecoration value) $default,){ +final _that = this; +switch (_that) { +case _ProfileDecoration(): +return $default(_that);case _: + throw StateError('Unexpected subclass'); + +} +} +/// A variant of `map` that fallback to returning `null`. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case _: +/// return null; +/// } +/// ``` + +@optionalTypeArgs TResult? mapOrNull(TResult? Function( _ProfileDecoration value)? $default,){ +final _that = this; +switch (_that) { +case _ProfileDecoration() when $default != null: +return $default(_that);case _: + return null; + +} +} +/// A variant of `when` that fallback to an `orElse` callback. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case _: +/// return orElse(); +/// } +/// ``` + +@optionalTypeArgs TResult maybeWhen(TResult Function( String text, Color color, Color? textColor)? $default,{required TResult orElse(),}) {final _that = this; +switch (_that) { +case _ProfileDecoration() when $default != null: +return $default(_that.text,_that.color,_that.textColor);case _: + return orElse(); + +} +} +/// A `switch`-like method, using callbacks. +/// +/// As opposed to `map`, this offers destructuring. +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case Subclass2(:final field2): +/// return ...; +/// } +/// ``` + +@optionalTypeArgs TResult when(TResult Function( String text, Color color, Color? textColor) $default,) {final _that = this; +switch (_that) { +case _ProfileDecoration(): +return $default(_that.text,_that.color,_that.textColor);case _: + throw StateError('Unexpected subclass'); + +} +} +/// A variant of `when` that fallback to returning `null` +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case _: +/// return null; +/// } +/// ``` + +@optionalTypeArgs TResult? whenOrNull(TResult? Function( String text, Color color, Color? textColor)? $default,) {final _that = this; +switch (_that) { +case _ProfileDecoration() when $default != null: +return $default(_that.text,_that.color,_that.textColor);case _: + return null; + +} +} + +} + +/// @nodoc + + +class _ProfileDecoration implements ProfileDecoration { + const _ProfileDecoration({required this.text, required this.color, this.textColor}); + + +@override final String text; +@override final Color color; +@override final Color? textColor; + +/// Create a copy of ProfileDecoration +/// with the given fields replaced by the non-null parameter values. +@override @JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +_$ProfileDecorationCopyWith<_ProfileDecoration> get copyWith => __$ProfileDecorationCopyWithImpl<_ProfileDecoration>(this, _$identity); + + + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is _ProfileDecoration&&(identical(other.text, text) || other.text == text)&&(identical(other.color, color) || other.color == color)&&(identical(other.textColor, textColor) || other.textColor == textColor)); +} + + +@override +int get hashCode => Object.hash(runtimeType,text,color,textColor); + +@override +String toString() { + return 'ProfileDecoration(text: $text, color: $color, textColor: $textColor)'; +} + + +} + +/// @nodoc +abstract mixin class _$ProfileDecorationCopyWith<$Res> implements $ProfileDecorationCopyWith<$Res> { + factory _$ProfileDecorationCopyWith(_ProfileDecoration value, $Res Function(_ProfileDecoration) _then) = __$ProfileDecorationCopyWithImpl; +@override @useResult +$Res call({ + String text, Color color, Color? textColor +}); + + + + +} +/// @nodoc +class __$ProfileDecorationCopyWithImpl<$Res> + implements _$ProfileDecorationCopyWith<$Res> { + __$ProfileDecorationCopyWithImpl(this._self, this._then); + + final _ProfileDecoration _self; + final $Res Function(_ProfileDecoration) _then; + +/// Create a copy of ProfileDecoration +/// with the given fields replaced by the non-null parameter values. +@override @pragma('vm:prefer-inline') $Res call({Object? text = null,Object? color = null,Object? textColor = freezed,}) { + return _then(_ProfileDecoration( +text: null == text ? _self.text : text // ignore: cast_nullable_to_non_nullable +as String,color: null == color ? _self.color : color // ignore: cast_nullable_to_non_nullable +as Color,textColor: freezed == textColor ? _self.textColor : textColor // ignore: cast_nullable_to_non_nullable +as Color?, + )); +} + + +} + +// dart format on