TF-1194 Refactor and optimize widget
This commit is contained in:
@@ -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(
|
||||
|
||||
+33
-30
@@ -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
|
||||
)),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
+62
@@ -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()
|
||||
]),
|
||||
);
|
||||
}
|
||||
}
|
||||
+90
-64
@@ -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!)),
|
||||
],
|
||||
),
|
||||
));
|
||||
});
|
||||
))
|
||||
);
|
||||
}
|
||||
}
|
||||
-82
@@ -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,
|
||||
);
|
||||
}),
|
||||
),
|
||||
))
|
||||
);
|
||||
}
|
||||
}
|
||||
+135
-89
@@ -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;
|
||||
}
|
||||
+6
-3
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
+1
-1
@@ -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)),
|
||||
]),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -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": {}
|
||||
}
|
||||
}
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user