TF-1194 Refactor and optimize widget

This commit is contained in:
dab246
2022-12-28 14:13:11 +07:00
committed by Dat H. Pham
parent f664a7fc05
commit d9d0b71d35
18 changed files with 489 additions and 434 deletions
@@ -36,6 +36,7 @@ class SettingsFirstLevelView extends GetWidget<SettingsController> {
SettingFirstLevelTileBuilder(
AppLocalizations.of(context).profiles,
AccountMenuItem.profiles.getIcon(_imagePaths),
subtitle: AppLocalizations.of(context).profilesSettingExplanation,
() => controller.selectSettings(AccountMenuItem.profiles)
),
Divider(
@@ -43,7 +43,6 @@ class IdentitiesController extends BaseController {
final DeleteIdentityInteractor _deleteIdentityInteractor;
final EditIdentityInteractor _editIdentityInteractor;
final selectedIndex = Rxn<int>();
final identitySelected = Rxn<Identity>();
final listAllIdentities = <Identity>[].obs;
@@ -71,28 +70,22 @@ class IdentitiesController extends BaseController {
@override
void onDone() {
viewState.value.fold(
(failure) {
if (failure is DeleteIdentityFailure) {
_deleteIdentityFailure(failure);
}
},
(success) {
if (success is GetAllIdentitiesSuccess) {
if (success.identities?.isNotEmpty == true) {
final newListIdentities = success.identities!
.where((identity) => identity.mayDelete == true)
.toList();
listAllIdentities.addAll(newListIdentities);
selectIdentity(0);
}
} else if (success is CreateNewIdentitySuccess) {
_createNewIdentitySuccess(success);
} else if (success is DeleteIdentitySuccess) {
_deleteIdentitySuccess(success);
} else if (success is EditIdentitySuccess) {
_editIdentitySuccess(success);
}
(failure) {
if (failure is DeleteIdentityFailure) {
_deleteIdentityFailure(failure);
}
},
(success) {
if (success is GetAllIdentitiesSuccess) {
_handleGetAllIdentitiesSuccess(success);
} else if (success is CreateNewIdentitySuccess) {
_createNewIdentitySuccess(success);
} else if (success is DeleteIdentitySuccess) {
_deleteIdentitySuccess(success);
} else if (success is EditIdentitySuccess) {
_editIdentitySuccess(success);
}
}
);
}
@@ -117,7 +110,7 @@ class IdentitiesController extends BaseController {
}
void _refreshAllIdentities() {
selectedIndex.value = null;
identitySelected.value = null;
listAllIdentities.clear();
final accountId = _accountDashBoardController.accountId.value;
@@ -126,11 +119,21 @@ class IdentitiesController extends BaseController {
}
}
void selectIdentity(int? index) {
selectedIndex.value = index;
if (selectedIndex.value != null) {
identitySelected.value = listAllIdentities[selectedIndex.value!];
void _handleGetAllIdentitiesSuccess(GetAllIdentitiesSuccess success) {
if (success.identities?.isNotEmpty == true) {
final newListIdentities = success.identities!
.where((identity) => identity.mayDelete == true)
.toList();
listAllIdentities.addAll(newListIdentities);
}
if (listAllIdentities.isNotEmpty) {
selectIdentity(listAllIdentities.first);
}
}
void selectIdentity(Identity? newIdentity) {
identitySelected.value = newIdentity;
}
void goToCreateNewIdentity(BuildContext context) async {
@@ -226,6 +229,8 @@ class IdentitiesController extends BaseController {
}
void _deleteIdentityAction(Identity identity) {
popBack();
final accountId = _accountDashBoardController.accountId.value;
if (accountId != null && identity.id != null) {
consumeState(_deleteIdentityInteractor.execute(accountId, identity.id!));
@@ -319,7 +324,5 @@ class IdentitiesController extends BaseController {
ImagePaths get imagePaths => _imagePaths;
bool isSignatureShow() {
return selectedIndex.value!= null && selectedIndex.value! >= 0;
}
bool get isSignatureShow => identitySelected.value != null;
}
@@ -1,12 +1,12 @@
import 'package:core/core.dart';
import 'package:core/presentation/resources/image_paths.dart';
import 'package:core/presentation/utils/responsive_utils.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:tmail_ui_user/features/base/mixin/app_loader_mixin.dart';
import 'package:tmail_ui_user/features/base/mixin/popup_menu_widget_mixin.dart';
import 'package:tmail_ui_user/features/manage_account/presentation/profiles/identities/identities_controller.dart';
import 'package:tmail_ui_user/features/manage_account/presentation/profiles/identities/widgets/identities_header_widget.dart';
import 'package:tmail_ui_user/features/manage_account/presentation/profiles/identities/widgets/identities_radio_list_builder.dart';
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
import 'package:tmail_ui_user/features/manage_account/presentation/profiles/identities/widgets/identities_radio_list_builder_web.dart' as identities_listview_web;
class IdentitiesView extends GetWidget<IdentitiesController> with PopupMenuWidgetMixin, AppLoaderMixin {
@@ -17,106 +17,52 @@ class IdentitiesView extends GetWidget<IdentitiesController> with PopupMenuWidge
@override
Widget build(BuildContext context) {
return ResponsiveWidget(
responsiveUtils: _responsiveUtils,
mobile: _buildIdentitiesViewMobile(context),
tablet: _buildIdentitiesViewMobile(context),
desktop: _buildIdentitiesViewWeb(context),
tabletLarge: _buildIdentitiesViewMobile(context),
return Container(
color: Colors.transparent,
margin: const EdgeInsets.all(24),
child: _responsiveUtils.isWebDesktop(context)
? _buildIdentitiesViewWebDesktop(context)
: _buildIdentitiesViewMobile(context),
);
}
Widget _buildIdentitiesViewMobile(BuildContext context) {
return SingleChildScrollView(
padding: const EdgeInsets.only(left: 16.0, right: 16.0, top: 24.0, bottom: 24.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
for(Widget item in _buildIdentitiesTitles(context))
item,
_buildCreateIdentityButton(context),
IdentitiesRadioListBuilder(controller: controller),
],
),
);
}
Widget _buildIdentitiesViewWeb(BuildContext context) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 24.0, horizontal: 8.0),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
width: 236,
padding: const EdgeInsets.only(right: 12.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
for(Widget widget in _buildIdentitiesTitles(context))
widget,
_buildCreateIdentityButton(context),
],
),
),
Expanded(
child: identities_listview_web.IdentitiesRadioListBuilder(controller: controller),
),
],
),
);
}
List<Widget> _buildIdentitiesTitles(BuildContext context) {
return [
Text(
AppLocalizations.of(context).identities.inCaps,
style: const TextStyle(
fontWeight: FontWeight.w500,
fontSize: 17,
color: Colors.black)),
const SizedBox(height: 4.0),
Text(
AppLocalizations.of(context).identities_description,
style: const TextStyle(
fontSize: 15,
fontWeight: FontWeight.w400,
color: AppColor.colorSettingExplanation),
),
const SizedBox(height: 12.0),
];
}
Widget _buildCreateIdentityButton(BuildContext context) {
return Row(
return Column(
children: [
Expanded(
child: Padding(
padding: const EdgeInsets.only(bottom: 12.0),
child: (ButtonBuilder(_imagePaths.icAddIdentity)
..key(const Key('button_add_identity'))
..decoration(BoxDecoration(
borderRadius: BorderRadius.circular(12),
color: AppColor.colorBorderIdentityInfo))
..paddingIcon(const EdgeInsets.only(right: 12))
..iconColor(AppColor.primaryColor)
..size(28)
..padding(const EdgeInsets.symmetric(vertical: 12))
..textStyle(const TextStyle(
fontSize: 16,
color: AppColor.primaryColor,
fontWeight: FontWeight.w500,
))
..onPressActionClick(() => controller.goToCreateNewIdentity(context))
..text(
AppLocalizations.of(context).create_new_identity,
isVertical: false,
))
.build(),
),
IdentitiesHeaderWidget(
imagePaths: _imagePaths,
responsiveUtils: _responsiveUtils,
onAddNewIdentityAction: () => controller.goToCreateNewIdentity(context),
),
const SizedBox(height: 12),
IdentitiesRadioListBuilder(
controller: controller,
responsiveUtils: _responsiveUtils,
imagePaths: _imagePaths
)
],
);
}
Widget _buildIdentitiesViewWebDesktop(BuildContext context) {
return Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(
width: 224,
child: IdentitiesHeaderWidget(
imagePaths: _imagePaths,
responsiveUtils: _responsiveUtils,
onAddNewIdentityAction: () => controller.goToCreateNewIdentity(context),
)
),
const SizedBox(width: 12),
Expanded(child: IdentitiesRadioListBuilder(
controller: controller,
responsiveUtils: _responsiveUtils,
imagePaths: _imagePaths
)),
],
);
}
}
@@ -0,0 +1,62 @@
import 'package:core/presentation/extensions/color_extension.dart';
import 'package:core/presentation/resources/image_paths.dart';
import 'package:core/presentation/utils/responsive_utils.dart';
import 'package:core/presentation/views/button/button_builder.dart';
import 'package:flutter/material.dart';
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
typedef OnAddNewIdentityAction = Function();
class IdentitiesHeaderWidget extends StatelessWidget {
const IdentitiesHeaderWidget({
Key? key,
required this.imagePaths,
required this.responsiveUtils,
this.onAddNewIdentityAction,
}) : super(key: key);
final ImagePaths imagePaths;
final ResponsiveUtils responsiveUtils;
final OnAddNewIdentityAction? onAddNewIdentityAction;
@override
Widget build(BuildContext context) {
return Container(
color: Colors.transparent,
child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
Text(
AppLocalizations.of(context).identities,
style: const TextStyle(
fontSize: 17,
fontWeight: FontWeight.w500,
color: Colors.black)),
const SizedBox(height: 4),
Text(
AppLocalizations.of(context).identitiesSettingExplanation,
style: const TextStyle(
fontSize: 15,
fontWeight: FontWeight.normal,
color: AppColor.colorSettingExplanation)),
const SizedBox(height: 24),
(ButtonBuilder(imagePaths.icAddIdentity)
..key(const Key('button_add_identity'))
..decoration(BoxDecoration(
borderRadius: BorderRadius.circular(12),
color: AppColor.colorCreateNewIdentityButton))
..paddingIcon(const EdgeInsets.only(right: 8))
..iconColor(AppColor.colorTextButton)
..size(28)
..radiusSplash(12)
..padding(const EdgeInsets.symmetric(vertical: 10))
..textStyle(const TextStyle(
fontSize: 16,
color: AppColor.colorTextButton,
fontWeight: FontWeight.w500))
..onPressActionClick(() => onAddNewIdentityAction?.call())
..text(AppLocalizations.of(context).createNewIdentity, isVertical: false)
).build()
]),
);
}
}
@@ -1,79 +1,105 @@
import 'package:core/presentation/extensions/color_extension.dart';
import 'package:core/presentation/resources/image_paths.dart';
import 'package:core/presentation/utils/responsive_utils.dart';
import 'package:fading_edge_scrollview/fading_edge_scrollview.dart';
import 'package:flutter/material.dart';
import 'package:get/get_state_manager/src/rx_flutter/rx_obx_widget.dart';
import 'package:get/get_state_manager/get_state_manager.dart';
import 'package:tmail_ui_user/features/manage_account/presentation/profiles/identities/identities_controller.dart';
import 'package:tmail_ui_user/features/manage_account/presentation/profiles/identities/widgets/identity_list_tile_builder.dart';
import 'package:tmail_ui_user/features/manage_account/presentation/profiles/identities/widgets/signature_of_identity_builder.dart';
import 'identity_list_tile_builder.dart';
class IdentitiesRadioListBuilder extends StatefulWidget {
const IdentitiesRadioListBuilder({
Key? key,
required this.controller,
}) : super(key: key);
class IdentitiesRadioListBuilder extends StatelessWidget {
final IdentitiesController controller;
final ResponsiveUtils responsiveUtils;
final ImagePaths imagePaths;
@override
State<StatefulWidget> createState() => _IdentitiesRadioListBuilderState();
}
class _IdentitiesRadioListBuilderState extends State<IdentitiesRadioListBuilder> {
late final controller = widget.controller;
const IdentitiesRadioListBuilder({
Key? key,
required this.controller,
required this.responsiveUtils,
required this.imagePaths,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Obx(() {
if (controller.listAllIdentities.isEmpty) {
return const SizedBox.shrink();
}
return Container(
height: responsiveUtils.isWebDesktop(context) ? 256 : null,
decoration: BoxDecoration(
border: Border.all(color: AppColor.attachmentFileBorderColor),
borderRadius: const BorderRadius.all(Radius.circular(16.0)),
color: Colors.white
),
child: ClipRRect(
borderRadius: const BorderRadius.all(Radius.circular(16.0)),
child: responsiveUtils.isWebDesktop(context)
? _buildIdentityViewHorizontal(context)
: _buildIdentityViewVertical(context))
);
}
return Container(
foregroundDecoration: BoxDecoration(
border: Border.all(color: AppColor.colorBorderIdentityInfo, width: 1),
borderRadius: const BorderRadius.all(Radius.circular(16.0)),
Widget _buildIdentityViewVertical(BuildContext context) {
return Obx(() => Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if(controller.isSignatureShow)
...[
_buildListIdentityView(context),
Container(height: 1, color: AppColor.attachmentFileBorderColor),
Obx(() => SignatureOfIdentityBuilder(identity: controller.identitySelected.value!))
]
else
_buildListIdentityView(context)
],
));
}
Widget _buildIdentityViewHorizontal(BuildContext context) {
return Obx(() => Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (controller.isSignatureShow)
...[
_buildListIdentityView(context),
Container(width: 1, color: AppColor.attachmentFileBorderColor),
Expanded(
child: Obx(() => SignatureOfIdentityBuilder(identity: controller.identitySelected.value!)),
)
]
else
Expanded(child: _buildListIdentityView(context))
],
));
}
Widget _buildListIdentityView(BuildContext context) {
return Container(
key: const Key('identities_list'),
width: responsiveUtils.isWebDesktop(context) ? 320 : null,
height: 256,
padding: const EdgeInsets.only(left: 12, top: 12, bottom: 12),
child: Obx(() => FadingEdgeScrollView.fromScrollView(
gradientFractionOnStart: 0.3,
gradientFractionOnEnd: 0.3,
shouldDisposeScrollController: true,
child: ListView.builder(
controller: ScrollController(),
padding: const EdgeInsets.only(right: 12.0),
itemCount: controller.listAllIdentities.length,
itemBuilder: ((context, index) {
return IdentityListTileBuilder(
imagePaths: imagePaths,
identity: controller.listAllIdentities[index],
identitySelected: controller.identitySelected.value,
onSelectIdentityAction: controller.selectIdentity,
onEditIdentityAction: (identitySelected) =>
controller.goToEditIdentity(context, identitySelected),
onDeleteIdentityAction: (identitySelected) =>
controller.openConfirmationDialogDeleteIdentityAction(context, identitySelected),
);
}),
),
child: Obx(() => Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
key: const Key('identities_checkbox_list'),
height: 256,
foregroundDecoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [0, 0.5, 0.55, 0.60, 0.65, 0.70, 0.75, 0.80, 0.85, 0.90, 1].map((e)
=> Colors.white.withOpacity(e.toDouble())).toList(),
stops: const [0.8, 0.82, 0.84, 0.86, 0.88, 0.90, 0.92, 0.94, 0.96, 0.98, 1],// Gradient from https://learnui.design/tools/gradient-generator.html
tileMode: TileMode.mirror,
),
border: controller.isSignatureShow() ? const Border(bottom: BorderSide(color: AppColor.colorBorderIdentityInfo)): null,
),
padding: const EdgeInsets.only(left: 12.0, bottom: 12.0, top: 12.0, right: 4.0),
child: Scrollbar(
child: MediaQuery.removePadding(
context: context,
removeTop: true,
child: ListView.builder(
padding: const EdgeInsets.only(right: 12.0),
itemCount: controller.listAllIdentities.value.length,
itemBuilder: ((context, index) {
return IdentityListTileBuilder(
controller: widget.controller,
index: index,
selected: widget.controller.selectedIndex.value,
);
}),
)
),
),
),
if(controller.isSignatureShow())
Obx(() => SignatureOfIdentityBuilder(identity: controller.identitySelected.value!)),
],
),
));
});
))
);
}
}
@@ -1,82 +0,0 @@
import 'package:core/presentation/extensions/color_extension.dart';
import 'package:flutter/material.dart';
import 'package:get/get_state_manager/get_state_manager.dart';
import 'package:tmail_ui_user/features/manage_account/presentation/profiles/identities/identities_controller.dart';
import 'package:tmail_ui_user/features/manage_account/presentation/profiles/identities/widgets/signature_of_identity_builder.dart';
import 'identity_list_tile_builder.dart';
class IdentitiesRadioListBuilder extends StatefulWidget {
const IdentitiesRadioListBuilder({
Key? key,
required this.controller,
}) : super(key: key);
final IdentitiesController controller;
@override
State<IdentitiesRadioListBuilder> createState() => _IdentitiesRadioListBuilderState();
}
class _IdentitiesRadioListBuilderState extends State<IdentitiesRadioListBuilder> {
int? selected;
late final allIdentities = widget.controller.listAllIdentities.value;
@override
Widget build(BuildContext context) {
return Container(
height: 256,
foregroundDecoration: BoxDecoration(
border: Border.all(color: AppColor.colorBorderIdentityInfo, width: 1),
borderRadius: const BorderRadius.all(Radius.circular(16.0)),
),
child: Obx(() => Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if(widget.controller.isSignatureShow())...[
_buildListViewContainer(),
Expanded(
child: Obx(() => SignatureOfIdentityBuilder(identity: widget.controller.identitySelected.value!)),
)
] else
Expanded(child: _buildListViewContainer())
],
)),
);
}
Widget _buildListViewContainer() {
return Container(
key: const Key('identities_checkbox_list'),
width: 320,
foregroundDecoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [0, 0.5, 0.55, 0.60, 0.65, 0.70, 0.75, 0.80, 0.85, 0.90, 1].map((e)
=> Colors.white.withOpacity(e.toDouble())).toList(),
stops: const [0.8, 0.82, 0.84, 0.86, 0.88, 0.90, 0.92, 0.94, 0.96, 0.98, 1],// Gradient from https://learnui.design/tools/gradient-generator.html
tileMode: TileMode.mirror,
),
border: widget.controller.isSignatureShow() ? const Border(right: BorderSide(color: AppColor.colorBorderIdentityInfo)): null,
),
padding: const EdgeInsets.only(left: 12.0, bottom: 12.0, top: 12.0, right: 4.0),
child: Scrollbar(
controller: ScrollController(),
radius: const Radius.circular(5.0),
thickness: 2.0,
child: Obx(() => ListView.builder(
padding: const EdgeInsets.only(right: 12.0),
itemCount: widget.controller.listAllIdentities.value.length,
itemBuilder: ((context, index) {
return IdentityListTileBuilder(
controller: widget.controller,
index: index,
selected: widget.controller.selectedIndex.value,
);
}),
),
))
);
}
}
@@ -1,121 +1,167 @@
import 'package:core/core.dart';
import 'package:core/presentation/extensions/color_extension.dart';
import 'package:core/presentation/resources/image_paths.dart';
import 'package:core/presentation/utils/style_utils.dart';
import 'package:core/presentation/views/button/icon_button_web.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:jmap_dart_client/jmap/identities/identity.dart';
import 'package:tmail_ui_user/features/manage_account/presentation/profiles/identities/identities_controller.dart';
import 'package:model/extensions/list_email_address_extension.dart';
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
typedef OnSelectIdentityAction = Function(Identity? identitySelected);
typedef OnEditIdentityAction = Function(Identity identitySelected);
typedef OnDeleteIdentityAction = Function(Identity identitySelected);
class IdentityListTileBuilder extends StatelessWidget {
const IdentityListTileBuilder({
Key? key,
required this.controller,
required this.index,
required this.selected
required this.identity,
required this.identitySelected,
required this.imagePaths,
this.onSelectIdentityAction,
this.onEditIdentityAction,
this.onDeleteIdentityAction
}) : super(key: key);
final IdentitiesController controller;
final int index;
final int? selected;
final Identity identity;
final Identity? identitySelected;
final ImagePaths imagePaths;
final OnSelectIdentityAction? onSelectIdentityAction;
final OnEditIdentityAction? onEditIdentityAction;
final OnDeleteIdentityAction? onDeleteIdentityAction;
@override
Widget build(BuildContext context) {
final imagePaths = controller.imagePaths;
final listAllIdentities = controller.listAllIdentities.value;
final identity = listAllIdentities[index];
return Material(
color: Colors.transparent,
child: InkWell(
borderRadius: BorderRadius.circular(12.0),
onTap: () => controller.selectIdentity(index),
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12.0),
color: isIdentitySelected(index) ? AppColor.colorItemSelected : Colors.transparent,
),
padding: const EdgeInsets.only(top: 12.0, bottom: 12.0, right: 12.0),
child: Row(
children: [
Padding(
padding: const EdgeInsets.symmetric(horizontal: BuildUtils.isWeb ? 8.0 : 0.0),
child: Radio<int>(
value: index,
groupValue: selected,
onChanged: (selectedValue) => controller.selectIdentity(index),
child: Padding(
padding: const EdgeInsets.only(bottom: 2),
child: InkWell(
borderRadius: BorderRadius.circular(12.0),
onTap: () => onSelectIdentityAction?.call(identity),
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12.0),
color: _isIdentitySelected
? AppColor.colorItemSelected
: Colors.transparent,
),
padding: const EdgeInsets.all(12),
child: Row(
children: [
Radio<Identity>(
value: identity,
splashRadius: 15,
groupValue: identitySelected,
activeColor: AppColor.primaryColor,
onChanged: onSelectIdentityAction,
),
),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
identity.name ?? '',
overflow: CommonTextStyle.defaultTextOverFlow,
softWrap: CommonTextStyle.defaultSoftWrap,
style: const TextStyle(
fontWeight: FontWeight.w500,
fontSize: 16,
color: Colors.black)),
_buildIconWithTextLine(imagePaths.icEmail, identity.email),
for(final widget in _buildReplyLines(identity, imagePaths))
widget
],
)
),
if(isIdentitySelected(index))...[
buildSVGIconButton(
padding: const EdgeInsets.only(left: 12.0, right: 12.0),
icon: imagePaths.icEdit,
iconSize: 24,
iconColor: AppColor.primaryColor,
onTap: () => controller.goToEditIdentity(context, controller.identitySelected.value!),
const SizedBox(width: 10),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: const EdgeInsets.only(bottom: 6),
child: Text(
identity.name ?? '',
overflow: CommonTextStyle.defaultTextOverFlow,
softWrap: CommonTextStyle.defaultSoftWrap,
style: const TextStyle(
fontWeight: FontWeight.w500,
fontSize: 16,
color: Colors.black)),
),
if (identity.email?.isNotEmpty == true)
_buildIconSVGWithTextLine(imagePaths.icEmail, identity.email),
if (identity.replyTo?.isNotEmpty == true)
_buildIconSVGWithTextLine(
imagePaths.icReplyTo,
identity.replyTo?.listEmailAddressToString(isFullEmailAddress: true)
),
if (identity.bcc?.isNotEmpty == true)
_buildIconCharacterWithTextLine(
AppLocalizations.of(context).bcc_email_address_prefix,
identity.bcc?.listEmailAddressToString(isFullEmailAddress: true)
),
],
)
),
buildSVGIconButton(
padding: const EdgeInsets.only(right: 0.0),
icon: imagePaths.icDeleteOutline,
iconSize: 24,
iconColor: AppColor.colorActionDeleteConfirmDialog,
onTap: () => controller.openConfirmationDialogDeleteIdentityAction(context, controller.identitySelected.value!),
),
]
],
if(_isIdentitySelected)
...[
buildSVGIconButton(
icon: imagePaths.icEditRule,
iconSize: 24,
iconColor: AppColor.primaryColor,
onTap: () => onEditIdentityAction?.call(identity),
),
buildSVGIconButton(
icon: imagePaths.icDeleteRule,
iconSize: 24,
iconColor: AppColor.colorDeletePermanentlyButton,
onTap: () => onDeleteIdentityAction?.call(identity),
),
]
],
),
),
),
),
);
}
List<Widget> _buildReplyLines(Identity? identity, ImagePaths imagePaths) {
return [
for(var identityReplyTo in identity?.replyTo?.toList() ?? [])
_buildIconWithTextLine(imagePaths.icReply, identityReplyTo.email)];
}
Widget _buildIconWithTextLine(String imagePath, String? text) {
return Row(
children: [
Padding(
padding: const EdgeInsets.only(right: 8.0),
child: SvgPicture.asset(
imagePath,
color: AppColor.primaryColor,
width: 16,
fit: BoxFit.fitHeight,
)),
// replacement character after ..., so wrap it inside richtext is workaround solution
Widget _buildIconSVGWithTextLine(String imagePath, String? text) {
return Padding(
padding: const EdgeInsets.only(bottom: 4),
child: Row(children: [
SizedBox(
width: 30,
child: Align(
alignment: Alignment.centerLeft,
child: SvgPicture.asset(imagePath, width: 15, height: 15))),
const SizedBox(width: 4),
Expanded(child: Text(
text ?? '', style: const TextStyle(
text ?? '',
style: const TextStyle(
color: AppColor.colorEmailAddressFull,
fontWeight: FontWeight.w400,
fontWeight: FontWeight.normal,
fontSize: 13,
),
overflow: CommonTextStyle.defaultTextOverFlow,
softWrap: CommonTextStyle.defaultSoftWrap,
)),
]
softWrap: CommonTextStyle.defaultSoftWrap
))
]),
);
}
bool isIdentitySelected(int index) {
return index == selected;
Widget _buildIconCharacterWithTextLine(String character, String? text) {
return Padding(
padding: const EdgeInsets.only(bottom: 4),
child: Row(children: [
Container(
width: 30,
alignment: Alignment.centerLeft,
child: Text(
character,
style: const TextStyle(
fontSize: 15,
fontWeight: FontWeight.normal,
decoration: TextDecoration.underline,
color: AppColor.colorTextButton))),
const SizedBox(width: 4),
Expanded(child: Text(text ?? '',
style: const TextStyle(
color: AppColor.colorEmailAddressFull,
fontWeight: FontWeight.normal,
fontSize: 13,
),
overflow: CommonTextStyle.defaultTextOverFlow,
softWrap: CommonTextStyle.defaultSoftWrap
))
]),
);
}
bool get _isIdentitySelected => identity.id == identitySelected?.id;
}
@@ -1,10 +1,14 @@
import 'package:core/core.dart';
import 'package:core/presentation/views/html_viewer/html_content_viewer_on_web_widget.dart';
import 'package:core/presentation/views/html_viewer/html_content_viewer_widget.dart';
import 'package:core/presentation/views/html_viewer/html_viewer_controller_for_web.dart';
import 'package:core/utils/build_utils.dart';
import 'package:flutter/material.dart';
import 'package:html_unescape/html_unescape_small.dart';
import 'package:jmap_dart_client/jmap/identities/identity.dart';
class SignatureBuilder extends StatelessWidget {
SignatureBuilder({
const SignatureBuilder({
Key? key,
this.width,
this.height,
@@ -61,5 +65,4 @@ class SignatureBuilder extends StatelessWidget {
final unescape = HtmlUnescape();
return unescape.convert(htmlString);
}
}
@@ -4,7 +4,7 @@ import 'package:tmail_ui_user/features/manage_account/presentation/profiles/iden
class SignatureOfIdentityBuilder extends StatelessWidget {
SignatureOfIdentityBuilder({required this.identity});
const SignatureOfIdentityBuilder({Key? key, required this.identity}) : super(key: key);
final Identity identity;
@@ -1,15 +1,18 @@
import 'package:core/core.dart';
import 'package:core/presentation/extensions/color_extension.dart';
import 'package:core/presentation/resources/image_paths.dart';
import 'package:core/presentation/utils/responsive_utils.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:tmail_ui_user/features/manage_account/presentation/menu/settings_utils.dart';
import 'package:tmail_ui_user/features/manage_account/presentation/profiles/identities/identities_view.dart';
import 'package:tmail_ui_user/features/manage_account/presentation/profiles/profiles_controller.dart';
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
import 'package:tmail_ui_user/features/manage_account/presentation/profiles/widgets/profiles_header_widget.dart';
class ProfilesView extends GetWidget<ProfilesController> {
final _responsiveUtils = Get.find<ResponsiveUtils>();
final _imagePaths = Get.find<ImagePaths>();
ProfilesView({Key? key}) : super(key: key);
@@ -17,52 +20,31 @@ class ProfilesView extends GetWidget<ProfilesController> {
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: SettingsUtils.getBackgroundColor(context, _responsiveUtils),
body: ResponsiveWidget(
responsiveUtils: _responsiveUtils,
mobile: IdentitiesView(),
desktop: _buildProfilesWeb(context))
);
}
Widget _buildProfilesWeb(BuildContext context) {
return Container(
decoration: BoxDecoration(
borderRadius: const BorderRadius.all(Radius.circular(16.0)),
border: Border.all(color: AppColor.colorBorderIdentityInfo),
color: Colors.white,
),
margin: const EdgeInsets.all(16.0),
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
for(var widget in _buildProfilesTitle(context))
widget,
const Divider(color: AppColor.lineItemListColor, height: 0.5, thickness: 0.2),
Expanded(child: IdentitiesView()),
],
),
);
}
List<Widget> _buildProfilesTitle(BuildContext context) {
return [
Text(
AppLocalizations.of(context).profiles.inCaps,
style: const TextStyle(
fontWeight: FontWeight.w700,
fontSize: 20,
fontFamily: 'Inter',
color: Colors.black)),
const SizedBox(height: 4.0),
Text(
AppLocalizations.of(context).profiles_description,
style: const TextStyle(
fontSize: 16,
fontWeight: FontWeight.normal,
color: AppColor.colorContentEmail),
body: Container(
width: double.infinity,
height: double.infinity,
color: SettingsUtils.getContentBackgroundColor(context, _responsiveUtils),
decoration: SettingsUtils.getBoxDecorationForContent(context, _responsiveUtils),
margin: SettingsUtils.getMarginViewForForwardSettingDetails(context, _responsiveUtils),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (_responsiveUtils.isWebDesktop(context))
...[
ProfilesHeaderWidget(imagePaths: _imagePaths, responsiveUtils: _responsiveUtils),
Container(height: 1, color: AppColor.colorDividerHeaderSetting)
],
Expanded(child: SingleChildScrollView(
physics: const ClampingScrollPhysics(),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
IdentitiesView()
])
))
],
),
const SizedBox(height: 16.0),
];
),
);
}
}
@@ -0,0 +1,40 @@
import 'package:core/presentation/extensions/color_extension.dart';
import 'package:core/presentation/resources/image_paths.dart';
import 'package:core/presentation/utils/responsive_utils.dart';
import 'package:flutter/material.dart';
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
class ProfilesHeaderWidget extends StatelessWidget {
const ProfilesHeaderWidget({
Key? key,
required this.imagePaths,
required this.responsiveUtils,
}) : super(key: key);
final ImagePaths imagePaths;
final ResponsiveUtils responsiveUtils;
@override
Widget build(BuildContext context) {
return Container(
color: Colors.transparent,
padding: const EdgeInsets.only(top: 16, left: 16, right: 16, bottom: 15),
child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
Text(
AppLocalizations.of(context).profiles,
style: const TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
color: Colors.black)),
const SizedBox(height: 4),
Text(
AppLocalizations.of(context).profilesSettingExplanation,
style: const TextStyle(
fontSize: 16,
fontWeight: FontWeight.w500,
color: AppColor.colorSettingExplanation)),
]),
);
}
}
+25 -1
View File
@@ -1,5 +1,5 @@
{
"@@last_modified": "2022-11-18T14:33:10.063321",
"@@last_modified": "2022-12-28T14:09:51.971658",
"initializing_data": "Initializing data...",
"@initializing_data": {
"type": "text",
@@ -1166,12 +1166,30 @@
"placeholders_order": [],
"placeholders": {}
},
"profilesSettingExplanation": "Info about you, and options to manage it",
"@profilesSettingExplanation": {
"type": "text",
"placeholders_order": [],
"placeholders": {}
},
"identities": "Identities",
"@identities": {
"type": "text",
"placeholders_order": [],
"placeholders": {}
},
"identitiesSettingExplanation": "Select the identity or email address you want to use to send an emails",
"@identitiesSettingExplanation": {
"type": "text",
"placeholders_order": [],
"placeholders": {}
},
"createNewIdentity": "Create new identity",
"@createNewIdentity": {
"type": "text",
"placeholders_order": [],
"placeholders": {}
},
"new_identity": "New Identity",
"@new_identity": {
"type": "text",
@@ -2527,5 +2545,11 @@
"type": "text",
"placeholders_order": [],
"placeholders": {}
},
"regards": "Regards",
"@regards": {
"type": "text",
"placeholders_order": [],
"placeholders": {}
}
}
+13 -9
View File
@@ -1200,9 +1200,11 @@ class AppLocalizations {
name: 'profiles');
}
String get profiles_description {
return Intl.message('Info about you, and options to manage it',
name: 'profiles_description');
String get profilesSettingExplanation {
return Intl.message(
'Info about you, and options to manage it',
name: 'profilesSettingExplanation'
);
}
String get identities {
@@ -1210,14 +1212,16 @@ class AppLocalizations {
name: 'identities');
}
String get identities_description {
return Intl.message('Select the identity or email address you want to use to send an emails',
name: 'identities_description');
String get identitiesSettingExplanation {
return Intl.message(
'Select the identity or email address you want to use to send an emails',
name: 'identitiesSettingExplanation');
}
String get create_new_identity {
return Intl.message('Create new identity',
name: 'create_new_identity');
String get createNewIdentity {
return Intl.message(
'Create new identity',
name: 'createNewIdentity');
}
String get new_identity {